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 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1764038866262" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11776" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M0 0h1024v1024H0V0z" fill="#202425" opacity=".01" p-id="11777"></path><path d="M540.842667 82.670933l-18.0224-9.0112a17.066667 17.066667 0 0 0-19.524267 3.003734l-280.917333 271.530666c-159.982933 154.624-159.982933 405.265067 0 559.854934a409.6 409.6 0 0 0 134.997333 86.766933c15.530667 6.144 30.208-14.472533 24.951467-30.378667a136.533333 136.533333 0 1 1 259.345066 0c-5.256533 15.906133 9.4208 36.522667 24.951467 30.378667a409.6 409.6 0 0 0 134.997333-86.766933c148.821333-143.837867 159.197867-370.824533 31.061334-526.267734-10.0352-12.1856-29.661867-3.652267-30.1056 12.151467C800.938667 452.369067 787.285333 546.133333 716.8 546.133333c-33.655467 0-37.819733-36.898133-28.228267-86.459733 28.706133-148.036267-12.868267-309.5552-147.729066-377.002667z" fill="#FF7744" p-id="11778"></path><path d="M656.827733 581.973333l-130.3552-164.795733c-7.9872-10.103467-20.957867-10.103467-28.945066 0l-130.3552 164.795733c-79.9744 101.102933-79.9744 265.079467 0 366.1824 3.549867 4.437333 10.8544 0.443733 9.966933-5.154133a136.533333 136.533333 0 1 1 269.7216 0c-0.887467 5.597867 6.417067 9.6256 9.966933 5.154133 79.9744-101.102933 79.9744-265.079467 0-366.1824z" fill="#FFAA44" p-id="11779"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"good-detail-popup":"/components/static/good-detail-popup/good-detail-popup"
}
}
@@ -0,0 +1,116 @@
/* components/static/product-popup/product-popup.wxss */
@import "variables";
.product-popup-wrapper {
position: fixed;
right: -100%;
bottom: $primary-gap * 10;
transition: right .3s linear;
.count {
position: absolute;
background: linear-gradient(100deg, #FEB133 60%, #ffffff00 100%);
border-top-left-radius: $primary-border-radius;
border-bottom-left-radius: $primary-border-radius;
top: -20%;
width: 200rpx;
color: white;
font-weight: 800;
line-height: 50rpx;
height: 50rpx;
.count-icon{
position: absolute;
top: -20%;
width: 50rpx;
height: 50rpx;
z-index: 111;
}
.count-content{
margin-left: $primary-gap*2.2;
}
.count-content-x{
font-size: small;
}
}
.product-popup {
width: 200rpx;
border-radius: $primary-border-radius;
overflow: hidden;
position: relative;
.close {
width: 36rpx;
height: 36rpx;
line-height: 30rpx;
font-size: 30rpx;
color: rgba(255, 255, 255, 0.78);
border-radius: 50%;
text-align: center;
position: absolute;
background: rgba(0, 0, 0, 0.25);
right: $primary-gap/2;
top: $primary-gap/2;
}
.top {
width: 200rpx;
height: 200rpx;
background: white;
display: flex;
justify-content: center;
align-items: center;
image {
border-top-left-radius: $primary-border-radius;
border-top-right-radius: $primary-border-radius;
width: 96%;
height: 98%;
// border: 1px soild #fff;
}
}
.name {
display: -webkit-box;
line-clamp: 2;
box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
justify-content: center;
background: white;
color: #000;
align-items: center;
font-size: 22rpx;
height: 60rpx;
padding: 0 8rpx;
display: flex;
flex-direction: column;
}
.button {
display: flex;
background: #FF0E4C;
color: white;
height: 50rpx;
font-weight: 800;
align-items: center;
.price {
margin-left: 8rpx;
flex: 3;
font-size: 34rpx;
}
.button-right {
height: 100%;
border-top-left-radius: $primary-border-radius;
text-align: center;
line-height: 50rpx;
flex: 1;
background: linear-gradient(100deg, #ff7a3c 60%, #ff004d 100%);
}
}
}
}
@@ -0,0 +1,168 @@
import { request } from "../../../utils/request";
import { join, leave, addCustomEventListener, removeCustomEventListener } from "../../../utils/server-sent-events";
const statusId = "roomId-1";
Component({
properties: {
open: { type: Boolean, value: false },
hasTabBar: {
type: Boolean,
value: false,
},
productNum: {
type: Number,
value: 1,
},
joinedGroupId: { type: String, value: "" }, // 用户房间号
},
data: {
name: "商品名称",
price: 0,
picUrl: "https://oneppp.mn188.cn/oneppp/image/037b08ef-e576-4063-9609-090773b50dfa.jpg",
skuId: 0,
joined: false,
skuRes: {},
show: false,
stock: 0,
count:0
},
lifetimes: {
async attached() {
const that = this as any;
// join SSE 频道
try {
if (!that.data.joined) {
await join(statusId);
that.setData({ joined: true });
}
} catch (err) {
console.warn("join失败", err);
}
// 绑定 SSE 事件
that._listenerFn = async (data: any) => {
const that = this as any;
if (!data || data.type !== "product" || !data.skuId) return;
try {
if (that.data.skuId == data.skuId) {
that.setData({
show: true
});
wx.nextTick(() => {
that.setData({ open: true });
});
return;
}
const info = await request({
options: {
url: `/app/shop-store/sku-one`,
data: { id: Number(data.skuId) }
},
isLoading: false
});
that.setData({
name: info.name,
price: info.price,
picUrl: info.picUrl,
skuId: info.skuId,
skuRes: info,
show: true,
stock: info.stock,
count: info.count
});
wx.nextTick(() => {
that.setData({ open: true });
});
} catch (err) {
console.error("获取商品信息失败", err);
}
};
addCustomEventListener("pushMsg", that._listenerFn);
},
async detached() {
const that = this as any;
// leave SSE 频道
try {
if (that.data.joined) {
await leave(statusId);
that.setData({ joined: false });
}
} catch (err) {
console.warn("leave失败", err);
}
// 移除事件监听
if (that._listenerFn) {
removeCustomEventListener("pushMsg", that._listenerFn);
that._listenerFn = null;
}
}
},
methods: {
handleClick() {
const that = this as any;
wx.navigateTo({
url: `/pages/common/live-good-detail/live-good-detail?skuId=${that.data.skuId}&roomId=${that.data.joinedGroupId}`
});
},
handleClose() {
const that = this as any;
that.setData({ open: false });
},
openPopup(){
const that = this as any;
const popup = that.selectComponent('#goodDetailPopup')
popup.openPopup()
}
// ,
// handleAddShopCart() {
// const that = this as any;
// const mbuId = wx.getStorageSync("mbuId");
// let allShoppingCart = wx.getStorageSync("shoppingCart");
// if (!Array.isArray(allShoppingCart)) {
// allShoppingCart = [];
// }
// let shoppingCart: any = allShoppingCart.find(
// (item: any) => item.mbuId == mbuId
// );
// if (shoppingCart) {
// const temp = shoppingCart.data.find(
// (item: any) => item.skuId == that.data.skuId
// );
// if (temp) {
// //购物车里已经有了
// temp.count += 1;
// if (temp.count > that.data.stock) {
// wx.showToast({ title: "购物车数量超过库存数量了!", icon: "none" })
// return;
// }
// } else {
// //没有在购物车里
// shoppingCart.data.push({ ...that.data, count: 1 });
// }
// } else {
// //无添加购物车历史
// shoppingCart = {
// mbuId,
// // @ts-ignore
// data: [{ ...this.data, count: 1 }]
// };
// allShoppingCart.push(shoppingCart);
// }
// wx.setStorageSync("shoppingCart", allShoppingCart);
// wx.showToast({ title: "加入购物车成功!" })
// }
}
});
@@ -0,0 +1,26 @@
<!--components/static/product-popup/product-popup.wxml-->
<view class="product-popup-wrapper" style="right: {{open ? '24rpx' : '-100%'}}" wx:if="{{show}}">
<view class="count" wx:if="{{productNum}}">
<image class="count-icon" src="./hot.svg"></image>
<span class="count-content">热卖</span>
<span class="count-content-x">x</span>
<span class="count-content-number">{{productNum}}</span>
</view>
<view class="product-popup">
<view class="close" bind:tap="handleClose">x</view>
<view class="top" bind:tap="handleClick">
<image mode="aspectFill" src="{{picUrl}}" />
</view>
<view class="name">{{name}}</view>
<view class='button' bind:tap="openPopup">
<view class="price"><span style="font-size: 22rpx;">¥</span>{{price/100}}</view>
<view class="button-right">抢</view>
</view>
</view>
</view>
<good-detail-popup hasTabBar="{{hasTabBar}}" skuId="{{skuId}}" id="goodDetailPopup" joinedGroupId="{{joinedGroupId}}"></good-detail-popup>