友情链接管理;封装上传接口

This commit is contained in:
linxd
2025-06-18 18:46:32 +08:00
parent 2a0532f775
commit 73db059e7d
24 changed files with 562 additions and 385 deletions

View File

@ -1,12 +1,7 @@
import React, { useState, useEffect } from 'react';
import { useIntl } from 'umi';
import { Table, Button, Modal, Form, Input, Space, message, Upload, Tag, TreeSelect } from 'antd';
import {
PlusOutlined,
DeleteOutlined,
ExclamationCircleOutlined,
UploadOutlined,
} from '@ant-design/icons';
import { Table, Button, Modal, Form, Input, Space, message, Tag, TreeSelect } from 'antd';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import type { UploadFile } from 'antd/es/upload/interface';
import {
getLinkList,
@ -16,8 +11,10 @@ import {
enableLink,
disableLink,
getAllCategories,
getLinkDetail,
} from '@/servers/api/friendLink';
import { useFriendLinkDict } from '@/dicts/friendLinkDict';
import { LinkStatusMap } from '@/dicts/friendLinkDict';
import FileUpload from '@/components/FileUpload';
import './friendLinkManage.less';
const FriendLinkManage: React.FC = () => {
@ -35,7 +32,6 @@ const FriendLinkManage: React.FC = () => {
total: 0,
});
const [form] = Form.useForm();
const [fileList, setFileList] = useState<UploadFile[]>([]);
const [categoryMap, setCategoryMap] = useState<Record<string, string>>({});
// 获取友情链接列表
@ -50,12 +46,7 @@ const FriendLinkManage: React.FC = () => {
});
if (res.data && res.success) {
// 处理分类名称
const links = res.data.records.map((item: API.LinkItem) => ({
...item,
categoryName: categoryMap[item.classificationId] || '',
}));
setLinkData(links);
setLinkData(res.data.records);
setPagination({
current: res.data.current,
pageSize: res.data.size,
@ -74,28 +65,7 @@ const FriendLinkManage: React.FC = () => {
try {
const res = await getAllCategories();
if (res.data && res.success) {
const flattenCategories = (
categories: API.CategoryType[],
result: API.CategoryType[] = [],
): API.CategoryType[] => {
categories.forEach((category) => {
result.push(category);
if (category.children && category.children.length > 0) {
flattenCategories(category.children, result);
}
});
return result;
};
const flatCategories = flattenCategories(res.data);
setCategoryData(res.data);
// 创建分类ID到名称的映射
const categoryNameMap: Record<string, string> = {};
flatCategories.forEach((category) => {
categoryNameMap[category.id] = category.name;
});
setCategoryMap(categoryNameMap);
}
} catch (error) {
console.error('Failed to fetch category list', error);
@ -119,7 +89,6 @@ const FriendLinkManage: React.FC = () => {
setIsEdit(false);
setCurrentId('');
form.resetFields();
setFileList([]);
form.setFieldsValue({
orderBy: 1,
});
@ -132,30 +101,34 @@ const FriendLinkManage: React.FC = () => {
setCurrentId(record.id);
setModalVisible(true);
// 设置表单初始值
form.setFieldsValue({
name: record.name,
nameEn: record.nameEn,
url: record.url,
orderBy: parseInt(record.orderBy),
classificationId: record.classificationId,
});
// 清空表单
form.resetFields();
// 设置上传文件列表
if (record.thumbnail) {
setFileList([
{
uid: '-1',
name: 'thumbnail.png',
status: 'done',
url: record.thumbnail,
type: 'image/png',
size: 0,
} as UploadFile,
]);
} else {
setFileList([]);
}
// 调用详情接口获取完整数据
getLinkDetail(record.id)
.then((res: API.Response<API.LinkType>) => {
if (res.success && res.data) {
const detail = res.data;
console.log('Detail data:', detail);
// 设置表单初始值包括缩略图URL
form.setFieldsValue({
name: detail.name,
nameEn: detail.nameEn,
url: detail.url,
orderBy: parseInt(detail.orderBy),
classificationId: detail.classificationId,
// 设置为URL字符串组件会自动处理
thumbnail: detail.thumbnail,
});
} else {
message.error(intl.formatMessage({ id: 'friendLink.detail.failed' }));
}
})
.catch((error: any) => {
console.error('Failed to get link detail', error);
message.error(intl.formatMessage({ id: 'friendLink.detail.failed' }));
});
};
// 处理删除
@ -220,22 +193,24 @@ const FriendLinkManage: React.FC = () => {
// 添加确认对话框
Modal.confirm({
title: intl.formatMessage({
id: record.status === '1'
? 'friendLink.disable.confirm.title'
: 'friendLink.enable.confirm.title'
id:
record.status === LinkStatusMap.ENABLED
? 'friendLink.disable.confirm.title'
: 'friendLink.enable.confirm.title',
}),
icon: <ExclamationCircleOutlined />,
content: intl.formatMessage({
id: record.status === '1'
? 'friendLink.disable.confirm.content'
: 'friendLink.enable.confirm.content'
id:
record.status === LinkStatusMap.ENABLED
? 'friendLink.disable.confirm.content'
: 'friendLink.enable.confirm.content',
}),
okText: intl.formatMessage({ id: 'common.confirm' }),
cancelText: intl.formatMessage({ id: 'common.cancel' }),
onOk: async () => {
try {
let res;
if (record.status === '1') {
if (record.status === LinkStatusMap.ENABLED) {
// 当前启用,需要禁用
res = await disableLink(record.id);
} else {
@ -245,7 +220,7 @@ const FriendLinkManage: React.FC = () => {
if (res.success) {
message.success(
record.status === '1'
record.status === LinkStatusMap.ENABLED
? intl.formatMessage({ id: 'friendLink.disable.success' })
: intl.formatMessage({ id: 'friendLink.enable.success' }),
);
@ -261,19 +236,15 @@ const FriendLinkManage: React.FC = () => {
// 处理表单提交
const handleModalSubmit = () => {
form.validateFields().then(async (values) => {
console.log('Form values:', values);
try {
// 确保thumbnail有值
if (fileList.length === 0) {
message.error(intl.formatMessage({ id: 'friendLink.form.thumbnail.required' }));
return;
}
// 准备提交数据
// 现在thumbnail字段已经直接是URL字符串不需要额外处理
const formData = {
...values,
thumbnail: fileList[0].url || fileList[0].thumbUrl || '',
};
console.log('Submitting form data:', formData);
let res;
if (isEdit) {
// 编辑模式
@ -301,11 +272,6 @@ const FriendLinkManage: React.FC = () => {
});
};
// 处理文件上传变化
const handleFileChange = (info: { fileList: UploadFile[] }) => {
setFileList(info.fileList);
};
// 表格列定义
const columns = [
{
@ -345,7 +311,7 @@ const FriendLinkManage: React.FC = () => {
dataIndex: 'status',
key: 'status',
render: (text: string) =>
text === '1' ? (
text === LinkStatusMap.ENABLED ? (
<Tag color="green">{intl.formatMessage({ id: 'friendLink.enabled' })}</Tag>
) : (
<Tag color="red">{intl.formatMessage({ id: 'friendLink.disabled' })}</Tag>
@ -361,7 +327,7 @@ const FriendLinkManage: React.FC = () => {
{intl.formatMessage({ id: 'friendLink.edit' })}
</Button>
<Button type="link" onClick={() => handleToggleStatus(record)}>
{record.status === '1'
{record.status === LinkStatusMap.ENABLED
? intl.formatMessage({ id: 'friendLink.disable' })
: intl.formatMessage({ id: 'friendLink.enable' })}
</Button>
@ -381,26 +347,28 @@ const FriendLinkManage: React.FC = () => {
return (
<div className="friend-link-manage-container common-container">
<div className="action-bar">
<div className="filter-action-row">
<Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>
{intl.formatMessage({ id: 'friendLink.add' })}
</Button>
<Button
danger
icon={<DeleteOutlined />}
onClick={handleBatchDelete}
disabled={selectedRowKeys.length === 0}
>
{intl.formatMessage({ id: 'friendLink.batchDelete' })}
</Button>
{selectedRowKeys.length > 0 && (
<span className="selected-count">
{intl.formatMessage(
{ id: 'friendLink.selectedCount' },
{ count: selectedRowKeys.length },
)}
</span>
)}
<div className="right-buttons">
<Button
danger
icon={<DeleteOutlined />}
onClick={handleBatchDelete}
disabled={selectedRowKeys.length === 0}
>
{intl.formatMessage({ id: 'friendLink.batchDelete' })}
</Button>
{selectedRowKeys.length > 0 && (
<span className="selected-count">
{intl.formatMessage(
{ id: 'friendLink.selectedCount' },
{ count: selectedRowKeys.length },
)}
</span>
)}
</div>
</div>
<div className="content-area">
@ -496,18 +464,30 @@ const FriendLinkManage: React.FC = () => {
<Input placeholder={intl.formatMessage({ id: 'friendLink.form.url.placeholder' })} />
</Form.Item>
<Form.Item name="thumbnail" label={intl.formatMessage({ id: 'friendLink.thumbnail' })}>
<Upload
listType="picture"
<Form.Item
name="thumbnail"
label={intl.formatMessage({ id: 'friendLink.thumbnail' })}
getValueFromEvent={(e) => {
return e[0].url;
}}
rules={[
{
required: true,
message: intl.formatMessage({ id: 'friendLink.form.thumbnail.required' }),
},
]}
>
<FileUpload
maxCount={1}
fileList={fileList}
onChange={handleFileChange}
beforeUpload={() => false}
>
<Button icon={<UploadOutlined />}>
{intl.formatMessage({ id: 'friendLink.form.thumbnail.upload' })}
</Button>
</Upload>
maxSize={2}
allowedTypes={['jpg', 'png']}
listType="picture"
tip={intl.formatMessage(
{ id: 'component.fileUpload.fileTypeTip' },
{ types: 'JPG, PNG' },
)}
buttonText={intl.formatMessage({ id: 'friendLink.form.thumbnail.upload' })}
/>
</Form.Item>
<Form.Item