OHIF Viewer (3.9版本最新版) 适配移动端——最后一篇

根据一些调用资料和尝试,OHIF 的底层用的是Cornerstonejs ,这个是基于web端写的,如果说写在微信小程序里,确实有很多报错,

第一个问题就是 npm下载的依赖,

一、运行环境差异

微信小程序的运行环境与传统的 Node.js 环境有很大不同。小程序在微信客户端中运行,有严格的安全限制和性能要求。而 npm 包通常是为 Node.js 环境设计的,其中可能包含一些在小程序环境中不被支持的代码或依赖项。

二、构建机制不同

  1. 小程序有自己特定的构建体系。微信小程序使用自己的开发工具进行构建和打包,这个过程与基于 npm 和 Webpack 等工具的传统前端构建流程不同。小程序的构建工具主要针对小程序的特定结构和需求进行优化,不一定能直接处理 npm 包的复杂依赖关系。
  2. 小程序的代码结构通常是由多个页面和组件组成,每个页面和组件都有自己独立的代码文件。这种结构与传统的基于模块的前端项目有所不同,也使得直接引入 npm 包变得更加困难。

第二个 修改的话很考验技术,得修改js文件,而且不保证是否能运行起来

第三个 ohif 最新版用的react+ hooks 框架写的,很多组件都是已经封装好,要是另外写的话 ,也很考研技术

现在是用手机模式写的适配移动端

第一个:

platform\app\src\utils\isMobile.ts

创建一个ts文件 用来判断现在是否处于移动端模式

export default function isMobile(): boolean {
  const pattern: RegExp = new RegExp(
    'Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini'
  );
  return pattern.test(navigator.userAgent);
}

第二个:

extensions\default\src\ViewerLayout\index.tsx

在这个里面是基础查看器的布局位置,我们先通过这个文件来找到 导航栏、左侧面板、右侧面板、·中间影像的查看器、以及工具栏的工具们的组件位置

导航栏 的移动端改造

原来的导航栏的组件组件 是

extensions\default\src\ViewerLayout\ViewerHeader.tsx  
这个里面的   Header
platform\ui\src\components\Header\Header.tsx
里面有个NavBar
platform\ui\src\components\NavBar\NavBar.tsx
这个是控制外面那个容器的 

我把它改成 没有下拉菜单的 ,都横着展示出来,所以要自己写一套组件组件出来或者直接判断 写两个return也可以

组件们都在

platform\ui\src\components  这个下面,如果想要自己新建一个组件的话,就来这里,记得导出,建完文件夹以后,还得导出
有两个index.js里面 写上新建的组件
platform\ui\src\components\index.js
platform\ui\src\index.js
这两个里面都得加上,不然你的组件没有办法使用

里面图标的具体 控制

 extensions\default\src\Toolbar\ToolbarSplitButtonWithServices.tsx
 这个里面的
  <SplitButton
        primary={primary}
        secondary={secondary}
        items={getSplitButtonItems(items)}
        groupId={groupId}
        renderer={listItemRenderer}
        onInteraction={onInteraction}
        Component={props => (
          <PrimaryButtonComponent
            {...props}
            servicesManager={servicesManager}
          />
        )}
      />

我先建了一个SplitButtonAPP的组件,在新的组件里面的把按钮拆成一长条,具体代码

import React, { useState } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import OutsideClickHandler from 'react-outside-click-handler';
import { useTranslation } from 'react-i18next';

import Icon from '../Icon';
import Tooltip from '../Tooltip';
import ListMenu from '../ListMenu';

const baseClasses = {
  Button: 'flex flex-col items-center rounded-md border-transparent group/button',
  Primary: 'flex flex-col items-center text-center',
  Content: 'flex flex-row space-x-4',
};

const classes = {
  Button: () => classNames(baseClasses.Button, 'hover:!bg-primary-dark hover:border-primary-dark'),
  Primary: ({ isActive }) =>
    classNames(
      baseClasses.Primary,
      isActive
        ? 'border-primary-light bg-primary-light rounded-md'
        : 'border-secondary-dark bg-secondary-dark group-hover/button:border-primary-dark group-hover/button:text-primary-light hover:!bg-primary-dark hover:border-primary-dark'
    ),
  Content: () => classNames(baseClasses.Content),
};

const DefaultListItemRenderer = props => {
  const { t, icon, label, className, isActive } = props;
  return (
    <div
      className={classNames(
        'flex h-8 w-full select-none flex-row items-center p-3',
        'whitespace-pre text-base',
        className,
        `${isActive ? 'hover:opacity-80' : 'hover:bg-primary-dark'}`
      )}
    >
      {icon && (
        <span className="mr-4">
          <Icon
            name={icon}
            className="h-[28px] w-[28px]"
          />
        </span>
      )}
      <span className="mr-5">{t?.(label)}</span>
    </div>
  );
};

/**
 * SplitButton 组件是一个更通用的拆分按钮实现,没有isActive和其他交互属性
 * 它提供了一种在主按钮和次按钮之间切换,并展示相关选项列表的功能
 *
 * @param {object} props - 组件的属性对象
 * @param {string} props.groupId - 按钮组的ID,用于数据追踪
 * @param {object} props.primary - 主按钮的配置对象
 * @param {object} props.secondary - 次按钮的配置对象
 * @param {array} props.items - 列表菜单项的数组
 * @param {function} props.renderer - 渲染列表项的自定义函数
 * @param {function} props.onInteraction - 交互时触发的回调函数
 * @param {React.Component} props.Component - 渲染图标使用的组件,默认为Icon
 * @returns {JSX.Element} - 拆分按钮的JSX实现
 */
const SplitButtonAPP = ({
  groupId,
  primary,
  secondary,
  items,
  renderer = null,
  onInteraction,
  Component = Icon,
}) => {
  // 使用useTranslation钩子管理翻译
  const { t } = useTranslation('Buttons');

  // 渲染函数,如果未提供renderer则使用默认渲染函数
  const listItemRenderer = renderer || DefaultListItemRenderer;
  return (
    <div
      id="SplitButtonAPP"
      className={classes.Content()}
    >
      {items.map((item, index) => {
        const primaryClassNames = classNames(
          classes.Primary({
            isActive: item.isActive,
          }),
          item.className
        );
        return (
          <div
            key={item.id}
            className="flex flex-col items-center"
          >
            <Tooltip
              content={item.label}
              className="h-full"
            >
              <Component
                key={item.id}
                {...item}
                onInteraction={onInteraction}
                rounded="none"
                className={primaryClassNames}
                data-tool={item.id}
                data-cy={`${groupId}-split-button-item-${index}`}
              />
            </Tooltip>
            {/* <div className="mt-2 text-center text-xs text-white">{t?.(item.label)}</div>{' '} */}
            {/* 添加按钮下方的名称 */}
          </div>
        );
      })}
    </div>
  );
};

SplitButtonAPP.propTypes = {
  groupId: PropTypes.string.isRequired,
  // primary: PropTypes.object.isRequired,
  // secondary: PropTypes.object.isRequired,
  items: PropTypes.array.isRequired,
  renderer: PropTypes.func,
  // isActive: PropTypes.bool,
  onInteraction: PropTypes.func.isRequired,
  Component: PropTypes.elementType,
  // interactionType: PropTypes.oneOf(['action', 'tool', 'toggle']),
};

export default SplitButtonAPP;

在这个文件里面进行判断当前模式是否是移动端

extensions\default\src\Toolbar\ToolbarSplitButtonWithServices.tsx


引入import isMobile from '../../../../platform/app/src/utils/isMobile';
 //判断当前是否是移动设备
  let isMob = isMobile();
  localStorage.setItem('isMobile', isMob);
  
    if (isMob) {
    return (
      <SplitButtonAPP
        primary={primary}
        secondary={secondary}
        items={getSplitButtonItems(items)}
        groupId={groupId}
        renderer={listItemRenderer}
        onInteraction={onInteraction}
        Component={props => (
          <PrimaryButtonComponent
            {...props}
            servicesManager={servicesManager}
          />
        )}
      />
    );
  } else {
    return (
      <SplitButton
        primary={primary}
        secondary={secondary}
        items={getSplitButtonItems(items)}
        groupId={groupId}
        renderer={listItemRenderer}
        onInteraction={onInteraction}
        Component={props => (
          <PrimaryButtonComponent
            {...props}
            servicesManager={servicesManager}
          />
        )}
      />
    );
  }

这个标题栏还是有很多英文的占的地方比较大,

modes\longitudinal\src\moreTools.ts
这里可以把英文的  修改成中文
modes\longitudinal\src\toolbarButtons.ts
这个里面也有
换成了中文

缩略图的改造

通过extensions\default\src\ViewerLayout\index.tsx

找这个组件
extensions\default\src\Components\SidePanelWithServices.tsx
 // 渲染侧边面板组件
  return (
    <SidePanel
      {...props}
      side={side}
      tabs={tabs}
      activeTabIndex={activeTabIndex}
      onOpen={handleSidePanelOpen}
      onActiveTabIndexChange={handleActiveTabIndexChange}
      expandedWidth={expandedWidth}
    ></SidePanel>
  );
  跳到这个组件里面

我忘记是怎么找的了,应该是根据类名找的

找到的几个有关于缩略图的

然后自己写了几个组件

ThumbnailAPP

import React, { useState } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { useDrag } from 'react-dnd';
import Icon from '../Icon';
import { StringNumber } from '../../types';
import DisplaySetMessageListTooltip from '../DisplaySetMessageListTooltip';

/**
 * 显示一个展示集的缩略图。
 *
 * 此组件用于显示指定展示集的缩略图,包括图片、文字描述及交互反馈。它支持单击、双击与拖拽操作。
 *
 * @param {string} displaySetInstanceUID - 展示集的唯一标识符。
 * @param {string} [className] - 缩略图容器的额外 CSS 类名。
 * @param {string} imageSrc - 图片资源的 URL 地址。
 * @param {string} imageAltText - 图片的替代文本。
 * @param {string} description - 缩略图下方的描述文字。
 * @param {number} seriesNumber - 序列号。
 * @param {number} numInstances - 实例数量。
 * @param {number} loadingProgress - 加载进度,范围从 0 到 1。
 * @param {object} [dragData={}] - 用于拖拽的数据对象。
 * @param {boolean} isActive - 是否处于激活状态。
 * @param {function} onClick - 单击事件处理函数。
 * @param {function} onDoubleClick - 双击事件处理函数。
 * @returns {React.ReactNode} - 返回缩略图组件。
 */
const ThumbnailAPP = ({
  displaySetInstanceUID,
  className,
  imageSrc,
  imageAltText,
  description,
  seriesNumber,
  numInstances,
  loadingProgress,
  countIcon,
  messages,
  dragData = {},
  isActive,
  onClick,
  onDoubleClick,
}): React.ReactNode => {
  // 使用 useDrag Hook 来实现拖拽功能
  const [collectedProps, drag, dragPreview] = useDrag({
    type: 'displayset',
    item: { ...dragData },
    canDrag: function (monitor) {
      return Object.keys(dragData).length !== 0;
    },
  });

  // 状态管理:记录最后一次触摸结束的时间戳
  const [lastTap, setLastTap] = useState(0);

  // 触摸开始事件处理器,用于记录触摸开始时间
  const handleTouchStart = e => {
    setLastTap(new Date().getTime());
  };

  // 触摸结束事件处理器,用于判断是否触发双击事件
  const handleTouchEnd = e => {
    const currentTime = new Date().getTime();
    const tapLength = currentTime - lastTap;

    // 判断是否为双击
    if (tapLength < 300 && tapLength > 0) {
      onDoubleClick(e);
    } else {
      onClick(e);
    }1
    setLastTap(currentTime);
  };

  // 渲染缩略图组件
  return (
    <div
      className={classnames(
        className,
        'group mb-8 flex flex-1 cursor-pointer select-none flex-col px-3 outline-none'
      )}
      id={`thumbnail-${displaySetInstanceUID}`}
      data-cy={`study-browser-thumbnail`}
      data-series={seriesNumber}
      onTouchStart={handleTouchStart}
      onTouchEnd={handleTouchEnd}
      role="button"
      tabIndex="0"
    >
      <div ref={drag}>
        <div
          className={classnames(
            'flex h-32 w-32 flex-1 items-center justify-center overflow-hidden rounded-md bg-black text-base text-white',
            isActive
              ? 'border-primary-light border-2'
              : 'border-secondary-light border hover:border-blue-300'
          )}
        >
          {imageSrc ? (
            <img
              src={imageSrc}
              alt={imageAltText}
              className="h-full w-full object-contain"
              crossOrigin="anonymous"
            />
          ) : (
            <div>{imageAltText}</div>
          )}
        </div>
        <div className="flex flex-1 flex-row items-center pt-2 text-base text-blue-300">
          <div className="mr-4">
            <span className="text-primary-main font-bold">{'S: '}</span>
            {seriesNumber}
          </div>
          <div className="flex flex-1 flex-row items-center">
            <Icon
              name={countIcon || 'group-layers'}
              className="mr-2 w-3"
            />
            {` ${numInstances}`}
          </div>
          <div className="mr-2 flex last:mr-0">
            {loadingProgress && loadingProgress < 1 && <>{Math.round(loadingProgress * 100)}%</>}
            {loadingProgress && loadingProgress === 1 && (
              <Icon
                name={'database'}
                className="w-3"
              />
            )}
          </div>
        </div>
        <DisplaySetMessageListTooltip
          messages={messages}
          id={`display-set-tooltip-${displaySetInstanceUID}`}
        />
      </div>
      {/* <div className="break-all text-base text-white">{description}</div> */}
    </div>
  );
};

ThumbnailAPP.propTypes = {
  displaySetInstanceUID: PropTypes.string.isRequired,
  className: PropTypes.string,
  imageSrc: PropTypes.string,
  dragData: PropTypes.shape({
    type: PropTypes.string.isRequired,
  }),
  imageAltText: PropTypes.string,
  description: PropTypes.string.isRequired,
  seriesNumber: StringNumber.isRequired,
  numInstances: PropTypes.number.isRequired,
  loadingProgress: PropTypes.number,
  messages: PropTypes.object,
  isActive: PropTypes.bool.isRequired,
  onClick: PropTypes.func.isRequired,
  onDoubleClick: PropTypes.func.isRequired,
};

export default ThumbnailAPP;

ThumbnailListAPP

import React from 'react';
import PropTypes from 'prop-types';

import ThumbnailAPP from '../ThumbnailAPP';
import ThumbnailNoImage from '../ThumbnailNoImage';
import ThumbnailTracked from '../ThumbnailTracked';
import * as Types from '../../types';

const ThumbnailListAPP = ({
  thumbnails,
  onThumbnailClick,
  onThumbnailDoubleClick,
  onClickUntrack,
  activeDisplaySetInstanceUIDs = [],
}) => {
  return (
    <div
      id="ohif-thumbnail-list"
      className="flex flex-row overflow-x-auto overflow-y-hidden bg-black"
      style={
   
   {
        position: 'fixed',
        bottom: 0,
        width: '100%',
        whiteSpace: 'nowrap',
        padding: '0 10px', // 添加填充以便在移动设备上获得更好的间距
      }}
    >
      {thumbnails.map(
        ({
          displaySetInstanceUID,
          description,
          dragData,
          seriesNumber,
          numInstances,
          loadingProgress,
          modality,
          componentType,
          seriesDate,
          countIcon,
          isTracked,
          canReject,
          onReject,
          imageSrc,
          messages,
          imageAltText,
          isHydratedForDerivedDisplaySet,
        }) => {
          const isActive = activeDisplaySetInstanceUIDs.includes(displaySetInstanceUID);
          const commonProps = {
            key: displaySetInstanceUID,
            displaySetInstanceUID,
            dragData,
            description,
            seriesNumber,
            numInstances,
            loadingProgress,
            countIcon,
            imageSrc,
            imageAltText,
            messages,
            isActive,
            onClick: () => onThumbnailClick(displaySetInstanceUID),
            onDoubleClick: () => onThumbnailDoubleClick(displaySetInstanceUID),
            style: {
              display: 'inline-block',
              marginRight: '10px',
              width: '75px', // 调整宽度以保持移动设备上的方块样式
              height: '75px', // 保持高度与宽度相同,以确保方块形状
            },
          };

          switch (componentType) {
            case 'thumbnail':
              return <ThumbnailAPP {...commonProps} />;
            case 'thumbnailTracked':
              return (
                <ThumbnailTracked
                  {...commonProps}
                  isTracked={isTracked}
                  onClickUntrack={() => onClickUntrack(displaySetInstanceUID)}
                />
              );
            case 'thumbnailNoImage':
              return (
                <ThumbnailNoImage
                  {...commonProps}
                  modality={modality}
                  modalityTooltip={_getModalityTooltip(modality)}
                  seriesDate={seriesDate}
                  canReject={canReject}
                  onReject={onReject}
                  isHydratedForDerivedDisplaySet={isHydratedForDerivedDisplaySet}
                />
              );
            default:
              return <></>;
          }
        }
      )}
    </div>
  );
};

ThumbnailListAPP.propTypes = {
  thumbnails: PropTypes.arrayOf(
    PropTypes.shape({
      displaySetInstanceUID: PropTypes.string.isRequired,
      imageSrc: PropTypes.string,
      imageAltText: PropTypes.string,
      seriesDate: PropTypes.string,
      seriesNumber: Types.StringNumber,
      numInstances: PropTypes.number,
      description: PropTypes.string,
      componentType: Types.ThumbnailType.isRequired,
      isTracked: PropTypes.bool,
      dragData: PropTypes.shape({
        type: PropTypes.string.isRequired,
      }),
    })
  ),
  activeDisplaySetInstanceUIDs: PropTypes.arrayOf(PropTypes.string),
  onThumbnailClick: PropTypes.func.isRequired,
  onThumbnailDoubleClick: PropTypes.func.isRequired,
  onClickUntrack: PropTypes.func.isRequired,
};

function _getModalityTooltip(modality) {
  if (_modalityTooltips.hasOwnProperty(modality)) {
    return _modalityTooltips[modality];
  }
  return 'Unknown';
}

const _modalityTooltips = {
  SR: 'Structured Report',
  SEG: 'Segmentation',
  OT: 'Other',
  RTSTRUCT: 'RT Structure Set',
};

export default ThumbnailListAPP;

期间还会有有其他几个组件的调整

一般是样式跳转,根据isMobile()判断当前是否是移动端设备

ThumbnailNoImage

//判断当前是否是移动设备
  let isMob = isMobile();
  localStorage.setItem('isMobile', isMob);
  if (isMob) {
    return (
      <div
        className={classnames(
          'flex flex-1 cursor-pointer select-none flex-row rounded outline-none hover:border-blue-300 focus:border-blue-300',
          isActive ? 'border-primary-light border-2' : 'border border-transparent'
        )}
        style={
   
   {
          padding: isActive ? '11px' : '12px',
        }}
        id={`thumbnail-${displaySetInstanceUID}`}
        onClick={onClick}
        onDoubleClick={onDoubleClick}
        onTouchEnd={handleTouchEnd}
        role="button"
        tabIndex="0"
        data-cy={`study-browser-thumbnail-no-image`}
      >
        <div ref={drag}>
          <div className="flex flex-1 flex-col">
            <div className="mb-2 flex flex-1 flex-row items-center">
              <Icon
                name="list-bullets"
                className={classnames(
                  'w-12',
                  isHydratedForDerivedDisplaySet ? 'text-primary-light' : 'text-secondary-light'
                )}
              />
              <Tooltip
                position="bottom"
                content={<Typography>{modalityTooltip}</Typography>}
              >
                <div
                  className={classnames(
                    'rounded-sm px-3 text-lg',
                    isHydratedForDerivedDisplaySet
                      ? 'bg-primary-light text-black'
                      : 'bg-primary-main text-white'
                  )}
                >
                  {modality}
                </div>
              </Tooltip>
              <span className="ml-4 text-base text-blue-300">{seriesDate}</span>
              <DisplaySetMessageListTooltip
                messages={messages}
                id={`display-set-tooltip-${displaySetInstanceUID}`}
              />
            </div>
            <div className="flex flex-row">
              {canReject && (
                <Icon
                  name="old-trash"
                  style={
   
   { minWidth: '12px' }}
                  className="ml-4 w-3 text-red-500"
                  onClick={onReject}
                />
              )}
              {/* <div className="ml-4 break-all text-base text-white">{description}</div> */}
            </div>
          </div>
        </div>
      </div>
    );
  } else {
    return (
      <div
        className={classnames(
          'flex flex-1 cursor-pointer select-none flex-row rounded outline-none hover:border-blue-300 focus:border-blue-300',
          isActive ? 'border-primary-light border-2' : 'border border-transparent'
        )}
        style={
   
   {
          padding: isActive ? '11px' : '12px',
        }}
        id={`thumbnail-${displaySetInstanceUID}`}
        onClick={onClick}
        onDoubleClick={onDoubleClick}
        onTouchEnd={handleTouchEnd}
        role="button"
        tabIndex="0"
        data-cy={`study-browser-thumbnail-no-image`}
      >
        <div ref={drag}>
          <div className="flex flex-1 flex-col">
            <div className="mb-2 flex flex-1 flex-row items-center">
              <Icon
                name="list-bullets"
                className={classnames(
                  'w-12',
                  isHydratedForDerivedDisplaySet ? 'text-primary-light' : 'text-secondary-light'
                )}
              />
              <Tooltip
                position="bottom"
                content={<Typography>{modalityTooltip}</Typography>}
              >
                <div
                  className={classnames(
                    'rounded-sm px-3 text-lg',
                    isHydratedForDerivedDisplaySet
                      ? 'bg-primary-light text-black'
                      : 'bg-primary-main text-white'
                  )}
                >
                  {modality}
                </div>
              </Tooltip>
              <span className="ml-4 text-base text-blue-300">{seriesDate}</span>
              <DisplaySetMessageListTooltip
                messages={messages}
                id={`display-set-tooltip-${displaySetInstanceUID}`}
              />
            </div>
            <div className="flex flex-row">
              {canReject && (
                <Icon
                  name="old-trash"
                  style={
   
   { minWidth: '12px' }}
                  className="ml-4 w-3 text-red-500"
                  onClick={onReject}
                />
              )}
              <div className="ml-4 break-all text-base text-white">{description}</div>
            </div>
          </div>
        </div>
      </div>
    );
  }
};

ThumbnailTracked

  //判断当前是否是移动设备
  let isMob = isMobile();
  localStorage.setItem('isMobile', isMob);
  if (isMob) {
    return (
      <div
        className={classnames('flex flex-1 cursor-pointer flex-row px-3 outline-none', className)}
        id={`thumbnail-${displaySetInstanceUID}`}
      >
        {/* <div className="flex-2 flex flex-col items-center">
          <div
            className={classnames(
              'relative mb-2 flex cursor-pointer flex-col items-center justify-start p-2',
              isTracked && 'rounded-sm hover:bg-gray-900'
            )}
          >
            <Tooltip
              position="right"
              content={
                <div className="flex flex-1 flex-row">
                  <div className="flex-2 flex items-center justify-center pr-4">
                    <Icon
                      name="info-link"
                      className="text-primary-active"
                    />
                  </div>
                  <div className="flex flex-1 flex-col">
                    <span>
                      <span className="text-white">
                        {isTracked ? t('Series is tracked') : t('Series is untracked')}
                      </span>
                    </span>
                  </div>
                </div>
              }
            >
              <Icon
                name={trackedIcon}
                className="text-primary-light mb-2 w-4"
              />
            </Tooltip>
          </div>
          {isTracked && (
            <div onClick={onClickUntrack}>
              <Icon
                name="cancel"
                className="text-primary-active w-4"
              />
            </div>
          )}
        </div> */}
        <ThumbnailAPP
          displaySetInstanceUID={displaySetInstanceUID}
          imageSrc={imageSrc}
          imageAltText={imageAltText}
          dragData={dragData}
          description={description}
          seriesNumber={seriesNumber}
          messages={messages}
          numInstances={numInstances}
          countIcon={countIcon}
          loadingProgress={loadingProgress}
          isActive={isActive}
          onClick={onClick}
          onDoubleClick={onDoubleClick}
        />
      </div>
    );
  } else {
    return (
      <div
        className={classnames('flex flex-1 cursor-pointer flex-row px-3 outline-none', className)}
        id={`thumbnail-${displaySetInstanceUID}`}
      >
        <div className="flex-2 flex flex-col items-center">
          <div
            className={classnames(
              'relative mb-2 flex cursor-pointer flex-col items-center justify-start p-2',
              isTracked && 'rounded-sm hover:bg-gray-900'
            )}
          >
            <Tooltip
              position="right"
              content={
                <div className="flex flex-1 flex-row">
                  <div className="flex-2 flex items-center justify-center pr-4">
                    <Icon
                      name="info-link"
                      className="text-primary-active"
                    />
                  </div>
                  <div className="flex flex-1 flex-col">
                    <span>
                      <span className="text-white">
                        {isTracked ? t('Series is tracked') : t('Series is untracked')}
                      </span>
                    </span>
                  </div>
                </div>
              }
            >
              <Icon
                name={trackedIcon}
                className="text-primary-light mb-2 w-4"
              />
            </Tooltip>
          </div>
          {isTracked && (
            <div onClick={onClickUntrack}>
              <Icon
                name="cancel"
                className="text-primary-active w-4"
              />
            </div>
          )}
        </div>
        <Thumbnail
          displaySetInstanceUID={displaySetInstanceUID}
          imageSrc={imageSrc}
          imageAltText={imageAltText}
          dragData={dragData}
          description={description}
          seriesNumber={seriesNumber}
          messages={messages}
          numInstances={numInstances}
          countIcon={countIcon}
          loadingProgress={loadingProgress}
          isActive={isActive}
          onClick={onClick}
          onDoubleClick={onDoubleClick}
        />
      </div>
    );
  }

样式自己调整吧,我也是自己慢慢研究的

具体效果是这样的,可以触屏滑动

中间的 图片改造

import isMobile from '../../../../platform/app/src/utils/isMobile';

因为有滚动条,而且 还有左右结构 ,挺难改的,下面那几个样式 我修改了, 我把flex 给删掉了,加了一个判断,判断是否是移动端模式

额 剩下的忘记了

现在就差让中间的图片 放大点有点太小了

我发现了 是照片本身就小,其他的有大的

猜你喜欢

转载自blog.csdn.net/qq_45947672/article/details/141883661
今日推荐