feat(knowledge): Web 病种图片上传 + 小程序症状图展示
This commit is contained in:
@@ -16,6 +16,7 @@ export interface Disease {
|
||||
recurrence?: string;
|
||||
detection?: string;
|
||||
prevention?: string;
|
||||
imageUrl?: string;
|
||||
sortOrder?: number;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,19 @@
|
||||
padding: $spacing-lg;
|
||||
}
|
||||
|
||||
.imageCard {
|
||||
margin: $spacing-lg $spacing-lg 0;
|
||||
background: $color-bg-card;
|
||||
border-radius: $radius-md;
|
||||
padding: $spacing-md;
|
||||
box-shadow: $shadow-card;
|
||||
}
|
||||
|
||||
.symptomImage {
|
||||
width: 100%;
|
||||
border-radius: $radius-sm;
|
||||
}
|
||||
|
||||
.sectionCard {
|
||||
background: $color-bg-card;
|
||||
border-radius: $radius-md;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { ScrollView, Text, View } from '@tarojs/components';
|
||||
import { Image, ScrollView, Text, View } from '@tarojs/components';
|
||||
import Taro, { useRouter } from '@tarojs/taro';
|
||||
import styles from './index.module.scss';
|
||||
import {
|
||||
@@ -86,6 +86,11 @@ const DetailPage: React.FC = () => {
|
||||
<Text className={styles.heroName}>{disease.name}</Text>
|
||||
<Text className={styles.heroTag}>{CATEGORY_LABELS[disease.category] || disease.category}</Text>
|
||||
</View>
|
||||
{disease.imageUrl ? (
|
||||
<View className={styles.imageCard}>
|
||||
<Image className={styles.symptomImage} src={disease.imageUrl} mode="widthFix" />
|
||||
</View>
|
||||
) : null}
|
||||
<View className={styles.sectionList}>
|
||||
{sections.map((s) => (
|
||||
<View key={s.label} className={styles.sectionCard}>
|
||||
|
||||
@@ -196,6 +196,7 @@ export interface Disease {
|
||||
recurrence?: string;
|
||||
detection?: string;
|
||||
prevention?: string;
|
||||
imageUrl?: string;
|
||||
sortOrder?: number;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,3 +45,9 @@ export const listArticles = (params?: any) => get<KnowledgeArticle[]>('/knowledg
|
||||
export const createArticle = (data: Partial<KnowledgeArticle>) => post<KnowledgeArticle>('/knowledge/articles', data);
|
||||
export const updateArticle = (id: string, data: Partial<KnowledgeArticle>) => patch<KnowledgeArticle>(`/knowledge/articles/${id}`, data);
|
||||
export const deleteArticle = (id: string) => del(`/knowledge/articles/${id}`);
|
||||
|
||||
export const uploadKnowledgeImage = (file: File) => {
|
||||
const fd = new FormData();
|
||||
fd.append('file', file);
|
||||
return post<{ url: string; name: string; size: number }>('/knowledge/images', fd);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import { Button, Form, Input, InputNumber, Modal, Popconfirm, Select, Switch, Tabs, Tag, message } from 'antd';
|
||||
import { Button, Form, Input, InputNumber, Modal, Popconfirm, Select, Switch, Tabs, Tag, Upload, message } from 'antd';
|
||||
import type { UploadFile } from 'antd';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { ProTable, type ActionType, type ProColumns } from '@ant-design/pro-components';
|
||||
import {
|
||||
@@ -11,6 +12,7 @@ import {
|
||||
createArticle,
|
||||
updateArticle,
|
||||
deleteArticle,
|
||||
uploadKnowledgeImage,
|
||||
type Disease,
|
||||
type KnowledgeArticle,
|
||||
} from '../dal/knowledge';
|
||||
@@ -38,6 +40,7 @@ function DiseaseTab() {
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [form] = Form.useForm<Partial<Disease>>();
|
||||
const [editing, setEditing] = useState<Disease | null>(null);
|
||||
const [imageList, setImageList] = useState<UploadFile[]>([]);
|
||||
|
||||
const columns: ProColumns<Disease>[] = [
|
||||
{ title: '序号', valueType: 'indexBorder', search: false, width: 60 },
|
||||
@@ -69,6 +72,9 @@ function DiseaseTab() {
|
||||
onClick={() => {
|
||||
setEditing(r);
|
||||
form.setFieldsValue(r);
|
||||
setImageList(
|
||||
r.imageUrl ? [{ uid: '-1', name: '症状图谱', status: 'done', url: r.imageUrl }] : [],
|
||||
);
|
||||
setModalOpen(true);
|
||||
}}
|
||||
>
|
||||
@@ -97,6 +103,7 @@ function DiseaseTab() {
|
||||
setEditing(null);
|
||||
form.resetFields();
|
||||
form.setFieldsValue({ category: 'viral', enabled: true, sortOrder: 0 });
|
||||
setImageList([]);
|
||||
setModalOpen(true);
|
||||
};
|
||||
|
||||
@@ -147,6 +154,35 @@ function DiseaseTab() {
|
||||
options={Object.entries(CATEGORY_LABELS).map(([value, label]) => ({ value, label }))}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="症状图谱图片">
|
||||
<Upload
|
||||
listType="picture-card"
|
||||
maxCount={1}
|
||||
accept=".jpg,.jpeg,.png,.webp"
|
||||
fileList={imageList}
|
||||
customRequest={async ({ file, onSuccess, onError }) => {
|
||||
try {
|
||||
const res = await uploadKnowledgeImage(file as File);
|
||||
form.setFieldValue('imageUrl', res.url);
|
||||
setImageList([{ uid: '-1', name: res.name, status: 'done', url: res.url }]);
|
||||
onSuccess?.(res);
|
||||
} catch (e) {
|
||||
onError?.(e as Error);
|
||||
}
|
||||
}}
|
||||
onRemove={() => {
|
||||
setImageList([]);
|
||||
form.setFieldValue('imageUrl', undefined);
|
||||
}}
|
||||
>
|
||||
{imageList.length >= 1 ? null : (
|
||||
<div>
|
||||
<PlusOutlined />
|
||||
<div style={{ marginTop: 8 }}>上传图谱</div>
|
||||
</div>
|
||||
)}
|
||||
</Upload>
|
||||
</Form.Item>
|
||||
<Form.Item label="病原" name="pathogen">
|
||||
<Input.TextArea rows={2} />
|
||||
</Form.Item>
|
||||
|
||||
Reference in New Issue
Block a user