feat(mp+health): 小程序分包迁移 + 积分商城后台列表 API
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

- 小程序页面迁移到 pkg-health/pkg-mall/pkg-profile 分包目录
- 删除旧 pages/health/input、pages/mall/detail 等旧路径
- 导航路径更新为分包路径(/pages/pkg-mall/exchange/index 等)
- TrendChart 组件优化
- 后台添加 admin_list_products API(支持查看已下架商品)
- config/index.ts 添加 defineConstants 环境变量
- mp e2e check-readiness 路径修正
This commit is contained in:
iven
2026-04-29 07:29:49 +08:00
parent 9015a2b85e
commit cb6f5cc651
32 changed files with 229 additions and 516 deletions

View File

@@ -0,0 +1,170 @@
@import '../../../styles/variables.scss';
@import '../../../styles/mixins.scss';
.trend-page {
min-height: 100vh;
background: $bg;
padding-bottom: 60px;
}
/* ── hero ── */
.trend-hero {
padding: 48px 32px 28px;
display: flex;
flex-direction: column;
align-items: center;
}
.trend-hero-icon {
@include flex-center;
width: 88px;
height: 88px;
border-radius: $r-lg;
background: $pri-l;
margin-bottom: 20px;
}
.trend-hero-icon-text {
font-family: 'Georgia', 'Times New Roman', serif;
font-size: 40px;
font-weight: bold;
color: $pri;
}
.trend-hero-title {
@include section-title;
font-size: 36px;
margin-bottom: 0;
}
/* ── range tabs ── */
.trange-wrap {
display: flex;
justify-content: center;
gap: 16px;
padding: 0 32px 28px;
}
.trange-tab {
padding: 12px 32px;
border-radius: $r-pill;
background: $card;
box-shadow: $shadow-sm;
transition: all 0.2s;
}
.trange-tab-active {
background: $pri;
box-shadow: $shadow-md;
}
.trange-tab-text {
font-size: 24px;
color: $tx2;
font-weight: 500;
}
.trange-tab-text-active {
color: white;
}
/* ── chart card ── */
.trend-chart-card {
margin: 0 24px 20px;
background: $card;
border-radius: $r;
box-shadow: $shadow-md;
padding: 24px;
min-height: 300px;
overflow: hidden;
}
/* ── reference card ── */
.trend-ref-card {
margin: 0 24px 20px;
background: $acc-l;
border-radius: $r;
padding: 20px 24px;
display: flex;
align-items: center;
gap: 16px;
}
.trend-ref-label {
font-size: 24px;
color: $acc;
font-weight: bold;
}
.trend-ref-value {
font-size: 26px;
color: $acc;
@include serif-number;
font-weight: 500;
}
/* ── list ── */
.trend-list {
margin: 0 24px;
}
.trend-list-title {
font-family: 'Georgia', 'Times New Roman', serif;
font-size: 28px;
font-weight: bold;
color: $tx;
display: block;
margin-bottom: 16px;
}
.trend-item {
display: flex;
justify-content: space-between;
align-items: center;
background: $card;
padding: 22px 28px;
border-bottom: 1px solid $bd-l;
&:first-child {
border-radius: $r $r 0 0;
}
&:last-child {
border-radius: 0 0 $r $r;
border-bottom: none;
}
}
.trend-item-warn {
background: $wrn-l;
}
.trend-item-left {
display: flex;
align-items: center;
gap: 12px;
}
.trend-item-date {
font-size: 26px;
color: $tx2;
}
.trend-item-tag {
@include tag($wrn-l, $wrn);
}
.trend-item-warn .trend-item-tag {
@include tag($dan-l, $dan);
}
.trend-item-value {
font-size: 28px;
color: $pri;
@include serif-number;
font-weight: bold;
}
.trend-item-value-warn {
color: $dan;
}

View File

@@ -0,0 +1,111 @@
import { useState, useEffect } from 'react';
import { View, Text } from '@tarojs/components';
import { useRouter } from '@tarojs/taro';
import { useHealthStore } from '@/stores/health';
import TrendChart from '@/components/TrendChart';
import './index.scss';
const RANGE_OPTIONS = [
{ value: '7d', label: '7天' },
{ value: '30d', label: '30天' },
{ value: '90d', label: '90天' },
];
const INDICATOR_META: Record<string, { label: string; unit: string; refMin?: number; refMax?: number }> = {
blood_pressure_systolic: { label: '收缩压', unit: 'mmHg', refMin: 90, refMax: 140 },
blood_pressure_diastolic: { label: '舒张压', unit: 'mmHg', refMin: 60, refMax: 90 },
heart_rate: { label: '心率', unit: 'bpm', refMin: 60, refMax: 100 },
blood_sugar_fasting: { label: '空腹血糖', unit: 'mmol/L', refMin: 3.9, refMax: 6.1 },
blood_sugar_postprandial: { label: '餐后血糖', unit: 'mmol/L', refMin: 3.9, refMax: 7.8 },
weight: { label: '体重', unit: 'kg' },
};
export default function Trend() {
const router = useRouter();
const indicator = router.params.indicator || 'heart_rate';
const [range, setRange] = useState('7d');
const [points, setPoints] = useState<{ date: string; value: number }[]>([]);
const { getTrend } = useHealthStore();
useEffect(() => {
getTrend(indicator, range).then(setPoints);
}, [indicator, range]);
const meta = INDICATOR_META[indicator] || { label: indicator, unit: '' };
const isOutOfRange = (val: number) => {
if (meta.refMin !== undefined && val < meta.refMin) return true;
if (meta.refMax !== undefined && val > meta.refMax) return true;
return false;
};
return (
<View className='trend-page'>
{/* 页面标题 */}
<View className='trend-hero'>
<View className='trend-hero-icon'>
<Text className='trend-hero-icon-text'>T</Text>
</View>
<Text className='trend-hero-title'>{meta.label}</Text>
</View>
{/* 时间范围切换 */}
<View className='trange-wrap'>
{RANGE_OPTIONS.map((opt) => (
<View
key={opt.value}
className={`trange-tab ${range === opt.value ? 'trange-tab-active' : ''}`}
onClick={() => setRange(opt.value)}
>
<Text className={`trange-tab-text ${range === opt.value ? 'trange-tab-text-active' : ''}`}>
{opt.label}
</Text>
</View>
))}
</View>
{/* ECharts 折线图 */}
<View className='trend-chart-card'>
<TrendChart
data={points}
referenceMin={meta.refMin}
referenceMax={meta.refMax}
unit={meta.unit}
/>
</View>
{/* 参考区间 */}
{meta.refMin !== undefined && meta.refMax !== undefined && (
<View className='trend-ref-card'>
<Text className='trend-ref-label'></Text>
<Text className='trend-ref-value'>
{meta.refMin} ~ {meta.refMax} {meta.unit}
</Text>
</View>
)}
{/* 数据列表 */}
{points.length > 0 && (
<View className='trend-list'>
<Text className='trend-list-title'></Text>
{points.slice().reverse().map((p, i) => {
const abnormal = isOutOfRange(p.value);
return (
<View className={`trend-item ${abnormal ? 'trend-item-warn' : ''}`} key={i}>
<View className='trend-item-left'>
<Text className='trend-item-date'>{p.date}</Text>
{abnormal && (
<Text className='trend-item-tag'></Text>
)}
</View>
<Text className={`trend-item-value ${abnormal ? 'trend-item-value-warn' : ''}`}>
{p.value}{meta.unit ? ` ${meta.unit}` : ''}
</Text>
</View>
);
})}
</View>
)}
</View>
);
}