Browse Source

fix : #10 设置可调整列宽,水平方向留白, 解决显示混乱问题

sw 1 week ago
parent
commit
e823381837
4 changed files with 152 additions and 7 deletions
  1. 49 0
      package-lock.json
  2. 1 0
      package.json
  3. 98 6
      src/pages/patient/components/WorklistTable.tsx
  4. 4 1
      src/pages/patient/worklist.tsx

+ 49 - 0
package-lock.json

@@ -40,6 +40,7 @@
         "react-dom": "^18.0.0",
         "react-intl": "^7.1.11",
         "react-redux": "^9.2.0",
+        "react-resizable": "^3.0.5",
         "react-router-dom": "^7.6.1",
         "redux": "^5.0.1",
         "zod": "^3.25.67"
@@ -8840,6 +8841,14 @@
         "mimic-response": "^1.0.0"
       }
     },
+    "node_modules/clsx": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+      "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/color-convert": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -18595,6 +18604,21 @@
         "node": ">= 4"
       }
     },
+    "node_modules/prop-types": {
+      "version": "15.8.1",
+      "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+      "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+      "dependencies": {
+        "loose-envify": "^1.4.0",
+        "object-assign": "^4.1.1",
+        "react-is": "^16.13.1"
+      }
+    },
+    "node_modules/prop-types/node_modules/react-is": {
+      "version": "16.13.1",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+    },
     "node_modules/property-expr": {
       "version": "2.0.6",
       "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
@@ -19475,6 +19499,31 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/react-resizable": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/react-resizable/-/react-resizable-3.0.5.tgz",
+      "integrity": "sha512-vKpeHhI5OZvYn82kXOs1bC8aOXktGU5AmKAgaZS4F5JPburCtbmDPqE7Pzp+1kN4+Wb81LlF33VpGwWwtXem+w==",
+      "dependencies": {
+        "prop-types": "15.x",
+        "react-draggable": "^4.0.3"
+      },
+      "peerDependencies": {
+        "react": ">= 16.3"
+      }
+    },
+    "node_modules/react-resizable/node_modules/react-draggable": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.5.0.tgz",
+      "integrity": "sha512-VC+HBLEZ0XJxnOxVAZsdRi8rD04Iz3SiiKOoYzamjylUcju/hP9np/aZdLHf/7WOD268WMoNJMvYfB5yAK45cw==",
+      "dependencies": {
+        "clsx": "^2.1.1",
+        "prop-types": "^15.8.1"
+      },
+      "peerDependencies": {
+        "react": ">= 16.3.0",
+        "react-dom": ">= 16.3.0"
+      }
+    },
     "node_modules/react-router": {
       "version": "7.6.1",
       "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.1.tgz",

+ 1 - 0
package.json

@@ -75,6 +75,7 @@
     "react-dom": "^18.0.0",
     "react-intl": "^7.1.11",
     "react-redux": "^9.2.0",
+    "react-resizable": "^3.0.5",
     "react-router-dom": "^7.6.1",
     "redux": "^5.0.1",
     "zod": "^3.25.67"

+ 98 - 6
src/pages/patient/components/WorklistTable.tsx

@@ -1,17 +1,19 @@
-import React from 'react';
+import React, { useState } from 'react';
 import { useSelector, useDispatch } from 'react-redux';
 import { useEffect } from 'react';
 import {
   fetchWorkThunk,
   workSelectionSlice,
 } from '../../../states/patient/worklist/slices/workSlice';
-import { Table } from 'antd';
+import { Table, TableColumnsType } from 'antd';
 import { FormattedMessage } from 'react-intl';
 import { RootState, AppDispatch } from '../../../states/store';
-import { Task } from '@/domain/work';
+import { Task, Task as DataType } from '@/domain/work';
 import worklistToExam from '../../../domain/patient/worklistToExam';
+import type { ResizeCallbackData } from 'react-resizable';
+import { Resizable } from 'react-resizable';
 
-const columns = [
+const columnsDef = [
   {
     title: (
       <FormattedMessage
@@ -329,6 +331,53 @@ const columns = [
   },
 ];
 
+interface TitlePropsType {
+  width: number;
+  onResize: (
+    e: React.SyntheticEvent<Element>,
+    data: ResizeCallbackData
+  ) => void;
+}
+
+const ResizableTitle: React.FC<
+  Readonly<
+    React.HTMLAttributes<HTMLTableCellElement | Resizable> & TitlePropsType
+  >
+> = (props) => {
+  const { onResize, width, ...restProps } = props;
+
+  if (!width) {
+    return <th {...restProps} />;
+  }
+
+  return (
+    <Resizable
+      width={width}
+      height={0}
+      minConstraints={[50, 0]} // 最小宽度 50px
+      // maxConstraints={[500, 0]} // 最大宽度 500px
+      handle={
+        <span
+          style={{
+            position: 'absolute',
+            right: '-5px', // 或 insetInlineEnd: "-5px"(支持逻辑属性)
+            bottom: '0',
+            zIndex: 1,
+            width: '10px',
+            height: '100%',
+            cursor: 'col-resize',
+          }}
+          onClick={(e) => e.stopPropagation()}
+        />
+      }
+      onResize={onResize}
+      draggableOpts={{ enableUserSelectHack: false }}
+    >
+      <th {...restProps} />
+    </Resizable>
+  );
+};
+
 const WorklistTable: React.FC = () => {
   const dispatch: AppDispatch = useDispatch();
   const worklistData = useSelector(
@@ -344,6 +393,14 @@ const WorklistTable: React.FC = () => {
   );
 
   useEffect(() => {
+    console.log(
+      'Fetching worklist data with filters:',
+      filters,
+      'page:',
+      page,
+      'pageSize:',
+      pageSize
+    );
     dispatch(fetchWorkThunk({ page, pageSize, filters }));
   }, [dispatch, filters, page, pageSize]);
 
@@ -363,9 +420,44 @@ const WorklistTable: React.FC = () => {
     worklistToExam(record);
   };
 
+  const [columns, setColumns] = useState<TableColumnsType<DataType>>(
+    columnsDef.map((col) => ({
+      ...col,
+      width: 150, // 默认宽度
+    }))
+  );
+
+  const handleResize =
+    (index: number) =>
+    (_: React.SyntheticEvent<Element>, { size }: ResizeCallbackData) => {
+      console.log('Resizing column:', index, size);
+      const newColumns = [...columns];
+      newColumns[index] = {
+        ...newColumns[index],
+        width: size.width,
+      };
+      setColumns(newColumns);
+    };
+
+  const mergedColumns = columns.map<TableColumnsType<DataType>[number]>(
+    (col, index) => ({
+      ...col,
+      onHeaderCell: (column: TableColumnsType<DataType>[number]) => ({
+        width: column.width,
+        onResize: handleResize(index) as React.ReactEventHandler<HTMLElement>,
+        style: { whiteSpace: 'nowrap' },
+      }),
+      onCell: () => ({ style: { whiteSpace: 'nowrap' } }),
+    })
+  );
+
   return (
-    <Table
-      columns={columns}
+    <Table<DataType>
+      bordered
+      className="px-4"
+      columns={mergedColumns}
+      scroll={{ x: 'max-content' }}
+      components={{ header: { cell: ResizableTitle } }}
       dataSource={worklistData}
       rowKey="StudyInstanceUID"
       onRow={(record) => ({

+ 4 - 1
src/pages/patient/worklist.tsx

@@ -40,7 +40,10 @@ const WorklistPage: React.FC = () => {
         </>
       ) : (
         <Row className="h-full">
-          <Col span={screens.lg ? 18 : screens.md ? 20 : 24}>
+          <Col
+            span={screens.lg ? 18 : screens.md ? 20 : 24}
+            className="overflow-auto"
+          >
             <WorklistTable />
           </Col>
           <Col