You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

table.tsx 6.1 kB

11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
11 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * @Author: 赵伟
  3. * @Date: 2024-06-26 10:05:52
  4. * @Description: Table Cell 自定义 render
  5. */
  6. import { isEmpty } from '@/utils';
  7. import { formatDate } from '@/utils/date';
  8. import { Tooltip, TooltipProps, Typography } from 'antd';
  9. import dayjs from 'dayjs';
  10. import React from 'react';
  11. import { formatEnum, type EnumOptions } from './format';
  12. export enum TableCellValueType {
  13. /** 序号 */
  14. Index = 'Index',
  15. /** 文本 */
  16. Text = 'Text',
  17. /** 日期 */
  18. Date = 'Date',
  19. /** 数组 */
  20. Array = 'Array',
  21. /** 链接 */
  22. Link = 'Link',
  23. /** 枚举 */
  24. Enum = 'Enum',
  25. /** 自定义 */
  26. Custom = 'Custom',
  27. }
  28. export type TableCellValueOptions<T> = {
  29. /** 页数,类型为 Index 时有效 */
  30. page?: number;
  31. /** 分页大小,类型为 Index 时有效 */
  32. pageSize?: number;
  33. /** 取数组对象的哪个属性值,类型为 Array 时有效 */
  34. property?: string;
  35. /** 日期格式,类型为 Date 时有效*/
  36. dateFormat?: string;
  37. /** 链接点击回调,类型为 Link 时有效 */
  38. onClick?: (record: T, e: React.MouseEvent) => void;
  39. /** 枚举选项,类型为 Enum 时有效*/
  40. options?: EnumOptions[];
  41. /** 自定义函数,类型为 Custom 时有效*/
  42. format?: (
  43. value: any | undefined | null,
  44. record?: T,
  45. index?: number,
  46. ) => React.ReactNode | undefined | null;
  47. /** 省略时是否可以复制 */
  48. copyable?: boolean;
  49. };
  50. type TableCellFormatter = (value: any | undefined | null) => string | undefined | null;
  51. /**
  52. * 日期转换函数
  53. * @param {string | undefined} dateFormat - 日期格式
  54. * @returns {TableCellFormatter} Table cell 渲染函数
  55. */
  56. function formatDateText(dateFormat?: string): TableCellFormatter {
  57. return (value: any | undefined | null): ReturnType<TableCellFormatter> => {
  58. if (value === undefined || value === null || value === '') {
  59. return null;
  60. }
  61. if (!dayjs(value).isValid()) {
  62. return null;
  63. }
  64. return formatDate(value, dateFormat);
  65. };
  66. }
  67. /**
  68. * 数组转换函数,将数组元素转换为字符串,用逗号分隔
  69. * @param {string} property - 如果数组元素是对象,那么取数组元素的某个属性
  70. * @returns {TableCellFormatter} Table cell 渲染函数
  71. */
  72. function formatArray(property?: string): TableCellFormatter {
  73. return (value: any | undefined | null): ReturnType<TableCellFormatter> => {
  74. if (
  75. value === undefined ||
  76. value === null ||
  77. Array.isArray(value) === false ||
  78. value.length === 0
  79. ) {
  80. return null;
  81. }
  82. const list =
  83. property && typeof value[0] === 'object' ? value.map((item) => item[property]) : value;
  84. return list.join(',');
  85. };
  86. }
  87. /**
  88. * Table cell render 函数
  89. * @param ellipsis - 是否省略
  90. * @param type - 类型
  91. * @param options - 选项
  92. * @returns Ant Design Table 的 render
  93. */
  94. function tableCellRender<T>(
  95. ellipsis: boolean | TooltipProps | 'auto' = false,
  96. type: TableCellValueType = TableCellValueType.Text,
  97. options?: TableCellValueOptions<T>,
  98. ) {
  99. return (value: any | undefined | null, record: T, index: number) => {
  100. let text = value;
  101. switch (type) {
  102. case TableCellValueType.Index:
  103. text = (options?.page ?? 0) * (options?.pageSize ?? 0) + index + 1;
  104. break;
  105. case TableCellValueType.Text:
  106. case TableCellValueType.Link:
  107. text = value;
  108. break;
  109. case TableCellValueType.Date:
  110. text = formatDateText(options?.dateFormat)(value);
  111. break;
  112. case TableCellValueType.Array:
  113. text = formatArray(options?.property)(value);
  114. break;
  115. case TableCellValueType.Enum:
  116. if (options?.options) {
  117. text = formatEnum(options.options)(value);
  118. }
  119. break;
  120. case TableCellValueType.Custom:
  121. text = options?.format?.(value, record, index);
  122. break;
  123. default:
  124. break;
  125. }
  126. if (ellipsis === 'auto' && text) {
  127. return renderCell(type, text, 'auto', record, options);
  128. } else if (ellipsis && text) {
  129. const tooltipProps = typeof ellipsis === 'object' ? ellipsis : {};
  130. const { overlayStyle, ...rest } = tooltipProps;
  131. return (
  132. <Tooltip {...rest} overlayStyle={{ maxWidth: 400, ...overlayStyle }} title={text}>
  133. {renderCell(type, text, true, record, options)}
  134. </Tooltip>
  135. );
  136. } else {
  137. return renderCell(type, text, false, record, options);
  138. }
  139. };
  140. }
  141. function renderCell<T>(
  142. type: TableCellValueType,
  143. text: any | undefined | null,
  144. ellipsis: boolean | 'auto',
  145. record: T,
  146. options?: TableCellValueOptions<T>,
  147. ) {
  148. return type === TableCellValueType.Link
  149. ? renderLink(text, ellipsis, record, options)
  150. : renderText(text, ellipsis, options);
  151. }
  152. function renderLink<T>(
  153. text: any | undefined | null,
  154. ellipsis: boolean | 'auto',
  155. record: T,
  156. options?: TableCellValueOptions<T>,
  157. ) {
  158. const { onClick } = options ?? {};
  159. return (
  160. <a className="kf-table-row-link" onClick={(e) => onClick?.(record, e)}>
  161. {renderText(text, ellipsis, options)}
  162. </a>
  163. );
  164. }
  165. function renderText<T>(
  166. text: any | undefined | null,
  167. ellipsis: boolean | 'auto',
  168. options?: TableCellValueOptions<T>,
  169. ) {
  170. const { copyable } = options ?? {};
  171. if (ellipsis === 'auto') {
  172. return (
  173. <Typography.Paragraph
  174. style={{ marginBottom: 0 }}
  175. copyable={copyable}
  176. ellipsis={{
  177. tooltip: {
  178. title: text,
  179. destroyTooltipOnHide: true,
  180. overlayStyle: { maxWidth: 400 },
  181. },
  182. }}
  183. >
  184. {!isEmpty(text) ? text : '--'}
  185. </Typography.Paragraph>
  186. );
  187. }
  188. return (
  189. <span
  190. style={
  191. ellipsis
  192. ? {
  193. whiteSpace: 'nowrap',
  194. overflow: 'hidden',
  195. textOverflow: 'ellipsis',
  196. wordBreak: 'break-all',
  197. display: 'inline-block',
  198. maxWidth: '100%',
  199. verticalAlign: 'middle',
  200. }
  201. : undefined
  202. }
  203. >
  204. {!isEmpty(text) ? text : '--'}
  205. </span>
  206. );
  207. }
  208. export default tableCellRender;