Browse Source

优化DRG基础数据维护:添加省市下拉框功能

- DRG基础数据维护页面新增省、市下拉框
- 新增/编辑弹框打开时自动加载省份数据
- 选择省份后自动加载对应的城市数据
- 编辑时自动回填省市数据
- 支持省市下拉框搜索和清除功能
- 删除无用的dist压缩包文件
- 优化API接口和请求配置
837390164@qq.com 2 weeks ago
parent
commit
0b9f5a2d46
7 changed files with 299 additions and 50 deletions
  1. BIN
      dist-final.zip
  2. BIN
      dist-icd-fix.zip
  3. BIN
      dist-update.zip
  4. 19 16
      src/api/basicData.ts
  5. 86 3
      src/api/request.ts
  6. 1 1
      src/api/system.ts
  7. 193 30
      src/pages/BasicData/BasicDataMaintenance.tsx

BIN
dist-final.zip


BIN
dist-icd-fix.zip


BIN
dist-update.zip


+ 19 - 16
src/api/basicData.ts

@@ -107,7 +107,7 @@ export const queryIcdMapping = (
   params: QueryIcdMappingParams,
   pagination: Pagination
 ): Promise<ApiResponse<PageResult<IcdMappingItem>>> => {
-  return invoke('02010025', [params], pagination);
+  return invoke('02010025', [params], undefined, pagination);
 };
 
 /** 保存ICD编码映射关系 (02010023) */
@@ -129,7 +129,7 @@ export const queryMedInsuIcdInfo = (
   params: QueryMedInsuIcdParams,
   pagination: Pagination
 ): Promise<ApiResponse<PageResult<MedInsuIcdItem>>> => {
-  return invoke('02010022', [params], pagination);
+  return invoke('02010022', [params], undefined, pagination);
 };
 
 // ========== ICD编码查询 (02010037) ==========
@@ -169,7 +169,7 @@ export const queryIcdInfo = (
   params: QueryIcdInfoParams,
   pagination: Pagination
 ): Promise<ApiResponse<PageResult<IcdInfoItem>>> => {
-  return invoke('02010037', [params], pagination);
+  return invoke('02010037', [params], undefined, pagination);
 };
 
 // ========== ADRG分组规则维护 (02010016, 02010017, 02010018) ==========
@@ -238,7 +238,7 @@ export const queryAdrgRules = (
   params: QueryAdrgRuleParams,
   pagination: Pagination
 ): Promise<ApiResponse<PageResult<AdrgRuleItem>>> => {
-  return invoke('02010017', [params], pagination);
+  return invoke('02010017', [params], undefined, pagination);
 };
 
 /** 保存ADRG规则 (02010016) */
@@ -326,7 +326,7 @@ export const queryCoreAlgorithm = (
   params: QueryCoreAlgorithmParams,
   pagination: Pagination
 ): Promise<ApiResponse<PageResult<CoreAlgorithmItem>>> => {
-  return invoke('02010033', [params], pagination);
+  return invoke('02010033', [params], undefined, pagination);
 };
 
 /** 保存DRG核心算法配置 (02010032) */
@@ -395,7 +395,7 @@ export const queryDipDiseases = (
   params: QueryDipDiseaseParams,
   pagination: Pagination
 ): Promise<ApiResponse<PageResult<DipDiseaseItem>>> => {
-  return invoke('02010020', [params], pagination);
+  return invoke('02010020', [params], undefined, pagination);
 };
 
 /** 保存DIP付费病种库 (02010019) */
@@ -420,13 +420,16 @@ export interface BasicDataItem {
   dictID: string;  // 用于查询明细的关联ID
   insuCode: string;
   insuDesc: string;
-  provinceDr: string;
+  provinceDr?: string;  // 兼容旧字段
+  provinceID?: string;  // 新字段名
   provinceName: string;
   provinceDesc: string;
-  cityDr: string;
+  cityDr?: string;  // 兼容旧字段
+  cityID?: string;  // 新字段名
   cityName: string;
   cityDesc: string;
-  areaDr: string;
+  areaDr?: string;  // 兼容旧字段
+  areaID?: string;  // 新字段名
   areaName: string;
   startDate: string;
   stopDate: string;
@@ -453,12 +456,12 @@ export interface BasicDataSubItem {
 
 /** 保存/更新DRG基础数据参数 */
 export interface SaveBasicDataParams {
-  id?: string;
+  dictID?: string;  // id改为dictID,为空表示新增,非空表示更新
   insuCode: string;
   insuDesc: string;
-  provinceDr: string;
-  cityDr: string;
-  areaDr?: string;
+  provinceID: string;
+  cityID: string;
+  areaID?: string;
   startDate: string;
   stopDate?: string;
   identification?: string;
@@ -509,7 +512,7 @@ export const queryBasicData = (
   params: QueryBasicDataParams,
   pagination: Pagination
 ): Promise<ApiResponse<PageResult<BasicDataItem>>> => {
-  return invoke('02010011', [params], pagination);
+  return invoke('02010011', [params], undefined, pagination);
 };
 
 /** 删除DRG基础数据 (02010012) */
@@ -531,7 +534,7 @@ export const queryBasicDataSub = (
   params: QueryBasicDataSubParams,
   pagination: Pagination
 ): Promise<ApiResponse<PageResult<BasicDataSubItem>>> => {
-  return invoke('02010014', [params], pagination);
+  return invoke('02010014', [params], undefined, pagination);
 };
 
 /** 删除DRG基础数据明细 (02010015) */
@@ -575,7 +578,7 @@ export const queryHospitalList = (
   params: QueryHospitalParams,
   pagination: Pagination
 ): Promise<ApiResponse<PageResult<HospitalItem>>> => {
-  return invoke('03020113', [params], pagination);
+  return invoke('03020113', [params], undefined, pagination);
 };
 
 // ========== 省市区下拉数据 (01010007, 01010008) ==========

+ 86 - 3
src/api/request.ts

@@ -28,18 +28,101 @@ request.interceptors.response.use(
   }
 );
 
+/**
+ * Session 信息类型 - 完整字段定义
+ */
+export interface SessionInfo {
+  userID: string;
+  userCode: string;
+  userName: string;
+  locID: string;
+  locDesc: string;
+  groupID: string;
+  groupDesc: string;
+  hospID: string;
+  hospCode: string;
+  hospDesc: string;
+  langID: number;
+  langDesc: string;
+  changeFlag: string;
+  changeDesc: string;
+  lastLoginDate: string;
+  lastLoginTime: string;
+  directorAuth: string;
+  defaultMenuType: string;
+  titleDesc: string;
+  userYBCode: string;
+  hospYBCode: string;
+  path: string;
+  sessionID: string;
+  errorMessageTime: string;
+  language: string;
+  messageTime: number;
+}
+
+/**
+ * 获取默认 Session 信息
+ * 从 localStorage 中读取或使用默认值
+ */
+const getDefaultSession = (): SessionInfo => {
+  try {
+    const sessionStr = localStorage.getItem('session');
+    if (sessionStr) {
+      return JSON.parse(sessionStr);
+    }
+  } catch (e) {
+    console.warn('读取 session 失败:', e);
+  }
+  // 返回默认 session(临时默认值)- 所有字段必须有值,无值传空
+  return {
+    userID: '158',
+    userCode: 'admin',
+    userName: 'admin',
+    locID: '2300',
+    locDesc: '信息中心',
+    groupID: '3',
+    groupDesc: '医院维护员',
+    hospID: '25',
+    hospCode: 'H03',
+    hospDesc: '合肥普瑞眼科医院',
+    langID: 1,
+    langDesc: '简体中文',
+    changeFlag: 'N',
+    changeDesc: '',
+    lastLoginDate: '2026-01-01',
+    lastLoginTime: '00:00:00',
+    directorAuth: 'N',
+    defaultMenuType: '2',
+    titleDesc: '',
+    userYBCode: '',
+    hospYBCode: 'H34010400768',
+    path: '',
+    sessionID: 'P9BXebxmDI',
+    errorMessageTime: '',
+    language: 'CN',
+    messageTime: 1,
+  };
+};
+
 /**
  * 通用接口调用方法
  * @param code 接口代码
  * @param params 接口参数数组
- * @param pagination 分页参数(可选)
+ * @param session Session 信息(可选,默认从 localStorage 读取)
+ * @param pagination 分页参数(可选,仅查询接口使用)
  */
-export const invoke = (code: string, params?: any[], pagination?: any) => {
+export const invoke = (
+  code: string,
+  params?: any[],
+  session?: SessionInfo,
+  pagination?: any
+) => {
   const requestData: any = {
     code,
     params: params || [],
+    session: [session || getDefaultSession()],
   };
-  // 如果有分页参数,添加到请求中
+  // 如果有分页参数,添加到请求中(仅查询接口使用)
   if (pagination) {
     requestData.pagination = [pagination];
   }

+ 1 - 1
src/api/system.ts

@@ -55,7 +55,7 @@ export const queryInterfaceServices = (
   },
   pagination: Pagination
 ): Promise<ApiResponse<PageResult<InterfaceServiceItem>>> => {
-  return invoke('01010017', [params], pagination);
+  return invoke('01010017', [params], undefined, pagination);
 };
 
 /** 保存接口服务 (02010405) */

+ 193 - 30
src/pages/BasicData/BasicDataMaintenance.tsx

@@ -1,8 +1,10 @@
 import React, { useState, useEffect, useCallback } from 'react';
 import {
   Card, Table, Button, Input, Select, Space, Modal, Form, Row, Col,
-  Tag, message, Popconfirm
+  Tag, message, Popconfirm, DatePicker, ConfigProvider
 } from 'antd';
+import zhCN from 'antd/locale/zh_CN';
+import dayjs, { type Dayjs } from 'dayjs';
 import { 
   PlusOutlined, SearchOutlined, ReloadOutlined, DeleteOutlined, EditOutlined,
   DatabaseOutlined
@@ -11,8 +13,10 @@ import type { ColumnsType } from 'antd/es/table';
 import {
   queryBasicData, saveBasicData, deleteBasicData,
   queryBasicDataSub, saveBasicDataSub, deleteBasicDataSub,
+  getProvinceData, getCityData,
   type BasicDataItem, type BasicDataSubItem,
-  type SaveBasicDataParams, type SaveBasicDataSubParams
+  type SaveBasicDataParams, type SaveBasicDataSubParams,
+  type ProvinceItem, type CityItem
 } from '../../api/basicData';
 
 const { Option } = Select;
@@ -48,6 +52,12 @@ const BasicDataMaintenance: React.FC = () => {
   const [subSaving, setSubSaving] = useState(false);
   const [subForm] = Form.useForm<SaveBasicDataSubParams>();
 
+  // 弹框省、市下拉数据
+  const [provinceList, setProvinceList] = useState<ProvinceItem[]>([]);
+  const [cityList, setCityList] = useState<CityItem[]>([]);
+  const [provinceLoading, setProvinceLoading] = useState(false);
+  const [cityLoading, setCityLoading] = useState(false);
+
   // 加载主表数据
   const fetchData = useCallback(async (page = currentPage, size = pageSize) => {
     setLoading(true);
@@ -130,26 +140,114 @@ const BasicDataMaintenance: React.FC = () => {
   };
 
   // 主表操作
-  const handleAdd = () => {
+  const handleAdd = async () => {
     setEditRecord(null);
     form.resetFields();
+    setCityList([]);
     setModalOpen(true);
+    // 获取省下拉数据
+    setProvinceLoading(true);
+    try {
+      const res = await getProvinceData();
+      if (res.errorCode === '0' && res.result) {
+        setProvinceList(res.result);
+      }
+    } finally {
+      setProvinceLoading(false);
+    }
   };
 
-  const handleEdit = (record: BasicDataItem) => {
+  const handleEdit = async (record: BasicDataItem) => {
     setEditRecord(record);
+    setModalOpen(true);
+    form.resetFields();
+    setCityList([]);
+    
+    // 先获取下拉数据
+    setProvinceLoading(true);
+    let currentProvinceList: ProvinceItem[] = [];
+    let currentCityList: CityItem[] = [];
+    
+    try {
+      const res = await getProvinceData();
+      if (res.errorCode === '0' && res.result) {
+        currentProvinceList = res.result;
+        setProvinceList(currentProvinceList);
+      }
+    } finally {
+      setProvinceLoading(false);
+    }
+    
+    // 找到省对应的ID(优先用ID匹配,如果没有则用名称匹配)
+    let provinceValue = record.provinceID || record.provinceDr;
+    let matchedProvinceId = '';
+    if (currentProvinceList.length > 0) {
+      // 先用ID匹配
+      let matched = currentProvinceList.find(p => 
+        String(p.id) === String(record.provinceID || record.provinceDr) || 
+        String(p.code) === String(record.provinceID || record.provinceDr)
+      );
+      // 如果ID没匹配到,再用名称匹配
+      if (!matched && record.provinceDesc) {
+        matched = currentProvinceList.find(p => 
+          p.descripts === record.provinceDesc ||
+          p.descripts.includes(record.provinceDesc) ||
+          record.provinceDesc.includes(p.descripts)
+        );
+      }
+      if (matched) {
+        provinceValue = matched.id;
+        matchedProvinceId = matched.id;
+      }
+    }
+    
+    // 根据匹配到的省ID获取市数据
+    if (matchedProvinceId) {
+      setCityLoading(true);
+      try {
+        const cityRes = await getCityData(matchedProvinceId);
+        if (cityRes.errorCode === '0' && cityRes.result) {
+          currentCityList = cityRes.result;
+          setCityList(currentCityList);
+        }
+      } finally {
+        setCityLoading(false);
+      }
+    }
+    
+    // 找到市对应的ID(优先用ID匹配,如果没有则用名称匹配)
+    let cityValue = record.cityID || record.cityDr;
+    if (currentCityList.length > 0) {
+      // 先用ID匹配
+      let matched = currentCityList.find(c => 
+        String(c.id) === String(record.cityID || record.cityDr) || 
+        String(c.code) === String(record.cityID || record.cityDr)
+      );
+      // 如果ID没匹配到,再用名称匹配
+      if (!matched && record.cityDesc) {
+        matched = currentCityList.find(c => 
+          c.descripts === record.cityDesc ||
+          c.descripts.includes(record.cityDesc) ||
+          record.cityDesc.includes(c.descripts)
+        );
+      }
+      if (matched) {
+        cityValue = matched.id;
+      }
+    }
+    
+    // 设置表单值(使用省市的ID,Select会根据ID匹配显示对应的中文)
     form.setFieldsValue({
       insuCode: record.insuCode,
       insuDesc: record.insuDesc,
-      provinceDr: record.provinceDr,
-      cityDr: record.cityDr,
-      areaDr: record.areaDr,
-      startDate: record.startDate,
-      stopDate: record.stopDate,
+      provinceID: provinceValue,
+      cityID: cityValue,
+      areaID: record.areaID || record.areaDr,
+      startDate: record.startDate ? dayjs(record.startDate.split(' ')[0]) as unknown as string : null,
+      stopDate: record.stopDate ? dayjs(record.stopDate.split(' ')[0]) as unknown as string : null,
       identification: record.identification,
       remark: record.remark,
     });
-    setModalOpen(true);
   };
 
   const handleDelete = async (id: string) => {
@@ -174,11 +272,13 @@ const BasicDataMaintenance: React.FC = () => {
     try {
       const values = await form.validateFields();
       setSaving(true);
+      // dictID 取查询接口02010011返回的dictID,为空表示新增,非空表示更新
+      const dictID = editRecord?.dictID || '';
       const params: SaveBasicDataParams = {
         ...values,
-        id: editRecord?.id || '',
-        startDate: values.startDate || '',
-        stopDate: values.stopDate || '',
+        dictID,
+        startDate: (values.startDate as unknown as Dayjs)?.format('YYYY-MM-DD') || '',
+        stopDate: (values.stopDate as unknown as Dayjs)?.format('YYYY-MM-DD') || '',
       };
       const res = await saveBasicData(params);
       if (res.errorCode === '0') {
@@ -203,7 +303,9 @@ const BasicDataMaintenance: React.FC = () => {
     }
     setSubEditRecord(null);
     subForm.resetFields();
-    subForm.setFieldsValue({ dictID: selectedRow.dictID || selectedRow.id });
+    // dictID 取自 02010011 查询主表返回的 dictID
+    const dictID = selectedRow?.dictID || selectedRow?.id || '';
+    subForm.setFieldsValue({ dictID });
     setSubModalOpen(true);
   };
 
@@ -213,8 +315,8 @@ const BasicDataMaintenance: React.FC = () => {
       code: record.code,
       desc: record.desc,
       identification: record.identification,
-      startDate: record.startDate,
-      stopDate: record.stopDate,
+      startDate: record.startDate ? dayjs(record.startDate.split(' ')[0]) as unknown as string : null,
+      stopDate: record.stopDate ? dayjs(record.stopDate.split(' ')[0]) as unknown as string : null,
     });
     setSubModalOpen(true);
   };
@@ -237,11 +339,14 @@ const BasicDataMaintenance: React.FC = () => {
     try {
       const values = await subForm.validateFields();
       setSubSaving(true);
+      // dictID 取自 02010011 查询主表返回的 dictID(selectedRow)
+      const dictID = selectedRow?.dictID || selectedRow?.id || '';
       const params: SaveBasicDataSubParams = {
         ...values,
         id: subEditRecord?.id || '',
-        startDate: values.startDate || '',
-        stopDate: values.stopDate || '',
+        dictID,
+        startDate: (values.startDate as unknown as Dayjs)?.format('YYYY-MM-DD') || '',
+        stopDate: (values.stopDate as unknown as Dayjs)?.format('YYYY-MM-DD') || '',
       };
       const res = await saveBasicDataSub(params);
       if (res.errorCode === '0') {
@@ -258,6 +363,36 @@ const BasicDataMaintenance: React.FC = () => {
     }
   };
 
+  // 省选择变化时获取市数据
+  const handleProvinceChange = async (value: string) => {
+    form.setFieldsValue({ cityID: undefined, areaID: undefined });
+    if (!value) {
+      setCityList([]);
+      return;
+    }
+    setCityLoading(true);
+    try {
+      const res = await getCityData(value);
+      if (res.errorCode === '0' && res.result) {
+        setCityList(res.result);
+      }
+    } finally {
+      setCityLoading(false);
+    }
+  };
+
+  // 市选择变化时填充区代码
+  const handleCityChange = (value: string) => {
+    if (!value) {
+      form.setFieldsValue({ areaID: undefined });
+      return;
+    }
+    const selectedCity = cityList.find(item => item.id === value);
+    if (selectedCity) {
+      form.setFieldsValue({ areaID: selectedCity.code });
+    }
+  };
+
   const columns: ColumnsType<BasicDataItem> = [
     { title: '代码', dataIndex: 'insuCode', width: 180, ellipsis: true },
     { title: '描述', dataIndex: 'insuDesc', width: 280, ellipsis: true },
@@ -318,7 +453,8 @@ const BasicDataMaintenance: React.FC = () => {
   ];
 
   return (
-    <div style={{ padding: 16, width: '100%', height: '100%', boxSizing: 'border-box', display: 'flex', flexDirection: 'column' }}>
+    <ConfigProvider locale={zhCN}>
+      <div style={{ padding: 16, width: '100%', height: '100%', boxSizing: 'border-box', display: 'flex', flexDirection: 'column' }}>
       {/* 左右两栏布局 */}
       <div style={{ flex: 1, minHeight: 0, display: 'flex', flexDirection: 'row', gap: 16 }}>
         {/* 左侧:主表数据 */}
@@ -628,28 +764,54 @@ const BasicDataMaintenance: React.FC = () => {
               </Form.Item>
             </Col>
             <Col span={8}>
-              <Form.Item name="provinceDr" label="省代码" rules={[{ required: true, message: '请输入省代码' }]}>
-                <Input placeholder="如 310000" />
+              <Form.Item name="provinceID" label="省" rules={[{ required: true, message: '请选择省' }]}>
+                <Select
+                  placeholder="请选择省"
+                  loading={provinceLoading}
+                  allowClear
+                  showSearch
+                  optionFilterProp="children"
+                  onChange={handleProvinceChange}
+                >
+                  {provinceList.map(item => (
+                    <Option key={item.id} value={item.id}>
+                      {item.descripts}
+                    </Option>
+                  ))}
+                </Select>
               </Form.Item>
             </Col>
             <Col span={8}>
-              <Form.Item name="cityDr" label="市代码" rules={[{ required: true, message: '请输入市代码' }]}>
-                <Input placeholder="如 310100" />
+              <Form.Item name="cityID" label="市" rules={[{ required: true, message: '请选择市' }]}>
+                <Select
+                  placeholder="请选择市"
+                  loading={cityLoading}
+                  allowClear
+                  showSearch
+                  optionFilterProp="children"
+                  onChange={handleCityChange}
+                >
+                  {cityList.map(item => (
+                    <Option key={item.id} value={item.id}>
+                      {item.descripts}
+                    </Option>
+                  ))}
+                </Select>
               </Form.Item>
             </Col>
             <Col span={8}>
-              <Form.Item name="areaDr" label="区代码">
+              <Form.Item name="areaID" label="区代码">
                 <Input placeholder="如 310101" />
               </Form.Item>
             </Col>
             <Col span={8}>
-              <Form.Item name="startDate" label="生效日期" rules={[{ required: true, message: '请输入生效日期' }]}>
-                <Input placeholder="YYYY-MM-DD" />
+              <Form.Item name="startDate" label="生效日期" rules={[{ required: true, message: '请选择生效日期' }]}>
+                <DatePicker style={{ width: '100%' }} format="YYYY-MM-DD" />
               </Form.Item>
             </Col>
             <Col span={8}>
               <Form.Item name="stopDate" label="失效日期">
-                <Input placeholder="YYYY-MM-DD" />
+                <DatePicker style={{ width: '100%' }} format="YYYY-MM-DD" />
               </Form.Item>
             </Col>
             <Col span={8}>
@@ -697,19 +859,20 @@ const BasicDataMaintenance: React.FC = () => {
               </Form.Item>
             </Col>
             <Col span={12}>
-              <Form.Item name="startDate" label="生效日期" rules={[{ required: true, message: '请输入生效日期' }]}>
-                <Input placeholder="YYYY-MM-DD" />
+              <Form.Item name="startDate" label="生效日期" rules={[{ required: true, message: '请选择生效日期' }]}>
+                <DatePicker style={{ width: '100%' }} format="YYYY-MM-DD" />
               </Form.Item>
             </Col>
             <Col span={12}>
               <Form.Item name="stopDate" label="失效日期">
-                <Input placeholder="YYYY-MM-DD" />
+                <DatePicker style={{ width: '100%' }} format="YYYY-MM-DD" />
               </Form.Item>
             </Col>
           </Row>
         </Form>
       </Modal>
     </div>
+    </ConfigProvider>
   );
 };