feat(componentAudit): 实现组件审核功能和历史记录查看

master
钟良源 3 weeks ago
parent c85e1528d4
commit 61ee43ae04

@ -1,5 +1,11 @@
import axios from 'axios'; import axios from 'axios';
import { ComponentMarketParams, PublishComponentParams, ReviewGroup } from '@/api/interface'; import {
ComponentHistoryReview,
ComponentMarketParams,
ComponentReviewNew,
PublishComponentParams,
ReviewGroup
} from '@/api/interface';
// 公共路径 // 公共路径
const urlPrefix = '/api/v1/bpms-workbench'; const urlPrefix = '/api/v1/bpms-workbench';
@ -9,6 +15,16 @@ export function getReviewGroupByNew(params: ReviewGroup) {
return axios.get(`${urlPrefix}/componentMarket/reviewGroupByNew`, { params }); return axios.get(`${urlPrefix}/componentMarket/reviewGroupByNew`, { params });
} }
// 获取组件历史审核记录
export function getComponentHistoryReview(params: ComponentHistoryReview) {
return axios.get(`${urlPrefix}/componentMarket/reviewGroupVersion`, { params });
}
// 管理员审核接口
export function reviewComponentMarket(params: ComponentReviewNew) {
return axios.post(`${urlPrefix}/componentMarket/compoentReviewNew`, params);
}
// 复制组件设计 // 复制组件设计
export function copyDesignMarket(params) { export function copyDesignMarket(params) {
return axios.post(`${urlPrefix}/componentMarket/copyDesign`, params); return axios.post(`${urlPrefix}/componentMarket/copyDesign`, params);

@ -38,9 +38,9 @@ export interface queryParams {
} }
export interface historyPageParams { export interface historyPageParams {
"pageSize": number, 'pageSize': number,
"currPage": number, 'currPage': number,
"appId": string 'appId': string
} }
export interface apiResData { export interface apiResData {
@ -271,6 +271,20 @@ export interface ReviewGroup {
size?: number; size?: number;
} }
export interface ComponentHistoryReview {
identifier: string;
componentVersion: number;
size?: number;
current?: number;
}
export interface ComponentReviewNew {
id: number;
reason: string;
reviewResult: number;
stars: number;
}
export interface ComponentMarketParams { export interface ComponentMarketParams {
componentClassify: string; componentClassify: string;
keyword: string; keyword: string;

@ -1,7 +1,20 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Pagination, Table, Tag, Button, Space, Message, Rate } from '@arco-design/web-react'; import {
Pagination,
Table,
Tag,
Button,
Space,
Message,
Rate,
Modal,
Select,
Radio,
Input,
Form
} from '@arco-design/web-react';
import styles from '@/pages/componentDevelopment/componentList/style/index.module.less'; import styles from '@/pages/componentDevelopment/componentList/style/index.module.less';
import { getReviewGroupByNew } from '@/api/componentMarket'; import { getReviewGroupByNew, getComponentHistoryReview, reviewComponentMarket } from '@/api/componentMarket';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
// 审核记录接口定义 // 审核记录接口定义
@ -23,12 +36,26 @@ interface ReviewRecord {
updateTime: string; updateTime: string;
} }
// 历史审核记录接口定义
interface HistoryAuditRecord {
reviewOpinion: string;
reviewUserName: string;
createTime: string;
publicStatus: number;
}
interface HistoryRecord {
main: ReviewRecord;
historyAudit: HistoryAuditRecord[];
}
// 发布状态映射 // 发布状态映射
const PUBLIC_STATUS_MAP = { const PUBLIC_STATUS_MAP = {
0: { text: '待审核', color: 'orange' }, '-1': { text: '未发布', color: 'orange' },
1: { text: '审核通过', color: 'green' }, 0: { text: '未发布', color: 'orange' },
2: { text: '审核拒绝', color: 'red' }, 1: { text: '已发布', color: 'green' },
3: { text: '已发布', color: 'arcoblue' } 2: { text: '审核中', color: 'arcoblue' },
3: { text: '审核被拒', color: 'red' }
}; };
const CompAudit = () => { const CompAudit = () => {
@ -41,6 +68,115 @@ const CompAudit = () => {
currPage: 1 currPage: 1
}); });
// 历史记录弹窗状态
const [historyModalVisible, setHistoryModalVisible] = useState(false);
const [historyLoading, setHistoryLoading] = useState(false);
const [historyData, setHistoryData] = useState<HistoryRecord[]>([]);
const [currentRecord, setCurrentRecord] = useState<ReviewRecord | null>(null);
// 审核弹窗状态
const [reviewModalVisible, setReviewModalVisible] = useState(false);
const [reviewLoading, setReviewLoading] = useState(false);
const [form] = Form.useForm();
const RadioGroup = Radio.Group;
const TextArea = Input.TextArea;
// 历史记录表格列定义
const historyColumns = [
{
title: '组件名称',
dataIndex: 'name',
width: 150,
render: (_, record: HistoryRecord) => record.main.name
},
{
title: '分类',
dataIndex: 'componentClassify',
width: 120,
render: (_, record: HistoryRecord) => record.main.componentClassify
},
{
title: '组件标识',
dataIndex: 'identifier',
width: 180,
render: (_, record: HistoryRecord) => record.main.identifier
},
{
title: '组件版本',
dataIndex: 'componentVersion',
width: 100,
render: (_, record: HistoryRecord) => `v${record.main.componentVersion}`
},
{
title: '发布状态',
dataIndex: 'publicStatus',
width: 120,
render: (_, record: HistoryRecord) => {
const statusInfo = PUBLIC_STATUS_MAP[record.main.publicStatus] || { text: '未知', color: 'gray' };
return <Tag color={statusInfo.color}>{statusInfo.text}</Tag>;
}
},
{
title: '组件评分',
dataIndex: 'stars',
width: 200,
render: (_, record: HistoryRecord) => {
if (record.main.stars < 0) return <span style={{ color: '#999' }}></span>;
return <Rate disabled allowHalf value={record.main.stars} />;
}
},
{
title: '组件介绍',
dataIndex: 'recommend',
width: 100,
render: (_, record: HistoryRecord) => record.main.recommend
},
{
title: '审核人',
dataIndex: 'reviewUserName',
width: 120,
render: (_, record: HistoryRecord) => record.main.reviewUserName
},
{
title: '审核结果',
dataIndex: 'reviewOpinion',
render: (_, record: HistoryRecord) => record.main.reviewOpinion || '-'
},
{
title: '组件附件',
dataIndex: 'attachmentAddress',
width: 120,
render: (_, record: HistoryRecord) => {
if (!record.main.attachmentAddress) return '-';
return (
<Button
type="text"
size="small"
onClick={() => handleDownloadAttachments(record.main.attachmentAddress)}
>
</Button>
);
}
}
// {
// title: '操作',
// dataIndex: 'operations',
// width: 100,
// fixed: 'right' as const,
// render: (_, record: HistoryRecord) => (
// <Button
// type="text"
// size="small"
// onClick={() => handleViewHistoryDetail(record)}
// >
// 查看
// </Button>
// )
// }
];
const columns = [ const columns = [
{ {
title: '组件名称', title: '组件名称',
@ -75,21 +211,16 @@ const CompAudit = () => {
{ {
title: '组件评分', title: '组件评分',
dataIndex: 'stars', dataIndex: 'stars',
width: 150, width: 200,
render: (stars: number) => { render: (stars: number) => {
if (stars < 0) return <span style={{ color: '#999' }}></span>; if (stars < 0) return <span style={{ color: '#999' }}></span>;
return <Rate disabled value={stars} />; return <Rate disabled allowHalf value={stars} />;
} }
}, },
{ {
title: '推荐度', title: '组件介绍',
dataIndex: 'recommend', dataIndex: 'recommend',
width: 100, width: 100
render: (recommend: string) => {
const level = parseInt(recommend);
const colors = ['red', 'orange', 'blue', 'green', 'arcoblue'];
return <Tag color={colors[level - 1] || 'gray'}> {recommend}</Tag>;
}
}, },
{ {
title: '审核人', title: '审核人',
@ -97,17 +228,11 @@ const CompAudit = () => {
width: 120 width: 120
}, },
{ {
title: '审核意见', title: '审核结果',
dataIndex: 'reviewOpinion', dataIndex: 'reviewOpinion',
width: 200, // width: 200,
render: (opinion: string) => opinion || '-' render: (opinion: string) => opinion || '-'
}, },
{
title: '创建时间',
dataIndex: 'createTime',
width: 180,
render: (time: string) => dayjs(time).format('YYYY-MM-DD HH:mm:ss')
},
{ {
title: '操作', title: '操作',
dataIndex: 'operations', dataIndex: 'operations',
@ -118,37 +243,17 @@ const CompAudit = () => {
<Button <Button
type="text" type="text"
size="small" size="small"
onClick={() => handleViewDetail(record)} onClick={() => handleGetHistory(record)}
> >
</Button> </Button>
{record.publicStatus === 0 && ( {record.publicStatus === 2 && (
<>
<Button
type="text"
size="small"
status="success"
onClick={() => handleApprove(record)}
>
</Button>
<Button
type="text"
size="small"
status="danger"
onClick={() => handleReject(record)}
>
</Button>
</>
)}
{record.attachmentAddress && (
<Button <Button
type="text" type="text"
size="small" size="small"
onClick={() => handleDownloadAttachment(record)} onClick={() => handleViewReview(record)}
> >
</Button> </Button>
)} )}
</Space> </Space>
@ -166,10 +271,8 @@ const CompAudit = () => {
size: pagination.pageSize size: pagination.pageSize
}); });
console.log('组件审核列表:', res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
setData(res.data.records || []); setData(res.data.list || []);
setPagination({ setPagination({
totalCount: res.data.total || 0, totalCount: res.data.total || 0,
pageSize: res.data.size || 10, pageSize: res.data.size || 10,
@ -188,31 +291,177 @@ const CompAudit = () => {
} }
}; };
// 查看详情 // 下载组件附件
const handleViewDetail = (record: ReviewRecord) => { const handleDownloadAttachments = (attachmentAddress: string) => {
// TODO: 实现查看详情逻辑 if (!attachmentAddress) {
console.log('查看详情:', record); Message.warning('暂无附件');
Message.info('查看详情功能待实现'); return;
}
// 按逗号分割多个文件地址
const fileUrls = attachmentAddress.split(',').map(url => url.trim()).filter(url => url);
if (fileUrls.length === 0) {
Message.warning('暂无附件');
return;
}
// 下载所有文件
fileUrls.forEach((url, index) => {
// 延迟下载,避免浏览器阻止多个下载
setTimeout(() => {
// 使用 fetch 下载文件
fetch(url)
.then(response => response.blob())
.then(blob => {
const blobUrl = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = blobUrl;
link.download = url.split('/').pop() || `attachment-${index + 1}`;
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// 释放 blob URL
window.URL.revokeObjectURL(blobUrl);
})
.catch(error => {
console.error('下载失败:', error);
// 如果 fetch 失败,尝试直接打开链接
window.open(url, '_blank');
});
}, index * 500); // 每个文件间隔500ms
});
Message.success(`开始下载 ${fileUrls.length} 个文件`);
}; };
// 审核通过 // 组件审核
const handleApprove = (record: ReviewRecord) => { const handleViewReview = (record: ReviewRecord) => {
// TODO: 实现审核通过逻辑 setCurrentRecord(record);
console.log('审核通过:', record); setReviewModalVisible(true);
Message.success('审核通过操作待实现'); // 初始化表单
form.setFieldsValue({
reviewResult: 1, // 默认通过
stars: 0,
reason: ''
});
};
// 提交审核
const handleSubmitReview = async () => {
try {
const values = await form.validate();
if (!currentRecord) {
Message.error('当前记录不存在');
return;
}
setReviewLoading(true);
const params = {
id: Number(currentRecord.id),
reviewResult: values.reviewResult,
stars: values.stars,
reason: values.reason || ''
};
const res: any = await reviewComponentMarket(params);
if (res.code === 200) {
Message.success('审核成功');
setReviewModalVisible(false);
form.resetFields();
// 刷新列表
fetchComponentReview();
}
else {
Message.error(res.msg || '审核失败');
}
} catch (error) {
console.error('审核失败:', error);
if (error?.errors) {
// 表单验证失败
return;
}
Message.error('审核失败');
} finally {
setReviewLoading(false);
}
}; };
// 审核拒绝
const handleReject = (record: ReviewRecord) => { // 查看审核历史
// TODO: 实现审核拒绝逻辑 const handleGetHistory = async (record: ReviewRecord) => {
console.log('审核拒绝:', record); setCurrentRecord(record);
Message.warning('审核拒绝操作待实现'); setHistoryModalVisible(true);
setHistoryLoading(true);
try {
const res: any = await getComponentHistoryReview({
identifier: record.identifier,
componentVersion: record.componentVersion
});
if (res.code === 200 && res.data) {
setHistoryData(res.data.list || []);
}
else {
Message.error(res.msg || '获取审核历史失败');
}
} catch (error) {
console.error('获取审核历史失败:', error);
Message.error('获取审核历史失败');
} finally {
setHistoryLoading(false);
}
}; };
// 下载附件 // 查看历史记录详情
const handleDownloadAttachment = (record: ReviewRecord) => { const handleViewHistoryDetail = (record: HistoryRecord) => {
if (record.attachmentAddress) { // 展开显示历史审核记录
window.open(record.attachmentAddress, '_blank'); if (record.historyAudit && record.historyAudit.length > 0) {
Modal.info({
title: '历史审核记录',
style: { width: 800 },
content: (
<div>
<Table
columns={[
{
title: '审核时间',
dataIndex: 'createTime',
render: (time: string) => dayjs(time).format('YYYY-MM-DD HH:mm:ss')
},
{
title: '审核人',
dataIndex: 'reviewUserName'
},
{
title: '审核状态',
dataIndex: 'publicStatus',
render: (status: number) => {
const statusInfo = PUBLIC_STATUS_MAP[status] || { text: '未知', color: 'gray' };
return <Tag color={statusInfo.color}>{statusInfo.text}</Tag>;
}
},
{
title: '审核意见',
dataIndex: 'reviewOpinion',
render: (opinion: string) => opinion || '-'
}
]}
data={record.historyAudit}
pagination={false}
border
/>
</div>
)
});
}
else {
Message.info('暂无历史审核记录');
} }
}; };
@ -255,6 +504,94 @@ const CompAudit = () => {
sizeCanChange sizeCanChange
/> />
</div> </div>
{/* 审核历史弹窗 */}
<Modal
title={`审核历史 - ${currentRecord?.name || ''}`}
visible={historyModalVisible}
onCancel={() => setHistoryModalVisible(false)}
footer={null}
style={{ width: '90%', maxWidth: 1400, minWidth: 800 }}
>
<div style={{ minHeight: 700 }}>
<Table
columns={historyColumns}
data={historyData}
loading={historyLoading}
pagination={false}
scroll={{ x: 1800, y: 500 }}
border={{
wrapper: true,
cell: true
}}
/>
</div>
</Modal>
{/* 组件审核弹窗 */}
<Modal
title="组件审核"
visible={reviewModalVisible}
onCancel={() => {
setReviewModalVisible(false);
form.resetFields();
}}
onOk={handleSubmitReview}
confirmLoading={reviewLoading}
okText="确定"
cancelText="取消"
>
<Form
form={form}
layout="vertical"
autoComplete="off"
>
<Form.Item label="组件附件">
{currentRecord?.attachmentAddress ? (
<Button
type="primary"
size="small"
onClick={() => handleDownloadAttachments(currentRecord.attachmentAddress)}
>
</Button>
) : (
<span style={{ color: '#999' }}></span>
)}
</Form.Item>
<Form.Item
label="组件评分"
field="stars"
rules={[{ required: true, message: '请选择评分' }]}
>
<Rate allowHalf />
</Form.Item>
<Form.Item
label="审核状态"
field="reviewResult"
rules={[{ required: true, message: '请选择审核状态' }]}
>
<RadioGroup>
<Radio value={1}></Radio>
<Radio value={0}></Radio>
</RadioGroup>
</Form.Item>
<Form.Item
label="驳回原因"
field="reason"
>
<TextArea
placeholder="请输入驳回原因"
rows={4}
maxLength={500}
showWordLimit
/>
</Form.Item>
</Form>
</Modal>
</> </>
); );
}; };

Loading…
Cancel
Save