diff --git a/config/proxy.ts b/config/proxy.ts index c68e6ac..dea0872 100644 --- a/config/proxy.ts +++ b/config/proxy.ts @@ -7,7 +7,7 @@ export default { // }, '/api': { // target: 'http://10.242.37.148:18022',//连接天宫的ng - target: 'http://10.0.0.14:18012',//连接天宫的ng + target: 'http://10.0.0.10:18013',//连接天宫的ng changeOrigin: true, pathRewrite: { '^/api': '' }, }, diff --git a/src/dicts/helpManageDict.ts b/src/dicts/helpManageDict.ts new file mode 100644 index 0000000..8622267 --- /dev/null +++ b/src/dicts/helpManageDict.ts @@ -0,0 +1,49 @@ +// 帮助中心字典 + +// 帮助状态枚举 +export enum HelpStatus { + DRAFT = '0', // 草稿 + PUBLISHED = '1', // 已发布 + UNPUBLISHED = '2', // 已下架 +} + +// 帮助状态文本映射 +export const HelpStatusText = { + [HelpStatus.DRAFT]: '草稿', + [HelpStatus.PUBLISHED]: '已发布', + [HelpStatus.UNPUBLISHED]: '已下架', +}; + +// 帮助状态标签颜色 +export const HelpStatusColor = { + [HelpStatus.DRAFT]: 'default', + [HelpStatus.PUBLISHED]: 'green', + [HelpStatus.UNPUBLISHED]: 'orange', +}; + +// 是否置顶枚举 +export enum TopStatus { + NO = '0', // 不置顶 + YES = '1', // 置顶 +} + +// 模态框类型 +export enum ModalType { + ADD = 'add', + EDIT = 'edit', + VIEW = 'view', +} + +// 英文内容设置 +export enum EnglishSetting { + NO = 0, // 不设置英文 + YES = 1, // 设置英文 +} + +// 帮助中心分类选项 +export const categoryOptions = [ + { value: '注册指南', label: '注册指南' }, + { value: '投标指南', label: '投标指南' }, + { value: '常见问题', label: '常见问题' }, + { value: '联系我们', label: '联系我们' }, +]; diff --git a/src/dicts/noticeManageDict.ts b/src/dicts/noticeManageDict.ts new file mode 100644 index 0000000..2c59afe --- /dev/null +++ b/src/dicts/noticeManageDict.ts @@ -0,0 +1,41 @@ +// 通知管理字典 + +// 通知状态枚举 +export enum NoticeStatus { + DRAFT = '0', // 草稿 + PUBLISHED = '1', // 已发布 + UNPUBLISHED = '2', // 已下架 +} + +// 通知状态文本映射 +export const NoticeStatusText = { + [NoticeStatus.DRAFT]: '草稿', + [NoticeStatus.PUBLISHED]: '已发布', + [NoticeStatus.UNPUBLISHED]: '已下架', +}; + +// 通知状态标签颜色 +export const NoticeStatusColor = { + [NoticeStatus.DRAFT]: 'default', + [NoticeStatus.PUBLISHED]: 'green', + [NoticeStatus.UNPUBLISHED]: 'orange', +}; + +// 是否置顶枚举 +export enum TopStatus { + NO = '0', // 不置顶 + YES = '1', // 置顶 +} + +// 模态框类型 +export enum ModalType { + ADD = 'add', + EDIT = 'edit', + VIEW = 'view', +} + +// 英文内容设置 +export enum EnglishSetting { + NO = 0, // 不设置英文 + YES = 1, // 设置英文 +} diff --git a/src/dicts/policyManageDict.ts b/src/dicts/policyManageDict.ts new file mode 100644 index 0000000..5d02272 --- /dev/null +++ b/src/dicts/policyManageDict.ts @@ -0,0 +1,41 @@ +// 政策法规字典 + +// 政策状态枚举 +export enum PolicyStatus { + DRAFT = '0', // 草稿 + PUBLISHED = '1', // 已发布 + UNPUBLISHED = '2', // 已下架 +} + +// 政策状态文本映射 +export const PolicyStatusText = { + [PolicyStatus.DRAFT]: '草稿', + [PolicyStatus.PUBLISHED]: '已发布', + [PolicyStatus.UNPUBLISHED]: '已下架', +}; + +// 政策状态标签颜色 +export const PolicyStatusColor = { + [PolicyStatus.DRAFT]: 'default', + [PolicyStatus.PUBLISHED]: 'green', + [PolicyStatus.UNPUBLISHED]: 'orange', +}; + +// 是否置顶枚举 +export enum TopStatus { + NO = '0', // 不置顶 + YES = '1', // 置顶 +} + +// 模态框类型 +export enum ModalType { + ADD = 'add', + EDIT = 'edit', + VIEW = 'view', +} + +// 英文内容设置 +export enum EnglishSetting { + NO = 0, // 不设置英文 + YES = 1, // 设置英文 +} diff --git a/src/dicts/userQuestionDict.ts b/src/dicts/userQuestionDict.ts new file mode 100644 index 0000000..92844db --- /dev/null +++ b/src/dicts/userQuestionDict.ts @@ -0,0 +1,74 @@ +// 用户问题管理字典 + +// 问题回答状态枚举 +export enum AnswerStatus { + UNREAD = '0', // 未阅 + READ = '1', // 已阅 + ANSWERED = '2', // 已回答 +} + +// 问题回答状态文本映射 +export const AnswerStatusText = { + [AnswerStatus.UNREAD]: '未阅', + [AnswerStatus.READ]: '已阅', + [AnswerStatus.ANSWERED]: '已回答', +}; + +// 问题回答状态标签颜色 +export const AnswerStatusColor = { + [AnswerStatus.UNREAD]: 'orange', + [AnswerStatus.READ]: 'blue', + [AnswerStatus.ANSWERED]: 'green', +}; + +// 是否发布枚举 +export enum PublishStatus { + NO = 0, // 未发布 + YES = 1, // 已发布 +} + +// 发布状态文本映射 +export const PublishStatusText = { + [PublishStatus.NO]: '未发布', + [PublishStatus.YES]: '已发布', +}; + +// 发布状态标签颜色 +export const PublishStatusColor = { + [PublishStatus.NO]: 'orange', + [PublishStatus.YES]: 'green', +}; + +// 是否置顶枚举 +export enum TopStatus { + NO = 0, // 不置顶 + YES = 1, // 置顶 +} + +// 置顶状态文本映射 +export const TopStatusText = { + [TopStatus.NO]: '未置顶', + [TopStatus.YES]: '已置顶', +}; + +// 置顶状态标签颜色 +export const TopStatusColor = { + [TopStatus.NO]: 'default', + [TopStatus.YES]: 'red', +}; + +// 模态框类型 +export enum ModalType { + VIEW = 'view', // 查看 + ANSWER = 'answer', // 回答 + EDIT = 'edit', // 编辑 +} + +// 问题分类选项 +export const QuestionCategoryOptions = [ + { value: '招标流程', label: '招标流程' }, + { value: '投标指南', label: '投标指南' }, + { value: '注册指南', label: '注册指南' }, + { value: '系统操作', label: '系统操作' }, + { value: '其他问题', label: '其他问题' }, +]; diff --git a/src/pages/aboutManage/aboutManage.less b/src/pages/aboutManage/aboutManage.less index ac5d200..56275a6 100644 --- a/src/pages/aboutManage/aboutManage.less +++ b/src/pages/aboutManage/aboutManage.less @@ -32,3 +32,4 @@ font-weight: 500; } } + \ No newline at end of file diff --git a/src/pages/friendLinkManage/friendLinkCategory.tsx b/src/pages/friendLinkManage/friendLinkCategory.tsx index 1eae7b8..7c44fe8 100644 --- a/src/pages/friendLinkManage/friendLinkCategory.tsx +++ b/src/pages/friendLinkManage/friendLinkCategory.tsx @@ -310,13 +310,13 @@ const FriendLinkCategory: React.FC = () => { width: 250, render: (_: any, record: CategoryType) => ( - - - diff --git a/src/pages/helpManage/HelpManageForm.tsx b/src/pages/helpManage/HelpManageForm.tsx new file mode 100644 index 0000000..885b340 --- /dev/null +++ b/src/pages/helpManage/HelpManageForm.tsx @@ -0,0 +1,218 @@ +import React, { useState, useEffect } from 'react'; +import { Form, Input, Switch, Tabs, message, Button, Select } from 'antd'; +import WangEditor from '@/components/WangEidtor/WangEidtor'; +import { TopStatus, EnglishSetting, categoryOptions } from '@/dicts/helpManageDict'; +import { addHelp, updateHelp, getHelpDetail } from '@/servers/api/help'; + +const { TabPane } = Tabs; +const { Option } = Select; + +interface HelpManageFormProps { + id?: string; + isEdit: boolean; + onSuccess: () => void; +} + +const HelpManageForm: React.FC = ({ id, isEdit, onSuccess }) => { + const [form] = Form.useForm(); + const [activeTabKey, setActiveTabKey] = useState('zh'); + const [loading, setLoading] = useState(false); + + // 获取详情数据 + useEffect(() => { + const fetchHelpDetail = async (helpId: string) => { + setLoading(true); + try { + const response = await getHelpDetail(helpId); + if (response && response.success) { + const detail = response.data; + form.setFieldsValue({ + isTop: detail.isTop === TopStatus.YES, + type: detail.type, + titleZh: detail.title, + titleEn: detail.titleEn, + contentZh: detail.content, + contentEn: detail.contentEn, + answerContentZh: detail.answerContent, + answerContentEn: detail.answerContentNe, + }); + } else { + message.error(response.message || '获取详情失败'); + } + } catch (error) { + console.error('获取帮助详情失败:', error); + message.error('获取详情失败'); + } finally { + setLoading(false); + } + }; + + if (isEdit && id) { + fetchHelpDetail(id); + } + }, [isEdit, id, form]); + + // 处理Tab切换 + const handleTabChange = (key: string) => { + setActiveTabKey(key); + }; + + // 提交表单 + const handleSubmit = async () => { + setLoading(true); + try { + // 一次性验证所有表单项 + try { + await form.validateFields(); + } catch (error: any) { + console.log(error); + // 如果有验证错误,自动切换到相应Tab + if (error.errorFields && error.errorFields.length > 0) { + // 获取第一个错误字段 + const firstError = error.errorFields[0]; + const fieldName = firstError.name[0]; + + // 根据字段名判断应该切换到哪个Tab + if (fieldName === 'titleZh' || fieldName === 'contentZh' || fieldName === 'answerContentZh') { + setActiveTabKey('zh'); + } else if (fieldName === 'titleEn' || fieldName === 'contentEn' || fieldName === 'answerContentEn') { + setActiveTabKey('en'); + } + } + + throw error; + } + + // 获取所有表单值 + const values = form.getFieldsValue(); + + // 转换表单数据为API需要的格式 + const requestData = { + title: values.titleZh, + titleEn: values.titleEn || '', + content: values.contentZh, + contentEn: values.contentEn || '', + type: values.type, + isTop: values.isTop ? TopStatus.YES : TopStatus.NO, + settingEn: values.titleEn && values.contentEn ? EnglishSetting.YES : EnglishSetting.NO, + answerContent: values.answerContentZh || '', + answerContentNe: values.answerContentEn || '', + }; + + let response; + if (isEdit && id) { + response = await updateHelp(id, requestData); + } else { + response = await addHelp(requestData); + } + + if (response && response.success) { + message.success(isEdit ? '更新成功' : '添加成功'); + onSuccess(); // 回调父组件 + } else { + message.error(response.message || (isEdit ? '更新失败' : '添加失败')); + } + } catch (error: any) { + console.error('表单验证或提交失败:', error); + // 错误已在前面处理 + } finally { + setLoading(false); + } + }; + + return ( +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+ ); +}; + +export default HelpManageForm; diff --git a/src/pages/helpManage/HelpManageInfo.tsx b/src/pages/helpManage/HelpManageInfo.tsx new file mode 100644 index 0000000..ed005c7 --- /dev/null +++ b/src/pages/helpManage/HelpManageInfo.tsx @@ -0,0 +1,80 @@ +import React from 'react'; +import { Descriptions, Divider, Card, Tag } from 'antd'; +import { HelpStatus, HelpStatusText, HelpStatusColor } from '@/dicts/helpManageDict'; + +interface HelpManageInfoProps { + data: API.HelpRecord | null; +} + +// 获取状态标签 +const getStatusTag = (status: string) => { + const statusKey = status as keyof typeof HelpStatusText; + const color = HelpStatusColor[statusKey] || 'default'; + const text = HelpStatusText[statusKey] || '未知'; + return {text}; +}; + +const HelpManageInfo: React.FC = ({ data }) => { + if (!data) return null; + + return ( +
+ + + {data.title} + + {data.titleEn && ( + + {data.titleEn} + + )} + + {data.type} + + {data.isTop === '1' ? '是' : '否'} + {getStatusTag(data.status)} + {data.createBy} + {data.createTime} + {data.updateTime && ( + + {data.updateTime} + + )} + + + 问题内容(中文) + +
+ + + {data.contentEn && ( + <> + 问题内容(英文) + +
+ + + )} + + {data.answerContent && ( + <> + 回答内容(中文) + +
+ + + )} + + {data.answerContentNe && ( + <> + 回答内容(英文) + +
+ + + )} +
+ ); +}; + +export default HelpManageInfo; diff --git a/src/pages/helpManage/helpManage.less b/src/pages/helpManage/helpManage.less index 40a8938..01fc169 100644 --- a/src/pages/helpManage/helpManage.less +++ b/src/pages/helpManage/helpManage.less @@ -61,3 +61,4 @@ } } } + \ No newline at end of file diff --git a/src/pages/helpManage/helpManage.tsx b/src/pages/helpManage/helpManage.tsx index 0d1a095..11135f9 100644 --- a/src/pages/helpManage/helpManage.tsx +++ b/src/pages/helpManage/helpManage.tsx @@ -1,20 +1,28 @@ import React, { useState, useEffect } from 'react'; import { useIntl } from 'umi'; -import { Button, Table, Modal, message, Input, Select, Form, Tooltip, Switch, Tag, Tabs } from 'antd'; +import { Button, Table, Modal, message, Input, Select, Form, Tooltip, Tag } from 'antd'; import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined, SearchOutlined, + EyeOutlined, } from '@ant-design/icons'; import './helpManage.less'; -// 引入封装的WangEditor组件 -import WangEditor from '@/components/WangEidtor/WangEidtor'; // 引入API -import { getHelpList, addHelp, updateHelp, deleteHelp, batchDeleteHelp, updateHelpStatus, updateHelpTopStatus } from '@/servers/api/help'; +import { getHelpList, deleteHelp, batchDeleteHelp, updateHelpStatus, updateHelpTopStatus, getHelpDetail } from '@/servers/api/help'; +// 引入字典和组件 +import { + HelpStatus, + HelpStatusText, + HelpStatusColor, + TopStatus, + categoryOptions +} from '@/dicts/helpManageDict'; +import HelpManageForm from './HelpManageForm'; +import HelpManageInfo from './HelpManageInfo'; const { Option } = Select; -const { TabPane } = Tabs; const { confirm } = Modal; // 帮助中心条目类型定义 @@ -22,6 +30,12 @@ interface HelpItemType extends API.HelpRecord { key: string; } +interface SearchParams { + title?: string; + type?: string; + status?: string; +} + const HelpManage: React.FC = () => { const intl = useIntl(); const [loading, setLoading] = useState(false); @@ -30,9 +44,9 @@ const HelpManage: React.FC = () => { const [form] = Form.useForm(); const [modalVisible, setModalVisible] = useState(false); const [isEdit, setIsEdit] = useState(false); + const [isViewMode, setIsViewMode] = useState(false); const [currentId, setCurrentId] = useState(''); - const [modalForm] = Form.useForm(); - const [activeTabKey, setActiveTabKey] = useState('zh'); + const [viewData, setViewData] = useState(null); const [pagination, setPagination] = useState({ current: 1, pageSize: 10, @@ -41,14 +55,19 @@ const HelpManage: React.FC = () => { showQuickJumper: true, showTotal: (total: number) => `共 ${total} 条记录`, }); - const [searchParams, setSearchParams] = useState({}); + const [searchParams, setSearchParams] = useState({}); // 获取帮助中心列表数据 - const fetchHelpList = (current: number = 1, pageSize: number = 10) => { + const fetchHelpList = (current: number = 1, pageSize: number = 10, params: SearchParams = searchParams) => { + // 更新搜索参数状态 + if (params !== searchParams) { + setSearchParams(params); + } + setLoading(true); // 调用API getHelpList({ - ...searchParams, + ...params, pageNo: current, pageSize, }) @@ -80,52 +99,61 @@ const HelpManage: React.FC = () => { // 首次加载时获取数据 useEffect(() => { - fetchHelpList(); + fetchHelpList(1, pagination.pageSize, {}); }, []); // 处理搜索 - const handleSearch = (values: any) => { - setSearchParams(values); - fetchHelpList(1, pagination.pageSize); + const handleSearch = (values: SearchParams) => { + fetchHelpList(1, pagination.pageSize, values); }; // 处理添加 const handleAdd = () => { setIsEdit(false); + setIsViewMode(false); setCurrentId(''); - modalForm.resetFields(); + setViewData(null); setModalVisible(true); - setActiveTabKey('zh'); + }; + + // 处理查看 + const handleView = async (record: HelpItemType) => { + setCurrentId(record.id); + setIsViewMode(true); + + try { + const response = await getHelpDetail(record.id); + if (response && response.success) { + // 设置查看详情数据 + setViewData(response.data); + setModalVisible(true); + } else { + message.error(response.message || '获取详情失败'); + } + } catch (error) { + console.error('获取帮助详情失败:', error); + message.error('获取详情失败'); + } }; // 处理编辑 const handleEdit = (record: HelpItemType) => { // 检查是否为已发布状态 - if (record.status === '1') { + if (record.status === HelpStatus.PUBLISHED) { message.warning('已发布的帮助不能编辑'); return; } setIsEdit(true); + setIsViewMode(false); setCurrentId(record.id); setModalVisible(true); - setActiveTabKey('zh'); - - // 填充表单数据 - modalForm.setFieldsValue({ - isTop: record.isTop === '1', - type: record.type, - titleZh: record.title, - titleEn: record.titleEn || '', - contentZh: record.content, - contentEn: record.contentEn || '', - }); }; // 处理删除 const showDeleteConfirm = (record: HelpItemType) => { // 检查是否为已发布状态 - if (record.status === '1') { + if (record.status === HelpStatus.PUBLISHED) { message.warning('已发布的帮助不能删除'); return; } @@ -141,11 +169,13 @@ const HelpManage: React.FC = () => { onOk: async () => { try { // 调用删除API - await deleteHelp(record.id); - // 更新本地数据 - const newData = helpData.filter(item => item.id !== record.id); - setHelpData(newData); - message.success('删除成功'); + const response = await deleteHelp(record.id); + if (response && response.success) { + message.success('删除成功'); + fetchHelpList(pagination.current, pagination.pageSize, searchParams); + } else { + message.error(response.message || '删除失败'); + } } catch (error) { console.error('删除帮助失败:', error); message.error('删除失败'); @@ -156,64 +186,77 @@ const HelpManage: React.FC = () => { // 处理发布/下架 const handlePublishStatus = async (record: HelpItemType) => { - // 状态: 0-草稿,1-已发布 - const isPublished = record.status === '1'; + const isPublished = record.status === HelpStatus.PUBLISHED; const actionText = isPublished ? '下架' : '发布'; - const newStatus = isPublished ? '0' : '1'; + const newStatus = isPublished ? HelpStatus.UNPUBLISHED : HelpStatus.PUBLISHED; - try { - // 调用API更新状态 - await updateHelpStatus(record.id, newStatus); - // 更新本地数据 - const newData = helpData.map(item => - item.id === record.id ? { ...item, status: newStatus } : item - ); - setHelpData(newData); - message.success(`${actionText}成功`); - } catch (error) { - console.error(`${actionText}失败:`, error); - message.error(`${actionText}失败`); - } + confirm({ + title: `确定要${actionText}该帮助吗?`, + icon: , + content: `标题: ${record.title}`, + okText: '确定', + cancelText: '取消', + maskClosable: false, + onOk: async () => { + try { + // 调用API更新状态 + const response = await updateHelpStatus(record.id, newStatus); + if (response && response.success) { + message.success(`${actionText}成功`); + fetchHelpList(pagination.current, pagination.pageSize, searchParams); + } else { + message.error(response.message || `${actionText}失败`); + } + } catch (error) { + console.error(`${actionText}失败:`, error); + message.error(`${actionText}失败`); + } + }, + }); }; // 处理置顶/取消置顶 const handleToggleTop = async (record: HelpItemType) => { - const isTop = record.isTop === '1'; + const isTop = record.isTop === TopStatus.YES; const actionText = isTop ? '取消置顶' : '置顶'; - const newIsTop = isTop ? '0' : '1'; + const newIsTop = isTop ? TopStatus.NO : TopStatus.YES; - try { - // 调用API更新置顶状态 - await updateHelpTopStatus(record.id, newIsTop); - // 更新本地数据 - const newData = helpData.map(item => - item.id === record.id ? { ...item, isTop: newIsTop } : item - ); - setHelpData(newData); - message.success(`${actionText}成功`); - } catch (error) { - console.error(`${actionText}失败:`, error); - message.error(`${actionText}失败`); - } + confirm({ + title: `确定要${actionText}该帮助吗?`, + icon: , + content: `标题: ${record.title}`, + okText: '确定', + cancelText: '取消', + maskClosable: false, + onOk: async () => { + try { + // 调用API更新置顶状态 + const response = await updateHelpTopStatus(record.id, newIsTop); + if (response && response.success) { + message.success(`${actionText}成功`); + fetchHelpList(pagination.current, pagination.pageSize, searchParams); + } else { + message.error(response.message || `${actionText}失败`); + } + } catch (error) { + console.error(`${actionText}失败:`, error); + message.error(`${actionText}失败`); + } + }, + }); }; // 获取状态标签 const getStatusTag = (status: string) => { - switch (status) { - case '0': - return 草稿; - case '1': - return 已发布; - case '2': - return 已下架; - default: - return 未知; - } + const statusKey = status as keyof typeof HelpStatusText; + const color = HelpStatusColor[statusKey] || 'default'; + const text = HelpStatusText[statusKey] || '未知'; + return {text}; }; // 处理表格分页变化 const handleTableChange = (newPagination: any) => { - fetchHelpList(newPagination.current, newPagination.pageSize); + fetchHelpList(newPagination.current, newPagination.pageSize, searchParams); }; // 处理批量删除 @@ -232,17 +275,19 @@ const HelpManage: React.FC = () => { // 获取可删除的ID(非已发布状态) const deleteIds = selectedRowKeys.filter(key => { const record = helpData.find(item => item.key === key); - return record && record.status !== '1'; + return record && record.status !== HelpStatus.PUBLISHED; }) as string[]; if (deleteIds.length > 0) { // 调用批量删除API - await batchDeleteHelp(deleteIds); - // 更新本地数据 - const newData = helpData.filter(item => !deleteIds.includes(item.key)); - setHelpData(newData); - setSelectedRowKeys([]); - message.success('删除成功'); + const response = await batchDeleteHelp(deleteIds); + if (response && response.success) { + setSelectedRowKeys([]); + message.success('删除成功'); + fetchHelpList(pagination.current, pagination.pageSize, searchParams); + } else { + message.error(response.message || '批量删除失败'); + } } else { message.warning('没有可删除的帮助'); } @@ -265,97 +310,26 @@ const HelpManage: React.FC = () => { selectedRowKeys, onChange: onSelectChange, getCheckboxProps: (record: HelpItemType) => ({ - disabled: record.status === '1', // 已发布的不能选择 + disabled: record.status === HelpStatus.PUBLISHED, // 已发布的不能选择 }), }; const hasSelected = selectedRowKeys.length > 0; - // 处理模态框提交 - const handleModalSubmit = () => { - // 先触发所有字段的验证 - modalForm.validateFields() - .then(async values => { - try { - const helpParams: API.HelpRequest = { - title: values.titleZh, - titleEn: values.titleEn || '', - content: values.contentZh, - contentEn: values.contentEn || '', - type: values.type, - isTop: values.isTop ? '1' : '0', - settingEn: values.titleEn && values.contentEn ? 1 : 0, - }; - - if (isEdit) { - // 编辑模式,调用更新API - await updateHelp(currentId, helpParams); - message.success('更新成功'); - } else { - // 新增模式,调用添加API - await addHelp(helpParams); - message.success('添加成功'); - } - - setModalVisible(false); - modalForm.resetFields(); - // 刷新列表 - fetchHelpList(pagination.current, pagination.pageSize); - } catch (error) { - console.error(isEdit ? '更新帮助失败:' : '添加帮助失败:', error); - message.error(isEdit ? '更新失败' : '添加失败'); - } - }) - .catch(errorInfo => { - // 获取所有字段的错误信息 - const errorFields = errorInfo.errorFields || []; - - // 检查是否有中文标题或内容的错误 - const hasZhError = errorFields.some((field: any) => { - if (!field.name) return false; - const fieldName = Array.isArray(field.name) ? field.name.join('.') : String(field.name); - return fieldName.includes('titleZh') || fieldName.includes('contentZh'); - }); - - // 检查是否有英文标题或内容的错误 - const hasEnError = errorFields.some((field: any) => { - if (!field.name) return false; - const fieldName = Array.isArray(field.name) ? field.name.join('.') : String(field.name); - return fieldName.includes('titleEn') || fieldName.includes('contentEn'); - }); - - // 如果有中文字段错误,切换到中文Tab - if (hasZhError) { - setActiveTabKey('zh'); - } - // 如果只有英文字段错误,切换到英文Tab - else if (hasEnError && !hasZhError) { - setActiveTabKey('en'); - } - - console.log('表单验证失败:', errorInfo); - }); - }; - - // 处理Tab切换 - const handleTabChange = (key: string) => { - setActiveTabKey(key); - }; - // 处理模态框取消 const handleModalCancel = () => { setModalVisible(false); - modalForm.resetFields(); + setIsViewMode(false); + setViewData(null); }; // 表格列定义 const columns = [ { title: '序号', - dataIndex: 'id', - key: 'id', - align: 'center' as const, + render: (_: any, record: HelpItemType, index: number) => index + 1, width: 80, + align: 'center' as const, }, { title: '标题', @@ -367,7 +341,7 @@ const HelpManage: React.FC = () => { render: (title: string, record: HelpItemType) => ( - {record.isTop === '1' && 置顶} + {record.isTop === TopStatus.YES && 置顶} {title} @@ -407,7 +381,10 @@ const HelpManage: React.FC = () => { align: 'center' as const, render: (_: unknown, record: HelpItemType) => ( <> - {record.status === '1' ? ( + + {record.status === HelpStatus.PUBLISHED ? ( <> ) : ( @@ -432,7 +409,6 @@ const HelpManage: React.FC = () => { )} @@ -450,14 +426,6 @@ const HelpManage: React.FC = () => { }, ]; - // 分类选项 - const categoryOptions = [ - { value: '注册指南', label: '注册指南' }, - { value: '投标指南', label: '投标指南' }, - { value: '常见问题', label: '常见问题' }, - { value: '联系我们', label: '联系我们' }, - ]; - return (
@@ -482,9 +450,9 @@ const HelpManage: React.FC = () => { @@ -497,8 +465,7 @@ const HelpManage: React.FC = () => { icon={} onClick={() => { form.resetFields(); - setSearchParams({}); - handleSearch({}); + fetchHelpList(1, pagination.pageSize, {}); }} > 重置 @@ -544,85 +511,38 @@ const HelpManage: React.FC = () => { />
- {/* 新增/编辑模态框 */} + {/* 新增/编辑/查看模态框 */} + 关闭 + , + ] + : null + } > -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ {isViewMode && viewData ? ( + // 查看详情模式 + + ) : ( + // 编辑/新增模式 + { + setModalVisible(false); + fetchHelpList(pagination.current, pagination.pageSize, searchParams); + }} + /> + )}
); diff --git a/src/pages/noticeManage/NoticeManageForm.tsx b/src/pages/noticeManage/NoticeManageForm.tsx new file mode 100644 index 0000000..061bab9 --- /dev/null +++ b/src/pages/noticeManage/NoticeManageForm.tsx @@ -0,0 +1,179 @@ +import React, { useState, useEffect } from 'react'; +import { Form, Input, Switch, Tabs, message, Button } from 'antd'; +import WangEditor from '@/components/WangEidtor/WangEidtor'; +import { TopStatus, EnglishSetting } from '@/dicts/noticeManageDict'; +import { addNotice, updateNotice, getNoticeDetail } from '@/servers/api/notice'; + +const { TabPane } = Tabs; + +interface NoticeManageFormProps { + id?: string; + isEdit: boolean; + onSuccess: () => void; +} + +const NoticeManageForm: React.FC = ({ id, isEdit, onSuccess }) => { + const [form] = Form.useForm(); + const [activeTabKey, setActiveTabKey] = useState('zh'); + const [loading, setLoading] = useState(false); + + // 获取详情数据 + useEffect(() => { + const fetchNoticeDetail = async (noticeId: string) => { + setLoading(true); + try { + const response = await getNoticeDetail(noticeId); + if (response && response.success) { + const detail = response.data; + form.setFieldsValue({ + isTop: detail.isTop === TopStatus.YES, + titleZh: detail.title, + titleEn: detail.titleEn, + contentZh: detail.content, + contentEn: detail.contentEn, + }); + } else { + message.error(response.message || '获取详情失败'); + } + } catch (error) { + console.error('获取通知详情失败:', error); + message.error('获取详情失败'); + } finally { + setLoading(false); + } + }; + + if (isEdit && id) { + fetchNoticeDetail(id); + } + }, [isEdit, id, form]); + + // 处理Tab切换 + const handleTabChange = (key: string) => { + setActiveTabKey(key); + }; + + // 提交表单 + const handleSubmit = async () => { + setLoading(true); + try { + // 一次性验证所有表单项 + try { + await form.validateFields(); + } catch (error: any) { + console.log(error); + // 如果有验证错误,自动切换到相应Tab + if (error.errorFields && error.errorFields.length > 0) { + // 获取第一个错误字段 + const firstError = error.errorFields[0]; + const fieldName = firstError.name[0]; + + // 根据字段名判断应该切换到哪个Tab + if (fieldName === 'titleZh' || fieldName === 'contentZh') { + setActiveTabKey('zh'); + } else if (fieldName === 'titleEn' || fieldName === 'contentEn') { + setActiveTabKey('en'); + } + } + + throw error; + } + + // 获取所有表单值 + const values = form.getFieldsValue(); + + // 转换表单数据为API需要的格式 + const requestData = { + title: values.titleZh, + titleEn: values.titleEn || '', + content: values.contentZh, + contentEn: values.contentEn || '', + isTop: values.isTop ? TopStatus.YES : TopStatus.NO, + settingEn: values.titleEn && values.contentEn ? EnglishSetting.YES : EnglishSetting.NO, + }; + + let response; + if (isEdit && id) { + response = await updateNotice(id, requestData); + } else { + response = await addNotice(requestData); + } + + if (response && response.success) { + message.success(isEdit ? '更新成功' : '添加成功'); + onSuccess(); // 回调父组件 + } else { + message.error(response.message || (isEdit ? '更新失败' : '添加失败')); + } + } catch (error: any) { + console.error('表单验证或提交失败:', error); + // 错误已在前面处理 + } finally { + setLoading(false); + } + }; + + return ( +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+ ); +}; + +export default NoticeManageForm; diff --git a/src/pages/noticeManage/NoticeManageInfo.tsx b/src/pages/noticeManage/NoticeManageInfo.tsx new file mode 100644 index 0000000..edd25bd --- /dev/null +++ b/src/pages/noticeManage/NoticeManageInfo.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { Descriptions, Divider, Card, Tag } from 'antd'; +import { NoticeStatus, NoticeStatusText, NoticeStatusColor } from '@/dicts/noticeManageDict'; + +interface NoticeManageInfoProps { + data: API.NoticeRecord | null; +} + +// 获取状态标签 +const getStatusTag = (status: string) => { + const statusKey = status as keyof typeof NoticeStatusText; + const color = NoticeStatusColor[statusKey] || 'default'; + const text = NoticeStatusText[statusKey] || '未知'; + return {text}; +}; + +const NoticeManageInfo: React.FC = ({ data }) => { + if (!data) return null; + + return ( +
+ + + {data.title} + + {data.titleEn && ( + + {data.titleEn} + + )} + {data.isTop === '1' ? '是' : '否'} + {getStatusTag(data.status)} + {data.createBy} + {data.createTime} + + + 中文内容 + +
+ + + {data.contentEn && ( + <> + 英文内容 + +
+ + + )} +
+ ); +}; + +export default NoticeManageInfo; diff --git a/src/pages/noticeManage/noticeManage.tsx b/src/pages/noticeManage/noticeManage.tsx index bf76580..7a59239 100644 --- a/src/pages/noticeManage/noticeManage.tsx +++ b/src/pages/noticeManage/noticeManage.tsx @@ -1,26 +1,38 @@ import React, { useState, useEffect } from 'react'; import { useIntl } from 'umi'; -import { Button, Table, Modal, message, Input, Select, Form, Tooltip, Switch, Tag, Tabs } from 'antd'; +import { Button, Table, Modal, message, Input, Select, Form, Tooltip, Tag, Tabs } from 'antd'; import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined, SearchOutlined, - VerticalAlignTopOutlined, + EyeOutlined, } from '@ant-design/icons'; -import { getNoticeList, addNotice, updateNotice, deleteNotice, batchDeleteNotice, updateNoticeStatus, updateNoticeTopStatus } from '@/servers/api/notice'; +import { getNoticeList, addNotice, updateNotice, deleteNotice, batchDeleteNotice, updateNoticeStatus, updateNoticeTopStatus, getNoticeDetail } from '@/servers/api/notice'; import './noticeManage.less'; -// 引入封装的WangEditor组件 -import WangEditor from '@/components/WangEidtor/WangEidtor'; +import { + NoticeStatus, + NoticeStatusText, + NoticeStatusColor, + TopStatus, + ModalType, +} from '@/dicts/noticeManageDict'; + +import NoticeManageForm from './NoticeManageForm'; +import NoticeManageInfo from './NoticeManageInfo'; const { Option } = Select; -const { TextArea } = Input; const { TabPane } = Tabs; type NoticeType = API.NoticeRecord & { key: string; }; +interface SearchParams { + title?: string; + status?: string; +} + const NoticeManage: React.FC = () => { const intl = useIntl(); const [selectedRowKeys, setSelectedRowKeys] = useState([]); @@ -28,121 +40,56 @@ const NoticeManage: React.FC = () => { const [form] = Form.useForm(); const [modalVisible, setModalVisible] = useState(false); const [isEdit, setIsEdit] = useState(false); + const [isViewMode, setIsViewMode] = useState(false); const [currentId, setCurrentId] = useState(''); - const [modalForm] = Form.useForm(); - // 富文本内容状态 - const [htmlZh, setHtmlZh] = useState(''); - const [htmlEn, setHtmlEn] = useState(''); - - const [noticeData, setNoticeData] = useState([ - { - key: '1', - id: '1', - title: '系统维护通知', - titleEn: 'System Maintenance Notice', - content: '系统将于2023年7月1日进行例行维护,请提前做好准备。', - contentEn: 'The system will undergo routine maintenance on July 1, 2023. Please prepare in advance.', - createTime: '2023-06-25 10:30:00', - createBy: 'admin', - status: '1', // 已发布 - isTop: '1', // 已置顶 - settingEn: 1, // 设置英文 - }, - { - key: '2', - id: '2', - title: '新功能上线通知', - titleEn: 'New Feature Launch', - content: '系统新增了XXXX功能,欢迎使用。', - contentEn: 'The system has added XXXX function, welcome to use.', - createTime: '2023-06-20 14:45:00', - createBy: 'admin', - status: '0', // 草稿 - isTop: '0', // 未置顶 - settingEn: 1, - }, - { - key: '3', - id: '3', - title: '用户反馈调查', - titleEn: '', - content: '为了提升用户体验,我们正在收集用户反馈...', - contentEn: '', - createTime: '2023-06-18 09:15:00', - createBy: 'admin', - status: '1', // 已发布 - isTop: '0', // 未置顶 - settingEn: 0, - }, - ]); + // 查看详情数据 + const [viewData, setViewData] = useState(null); + const [noticeData, setNoticeData] = useState([]); const [pagination, setPagination] = useState({ current: 1, pageSize: 10, - total: 3, + total: 0, showSizeChanger: true, showQuickJumper: true, showTotal: (total: number) => `共 ${total} 条记录`, }); - const [searchParams, setSearchParams] = useState({}); - const [activeTabKey, setActiveTabKey] = useState('zh'); + const [searchParams, setSearchParams] = useState({}); + + // 获取通知列表 + const fetchNoticeList = (current: number = 1, pageSize: number = 10, params: SearchParams = searchParams) => { + // 更新搜索参数状态 + if (params !== searchParams) { + setSearchParams(params); + } - // 获取通知列表(模拟数据) - const fetchNoticeList = (current: number = 1, pageSize: number = 10) => { setLoading(true); // 实际项目中应调用API getNoticeList({ - ...searchParams, + ...params, + pageNo: current, + pageSize: pageSize, }) .then(res => { - // 此处为模拟数据,实际项目中应使用API返回的数据 - setNoticeData([ - { - key: '1', - id: '1', - title: '系统维护通知', - titleEn: 'System Maintenance Notice', - content: '系统将于2023年7月1日进行例行维护,请提前做好准备。', - contentEn: 'The system will undergo routine maintenance on July 1, 2023. Please prepare in advance.', - createTime: '2023-06-25 10:30:00', - createBy: 'admin', - status: '1', // 已发布 - isTop: '1', // 已置顶 - settingEn: 1, - }, - { - key: '2', - id: '2', - title: '新功能上线通知', - titleEn: 'New Feature Launch', - content: '系统新增了XXXX功能,欢迎使用。', - contentEn: 'The system has added XXXX function, welcome to use.', - createTime: '2023-06-20 14:45:00', - createBy: 'admin', - status: '0', // 草稿 - isTop: '0', // 未置顶 - settingEn: 1, - }, - { - key: '3', - id: '3', - title: '用户反馈调查', - titleEn: '', - content: '为了提升用户体验,我们正在收集用户反馈...', - contentEn: '', - createTime: '2023-06-18 09:15:00', - createBy: 'admin', - status: '1', // 已发布 - isTop: '0', // 未置顶 - settingEn: 0, - }, - ]); - setPagination({ - ...pagination, - current, - pageSize, - total: 3, // 应该是res.total - }); + if (res && res.success) { + const { records, total, current: currentPage, size } = res.data; + + // 添加key属性 + setNoticeData( + records.map((item: API.NoticeRecord) => ({ + ...item, + key: item.id, + })) + ); + setPagination({ + ...pagination, + current: currentPage, + pageSize: size, + total: total, + }); + } else { + message.error(res.message || '获取通知列表失败'); + } }) .catch(error => { console.error('获取通知列表失败:', error); @@ -155,36 +102,47 @@ const NoticeManage: React.FC = () => { // 首次加载时获取数据 useEffect(() => { - fetchNoticeList(); + fetchNoticeList(1, pagination.pageSize, {}); }, []); + // 处理查看 + const handleView = async (record: NoticeType) => { + setCurrentId(record.id); + setIsViewMode(true); + + try { + const response = await getNoticeDetail(record.id); + if (response && response.success) { + // 设置查看详情数据 + setViewData(response.data); + setModalVisible(true); + } else { + message.error(response.message || '获取详情失败'); + } + } catch (error) { + console.error('获取通知详情失败:', error); + message.error('获取详情失败'); + } + }; + // 处理编辑 const handleEdit = (record: NoticeType) => { // 检查是否为已发布状态 - if (record.status === '1') { + if (record.status === NoticeStatus.PUBLISHED) { message.warning('已发布的通知不能编辑'); return; } setIsEdit(true); + setIsViewMode(false); setCurrentId(record.id); setModalVisible(true); - setActiveTabKey('zh'); - - // 填充表单数据 - modalForm.setFieldsValue({ - isTop: record.isTop === '1', - titleZh: record.title, - titleEn: record.titleEn, - contentZh: record.content, - contentEn: record.contentEn || '', - }); }; // 处理删除 const showDeleteConfirm = (record: NoticeType) => { // 检查是否为已发布状态 - if (record.status === '1') { + if (record.status === NoticeStatus.PUBLISHED) { message.warning('已发布的通知不能删除'); return; } @@ -200,11 +158,13 @@ const NoticeManage: React.FC = () => { onOk: async () => { try { // 调用删除API - await deleteNotice(record.id); - // 更新本地数据 - const newData = noticeData.filter(item => item.id !== record.id); - setNoticeData(newData); - message.success('删除成功'); + const response = await deleteNotice(record.id); + if (response && response.success) { + message.success('删除成功'); + fetchNoticeList(pagination.current, pagination.pageSize, searchParams); // 重新加载数据 + } else { + message.error(response.message || '删除失败'); + } } catch (error) { console.error('删除通知失败:', error); message.error('删除失败'); @@ -216,19 +176,19 @@ const NoticeManage: React.FC = () => { // 处理发布/下架 const handlePublishStatus = async (record: NoticeType) => { // 状态: 0-草稿,1-已发布 - const isPublished = record.status === '1'; + const isPublished = record.status === NoticeStatus.PUBLISHED; const actionText = isPublished ? '下架' : '发布'; - const newStatus = isPublished ? '0' : '1'; + const newStatus = isPublished ? NoticeStatus.UNPUBLISHED : NoticeStatus.PUBLISHED; try { // 调用API更新状态 - await updateNoticeStatus(record.id, newStatus); - // 更新本地数据 - const newData = noticeData.map(item => - item.id === record.id ? { ...item, status: newStatus } : item - ); - setNoticeData(newData); - message.success(`${actionText}成功`); + const response = await updateNoticeStatus(record.id, newStatus); + if (response && response.success) { + message.success(`${actionText}成功`); + fetchNoticeList(pagination.current, pagination.pageSize, searchParams); // 重新加载数据 + } else { + message.error(response.message || `${actionText}失败`); + } } catch (error) { console.error(`${actionText}失败:`, error); message.error(`${actionText}失败`); @@ -237,19 +197,19 @@ const NoticeManage: React.FC = () => { // 处理置顶/取消置顶 const handleToggleTop = async (record: NoticeType) => { - const isTop = record.isTop === '1'; + const isTop = record.isTop === TopStatus.YES; const actionText = isTop ? '取消置顶' : '置顶'; - const newIsTop = isTop ? '0' : '1'; + const newIsTop = isTop ? TopStatus.NO : TopStatus.YES; try { // 调用API更新置顶状态 - await updateNoticeTopStatus(record.id, newIsTop); - // 更新本地数据 - const newData = noticeData.map(item => - item.id === record.id ? { ...item, isTop: newIsTop } : item - ); - setNoticeData(newData); - message.success(`${actionText}成功`); + const response = await updateNoticeTopStatus(record.id, newIsTop); + if (response && response.success) { + message.success(`${actionText}成功`); + fetchNoticeList(pagination.current, pagination.pageSize, searchParams); // 重新加载数据 + } else { + message.error(response.message || `${actionText}失败`); + } } catch (error) { console.error(`${actionText}失败:`, error); message.error(`${actionText}失败`); @@ -258,30 +218,23 @@ const NoticeManage: React.FC = () => { // 获取状态标签 const getStatusTag = (status: string) => { - switch (status) { - case '0': - return 草稿; - case '1': - return 已发布; - case '2': - return 已下架; - default: - return 未知; - } + const statusKey = status as keyof typeof NoticeStatusText; + const color = NoticeStatusColor[statusKey] || 'default'; + const text = NoticeStatusText[statusKey] || '未知'; + return {text}; }; // 处理表格分页变化 const handleTableChange = (newPagination: any) => { - fetchNoticeList(newPagination.current, newPagination.pageSize); + fetchNoticeList(newPagination.current, newPagination.pageSize, searchParams); }; const columns = [ { title: '序号', - dataIndex: 'id', - key: 'id', - align: 'center' as const, + render: (text: string, record: NoticeType, index: number) => index + 1, width: 80, + align: 'center' as const, }, { title: '标题', @@ -293,7 +246,7 @@ const NoticeManage: React.FC = () => { render: (title: string, record: NoticeType) => ( - {record.isTop === '1' && 置顶} + {record.isTop === TopStatus.YES && 置顶} {title} @@ -325,7 +278,10 @@ const NoticeManage: React.FC = () => { align: 'center' as const, render: (_: unknown, record: NoticeType) => ( <> - {record.status === '1' ? ( + + {record.status === NoticeStatus.PUBLISHED ? ( <> ) : ( @@ -358,7 +314,7 @@ const NoticeManage: React.FC = () => { type="link" onClick={() => handleToggleTop(record)} > - {record.isTop === '1' ? '取消置顶' : '置顶'} + {record.isTop === TopStatus.YES ? '取消置顶' : '置顶'} )} @@ -369,7 +325,7 @@ const NoticeManage: React.FC = () => { // 行选择限制 const checkSelectable = (record: NoticeType) => { - return record.status !== '1'; // 已发布的不能选择 + return record.status !== NoticeStatus.PUBLISHED; // 已发布的不能选择 }; const onSelectChange = (newSelectedRowKeys: React.Key[]) => { @@ -380,7 +336,7 @@ const NoticeManage: React.FC = () => { selectedRowKeys, onChange: onSelectChange, getCheckboxProps: (record: NoticeType) => ({ - disabled: record.status === '1', // 已发布的不能选择 + disabled: record.status === NoticeStatus.PUBLISHED, // 已发布的不能选择 }), }; @@ -389,10 +345,10 @@ const NoticeManage: React.FC = () => { // 处理添加 const handleAdd = () => { setIsEdit(false); + setIsViewMode(false); setCurrentId(''); - modalForm.resetFields(); + setViewData(null); setModalVisible(true); - setActiveTabKey('zh'); }; // 处理批量删除 @@ -411,17 +367,19 @@ const NoticeManage: React.FC = () => { // 获取可删除的ID(非已发布状态) const deleteIds = selectedRowKeys.filter(key => { const record = noticeData.find(item => item.key === key); - return record && record.status !== '1'; + return record && record.status !== NoticeStatus.PUBLISHED; }) as string[]; if (deleteIds.length > 0) { // 调用批量删除API - await batchDeleteNotice(deleteIds); - // 更新本地数据 - const newData = noticeData.filter(item => !deleteIds.includes(item.key)); - setNoticeData(newData); - setSelectedRowKeys([]); - message.success('删除成功'); + const response = await batchDeleteNotice(deleteIds); + if (response && response.success) { + setSelectedRowKeys([]); + message.success('删除成功'); + fetchNoticeList(pagination.current, pagination.pageSize, searchParams); // 重新加载数据 + } else { + message.error(response.message || '批量删除失败'); + } } else { message.warning('没有可删除的通知'); } @@ -436,85 +394,15 @@ const NoticeManage: React.FC = () => { }; // 处理搜索 - const handleSearch = (values: API.NoticeSearchParams) => { - setSearchParams(values); - fetchNoticeList(1, pagination.pageSize); - }; - - // 处理模态框提交 - const handleModalSubmit = () => { - // 先触发所有字段的验证 - modalForm.validateFields() - .then(async values => { - try { - const noticeParams: API.NoticeRequest = { - title: values.titleZh, - titleEn: values.titleEn || '', - content: values.contentZh, - contentEn: values.contentEn || '', - isTop: values.isTop ? '1' : '0', - settingEn: values.titleEn && values.contentEn ? 1 : 0, - }; - - if (isEdit) { - // 编辑模式,调用更新API - await updateNotice(currentId, noticeParams); - message.success('更新成功'); - } else { - // 新增模式,调用添加API - await addNotice(noticeParams); - message.success('添加成功'); - } - - setModalVisible(false); - modalForm.resetFields(); - // 刷新列表 - fetchNoticeList(pagination.current, pagination.pageSize); - } catch (error) { - console.error(isEdit ? '更新通知失败:' : '添加通知失败:', error); - message.error(isEdit ? '更新失败' : '添加失败'); - } - }) - .catch(errorInfo => { - // 获取所有字段的错误信息 - const errorFields = errorInfo.errorFields || []; - - // 检查是否有中文标题或内容的错误 - const hasZhError = errorFields.some((field: any) => { - if (!field.name) return false; - const fieldName = Array.isArray(field.name) ? field.name.join('.') : String(field.name); - return fieldName.includes('titleZh') || fieldName.includes('contentZh'); - }); - - // 检查是否有英文标题或内容的错误 - const hasEnError = errorFields.some((field: any) => { - if (!field.name) return false; - const fieldName = Array.isArray(field.name) ? field.name.join('.') : String(field.name); - return fieldName.includes('titleEn') || fieldName.includes('contentEn'); - }); - - // 如果有中文字段错误,切换到中文Tab - if (hasZhError) { - setActiveTabKey('zh'); - } - // 如果只有英文字段错误,切换到英文Tab - else if (hasEnError && !hasZhError) { - setActiveTabKey('en'); - } - - console.log('表单验证失败:', errorInfo); - }); - }; - - // 处理Tab切换 - const handleTabChange = (key: string) => { - setActiveTabKey(key); + const handleSearch = (values: SearchParams) => { + fetchNoticeList(1, pagination.pageSize, values); }; // 处理模态框取消 const handleModalCancel = () => { setModalVisible(false); - modalForm.resetFields(); + setIsViewMode(false); + setViewData(null); }; return ( @@ -532,9 +420,9 @@ const NoticeManage: React.FC = () => { @@ -547,8 +435,7 @@ const NoticeManage: React.FC = () => { icon={} onClick={() => { form.resetFields(); - setSearchParams({}); - handleSearch({}); + fetchNoticeList(1, pagination.pageSize, {}); }} > 重置 @@ -593,71 +480,38 @@ const NoticeManage: React.FC = () => { />
- {/* 新增/编辑模态框 */} + {/* 新增/编辑/查看模态框 */} + 关闭 + , + ] + : null + } > -
- - - - - - - - - - - - - - - - - - - - - - - - -
+ {isViewMode && viewData ? ( + // 查看详情模式 + + ) : ( + // 编辑/新增模式 + { + setModalVisible(false); + fetchNoticeList(pagination.current, pagination.pageSize, searchParams); + }} + /> + )}
); diff --git a/src/pages/policyManage/PolicyManageForm.tsx b/src/pages/policyManage/PolicyManageForm.tsx new file mode 100644 index 0000000..5e3f72b --- /dev/null +++ b/src/pages/policyManage/PolicyManageForm.tsx @@ -0,0 +1,179 @@ +import React, { useState, useEffect } from 'react'; +import { Form, Input, Switch, Tabs, message, Button } from 'antd'; +import WangEditor from '@/components/WangEidtor/WangEidtor'; +import { TopStatus, EnglishSetting } from '@/dicts/policyManageDict'; +import { addPolicy, updatePolicy, getPolicyDetail } from '@/servers/api/policy'; + +const { TabPane } = Tabs; + +interface PolicyManageFormProps { + id?: string; + isEdit: boolean; + onSuccess: () => void; +} + +const PolicyManageForm: React.FC = ({ id, isEdit, onSuccess }) => { + const [form] = Form.useForm(); + const [activeTabKey, setActiveTabKey] = useState('zh'); + const [loading, setLoading] = useState(false); + + // 获取详情数据 + useEffect(() => { + const fetchPolicyDetail = async (policyId: string) => { + setLoading(true); + try { + const response = await getPolicyDetail(policyId); + if (response && response.success) { + const detail = response.data; + form.setFieldsValue({ + isTop: detail.isTop === TopStatus.YES, + titleZh: detail.title, + titleEn: detail.titleEn, + contentZh: detail.content, + contentEn: detail.contentEn, + }); + } else { + message.error(response.message || '获取详情失败'); + } + } catch (error) { + console.error('获取政策详情失败:', error); + message.error('获取详情失败'); + } finally { + setLoading(false); + } + }; + + if (isEdit && id) { + fetchPolicyDetail(id); + } + }, [isEdit, id, form]); + + // 处理Tab切换 + const handleTabChange = (key: string) => { + setActiveTabKey(key); + }; + + // 提交表单 + const handleSubmit = async () => { + setLoading(true); + try { + // 一次性验证所有表单项 + try { + await form.validateFields(); + } catch (error: any) { + console.log(error); + // 如果有验证错误,自动切换到相应Tab + if (error.errorFields && error.errorFields.length > 0) { + // 获取第一个错误字段 + const firstError = error.errorFields[0]; + const fieldName = firstError.name[0]; + + // 根据字段名判断应该切换到哪个Tab + if (fieldName === 'titleZh' || fieldName === 'contentZh') { + setActiveTabKey('zh'); + } else if (fieldName === 'titleEn' || fieldName === 'contentEn') { + setActiveTabKey('en'); + } + } + + throw error; + } + + // 获取所有表单值 + const values = form.getFieldsValue(); + + // 转换表单数据为API需要的格式 + const requestData = { + title: values.titleZh, + titleEn: values.titleEn || '', + content: values.contentZh, + contentEn: values.contentEn || '', + isTop: values.isTop ? TopStatus.YES : TopStatus.NO, + settingEn: values.titleEn && values.contentEn ? EnglishSetting.YES : EnglishSetting.NO, + }; + + let response; + if (isEdit && id) { + response = await updatePolicy(id, requestData); + } else { + response = await addPolicy(requestData); + } + + if (response && response.success) { + message.success(isEdit ? '更新成功' : '添加成功'); + onSuccess(); // 回调父组件 + } else { + message.error(response.message || (isEdit ? '更新失败' : '添加失败')); + } + } catch (error: any) { + console.error('表单验证或提交失败:', error); + // 错误已在前面处理 + } finally { + setLoading(false); + } + }; + + return ( +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+ ); +}; + +export default PolicyManageForm; diff --git a/src/pages/policyManage/PolicyManageInfo.tsx b/src/pages/policyManage/PolicyManageInfo.tsx new file mode 100644 index 0000000..d04d442 --- /dev/null +++ b/src/pages/policyManage/PolicyManageInfo.tsx @@ -0,0 +1,59 @@ +import React from 'react'; +import { Descriptions, Divider, Card, Tag } from 'antd'; +import { PolicyStatusText, PolicyStatusColor, PolicyStatus } from '@/dicts/policyManageDict'; + +interface PolicyManageInfoProps { + data: API.PolicyRecord | null; +} + +// 获取状态标签 +const getStatusTag = (status: PolicyStatus) => { + const statusKey = status; + const color = PolicyStatusColor[statusKey] || 'default'; + const text = PolicyStatusText[statusKey] || '未知'; + return {text}; +}; + +const PolicyManageInfo: React.FC = ({ data }) => { + if (!data) return null; + + return ( +
+ + + {data.title} + + {data.titleEn && ( + + {data.titleEn} + + )} + {data.isTop ? '是' : '否'} + {getStatusTag(data.status)} + {data.createBy} + {data.createTime} + {data.updateTime && ( + + {data.updateTime} + + )} + + + 中文内容 + +
+ + + {data.contentEn && ( + <> + 英文内容 + +
+ + + )} +
+ ); +}; + +export default PolicyManageInfo; diff --git a/src/pages/policyManage/policyManage.tsx b/src/pages/policyManage/policyManage.tsx index 035ed53..928ca49 100644 --- a/src/pages/policyManage/policyManage.tsx +++ b/src/pages/policyManage/policyManage.tsx @@ -1,27 +1,49 @@ import React, { useState, useEffect } from 'react'; import { useIntl } from 'umi'; -import { Button, Table, Space, Modal, message, Input, Select, Form, Tooltip, Switch, Tabs, Tag, TablePaginationConfig } from 'antd'; +import { + Button, + Table, + Space, + Modal, + message, + Input, + Select, + Form, + Tooltip, + Tag, + TablePaginationConfig, + Tabs, +} from 'antd'; import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined, SearchOutlined, + EyeOutlined, } from '@ant-design/icons'; -import { addPolicy, getPolicyPage, deletePolicy, publishPolicy, unpublishPolicy, getPolicyDetail, updatePolicy } from '@/servers/api/policy'; -import WangEditor from '@/components/WangEidtor/WangEidtor'; +import { + getPolicyPage, + deletePolicy, + publishPolicy, + unpublishPolicy, + getPolicyDetail, +} from '@/servers/api/policy'; +import { + PolicyStatus, + PolicyStatusText, + PolicyStatusColor, + TopStatus, +} from '@/dicts/policyManageDict'; +import PolicyManageInfo from './PolicyManageInfo'; +import PolicyManageForm from './PolicyManageForm'; const { Option } = Select; const { TabPane } = Tabs; -interface PolicyType { +// 扩展 API.PolicyRecord 类型,添加 key 属性 +type PolicyType = API.PolicyRecord & { key: string; - id: string; - title: string; - createTime: string; - status: string; - createBy: string; - isTop: string; -} +}; interface SearchParams { title?: string; @@ -35,8 +57,11 @@ const PolicyManage: React.FC = () => { const [form] = Form.useForm(); const [modalVisible, setModalVisible] = useState(false); const [isEdit, setIsEdit] = useState(false); + const [isViewMode, setIsViewMode] = useState(false); const [currentId, setCurrentId] = useState(''); - const [modalForm] = Form.useForm(); + + // 查看详情数据 + const [viewData, setViewData] = useState(null); const [policyData, setPolicyData] = useState([]); const [pagination, setPagination] = useState({ current: 1, @@ -47,37 +72,40 @@ const PolicyManage: React.FC = () => { showTotal: (total) => `共 ${total} 条记录`, }); const [searchParams, setSearchParams] = useState({}); - const [activeTabKey, setActiveTabKey] = useState('zh'); // 获取政策列表 - const fetchPolicyList = async (current: number = 1, pageSize: number = 10) => { + const fetchPolicyList = async ( + current = 1, + pageSize = 10, + params: SearchParams = searchParams, + ) => { + // 更新搜索参数状态 + if (params !== searchParams) { + setSearchParams(params); + } + setLoading(true); try { // 构造请求参数 - const params: API.PageRequest = { + const requestParams: API.PageRequest = { basePageRequest: { pageNo: current, pageSize: pageSize, }, - ...searchParams, + ...params, // 使用传入的参数,而不是依赖状态 }; - const response = await getPolicyPage(params); + const response = await getPolicyPage(requestParams); if (response && response.success) { const { records, total, current: currentPage, size } = response.data; - // 转换数据 - const formattedData = records.map((item: API.PolicyRecord) => ({ - key: item.id, - id: item.id, - title: item.title, - createTime: item.createTime, - status: item.status, - createBy: item.createBy, - isTop: item.isTop, - })); - - setPolicyData(formattedData); + // 只添加必要的 key 属性 + setPolicyData( + records.map((item: API.PolicyRecord) => ({ + ...item, + key: item.id, + })), + ); setPagination({ ...pagination, current: currentPage, @@ -97,27 +125,20 @@ const PolicyManage: React.FC = () => { // 首次加载获取数据 useEffect(() => { - fetchPolicyList(pagination.current as number, pagination.pageSize as number); + fetchPolicyList(pagination.current, pagination.pageSize, {}); }, []); - // 处理编辑 - const handleEdit = async (record: PolicyType) => { - setIsEdit(true); + // 处理查看 + const handleView = async (record: PolicyType) => { setCurrentId(record.id); - setModalVisible(true); - setActiveTabKey('zh'); + setIsViewMode(true); try { const response = await getPolicyDetail(record.id); if (response && response.success) { - const detail = response.data; - modalForm.setFieldsValue({ - isTop: detail.isTop === '1', - titleZh: detail.title, - titleEn: detail.titleEn, - contentZh: detail.content, - contentEn: detail.contentEn, - }); + // 设置查看详情数据 + setViewData(response.data); + setModalVisible(true); } else { message.error(response.message || '获取详情失败'); } @@ -127,6 +148,14 @@ const PolicyManage: React.FC = () => { } }; + // 处理编辑 + const handleEdit = (record: PolicyType) => { + setIsEdit(true); + setIsViewMode(false); + setCurrentId(record.id); + setModalVisible(true); + }; + // 处理删除 const showDeleteConfirm = (record: PolicyType) => { Modal.confirm({ @@ -142,7 +171,7 @@ const PolicyManage: React.FC = () => { const response = await deletePolicy(record.id); if (response && response.success) { message.success('删除成功'); - fetchPolicyList(pagination.current as number, pagination.pageSize as number); // 重新加载数据 + fetchPolicyList(pagination.current, pagination.pageSize, searchParams); // 重新加载数据 } else { message.error(response.message || '删除失败'); } @@ -156,54 +185,57 @@ const PolicyManage: React.FC = () => { // 处理发布/下架 const handlePublishStatus = async (record: PolicyType) => { - // 状态: 0.草稿、1.上架、2.下架 - const isPublished = record.status === '1'; + const isPublished = record.status === PolicyStatus.PUBLISHED; const actionText = isPublished ? '下架' : '发布'; - try { - let response; - if (isPublished) { - response = await unpublishPolicy(record.id); - } else { - response = await publishPolicy(record.id); - } + Modal.confirm({ + title: `确定要${actionText}该政策吗?`, + icon: , + content: `标题: ${record.title}`, + okText: '确定', + cancelText: '取消', + maskClosable: false, + onOk: async () => { + try { + let response; + if (isPublished) { + response = await unpublishPolicy(record.id); + } else { + response = await publishPolicy(record.id); + } - if (response && response.success) { - message.success(`${actionText}成功`); - fetchPolicyList(pagination.current as number, pagination.pageSize as number); // 重新加载数据 - } else { - message.error(response.message || `${actionText}失败`); - } - } catch (error) { - console.error(`${actionText}失败:`, error); - message.error(`${actionText}失败`); - } + if (response && response.success) { + message.success(`${actionText}成功`); + fetchPolicyList(pagination.current, pagination.pageSize, searchParams); // 重新加载数据 + } else { + message.error(response.message || `${actionText}失败`); + } + } catch (error) { + console.error(`${actionText}失败:`, error); + message.error(`${actionText}失败`); + } + }, + }); }; // 获取状态标签 const getStatusTag = (status: string) => { - switch (status) { - case '0': - return 草稿; - case '1': - return 已发布; - case '2': - return 已下架; - default: - return 未知; - } + const statusKey = status as keyof typeof PolicyStatusText; + const color = PolicyStatusColor[statusKey] || 'default'; + const text = PolicyStatusText[statusKey] || '未知'; + return {text}; }; // 处理表格分页变化 const handleTableChange = (newPagination: TablePaginationConfig) => { - fetchPolicyList(newPagination.current as number, newPagination.pageSize as number); + fetchPolicyList(newPagination.current, newPagination.pageSize, searchParams); }; const columns = [ { title: '序号', - dataIndex: 'id', - key: 'id', + // pageNo *pageSize + + render: (text: string, record: PolicyType, index: number) => index + 1, width: 80, }, { @@ -217,7 +249,11 @@ const PolicyManage: React.FC = () => { render: (title: string, record: PolicyType) => ( - {record.isTop === '1' && 置顶} + {record.isTop === TopStatus.YES && ( + + 置顶 + + )} {title} @@ -248,27 +284,28 @@ const PolicyManage: React.FC = () => { width: 230, align: 'center' as const, render: (_: unknown, record: PolicyType) => ( - - {record.status === '1' ? ( + <> + + {record.status === PolicyStatus.PUBLISHED ? ( ) : ( - + <> + + + + )} - - - + ), }, ]; @@ -287,10 +324,10 @@ const PolicyManage: React.FC = () => { // 处理添加 const handleAdd = () => { setIsEdit(false); + setIsViewMode(false); setCurrentId(''); - modalForm.resetFields(); + setViewData(null); setModalVisible(true); - setActiveTabKey('zh'); }; // 处理批量删除 @@ -307,16 +344,16 @@ const PolicyManage: React.FC = () => { setLoading(true); try { // 实际项目中应该使用批量删除API - const deletePromises = selectedRowKeys.map(id => deletePolicy(id.toString())); + const deletePromises = selectedRowKeys.map((id) => deletePolicy(id.toString())); const results = await Promise.all(deletePromises); // 检查是否所有操作都成功 - const allSuccess = results.every(res => res.success); + const allSuccess = results.every((res) => res.success); if (allSuccess) { setSelectedRowKeys([]); message.success('删除成功'); - fetchPolicyList(pagination.current as number, pagination.pageSize as number); // 重新加载数据 + fetchPolicyList(pagination.current, pagination.pageSize, searchParams); // 重新加载数据 } else { message.error('部分删除失败,请刷新后重试'); } @@ -332,85 +369,15 @@ const PolicyManage: React.FC = () => { // 处理搜索 const handleSearch = (values: SearchParams) => { - setSearchParams(values); - fetchPolicyList(1, pagination.pageSize as number); // 搜索时重置为第一页 + fetchPolicyList(1, pagination.pageSize, values); // 搜索时重置为第一页,直接传入表单值 }; - // 处理Tab切换 - const handleTabChange = (key: string) => { - setActiveTabKey(key); - }; - - // 处理模态框提交 - const handleModalSubmit = () => { - modalForm.validateFields() - .then(async values => { - try { - // 转换表单数据为API需要的格式 - const requestData: API.PolicyRequest = { - title: values.titleZh, - titleEn: values.titleEn || '', - content: values.contentZh, - contentEn: values.contentEn || '', - isTop: values.isTop ? '1' : '0', - settingEn: values.titleEn && values.contentEn ? 1 : 0, - }; - - let response; - if (isEdit) { - response = await updatePolicy(currentId, requestData); - } else { - response = await addPolicy(requestData); - } - - if (response && response.success) { - message.success(isEdit ? '更新成功' : '添加成功'); - setModalVisible(false); - modalForm.resetFields(); - fetchPolicyList(1, pagination.pageSize as number); // 操作成功后返回第一页 - } else { - message.error(response.message || (isEdit ? '更新失败' : '添加失败')); - } - } catch (error) { - console.error(isEdit ? '更新政策失败:' : '添加政策失败:', error); - message.error(isEdit ? '更新失败' : '添加失败'); - } - }) - .catch(errorInfo => { - // 获取所有字段的错误信息 - const errorFields = errorInfo.errorFields || []; - - // 检查是否有中文标题或内容的错误 - const hasZhError = errorFields.some((field: any) => { - if (!field.name) return false; - const fieldName = Array.isArray(field.name) ? field.name.join('.') : String(field.name); - return fieldName.includes('titleZh') || fieldName.includes('contentZh'); - }); - - // 检查是否有英文标题或内容的错误 - const hasEnError = errorFields.some((field: any) => { - if (!field.name) return false; - const fieldName = Array.isArray(field.name) ? field.name.join('.') : String(field.name); - return fieldName.includes('titleEn') || fieldName.includes('contentEn'); - }); - - // 如果有中文字段错误,切换到中文Tab - if (hasZhError) { - setActiveTabKey('zh'); - } - // 如果只有英文字段错误,切换到英文Tab - else if (hasEnError && !hasZhError) { - setActiveTabKey('en'); - } - - console.log('表单验证失败:', errorInfo); - }); - }; // 处理模态框取消 const handleModalCancel = () => { setModalVisible(false); - modalForm.resetFields(); + setIsViewMode(false); + setViewData(null); }; return ( @@ -443,8 +410,7 @@ const PolicyManage: React.FC = () => { icon={} onClick={() => { form.resetFields(); - setSearchParams({}); - fetchPolicyList(1, pagination.pageSize as number); + fetchPolicyList(1, pagination.pageSize, {}); }} > 重置 @@ -453,12 +419,7 @@ const PolicyManage: React.FC = () => {
- {hasSelected && ( - - 已选择 {selectedRowKeys.length} 项 - + 已选择 {selectedRowKeys.length} 项 )}
@@ -489,71 +448,38 @@ const PolicyManage: React.FC = () => { />
- {/* 新增/编辑模态框 */} + {/* 新增/编辑/查看模态框 */} + 关闭 + , + ] + : null + } > -
- - - - - - - - - - - - - - - - - - - - - - - - -
+ {isViewMode && viewData ? ( + // 查看详情模式 + + ) : ( + // 编辑/新增模式 + { + setModalVisible(false); + fetchPolicyList(1, pagination.pageSize, searchParams); + }} + /> + )}
); diff --git a/src/pages/userQuestionManage/QuestionModal.tsx b/src/pages/userQuestionManage/QuestionModal.tsx new file mode 100644 index 0000000..a3e8276 --- /dev/null +++ b/src/pages/userQuestionManage/QuestionModal.tsx @@ -0,0 +1,345 @@ +import React, { useState, useEffect } from 'react'; +import { Modal, Button, Form, Input, Switch, message, Descriptions, Divider, Card, Tag } from 'antd'; +import { ExclamationCircleOutlined } from '@ant-design/icons'; +import { answerQuestion } from '@/servers/api/userQuestion'; +// 引入字典 +import { + AnswerStatus, + AnswerStatusText, + AnswerStatusColor, + PublishStatus, + PublishStatusText, + PublishStatusColor, + TopStatus, + TopStatusText, + TopStatusColor +} from '@/dicts/userQuestionDict'; + +const { TextArea } = Input; + +interface QuestionModalProps { + visible: boolean; + onCancel: () => void; + question: any; + mode: 'view' | 'answer' | 'edit'; + onSuccess: () => void; +} + +/** + * 问题模态框组件 - 整合了查看详情、回答问题和编辑回答功能 + */ +const QuestionModal: React.FC = ({ + visible, + onCancel, + question, + mode, + onSuccess +}) => { + const [form] = Form.useForm(); + const [answerContent, setAnswerContent] = useState(''); + const [loading, setLoading] = useState(false); + + // 初始化表单数据 + useEffect(() => { + if (question) { + setAnswerContent(question.answerContent || ''); + + // 设置表单初始值 + form.setFieldsValue({ + answer: question.answerContent || '', + isPublished: question.isPublished === 1, + isTop: question.isTop === 1 + }); + } + }, [question, form]); + + // 根据模式设置标题 + const getModalTitle = () => { + switch (mode) { + case 'answer': + return '回答问题'; + case 'edit': + return '编辑回答'; + case 'view': + default: + return '问题详情'; + } + }; + + // 获取发布状态标签 + const getPublishTag = (isPublished: number) => { + return isPublished === 1 ? + 已发布 : + 未发布; + }; + + // 获取置顶状态标签 + const getTopTag = (isTop: number) => { + return isTop === 1 ? + 已置顶 : + 未置顶; + }; + + // 获取回答状态标签 + const getAnswerStatusTag = (questionData: any) => { + if (questionData.answerContent && questionData.answerContent.trim() !== '') { + return 已回答; + } else if (questionData.isAnswer === '1') { + return 已阅; + } else { + return 未阅; + } + }; + + // 提交表单处理 + const handleSubmit = () => { + form.validateFields().then(values => { + if (!answerContent || answerContent.trim() === '') { + message.error('请输入回答内容'); + return; + } + + const actionText = mode === 'answer' ? '提交回答' : '保存修改'; + + Modal.confirm({ + title: `确认${actionText}`, + icon: , + content: mode === 'answer' + ? '确定要提交这个回答吗?提交后将变为已回答状态。' + : '确定要保存对此回答的修改吗?', + okText: '确定', + cancelText: '取消', + onOk: async () => { + setLoading(true); + try { + // 调用回答问题API + const response = await answerQuestion({ + id: question.id, + answerContent, + isPublished: values.isPublished ? 1 : 0, + isTop: values.isTop ? 1 : 0 + }); + + if (response && response.success) { + message.success(mode === 'answer' ? '回答提交成功' : '回答修改成功'); + onSuccess(); + onCancel(); + } else { + message.error(response.message || `${actionText}失败`); + } + } catch (error) { + console.error(`${actionText}失败:`, error); + message.error(`${actionText}失败`); + } finally { + setLoading(false); + } + } + }); + }).catch(errorInfo => { + console.log('表单验证失败:', errorInfo); + }); + }; + + // 渲染查看模式内容 + const renderViewContent = () => { + if (!question) return null; + + return ( +
+ + + {question.title} + + + {question.type} + + + {question.askTime} + + + {question.userName} + + + {question.companyName || '-'} + + + {question.fullName || '-'} + + + {question.contactDetails || '-'} + + + {question.email || '-'} + + + {/* 只有已回答的问题才会显示以下字段 */} + {question.isAnswer === '1' && ( + <> + + {getAnswerStatusTag(question)} + + + {getPublishTag(question.isPublished)} + + + {getTopTag(question.isTop)} + + + {question.answerTime || '-'} + + + {question.answerBy || '-'} + + + )} + {/* 未回答的问题显示状态 */} + {question.isAnswer !== '1' && ( + + {getAnswerStatusTag(question)} + + )} + + + 问题内容 + +
+ {question.content} +
+
+ + {question.answerContent && ( + <> + 回答内容 + +
+ {question.answerContent} +
+
+ + )} +
+ ); + }; + + // 渲染编辑模式内容 + const renderEditContent = () => { + if (!question) return null; + + return ( +
+
+ + + {question.title} + + + {question.type} + + + {question.askTime} + + + {question.userName} + + + {question.companyName || '-'} + + + {question.fullName || '-'} + + + {question.contactDetails || '-'} + + + {question.email || '-'} + + + + 问题内容 + +
+ {question.content} +
+
+
+ + 回答内容 + +