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
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"component":true,"usingComponents":{}}
@@ -0,0 +1,16 @@
<view
id="doubleTapLikeWrapper"
class="double-tap-like-wrapper"
bindtouchstart="handleTouchStart"
bindtouchmove="handleTouchMove"
bindtouchend="handleTouchEnd"
bindtouchcancel="handleTouchCancel"
>
<slot />
<canvas
wx:if="{{canvasVisible}}"
type="2d"
id="likeCanvas"
class="like-canvas"
></canvas>
</view>
@@ -0,0 +1 @@
.double-tap-like-wrapper{position:relative;width:100%;height:100%}.like-canvas{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:999}
@@ -0,0 +1 @@
"use strict";function _typeof(t){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},_typeof(t)}function _classCallCheck(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function _defineProperties(t,e){for(var i=0;i<e.length;i++){var r=e[i];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,_toPropertyKey(r.key),r)}}function _createClass(t,e,i){return e&&_defineProperties(t.prototype,e),i&&_defineProperties(t,i),Object.defineProperty(t,"prototype",{writable:!1}),t}function _toPropertyKey(t){var e=_toPrimitive(t,"string");return"symbol"===_typeof(e)?e:String(e)}function _toPrimitive(t,e){if("object"!==_typeof(t)||null===t)return t;var i=t[Symbol.toPrimitive];if(void 0!==i){var r=i.call(t,e||"default");if("object"!==_typeof(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===e?String:Number)(t)}Object.defineProperty(exports,"__esModule",{value:!0}),exports.LikeAnimation=void 0;var LikeAnimation=function(){function t(e,i,r){var o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:[];_classCallCheck(this,t),this.x=e,this.y=i,this.canvas=r,this.startTime=Date.now(),this.duration=500,this.imageUrl=o.length>0?o[Math.floor(Math.random()*o.length)]:"../../../assets/thumb.png",this.image=null,this.imageLoaded=!1,this.loadImage(),this.startScale=.5,this.endScale=1.5,this.startRotation=20*(Math.random()-.5),this.offsetY=-60}return _createClass(t,[{key:"loadImage",value:function(){var t=this;if(this.canvas){var e=this.canvas.createImage();e.onload=function(){t.imageLoaded=!0,t.image=e},e.onerror=function(){console.error("Failed to load like animation image:",t.imageUrl)},e.src=this.imageUrl}}},{key:"update",value:function(){var t=Date.now()-this.startTime,e=Math.min(t/this.duration,1);return!(e>=1||(this.progress=e,0))}},{key:"draw",value:function(t){if(this.imageLoaded&&this.image){var e,i,r,o=this.progress||0,a=this.y+this.offsetY*o;e=o<.25?this.startScale+(1-this.startScale)*(o/.25):o<.75?1:1+(this.endScale-1)*((o-.75)/.25),i=o<.25?o/.25:o<.75?1:1-(o-.75)/.25,r=o<.25?this.startRotation:o<.5?this.startRotation*(1-(o-.25)/.25):0,t.save(),t.globalAlpha=i,t.translate(this.x,a),t.rotate(r*Math.PI/180),t.scale(e,e),t.drawImage(this.image,-15,-15,30,30),t.restore()}}}]),t}();exports.LikeAnimation=LikeAnimation;
@@ -0,0 +1 @@
"use strict";var _thumbService=_interopRequireDefault(require("../../../services/thumb-service")),_thumbsItem=require("./thumbs-item"),_utils=require("../../../utils/utils"),_bottomIcon=require("../../../utils/icons/bottom-icon");function _interopRequireDefault(t){return t&&t.__esModule?t:{default:t}}var DEFAULT_THUMB_ICON_SRC="../../../assets/thumb.png";Component({properties:{mode:{type:String,value:"portrait"},sdkInstance:{type:Object,value:null,observer:function(t){this.bindSdkInstance(t)}}},data:{visible:!0,bottomIcon:{visible:!1},count:0,countStr:"0",thumbUpEffectUrls:[],iconSrc:DEFAULT_THUMB_ICON_SRC},lifetimes:{attached:function(){var t=_thumbService.default.totalCount;this.lastCount=t;var i=t;t>9999&&(i=(t/1e4).toFixed(1)+"w"),(0,_utils.setDataIfChanged)(this,{count:t,countStr:i.toString()}),this.updateConfig(_thumbService.default.config),this._updateCountBound=this.updateCount.bind(this),this._onConfigChange=this.onConfigChange.bind(this),_thumbService.default.on("onCountChange",this._updateCountBound),_thumbService.default.on("onConfigChange",this._onConfigChange)},ready:function(){this.initCanvas()},detached:function(){_thumbService.default.off("onCountChange",this._updateCountBound),_thumbService.default.off("onConfigChange",this._onConfigChange),this.unbindSdkInstance(),this.processingTimer&&(clearInterval(this.processingTimer),this.processingTimer=null)}},methods:{bindSdkInstance:function(t){var i,n=this;if(t&&this._bottomIconSdkInstance!==t){this.unbindSdkInstance(),this._bottomIconSdkInstance=t;var e=t.store;this._bottomIconUnsub=null==e||null===(i=e.get)||void 0===i?void 0:i.call(e,{liveInfo:function(){return n.syncHeartBottomIcon()},iconList:function(){return n.syncHeartBottomIcon()}}),this.syncHeartBottomIcon()}},unbindSdkInstance:function(){"function"==typeof this._bottomIconUnsub&&this._bottomIconUnsub(),this._bottomIconUnsub=null,this._bottomIconSdkInstance=null},syncHeartBottomIcon:function(){var t,i,n=this._bottomIconSdkInstance,e=null==n?void 0:n.store,s=(null==e||null===(t=e.get)||void 0===t?void 0:t.call(e,"liveInfo"))||{},o=null==e||null===(i=e.get)||void 0===i?void 0:i.call(e,"iconList"),a=(0,_bottomIcon.buildFixedBottomIconViewModel)(n,(0,_bottomIcon.buildHeartBottomIconSource)(s,o),this.data.mode)||{visible:!1};(0,_utils.setDataIfChanged)(this,{bottomIcon:a})},onConfigChange:function(t){this.updateConfig(t)},updateConfig:function(t){var i=this;if(t){var n={};void 0!==t.isThumbUpEnable&&(n.visible=!!t.isThumbUpEnable),void 0!==t.isThumbUpNumberEnable&&(n.showNumber=!!t.isThumbUpNumberEnable),n.iconSrc=t.thumbUpUrl||DEFAULT_THUMB_ICON_SRC,t.thumbUpEffectUrls&&(n.thumbUpEffectUrls=t.thumbUpEffectUrls),this.setData(n,function(){i.data.visible&&!i.canvas&&i.initCanvas()})}},updateCount:function(t){var i=t-(this.lastCount||0);if(this.isReady&&i>0&&i<50){var n=Math.min(i,10);this.addPendingAnimations(n)}this.lastCount=t,this.isReady||(this.isReady=!0);var e=t;t>9999&&(e=(t/1e4).toFixed(1)+"w"),(0,_utils.setDataIfChanged)(this,{count:t,countStr:e.toString()})},addPendingAnimations:function(t){this.pendingCount=(this.pendingCount||0)+t,this.processPendingAnimations()},processPendingAnimations:function(){var t=this;if(!this.processingTimer){var i=function(){t.pendingCount<=0?t.processingTimer&&(clearInterval(t.processingTimer),t.processingTimer=null):(t.startAnimation(),t.pendingCount--)};i(),this.pendingCount>0&&(this.processingTimer=setInterval(i,200))}},handleTap:function(){var t=this;_thumbService.default.addLike()&&(this.canvas||this.initCanvas(),this.calcCount=(this.calcCount||0)+1,this.calcTimer&&clearTimeout(this.calcTimer),this.calcTimer=setTimeout(function(){t.calcCount=0,t.calcTimer=null,t.setData({comboCount:0})},1e3),this.calcCount>=5&&this.setData({comboCount:this.calcCount}),wx.vibrateShort({type:"light"}).catch(function(){}))},initCanvas:function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;this.data.visible&&this.createSelectorQuery().select("#thumbCanvas").fields({node:!0,size:!0}).exec(function(n){if(n[0]){var e=n[0].node,s=n[0].width,o=n[0].height,a=wx.getSystemInfoSync().pixelRatio;e.width=s*a,e.height=o*a,t.ctx=e.getContext("2d"),t.ctx.scale(a,a),t.canvas=e,t.width=s,t.height=o,t.thumbs=[]}else t.data.visible&&i<5&&setTimeout(function(){t.initCanvas(i+1)},500)})},startAnimation:function(){if(this.canvas){var t=new _thumbsItem.ThumbsItem(this.width,this.height,this.canvas,this.data.thumbUpEffectUrls);this.thumbs.push(t),this.animating||(this.animating=!0,this.animate())}},animate:function(){var t=this;if(0===this.thumbs.length)return this.animating=!1,void(this.ctx&&this.ctx.clearRect(0,0,this.width,this.height));this.ctx&&(this.ctx.clearRect(0,0,this.width,this.height),this.thumbs=this.thumbs.filter(function(t){return t.update()}),this.thumbs.forEach(function(i){return i.draw(t.ctx)})),this.canvas.requestAnimationFrame(function(){return t.animate()})}}});
@@ -0,0 +1 @@
{"component":true}
@@ -0,0 +1,11 @@
<view class="thumb-container {{mode}}" bindtap="handleTap" style="display: {{visible && bottomIcon.visible !== false ? 'flex' : 'none'}};">
<view class="thumb-icon-wrapper" style="{{bottomIcon.containerStyle}}">
<image class="thumb-icon" src="{{bottomIcon.iconUrl || iconSrc}}" style="{{bottomIcon.style}}" />
</view>
<text class="thumb-count" wx:if="{{showNumber && countStr}}">{{countStr}}</text>
<view class="thumb-combo-number" wx:if="{{comboCount >= 5}}">
<text class="number-x">X</text>
<text class="number-val">{{comboCount > 99 ? '99+' : comboCount}}</text>
</view>
<canvas type="2d" id="thumbCanvas" class="thumb-canvas"></canvas>
</view>
@@ -0,0 +1 @@
:host{display:flex}.thumb-container{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;width:calc(72rpx + .5 * (1rem - 16px));height:calc(72rpx + .5 * (1rem - 16px));flex-shrink:0}.thumb-container.portrait{margin-left:16rpx}.thumb-container.landscape{margin-left:12rpx}.thumb-icon-wrapper{width:calc(72rpx + .5 * (1rem - 16px));height:calc(72rpx + .5 * (1rem - 16px));border-radius:50%;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.14)}.thumb-icon{width:70%;height:70%}.thumb-count{font-size:calc(18rpx + .5 * (1rem - 16px));color:#fff;position:absolute;bottom:0;left:50%;transform:translateX(-50%);background:rgba(0,0,0,.3);padding:0 8rpx;border-radius:12rpx;line-height:calc(24rpx + .5 * (1rem - 16px));min-width:24rpx;text-align:center}.thumb-canvas{position:absolute;bottom:60rpx;right:-20rpx;width:128rpx;height:300rpx;pointer-events:none;z-index:999}.thumb-combo-number{position:absolute;top:-320rpx;left:36rpx;transform:translateX(-50%);display:flex;align-items:flex-end;pointer-events:none;z-index:1000;color:#fcc75c;font-weight:700;font-style:italic;animation:popIn .3s cubic-bezier(.175,.885,.32,1.275)}.number-x{font-size:calc(24rpx + .5 * (1rem - 16px));margin-right:2rpx;margin-bottom:4rpx}.number-val{font-size:calc(36rpx + .5 * (1rem - 16px))}@keyframes popIn{from{transform:translateX(-50%) scale(.5);opacity:0}to{transform:translateX(-50%) scale(1);opacity:1}}
File diff suppressed because one or more lines are too long