@@ -1,5 +1,5 @@ | |||||
import React, { useState, useEffect, useRef, useContext, MutableRefObject, forwardRef, useImperativeHandle } from 'react'; | import React, { useState, useEffect, useRef, useContext, MutableRefObject, forwardRef, useImperativeHandle } from 'react'; | ||||
import { Space, Table, Button, Input, Select, Divider, Form, Popconfirm, Modal, Radio } from 'antd'; | |||||
import { Space, Table, Button, Input, Badge, Divider, Form, Popconfirm, Modal, Radio } from 'antd'; | |||||
import type { TableColumnsType } from 'antd'; | import type { TableColumnsType } from 'antd'; | ||||
import type { InputRef } from 'antd'; | import type { InputRef } from 'antd'; | ||||
import type { FormInstance } from 'antd/es/form'; | import type { FormInstance } from 'antd/es/form'; | ||||
@@ -274,6 +274,16 @@ export default forwardRef((props, ref) => { | |||||
width: '30%', | width: '30%', | ||||
editable: true, | editable: true, | ||||
}, | }, | ||||
{ | |||||
title: '是否默认属性', | |||||
key: 'isDefault', | |||||
dataIndex: 'isDefault', | |||||
width: 120, | |||||
align: 'center', | |||||
render: (value: number) => { | |||||
return (value === 1 ? <Badge status="success" text="是" /> : <Badge status="error" text="否" />) | |||||
} | |||||
}, | |||||
{ | { | ||||
title: '创建时间', | title: '创建时间', | ||||
dataIndex: 'createTime', | dataIndex: 'createTime', | ||||
@@ -1,5 +1,5 @@ | |||||
import React, { useState, useEffect, useRef, useContext, forwardRef, useImperativeHandle } from 'react'; | import React, { useState, useEffect, useRef, useContext, forwardRef, useImperativeHandle } from 'react'; | ||||
import { Space, Table, Button, Input, Select, Divider, Form, Popconfirm } from 'antd'; | |||||
import { Space, Table, Button, Input, Modal, Radio, Form, Popconfirm, Badge } from 'antd'; | |||||
import type { TableColumnsType } from 'antd'; | import type { TableColumnsType } from 'antd'; | ||||
import type { InputRef } from 'antd'; | import type { InputRef } from 'antd'; | ||||
import type { FormInstance } from 'antd/es/form'; | import type { FormInstance } from 'antd/es/form'; | ||||
@@ -13,6 +13,101 @@ import goodsAttrService from '@/request/service/goods-attr'; | |||||
import { formatDate } from '@/utils/formatTime'; | import { formatDate } from '@/utils/formatTime'; | ||||
import { useSetState } from 'ahooks'; | import { useSetState } from 'ahooks'; | ||||
const AttrEditor = (props: { | |||||
visible: boolean; | |||||
onCancel: (flag?: boolean) => void; | |||||
onSave: (role: GoodsAttrVO) => void; | |||||
}) => { | |||||
const { visible, onCancel, onSave } = props; | |||||
const { runAsync: createApi } = useRequest(goodsAttrService.createGoodsAttrApi, { manual: true }); | |||||
const [saveLoading, setSaveLoading] = useState(false); | |||||
const [form] = Form.useForm(); | |||||
useEffect(() => { | |||||
if (visible) { | |||||
form.setFieldValue("attrStatus", 1); | |||||
} else { | |||||
form.resetFields(); | |||||
} | |||||
}, [visible]); | |||||
const save = async () => { | |||||
await form.validateFields(); | |||||
setSaveLoading(true); | |||||
const fieldValues = form.getFieldsValue(); | |||||
const [error, { msg, code }] = await createApi(fieldValues); | |||||
if (!error && code === 0) { | |||||
onSave(fieldValues); | |||||
} else { | |||||
antdUtils.message?.open({ | |||||
type: 'error', | |||||
content: msg ?? '操作失败', | |||||
}); | |||||
} | |||||
setSaveLoading(false); | |||||
} | |||||
return ( | |||||
<> | |||||
<Modal | |||||
open={visible} | |||||
title={"新建"} | |||||
width={640} | |||||
onOk={save} | |||||
onCancel={() => onCancel()} | |||||
confirmLoading={saveLoading} | |||||
destroyOnClose | |||||
> | |||||
<Form | |||||
form={form} | |||||
onFinish={save} | |||||
labelCol={{ flex: '0 0 120px' }} | |||||
wrapperCol={{ span: 16 }} | |||||
> | |||||
<Form.Item name="attrNameCn" label="属性名称(中文):" | |||||
rules={[ | |||||
{ | |||||
required: true, | |||||
message: '请输属性中文名称', | |||||
}, | |||||
]} | |||||
> | |||||
<Input /> | |||||
</Form.Item> | |||||
<Form.Item name="attrNameEn" label="属性名称(英文):" | |||||
rules={[ | |||||
{ | |||||
required: true, | |||||
message: '请输属性英文名称', | |||||
}, | |||||
]} | |||||
> | |||||
<Input /> | |||||
</Form.Item> | |||||
<Form.Item name="attrStatus" label="可用状态:" | |||||
rules={[ | |||||
{ | |||||
required: true, | |||||
message: '请输选择', | |||||
}, | |||||
]} | |||||
> | |||||
<Radio.Group options={[ | |||||
{ value: 1, label: "正常使用" }, | |||||
{ value: 2, label: "停止使用" } | |||||
]} optionType="default"> | |||||
</Radio.Group> | |||||
</Form.Item> | |||||
</Form> | |||||
</Modal> | |||||
</> | |||||
) | |||||
}; | |||||
const EditableContext = React.createContext<FormInstance<any> | null>(null); | const EditableContext = React.createContext<FormInstance<any> | null>(null); | ||||
interface EditableRowProps { | interface EditableRowProps { | ||||
@@ -106,7 +201,8 @@ type ColumnTypes = Exclude<EditableTableProps['columns'], undefined>; | |||||
export default forwardRef((props, ref) => { | export default forwardRef((props, ref) => { | ||||
useImperativeHandle(ref, () => { | useImperativeHandle(ref, () => { | ||||
addItem | addItem | ||||
}) | |||||
}); | |||||
const [visible, setVisible] = useState<boolean>(false); | |||||
const [dataSource, setDataSource] = useState<GoodsAttrVO[]>([]); | const [dataSource, setDataSource] = useState<GoodsAttrVO[]>([]); | ||||
const [searchFrom] = Form.useForm(); | const [searchFrom] = Form.useForm(); | ||||
@@ -124,9 +220,10 @@ export default forwardRef((props, ref) => { | |||||
const { runAsync: deleteApi } = useRequest(goodsAttrService.deleteGoodsAttrApi, { manual: true }); | const { runAsync: deleteApi } = useRequest(goodsAttrService.deleteGoodsAttrApi, { manual: true }); | ||||
const load = async () => { | const load = async () => { | ||||
const [error, { data }] = await getPageApi(searchFrom.getFieldsValue()); | |||||
const [error, { data }] = await getPageApi(searchState); | |||||
if (!error) { | if (!error) { | ||||
setDataSource(data.list); | setDataSource(data.list); | ||||
setTotal(data.total); | |||||
} | } | ||||
}; | }; | ||||
@@ -196,6 +293,16 @@ export default forwardRef((props, ref) => { | |||||
width: '30%', | width: '30%', | ||||
editable: true, | editable: true, | ||||
}, | }, | ||||
{ | |||||
title: '状态', | |||||
key: 'attrStatus', | |||||
dataIndex: 'attrStatus', | |||||
width: 100, | |||||
align: 'center', | |||||
render: (value: number) => { | |||||
return (value === 1 ? <Badge status="success" text="已开启" /> : <Badge status="error" text="已关闭" />) | |||||
} | |||||
}, | |||||
{ | { | ||||
title: '创建时间', | title: '创建时间', | ||||
dataIndex: 'createTime', | dataIndex: 'createTime', | ||||
@@ -209,9 +316,9 @@ export default forwardRef((props, ref) => { | |||||
title: t("QkOmYwne" /* 操作 */), | title: t("QkOmYwne" /* 操作 */), | ||||
dataIndex: 'operation', | dataIndex: 'operation', | ||||
key: 'action', | key: 'action', | ||||
render: (value: GoodsAttrVO) => | |||||
render: (_, record, index) => | |||||
dataSource.length >= 1 ? ( | dataSource.length >= 1 ? ( | ||||
<Popconfirm title="确认要将该属性删除吗?" onConfirm={() => deleteItem(value)}> | |||||
<Popconfirm title="确认要将该属性删除吗?" onConfirm={() => deleteItem(dataSource[index])}> | |||||
<a>删除</a> | <a>删除</a> | ||||
</Popconfirm> | </Popconfirm> | ||||
) : null, | ) : null, | ||||
@@ -260,7 +367,7 @@ export default forwardRef((props, ref) => { | |||||
useEffect(() => { | useEffect(() => { | ||||
load(); | load(); | ||||
}, []); | |||||
}, [searchState]); | |||||
const onReset = () => { | const onReset = () => { | ||||
searchFrom.resetFields() | searchFrom.resetFields() | ||||
@@ -271,7 +378,7 @@ export default forwardRef((props, ref) => { | |||||
<> | <> | ||||
<div> | <div> | ||||
<div className='flex flex-row-reverse mb-2'> | <div className='flex flex-row-reverse mb-2'> | ||||
<Button type='primary' size='large' icon={<PlusOutlined />} > 新增颜色 </Button> | |||||
<Button type='primary' size='large' icon={<PlusOutlined />} onClick={() => { setVisible(true) }}> 新增颜色 </Button> | |||||
</div> | </div> | ||||
<Table rowKey="id" | <Table rowKey="id" | ||||
scroll={{ x: true }} | scroll={{ x: true }} | ||||
@@ -279,6 +386,15 @@ export default forwardRef((props, ref) => { | |||||
dataSource={dataSource} | dataSource={dataSource} | ||||
components={components} | components={components} | ||||
rowClassName={() => 'editable-row'} | rowClassName={() => 'editable-row'} | ||||
onChange={async (pagination, filters) => { | |||||
const state: GoodsAttrPageReqVO = { | |||||
attrNameCn: filters.attrNameCn ? filters.attrNameCn[0] as string : undefined, | |||||
attrNameEn: filters.attrNameEn ? filters.attrNameEn[0] as string : undefined, | |||||
pageNo: pagination.current ?? 1, | |||||
pageSize: pagination.pageSize | |||||
} | |||||
setSearchState(state); | |||||
}} | |||||
pagination={{ | pagination={{ | ||||
position: ['bottomRight'], | position: ['bottomRight'], | ||||
current: searchState.pageNo, | current: searchState.pageNo, | ||||
@@ -286,6 +402,13 @@ export default forwardRef((props, ref) => { | |||||
total | total | ||||
}} /> | }} /> | ||||
</div> | </div> | ||||
<AttrEditor | |||||
visible={visible} | |||||
onCancel={() => { setVisible(false) }} | |||||
onSave={(data: GoodsAttrVO) => { | |||||
setVisible(false); | |||||
load(); | |||||
}} /> | |||||
</> | </> | ||||
); | ); | ||||
}); | }); | ||||
@@ -1,5 +1,5 @@ | |||||
import React, { useState, useEffect, useRef, useContext, forwardRef, useImperativeHandle } from 'react'; | import React, { useState, useEffect, useRef, useContext, forwardRef, useImperativeHandle } from 'react'; | ||||
import { Space, Table, Button, Input, Select, Divider, Form, Popconfirm } from 'antd'; | |||||
import { Space, Table, Button, Input, Modal, Radio, Form, Popconfirm, Badge } from 'antd'; | |||||
import type { TableColumnsType } from 'antd'; | import type { TableColumnsType } from 'antd'; | ||||
import type { InputRef } from 'antd'; | import type { InputRef } from 'antd'; | ||||
import type { FormInstance } from 'antd/es/form'; | import type { FormInstance } from 'antd/es/form'; | ||||
@@ -13,6 +13,101 @@ import goodsAttrService from '@/request/service/goods-attr'; | |||||
import { formatDate } from '@/utils/formatTime'; | import { formatDate } from '@/utils/formatTime'; | ||||
import { useSetState } from 'ahooks'; | import { useSetState } from 'ahooks'; | ||||
const AttrEditor = (props: { | |||||
visible: boolean; | |||||
onCancel: (flag?: boolean) => void; | |||||
onSave: (role: GoodsAttrVO) => void; | |||||
}) => { | |||||
const { visible, onCancel, onSave } = props; | |||||
const { runAsync: createApi } = useRequest(goodsAttrService.createGoodsAttrApi, { manual: true }); | |||||
const [saveLoading, setSaveLoading] = useState(false); | |||||
const [form] = Form.useForm(); | |||||
useEffect(() => { | |||||
if (visible) { | |||||
form.setFieldValue("attrStatus", 1); | |||||
} else { | |||||
form.resetFields(); | |||||
} | |||||
}, [visible]); | |||||
const save = async () => { | |||||
await form.validateFields(); | |||||
setSaveLoading(true); | |||||
const fieldValues = form.getFieldsValue(); | |||||
const [error, { msg, code }] = await createApi(fieldValues); | |||||
if (!error && code === 0) { | |||||
onSave(fieldValues); | |||||
} else { | |||||
antdUtils.message?.open({ | |||||
type: 'error', | |||||
content: msg ?? '操作失败', | |||||
}); | |||||
} | |||||
setSaveLoading(false); | |||||
} | |||||
return ( | |||||
<> | |||||
<Modal | |||||
open={visible} | |||||
title={"新建"} | |||||
width={640} | |||||
onOk={save} | |||||
onCancel={() => onCancel()} | |||||
confirmLoading={saveLoading} | |||||
destroyOnClose | |||||
> | |||||
<Form | |||||
form={form} | |||||
onFinish={save} | |||||
labelCol={{ flex: '0 0 120px' }} | |||||
wrapperCol={{ span: 16 }} | |||||
> | |||||
<Form.Item name="attrNameCn" label="属性名称(中文):" | |||||
rules={[ | |||||
{ | |||||
required: true, | |||||
message: '请输属性中文名称', | |||||
}, | |||||
]} | |||||
> | |||||
<Input /> | |||||
</Form.Item> | |||||
<Form.Item name="attrNameEn" label="属性名称(英文):" | |||||
rules={[ | |||||
{ | |||||
required: true, | |||||
message: '请输属性英文名称', | |||||
}, | |||||
]} | |||||
> | |||||
<Input /> | |||||
</Form.Item> | |||||
<Form.Item name="attrStatus" label="可用状态:" | |||||
rules={[ | |||||
{ | |||||
required: true, | |||||
message: '请输选择', | |||||
}, | |||||
]} | |||||
> | |||||
<Radio.Group options={[ | |||||
{ value: 1, label: "正常使用" }, | |||||
{ value: 2, label: "停止使用" } | |||||
]} optionType="default"> | |||||
</Radio.Group> | |||||
</Form.Item> | |||||
</Form> | |||||
</Modal> | |||||
</> | |||||
) | |||||
}; | |||||
const EditableContext = React.createContext<FormInstance<any> | null>(null); | const EditableContext = React.createContext<FormInstance<any> | null>(null); | ||||
interface EditableRowProps { | interface EditableRowProps { | ||||
@@ -106,7 +201,8 @@ type ColumnTypes = Exclude<EditableTableProps['columns'], undefined>; | |||||
export default forwardRef((props, ref) => { | export default forwardRef((props, ref) => { | ||||
useImperativeHandle(ref, () => { | useImperativeHandle(ref, () => { | ||||
addItem | addItem | ||||
}) | |||||
}); | |||||
const [visible, setVisible] = useState<boolean>(false); | |||||
const [dataSource, setDataSource] = useState<GoodsAttrVO[]>([]); | const [dataSource, setDataSource] = useState<GoodsAttrVO[]>([]); | ||||
const [searchFrom] = Form.useForm(); | const [searchFrom] = Form.useForm(); | ||||
@@ -124,9 +220,10 @@ export default forwardRef((props, ref) => { | |||||
const { runAsync: deleteApi } = useRequest(goodsAttrService.deleteGoodsAttrApi, { manual: true }); | const { runAsync: deleteApi } = useRequest(goodsAttrService.deleteGoodsAttrApi, { manual: true }); | ||||
const load = async () => { | const load = async () => { | ||||
const [error, { data }] = await getPageApi(searchFrom.getFieldsValue()); | |||||
const [error, { data }] = await getPageApi(searchState); | |||||
if (!error) { | if (!error) { | ||||
setDataSource(data.list); | setDataSource(data.list); | ||||
setTotal(data.total); | |||||
} | } | ||||
}; | }; | ||||
@@ -196,6 +293,16 @@ export default forwardRef((props, ref) => { | |||||
width: '30%', | width: '30%', | ||||
editable: true, | editable: true, | ||||
}, | }, | ||||
{ | |||||
title: '状态', | |||||
key: 'attrStatus', | |||||
dataIndex: 'attrStatus', | |||||
width: 100, | |||||
align: 'center', | |||||
render: (value: number) => { | |||||
return (value === 1 ? <Badge status="success" text="已开启" /> : <Badge status="error" text="已关闭" />) | |||||
} | |||||
}, | |||||
{ | { | ||||
title: '创建时间', | title: '创建时间', | ||||
dataIndex: 'createTime', | dataIndex: 'createTime', | ||||
@@ -209,9 +316,9 @@ export default forwardRef((props, ref) => { | |||||
title: t("QkOmYwne" /* 操作 */), | title: t("QkOmYwne" /* 操作 */), | ||||
dataIndex: 'operation', | dataIndex: 'operation', | ||||
key: 'action', | key: 'action', | ||||
render: (value: GoodsAttrVO) => | |||||
render: (_, record, index) => | |||||
dataSource.length >= 1 ? ( | dataSource.length >= 1 ? ( | ||||
<Popconfirm title="确认要将该属性删除吗?" onConfirm={() => deleteItem(value)}> | |||||
<Popconfirm title="确认要将该属性删除吗?" onConfirm={() => deleteItem(dataSource[index])}> | |||||
<a>删除</a> | <a>删除</a> | ||||
</Popconfirm> | </Popconfirm> | ||||
) : null, | ) : null, | ||||
@@ -260,7 +367,7 @@ export default forwardRef((props, ref) => { | |||||
useEffect(() => { | useEffect(() => { | ||||
load(); | load(); | ||||
}, []); | |||||
}, [searchState]); | |||||
const onReset = () => { | const onReset = () => { | ||||
searchFrom.resetFields() | searchFrom.resetFields() | ||||
@@ -271,7 +378,7 @@ export default forwardRef((props, ref) => { | |||||
<> | <> | ||||
<div> | <div> | ||||
<div className='flex flex-row-reverse mb-2'> | <div className='flex flex-row-reverse mb-2'> | ||||
<Button type='primary' size='large' icon={<PlusOutlined />} > 新增尺码 </Button> | |||||
<Button type='primary' size='large' icon={<PlusOutlined />} onClick={() => { setVisible(true) }}> 新增尺码 </Button> | |||||
</div> | </div> | ||||
<Table rowKey="id" | <Table rowKey="id" | ||||
scroll={{ x: true }} | scroll={{ x: true }} | ||||
@@ -279,6 +386,15 @@ export default forwardRef((props, ref) => { | |||||
dataSource={dataSource} | dataSource={dataSource} | ||||
components={components} | components={components} | ||||
rowClassName={() => 'editable-row'} | rowClassName={() => 'editable-row'} | ||||
onChange={async (pagination, filters) => { | |||||
const state: GoodsAttrPageReqVO = { | |||||
attrNameCn: filters.attrNameCn ? filters.attrNameCn[0] as string : undefined, | |||||
attrNameEn: filters.attrNameEn ? filters.attrNameEn[0] as string : undefined, | |||||
pageNo: pagination.current ?? 1, | |||||
pageSize: pagination.pageSize | |||||
} | |||||
setSearchState(state); | |||||
}} | |||||
pagination={{ | pagination={{ | ||||
position: ['bottomRight'], | position: ['bottomRight'], | ||||
current: searchState.pageNo, | current: searchState.pageNo, | ||||
@@ -286,6 +402,13 @@ export default forwardRef((props, ref) => { | |||||
total | total | ||||
}} /> | }} /> | ||||
</div> | </div> | ||||
<AttrEditor | |||||
visible={visible} | |||||
onCancel={() => { setVisible(false) }} | |||||
onSave={(data: GoodsAttrVO) => { | |||||
setVisible(false); | |||||
load(); | |||||
}} /> | |||||
</> | </> | ||||
); | ); | ||||
}); | }); | ||||