feat(miniapp): 饲养阶段风险提示选择器与展示(#13)
This commit is contained in:
@@ -29,8 +29,23 @@ export interface KnowledgeArticle {
|
||||
sortOrder?: number;
|
||||
}
|
||||
|
||||
export interface StageDiseaseHint {
|
||||
id: string;
|
||||
name: string;
|
||||
reason: string;
|
||||
}
|
||||
|
||||
export interface StageHint {
|
||||
stage: string;
|
||||
label: string;
|
||||
summary: string;
|
||||
diseases: StageDiseaseHint[];
|
||||
}
|
||||
|
||||
export const listDiseases = () => get<Disease[]>('/knowledge/diseases');
|
||||
export const getDisease = (id: string) => get<Disease>(`/knowledge/diseases/${id}`);
|
||||
export const listAIGuides = () => get<KnowledgeArticle[]>('/knowledge/articles', { kind: 'ai_guide' });
|
||||
export const listLAMPGuides = () => get<KnowledgeArticle[]>('/knowledge/articles', { kind: 'lamp_guide' });
|
||||
export const getArticle = (id: string) => get<KnowledgeArticle>(`/knowledge/articles/${id}`);
|
||||
export const getStageHints = (stage?: string) =>
|
||||
get<StageHint[]>('/knowledge/stage-hints', stage ? { stage } : undefined);
|
||||
|
||||
@@ -58,6 +58,78 @@
|
||||
margin: $spacing-lg 0 $spacing-md;
|
||||
}
|
||||
|
||||
.stageChips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: $spacing-sm;
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
.stageChip {
|
||||
padding: 8rpx $spacing-md;
|
||||
border-radius: $radius-round;
|
||||
background: $color-bg-card;
|
||||
border: 1rpx solid rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.stageChipActive {
|
||||
background: $color-primary;
|
||||
border-color: $color-primary;
|
||||
}
|
||||
|
||||
.stageChipText {
|
||||
font-size: $font-size-xs;
|
||||
color: $color-text-secondary;
|
||||
}
|
||||
|
||||
.stageChipActive .stageChipText {
|
||||
color: $color-text-white;
|
||||
}
|
||||
|
||||
.stageHintCard {
|
||||
background: $color-bg-card;
|
||||
border-radius: $radius-md;
|
||||
padding: $spacing-lg;
|
||||
box-shadow: $shadow-card;
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
.stageHintLabel {
|
||||
display: block;
|
||||
font-size: $font-size-md;
|
||||
font-weight: $font-weight-semibold;
|
||||
color: $color-primary;
|
||||
margin-bottom: $spacing-xs;
|
||||
}
|
||||
|
||||
.stageHintSummary {
|
||||
display: block;
|
||||
font-size: $font-size-xs;
|
||||
color: $color-text-secondary;
|
||||
line-height: $line-height-normal;
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
|
||||
.stageDiseaseRow {
|
||||
padding: $spacing-sm 0;
|
||||
border-top: 1rpx solid rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.stageDiseaseName {
|
||||
display: block;
|
||||
font-size: $font-size-md;
|
||||
font-weight: $font-weight-medium;
|
||||
color: $color-text-primary;
|
||||
}
|
||||
|
||||
.stageDiseaseReason {
|
||||
display: block;
|
||||
font-size: $font-size-xs;
|
||||
color: $color-text-secondary;
|
||||
line-height: $line-height-normal;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.diseaseList {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -6,8 +6,10 @@ import {
|
||||
listAIGuides,
|
||||
listLAMPGuides,
|
||||
listDiseases,
|
||||
getStageHints,
|
||||
type Disease,
|
||||
type KnowledgeArticle,
|
||||
type StageHint,
|
||||
} from '@/api/knowledge';
|
||||
|
||||
const GUIDE_LABELS: Record<string, string> = {
|
||||
@@ -15,6 +17,13 @@ const GUIDE_LABELS: Record<string, string> = {
|
||||
lamp_guide: 'LAMP 教程',
|
||||
};
|
||||
|
||||
const STAGE_OPTIONS = [
|
||||
{ key: 'young', label: '小蚕期(1-3龄)' },
|
||||
{ key: 'grown', label: '大蚕期(4-5龄)' },
|
||||
{ key: 'late5', label: '5龄后期' },
|
||||
{ key: 'pupa', label: '蛹期' },
|
||||
];
|
||||
|
||||
const CATEGORY_LABELS: Record<string, string> = {
|
||||
viral: '病毒性',
|
||||
fungal: '真菌性',
|
||||
@@ -27,7 +36,20 @@ const KnowledgePage: React.FC = () => {
|
||||
const [diseases, setDiseases] = useState<Disease[]>([]);
|
||||
const [guides, setGuides] = useState<KnowledgeArticle[]>([]);
|
||||
const [lampGuides, setLampGuides] = useState<KnowledgeArticle[]>([]);
|
||||
const [stage, setStage] = useState('young');
|
||||
const [stageHints, setStageHints] = useState<StageHint[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [stageLoading, setStageLoading] = useState(false);
|
||||
|
||||
const fetchStageHints = useCallback(async (key: string) => {
|
||||
setStageLoading(true);
|
||||
try {
|
||||
const res = await getStageHints(key).catch(() => [] as StageHint[]);
|
||||
setStageHints(res);
|
||||
} finally {
|
||||
setStageLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
try {
|
||||
@@ -54,8 +76,12 @@ const KnowledgePage: React.FC = () => {
|
||||
fetchData();
|
||||
}, [fetchData]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchStageHints(stage);
|
||||
}, [stage, fetchStageHints]);
|
||||
|
||||
usePullDownRefresh(() => {
|
||||
fetchData().then(() => Taro.stopPullDownRefresh());
|
||||
Promise.all([fetchData(), fetchStageHints(stage)]).then(() => Taro.stopPullDownRefresh());
|
||||
});
|
||||
|
||||
const openGuide = (a: KnowledgeArticle) => {
|
||||
@@ -90,6 +116,43 @@ const KnowledgePage: React.FC = () => {
|
||||
</View>
|
||||
))}
|
||||
|
||||
<Text className={styles.sectionTitle}>饲养阶段风险提示</Text>
|
||||
<View className={styles.stageChips}>
|
||||
{STAGE_OPTIONS.map((opt) => (
|
||||
<View
|
||||
key={opt.key}
|
||||
className={`${styles.stageChip} ${stage === opt.key ? styles.stageChipActive : ''}`}
|
||||
onClick={() => setStage(opt.key)}
|
||||
>
|
||||
<Text className={styles.stageChipText}>{opt.label}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
{stageLoading ? (
|
||||
<Text className={styles.emptyText}>加载中...</Text>
|
||||
) : (
|
||||
stageHints.map((h) => (
|
||||
<View key={h.stage} className={styles.stageHintCard}>
|
||||
<Text className={styles.stageHintLabel}>{h.label}</Text>
|
||||
<Text className={styles.stageHintSummary}>{h.summary}</Text>
|
||||
{h.diseases.map((d) => (
|
||||
<View
|
||||
key={d.name}
|
||||
className={styles.stageDiseaseRow}
|
||||
onClick={() => {
|
||||
if (d.id) {
|
||||
Taro.navigateTo({ url: `/pages/knowledge/detail/index?kind=disease&id=${d.id}` });
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Text className={styles.stageDiseaseName}>{d.name}</Text>
|
||||
<Text className={styles.stageDiseaseReason}>{d.reason}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
))
|
||||
)}
|
||||
|
||||
<Text className={styles.sectionTitle}>蚕病百科</Text>
|
||||
<View className={styles.diseaseList}>
|
||||
{diseases.map((d) => (
|
||||
|
||||
Reference in New Issue
Block a user