forked from yoone/WEB
1
0
Fork 0
WEB/src/pages/Category/index.tsx

346 lines
10 KiB
TypeScript

import {
productcontrollerCreatecategory,
productcontrollerCreatecategoryattribute,
productcontrollerDeletecategory,
productcontrollerDeletecategoryattribute,
productcontrollerGetcategoriesall,
productcontrollerGetcategoryattributes,
productcontrollerUpdatecategory,
} from '@/servers/api/product';
import { PlusOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-components';
import { request } from '@umijs/max';
import {
Button,
Card,
Form,
Input,
Layout,
List,
Modal,
Popconfirm,
Select,
message,
} from 'antd';
import React, { useEffect, useState } from 'react';
import { attributes } from '../Attribute/consts';
const { Sider, Content } = Layout;
const CategoryPage: React.FC = () => {
const [categories, setCategories] = useState<any[]>([]);
const [loadingCategories, setLoadingCategories] = useState(false);
const [selectedCategory, setSelectedCategory] = useState<any>(null);
const [categoryAttributes, setCategoryAttributes] = useState<any[]>([]);
const [loadingAttributes, setLoadingAttributes] = useState(false);
const [isCategoryModalVisible, setIsCategoryModalVisible] = useState(false);
const [categoryForm] = Form.useForm();
const [editingCategory, setEditingCategory] = useState<any>(null);
const [isAttributeModalVisible, setIsAttributeModalVisible] = useState(false);
const [availableDicts, setAvailableDicts] = useState<any[]>([]);
const [selectedDictIds, setSelectedDictIds] = useState<number[]>([]);
const fetchCategories = async () => {
setLoadingCategories(true);
try {
const res = await productcontrollerGetcategoriesall();
setCategories(res || []);
} catch (error) {
message.error('获取分类列表失败');
}
setLoadingCategories(false);
};
useEffect(() => {
fetchCategories();
}, []);
const fetchCategoryAttributes = async (categoryId: number) => {
setLoadingAttributes(true);
try {
const res = await productcontrollerGetcategoryattributes({
categoryItemId: categoryId,
});
setCategoryAttributes(res || []);
} catch (error) {
message.error('获取分类属性失败');
}
setLoadingAttributes(false);
};
useEffect(() => {
if (selectedCategory) {
fetchCategoryAttributes(selectedCategory.id);
} else {
setCategoryAttributes([]);
}
}, [selectedCategory]);
const handleCategorySubmit = async (values: any) => {
try {
if (editingCategory) {
await productcontrollerUpdatecategory(
{ id: editingCategory.id },
values,
);
message.success('更新成功');
} else {
await productcontrollerCreatecategory(values);
message.success('创建成功');
}
setIsCategoryModalVisible(false);
fetchCategories();
} catch (error: any) {
message.error(error.message || '操作失败');
}
};
const handleDeleteCategory = async (id: number) => {
try {
await productcontrollerDeletecategory({ id });
message.success('删除成功');
if (selectedCategory?.id === id) {
setSelectedCategory(null);
}
fetchCategories();
} catch (error: any) {
message.error(error.message || '删除失败');
}
};
const handleAddAttribute = async () => {
// Fetch all dicts and filter those that are allowed attributes
try {
const res = await request('/dict/list');
const filtered = (res || []).filter((d: any) => attributes.has(d.name));
// Filter out already added attributes
const existingDictIds = new Set(
categoryAttributes.map((ca: any) => ca.dict.id),
);
const available = filtered.filter((d: any) => !existingDictIds.has(d.id));
setAvailableDicts(available);
setSelectedDictIds([]);
setIsAttributeModalVisible(true);
} catch (error) {
message.error('获取属性字典失败');
}
};
const handleAttributeSubmit = async () => {
if (selectedDictIds.length === 0) {
message.warning('请选择属性');
return;
}
try {
await productcontrollerCreatecategoryattribute({
categoryItemId: selectedCategory.id,
attributeDictIds: selectedDictIds,
});
message.success('添加属性成功');
setIsAttributeModalVisible(false);
fetchCategoryAttributes(selectedCategory.id);
} catch (error: any) {
message.error(error.message || '添加失败');
}
};
const handleDeleteAttribute = async (id: number) => {
try {
await productcontrollerDeletecategoryattribute({ id });
message.success('移除属性成功');
fetchCategoryAttributes(selectedCategory.id);
} catch (error: any) {
message.error(error.message || '移除失败');
}
};
return (
<PageContainer>
<Layout style={{ background: '#fff', height: 'calc(100vh - 200px)' }}>
<Sider
width={300}
style={{
background: '#fff',
borderRight: '1px solid #f0f0f0',
padding: '16px',
}}
>
<div
style={{
marginBottom: 16,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<span style={{ fontWeight: 'bold' }}></span>
<Button
type="primary"
size="small"
icon={<PlusOutlined />}
onClick={() => {
setEditingCategory(null);
categoryForm.resetFields();
setIsCategoryModalVisible(true);
}}
>
</Button>
</div>
<List
loading={loadingCategories}
dataSource={categories}
renderItem={(item) => (
<List.Item
className={
selectedCategory?.id === item.id ? 'ant-list-item-active' : ''
}
style={{
cursor: 'pointer',
background:
selectedCategory?.id === item.id
? '#e6f7ff'
: 'transparent',
padding: '8px 12px',
borderRadius: '4px',
}}
onClick={() => setSelectedCategory(item)}
actions={[
<a
key="edit"
onClick={(e) => {
e.stopPropagation();
setEditingCategory(item);
categoryForm.setFieldsValue(item);
setIsCategoryModalVisible(true);
}}
>
</a>,
<Popconfirm
key="delete"
title="确定删除该分类吗?"
onConfirm={(e) => {
e?.stopPropagation();
handleDeleteCategory(item.id);
}}
onCancel={(e) => e?.stopPropagation()}
>
<a
onClick={(e) => e.stopPropagation()}
style={{ color: 'red' }}
>
</a>
</Popconfirm>,
]}
>
<List.Item.Meta title={item.title} description={item.name} />
</List.Item>
)}
/>
</Sider>
<Content style={{ padding: '24px' }}>
{selectedCategory ? (
<Card
title={`分类:${selectedCategory.title} (${selectedCategory.name})`}
extra={
<Button type="primary" onClick={handleAddAttribute}>
</Button>
}
>
<List
loading={loadingAttributes}
dataSource={categoryAttributes}
renderItem={(item) => (
<List.Item
actions={[
<Popconfirm
title="确定移除该属性吗?"
onConfirm={() => handleDeleteAttribute(item.id)}
>
<Button type="link" danger>
</Button>
</Popconfirm>,
]}
>
<List.Item.Meta
title={item.dict.title}
description={`Code: ${item.dict.name}`}
/>
</List.Item>
)}
/>
</Card>
) : (
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100%',
color: '#999',
}}
>
</div>
)}
</Content>
</Layout>
<Modal
title={editingCategory ? '编辑分类' : '新增分类'}
open={isCategoryModalVisible}
onOk={() => categoryForm.submit()}
onCancel={() => setIsCategoryModalVisible(false)}
>
<Form
form={categoryForm}
onFinish={handleCategorySubmit}
layout="vertical"
>
<Form.Item name="title" label="标题" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item
name="name"
label="标识 (Code)"
rules={[{ required: true }]}
>
<Input />
</Form.Item>
</Form>
</Modal>
<Modal
title="添加关联属性"
open={isAttributeModalVisible}
onOk={handleAttributeSubmit}
onCancel={() => setIsAttributeModalVisible(false)}
>
<Form layout="vertical">
<Form.Item label="选择属性">
<Select
mode="multiple"
style={{ width: '100%' }}
placeholder="请选择要关联的属性"
value={selectedDictIds}
onChange={setSelectedDictIds}
options={availableDicts.map((d) => ({
label: d.title,
value: d.id,
}))}
/>
</Form.Item>
</Form>
</Modal>
</PageContainer>
);
};
export default CategoryPage;