diff --git a/apps/miniprogram/src/pages/appointment/detail/index.tsx b/apps/miniprogram/src/pages/appointment/detail/index.tsx
index 3ce7780..ba12997 100644
--- a/apps/miniprogram/src/pages/appointment/detail/index.tsx
+++ b/apps/miniprogram/src/pages/appointment/detail/index.tsx
@@ -17,28 +17,9 @@ export default function AppointmentDetail() {
const id = router.params.id || '';
const [cancelling, setCancelling] = useState(false);
- // 从页面参数或全局缓存获取预约数据
- const encodedData = router.params.data || '';
- let appointment: Appointment | null = null;
- try {
- if (encodedData) {
- appointment = JSON.parse(decodeURIComponent(encodedData));
- }
- } catch {
- // 解析失败则尝试从 Storage 获取
- const cached = Taro.getStorageSync('appointment_detail_cache');
- if (cached && cached.id === id) {
- appointment = cached;
- }
- }
-
- // 如果没有传数据,尝试从缓存获取
- if (!appointment) {
- const cached = Taro.getStorageSync('appointment_detail_cache');
- if (cached && cached.id === id) {
- appointment = cached;
- }
- }
+ // 从缓存获取预约数据
+ const cached = Taro.getStorageSync('appointment_detail_cache');
+ const appointment: Appointment | null = (cached && cached.id === id) ? cached : null;
const status = appointment ? (STATUS_MAP[appointment.status] || { label: appointment.status, className: 'tag-pending' }) : { label: '未知', className: 'tag-pending' };
const canCancel = appointment && (appointment.status === 'pending' || appointment.status === 'confirmed');
diff --git a/apps/miniprogram/src/pages/article/index.tsx b/apps/miniprogram/src/pages/article/index.tsx
index c01020e..c4ad4c0 100644
--- a/apps/miniprogram/src/pages/article/index.tsx
+++ b/apps/miniprogram/src/pages/article/index.tsx
@@ -1,5 +1,5 @@
import React, { useState, useCallback } from 'react';
-import { View, Text } from '@tarojs/components';
+import { View, Text, Image } from '@tarojs/components';
import Taro, { useDidShow, usePullDownRefresh, useReachBottom } from '@tarojs/taro';
import { listArticles, Article } from '../../services/article';
import EmptyState from '../../components/EmptyState';
@@ -74,7 +74,7 @@ export default function ArticleList() {
{a.cover_image && (
-
+
)}
diff --git a/apps/miniprogram/src/pages/followup/detail/index.tsx b/apps/miniprogram/src/pages/followup/detail/index.tsx
index e6bd428..05f9110 100644
--- a/apps/miniprogram/src/pages/followup/detail/index.tsx
+++ b/apps/miniprogram/src/pages/followup/detail/index.tsx
@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
-import { View, Text } from '@tarojs/components';
+import { View, Text, Textarea } from '@tarojs/components';
import Taro, { useRouter } from '@tarojs/taro';
import { listTasks, submitRecord, FollowUpTask } from '../../../services/followup';
import './index.scss';
@@ -97,7 +97,7 @@ export default function FollowUpDetail() {
{!isCompleted && (
填写随访记录
-
-
- 数值
- setValue(e.detail.value)}
- />
-
+ {INDICATORS[indicatorIdx].value === 'blood_pressure' ? (
+ <>
+
+ 收缩压
+ setSystolic(e.detail.value)}
+ />
+
+
+ 舒张压
+ setDiastolic(e.detail.value)}
+ />
+
+ >
+ ) : (
+
+ 数值
+ setValue(e.detail.value)}
+ />
+
+ )}
备注(可选)
diff --git a/apps/miniprogram/src/pages/index/index.tsx b/apps/miniprogram/src/pages/index/index.tsx
index c7dc16c..f768469 100644
--- a/apps/miniprogram/src/pages/index/index.tsx
+++ b/apps/miniprogram/src/pages/index/index.tsx
@@ -1,16 +1,21 @@
import { View, Text } from '@tarojs/components';
import Taro, { useDidShow } from '@tarojs/taro';
import { useAuthStore } from '../../stores/auth';
+import { useHealthStore } from '../../stores/health';
import EmptyState from '../../components/EmptyState';
import './index.scss';
export default function Index() {
const { user, restore } = useAuthStore();
+ const { todaySummary, refreshToday } = useHealthStore();
useDidShow(() => {
restore();
+ refreshToday();
});
+ const s = todaySummary || {};
+
const greeting = () => {
const h = new Date().getHours();
if (h < 6) return '凌晨好';
@@ -38,10 +43,10 @@ export default function Index() {
今日健康
{[
- { label: '血压', value: '--/--', unit: 'mmHg', status: '' },
- { label: '心率', value: '--', unit: 'bpm', status: '' },
- { label: '血糖', value: '--', unit: 'mmol/L', status: '' },
- { label: '体重', value: '--', unit: 'kg', status: '' },
+ { label: '血压', value: s.blood_pressure ? `${s.blood_pressure.systolic}/${s.blood_pressure.diastolic}` : '--/--', unit: 'mmHg' },
+ { label: '心率', value: s.heart_rate ? `${s.heart_rate.value}` : '--', unit: 'bpm' },
+ { label: '血糖', value: s.blood_sugar ? `${s.blood_sugar.value}` : '--', unit: 'mmol/L' },
+ { label: '体重', value: s.weight ? `${s.weight.value}` : '--', unit: 'kg' },
].map((item) => (
{item.label}
@@ -57,15 +62,21 @@ export default function Index() {
快捷服务
{[
- { label: '录数据', icon: '📝', path: '/pages/health/index' },
- { label: '预约', icon: '📅', path: '/pages/appointment/index' },
- { label: '报告', icon: '📋', path: '/pages/profile/index' },
- { label: '随访', icon: '💬', path: '/pages/profile/index' },
+ { label: '录数据', icon: '📝', path: '/pages/health/index', isTab: true },
+ { label: '预约', icon: '📅', path: '/pages/appointment/index', isTab: true },
+ { label: '报告', icon: '📋', path: '/pages/report/index', isTab: false },
+ { label: '随访', icon: '💬', path: '/pages/followup/index', isTab: false },
].map((item) => (
Taro.switchTab({ url: item.path })}
+ onClick={() => {
+ if (item.isTab) {
+ Taro.switchTab({ url: item.path });
+ } else {
+ Taro.navigateTo({ url: item.path });
+ }
+ }}
>
{item.icon}
{item.label}
diff --git a/apps/miniprogram/src/pages/login/index.tsx b/apps/miniprogram/src/pages/login/index.tsx
index 6079b77..43d4934 100644
--- a/apps/miniprogram/src/pages/login/index.tsx
+++ b/apps/miniprogram/src/pages/login/index.tsx
@@ -6,7 +6,6 @@ import './index.scss';
export default function Login() {
const [needBind, setNeedBind] = useState(false);
- const [openid, setOpenid] = useState('');
const { login, bindPhone, loading } = useAuthStore();
const handleWechatLogin = async () => {
@@ -16,11 +15,10 @@ export default function Login() {
if (success) {
Taro.switchTab({ url: '/pages/index/index' });
} else {
- // 未绑定,需要获取手机号
+ // 未绑定,需要获取手机号(openid 已由 store 缓存到 Storage)
setNeedBind(true);
- // 从最近的登录响应获取 openid(简化处理)
}
- } catch (e: any) {
+ } catch {
Taro.showToast({ title: '登录失败', icon: 'none' });
}
};
@@ -31,7 +29,7 @@ export default function Login() {
return;
}
const { encryptedData, iv } = e.detail;
- const success = await bindPhone(openid, encryptedData, iv);
+ const success = await bindPhone(encryptedData, iv);
if (success) {
Taro.switchTab({ url: '/pages/index/index' });
} else {
diff --git a/apps/miniprogram/src/pages/profile/family-add/index.tsx b/apps/miniprogram/src/pages/profile/family-add/index.tsx
index 08e0197..02c352d 100644
--- a/apps/miniprogram/src/pages/profile/family-add/index.tsx
+++ b/apps/miniprogram/src/pages/profile/family-add/index.tsx
@@ -1,7 +1,6 @@
import React, { useState } from 'react';
-import { View, Text } from '@tarojs/components';
+import { View, Text, Input, Picker } from '@tarojs/components';
import Taro from '@tarojs/taro';
-import { Picker } from '@tarojs/components';
import { createPatient } from '../../../services/patient';
import './index.scss';
@@ -44,7 +43,7 @@ export default function FamilyAdd() {
{/* 姓名 */}
姓名
-
{tasks.length === 0 && !loading && (
-
- 暂无{(() => {
- const tab = TABS.find((t) => t.key === activeTab);
- return tab ? tab.label : '';
- })()}任务
-
+ {
+ const tab = TABS.find((t) => t.key === activeTab);
+ return tab ? tab.label : '';
+ })()}任务`} />
)}
{loading && (
-
- 加载中...
-
+
)}
);
diff --git a/apps/miniprogram/src/pages/profile/medication/index.tsx b/apps/miniprogram/src/pages/profile/medication/index.tsx
index fe808fc..9145049 100644
--- a/apps/miniprogram/src/pages/profile/medication/index.tsx
+++ b/apps/miniprogram/src/pages/profile/medication/index.tsx
@@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react';
-import { View, Text } from '@tarojs/components';
+import { View, Text, Input } from '@tarojs/components';
import Taro from '@tarojs/taro';
+import EmptyState from '../../../components/EmptyState';
import './index.scss';
interface MedicationReminder {
@@ -105,9 +106,7 @@ export default function MedicationReminder() {
{reminders.length === 0 && (
-
- 暂无用药提醒
-
+
)}
{/* 添加表单 */}
@@ -115,7 +114,7 @@ export default function MedicationReminder() {
药品名称
-
剂量
- (`/health/appointments?page=${page}&page_size=20`);
}
@@ -34,17 +49,17 @@ export async function cancelAppointment(id: string, version: number) {
}
export async function getDoctorSchedules(doctorId: string, startDate: string, endDate: string) {
- return api.get<{ data: any[]; total: number }>(
+ return api.get<{ data: DoctorSchedule[]; total: number }>(
`/health/doctor-schedules?doctor_id=${doctorId}&start_date=${startDate}&end_date=${endDate}&page_size=50`
);
}
export async function listDoctors(department?: string) {
const deptParam = department ? `&department=${department}` : '';
- return api.get<{ data: any[]; total: number }>(`/health/doctors?page_size=100${deptParam}`);
+ return api.get<{ data: Doctor[]; total: number }>(`/health/doctors?page_size=100${deptParam}`);
}
export async function calendarView(startDate: string, endDate: string, doctorId?: string) {
const docParam = doctorId ? `&doctor_id=${doctorId}` : '';
- return api.get(`/health/doctor-schedules/calendar?start_date=${startDate}&end_date=${endDate}${docParam}`);
+ return api.get(`/health/doctor-schedules/calendar?start_date=${startDate}&end_date=${endDate}${docParam}`);
}
diff --git a/apps/miniprogram/src/services/article.ts b/apps/miniprogram/src/services/article.ts
index 4b5ebe5..17c12d1 100644
--- a/apps/miniprogram/src/services/article.ts
+++ b/apps/miniprogram/src/services/article.ts
@@ -8,6 +8,7 @@ export interface Article {
cover_image?: string;
category?: string;
published_at?: string;
+ author?: string;
}
export async function listArticles(page = 1) {
diff --git a/apps/miniprogram/src/services/followup.ts b/apps/miniprogram/src/services/followup.ts
index 1a7734d..ea2fd20 100644
--- a/apps/miniprogram/src/services/followup.ts
+++ b/apps/miniprogram/src/services/followup.ts
@@ -10,10 +10,15 @@ export interface FollowUpTask {
version: number;
}
+export interface FollowUpContent {
+ text: string;
+ [key: string]: string;
+}
+
export interface FollowUpRecord {
id: string;
task_id: string;
- content: any;
+ content: FollowUpContent;
created_at: string;
}
@@ -24,7 +29,7 @@ export async function listTasks(status?: string) {
);
}
-export async function submitRecord(data: { task_id: string; content: any }) {
+export async function submitRecord(data: { task_id: string; content: FollowUpContent }) {
return api.post('/health/follow-up-records', data);
}
diff --git a/apps/miniprogram/src/services/health.ts b/apps/miniprogram/src/services/health.ts
index 064f2e2..6d5e17c 100644
--- a/apps/miniprogram/src/services/health.ts
+++ b/apps/miniprogram/src/services/health.ts
@@ -5,6 +5,7 @@ export interface VitalSignInput {
value: number;
measured_at?: string;
note?: string;
+ extra?: Record;
}
export interface TodaySummary {
diff --git a/apps/miniprogram/src/services/patient.ts b/apps/miniprogram/src/services/patient.ts
index f53d6f2..438b424 100644
--- a/apps/miniprogram/src/services/patient.ts
+++ b/apps/miniprogram/src/services/patient.ts
@@ -25,6 +25,15 @@ export async function createPatient(data: {
return api.post('/health/patients', data);
}
-export async function updatePatient(id: string, data: any, version: number) {
+export interface PatientUpdateInput {
+ name?: string;
+ gender?: string;
+ birthday?: string;
+ phone?: string;
+ id_number?: string;
+ relation?: string;
+}
+
+export async function updatePatient(id: string, data: PatientUpdateInput, version: number) {
return api.put(`/health/patients/${id}`, { ...data, version });
}
diff --git a/apps/miniprogram/src/services/report.ts b/apps/miniprogram/src/services/report.ts
index ae18ed6..195ca4c 100644
--- a/apps/miniprogram/src/services/report.ts
+++ b/apps/miniprogram/src/services/report.ts
@@ -1,10 +1,18 @@
import { api } from './request';
+export interface IndicatorDetail {
+ value: number;
+ unit?: string;
+ reference_min?: number;
+ reference_max?: number;
+ status?: string;
+}
+
export interface LabReport {
id: string;
report_date: string;
report_type: string;
- indicators: any;
+ indicators: Record;
doctor_interpretation?: string;
image_urls?: string[];
version: number;
diff --git a/apps/miniprogram/src/stores/auth.ts b/apps/miniprogram/src/stores/auth.ts
index ef85d6a..6450ead 100644
--- a/apps/miniprogram/src/stores/auth.ts
+++ b/apps/miniprogram/src/stores/auth.ts
@@ -2,6 +2,12 @@ import { create } from 'zustand';
import Taro from '@tarojs/taro';
import * as authApi from '../services/auth';
+interface BindPhoneResp {
+ access_token: string;
+ refresh_token: string;
+ user: { id: string; username: string; display_name?: string; phone?: string; tenant_id?: string };
+}
+
interface AuthState {
token: string | null;
refreshToken: string | null;
@@ -11,7 +17,7 @@ interface AuthState {
loading: boolean;
login: (code: string) => Promise;
- bindPhone: (openid: string, encryptedData: string, iv: string) => Promise;
+ bindPhone: (encryptedData: string, iv: string) => Promise;
setCurrentPatient: (patient: authApi.PatientInfo) => void;
loadPatients: () => Promise;
logout: () => void;
@@ -47,6 +53,8 @@ export const useAuthStore = create((set, get) => ({
set({ token: access_token, refreshToken: refresh_token, user, loading: false });
return true;
}
+ // 未绑定手机号,缓存 openid 供后续 bindPhone 使用
+ Taro.setStorageSync('wechat_openid', resp.openid);
set({ loading: false });
return false;
} catch {
@@ -55,14 +63,21 @@ export const useAuthStore = create((set, get) => ({
}
},
- bindPhone: async (openid: string, encryptedData: string, iv: string) => {
+ bindPhone: async (encryptedData: string, iv: string) => {
set({ loading: true });
try {
- const resp: any = await authApi.wechatBindPhone(openid, encryptedData, iv);
+ const openid = Taro.getStorageSync('wechat_openid') || '';
+ if (!openid) {
+ set({ loading: false });
+ return false;
+ }
+ const resp = await authApi.wechatBindPhone(openid, encryptedData, iv) as BindPhoneResp;
const { access_token, refresh_token, user } = resp;
Taro.setStorageSync('access_token', access_token);
Taro.setStorageSync('refresh_token', refresh_token);
Taro.setStorageSync('user', user);
+ Taro.setStorageSync('tenant_id', user.tenant_id || '');
+ Taro.removeStorageSync('wechat_openid');
set({ token: access_token, refreshToken: refresh_token, user, loading: false });
return true;
} catch {