Browse Source

代码提交

837390164@qq.com 4 months ago
parent
commit
6bbd10dec5
4 changed files with 747 additions and 6 deletions
  1. 81 1
      src/api/basicData.ts
  2. 1 0
      src/api/logon.ts
  3. 3 0
      src/api/request.ts
  4. 662 5
      src/pages/BasicData/CoreAlgorithmConfig.tsx

+ 81 - 1
src/api/basicData.ts

@@ -657,19 +657,28 @@ export interface HospitalInfoItem {
   descriptsSPCode: string;
   MedinsLv?: string;
   medinsLv?: string;
+  provinceId?: string;  // 省的id
+  cityId?: string;      // 市的id
 }
 
 /** 查询医疗机构参数 */
 export interface QueryHospitalInfoParams {
   active: string;
   descripts: string;
+  provinceID?: string;  // 省代码,用于过滤
+  cityID?: string;     // 市代码,用于过滤
 }
 
 /** 查询医疗机构信息 (01010064) */
 export const queryHospitalInfo = (
   params: QueryHospitalInfoParams
 ): Promise<ApiResponse<HospitalInfoItem[]>> => {
-  return invoke('01010064', [params]);
+  return invoke('01010064', [{
+    active: params.active,
+    descripts: params.descripts,
+    provinceID: params.provinceID || '',
+    cityID: params.cityID || ''
+  }]);
 };
 
 // ========== ICD编码导入 (02010038, 02010039, 02010040) ==========
@@ -914,3 +923,74 @@ export const deleteHBDRGSegmentationRules = (
 ): Promise<ApiResponse> => {
   return invoke('02010046', [{ id }]);
 };
+
+// ========== DRG核心算法配置导入 (02010050, 02010051, 02010052) ==========
+
+/** DRG核心算法导入预览数据项 */
+export interface DrgCoreAlgorithmImportPreviewItem {
+  rowNum: number;
+  drgCode: string;
+  drgDesc: string;
+  points: string;
+  pipValue: string;
+  dgdov: string;
+  payStandard: string;
+  status: 'valid' | 'duplicate' | 'invalid';
+  statusDesc: string;
+  errorMsg?: string;
+}
+
+/** DRG核心算法导入预览结果 */
+export interface DrgCoreAlgorithmImportPreviewResult {
+  totalCount: number;
+  validCount: number;
+  invalidCount: number;
+  duplicateCount: number;
+  previewList: DrgCoreAlgorithmImportPreviewItem[];
+}
+
+/** DRG核心算法导入结果 */
+export interface DrgCoreAlgorithmImportResult {
+  totalCount: number;
+  successCount: number;
+  failCount: number;
+  duplicateCount: number;
+  newCount: number;
+  failList: Array<{
+    rowNum: number;
+    drgCode: string;
+    errorMsg: string;
+  }>;
+  reportUrl?: string;
+}
+
+/** DRG核心算法导入参数 */
+export interface DrgCoreAlgorithmImportParams {
+  provinceID: string;
+  cityID: string;
+  mdtrtArea: string;        // 行政区划代码(来自市的code)
+  fixmedinsCode: string;   // 医疗机构代码(来自医疗机构的OrganizationCode)
+  fixmedinsName: string;  // 医疗机构名称(来自医疗机构的Descripts)
+  medinsLv: string;        // 机构等级(来自医疗机构的HospGrade_Dr)
+  fileData: string;
+  fileName: string;
+}
+
+/** 下载DRG核心算法配置导入模板 (02010052) */
+export const downloadDrgCoreAlgorithmTemplate = (): Promise<ApiResponse<{ fileName: string; fileData: string; contentType: string }>> => {
+  return invoke('02010052', []);
+};
+
+/** DRG核心算法配置导入预览 (02010050) */
+export const previewDrgCoreAlgorithmImport = (
+  params: DrgCoreAlgorithmImportParams
+): Promise<ApiResponse<DrgCoreAlgorithmImportPreviewResult>> => {
+  return invoke('02010050', [params]);
+};
+
+/** DRG核心算法配置确认导入 (02010051) */
+export const confirmDrgCoreAlgorithmImport = (
+  params: DrgCoreAlgorithmImportParams
+): Promise<ApiResponse<DrgCoreAlgorithmImportResult>> => {
+  return invoke('02010051', [params]);
+};

+ 1 - 0
src/api/logon.ts

@@ -64,6 +64,7 @@ export interface LogonResult {
   provID:string;
   cityID:string;
   areaCode:string;
+  medinsLv:string;
   path?: string;
   sessionID: string;
   errorMessageTime?: string;

+ 3 - 0
src/api/request.ts

@@ -57,6 +57,7 @@ export interface SessionInfo {
   provID: string;
   cityID: string;
   areaCode:string;
+  medinsLv:string;
   path: string;
   sessionID: string;
   errorMessageTime: string;
@@ -98,6 +99,7 @@ export const getDefaultSession = (): SessionInfo => {
         provID: session.provID || '',
         cityID: session.cityID || '',
         areaCode: session.areaCode || '',
+        medinsLv:session.medinsLv || '',
         path: session.path || '',
         sessionID: session.sessionID || '',
         errorMessageTime: session.errorMessageTime || '',
@@ -135,6 +137,7 @@ export const getDefaultSession = (): SessionInfo => {
     provID: '',
     cityID: '',
     areaCode:'',
+    medinsLv:'',
     path: '',
     sessionID: '',
     errorMessageTime: '',

+ 662 - 5
src/pages/BasicData/CoreAlgorithmConfig.tsx

@@ -1,16 +1,29 @@
-import React, { useState, useEffect, useCallback } from 'react';
+import React, { useState, useEffect, useCallback, useRef } from 'react';
 import {
   Card, Table, Button, Input, Select, Space, Modal, Form,
-  Row, Col, Tag, message, Popconfirm, DatePicker
+  Row, Col, Tag, message, Popconfirm, DatePicker, Upload,
+  Steps, Alert, Statistic, Divider, Typography, List, Result, Modal as ImportModal
 } from 'antd';
-import { PlusOutlined, SearchOutlined, ReloadOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons';
+import {
+  PlusOutlined, SearchOutlined, ReloadOutlined, DeleteOutlined, EditOutlined,
+  UploadOutlined, DownloadOutlined, EyeOutlined, FileTextOutlined,
+  CheckCircleOutlined, CloseCircleOutlined, WarningOutlined,
+  FileExcelOutlined, ArrowRightOutlined, ArrowLeftOutlined
+} from '@ant-design/icons';
 import type { ColumnsType } from 'antd/es/table';
+import type { UploadFile } from 'antd/es/upload/interface';
 import dayjs from 'dayjs';
 import {
   queryCoreAlgorithm, saveCoreAlgorithm, deleteCoreAlgorithm,
   getProvinceData, getCityData, queryHospitalInfo,
+  downloadDrgCoreAlgorithmTemplate,
+  previewDrgCoreAlgorithmImport,
+  confirmDrgCoreAlgorithmImport,
   type CoreAlgorithmItem, type SaveCoreAlgorithmParams,
-  type ProvinceItem, type CityItem, type HospitalInfoItem
+  type ProvinceItem, type CityItem, type HospitalInfoItem,
+  type DrgCoreAlgorithmImportPreviewItem,
+  type DrgCoreAlgorithmImportResult,
+  type DrgCoreAlgorithmImportParams
 } from '../../api/basicData';
 import CustomPagination from '../../components/CustomPagination';
 
@@ -53,6 +66,33 @@ const CoreAlgorithmConfig: React.FC = () => {
   const [queryCityLoading, setQueryCityLoading] = useState(false);
   const [queryHospitalLoading, setQueryHospitalLoading] = useState(false);
 
+  // ==================== 导入功能状态 ====================
+  // 导入弹窗显示状态
+  const [importModalVisible, setImportModalVisible] = useState(false);
+  // 当前步骤(0:上传, 1:预览, 2:结果)
+  const [importStep, setImportStep] = useState(0);
+  // 导入加载状态
+  const [importLoading, setImportLoading] = useState(false);
+  // 导入表单
+  const [importForm] = Form.useForm();
+  // 导入省市选择
+  const [importProvinceList, setImportProvinceList] = useState<ProvinceItem[]>([]);
+  const [importCityList, setImportCityList] = useState<CityItem[]>([]);
+  const [importHospitalList, setImportHospitalList] = useState<HospitalInfoItem[]>([]);
+  const [importProvinceLoading, setImportProvinceLoading] = useState(false);
+  const [importCityLoading, setImportCityLoading] = useState(false);
+  const [importHospitalLoading, setImportHospitalLoading] = useState(false);
+  // 上传文件列表
+  const [fileList, setFileList] = useState<UploadFile[]>([]);
+  // 预览数据
+  const [previewData, setPreviewData] = useState<DrgCoreAlgorithmImportPreviewItem[]>([]);
+  const [previewStats, setPreviewStats] = useState({ total: 0, valid: 0, invalid: 0, duplicate: 0 });
+  // 导入结果
+  const [importResult, setImportResult] = useState<DrgCoreAlgorithmImportResult | null>(null);
+  // 当前文件内容(Base64)
+  const fileContentRef = useRef<string>('');
+  const fileNameRef = useRef<string>('');
+
   // 固定险种选项
   const insuTypeOptions = [
     { code: '310', name: '职工' },
@@ -157,6 +197,291 @@ const CoreAlgorithmConfig: React.FC = () => {
     setStatus('');
   };
 
+  // ==================== 导入功能方法 ====================
+
+  // 打开导入弹窗
+  const handleOpenImport = async () => {
+    setImportModalVisible(true);
+    setImportStep(0);
+    setFileList([]);
+    setPreviewData([]);
+    setImportResult(null);
+    importForm.resetFields();
+    fileContentRef.current = '';
+    fileNameRef.current = '';
+
+    // 清空省市列表
+    setImportCityList([]);
+    setImportHospitalList([]);
+
+    // 加载省下拉数据
+    setImportProvinceLoading(true);
+    try {
+      const res = await getProvinceData();
+      if (res.errorCode === '0' && res.result) {
+        setImportProvinceList(res.result);
+      }
+    } finally {
+      setImportProvinceLoading(false);
+    }
+  };
+
+  // 导入弹窗省选择变化
+  const handleImportProvinceChange = (value: string) => {
+    importForm.setFieldsValue({
+      importProvinceId: value,
+      importCityId: undefined,
+      importHospitalId: undefined,
+    });
+    setImportCityList([]);
+    setImportHospitalList([]);
+
+    if (!value) {
+      return;
+    }
+    const fetchCityData = async () => {
+      setImportCityLoading(true);
+      try {
+        const res = await getCityData(value);
+        if (res.errorCode === '0' && res.result) {
+          setImportCityList(res.result);
+        }
+      } finally {
+        setImportCityLoading(false);
+      }
+    };
+    fetchCityData();
+  };
+
+  // 导入弹窗市选择变化 - 根据省市过滤医疗机构
+  const handleImportCityChange = (value: string) => {
+    importForm.setFieldsValue({
+      importHospitalId: undefined,
+    });
+    setImportHospitalList([]);
+
+    const provinceId = importForm.getFieldValue('importProvinceId');
+    if (!value || !provinceId) {
+      return;
+    }
+    const fetchFilteredHospitalData = async () => {
+      setImportHospitalLoading(true);
+      try {
+        // 直接传入省市的id进行过滤
+        const res = await queryHospitalInfo({
+          active: 'Y',
+          descripts: '',
+          provinceID: provinceId,
+          cityID: value
+        });
+        if (res.errorCode === '0' && res.result) {
+          setImportHospitalList(res.result);
+        }
+      } finally {
+        setImportHospitalLoading(false);
+      }
+    };
+    fetchFilteredHospitalData();
+  };
+
+  // 导入弹窗医疗机构选择变化 - 填充机构信息
+  const handleImportHospitalChange = (value: string) => {
+    const selected = importHospitalList.find(h => h.code === value);
+    if (selected) {
+      importForm.setFieldsValue({
+        importHospitalId: value,
+      });
+    } else {
+      importForm.setFieldsValue({
+        importHospitalId: undefined,
+      });
+    }
+  };
+
+  // 下载导入模板
+  const handleDownloadTemplate = async () => {
+    try {
+      const res = await downloadDrgCoreAlgorithmTemplate();
+      if (res.errorCode === '0' && res.result) {
+        // Base64解码并下载
+        const byteString = atob(res.result.fileData);
+        const ab = new ArrayBuffer(byteString.length);
+        const ia = new Uint8Array(ab);
+        for (let i = 0; i < byteString.length; i++) {
+          ia[i] = byteString.charCodeAt(i);
+        }
+        const blob = new Blob([ab], { type: res.result.contentType || 'text/csv' });
+        const url = URL.createObjectURL(blob);
+        const link = document.createElement('a');
+        link.href = url;
+        link.download = res.result.fileName;
+        document.body.appendChild(link);
+        link.click();
+        document.body.removeChild(link);
+        URL.revokeObjectURL(url);
+        message.success('模板下载成功');
+      } else {
+        message.error(res.errorMessage || '下载模板失败');
+      }
+    } catch (error: any) {
+      message.error('下载模板失败:' + (error.message || '网络异常'));
+    }
+  };
+
+  // 文件上传前处理
+  const beforeUpload = (file: UploadFile) => {
+    const rawFile = file.originFileObj || file;
+    const isExcel = rawFile.type === 'application/vnd.open-excel' ||
+                    rawFile.type === 'application/vnd.ms-excel' ||
+                    rawFile.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
+                    rawFile.name?.endsWith('.csv');
+    if (!isExcel) {
+      message.error('请上传Excel或CSV文件!');
+      return false;
+    }
+    const isLt10M = (rawFile.size || 0) / 1024 / 1024 < 10;
+    if (!isLt10M) {
+      message.error('文件大小不能超过10MB!');
+      return false;
+    }
+
+    // 读取文件内容为Base64(正确处理中文字符)
+    const reader = new FileReader();
+    reader.onload = (e) => {
+      const arrayBuffer = e.target?.result as ArrayBuffer;
+      const bytes = new Uint8Array(arrayBuffer);
+      let binary = '';
+      for (let i = 0; i < bytes.byteLength; i++) {
+        binary += String.fromCharCode(bytes[i]);
+      }
+      const base64Content = btoa(binary);
+      fileContentRef.current = base64Content;
+      fileNameRef.current = rawFile.name || '';
+    };
+    reader.readAsArrayBuffer(rawFile as Blob);
+
+    setFileList([file]);
+    return false; // 阻止自动上传
+  };
+
+  // 预览导入数据
+  const handlePreviewImport = async () => {
+    const values = importForm.getFieldsValue();
+    if (!values.importProvinceId) {
+      message.error('请先选择省');
+      return;
+    }
+    if (!values.importCityId) {
+      message.error('请先选择市');
+      return;
+    }
+    if (!values.importHospitalId) {
+      message.error('请先选择医疗机构');
+      return;
+    }
+    if (fileList.length === 0) {
+      message.error('请先上传导入文件');
+      return;
+    }
+
+    // 获取市的信息
+    const selectedCity = importCityList.find(c => c.id === values.importCityId);
+
+    const params: DrgCoreAlgorithmImportParams = {
+      provinceID: values.importProvinceId,
+      cityID: values.importCityId,
+      mdtrtArea: selectedCity?.code || '',          // 市的code作为MdtrtArea
+      fixmedinsCode: values.importHospitalId,       // 医疗机构的code
+      fixmedinsName: '', // 医疗机构名称由后端填充
+      medinsLv: '', // 机构等级由后端填充
+      fileData: fileContentRef.current,
+      fileName: fileNameRef.current
+    };
+
+    try {
+      setImportLoading(true);
+      const res = await previewDrgCoreAlgorithmImport(params);
+
+      if (res.errorCode === '0' && res.result) {
+        setPreviewData(res.result.previewList || []);
+        setPreviewStats({
+          total: res.result.totalCount,
+          valid: res.result.validCount,
+          invalid: res.result.invalidCount,
+          duplicate: res.result.duplicateCount
+        });
+        setImportStep(1);
+      } else {
+        message.error(res.errorMessage || '预览失败');
+      }
+    } catch (error: any) {
+      message.error('预览失败:' + (error.message || '网络异常'));
+    } finally {
+      setImportLoading(false);
+    }
+  };
+
+  // 确认导入
+  const handleConfirmImport = async () => {
+    const values = importForm.getFieldsValue();
+
+    // 验证省市和医疗机构是否已选择
+    if (!values.importProvinceId) {
+      message.error('请先选择省');
+      return;
+    }
+    if (!values.importCityId) {
+      message.error('请先选择市');
+      return;
+    }
+    if (!values.importHospitalId) {
+      message.error('请先选择医疗机构');
+      return;
+    }
+
+    // 获取市的信息
+    const selectedCity = importCityList.find(c => c.id === values.importCityId);
+
+    const params: DrgCoreAlgorithmImportParams = {
+      provinceID: String(values.importProvinceId),
+      cityID: String(values.importCityId),
+      mdtrtArea: selectedCity?.code || '',
+      fixmedinsCode: String(values.importHospitalId),
+      fixmedinsName: '',
+      medinsLv: '',
+      fileData: fileContentRef.current,
+      fileName: fileNameRef.current
+    };
+
+    try {
+      setImportLoading(true);
+      const res = await confirmDrgCoreAlgorithmImport(params);
+
+      if (res.result) {
+        setImportResult(res.result);
+        setImportStep(2);
+        // 刷新列表数据
+        fetchData(1, pageSize);
+      } else {
+        message.error(res.errorMessage || '导入失败');
+      }
+    } catch (error: any) {
+      message.error('导入失败:' + (error.message || '网络异常'));
+    } finally {
+      setImportLoading(false);
+    }
+  };
+
+  // 关闭导入弹窗
+  const handleCloseImport = () => {
+    setImportModalVisible(false);
+    setImportStep(0);
+    setFileList([]);
+    setPreviewData([]);
+    setImportResult(null);
+    importForm.resetFields();
+  };
+
   // 获取省下拉数据
   const fetchProvinceData = async () => {
     setProvinceLoading(true);
@@ -450,6 +775,37 @@ const CoreAlgorithmConfig: React.FC = () => {
     },
   ];
 
+  // 预览表格列定义
+  const previewColumns: ColumnsType<DrgCoreAlgorithmImportPreviewItem> = [
+    { title: '行号', dataIndex: 'rowNum', width: 60 },
+    { title: 'DRG代码', dataIndex: 'drgCode', width: 100 },
+    { title: 'DRG描述', dataIndex: 'drgDesc', ellipsis: true },
+    { title: '基准点数', dataIndex: 'points', width: 90, align: 'right' },
+    { title: '预估点值', dataIndex: 'pipValue', width: 90, align: 'right' },
+    { title: '差异系数', dataIndex: 'dgdov', width: 80, align: 'right' },
+    { title: '支付标准', dataIndex: 'payStandard', width: 90, align: 'right' },
+    {
+      title: '状态',
+      dataIndex: 'status',
+      width: 80,
+      render: (status: string) => {
+        if (status === 'valid') {
+          return <Tag color="success" icon={<CheckCircleOutlined />}>正常</Tag>;
+        } else if (status === 'duplicate') {
+          return <Tag color="warning" icon={<WarningOutlined />}>重复</Tag>;
+        } else {
+          return <Tag color="error" icon={<CloseCircleOutlined />}>错误</Tag>;
+        }
+      }
+    },
+    {
+      title: '备注',
+      dataIndex: 'errorMsg',
+      ellipsis: true,
+      render: (text: string) => text || '-'
+    }
+  ];
+
   return (
     <div style={{ padding: 16 }}>
       {/* 查询条件 */}
@@ -558,7 +914,10 @@ const CoreAlgorithmConfig: React.FC = () => {
       {/* 工具栏 + 表格 */}
       <Card size="small">
         <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 12 }}>
-          <Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>新增配置</Button>
+          <Space>
+            <Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>新增配置</Button>
+            <Button type="primary" icon={<UploadOutlined />} onClick={handleOpenImport}>导入</Button>
+          </Space>
           <span>共 {total} 条记录</span>
         </div>
         <Table
@@ -784,6 +1143,304 @@ const CoreAlgorithmConfig: React.FC = () => {
           </Card>
         </Form>
       </Modal>
+
+      {/* 导入弹窗 */}
+      <ImportModal
+        title="DRG核心算法配置导入"
+        open={importModalVisible}
+        onCancel={handleCloseImport}
+        width={850}
+        footer={null}
+        destroyOnClose
+      >
+        <Steps
+          current={importStep}
+          style={{ marginBottom: 24 }}
+          items={[
+            { title: '上传文件', icon: <UploadOutlined /> },
+            { title: '数据预览', icon: <EyeOutlined /> },
+            { title: '导入结果', icon: <CheckCircleOutlined /> }
+          ]}
+        />
+
+        {/* 步骤1:上传文件 */}
+        {importStep === 0 && (
+          <div>
+            <Alert
+              message="导入前请先选择省市和医疗机构"
+              description="导入的DRG算法配置将归属到选定的省、市和医疗机构,请仔细确认。"
+              type="warning"
+              showIcon
+              style={{ marginBottom: 16 }}
+            />
+            <Form form={importForm} layout="vertical">
+              <Row gutter={16}>
+                <Col span={8}>
+                  <Form.Item
+                    name="importProvinceId"
+                    label="省"
+                    rules={[{ required: true, message: '请选择省' }]}
+                  >
+                    <Select
+                      placeholder="请选择省"
+                      loading={importProvinceLoading}
+                      showSearch
+                      optionFilterProp="children"
+                      onChange={handleImportProvinceChange}
+                    >
+                      {importProvinceList.map(item => (
+                        <Option key={item.id} value={item.id}>{item.descripts}</Option>
+                      ))}
+                    </Select>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item
+                    name="importCityId"
+                    label="市"
+                    rules={[{ required: true, message: '请选择市' }]}
+                  >
+                    <Select
+                      placeholder="请选择市"
+                      loading={importCityLoading}
+                      showSearch
+                      optionFilterProp="children"
+                      onChange={handleImportCityChange}
+                      disabled={!importForm.getFieldValue('importProvinceId')}
+                    >
+                      {importCityList.map(item => (
+                        <Option key={item.id} value={item.id}>{item.descripts}</Option>
+                      ))}
+                    </Select>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item
+                    name="importHospitalId"
+                    label="医疗机构"
+                    rules={[{ required: true, message: '请选择医疗机构' }]}
+                  >
+                    <Select
+                      placeholder="请选择医疗机构"
+                      loading={importHospitalLoading}
+                      showSearch
+                      optionFilterProp="children"
+                      onChange={handleImportHospitalChange}
+                      filterOption={(input, option) =>
+                        (option?.children as unknown as string)?.toLowerCase().includes(input.toLowerCase())
+                      }
+                      disabled={!importForm.getFieldValue('importProvinceId') || !importForm.getFieldValue('importCityId')}
+                    >
+                      {importHospitalList.map(item => (
+                        <Option key={item.code} value={item.code}>
+                          {item.descripts} ({item.code})
+                        </Option>
+                      ))}
+                    </Select>
+                  </Form.Item>
+                </Col>
+              </Row>
+
+              <Divider />
+
+              <Form.Item label="导入文件" required>
+                <Upload.Dragger
+                  fileList={fileList}
+                  beforeUpload={beforeUpload}
+                  onRemove={() => {
+                    setFileList([]);
+                    fileContentRef.current = '';
+                    fileNameRef.current = '';
+                  }}
+                  accept=".xlsx,.xls,.csv"
+                  maxCount={1}
+                >
+                  <p className="ant-upload-drag-icon">
+                    <FileExcelOutlined style={{ color: '#52c41a' }} />
+                  </p>
+                  <p className="ant-upload-text">点击或拖拽文件到此区域上传</p>
+                  <p className="ant-upload-hint">
+                    仅支持.csv 格式,文件大小不超过10MB
+                  </p>
+                </Upload.Dragger>
+              </Form.Item>
+
+              <div style={{ textAlign: 'center' }}>
+                <Button icon={<DownloadOutlined />} onClick={handleDownloadTemplate}>
+                  下载导入模板
+                </Button>
+              </div>
+
+              <Divider />
+
+              <Alert
+                message="导入说明"
+                description={
+                  <ul style={{ margin: 0, paddingLeft: 16 }}>
+                    <li>必填列:DRG代码(DRGCode)、DRG描述(DRGDesc)、基准点数(Points)、预估点值(PipValue)、病组差异系数(DGDOV)、支付标准(PayStandard)</li>
+                    <li>字段说明:DRGCode=DRG代码、DRGDesc=DRG描述、Points=基准点数、PipValue=预估点值、DGDOV=病组差异系数、PayStandard=支付标准</li>
+                    <li>重复处理:DRG代码+行政区划+机构代码相同则更新,否则新增</li>
+                    <li>模板规范:模板列名不可变更</li>
+                  </ul>
+                }
+                type="info"
+                showIcon
+              />
+            </Form>
+
+            <div style={{ marginTop: 24, textAlign: 'right' }}>
+              <Button onClick={handleCloseImport}>取消</Button>
+              <Button
+                type="primary"
+                style={{ marginLeft: 8 }}
+                onClick={handlePreviewImport}
+                loading={importLoading}
+                disabled={fileList.length === 0}
+              >
+                下一步:预览 <ArrowRightOutlined />
+              </Button>
+            </div>
+          </div>
+        )}
+
+        {/* 步骤2:数据预览 */}
+        {importStep === 1 && (
+          <div>
+            <Alert
+              message={
+                <Space>
+                  <span>数据概览:</span>
+                  <Typography.Text>共计 <Typography.Text strong>{previewStats.total}</Typography.Text> 条</Typography.Text>
+                  <Divider type="vertical" />
+                  <Typography.Text type="success">正常 <Typography.Text strong>{previewStats.valid}</Typography.Text> 条</Typography.Text>
+                  <Divider type="vertical" />
+                  <Typography.Text type="warning">重复 <Typography.Text strong>{previewStats.duplicate}</Typography.Text> 条</Typography.Text>
+                  <Divider type="vertical" />
+                  <Typography.Text type="danger">异常 <Typography.Text strong>{previewStats.invalid}</Typography.Text> 条</Typography.Text>
+                </Space>
+              }
+              type="info"
+              showIcon
+              style={{ marginBottom: 16 }}
+            />
+
+            <Table
+              columns={previewColumns}
+              dataSource={previewData}
+              rowKey="rowNum"
+              size="small"
+              scroll={{ y: 300 }}
+              pagination={false}
+            />
+
+            <div style={{ marginTop: 16 }}>
+              <Alert
+                message="确认导入后将执行以下操作"
+                description={
+                  <ul style={{ margin: 0, paddingLeft: 16 }}>
+                    <li>正常数据:直接导入</li>
+                    <li>重复数据:更新现有记录</li>
+                    <li>异常数据:跳过不导入</li>
+                  </ul>
+                }
+                type="warning"
+                showIcon
+              />
+            </div>
+
+            <div style={{ marginTop: 24, textAlign: 'right' }}>
+              <Button onClick={() => setImportStep(0)} icon={<ArrowLeftOutlined />}>
+                上一步
+              </Button>
+              <Button
+                type="primary"
+                style={{ marginLeft: 8 }}
+                onClick={handleConfirmImport}
+                loading={importLoading}
+              >
+                确认导入
+              </Button>
+            </div>
+          </div>
+        )}
+
+        {/* 步骤3:导入结果 */}
+        {importStep === 2 && importResult && (
+          <div>
+            <Result
+              status={importResult.failCount === 0 ? 'success' : 'warning'}
+              title={importResult.failCount === 0 ? '导入成功' : '导入完成(部分失败)'}
+              subTitle={`总计 ${importResult.totalCount} 条数据,成功 ${importResult.successCount} 条,失败 ${importResult.failCount} 条`}
+            />
+
+            <Row gutter={16} style={{ marginBottom: 16 }}>
+              <Col span={6}>
+                <Card size="small">
+                  <Statistic
+                    title="总记录数"
+                    value={importResult.totalCount}
+                  />
+                </Card>
+              </Col>
+              <Col span={6}>
+                <Card size="small">
+                  <Statistic
+                    title="成功导入"
+                    value={importResult.successCount}
+                    valueStyle={{ color: '#52c41a' }}
+                  />
+                </Card>
+              </Col>
+              <Col span={6}>
+                <Card size="small">
+                  <Statistic
+                    title="新增记录"
+                    value={importResult.newCount}
+                    valueStyle={{ color: '#1890ff' }}
+                  />
+                </Card>
+              </Col>
+              <Col span={6}>
+                <Card size="small">
+                  <Statistic
+                    title="更新记录"
+                    value={importResult.duplicateCount}
+                    valueStyle={{ color: '#faad14' }}
+                  />
+                </Card>
+              </Col>
+            </Row>
+
+            {importResult.failCount > 0 && (
+              <>
+                <Divider />
+                <Typography.Title level={5}>失败明细</Typography.Title>
+                <List
+                  size="small"
+                  bordered
+                  dataSource={importResult.failList}
+                  renderItem={item => (
+                    <List.Item>
+                      <Space>
+                        <Typography.Text type="secondary">行 {item.rowNum}</Typography.Text>
+                        <Typography.Text code>{item.drgCode || '空代码'}</Typography.Text>
+                        <Typography.Text type="danger">{item.errorMsg}</Typography.Text>
+                      </Space>
+                    </List.Item>
+                  )}
+                  style={{ maxHeight: 200, overflow: 'auto' }}
+                />
+              </>
+            )}
+
+            <div style={{ marginTop: 24, textAlign: 'right' }}>
+              <Button onClick={handleCloseImport} type="primary">
+                完成
+              </Button>
+            </div>
+          </div>
+        )}
+      </ImportModal>
     </div>
   );
 };