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,6 @@
{
"component": true,
"usingComponents": {
"popup": "/components/popup/popup"
}
}
@@ -0,0 +1,186 @@
/* components/static/coupon-popup/coupon-popup.wxss */
.popup-header {
font-size: 36rpx;
color: #FA6905;
font-weight: 600;
padding-bottom: 12rpx;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.1);
}
.list-container {
margin-top: 24rpx;
position: relative;
box-shadow: rgba(0, 0, 0, 0.1) 0px 2px 8px;
display: grid;
grid-template-columns: repeat(1, 1fr);
gap: 24rpx;
background: rgba(0, 0, 0, 0);
.default {
background: linear-gradient(135deg, rgb(255, 107, 107) 0%, rgb(255, 142, 83) 100%);
padding: 32rpx;
border-radius: 24rpx;
color: #fff;
display: flex;
flex-direction: column;
gap: 20rpx;
min-height: 240rpx;
.default-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 8rpx;
.amount {
font-size: 48rpx;
font-weight: 700;
line-height: 1;
}
.min-price {
font-size: 24rpx;
opacity: 0.9;
}
.name {
font-size: 28rpx;
font-weight: 600;
line-height: 1.3;
height: 76rpx;
overflow: hidden;
}
.desc {
font-size: 24rpx;
opacity: 0.85;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.default-bottom {
display: flex;
justify-content: space-between;
}
.id {
opacity: 0;
user-select: none;
}
}
.large {
display: flex;
flex-direction: row;
justify-content: space-around;
gap: 32rpx;
color: #fff;
// height: 160rpx;
background: linear-gradient(135deg, rgb(255, 107, 107) 0%, rgb(255, 142, 83) 100%);
padding: 32rpx;
border-radius: 24rpx;
.large-left {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 8rpx;
.amount {
font-size: 48rpx;
font-weight: 700;
line-height: 1;
}
.min-price {
font-size: 24rpx;
opacity: 0.9;
}
}
.large-center {
width: 1px;
background: white;
margin: 0rpx;
}
.large-right {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
gap: 8rpx;
width: 100%;
.large-title {
display: flex;
align-items: center;
.name {
font-weight: bold;
font-size: 30rpx;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.desc {
font-size: 24rpx;
opacity: 0.85;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.large-bottom {
display: flex;
align-items: center;
justify-content: space-between;
.id {
opacity: 0;
user-select: none;
}
.large-button {
margin-top: 8rpx;
}
}
}
}
.button {
background: rgba(255, 255, 255, 0.9);
border: none;
color: #333;
font-weight: 600;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
min-width: 140rpx;
height: 48rpx;
border-radius: 24rpx;
line-height: 48rpx;
font-size: 28rpx;
margin: 0;
color: #FA6905;
}
}
.no-use{
width: 100%;
background-color:rgb(255, 125, 95);
border-radius:24rpx;
margin-top:24rpx;
height: 70rpx;
line-height: 70rpx;
text-align: center;
font-weight: 800;
font-size: 38rpx;
color: #fff;
}
@@ -0,0 +1,103 @@
// components/static/coupon-popup/coupon-popup.ts
import { request } from "../../../utils/request";
const app = getApp<IAppOption>();
Component({
/**
* 组件的属性列表
*/
properties: {
hasTabBar: {
type: Boolean,
value: false,
},
},
/**
* 组件的初始数据
*/
data: {
visible: false,
couponList: [],
safeBottom: app.globalData.safeBottom,
},
/**
* 组件的方法列表
*/
methods: {
async handleSwitch(amount?: number) {
const that = this as any;
if (amount) {
try {
const res = await request({
options: {
url: "/app/mini-app/user-coupon",
data: {
amount,
mbuId: wx.getStorageSync('mbuId')
}
},
needLogin: true
})
if (!res || !res.data || res.data.length == 0) {
// wx.showToast({
// title: "没有可使用的优惠券",
// icon: "none",
// duration: 2000
// })
that.triggerEvent('select', {
coupon: null
});
return;
} else {
if (res.data.length > 0) res.data.forEach((item: any) => {
item.discountPrice = (item.discountPrice / 100).toFixed(2);
item.usePrice = item.usePrice / 100;
item.validStartTime = item.validStartTime.replace("T", " ");
item.validEndTime = item.validEndTime.replace("T", " ");
}); //金额单位为分
that.setData({ couponList: res.data, visible: true })
}
} catch (e) {
console.log(e, 'error');
wx.showToast({
title: "查询优惠券信息出错了!",
icon: "none",
duration: 2000
})
that.setData({
visible: false,
})
}
} else {
that.setData({
visible: false,
})
}
},
//选择优惠券
handleSelect(e: any) {
const that = this as any;
const index = e.currentTarget.dataset.index;
const coupon = that.data.couponList[index];
that.setData({ visible: false });
that.triggerEvent('select', {
couponId: coupon?.couponIds?.[0] ?? coupon?.id ?? null,
coupon
});
},
handleClose(this: WechatMiniprogram.Component.TrivialInstance) {
this.setData({ visible: false });
this.triggerEvent("select", { couponId: null });
},
closePopup(this: WechatMiniprogram.Component.TrivialInstance) {
this.setData({ visible: false });
},
}
})
@@ -0,0 +1,36 @@
<!--components/static/coupon-popup/coupon-popup.wxml-->
<popup visible="{{visible}}" bind:close="closePopup">
<view slot="header" class="popup-header">
选择优惠券
</view>
<view class="list-container">
<view wx:for="{{couponList}}" wx:key="name" class="large" data-index="{{index}}">
<view class="large-left">
<view class="amount">{{'¥'+item.discountPrice}}</view>
<view class="min-price">满{{item.usePrice}}元可用</view>
<view class="min-price">剩余{{item.count}}张</view>
</view>
<view class="large-center"></view>
<view class="large-right">
<view class="large-title">
<tag propStyle="background: rgba(0, 0, 0, 0.2);border:none;color:white;">
{{item.discountType===1?'代金券':'折扣券'}}
</tag>
<view class="name">{{item.name}}</view>
</view>
<view class="desc">优惠开始时间:{{item.validStartTime}}</view>
<view class="desc">优惠结束时间:{{item.validEndTime}}</view>
<div class="large-bottom">
<div class="id">ID{{item.couponIds}}</div>
<button class="button large-button" data-index="{{index}}" bind:tap="handleSelect">选择</button>
</div>
</view>
</view>
</view>
<view class="no-use" bind:tap="handleSelect">
不使用优惠券
</view>
<view style="height:{{hasTabBar? safeBottom/2 + 90 : safeBottom}}rpx;"></view>
</popup>