问题分类取字典

This commit is contained in:
linxd
2025-08-11 10:51:55 +08:00
parent 5740fbdef1
commit c2e62dfc62
12 changed files with 318 additions and 234 deletions

View File

@ -9,6 +9,7 @@ import {
} from '@ant-design/icons'; } from '@ant-design/icons';
import { getDownloadList, updateDownloadStatus, batchDeleteDownload } from '@/servers/api/download'; import { getDownloadList, updateDownloadStatus, batchDeleteDownload } from '@/servers/api/download';
import DownloadManageForm from './DownloadManageForm'; import DownloadManageForm from './DownloadManageForm';
import uiconfig from '@/uiconfig';
import { import {
DownloadStatus, DownloadStatus,
DownloadIsTop, DownloadIsTop,
@ -499,7 +500,7 @@ const DownloadManage: React.FC = () => {
} }
open={modalVisible} open={modalVisible}
onCancel={handleModalCancel} onCancel={handleModalCancel}
width={600} width={uiconfig.Modal.width}
maskClosable={false} maskClosable={false}
destroyOnClose destroyOnClose
footer={null} footer={null}

View File

@ -5,6 +5,8 @@ import WangEditor from '@/components/WangEidtor/WangEidtor';
import { TopStatus, EnglishSetting, categoryOptions } from '@/dicts/helpManageDict'; import { TopStatus, EnglishSetting, categoryOptions } from '@/dicts/helpManageDict';
import { addHelp, updateHelp, getHelpDetail } from '@/servers/api/help'; import { addHelp, updateHelp, getHelpDetail } from '@/servers/api/help';
import styles from './helpManage.less'; import styles from './helpManage.less';
import { getDictList } from '@/servers/api/dicts';
import type { DictItem } from '@/servers/api/dicts';
const { TabPane } = Tabs; const { TabPane } = Tabs;
const { Option } = Select; const { Option } = Select;
@ -20,9 +22,15 @@ const HelpManageForm: React.FC<HelpManageFormProps> = ({ id, isEdit, onSuccess }
const [activeTabKey, setActiveTabKey] = useState<string>('zh'); const [activeTabKey, setActiveTabKey] = useState<string>('zh');
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
const intl = useIntl(); const intl = useIntl();
const [typeList, setTypeList] = useState<DictItem[]>([]);
// 获取详情数据 // 获取详情数据
useEffect(() => { useEffect(() => {
getDictList('help_center').then((res) => {
if (res.code === 200 && res.success) {
setTypeList(res.data);
}
});
const fetchHelpDetail = async (helpId: string) => { const fetchHelpDetail = async (helpId: string) => {
setLoading(true); setLoading(true);
try { try {
@ -40,7 +48,9 @@ const HelpManageForm: React.FC<HelpManageFormProps> = ({ id, isEdit, onSuccess }
answerContentEn: detail.answerContentNe, answerContentEn: detail.answerContentNe,
}); });
} else { } else {
message.error(response.message || intl.formatMessage({ id: 'helpManage.fetchDetailFailed' })); message.error(
response.message || intl.formatMessage({ id: 'helpManage.fetchDetailFailed' }),
);
} }
} catch (error) { } catch (error) {
console.error('获取帮助详情失败:', error); console.error('获取帮助详情失败:', error);
@ -76,9 +86,17 @@ const HelpManageForm: React.FC<HelpManageFormProps> = ({ id, isEdit, onSuccess }
const fieldName = firstError.name[0]; const fieldName = firstError.name[0];
// 根据字段名判断应该切换到哪个Tab // 根据字段名判断应该切换到哪个Tab
if (fieldName === 'titleZh' || fieldName === 'contentZh' || fieldName === 'answerContentZh') { if (
fieldName === 'titleZh' ||
fieldName === 'contentZh' ||
fieldName === 'answerContentZh'
) {
setActiveTabKey('zh'); setActiveTabKey('zh');
} else if (fieldName === 'titleEn' || fieldName === 'contentEn' || fieldName === 'answerContentEn') { } else if (
fieldName === 'titleEn' ||
fieldName === 'contentEn' ||
fieldName === 'answerContentEn'
) {
setActiveTabKey('en'); setActiveTabKey('en');
} }
} }
@ -110,14 +128,19 @@ const HelpManageForm: React.FC<HelpManageFormProps> = ({ id, isEdit, onSuccess }
} }
if (response && response.success) { if (response && response.success) {
message.success(isEdit message.success(
? intl.formatMessage({ id: 'helpManage.updateSuccess' }) isEdit
: intl.formatMessage({ id: 'helpManage.addSuccess' })); ? intl.formatMessage({ id: 'helpManage.updateSuccess' })
: intl.formatMessage({ id: 'helpManage.addSuccess' }),
);
onSuccess(); // 回调父组件 onSuccess(); // 回调父组件
} else { } else {
message.error(response.message || (isEdit message.error(
? intl.formatMessage({ id: 'helpManage.updateFailed' }) response.message ||
: intl.formatMessage({ id: 'helpManage.addFailed' }))); (isEdit
? intl.formatMessage({ id: 'helpManage.updateFailed' })
: intl.formatMessage({ id: 'helpManage.addFailed' })),
);
} }
} catch (error: any) { } catch (error: any) {
console.error('表单验证或提交失败:', error); console.error('表单验证或提交失败:', error);
@ -130,38 +153,63 @@ const HelpManageForm: React.FC<HelpManageFormProps> = ({ id, isEdit, onSuccess }
return ( return (
<div className={styles.helpForm}> <div className={styles.helpForm}>
<Form form={form} layout="vertical" name="helpForm" preserve={false}> <Form form={form} layout="vertical" name="helpForm" preserve={false}>
<Form.Item name="isTop" label={intl.formatMessage({ id: 'helpManage.form.isTop' })} valuePropName="checked"> <Form.Item
name="isTop"
label={intl.formatMessage({ id: 'helpManage.form.isTop' })}
valuePropName="checked"
>
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="type" name="type"
label={intl.formatMessage({ id: 'helpManage.form.category' })} label={intl.formatMessage({ id: 'helpManage.form.category' })}
rules={[{ required: true, message: intl.formatMessage({ id: 'helpManage.form.categoryRequired' }) }]} rules={[
{
required: true,
message: intl.formatMessage({ id: 'helpManage.form.categoryRequired' }),
},
]}
> >
<Select placeholder={intl.formatMessage({ id: 'helpManage.form.categoryPlaceholder' })}> <Select placeholder={intl.formatMessage({ id: 'helpManage.form.categoryPlaceholder' })}>
{categoryOptions.map(option => ( {typeList.map((option) => (
<Option key={option.value} value={option.value}> <Option key={option.code} value={option.code}>
{typeof option.label === 'function' ? option.label() : option.label} {option.dicName}
</Option> </Option>
))} ))}
</Select> </Select>
</Form.Item> </Form.Item>
<Tabs activeKey={activeTabKey} onChange={handleTabChange}> <Tabs activeKey={activeTabKey} onChange={handleTabChange}>
<TabPane tab={intl.formatMessage({ id: 'helpManage.form.chineseTab' })} key="zh" forceRender={true}> <TabPane
tab={intl.formatMessage({ id: 'helpManage.form.chineseTab' })}
key="zh"
forceRender={true}
>
<Form.Item <Form.Item
name="titleZh" name="titleZh"
label={intl.formatMessage({ id: 'helpManage.form.titleZh' })} label={intl.formatMessage({ id: 'helpManage.form.titleZh' })}
rules={[{ required: true, message: intl.formatMessage({ id: 'helpManage.form.titleZhRequired' }) }]} rules={[
{
required: true,
message: intl.formatMessage({ id: 'helpManage.form.titleZhRequired' }),
},
]}
> >
<Input placeholder={intl.formatMessage({ id: 'helpManage.form.titleZhPlaceholder' })} /> <Input
placeholder={intl.formatMessage({ id: 'helpManage.form.titleZhPlaceholder' })}
/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="contentZh" name="contentZh"
label={intl.formatMessage({ id: 'helpManage.form.contentZh' })} label={intl.formatMessage({ id: 'helpManage.form.contentZh' })}
rules={[{ required: true, message: intl.formatMessage({ id: 'helpManage.form.contentZhRequired' }) }]} rules={[
{
required: true,
message: intl.formatMessage({ id: 'helpManage.form.contentZhRequired' }),
},
]}
> >
<WangEditor <WangEditor
language="zh-CN" language="zh-CN"
@ -177,23 +225,41 @@ const HelpManageForm: React.FC<HelpManageFormProps> = ({ id, isEdit, onSuccess }
<WangEditor <WangEditor
language="zh-CN" language="zh-CN"
height="200px" height="200px"
placeholder={intl.formatMessage({ id: 'helpManage.form.answerContentZhPlaceholder' })} placeholder={intl.formatMessage({
id: 'helpManage.form.answerContentZhPlaceholder',
})}
/> />
</Form.Item> </Form.Item>
</TabPane> </TabPane>
<TabPane tab={intl.formatMessage({ id: 'helpManage.form.englishTab' })} key="en" forceRender={true}> <TabPane
tab={intl.formatMessage({ id: 'helpManage.form.englishTab' })}
key="en"
forceRender={true}
>
<Form.Item <Form.Item
name="titleEn" name="titleEn"
label={intl.formatMessage({ id: 'helpManage.form.titleEn' })} label={intl.formatMessage({ id: 'helpManage.form.titleEn' })}
rules={[{ required: true, message: intl.formatMessage({ id: 'helpManage.form.titleEnRequired' }) }]} rules={[
{
required: true,
message: intl.formatMessage({ id: 'helpManage.form.titleEnRequired' }),
},
]}
> >
<Input placeholder={intl.formatMessage({ id: 'helpManage.form.titleEnPlaceholder' })} /> <Input
placeholder={intl.formatMessage({ id: 'helpManage.form.titleEnPlaceholder' })}
/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="contentEn" name="contentEn"
label={intl.formatMessage({ id: 'helpManage.form.contentEn' })} label={intl.formatMessage({ id: 'helpManage.form.contentEn' })}
rules={[{ required: true, message: intl.formatMessage({ id: 'helpManage.form.contentEnRequired' }) }]} rules={[
{
required: true,
message: intl.formatMessage({ id: 'helpManage.form.contentEnRequired' }),
},
]}
> >
<WangEditor <WangEditor
language="en" language="en"
@ -209,7 +275,9 @@ const HelpManageForm: React.FC<HelpManageFormProps> = ({ id, isEdit, onSuccess }
<WangEditor <WangEditor
language="en" language="en"
height="200px" height="200px"
placeholder={intl.formatMessage({ id: 'helpManage.form.answerContentEnPlaceholder' })} placeholder={intl.formatMessage({
id: 'helpManage.form.answerContentEnPlaceholder',
})}
/> />
</Form.Item> </Form.Item>
</TabPane> </TabPane>
@ -219,11 +287,7 @@ const HelpManageForm: React.FC<HelpManageFormProps> = ({ id, isEdit, onSuccess }
<Button onClick={() => onSuccess()}> <Button onClick={() => onSuccess()}>
{intl.formatMessage({ id: 'helpManage.cancel' })} {intl.formatMessage({ id: 'helpManage.cancel' })}
</Button> </Button>
<Button <Button type="primary" loading={loading} onClick={handleSubmit}>
type="primary"
loading={loading}
onClick={handleSubmit}
>
{intl.formatMessage({ id: 'helpManage.submit' })} {intl.formatMessage({ id: 'helpManage.submit' })}
</Button> </Button>
</div> </div>

View File

@ -1,22 +1,27 @@
import React from 'react'; import React, { useState } from 'react';
import { Descriptions, Divider, Card, Tag } from 'antd'; import { Descriptions, Divider, Card, Tag } from 'antd';
import { useIntl } from 'umi'; import { useIntl } from 'umi';
import { HelpStatus, HelpStatusText, HelpStatusColor } from '@/dicts/helpManageDict'; import { HelpStatus, HelpStatusText, HelpStatusColor } from '@/dicts/helpManageDict';
import styles from './helpManage.less'; import styles from './helpManage.less';
import { getDictList } from '@/servers/api/dicts';
import type { DictItem } from '@/servers/api/dicts';
interface HelpManageInfoProps { interface HelpManageInfoProps {
data: API.HelpRecord | null; data: API.HelpRecord | null;
typeList: DictItem[];
} }
const HelpManageInfo: React.FC<HelpManageInfoProps> = ({ data }) => { const HelpManageInfo: React.FC<HelpManageInfoProps> = ({ data, typeList }) => {
const intl = useIntl(); const intl = useIntl();
// 获取状态标签 // 获取状态标签
const getStatusTag = (status: string) => { const getStatusTag = (status: string) => {
const statusKey = status as keyof typeof HelpStatusText; const statusKey = status as keyof typeof HelpStatusText;
const color = HelpStatusColor[statusKey] || 'default'; const color = HelpStatusColor[statusKey] || 'default';
const getText = HelpStatusText[statusKey]; const getText = HelpStatusText[statusKey];
const text = typeof getText === 'function' ? getText() : intl.formatMessage({ id: 'helpManage.status.unknown' }); const text =
typeof getText === 'function'
? getText()
: intl.formatMessage({ id: 'helpManage.status.unknown' });
return <Tag color={color}>{text}</Tag>; return <Tag color={color}>{text}</Tag>;
}; };
@ -29,12 +34,15 @@ const HelpManageInfo: React.FC<HelpManageInfoProps> = ({ data }) => {
{data.title} {data.title}
</Descriptions.Item> </Descriptions.Item>
{data.titleEn && ( {data.titleEn && (
<Descriptions.Item label={intl.formatMessage({ id: 'helpManage.detail.titleEn' })} span={2}> <Descriptions.Item
label={intl.formatMessage({ id: 'helpManage.detail.titleEn' })}
span={2}
>
{data.titleEn} {data.titleEn}
</Descriptions.Item> </Descriptions.Item>
)} )}
<Descriptions.Item label={intl.formatMessage({ id: 'helpManage.detail.category' })}> <Descriptions.Item label={intl.formatMessage({ id: 'helpManage.detail.category' })}>
{data.type} {typeList.find((item) => item.code == data.type) ? typeList.find((item) => item.code == data.type).dicName : '-'}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'helpManage.detail.isTop' })}> <Descriptions.Item label={intl.formatMessage({ id: 'helpManage.detail.isTop' })}>
{data.isTop === '1' {data.isTop === '1'
@ -51,40 +59,60 @@ const HelpManageInfo: React.FC<HelpManageInfoProps> = ({ data }) => {
{data.createTime} {data.createTime}
</Descriptions.Item> </Descriptions.Item>
{data.updateTime && ( {data.updateTime && (
<Descriptions.Item label={intl.formatMessage({ id: 'helpManage.detail.updateTime' })} span={2}> <Descriptions.Item
label={intl.formatMessage({ id: 'helpManage.detail.updateTime' })}
span={2}
>
{data.updateTime} {data.updateTime}
</Descriptions.Item> </Descriptions.Item>
)} )}
</Descriptions> </Descriptions>
<Divider orientation="left">{intl.formatMessage({ id: 'helpManage.detail.contentZh' })}</Divider> <Divider orientation="left">
{intl.formatMessage({ id: 'helpManage.detail.contentZh' })}
</Divider>
<Card size="small" bordered={false} className={styles.contentCard}> <Card size="small" bordered={false} className={styles.contentCard}>
<div className={styles.helpContent} dangerouslySetInnerHTML={{ __html: data.content }} /> <div className={styles.helpContent} dangerouslySetInnerHTML={{ __html: data.content }} />
</Card> </Card>
{data.contentEn && ( {data.contentEn && (
<> <>
<Divider orientation="left">{intl.formatMessage({ id: 'helpManage.detail.contentEn' })}</Divider> <Divider orientation="left">
{intl.formatMessage({ id: 'helpManage.detail.contentEn' })}
</Divider>
<Card size="small" bordered={false} className={styles.contentCard}> <Card size="small" bordered={false} className={styles.contentCard}>
<div className={styles.helpContent} dangerouslySetInnerHTML={{ __html: data.contentEn }} /> <div
className={styles.helpContent}
dangerouslySetInnerHTML={{ __html: data.contentEn }}
/>
</Card> </Card>
</> </>
)} )}
{data.answerContent && ( {data.answerContent && (
<> <>
<Divider orientation="left">{intl.formatMessage({ id: 'helpManage.detail.answerContentZh' })}</Divider> <Divider orientation="left">
{intl.formatMessage({ id: 'helpManage.detail.answerContentZh' })}
</Divider>
<Card size="small" bordered={false} className={styles.contentCard}> <Card size="small" bordered={false} className={styles.contentCard}>
<div className={styles.helpContent} dangerouslySetInnerHTML={{ __html: data.answerContent }} /> <div
className={styles.helpContent}
dangerouslySetInnerHTML={{ __html: data.answerContent }}
/>
</Card> </Card>
</> </>
)} )}
{data.answerContentNe && ( {data.answerContentNe && (
<> <>
<Divider orientation="left">{intl.formatMessage({ id: 'helpManage.detail.answerContentEn' })}</Divider> <Divider orientation="left">
{intl.formatMessage({ id: 'helpManage.detail.answerContentEn' })}
</Divider>
<Card size="small" bordered={false} className={styles.contentCard}> <Card size="small" bordered={false} className={styles.contentCard}>
<div className={styles.helpContent} dangerouslySetInnerHTML={{ __html: data.answerContentNe }} /> <div
className={styles.helpContent}
dangerouslySetInnerHTML={{ __html: data.answerContentNe }}
/>
</Card> </Card>
</> </>
)} )}

View File

@ -63,7 +63,7 @@ const HelpManage: React.FC = () => {
showTotal: (total: number) => `${total} 条记录`, showTotal: (total: number) => `${total} 条记录`,
}); });
const [searchParams, setSearchParams] = useState<SearchParams>({}); const [searchParams, setSearchParams] = useState<SearchParams>({});
const [typeList, setTypeList] = useState<DictItem[]>([]); const [typeList, setTypeList] = useState<DictItem[]>([]);
// 获取帮助中心列表数据 // 获取帮助中心列表数据
const fetchHelpList = ( const fetchHelpList = (
@ -111,11 +111,11 @@ const HelpManage: React.FC = () => {
// 首次加载时获取数据 // 首次加载时获取数据
useEffect(() => { useEffect(() => {
getDictList('download_section').then((res) => { getDictList('help_center').then((res) => {
if (res.code === 200 && res.success) { if (res.code === 200 && res.success) {
setTypeList(res.data); setTypeList(res.data);
} }
}); });
fetchHelpList(1, pagination.pageSize, {}); fetchHelpList(1, pagination.pageSize, {});
}, []); }, []);
@ -358,6 +358,10 @@ const HelpManage: React.FC = () => {
dataIndex: 'type', dataIndex: 'type',
key: 'type', key: 'type',
align: 'center' as const, align: 'center' as const,
render: (type: string) => {
const dictItem = typeList.find((item) => item.code === type);
return dictItem ? dictItem.dicName : '-';
},
}, },
{ {
title: intl.formatMessage({ id: 'helpManage.date' }), title: intl.formatMessage({ id: 'helpManage.date' }),
@ -434,9 +438,9 @@ const HelpManage: React.FC = () => {
allowClear allowClear
style={{ width: 150 }} style={{ width: 150 }}
> >
{categoryOptions.map((option) => ( {typeList.map((option) => (
<Option key={option.value} value={option.value}> <Option key={option.code} value={option.code}>
{typeof option.label === 'function' ? option.label() : option.label} {option.dicName}
</Option> </Option>
))} ))}
</Select> </Select>
@ -526,7 +530,7 @@ const HelpManage: React.FC = () => {
maskClosable={false} maskClosable={false}
> >
{isViewMode ? ( {isViewMode ? (
<HelpManageInfo data={viewData} /> <HelpManageInfo data={viewData} typeList={typeList} />
) : ( ) : (
<HelpManageForm id={currentId} isEdit={isEdit} onSuccess={handleModalCancel} /> <HelpManageForm id={currentId} isEdit={isEdit} onSuccess={handleModalCancel} />
)} )}

View File

@ -18,7 +18,7 @@ import {
updateNoticeTopStatus, updateNoticeTopStatus,
getNoticeDetail, getNoticeDetail,
} from '@/servers/api/notice'; } from '@/servers/api/notice';
import styles from './noticeManage.less'; import uiconfig from '@/uiconfig';
import { import {
NoticeStatus, NoticeStatus,
NoticeStatusText, NoticeStatusText,
@ -587,7 +587,7 @@ const NoticeManage: React.FC = () => {
} }
open={modalVisible} open={modalVisible}
onCancel={handleModalCancel} onCancel={handleModalCancel}
width={900} width={uiconfig.Modal.width}
maskClosable={false} maskClosable={false}
destroyOnClose destroyOnClose
footer={ footer={

View File

@ -142,6 +142,7 @@ const PolicyManageForm: React.FC<PolicyManageFormProps> = ({ id, isEdit, onSucce
<Form.Item <Form.Item
name="contentZh" name="contentZh"
valuePropName="value"
label={intl.formatMessage({ id: 'policyManage.form.contentZh' })} label={intl.formatMessage({ id: 'policyManage.form.contentZh' })}
rules={[{ required: true, message: intl.formatMessage({ id: 'policyManage.form.contentZhRequired' }) }]} rules={[{ required: true, message: intl.formatMessage({ id: 'policyManage.form.contentZhRequired' }) }]}
> >
@ -163,6 +164,7 @@ const PolicyManageForm: React.FC<PolicyManageFormProps> = ({ id, isEdit, onSucce
<Form.Item <Form.Item
name="contentEn" name="contentEn"
valuePropName="value"
label={intl.formatMessage({ id: 'policyManage.form.contentEn' })} label={intl.formatMessage({ id: 'policyManage.form.contentEn' })}
rules={[{ required: true, message: intl.formatMessage({ id: 'policyManage.form.contentEnRequired' }) }]} rules={[{ required: true, message: intl.formatMessage({ id: 'policyManage.form.contentEnRequired' }) }]}
> >

View File

@ -14,6 +14,7 @@ import {
TablePaginationConfig, TablePaginationConfig,
Tabs, Tabs,
} from 'antd'; } from 'antd';
import uiconfig from '@/uiconfig';
import { import {
PlusOutlined, PlusOutlined,
DeleteOutlined, DeleteOutlined,
@ -476,7 +477,7 @@ const PolicyManage: React.FC = () => {
: intl.formatMessage({ id: 'policyManage.form.add' })} : intl.formatMessage({ id: 'policyManage.form.add' })}
open={modalVisible} open={modalVisible}
onCancel={handleModalCancel} onCancel={handleModalCancel}
width={900} width={uiconfig.Modal.width}
maskClosable={false} maskClosable={false}
destroyOnClose destroyOnClose
footer={ footer={

View File

@ -16,26 +16,29 @@ import {
TopStatusText, TopStatusText,
TopStatusColor TopStatusColor
} from '@/dicts/userQuestionDict'; } from '@/dicts/userQuestionDict';
import type { DictItem } from '@/servers/api/dicts';
const { TextArea } = Input; const { TextArea } = Input;
interface QuestionModalProps { interface QuestionModalProps {
visible: boolean; open: boolean;
onCancel: () => void; onCancel: () => void;
question: any; question: any;
mode: 'view' | 'answer' | 'edit'; mode: 'view' | 'answer' | 'edit';
onSuccess: () => void; onSuccess: () => void;
typeList: DictItem[];
} }
/** /**
* 问题模态框组件 - 整合了查看详情、回答问题和编辑回答功能 * 问题模态框组件 - 整合了查看详情、回答问题和编辑回答功能
*/ */
const QuestionModal: React.FC<QuestionModalProps> = ({ const QuestionModal: React.FC<QuestionModalProps> = ({
visible, open,
onCancel, onCancel,
question, question,
mode, mode,
onSuccess onSuccess,
typeList
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const [form] = Form.useForm(); const [form] = Form.useForm();
@ -170,7 +173,7 @@ const QuestionModal: React.FC<QuestionModalProps> = ({
{question.title} {question.title}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.category' })}> <Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.category' })}>
{question.type} {typeList.find((item) => item.code === question.type)?.dicName}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.askTime' })}> <Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.askTime' })}>
{question.askTime} {question.askTime}
@ -252,7 +255,7 @@ const QuestionModal: React.FC<QuestionModalProps> = ({
{question.title} {question.title}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.category' })}> <Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.category' })}>
{question.type} {typeList.find((item) => item.code === question.type)?.dicName}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.askTime' })}> <Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.askTime' })}>
{question.askTime} {question.askTime}
@ -357,7 +360,7 @@ const QuestionModal: React.FC<QuestionModalProps> = ({
return ( return (
<Modal <Modal
title={getModalTitle()} title={getModalTitle()}
open={visible} open={open}
onCancel={onCancel} onCancel={onCancel}
width={800} width={800}
footer={renderFooter()} footer={renderFooter()}

View File

@ -1,108 +0,0 @@
import React from 'react';
import { Descriptions, Divider, Card, Tag } from 'antd';
import { useIntl, FormattedMessage } from 'umi';
import styles from './userQuestionManage.less';
import {
PublishStatus,
PublishStatusText,
PublishStatusColor,
TopStatus,
TopStatusText,
TopStatusColor
} from '@/dicts/userQuestionDict';
interface QuestionDetailProps {
question: any; // 可以改为具体的类型
}
/**
* 问题详情查看组件
*/
const QuestionViewDetail: React.FC<QuestionDetailProps> = ({ question }) => {
const intl = useIntl();
if (!question) return null;
// 获取发布状态标签
const getPublishTag = (isPublished: number) => {
return isPublished === 1 ?
<Tag color="green">{PublishStatusText[PublishStatus.YES]()}</Tag> :
<Tag color="orange">{PublishStatusText[PublishStatus.NO]()}</Tag>;
};
// 获取置顶状态标签
const getTopTag = (isTop: number) => {
return isTop === 1 ?
<Tag color="red">{TopStatusText[TopStatus.YES]()}</Tag> :
<Tag color="default">{TopStatusText[TopStatus.NO]()}</Tag>;
};
return (
<div className={styles.questionDetailView}>
<Descriptions bordered column={2} size="small">
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.title' })} span={2}>
{question.title}
</Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.category' })}>
{question.type}
</Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.askTime' })}>
{question.askTime}
</Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.asker' })}>
{question.userName}
</Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.company' })}>
{question.companyName}
</Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.account' })}>
{question.fullName}
</Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.contact' })}>
{question.contactDetails}
</Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.email' })}>
{question.email}
</Descriptions.Item>
{/* 只有已回答的问题才会显示以下字段 */}
{question.isAnswer === '1' && (
<>
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.publishStatus' })}>
{getPublishTag(question.isPublished)}
</Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.topStatus' })}>
{getTopTag(question.isTop)}
</Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.answerTime' })}>
{question.answerTime}
</Descriptions.Item>
<Descriptions.Item label={intl.formatMessage({ id: 'questionDetail.respondent' })}>
{question.answerBy || '-'}
</Descriptions.Item>
</>
)}
</Descriptions>
<Divider orientation="left">{intl.formatMessage({ id: 'questionDetail.questionContent' })}</Divider>
<Card size="small" bordered={false} className={styles.contentCard}>
<div className={styles.questionContent}>
{question.content}
</div>
</Card>
{question.answerContent && (
<>
<Divider orientation="left">{intl.formatMessage({ id: 'questionDetail.answerContent' })}</Divider>
<Card size="small" bordered={false} className={styles.contentCard}>
<div className={styles.answerContent}>
{question.answerContent}
</div>
</Card>
</>
)}
</div>
);
};
export default QuestionViewDetail;

View File

@ -1,12 +1,23 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useIntl, FormattedMessage } from 'umi'; import { useIntl, FormattedMessage } from 'umi';
import { Button, Table, Modal, message, Input, Form, Tooltip, Tag, Space, Switch, TablePaginationConfig, Select } from 'antd';
import { import {
DeleteOutlined, Button,
ExclamationCircleOutlined, Table,
SearchOutlined Modal,
} from '@ant-design/icons'; message,
Input,
Form,
Tooltip,
Tag,
Space,
Switch,
TablePaginationConfig,
Select,
} from 'antd';
import { DeleteOutlined, ExclamationCircleOutlined, SearchOutlined } from '@ant-design/icons';
import styles from './userQuestionManage.less'; import styles from './userQuestionManage.less';
import { getDictList } from '@/servers/api/dicts';
import type { DictItem } from '@/servers/api/dicts';
// 引入封装的组件 // 引入封装的组件
import QuestionModal from './QuestionModal'; import QuestionModal from './QuestionModal';
// 引入API // 引入API
@ -14,15 +25,16 @@ import {
getQuestionPage, getQuestionPage,
getQuestionDetail, getQuestionDetail,
deleteQuestion, deleteQuestion,
batchDeleteQuestion batchDeleteQuestion,
} from '@/servers/api/userQuestion'; } from '@/servers/api/userQuestion';
// 引入字典 // 引入字典
import { import {
QuestionCategoryOptions, QuestionCategoryOptions,
AnswerStatus, AnswerStatus,
AnswerStatusText, AnswerStatusText,
AnswerStatusColor AnswerStatusColor,
} from '@/dicts/userQuestionDict'; } from '@/dicts/userQuestionDict';
import { render } from 'react-dom';
const { confirm } = Modal; const { confirm } = Modal;
const { Option } = Select; const { Option } = Select;
@ -49,6 +61,7 @@ const ReadQuestionManage: React.FC = () => {
const [modalVisible, setModalVisible] = useState<boolean>(false); const [modalVisible, setModalVisible] = useState<boolean>(false);
const [currentQuestion, setCurrentQuestion] = useState<QuestionItemType | null>(null); const [currentQuestion, setCurrentQuestion] = useState<QuestionItemType | null>(null);
const [modalMode, setModalMode] = useState<'view' | 'edit'>('view'); const [modalMode, setModalMode] = useState<'view' | 'edit'>('view');
const [typeList, setTypeList] = useState<DictItem[]>([]);
const [pagination, setPagination] = useState<TablePaginationConfig>({ const [pagination, setPagination] = useState<TablePaginationConfig>({
current: 1, current: 1,
pageSize: 10, pageSize: 10,
@ -58,7 +71,7 @@ const ReadQuestionManage: React.FC = () => {
showTotal: (total: number) => `${total} 条记录`, showTotal: (total: number) => `${total} 条记录`,
}); });
const [searchParams, setSearchParams] = useState<SearchParams>({ const [searchParams, setSearchParams] = useState<SearchParams>({
isAnswer: 1 // 默认已回答 isAnswer: 1, // 默认已回答
}); });
// 获取已回答的用户提问列表数据 // 获取已回答的用户提问列表数据
@ -115,6 +128,11 @@ const ReadQuestionManage: React.FC = () => {
// 首次加载时获取数据 // 首次加载时获取数据
useEffect(() => { useEffect(() => {
fetchQuestionList(pagination.current, pagination.pageSize); fetchQuestionList(pagination.current, pagination.pageSize);
getDictList('help_center').then((res) => {
if (res.code === 200 && res.success) {
setTypeList(res.data);
}
});
}, []); }, []);
// 处理搜索 // 处理搜索
@ -123,7 +141,7 @@ const ReadQuestionManage: React.FC = () => {
...values, ...values,
isAnswer: 1, isAnswer: 1,
// 如果设置了answerStatus为已回答则需要特殊处理 // 如果设置了answerStatus为已回答则需要特殊处理
...values.answerStatus === AnswerStatus.ANSWERED ? { hasAnswerContent: 1 } : {} ...(values.answerStatus === AnswerStatus.ANSWERED ? { hasAnswerContent: 1 } : {}),
}; };
fetchQuestionList(1, pagination.pageSize, params); fetchQuestionList(1, pagination.pageSize, params);
}; };
@ -136,7 +154,7 @@ const ReadQuestionManage: React.FC = () => {
const detailData = response.data; const detailData = response.data;
const formattedDetail = { const formattedDetail = {
...detailData, ...detailData,
key: detailData.id key: detailData.id,
}; };
setCurrentQuestion(formattedDetail); setCurrentQuestion(formattedDetail);
@ -178,7 +196,9 @@ const ReadQuestionManage: React.FC = () => {
message.success(intl.formatMessage({ id: 'readQuestion.deleteSuccess' })); message.success(intl.formatMessage({ id: 'readQuestion.deleteSuccess' }));
fetchQuestionList(pagination.current, pagination.pageSize, searchParams); // 重新加载数据 fetchQuestionList(pagination.current, pagination.pageSize, searchParams); // 重新加载数据
} else { } else {
message.error(response.message || intl.formatMessage({ id: 'readQuestion.deleteFailed' })); message.error(
response.message || intl.formatMessage({ id: 'readQuestion.deleteFailed' }),
);
} }
} catch (error) { } catch (error) {
console.error('删除问题失败:', error); console.error('删除问题失败:', error);
@ -216,7 +236,9 @@ const ReadQuestionManage: React.FC = () => {
message.success(intl.formatMessage({ id: 'readQuestion.batchDeleteSuccess' })); message.success(intl.formatMessage({ id: 'readQuestion.batchDeleteSuccess' }));
fetchQuestionList(pagination.current, pagination.pageSize, searchParams); fetchQuestionList(pagination.current, pagination.pageSize, searchParams);
} else { } else {
message.error(response.message || intl.formatMessage({ id: 'readQuestion.batchDeleteFailed' })); message.error(
response.message || intl.formatMessage({ id: 'readQuestion.batchDeleteFailed' }),
);
} }
} catch (error) { } catch (error) {
console.error('批量删除失败:', error); console.error('批量删除失败:', error);
@ -241,17 +263,25 @@ const ReadQuestionManage: React.FC = () => {
// 获取回答状态标签 // 获取回答状态标签
const getAnswerTag = (record: QuestionItemType) => { const getAnswerTag = (record: QuestionItemType) => {
if (record.answerContent && record.answerContent.trim() !== '') { if (record.answerContent && record.answerContent.trim() !== '') {
return <Tag color={AnswerStatusColor[AnswerStatus.ANSWERED]}>{AnswerStatusText[AnswerStatus.ANSWERED]()}</Tag>; return (
<Tag color={AnswerStatusColor[AnswerStatus.ANSWERED]}>
{AnswerStatusText[AnswerStatus.ANSWERED]()}
</Tag>
);
} else { } else {
return <Tag color={AnswerStatusColor[AnswerStatus.READ]}>{AnswerStatusText[AnswerStatus.READ]()}</Tag>; return (
<Tag color={AnswerStatusColor[AnswerStatus.READ]}>
{AnswerStatusText[AnswerStatus.READ]()}
</Tag>
);
} }
}; };
// 获取置顶状态标签 // 获取置顶状态标签
const getTopTag = (isTop: number) => { const getTopTag = (isTop: number) => {
return isTop === 1 ? return isTop === 1 ? (
<Tag color="red">{intl.formatMessage({ id: 'userQuestion.top' })}</Tag> : <Tag color="red">{intl.formatMessage({ id: 'userQuestion.top' })}</Tag>
null; ) : null;
}; };
// 表格列定义 // 表格列定义
@ -283,6 +313,10 @@ const ReadQuestionManage: React.FC = () => {
dataIndex: 'type', dataIndex: 'type',
key: 'type', key: 'type',
align: 'center' as const, align: 'center' as const,
render: (type: string) => {
const dictItem = typeList.find((item) => item.code === type);
return dictItem ? dictItem.dicName : '-';
},
}, },
{ {
title: intl.formatMessage({ id: 'readQuestion.asker' }), title: intl.formatMessage({ id: 'readQuestion.asker' }),
@ -353,7 +387,9 @@ const ReadQuestionManage: React.FC = () => {
render: (_: unknown, record: QuestionItemType) => ( render: (_: unknown, record: QuestionItemType) => (
<Space> <Space>
{getAnswerTag(record)} {getAnswerTag(record)}
{record.isPublished === 1 && <Tag color="green">{intl.formatMessage({ id: 'userQuestion.published' })}</Tag>} {record.isPublished === 1 && (
<Tag color="green">{intl.formatMessage({ id: 'userQuestion.published' })}</Tag>
)}
</Space> </Space>
), ),
}, },
@ -380,9 +416,9 @@ const ReadQuestionManage: React.FC = () => {
// 获取分类选项,处理为下拉框选项 // 获取分类选项,处理为下拉框选项
const getCategoryOptions = () => { const getCategoryOptions = () => {
return QuestionCategoryOptions.map(option => ( return typeList.map((option) => (
<Option key={option.value} value={option.value}> <Option key={option.code} value={option.code}>
{typeof option.label === 'function' ? option.label() : option.label} {option.dicName}
</Option> </Option>
)); ));
}; };
@ -398,17 +434,33 @@ const ReadQuestionManage: React.FC = () => {
className="filter-form" className="filter-form"
> >
<Form.Item name="title" label={intl.formatMessage({ id: 'readQuestion.questionTitle' })}> <Form.Item name="title" label={intl.formatMessage({ id: 'readQuestion.questionTitle' })}>
<Input placeholder={intl.formatMessage({ id: 'readQuestion.questionPlaceholder' })} allowClear /> <Input
placeholder={intl.formatMessage({ id: 'readQuestion.questionPlaceholder' })}
allowClear
/>
</Form.Item> </Form.Item>
<Form.Item name="type" label={intl.formatMessage({ id: 'readQuestion.category' })}> <Form.Item name="type" label={intl.formatMessage({ id: 'readQuestion.category' })}>
<Select placeholder={intl.formatMessage({ id: 'readQuestion.selectCategory' })} allowClear style={{ width: 150 }}> <Select
placeholder={intl.formatMessage({ id: 'readQuestion.selectCategory' })}
allowClear
style={{ width: 150 }}
>
{getCategoryOptions()} {getCategoryOptions()}
</Select> </Select>
</Form.Item> </Form.Item>
<Form.Item name="answerStatus" label={intl.formatMessage({ id: 'readQuestion.answerStatus' })}> <Form.Item
<Select placeholder={intl.formatMessage({ id: 'readQuestion.selectAnswerStatus' })} allowClear style={{ width: 120 }}> name="answerStatus"
label={intl.formatMessage({ id: 'readQuestion.answerStatus' })}
>
<Select
placeholder={intl.formatMessage({ id: 'readQuestion.selectAnswerStatus' })}
allowClear
style={{ width: 120 }}
>
<Option value={AnswerStatus.READ}>{AnswerStatusText[AnswerStatus.READ]()}</Option> <Option value={AnswerStatus.READ}>{AnswerStatusText[AnswerStatus.READ]()}</Option>
<Option value={AnswerStatus.ANSWERED}>{AnswerStatusText[AnswerStatus.ANSWERED]()}</Option> <Option value={AnswerStatus.ANSWERED}>
{AnswerStatusText[AnswerStatus.ANSWERED]()}
</Option>
</Select> </Select>
</Form.Item> </Form.Item>
<Form.Item className="filter-btns"> <Form.Item className="filter-btns">
@ -430,17 +482,15 @@ const ReadQuestionManage: React.FC = () => {
</Form> </Form>
<div className="right-buttons"> <div className="right-buttons">
<Button <Button danger onClick={handleBatchDelete} disabled={!hasSelected} loading={loading}>
danger
onClick={handleBatchDelete}
disabled={!hasSelected}
loading={loading}
>
{intl.formatMessage({ id: 'readQuestion.batchDelete' })} {intl.formatMessage({ id: 'readQuestion.batchDelete' })}
</Button> </Button>
{hasSelected && ( {hasSelected && (
<span className="selected-count"> <span className="selected-count">
{intl.formatMessage({ id: 'readQuestion.selectedCount' }, { count: selectedRowKeys.length })} {intl.formatMessage(
{ id: 'readQuestion.selectedCount' },
{ count: selectedRowKeys.length },
)}
</span> </span>
)} )}
</div> </div>
@ -464,6 +514,7 @@ const ReadQuestionManage: React.FC = () => {
onCancel={() => setModalVisible(false)} onCancel={() => setModalVisible(false)}
question={currentQuestion} question={currentQuestion}
mode={modalMode} mode={modalMode}
typeList={typeList}
onSuccess={() => fetchQuestionList(pagination.current, pagination.pageSize, searchParams)} onSuccess={() => fetchQuestionList(pagination.current, pagination.pageSize, searchParams)}
/> />
</div> </div>

View File

@ -1,14 +1,23 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useIntl, FormattedMessage } from 'umi'; import { useIntl, FormattedMessage } from 'umi';
import { Button, Table, Modal, message, Input, Form, Tooltip, Tag, Space, TablePaginationConfig } from 'antd';
import { import {
DeleteOutlined, Button,
ExclamationCircleOutlined, Table,
SearchOutlined Modal,
} from '@ant-design/icons'; message,
Input,
Form,
Tooltip,
Tag,
Space,
TablePaginationConfig,
} from 'antd';
import { DeleteOutlined, ExclamationCircleOutlined, SearchOutlined } from '@ant-design/icons';
import styles from './userQuestionManage.less'; import styles from './userQuestionManage.less';
// 引入封装的组件 // 引入封装的组件
import QuestionModal from './QuestionModal'; import QuestionModal from './QuestionModal';
import { getDictList } from '@/servers/api/dicts';
import type { DictItem } from '@/servers/api/dicts';
// 引入API // 引入API
import { import {
getQuestionPage, getQuestionPage,
@ -16,7 +25,7 @@ import {
markQuestionSeen, markQuestionSeen,
markQuestionSeeEdit, markQuestionSeeEdit,
deleteQuestion, deleteQuestion,
batchDeleteQuestion batchDeleteQuestion,
} from '@/servers/api/userQuestion'; } from '@/servers/api/userQuestion';
// 引入字典 // 引入字典
import { QuestionCategoryOptions } from '@/dicts/userQuestionDict'; import { QuestionCategoryOptions } from '@/dicts/userQuestionDict';
@ -43,6 +52,7 @@ const UnreadQuestionManage: React.FC = () => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [answerModalVisible, setAnswerModalVisible] = useState<boolean>(false); const [answerModalVisible, setAnswerModalVisible] = useState<boolean>(false);
const [currentQuestion, setCurrentQuestion] = useState<QuestionItemType | null>(null); const [currentQuestion, setCurrentQuestion] = useState<QuestionItemType | null>(null);
const [typeList, setTypeList] = useState<DictItem[]>([]);
const [pagination, setPagination] = useState<TablePaginationConfig>({ const [pagination, setPagination] = useState<TablePaginationConfig>({
current: 1, current: 1,
pageSize: 10, pageSize: 10,
@ -52,7 +62,7 @@ const UnreadQuestionManage: React.FC = () => {
showTotal: (total: number) => `${total} 条记录`, showTotal: (total: number) => `${total} 条记录`,
}); });
const [searchParams, setSearchParams] = useState<SearchParams>({ const [searchParams, setSearchParams] = useState<SearchParams>({
isAnswer: 0 // 默认未回答 isAnswer: 0, // 默认未回答
}); });
// 获取未回答的用户提问列表数据 // 获取未回答的用户提问列表数据
@ -89,8 +99,8 @@ const UnreadQuestionManage: React.FC = () => {
})); }));
setQuestionData(formattedData); setQuestionData(formattedData);
setPagination({ setPagination({
...pagination, ...pagination,
current: currentPage, current: currentPage,
pageSize: size, pageSize: size,
total, total,
@ -102,12 +112,17 @@ const UnreadQuestionManage: React.FC = () => {
console.error('获取问题列表失败:', error); console.error('获取问题列表失败:', error);
message.error(intl.formatMessage({ id: 'unreadQuestion.fetchFailed' })); message.error(intl.formatMessage({ id: 'unreadQuestion.fetchFailed' }));
} finally { } finally {
setLoading(false); setLoading(false);
} }
}; };
// 首次加载时获取数据 // 首次加载时获取数据
useEffect(() => { useEffect(() => {
getDictList('help_center').then((res) => {
if (res.code === 200 && res.success) {
setTypeList(res.data);
}
});
fetchQuestionList(pagination.current, pagination.pageSize); fetchQuestionList(pagination.current, pagination.pageSize);
}, []); }, []);
@ -124,8 +139,8 @@ const UnreadQuestionManage: React.FC = () => {
const response = await markQuestionSeeEdit(record.id); const response = await markQuestionSeeEdit(record.id);
if (!response || !response.success) { if (!response || !response.success) {
message.error(response?.message || intl.formatMessage({ id: 'userQuestion.replyFailed' })); message.error(response?.message || intl.formatMessage({ id: 'userQuestion.replyFailed' }));
return; return;
} }
// 获取问题详情 // 获取问题详情
const detailResponse = await getQuestionDetail(record.id); const detailResponse = await getQuestionDetail(record.id);
@ -133,13 +148,15 @@ const UnreadQuestionManage: React.FC = () => {
const detailData = detailResponse.data; const detailData = detailResponse.data;
const formattedDetail = { const formattedDetail = {
...detailData, ...detailData,
key: detailData.id key: detailData.id,
}; };
setCurrentQuestion(formattedDetail); setCurrentQuestion(formattedDetail);
setAnswerModalVisible(true); setAnswerModalVisible(true);
} else { } else {
message.error(detailResponse.message || intl.formatMessage({ id: 'userQuestion.replyFailed' })); message.error(
detailResponse.message || intl.formatMessage({ id: 'userQuestion.replyFailed' }),
);
} }
} catch (error) { } catch (error) {
console.error('处理问题失败:', error); console.error('处理问题失败:', error);
@ -164,7 +181,9 @@ const UnreadQuestionManage: React.FC = () => {
message.success(intl.formatMessage({ id: 'userQuestion.deleteSuccess' })); message.success(intl.formatMessage({ id: 'userQuestion.deleteSuccess' }));
fetchQuestionList(pagination.current, pagination.pageSize, searchParams); // 重新加载数据 fetchQuestionList(pagination.current, pagination.pageSize, searchParams); // 重新加载数据
} else { } else {
message.error(response.message || intl.formatMessage({ id: 'userQuestion.deleteFailed' })); message.error(
response.message || intl.formatMessage({ id: 'userQuestion.deleteFailed' }),
);
} }
} catch (error) { } catch (error) {
console.error('删除问题失败:', error); console.error('删除问题失败:', error);
@ -202,7 +221,9 @@ const UnreadQuestionManage: React.FC = () => {
message.success(intl.formatMessage({ id: 'unreadQuestion.batchDeleteSuccess' })); message.success(intl.formatMessage({ id: 'unreadQuestion.batchDeleteSuccess' }));
fetchQuestionList(pagination.current, pagination.pageSize, searchParams); fetchQuestionList(pagination.current, pagination.pageSize, searchParams);
} else { } else {
message.error(response.message || intl.formatMessage({ id: 'unreadQuestion.batchDeleteFailed' })); message.error(
response.message || intl.formatMessage({ id: 'unreadQuestion.batchDeleteFailed' }),
);
} }
} catch (error) { } catch (error) {
console.error('批量删除失败:', error); console.error('批量删除失败:', error);
@ -226,9 +247,9 @@ const UnreadQuestionManage: React.FC = () => {
// 获取分类选项,处理为下拉框选项 // 获取分类选项,处理为下拉框选项
const getCategoryOptions = () => { const getCategoryOptions = () => {
return QuestionCategoryOptions.map(option => ( return typeList.map((option) => (
<option key={option.value} value={option.value}> <option key={option.code} value={option.code}>
{typeof option.label === 'function' ? option.label() : option.label} {option.dicName}
</option> </option>
)); ));
}; };
@ -260,6 +281,10 @@ const UnreadQuestionManage: React.FC = () => {
key: 'type', key: 'type',
width: 120, width: 120,
align: 'center' as const, align: 'center' as const,
render: (type: string) => {
const dictItem = typeList.find((item) => item.code === type);
return dictItem ? dictItem.dicName : '-';
},
}, },
{ {
title: intl.formatMessage({ id: 'unreadQuestion.asker' }), title: intl.formatMessage({ id: 'unreadQuestion.asker' }),
@ -327,7 +352,7 @@ const UnreadQuestionManage: React.FC = () => {
<Space> <Space>
<Button type="link" onClick={() => handleAnswer(record)}> <Button type="link" onClick={() => handleAnswer(record)}>
{intl.formatMessage({ id: 'unreadQuestion.reply' })} {intl.formatMessage({ id: 'unreadQuestion.reply' })}
</Button> </Button>
<Button type="link" onClick={() => showDeleteConfirm(record)}> <Button type="link" onClick={() => showDeleteConfirm(record)}>
{intl.formatMessage({ id: 'unreadQuestion.delete' })} {intl.formatMessage({ id: 'unreadQuestion.delete' })}
</Button> </Button>
@ -346,12 +371,20 @@ const UnreadQuestionManage: React.FC = () => {
layout="inline" layout="inline"
className="filter-form" className="filter-form"
> >
<Form.Item name="title" label={intl.formatMessage({ id: 'unreadQuestion.questionTitle' })}> <Form.Item
<Input placeholder={intl.formatMessage({ id: 'unreadQuestion.questionPlaceholder' })} allowClear /> name="title"
label={intl.formatMessage({ id: 'unreadQuestion.questionTitle' })}
>
<Input
placeholder={intl.formatMessage({ id: 'unreadQuestion.questionPlaceholder' })}
allowClear
/>
</Form.Item> </Form.Item>
<Form.Item name="type" label={intl.formatMessage({ id: 'unreadQuestion.category' })}> <Form.Item name="type" label={intl.formatMessage({ id: 'unreadQuestion.category' })}>
<select className="ant-select" style={{ width: 150, height: 32, borderRadius: 2 }}> <select className="ant-select" style={{ width: 150, height: 32, borderRadius: 2 }}>
<option value="">{intl.formatMessage({ id: 'unreadQuestion.selectCategory' })}</option> <option value="">
{intl.formatMessage({ id: 'unreadQuestion.selectCategory' })}
</option>
{getCategoryOptions()} {getCategoryOptions()}
</select> </select>
</Form.Item> </Form.Item>
@ -374,17 +407,15 @@ const UnreadQuestionManage: React.FC = () => {
</Form> </Form>
<div className="right-buttons"> <div className="right-buttons">
<Button <Button danger onClick={handleBatchDelete} disabled={!hasSelected} loading={loading}>
danger
onClick={handleBatchDelete}
disabled={!hasSelected}
loading={loading}
>
{intl.formatMessage({ id: 'unreadQuestion.batchDelete' })} {intl.formatMessage({ id: 'unreadQuestion.batchDelete' })}
</Button> </Button>
{hasSelected && ( {hasSelected && (
<span className="selected-count"> <span className="selected-count">
{intl.formatMessage({ id: 'unreadQuestion.selectedCount' }, { count: selectedRowKeys.length })} {intl.formatMessage(
{ id: 'unreadQuestion.selectedCount' },
{ count: selectedRowKeys.length },
)}
</span> </span>
)} )}
</div> </div>
@ -408,6 +439,7 @@ const UnreadQuestionManage: React.FC = () => {
open={answerModalVisible} open={answerModalVisible}
onCancel={() => setAnswerModalVisible(false)} onCancel={() => setAnswerModalVisible(false)}
question={currentQuestion} question={currentQuestion}
typeList={typeList}
mode="answer" mode="answer"
onSuccess={() => fetchQuestionList(pagination.current, pagination.pageSize, searchParams)} onSuccess={() => fetchQuestionList(pagination.current, pagination.pageSize, searchParams)}
/> />

6
src/uiconfig.ts Normal file
View File

@ -0,0 +1,6 @@
// 配置ui
export default {
Modal: {
width: 1000
}
}