ItemForm.jsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import { useEffect, useState } from 'react'
  2. import { Modal, Form, Input, InputNumber, message, Spin } from 'antd'
  3. import { itemApi } from '../services/api'
  4. const MOBILE_BREAKPOINT = 768
  5. function ItemForm({ visible, item, onSuccess, onCancel }) {
  6. const [form] = Form.useForm()
  7. const [submitting, setSubmitting] = useState(false)
  8. const [loading, setLoading] = useState(false)
  9. const [isMobile, setIsMobile] = useState(window.innerWidth < MOBILE_BREAKPOINT)
  10. const isEdit = !!item
  11. useEffect(() => {
  12. const handleResize = () => {
  13. setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
  14. }
  15. window.addEventListener('resize', handleResize)
  16. return () => window.removeEventListener('resize', handleResize)
  17. }, [])
  18. useEffect(() => {
  19. if (visible) {
  20. setLoading(true)
  21. if (item) {
  22. form.setFieldsValue({
  23. name: item.name,
  24. unit_price: item.unit_price
  25. })
  26. } else {
  27. form.resetFields()
  28. }
  29. setLoading(false)
  30. }
  31. }, [visible, item, form])
  32. const handleOk = async () => {
  33. try {
  34. const values = await form.validateFields()
  35. setSubmitting(true)
  36. if (isEdit) {
  37. await itemApi.update({ id: item.id, ...values })
  38. message.success('更新成功')
  39. } else {
  40. await itemApi.create(values)
  41. message.success('创建成功')
  42. }
  43. onSuccess()
  44. } catch (error) {
  45. if (error.errorFields) {
  46. return
  47. }
  48. message.error(error.message || '操作失败')
  49. } finally {
  50. setSubmitting(false)
  51. }
  52. }
  53. const validateName = (_, value) => {
  54. if (!value || !value.trim()) {
  55. return Promise.reject(new Error('请输入物品名称'))
  56. }
  57. return Promise.resolve()
  58. }
  59. const validateUnitPrice = (_, value) => {
  60. if (value === null || value === undefined || value === '') {
  61. return Promise.reject(new Error('请输入单价'))
  62. }
  63. if (typeof value !== 'number' || value <= 0) {
  64. return Promise.reject(new Error('单价必须是正数'))
  65. }
  66. return Promise.resolve()
  67. }
  68. return (
  69. <Modal
  70. title={isEdit ? '编辑物品' : '新增物品'}
  71. open={visible}
  72. onOk={handleOk}
  73. onCancel={onCancel}
  74. confirmLoading={submitting}
  75. okButtonProps={{ disabled: loading }}
  76. cancelButtonProps={{ disabled: submitting }}
  77. destroyOnClose
  78. okText="确定"
  79. cancelText="取消"
  80. width={isMobile ? '100%' : 520}
  81. style={isMobile ? { top: 20, maxWidth: 'calc(100vw - 32px)', margin: '0 auto' } : undefined}
  82. >
  83. <Spin spinning={loading}>
  84. <Form
  85. form={form}
  86. layout="vertical"
  87. autoComplete="off"
  88. >
  89. <Form.Item
  90. name="name"
  91. label="物品名称"
  92. rules={[{ validator: validateName }]}
  93. >
  94. <Input placeholder="请输入物品名称" maxLength={50} disabled={loading} />
  95. </Form.Item>
  96. <Form.Item
  97. name="unit_price"
  98. label="单价"
  99. rules={[{ validator: validateUnitPrice }]}
  100. >
  101. <InputNumber
  102. placeholder="请输入单价"
  103. min={0.01}
  104. step={0.01}
  105. precision={2}
  106. style={{ width: '100%' }}
  107. prefix="¥"
  108. disabled={loading}
  109. />
  110. </Form.Item>
  111. </Form>
  112. </Spin>
  113. </Modal>
  114. )
  115. }
  116. export default ItemForm