pages_zichan_transfer.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. import React, { useState, useEffect } from 'react';
  2. import {
  3. Button, Table, Space,
  4. Form, Input, Select, message, Modal,
  5. Card, Row, Col, Typography,
  6. Tag, DatePicker
  7. } from 'antd';
  8. import {
  9. useQuery,
  10. } from '@tanstack/react-query';
  11. import dayjs from 'dayjs';
  12. import 'dayjs/locale/zh-cn';
  13. import type {
  14. ZichanInfo, ZichanTransLog
  15. } from '../share/monitorTypes.ts';
  16. import {
  17. AssetTransferType,
  18. AssetTransferTypeNameMap, AssetTransferTypeColorMap,
  19. } from '../share/monitorTypes.ts';
  20. import { ZichanAPI, ZichanTransferAPI } from './api/index.ts';
  21. import { getEnumOptions } from './utils.ts';
  22. const { Title } = Typography;
  23. // 资产流转管理页面
  24. export const ZichanTransferPage = () => {
  25. const [form] = Form.useForm();
  26. const [formMode, setFormMode] = useState<'create' | 'edit'>('create');
  27. const [editingId, setEditingId] = useState<number | null>(null);
  28. const [modalVisible, setModalVisible] = useState(false);
  29. const [isLoading, setIsLoading] = useState(false);
  30. const [zichanOptions, setZichanOptions] = useState<{ label: string, value: number }[]>([]);
  31. const [searchParams, setSearchParams] = useState({
  32. page: 1,
  33. limit: 10,
  34. asset_id: undefined as number | undefined,
  35. asset_transfer: undefined as AssetTransferType | undefined
  36. });
  37. // 资产流转类型选项
  38. const transferTypeOptions = getEnumOptions(AssetTransferType, AssetTransferTypeNameMap);
  39. // 获取资产列表用于下拉选择
  40. useEffect(() => {
  41. const fetchZichanList = async () => {
  42. try {
  43. const result = await ZichanAPI.getZichanList({ limit: 100 });
  44. const options = result.data.map((item: ZichanInfo) => ({
  45. label: `${item.asset_name} (ID:${item.id})`,
  46. value: item.id
  47. }));
  48. setZichanOptions(options);
  49. } catch (error) {
  50. console.error('获取资产列表失败', error);
  51. }
  52. };
  53. fetchZichanList();
  54. }, []);
  55. // 查询资产流转记录列表
  56. const {
  57. data: transferResult = { data: [], pagination: { total: 0, current: 1, pageSize: 10 } },
  58. isLoading: isFetching,
  59. refetch
  60. } = useQuery({
  61. queryKey: ['zichan-transfer', searchParams],
  62. queryFn: () => ZichanTransferAPI.getTransferList(searchParams),
  63. });
  64. // 提取数据和分页信息
  65. const transferList = transferResult.data || [];
  66. const pagination = transferResult.pagination || { total: 0, current: 1, pageSize: 10 };
  67. // 处理表单提交
  68. const handleSubmit = async (values: Partial<ZichanTransLog>) => {
  69. try {
  70. setIsLoading(true);
  71. // 创建一个新的对象以避免修改原始值
  72. const submitData = { ...values };
  73. // 处理流转时间格式
  74. if (submitData.transfer_time && dayjs.isDayjs(submitData.transfer_time)) {
  75. // 使用字符串格式,确保后端可以正确处理
  76. submitData.transfer_time = (submitData.transfer_time as any).format('YYYY-MM-DD HH:mm:ss');
  77. }
  78. if (formMode === 'create') {
  79. await ZichanTransferAPI.createTransfer(submitData);
  80. message.success('资产流转记录创建成功');
  81. } else {
  82. if (editingId) {
  83. await ZichanTransferAPI.updateTransfer(editingId, submitData);
  84. message.success('资产流转记录更新成功');
  85. }
  86. }
  87. setModalVisible(false);
  88. refetch();
  89. } catch (error: any) {
  90. message.error(error.response?.data?.error || '操作失败');
  91. } finally {
  92. setIsLoading(false);
  93. }
  94. };
  95. // 处理编辑
  96. const handleEdit = async (id: number) => {
  97. try {
  98. setIsLoading(true);
  99. const data = await ZichanTransferAPI.getTransfer(id);
  100. // 处理日期格式
  101. if (data.transfer_time) {
  102. // 使用dayjs解析时间,确保传入字符串
  103. data.transfer_time = dayjs(String(data.transfer_time));
  104. }
  105. form.setFieldsValue(data);
  106. setEditingId(id);
  107. setFormMode('edit');
  108. setModalVisible(true);
  109. } catch (error: any) {
  110. message.error(error.response?.data?.error || '获取资产流转记录详情失败');
  111. } finally {
  112. setIsLoading(false);
  113. }
  114. };
  115. // 处理删除
  116. const handleDelete = async (id: number) => {
  117. try {
  118. await ZichanTransferAPI.deleteTransfer(id);
  119. message.success('资产流转记录删除成功');
  120. refetch();
  121. } catch (error: any) {
  122. message.error(error.response?.data?.error || '删除资产流转记录失败');
  123. }
  124. };
  125. // 处理搜索
  126. const handleSearch = (values: any) => {
  127. setSearchParams({
  128. ...searchParams,
  129. page: 1, // 重置为第一页
  130. asset_id: values.asset_id,
  131. asset_transfer: values.asset_transfer
  132. });
  133. };
  134. // 处理页码变化
  135. const handlePageChange = (page: number, pageSize?: number) => {
  136. setSearchParams({
  137. ...searchParams,
  138. page,
  139. limit: pageSize || 10
  140. });
  141. };
  142. // 处理新增
  143. const handleAdd = () => {
  144. form.resetFields();
  145. form.setFieldsValue({
  146. transfer_time: dayjs() // 默认设置为当前时间
  147. });
  148. setFormMode('create');
  149. setEditingId(null);
  150. setModalVisible(true);
  151. };
  152. // 表格列定义
  153. const columns = [
  154. {
  155. title: 'ID',
  156. dataIndex: 'id',
  157. key: 'id',
  158. width: 80
  159. },
  160. {
  161. title: '资产',
  162. dataIndex: 'asset_id',
  163. key: 'asset_id',
  164. render: (asset_id: number, record: ZichanTransLog) => {
  165. return record.asset_info ? record.asset_info.asset_name : `资产ID: ${asset_id}`;
  166. }
  167. },
  168. {
  169. title: '流转类型',
  170. dataIndex: 'asset_transfer',
  171. key: 'asset_transfer',
  172. render: (type: AssetTransferType) => {
  173. return <Tag color={AssetTransferTypeColorMap[type] || 'default'}>
  174. {AssetTransferTypeNameMap[type] || '未知类型'}
  175. </Tag>;
  176. }
  177. },
  178. {
  179. title: '人员',
  180. dataIndex: 'person',
  181. key: 'person'
  182. },
  183. {
  184. title: '部门',
  185. dataIndex: 'department',
  186. key: 'department'
  187. },
  188. {
  189. title: '联系电话',
  190. dataIndex: 'phone',
  191. key: 'phone'
  192. },
  193. {
  194. title: '流转事由',
  195. dataIndex: 'transfer_reason',
  196. key: 'transfer_reason',
  197. ellipsis: true
  198. },
  199. {
  200. title: '流转时间',
  201. dataIndex: 'transfer_time',
  202. key: 'transfer_time',
  203. render: (date: string) => date ? dayjs(date).format('YYYY-MM-DD HH:mm:ss') : '-'
  204. },
  205. {
  206. title: '操作',
  207. key: 'action',
  208. width: 200,
  209. render: (_: any, record: ZichanTransLog) => (
  210. <Space>
  211. <Button size="small" type="primary" onClick={() => handleEdit(record.id)}>编辑</Button>
  212. <Button size="small" danger onClick={() =>
  213. Modal.confirm({
  214. title: '确认删除',
  215. content: `确定要删除此资产流转记录吗?`,
  216. onOk: () => handleDelete(record.id)
  217. })
  218. }>删除</Button>
  219. </Space>
  220. )
  221. }
  222. ];
  223. return (
  224. <div>
  225. <Title level={2}>资产流转管理</Title>
  226. <Card>
  227. <Form layout="inline" onFinish={handleSearch} style={{ marginBottom: 16 }}>
  228. <Form.Item name="asset_id" label="选择资产">
  229. <Select
  230. placeholder="请选择资产"
  231. style={{ width: 240 }}
  232. allowClear
  233. options={zichanOptions}
  234. showSearch
  235. filterOption={(input, option) =>
  236. (String(option?.label ?? '')).toLowerCase().includes(input.toLowerCase())
  237. }
  238. />
  239. </Form.Item>
  240. <Form.Item name="asset_transfer" label="流转类型">
  241. <Select
  242. placeholder="请选择流转类型"
  243. style={{ width: 140 }}
  244. allowClear
  245. options={transferTypeOptions}
  246. />
  247. </Form.Item>
  248. <Form.Item>
  249. <Button type="primary" htmlType="submit">查询</Button>
  250. </Form.Item>
  251. <Form.Item>
  252. <Button type="primary" onClick={handleAdd}>新增流转记录</Button>
  253. </Form.Item>
  254. </Form>
  255. <Table
  256. columns={columns}
  257. dataSource={transferList}
  258. rowKey="id"
  259. loading={isFetching}
  260. pagination={{
  261. current: pagination.current,
  262. pageSize: pagination.pageSize,
  263. total: pagination.total,
  264. onChange: handlePageChange,
  265. showSizeChanger: true,
  266. showTotal: (total) => `共 ${total} 条记录`
  267. }}
  268. />
  269. <Modal
  270. title={formMode === 'create' ? '新增资产流转记录' : '编辑资产流转记录'}
  271. open={modalVisible}
  272. onCancel={() => setModalVisible(false)}
  273. footer={null}
  274. width={720}
  275. >
  276. <Form
  277. form={form}
  278. layout="vertical"
  279. onFinish={handleSubmit}
  280. >
  281. <Row gutter={16}>
  282. <Col span={12}>
  283. <Form.Item
  284. name="asset_id"
  285. label="选择资产"
  286. rules={[{ required: true, message: '请选择资产' }]}
  287. >
  288. <Select
  289. placeholder="请选择资产"
  290. options={zichanOptions}
  291. showSearch
  292. filterOption={(input, option) =>
  293. (String(option?.label ?? '')).toLowerCase().includes(input.toLowerCase())
  294. }
  295. />
  296. </Form.Item>
  297. </Col>
  298. <Col span={12}>
  299. <Form.Item
  300. name="asset_transfer"
  301. label="流转类型"
  302. rules={[{ required: true, message: '请选择流转类型' }]}
  303. >
  304. <Select
  305. placeholder="请选择流转类型"
  306. options={transferTypeOptions}
  307. />
  308. </Form.Item>
  309. </Col>
  310. </Row>
  311. <Row gutter={16}>
  312. <Col span={12}>
  313. <Form.Item
  314. name="person"
  315. label="人员"
  316. rules={[{ required: true, message: '请输入人员姓名' }]}
  317. >
  318. <Input placeholder="请输入人员姓名" />
  319. </Form.Item>
  320. </Col>
  321. <Col span={12}>
  322. <Form.Item
  323. name="department"
  324. label="部门"
  325. >
  326. <Input placeholder="请输入部门" />
  327. </Form.Item>
  328. </Col>
  329. </Row>
  330. <Row gutter={16}>
  331. <Col span={12}>
  332. <Form.Item
  333. name="phone"
  334. label="联系电话"
  335. >
  336. <Input placeholder="请输入联系电话" />
  337. </Form.Item>
  338. </Col>
  339. <Col span={12}>
  340. <Form.Item
  341. name="transfer_time"
  342. label="流转时间"
  343. rules={[{ required: true, message: '请选择流转时间' }]}
  344. >
  345. <DatePicker
  346. showTime={{ format: 'HH:mm:ss' }}
  347. format="YYYY-MM-DD HH:mm:ss"
  348. style={{ width: '100%' }}
  349. placeholder="请选择流转时间"
  350. />
  351. </Form.Item>
  352. </Col>
  353. </Row>
  354. <Form.Item
  355. name="transfer_reason"
  356. label="流转事由"
  357. >
  358. <Input.TextArea rows={4} placeholder="请输入流转事由" />
  359. </Form.Item>
  360. <Form.Item>
  361. <Space>
  362. <Button type="primary" htmlType="submit" loading={isLoading}>
  363. {formMode === 'create' ? '创建' : '保存'}
  364. </Button>
  365. <Button onClick={() => setModalVisible(false)}>取消</Button>
  366. </Space>
  367. </Form.Item>
  368. </Form>
  369. </Modal>
  370. </Card>
  371. </div>
  372. );
  373. };