维护所有模块的多语言功能,对接友情分类接口和友情链接接口
This commit is contained in:
@ -1,323 +1,201 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useIntl } from 'umi';
|
||||
import { Card, Table, Button, Modal, Form, Input, Space, message, Select, TreeSelect } from 'antd';
|
||||
import { Card, Table, Button, Modal, Form, Input, Space, message, Select, TreeSelect, Popconfirm, Tag } from 'antd';
|
||||
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined, EditOutlined } from '@ant-design/icons';
|
||||
import { getCategoryList, getAllCategories, addCategory, updateCategory, deleteCategory } from '@/servers/api/friendLink';
|
||||
import { useFriendLinkDict } from '@/dicts/friendLinkDict';
|
||||
import './friendLinkManage.less';
|
||||
|
||||
const { Option } = Select;
|
||||
const { TextArea } = Input;
|
||||
|
||||
// 友情链接分类类型定义
|
||||
interface CategoryType {
|
||||
id: string;
|
||||
name: string;
|
||||
parentId: string | null;
|
||||
level: number;
|
||||
sort: number;
|
||||
children?: CategoryType[];
|
||||
key?: string;
|
||||
}
|
||||
// 友情链接分类类型定义已移至全局typings.d.ts
|
||||
|
||||
const FriendLinkCategory: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const { categoryTypeOptions, getCategoryTypeText } = useFriendLinkDict();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [modalVisible, setModalVisible] = useState<boolean>(false);
|
||||
const [isEdit, setIsEdit] = useState<boolean>(false);
|
||||
const [isAddChild, setIsAddChild] = useState<boolean>(false);
|
||||
const [currentCategory, setCurrentCategory] = useState<CategoryType | null>(null);
|
||||
const [categoryData, setCategoryData] = useState<CategoryType[]>([]);
|
||||
const [currentCategory, setCurrentCategory] = useState<API.CategoryType | null>(null);
|
||||
const [categoryData, setCategoryData] = useState<API.CategoryType[]>([]);
|
||||
const [pagination, setPagination] = useState({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
const [form] = Form.useForm();
|
||||
|
||||
// 模拟分类数据
|
||||
const mockCategories: CategoryType[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: '政府机构',
|
||||
parentId: null,
|
||||
level: 1,
|
||||
sort: 1,
|
||||
children: [
|
||||
{
|
||||
id: '1-1',
|
||||
name: '中央部委',
|
||||
parentId: '1',
|
||||
level: 2,
|
||||
sort: 1,
|
||||
},
|
||||
{
|
||||
id: '1-2',
|
||||
name: '地方政府',
|
||||
parentId: '1',
|
||||
level: 2,
|
||||
sort: 2,
|
||||
children: [
|
||||
{
|
||||
id: '1-2-1',
|
||||
name: '省级政府',
|
||||
parentId: '1-2',
|
||||
level: 3,
|
||||
sort: 1,
|
||||
},
|
||||
{
|
||||
id: '1-2-2',
|
||||
name: '市级政府',
|
||||
parentId: '1-2',
|
||||
level: 3,
|
||||
sort: 2,
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: '港口集团',
|
||||
parentId: null,
|
||||
level: 1,
|
||||
sort: 2,
|
||||
children: [
|
||||
{
|
||||
id: '2-1',
|
||||
name: '沿海港口',
|
||||
parentId: '2',
|
||||
level: 2,
|
||||
sort: 1,
|
||||
},
|
||||
{
|
||||
id: '2-2',
|
||||
name: '内河港口',
|
||||
parentId: '2',
|
||||
level: 2,
|
||||
sort: 2,
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: '航运企业',
|
||||
parentId: null,
|
||||
level: 1,
|
||||
sort: 3,
|
||||
}
|
||||
];
|
||||
|
||||
// 获取分类列表
|
||||
const fetchCategoryList = () => {
|
||||
const fetchCategoryList = async (pageNo = 1, pageSize = 10) => {
|
||||
setLoading(true);
|
||||
// 实际项目中应调用API
|
||||
setTimeout(() => {
|
||||
// 为每个节点添加key属性,用于Table组件
|
||||
const processData = (data: CategoryType[]): CategoryType[] => {
|
||||
return data.map(item => {
|
||||
const newItem = { ...item, key: item.id };
|
||||
if (item.children && item.children.length > 0) {
|
||||
newItem.children = processData(item.children);
|
||||
}
|
||||
return newItem;
|
||||
});
|
||||
};
|
||||
try {
|
||||
const res = await getCategoryList({
|
||||
basePageRequest: {
|
||||
pageNo,
|
||||
pageSize,
|
||||
},
|
||||
});
|
||||
|
||||
const processedData = processData(mockCategories);
|
||||
setCategoryData(processedData);
|
||||
if (res.data && res.success) {
|
||||
setCategoryData(res.data.records);
|
||||
setPagination({
|
||||
current: res.data.current,
|
||||
pageSize: res.data.size,
|
||||
total: res.data.total,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch category list', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}, 500);
|
||||
}
|
||||
};
|
||||
|
||||
// 首次加载时获取数据
|
||||
useEffect(() => {
|
||||
fetchCategoryList();
|
||||
}, []);
|
||||
|
||||
// 获取所有分类(扁平化)用于选择父分类
|
||||
const getAllCategories = (categories: CategoryType[] = categoryData, result: CategoryType[] = []): CategoryType[] => {
|
||||
categories.forEach(category => {
|
||||
result.push(category);
|
||||
if (category.children && category.children.length > 0) {
|
||||
getAllCategories(category.children, result);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
// 处理分页变化
|
||||
const handleTableChange = (paginationParams: any) => {
|
||||
fetchCategoryList(paginationParams.current, paginationParams.pageSize);
|
||||
};
|
||||
|
||||
// 处理添加分类
|
||||
const handleAddCategory = () => {
|
||||
setIsEdit(false);
|
||||
setIsAddChild(false);
|
||||
setCurrentCategory(null);
|
||||
form.resetFields();
|
||||
setModalVisible(true);
|
||||
};
|
||||
|
||||
// 处理添加子分类
|
||||
const handleAddChildCategory = (record: CategoryType) => {
|
||||
setIsEdit(false);
|
||||
setIsAddChild(true);
|
||||
setCurrentCategory(record);
|
||||
form.resetFields();
|
||||
form.setFieldsValue({
|
||||
parentId: record.id,
|
||||
parentId: '0', // 设置默认父级为顶级
|
||||
type: '0', // 设置默认类型为普通展示
|
||||
orderBy: '1', // 设置默认排序为1
|
||||
});
|
||||
setModalVisible(true);
|
||||
};
|
||||
|
||||
// 处理编辑分类
|
||||
const handleEditCategory = (record: CategoryType) => {
|
||||
const handleEditCategory = (record: API.CategoryType) => {
|
||||
setIsEdit(true);
|
||||
setIsAddChild(false);
|
||||
setCurrentCategory(record);
|
||||
form.setFieldsValue({
|
||||
name: record.name,
|
||||
type: record.type,
|
||||
parentId: record.parentId,
|
||||
sort: record.sort,
|
||||
orderBy: record.orderBy,
|
||||
remark: record.remark,
|
||||
});
|
||||
setModalVisible(true);
|
||||
};
|
||||
|
||||
// 处理删除分类
|
||||
const handleDeleteCategory = (record: CategoryType) => {
|
||||
// 检查是否有子分类
|
||||
if (record.children && record.children.length > 0) {
|
||||
message.error('该分类下有子分类,不能直接删除');
|
||||
return;
|
||||
const handleDeleteCategory = async (id: string) => {
|
||||
try {
|
||||
const res = await deleteCategory(id);
|
||||
if (res.success) {
|
||||
message.success(intl.formatMessage({ id: 'friendLink.category.delete.success' }));
|
||||
fetchCategoryList(pagination.current, pagination.pageSize);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to delete category', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 显示删除确认框
|
||||
const showDeleteConfirm = (record: API.CategoryType) => {
|
||||
Modal.confirm({
|
||||
title: '删除分类',
|
||||
title: intl.formatMessage({ id: 'friendLink.category.delete.confirm.title' }),
|
||||
icon: <ExclamationCircleOutlined />,
|
||||
content: `确定要删除分类"${record.name}"吗?`,
|
||||
okText: '确定',
|
||||
content: intl.formatMessage(
|
||||
{ id: 'friendLink.category.delete.confirm.content' },
|
||||
{ name: record.name }
|
||||
),
|
||||
okText: intl.formatMessage({ id: 'common.confirm' }),
|
||||
okType: 'danger',
|
||||
cancelText: '取消',
|
||||
cancelText: intl.formatMessage({ id: 'common.cancel' }),
|
||||
onOk() {
|
||||
// 实际项目中应调用API
|
||||
// 递归查找并删除分类
|
||||
const deleteCategory = (data: CategoryType[], id: string): CategoryType[] => {
|
||||
return data.filter(item => {
|
||||
if (item.id === id) {
|
||||
return false;
|
||||
}
|
||||
if (item.children && item.children.length > 0) {
|
||||
item.children = deleteCategory(item.children, id);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
const newData = deleteCategory(categoryData, record.id);
|
||||
setCategoryData(newData);
|
||||
message.success('删除成功');
|
||||
handleDeleteCategory(record.id);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 处理表单提交
|
||||
const handleModalSubmit = () => {
|
||||
form.validateFields().then(values => {
|
||||
// 准备提交数据
|
||||
const formData = {
|
||||
...values,
|
||||
level: values.parentId ? (isAddChild ? currentCategory!.level + 1 : 2) : 1,
|
||||
};
|
||||
|
||||
if (isEdit && currentCategory) {
|
||||
// 编辑模式
|
||||
// 递归更新分类
|
||||
const updateCategory = (data: CategoryType[], id: string, newData: any): CategoryType[] => {
|
||||
return data.map(item => {
|
||||
if (item.id === id) {
|
||||
return { ...item, ...newData };
|
||||
}
|
||||
if (item.children && item.children.length > 0) {
|
||||
item.children = updateCategory(item.children, id, newData);
|
||||
}
|
||||
return item;
|
||||
form.validateFields().then(async (values) => {
|
||||
try {
|
||||
if (isEdit && currentCategory) {
|
||||
// 编辑模式
|
||||
const res = await updateCategory({
|
||||
...values,
|
||||
id: currentCategory.id,
|
||||
});
|
||||
};
|
||||
|
||||
const newData = updateCategory(categoryData, currentCategory.id, formData);
|
||||
setCategoryData(newData);
|
||||
message.success('更新成功');
|
||||
} else {
|
||||
// 新增模式
|
||||
const newId = isAddChild
|
||||
? `${currentCategory!.id}-${Date.now().toString().substr(-4)}`
|
||||
: (categoryData.length + 1).toString();
|
||||
|
||||
const newCategory: CategoryType = {
|
||||
id: newId,
|
||||
name: formData.name,
|
||||
parentId: formData.parentId,
|
||||
level: formData.level,
|
||||
sort: formData.sort || 99,
|
||||
key: newId,
|
||||
};
|
||||
|
||||
if (formData.parentId) {
|
||||
// 有父分类,需要将新分类添加到父分类的children中
|
||||
const addChildToParent = (data: CategoryType[], parentId: string, newChild: CategoryType): CategoryType[] => {
|
||||
return data.map(item => {
|
||||
if (item.id === parentId) {
|
||||
if (!item.children) {
|
||||
item.children = [];
|
||||
}
|
||||
item.children.push(newChild);
|
||||
return item;
|
||||
}
|
||||
if (item.children && item.children.length > 0) {
|
||||
item.children = addChildToParent(item.children, parentId, newChild);
|
||||
}
|
||||
return item;
|
||||
});
|
||||
};
|
||||
|
||||
const newData = addChildToParent(categoryData, formData.parentId, newCategory);
|
||||
setCategoryData(newData);
|
||||
if (res.success) {
|
||||
message.success(intl.formatMessage({ id: 'friendLink.category.update.success' }));
|
||||
setModalVisible(false);
|
||||
fetchCategoryList(pagination.current, pagination.pageSize);
|
||||
}
|
||||
} else {
|
||||
// 无父分类,直接添加到顶级
|
||||
setCategoryData([...categoryData, newCategory]);
|
||||
// 新增模式
|
||||
const res = await addCategory(values);
|
||||
if (res.success) {
|
||||
message.success(intl.formatMessage({ id: 'friendLink.category.add.success' }));
|
||||
setModalVisible(false);
|
||||
fetchCategoryList(pagination.current, pagination.pageSize);
|
||||
}
|
||||
}
|
||||
|
||||
message.success('添加成功');
|
||||
} catch (error) {
|
||||
console.error('Submit failed', error);
|
||||
}
|
||||
|
||||
setModalVisible(false);
|
||||
form.resetFields();
|
||||
});
|
||||
};
|
||||
|
||||
// 渲染分类类型标签
|
||||
const renderCategoryType = (type: string) => {
|
||||
const color = type === '1' ? 'blue' : 'default';
|
||||
return (
|
||||
<Tag color={color}>
|
||||
{getCategoryTypeText(type)}
|
||||
</Tag>
|
||||
);
|
||||
};
|
||||
|
||||
// 表格列定义
|
||||
const columns = [
|
||||
{
|
||||
title: '分类名称',
|
||||
title: intl.formatMessage({ id: 'friendLink.category.name' }),
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '层级',
|
||||
dataIndex: 'level',
|
||||
key: 'level',
|
||||
title: intl.formatMessage({ id: 'friendLink.category.type' }),
|
||||
dataIndex: 'type',
|
||||
key: 'type',
|
||||
render: (type: string) => renderCategoryType(type),
|
||||
},
|
||||
{
|
||||
title: intl.formatMessage({ id: 'friendLink.category.sort' }),
|
||||
dataIndex: 'orderBy',
|
||||
key: 'orderBy',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'sort',
|
||||
key: 'sort',
|
||||
width: 100,
|
||||
sorter: (a: CategoryType, b: CategoryType) => a.sort - b.sort,
|
||||
title: intl.formatMessage({ id: 'friendLink.category.form.remark' }),
|
||||
dataIndex: 'remark',
|
||||
key: 'remark',
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
title: intl.formatMessage({ id: 'friendLink.category.operation' }),
|
||||
key: 'operation',
|
||||
width: 250,
|
||||
render: (_: any, record: CategoryType) => (
|
||||
width: 150,
|
||||
render: (_: any, record: API.CategoryType) => (
|
||||
<Space size="middle">
|
||||
<Button type="link" onClick={() => handleAddChildCategory(record)}>
|
||||
新增子类
|
||||
<Button type="link" onClick={() => handleEditCategory(record)}>
|
||||
{intl.formatMessage({ id: 'friendLink.category.edit' })}
|
||||
</Button>
|
||||
<Button type="link" onClick={() => handleEditCategory(record)}>
|
||||
编辑
|
||||
</Button>
|
||||
<Button type="link" onClick={() => handleDeleteCategory(record)}>
|
||||
删除
|
||||
<Button type="link" danger onClick={() => showDeleteConfirm(record)}>
|
||||
{intl.formatMessage({ id: 'friendLink.category.delete' })}
|
||||
</Button>
|
||||
</Space>
|
||||
),
|
||||
@ -328,7 +206,7 @@ const FriendLinkCategory: React.FC = () => {
|
||||
<div className="friend-link-category-container common-container">
|
||||
<div className="action-bar">
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={handleAddCategory}>
|
||||
新增分类
|
||||
{intl.formatMessage({ id: 'friendLink.category.add' })}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -338,16 +216,18 @@ const FriendLinkCategory: React.FC = () => {
|
||||
columns={columns}
|
||||
dataSource={categoryData}
|
||||
loading={loading}
|
||||
pagination={false}
|
||||
expandable={{
|
||||
defaultExpandAllRows: true
|
||||
}}
|
||||
pagination={pagination}
|
||||
onChange={handleTableChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 新增/编辑分类模态框 */}
|
||||
<Modal
|
||||
title={isEdit ? '编辑分类' : (isAddChild ? '新增子分类' : '新增分类')}
|
||||
title={
|
||||
isEdit
|
||||
? intl.formatMessage({ id: 'friendLink.category.form.title.edit' })
|
||||
: intl.formatMessage({ id: 'friendLink.category.form.title.add' })
|
||||
}
|
||||
visible={modalVisible}
|
||||
onOk={handleModalSubmit}
|
||||
onCancel={() => setModalVisible(false)}
|
||||
@ -359,46 +239,63 @@ const FriendLinkCategory: React.FC = () => {
|
||||
>
|
||||
<Form.Item
|
||||
name="name"
|
||||
label="分类名称"
|
||||
rules={[{ required: true, message: '请输入分类名称' }]}
|
||||
label={intl.formatMessage({ id: 'friendLink.category.form.name' })}
|
||||
rules={[{
|
||||
required: true,
|
||||
message: intl.formatMessage({ id: 'friendLink.category.form.name.required' })
|
||||
}]}
|
||||
>
|
||||
<Input placeholder="请输入分类名称" />
|
||||
<Input placeholder={intl.formatMessage({ id: 'friendLink.category.form.name.placeholder' })} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="parentId"
|
||||
label="父级分类"
|
||||
rules={[{ required: isAddChild, message: '请选择父级分类' }]}
|
||||
name="type"
|
||||
label={intl.formatMessage({ id: 'friendLink.category.form.type' })}
|
||||
rules={[{
|
||||
required: true,
|
||||
message: intl.formatMessage({ id: 'friendLink.category.form.type.required' })
|
||||
}]}
|
||||
>
|
||||
<TreeSelect
|
||||
placeholder="请选择父级分类"
|
||||
allowClear
|
||||
treeData={categoryData.map(item => ({
|
||||
title: item.name,
|
||||
value: item.id,
|
||||
disabled: isEdit && currentCategory ? (item.id === currentCategory.id || item.parentId === currentCategory.id) : false,
|
||||
children: item.children?.map(child => ({
|
||||
title: child.name,
|
||||
value: child.id,
|
||||
disabled: isEdit && currentCategory ? (child.id === currentCategory.id || child.parentId === currentCategory.id) : false,
|
||||
children: child.children?.map(grandChild => ({
|
||||
title: grandChild.name,
|
||||
value: grandChild.id,
|
||||
disabled: isEdit && currentCategory ? (grandChild.id === currentCategory.id || grandChild.parentId === currentCategory.id) : false,
|
||||
}))
|
||||
}))
|
||||
}))}
|
||||
disabled={isAddChild}
|
||||
<Select placeholder={intl.formatMessage({ id: 'friendLink.category.form.type.placeholder' })}>
|
||||
{categoryTypeOptions.map((option) => (
|
||||
<Option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
{/* 父级分类项,已完全隐藏 */}
|
||||
<Form.Item name="parentId" hidden initialValue="0">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="orderBy"
|
||||
label={intl.formatMessage({ id: 'friendLink.category.form.sort' })}
|
||||
rules={[{
|
||||
required: true,
|
||||
message: intl.formatMessage({ id: 'friendLink.category.form.sort.required' })
|
||||
}]}
|
||||
>
|
||||
<Input
|
||||
type="number"
|
||||
placeholder={intl.formatMessage({ id: 'friendLink.category.form.sort.placeholder' })}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="sort"
|
||||
label="排序"
|
||||
rules={[{ required: true, message: '请输入排序值' }]}
|
||||
initialValue={99}
|
||||
name="remark"
|
||||
label={intl.formatMessage({ id: 'friendLink.category.form.remark' })}
|
||||
rules={[{
|
||||
required: true,
|
||||
message: intl.formatMessage({ id: 'friendLink.category.form.remark.required' })
|
||||
}]}
|
||||
>
|
||||
<Input type="number" placeholder="请输入排序值,数字越小越靠前" />
|
||||
<TextArea
|
||||
rows={4}
|
||||
placeholder={intl.formatMessage({ id: 'friendLink.category.form.remark.placeholder' })}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
Reference in New Issue
Block a user