2
0

ProTableTest.tsx 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. import React, { useRef, useState } from "react";
  2. import { Button, Badge, message } from "antd";
  3. import { PlusOutlined } from "@ant-design/icons";
  4. import ProTable, { type ActionType } from "./ProTable";
  5. // 模拟数据类型
  6. interface IChannelItem {
  7. id: number;
  8. uid: string;
  9. title: string;
  10. summary: string;
  11. type: "translation" | "nissaya" | "commentary" | "original";
  12. role?: "owner" | "manager" | "editor" | "member";
  13. publicity: number;
  14. created_at: string;
  15. }
  16. // 模拟 API 响应
  17. const mockApiResponse = (page: number, pageSize: number, keyword: string) => {
  18. const mockData: IChannelItem[] = Array.from({ length: 50 }, (_, i) => ({
  19. id: i + 1,
  20. uid: `channel-${i + 1}`,
  21. title: `Channel ${i + 1} ${keyword ? `(含关键词: ${keyword})` : ""}`,
  22. summary: `这是第 ${i + 1} 个频道的简介`,
  23. type: ["translation", "nissaya", "commentary", "original"][i % 4] as any,
  24. role: ["owner", "manager", "editor", "member"][i % 4] as any,
  25. publicity: i % 3,
  26. created_at: new Date(2024, 0, i + 1).toISOString(),
  27. }));
  28. const start = (page - 1) * pageSize;
  29. const end = start + pageSize;
  30. // 模拟关键词搜索
  31. let filtered = mockData;
  32. if (keyword) {
  33. filtered = mockData.filter((item) =>
  34. item.title.toLowerCase().includes(keyword.toLowerCase())
  35. );
  36. }
  37. return {
  38. data: {
  39. rows: filtered.slice(start, end),
  40. count: filtered.length,
  41. },
  42. };
  43. };
  44. // 测试组件
  45. const ProTableTest: React.FC = () => {
  46. const ref = useRef<ActionType | null>(null);
  47. const [activeKey, setActiveKey] = useState<React.Key>("my");
  48. const [myNumber] = useState(25);
  49. const [collaborationNumber] = useState(15);
  50. const renderBadge = (count: number, active = false) => {
  51. return (
  52. <Badge
  53. count={count}
  54. style={{
  55. marginBlockStart: -2,
  56. marginInlineStart: 4,
  57. color: active ? "#1890FF" : "#999",
  58. backgroundColor: active ? "#E6F7FF" : "#eee",
  59. }}
  60. />
  61. );
  62. };
  63. return (
  64. <div style={{ padding: 24 }}>
  65. <h1>ProTable 测试示例</h1>
  66. <ProTable<IChannelItem>
  67. actionRef={ref}
  68. columns={[
  69. {
  70. title: "序号",
  71. dataIndex: "id",
  72. key: "id",
  73. width: 50,
  74. search: false,
  75. },
  76. {
  77. title: "标题",
  78. dataIndex: "title",
  79. width: 250,
  80. key: "title",
  81. tooltip: "过长会自动收缩",
  82. ellipsis: true,
  83. render: (_text, row, _index, _action) => {
  84. return (
  85. <Button
  86. type="link"
  87. onClick={() => {
  88. message.info(`点击了: ${row.title}`);
  89. console.log("选中的频道:", row);
  90. }}
  91. >
  92. {row.title}
  93. </Button>
  94. );
  95. },
  96. },
  97. {
  98. title: "简介",
  99. dataIndex: "summary",
  100. key: "summary",
  101. tooltip: "过长会自动收缩",
  102. ellipsis: true,
  103. },
  104. {
  105. title: "角色",
  106. dataIndex: "role",
  107. key: "role",
  108. width: 80,
  109. search: false,
  110. filters: true,
  111. onFilter: true,
  112. valueEnum: {
  113. all: { text: "全部", status: "Default" },
  114. owner: { text: "所有者" },
  115. manager: { text: "管理员" },
  116. editor: { text: "编辑" },
  117. member: { text: "成员" },
  118. },
  119. },
  120. {
  121. title: "类型",
  122. dataIndex: "type",
  123. key: "type",
  124. width: 80,
  125. search: false,
  126. filters: true,
  127. onFilter: true,
  128. valueEnum: {
  129. all: { text: "全部", status: "Default" },
  130. translation: { text: "翻译", status: "Success" },
  131. nissaya: { text: "Nissaya", status: "Processing" },
  132. commentary: { text: "注释", status: "Default" },
  133. original: { text: "原创", status: "Default" },
  134. },
  135. },
  136. {
  137. title: "公开性",
  138. dataIndex: "publicity",
  139. key: "publicity",
  140. width: 80,
  141. search: false,
  142. filters: true,
  143. onFilter: true,
  144. valueEnum: {
  145. 0: { text: "私有" },
  146. 1: { text: "组内" },
  147. 2: { text: "公开" },
  148. },
  149. },
  150. {
  151. title: "创建时间",
  152. key: "created_at",
  153. width: 120,
  154. search: false,
  155. dataIndex: "created_at",
  156. valueType: "date",
  157. sorter: true,
  158. },
  159. {
  160. title: "操作",
  161. key: "option",
  162. width: 120,
  163. valueType: "option",
  164. hideInTable: activeKey !== "my",
  165. render: (_text, row, _index, action) => {
  166. return [
  167. <Button
  168. key="edit"
  169. type="link"
  170. onClick={() => message.info(`编辑: ${row.title}`)}
  171. >
  172. 编辑
  173. </Button>,
  174. <Button
  175. key="delete"
  176. type="link"
  177. danger
  178. onClick={() => {
  179. message.success(`删除成功: ${row.title}`);
  180. action.reload();
  181. }}
  182. >
  183. 删除
  184. </Button>,
  185. ];
  186. },
  187. },
  188. ]}
  189. request={async (params = {}, sorter, filter) => {
  190. console.log("请求参数:", { params, sorter, filter });
  191. // 模拟网络延迟
  192. await new Promise((resolve) => setTimeout(resolve, 500));
  193. const page = params.current || 1;
  194. const pageSize = params.pageSize || 20;
  195. const keyword = params.keyword || "";
  196. const res = mockApiResponse(page, pageSize, keyword);
  197. return {
  198. total: res.data.count,
  199. success: true,
  200. data: res.data.rows.map((item, id) => ({
  201. ...item,
  202. id: (page - 1) * pageSize + id + 1,
  203. })),
  204. };
  205. }}
  206. rowKey="uid"
  207. bordered
  208. pagination={{
  209. showQuickJumper: true,
  210. showSizeChanger: true,
  211. defaultPageSize: 10,
  212. }}
  213. search={false}
  214. options={{
  215. search: true,
  216. }}
  217. toolBarRender={() => [
  218. <Button
  219. key="refresh"
  220. onClick={() => {
  221. ref.current?.reload();
  222. message.success("刷新成功");
  223. }}
  224. >
  225. 刷新
  226. </Button>,
  227. <Button
  228. key="reset"
  229. onClick={() => {
  230. ref.current?.reset();
  231. message.success("重置成功");
  232. }}
  233. >
  234. 重置
  235. </Button>,
  236. <Button
  237. key="create"
  238. icon={<PlusOutlined />}
  239. type="primary"
  240. onClick={() => message.info("创建新频道")}
  241. >
  242. 创建
  243. </Button>,
  244. ]}
  245. toolbar={{
  246. menu: {
  247. activeKey,
  248. items: [
  249. {
  250. key: "my",
  251. label: (
  252. <span>
  253. 我的工作室
  254. {renderBadge(myNumber, activeKey === "my")}
  255. </span>
  256. ),
  257. },
  258. {
  259. key: "collaboration",
  260. label: (
  261. <span>
  262. 协作
  263. {renderBadge(
  264. collaborationNumber,
  265. activeKey === "collaboration"
  266. )}
  267. </span>
  268. ),
  269. },
  270. {
  271. key: "community",
  272. label: (
  273. <span>
  274. 社区
  275. {renderBadge(10, activeKey === "community")}
  276. </span>
  277. ),
  278. },
  279. ],
  280. onChange(key) {
  281. console.log("切换标签:", key);
  282. setActiveKey(key);
  283. ref.current?.reload();
  284. },
  285. },
  286. }}
  287. headerTitle="频道列表"
  288. />
  289. <div style={{ marginTop: 24, padding: 16, background: "#f5f5f5" }}>
  290. <h3>测试功能:</h3>
  291. <ul>
  292. <li>✅ 切换标签页(我的工作室/协作/社区)</li>
  293. <li>✅ 搜索功能(输入关键词搜索)</li>
  294. <li>✅ 分页(切换页码、调整每页数量)</li>
  295. <li>✅ 排序(点击"创建时间"列头排序)</li>
  296. <li>✅ 过滤(点击"角色"、"类型"、"公开性"列头过滤)</li>
  297. <li>✅ 刷新按钮(手动刷新表格)</li>
  298. <li>✅ 重置按钮(重置所有过滤和排序)</li>
  299. <li>✅ 操作列(仅在"我的工作室"显示)</li>
  300. <li>✅ 文本省略(标题和简介过长自动省略)</li>
  301. <li>✅ 日期格式化(创建时间自动格式化)</li>
  302. </ul>
  303. </div>
  304. </div>
  305. );
  306. };
  307. export default ProTableTest;