| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- import React, { useState, useEffect } from 'react';
- import { Row, Col, Button, Drawer, Grid } from 'antd';
- import { SettingOutlined } from '@ant-design/icons';
- import { FormattedMessage } from 'react-intl';
- import { useSelector, useDispatch } from 'react-redux';
- import { useRisAutoSync } from '@/hooks/useRisAutoSync';
- import {
- fetchWorkThunk,
- workSelectionSlice,
- workPaginationSlice,
- workFiltersSlice,
- } from '../../states/patient/worklist/slices/workSlice';
- import { updateThumbnailsFromWorkSelection } from '../../states/patient/worklist/slices/thumbnailListSlice';
- import WorklistTable from './components/WorklistTable';
- import OperationPanel from './components/OperationPanel';
- import ThumbnailList from './components/ThumbnailList';
- import GenericPagination from '../../components/GenericPagination';
- import PatientPortraitFloat from './components/PatientPortraitFloat';
- import { RootState, AppDispatch } from '../../states/store';
- import { Task } from '@/domain/work';
- import worklistToExam from '../../domain/patient/worklistToExam';
- import { columnConfigService } from '@/config/tableColumns';
- import { ColumnConfig } from '@/config/tableColumns/types/columnConfig';
- import { useMultiSelection } from '@/hooks/useMultiSelection';
- const { useBreakpoint } = Grid;
- const WorklistPage: React.FC = () => {
- const screens = useBreakpoint();
- const [drawerVisible, setDrawerVisible] = useState(false);
- const [columnConfig, setColumnConfig] = useState<ColumnConfig[]>([]); // 新增:列配置状态
- const [selectedPatientForPortrait, setSelectedPatientForPortrait] = useState<Task | null>(null); // 照片显示用的选中患者
- // 启用RIS自动同步(在后台静默运行)
- useRisAutoSync();
- const dispatch: AppDispatch = useDispatch();
- const filters = useSelector((state: RootState) => state.workFilters);
- const page = useSelector((state: RootState) => state.workPagination.page);
- const pageSize = useSelector(
- (state: RootState) => state.workPagination.pageSize
- );
- const selectedIds = useSelector(
- (state: RootState) => state.workSelection.selectedIds
- );
- const selectedSecondaryIds = useSelector( // 获取次要选中ID列表
- (state: RootState) => state.workSelection.selectedSecondaryIds
- );
- const worklistData = useSelector(
- (state: RootState) => state.workEntities.data
- );
- // 新增:获取列配置
- useEffect(() => {
- columnConfigService
- .getColumnConfig('worklist')
- .then((config) => {
- setColumnConfig(config.columns);
- })
- .catch((error) => {
- console.error('Failed to load worklist column config:', error);
- // 失败时使用空配置,表格会显示所有列
- setColumnConfig([]);
- });
- }, []);
- // 同步分页状态到过滤器
- useEffect(() => {
- console.log('[worklist] Syncing pagination to filters:', {
- page,
- pageSize,
- });
- dispatch(
- workFiltersSlice.actions.setFilters({
- page,
- page_size: pageSize,
- })
- );
- }, [dispatch, page, pageSize]);
- useEffect(() => {
- console.log(
- '[worklist] Fetching worklist data with filters:',
- filters,
- 'page:',
- page,
- 'pageSize:',
- pageSize
- );
- dispatch(fetchWorkThunk({ page, pageSize, filters }));
- }, [dispatch, page, pageSize, filters]);
- // 使用多选 Hook
- const { handleRowClick } = useMultiSelection({
- selectedIds,
- selectedSecondaryIds,
- onSelectionChange: (newIds,secondNewIds) => {
- console.log('Selected IDs changed:', newIds,secondNewIds);
-
- // 如果只有一个选中项,设置选中患者用于显示照片
- if (newIds.length === 1) {
- const selectedRecord = worklistData.find(item => item.StudyID === newIds[0]&&item.entry_id===secondNewIds?.[0]);
- if (selectedRecord) {
- setSelectedPatientForPortrait(selectedRecord);
- }
- } else {
- // 多选时清空患者照片
- setSelectedPatientForPortrait(null);
- }
-
- // 更新 Redux 状态(用于其他功能)
- dispatch(workSelectionSlice.actions.setSelectedIds(newIds));
- dispatch(workSelectionSlice.actions.setSelectedSecondaryIds(secondNewIds??[]));
- dispatch(updateThumbnailsFromWorkSelection(newIds));
- },
- enableMultiSelect: true,
- });
- // 处理行点击事件(兼容现有功能)
- const handleRowClickInternal = (record: Task, event?: React.MouseEvent) => {
- handleRowClick(record, event || {} as React.MouseEvent);
- };
- const handleRowDoubleClick = (record: Task) => {
- console.log(
- '[WorklistTable] Row double-clicked:',
- JSON.stringify(record, null, 2)
- );
- worklistToExam(record);
- };
- return (
- <div className="h-full">
- {/* 患者照片浮动组件 */}
- <PatientPortraitFloat
- patient={selectedPatientForPortrait}
- onClose={() => setSelectedPatientForPortrait(null)}
- />
-
- {screens.xs ? (
- <>
- <div className="flex-1 overflow-auto">
- <WorklistTable
- columnConfig={columnConfig}
- worklistData={worklistData}
- filters={filters}
- page={page}
- pageSize={pageSize}
- selectedIds={selectedIds}
- selectedSecondaryIds={selectedSecondaryIds} // 新增
- handleRowClick={handleRowClickInternal}
- handleRowDoubleClick={handleRowDoubleClick}
- />
- </div>
- <GenericPagination
- paginationSelector={(state) => state.workPagination}
- entitiesSelector={(state) => state.workEntities}
- paginationActions={workPaginationSlice.actions}
- className="border-t"
- />
- <Button
- type="primary"
- shape="circle"
- icon={<SettingOutlined />}
- className="fixed bottom-6 right-6 z-50"
- onClick={() => setDrawerVisible(true)}
- />
- <Drawer
- title={
- <FormattedMessage
- id="worklist.operationPanel"
- defaultMessage="worklist.operationPanel"
- />
- }
- placement="left"
- onClose={() => setDrawerVisible(false)}
- open={drawerVisible}
- width={300}
- >
- <OperationPanel />
- </Drawer>
- </>
- ) : (
- <Row className="h-full">
- <Col
- span={screens.lg ? 18 : screens.md ? 20 : 24}
- className="h-full flex flex-col"
- >
- <div className="flex-1 flex flex-col">
- <div className="flex-1 overflow-auto">
- <WorklistTable
- columnConfig={columnConfig}
- worklistData={worklistData}
- filters={filters}
- page={page}
- pageSize={pageSize}
- selectedIds={selectedIds}
- selectedSecondaryIds={selectedSecondaryIds} // 新增
- handleRowClick={handleRowClickInternal}
- handleRowDoubleClick={handleRowDoubleClick}
- />
- </div>
- <GenericPagination
- paginationSelector={(state) => state.workPagination}
- entitiesSelector={(state) => state.workEntities}
- paginationActions={workPaginationSlice.actions}
- className="border-t"
- />
- </div>
- <div className="h-60 border-t border-gray-200">
- <ThumbnailList />
- </div>
- </Col>
- <Col
- span={screens.lg ? 6 : screens.md ? 4 : 0}
- className="h-full overflow-auto"
- >
- <OperationPanel />
- </Col>
- </Row>
- )}
- </div>
- );
- };
- export default WorklistPage;
|