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";Component({properties:{icon:{type:String,value:""},describeText:{type:String,value:""},title:{type:String,value:""},buttonText:{type:String,value:""},buttonType:{type:String,value:"primary"},useDarkTheme:{type:Boolean,value:""},current:{type:Object,value:null},showCountDown:{type:Boolean,value:!1}},data:{visible:!0},lifetimes:{attached:function(){}},observers:{},methods:{onClick:function(){this.triggerEvent("onClick")}}});
@@ -0,0 +1 @@
{"component":true,"usingComponents":{"count-down":"../../image-text-float/count-down/count-down"}}
@@ -0,0 +1,16 @@
<view class="image-text-item-card {{useDarkTheme ? 'image-text-item-card-dark' : ''}}" bindtap="onClick">
<view class="image-text-item-prefix">
<image src="{{icon}}" />
<count-down class="count-down" wx:if="{{showCountDown}}" sendTime="{{current.SendTime}}" deadLine="{{current.Deadline || current.DeadLine}}" deadLineSecond="{{current.DeadlineSecond || current.DeadLineSecond}}" />
</view>
<view class="image-text-item-content">
<view class="image-text-item-content-title">{{title}}</view>
<view wx:if="{{describeText}}" class="image-text-item-content-info">
<view class="image-text-item-content-describe">{{describeText}}</view>
</view>
</view>
<view class="image-text-item-btn">
<!-- CTA 自身和整卡都可点击;这里截断冒泡,避免按钮点击时重复触发 feature.click。 -->
<view class="image-text-item-content-button image-text-item-content-button-{{buttonType || 'primary'}}" catchtap="onClick">{{buttonText}}</view>
</view>
</view>
@@ -0,0 +1 @@
.image-text-item-card{padding:24rpx;display:flex;align-items:center;justify-content:flex-start;border-radius:16rpx;border:2rpx solid rgba(22,24,35,.08);background-color:rgba(255,255,255,.5);width:100%;box-sizing:border-box}.image-text-item-prefix{flex:0 0 72rpx;width:72rpx;height:72rpx;display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden;border:1rpx solid rgba(22,24,35,.12);border-radius:16rpx;background-color:#fff;box-sizing:border-box}.image-text-item-prefix image{width:100%;height:100%;border-radius:14rpx}.count-down{font-weight:600;font-size:calc(24rpx + .5 * (1rem - 16px));position:absolute;min-width:100%;text-align:center;display:flex;justify-content:center;align-items:center;height:calc(24rpx + .5 * (1rem - 16px));line-height:calc(24rpx + .5 * (1rem - 16px));bottom:0;color:#fff;background:rgba(0,0,0,.5);border-radius:16rpx}.image-text-item-content{flex:1;display:flex;padding-left:24rpx;padding-right:20rpx;flex-direction:column;justify-content:space-between;overflow:hidden}.image-text-item-content-info{display:flex;align-items:center;margin-top:8rpx;color:rgba(22,24,35,.6);overflow:hidden}.image-text-item-content-title{color:#161823;font-size:calc(28rpx + .5 * (1rem - 16px));font-weight:500;line-height:calc(44rpx + .5 * (1rem - 16px));padding:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.image-text-item-content-describe{flex:1;font-size:calc(24rpx + .5 * (1rem - 16px));line-height:calc(34rpx + .5 * (1rem - 16px));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.image-text-item-btn{flex-shrink:0;margin-left:auto;display:flex;white-space:nowrap}.image-text-item-content-button{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;min-height:calc(56rpx + .5 * (1rem - 16px));border-radius:8rpx;padding:0 20rpx;font-size:calc(28rpx + .5 * (1rem - 16px));line-height:calc(40rpx + .5 * (1rem - 16px));white-space:nowrap;box-sizing:border-box}.image-text-item-content-button-primary{color:#fff;background-color:#fe2c55;border:2rpx solid transparent}.image-text-item-content-button-ghost{color:#323b47;background-color:#fff;border:2rpx solid rgba(22,24,35,.34)}.image-text-item-content-button-minor{color:#fe2c55;background-color:rgba(254,44,85,.08);border:2rpx solid transparent}.image-text-item-content-button view{color:inherit!important}.image-text-item-content-button>svg{margin-left:8rpx;width:24rpx;height:24rpx}.image-text-item-card-dark{border-color:rgba(22,24,35,.08);background-color:rgba(255,255,255,.1)}.image-text-item-card-dark .image-text-item-prefix{border-color:rgba(255,255,255,.08);background-color:rgba(22,24,35,.15)}.image-text-item-card-dark .image-text-item-content-title{color:rgba(255,255,255,.9)}.image-text-item-card-dark .image-text-item-content-info{color:rgba(255,255,255,.5)}.image-text-item-card-dark .image-text-item-content-button-primary{color:#fff;background-color:#fe2c55;border-color:transparent}.image-text-item-card-dark .image-text-item-content-button-minor{color:#fe2c55;background-color:rgba(254,44,85,.2);border-color:transparent}.image-text-item-card-dark .image-text-item-content-button-ghost{color:#fff;background-color:rgba(255,255,255,.06);border-color:transparent}.image-text-item-card-dark .image-text-item-content-button view{color:inherit!important}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"component":true,"usingComponents":{"card-item":"./card-item/card-item"}}
@@ -0,0 +1,93 @@
<wxs module="m1">
var getDateFormat = function(time) {
var objectDate = getDate(+time) ;
var time = objectDate.getMinutes().toString();
var seconds = objectDate.getSeconds().toString();
var hours = objectDate.getHours().toString();
var day = objectDate.getDate().toString();
var month = (objectDate.getMonth() + 1).toString();
var year = objectDate.getFullYear().toString();
return year + '/' + (month.length === 1 ? '0' : '') + month + '/' + (day.length === 1 ? '0' : '') + day + ' ' + (hours.length === 1 ? '0' : '') + hours + ':' + (time.length === 1 ? '0' : '') + time + ':' + (seconds.length === 1 ? '0' : '') + seconds;
}
module.exports.getDateFormat = getDateFormat;
</wxs>
<view class="volc-live-portrait-image-card {{useDarkTheme ? 'volc-live-portrait-image-card-dark' : ''}}">
<view wx:if="{{!iconList.length}}" class="no-content-wrapper">
<image class="no-content-image" src="{{useDarkTheme ? '../../assets/no_content_dark.svg' : '../../assets/no_content.svg'}}"></image>
<view class="no-content-text">暂无内容</view>
</view>
<view wx:else>
<view class="image-text-count">
<view class="image-text-number">{{iconList.length || 0}}</view>
条直播内容
</view>
<view
wx:for="{{iconList}}"
wx:for-index="index"
wx:for-item="message"
wx:key="ImageTextId"
class="image-text-message image-text-timeline-message {{index === iconList.length - 1 ? 'image-text-message-last' : ''}}"
>
<view class="image-text-circle"></view>
<view class="image-text-line"></view>
<view class="image-text-item">
<view class="image-text-item-header">
<view class="create-time">{{m1.getDateFormat(message.CreateTime)}}</view>
</view>
<view class="image-text-item-content">
<view
wx:for="{{message.Context || []}}"
wx:for-index="index"
wx:for-item="item"
wx:key="index"
class="image-text-message {{item.renderType === 'image' && item.multiImages ? 'image-text-message-image-grid' : ''}}"
>
<view wx:if="{{item.renderType === 'text'}}" class="image-text-item-text">
<block
wx:for="{{item.segments}}"
wx:for-item="segment"
wx:for-index="segmentIndex"
wx:key="segmentIndex"
>
<text
wx:if="{{segment.type === 'link'}}"
class="image-text-item-link"
data-url="{{segment.url}}"
data-text="{{segment.text}}"
bindtap="onTextLinkClick"
>{{segment.text}}</text>
<text wx:else>{{segment.text}}</text>
</block>
</view>
<view
wx:elif="{{item.renderType === 'image'}}"
class="image-text-item-image {{item.multiImages ? 'image-text-item-image-multi' : ''}}"
data-src="{{item.src}}"
data-images="{{item.images}}"
data-image-index="{{item.imageIndex}}"
bindtap="previewImage"
>
<image src="{{item.src}}" mode="{{item.multiImages ? 'aspectFill' : 'aspectFit'}}" />
</view>
<card-item
wx:else
data-item="{{item}}"
bind:onClick="onClick"
icon="{{item.icon}}"
text="{{item.text}}"
describeText="{{item.describeText}}"
title="{{item.title}}"
buttonText="{{item.buttonText}}"
buttonType="{{item.buttonType}}"
useDarkTheme="{{useDarkTheme}}"
showCountDown="{{item.showCountDown}}"
current="{{item.current}}"
/>
</view>
</view>
</view>
</view>
<view class="image-text-divider">没有更多内容了</view>
</view>
</view>
@@ -0,0 +1 @@
.volc-live-portrait-image-card{width:calc(100% - 48rpx);margin:0 24rpx;height:100%;padding-top:24rpx;box-sizing:border-box}.no-content-wrapper{height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center}.no-content-image{width:200rpx;height:200rpx}.no-content-text{font-size:calc(28rpx + .5 * (1rem - 16px));color:#1d21294d}.image-text-count{margin:0 0 24rpx 0;color:#6f7680;font-size:calc(24rpx + .5 * (1rem - 16px));line-height:calc(34rpx + .5 * (1rem - 16px));text-align:left}.image-text-number{color:#fe2c55;margin:auto 4rpx;font-weight:500;display:inline-block}.image-text-message{display:flex;flex-direction:column}.image-text-timeline-message{position:relative}.image-text-circle{position:absolute;top:0;left:0;width:20rpx;height:20rpx;border:2rpx solid rgba(29,33,41,.12);border-radius:50%;box-sizing:border-box}.image-text-line{position:absolute;top:20rpx;left:9rpx;height:calc(100% - 20rpx);border-left:2rpx solid rgba(29,33,41,.12)}.image-text-message-last .image-text-line{display:none}.image-text-item{float:left;text-align:left;border-radius:8rpx;margin-bottom:16rpx;padding:0 0 24rpx 24rpx;background-color:transparent}.image-text-item-header{font-size:calc(26rpx + .5 * (1rem - 16px));word-break:break-all;color:#6f7680;display:flex;justify-content:flex-start}.tag-host{display:inline-flex;align-items:center;font-size:calc(22rpx + .5 * (1rem - 16px));color:#fa9600;margin-right:24rpx;border:2rpx solid #fa9600;border-radius:4rpx;padding:0 6rpx;line-height:calc(32rpx + .5 * (1rem - 16px))}.is-portrait{color:#fa9600;border-color:#fa9600}.create-time{position:relative;top:-8rpx;font-size:calc(24rpx + .5 * (1rem - 16px));line-height:calc(34rpx + .5 * (1rem - 16px))}.image-text-item-content{line-height:1;font-size:calc(26rpx + .5 * (1rem - 16px));margin-top:0;display:flex;flex-wrap:wrap;gap:16rpx;align-items:flex-start}.image-text-item-content>.image-text-message{width:100%}.image-text-item-content>.image-text-message-image-grid{width:calc((100% - 32rpx)/ 3)}.image-text-item-text{font-size:calc(26rpx + .5 * (1rem - 16px));word-break:break-all;color:#323b47;line-height:calc(40rpx + .5 * (1rem - 16px));margin-bottom:16rpx;white-space:pre-wrap}.image-text-item-link{color:#3370ff;text-decoration:none}.image-text-item-image{cursor:pointer;border-radius:4rpx;display:block;width:100%;max-width:320rpx;height:320rpx;position:relative;overflow:hidden;box-shadow:0 12rpx 34rpx 0 rgba(0,0,0,.04);background-color:rgba(0,0,0,.04)}.image-text-item-image-multi{width:100%;max-width:none;height:0;padding-top:100%}.image-text-item-image image{position:absolute;top:0;left:0;height:100%;width:100%}.image-text-divider{font-size:calc(26rpx + .5 * (1rem - 16px));padding-bottom:40rpx;text-align:center;color:rgba(29,33,41,.38)}.volc-live-portrait-image-card-dark .image-text-count{color:#909090}.volc-live-portrait-image-card-dark .no-content-text{color:#ffffff4d}.volc-live-portrait-image-card-dark .image-text-item{background-color:transparent}.volc-live-portrait-image-card-dark .image-text-circle{border-color:rgba(255,255,255,.12)}.volc-live-portrait-image-card-dark .image-text-line{border-left-color:rgba(255,255,255,.12)}.volc-live-portrait-image-card-dark .image-text-item-header{color:#909090}.volc-live-portrait-image-card-dark .tag-host{color:#ffd58b;border:2rpx solid #ffd58b}.volc-live-portrait-image-card-dark .is-portrait{color:#ffd58b;border-color:#ffd58b}.volc-live-portrait-image-card-dark .image-text-item-text{color:#d2d3d3}.volc-live-portrait-image-card-dark .image-text-item-link{color:#3370ff}.volc-live-portrait-image-card-dark .image-text-divider{color:rgba(255,255,255,.38)}