feat: 1. 添加企查查的按钮。新增相关组件和对接接口进行显示。
2. 为51707端口添加只存在交叉评查入口的项目启动配置。入口页添加相关的区分。 3. 完善文档列表的权限功能控制。 4. 隐藏系统概览中高风险用户的统计模块。 fix: 1. 修复合同起草无权访问却生成了新的模板文件的问题。 2. 修复文档类型无法编辑入口模块的问题。
This commit is contained in:
+130
-72
@@ -5,7 +5,7 @@ import styles from "~/styles/pages/home.css?url";
|
||||
import dayjs from 'dayjs';
|
||||
import { getUserSession, logout } from "~/api/login/auth.server";
|
||||
import { toastService } from '~/components/ui';
|
||||
import { DOCUMENT_URL } from '~/config/api-config';
|
||||
import { DOCUMENT_URL, CROSS_CHECKING_ONLY_MODE, CROSS_CHECKING_ONLY_PORT, getCurrentPort } from '~/config/api-config';
|
||||
|
||||
export const links = () => [
|
||||
{ rel: "stylesheet", href: styles }
|
||||
@@ -87,8 +87,26 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
}
|
||||
}
|
||||
|
||||
// 🔑 判断是否启用交叉评查专属模式
|
||||
// 条件:CROSS_CHECKING_ONLY_MODE=true 且 当前端口为 51707
|
||||
const currentPort = getCurrentPort();
|
||||
const isCrossCheckingOnlyMode = CROSS_CHECKING_ONLY_MODE && currentPort === CROSS_CHECKING_ONLY_PORT;
|
||||
|
||||
if (isCrossCheckingOnlyMode) {
|
||||
console.log(`🔒 [Index Loader] 交叉评查专属模式已启用 (端口: ${currentPort})`);
|
||||
}
|
||||
|
||||
// 返回用户信息、入口模块和权限给客户端
|
||||
return Response.json({ userRole, userInfo, entryModules, hasSettingsAccess, hasCrossCheckingAccess, hasChatLLMAccess, settingsChildren });
|
||||
return Response.json({
|
||||
userRole,
|
||||
userInfo,
|
||||
entryModules,
|
||||
hasSettingsAccess,
|
||||
hasCrossCheckingAccess,
|
||||
hasChatLLMAccess,
|
||||
settingsChildren,
|
||||
isCrossCheckingOnlyMode // 新增:交叉评查专属模式标志
|
||||
});
|
||||
}
|
||||
|
||||
export default function Index() {
|
||||
@@ -326,8 +344,8 @@ export default function Index() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="user-info">
|
||||
{/* 系统设置按钮 - 只在有权限时显示 */}
|
||||
{loaderData.hasSettingsAccess && (
|
||||
{/* 系统设置按钮 - 只在有权限且非交叉评查专属模式时显示 */}
|
||||
{loaderData.hasSettingsAccess && !loaderData.isCrossCheckingOnlyMode && (
|
||||
<button
|
||||
onClick={handleEnterSettings}
|
||||
className="settings-button"
|
||||
@@ -369,79 +387,119 @@ export default function Index() {
|
||||
|
||||
{/* 模块网格区域 */}
|
||||
<div className="modules-container">
|
||||
{/* 动态渲染入口模块 */}
|
||||
{loaderData.entryModules && loaderData.entryModules.length > 0 ? (
|
||||
<>
|
||||
{loaderData.entryModules.map((module) => {
|
||||
// 判断是否为智慧法务助手,如果是且有交叉评查权限,则在其之前插入交叉评查卡片
|
||||
const isLLMModule = module.name === '智慧法务助手';
|
||||
{/* 🔒 交叉评查专属模式:只显示交叉评查入口 */}
|
||||
{loaderData.isCrossCheckingOnlyMode ? (
|
||||
loaderData.hasCrossCheckingAccess ? (
|
||||
<div
|
||||
className="module-card"
|
||||
onClick={handleEnterCrossChecking}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
handleEnterCrossChecking();
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="交叉评查"
|
||||
>
|
||||
<img
|
||||
src="/images/icon_cross@2x.png"
|
||||
alt="交叉评查"
|
||||
className="w-12 h-12 mx-1"
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).style.display = 'none';
|
||||
const parent = (e.target as HTMLImageElement).parentElement;
|
||||
if (parent) {
|
||||
const icon = document.createElement('i');
|
||||
icon.className = 'ri-shuffle-line';
|
||||
icon.style.fontSize = '48px';
|
||||
icon.style.color = 'var(--color-primary)';
|
||||
parent.insertBefore(icon, parent.firstChild);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<span className="module-name">交叉评查</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center text-gray-500 py-8">
|
||||
暂无可用模块
|
||||
</div>
|
||||
)
|
||||
) : (
|
||||
/* 正常模式:显示所有入口模块 */
|
||||
loaderData.entryModules && loaderData.entryModules.length > 0 ? (
|
||||
<>
|
||||
{loaderData.entryModules.map((module) => {
|
||||
// 判断是否为智慧法务助手,如果是且有交叉评查权限,则在其之前插入交叉评查卡片
|
||||
const isLLMModule = module.name === '智慧法务助手';
|
||||
|
||||
// 🔑 如果是智慧法务助手且用户没有访问权限,则不渲染该模块
|
||||
if (isLLMModule && !loaderData.hasChatLLMAccess) {
|
||||
return null;
|
||||
}
|
||||
// 🔑 如果是智慧法务助手且用户没有访问权限,则不渲染该模块
|
||||
if (isLLMModule && !loaderData.hasChatLLMAccess) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment key={module.id}>
|
||||
{/* 在智慧法务助手之前插入交叉评查入口 */}
|
||||
{isLLMModule && loaderData.hasCrossCheckingAccess && (
|
||||
<div
|
||||
className="module-card"
|
||||
onClick={handleEnterCrossChecking}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
handleEnterCrossChecking();
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="交叉评查"
|
||||
>
|
||||
<img
|
||||
src="/images/icon_cross@2x.png"
|
||||
alt="交叉评查"
|
||||
className="w-12 h-12 mx-1"
|
||||
onError={(e) => {
|
||||
// 如果图片加载失败,使用 icon
|
||||
(e.target as HTMLImageElement).style.display = 'none';
|
||||
const parent = (e.target as HTMLImageElement).parentElement;
|
||||
if (parent) {
|
||||
const icon = document.createElement('i');
|
||||
icon.className = 'ri-shuffle-line';
|
||||
icon.style.fontSize = '48px';
|
||||
icon.style.color = 'var(--color-primary)';
|
||||
parent.insertBefore(icon, parent.firstChild);
|
||||
return (
|
||||
<React.Fragment key={module.id}>
|
||||
{/* 在智慧法务助手之前插入交叉评查入口 */}
|
||||
{isLLMModule && loaderData.hasCrossCheckingAccess && (
|
||||
<div
|
||||
className="module-card"
|
||||
onClick={handleEnterCrossChecking}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
handleEnterCrossChecking();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<span className="module-name">交叉评查</span>
|
||||
</div>
|
||||
)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="交叉评查"
|
||||
>
|
||||
<img
|
||||
src="/images/icon_cross@2x.png"
|
||||
alt="交叉评查"
|
||||
className="w-12 h-12 mx-1"
|
||||
onError={(e) => {
|
||||
// 如果图片加载失败,使用 icon
|
||||
(e.target as HTMLImageElement).style.display = 'none';
|
||||
const parent = (e.target as HTMLImageElement).parentElement;
|
||||
if (parent) {
|
||||
const icon = document.createElement('i');
|
||||
icon.className = 'ri-shuffle-line';
|
||||
icon.style.fontSize = '48px';
|
||||
icon.style.color = 'var(--color-primary)';
|
||||
parent.insertBefore(icon, parent.firstChild);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<span className="module-name">交叉评查</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 渲染原有模块 */}
|
||||
<div
|
||||
className="module-card"
|
||||
onClick={() => handleModuleClick(module)}
|
||||
onKeyDown={(e) => handleKeyDown(module, e)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={module.name}
|
||||
>
|
||||
<img
|
||||
src={isLLMModule ? '/images/icon_assistant.png' : getModuleIcon(module)}
|
||||
alt={module.name}
|
||||
className="w-12 h-12 mx-1"
|
||||
/>
|
||||
<span className="module-name">{module.name}</span>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
) : (
|
||||
<div className="text-center text-gray-500 py-8">
|
||||
暂无可用模块
|
||||
</div>
|
||||
{/* 渲染原有模块 */}
|
||||
<div
|
||||
className="module-card"
|
||||
onClick={() => handleModuleClick(module)}
|
||||
onKeyDown={(e) => handleKeyDown(module, e)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={module.name}
|
||||
>
|
||||
<img
|
||||
src={isLLMModule ? '/images/icon_assistant.png' : getModuleIcon(module)}
|
||||
alt={module.name}
|
||||
className="w-12 h-12 mx-1"
|
||||
/>
|
||||
<span className="module-name">{module.name}</span>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
) : (
|
||||
<div className="text-center text-gray-500 py-8">
|
||||
暂无可用模块
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { MetaFunction, LoaderFunctionArgs, ActionFunctionArgs } from '@remix-run/node';
|
||||
import { redirect } from '@remix-run/node';
|
||||
import { useLoaderData, useNavigate, useSubmit } from '@remix-run/react';
|
||||
import { useLoaderData, useNavigate, useSubmit, useActionData } from '@remix-run/react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { getContractTemplate } from '~/api/contract-template/templates';
|
||||
import type { ContractTemplate } from '~/api/contract-template/templates';
|
||||
@@ -9,6 +9,7 @@ import filePreviewStyles from '~/styles/components/file-preview-isolation.css?ur
|
||||
import { getUserSession } from '~/api/login/auth.server';
|
||||
import { createDraftContract } from '~/api/contracts/draft-service.server';
|
||||
import { apiRequest, downloadFile } from '~/api/axios-client';
|
||||
import { checkRoutePermission } from '~/api/auth/check-route-permission.server';
|
||||
|
||||
// 导入FilePreview组件
|
||||
import { FilePreview } from '~/components/reviews';
|
||||
@@ -76,11 +77,20 @@ export async function action({ request, params }: ActionFunctionArgs) {
|
||||
}
|
||||
|
||||
// 获取用户信息和JWT
|
||||
const { userInfo, frontendJWT } = await getUserSession(request);
|
||||
const { userInfo, frontendJWT, userRole } = await getUserSession(request);
|
||||
if (!userInfo?.sub) {
|
||||
return Response.json({ error: '未登录' }, { status: 401 });
|
||||
}
|
||||
|
||||
// 🔒 在执行任何操作之前,先检查用户是否有权限访问目标路由
|
||||
const targetPath = '/contract-draft';
|
||||
const permissionCheck = await checkRoutePermission(targetPath, userRole, frontendJWT || undefined);
|
||||
|
||||
if (!permissionCheck.allowed) {
|
||||
console.warn(`[Action] 用户无权访问 ${targetPath}:`, permissionCheck.error);
|
||||
return Response.json({ error: permissionCheck.error || '您没有权限使用起草合同功能' }, { status: 403 });
|
||||
}
|
||||
|
||||
try {
|
||||
// 解析表单数据
|
||||
const formData = await request.formData();
|
||||
@@ -148,8 +158,14 @@ export async function action({ request, params }: ActionFunctionArgs) {
|
||||
}
|
||||
}
|
||||
|
||||
// Action 返回的数据类型
|
||||
interface ActionData {
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export default function ContractTemplateDetail() {
|
||||
const { template }: { template: ContractTemplate } = useLoaderData<typeof loader>();
|
||||
const actionData = useActionData<ActionData>();
|
||||
const navigate = useNavigate();
|
||||
const submit = useSubmit();
|
||||
const [isCreatingDraft, setIsCreatingDraft] = useState(false);
|
||||
@@ -162,6 +178,14 @@ export default function ContractTemplateDetail() {
|
||||
window.scrollTo({ top: 0, behavior: 'instant' });
|
||||
}, []);
|
||||
|
||||
// 处理 action 返回的错误
|
||||
useEffect(() => {
|
||||
if (actionData?.error) {
|
||||
toastService.error(actionData.error);
|
||||
setIsCreatingDraft(false);
|
||||
}
|
||||
}, [actionData]);
|
||||
|
||||
const handleBack = () => {
|
||||
navigate('/contract-template/list');
|
||||
};
|
||||
|
||||
@@ -196,7 +196,7 @@ export async function action({ request }: ActionFunctionArgs) {
|
||||
}, { status: 500 });
|
||||
}
|
||||
|
||||
console.log('用户任务详情返回:', response.data);
|
||||
// console.log('用户任务详情返回:', response.data);
|
||||
return Response.json({
|
||||
success: true,
|
||||
data: response.data
|
||||
|
||||
@@ -163,6 +163,7 @@ export default function DocumentTypesList() {
|
||||
const canCreateType = canCreate('document_type');
|
||||
const canUpdateType = canUpdate('document_type');
|
||||
const canDeleteType = canDelete('document_type');
|
||||
// console.log('document_type---canDeleteType',canDeleteType)
|
||||
const canViewType = canView('document_type');
|
||||
|
||||
// 获取搜索参数
|
||||
@@ -299,7 +300,7 @@ export default function DocumentTypesList() {
|
||||
{
|
||||
title: "文档类型名称",
|
||||
key: "name",
|
||||
width: "200px",
|
||||
width: "220px",
|
||||
render: (_: unknown, record: DocumentTypeUI) => (
|
||||
<div className="flex items-center">
|
||||
<i className="ri-file-text-line text-primary mr-2"></i>
|
||||
@@ -310,10 +311,10 @@ export default function DocumentTypesList() {
|
||||
{
|
||||
title: "描述",
|
||||
key: "description",
|
||||
width: "250px",
|
||||
width: "260px",
|
||||
render: (_: unknown, record: DocumentTypeUI) => (
|
||||
<div className="text-secondary text-sm truncate max-w-xs" title={record.description}>
|
||||
{record.description}
|
||||
<div className="text-secondary text-sm truncate max-w-[300px]" title={record.description}>
|
||||
{record.description || '-'}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
@@ -326,7 +327,7 @@ export default function DocumentTypesList() {
|
||||
{record.entry_module ? (
|
||||
<span className="entry-module-badge">{record.entry_module.name}</span>
|
||||
) : (
|
||||
<span className="text-gray-400">暂无关联入口</span>
|
||||
<span className="text-gray-400">-</span>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
@@ -343,7 +344,7 @@ export default function DocumentTypesList() {
|
||||
</span>
|
||||
))
|
||||
) : (
|
||||
<span className="text-gray-400">暂无关联分组</span>
|
||||
<span className="text-gray-400">-</span>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
@@ -351,19 +352,19 @@ export default function DocumentTypesList() {
|
||||
{
|
||||
title: "创建时间",
|
||||
key: "created_at",
|
||||
width: "150px",
|
||||
render: (_: unknown, record: DocumentTypeUI) => record.created_at
|
||||
width: "160px",
|
||||
render: (_: unknown, record: DocumentTypeUI) => record.created_at || '-'
|
||||
},
|
||||
{
|
||||
title: "更新时间",
|
||||
key: "updated_at",
|
||||
width: "150px",
|
||||
render: (_: unknown, record: DocumentTypeUI) => record.updated_at
|
||||
width: "160px",
|
||||
render: (_: unknown, record: DocumentTypeUI) => record.updated_at || '-'
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
key: "operation",
|
||||
width: "150px",
|
||||
width: "160px",
|
||||
render: (_: unknown, record: DocumentTypeUI) => (
|
||||
<div className="operations-cell">
|
||||
{canViewType && (
|
||||
@@ -379,7 +380,7 @@ export default function DocumentTypesList() {
|
||||
)}
|
||||
{canDeleteType && (
|
||||
<button
|
||||
className="operation-btn text-error !hidden"
|
||||
className="operation-btn text-error"
|
||||
onClick={() => handleDelete(record.id)}
|
||||
disabled={isDeleting}
|
||||
>
|
||||
|
||||
@@ -477,6 +477,8 @@ export default function DocumentTypeNew() {
|
||||
} else if (name === 'vlm_extraction_template') {
|
||||
fieldName = 'vlmExtractionTemplateId';
|
||||
setTouchedFields(prev => ({...prev, vlmExtractionTemplate: true}));
|
||||
} else if (name === 'entry_module_id') {
|
||||
fieldName = 'entryModuleId';
|
||||
} else if (name === 'name') {
|
||||
setTouchedFields(prev => ({...prev, name: true}));
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useLoaderData, useActionData, useNavigate, Form } from "@remix-run/reac
|
||||
import { redirect, type ActionFunctionArgs, type LoaderFunctionArgs, type MetaFunction } from "@remix-run/node";
|
||||
import { Card } from "~/components/ui/Card";
|
||||
import { Button } from "~/components/ui/Button";
|
||||
import { usePermission } from "~/hooks/usePermission";
|
||||
import documentEditStyles from "~/styles/pages/documents_edit.css?url";
|
||||
import { getDocument, updateDocument } from "~/api/files/documents";
|
||||
import { getDocumentTypes } from "~/api/document-types/document-types";
|
||||
@@ -208,6 +209,10 @@ export default function DocumentEdit() {
|
||||
const [numPages, setNumPages] = useState(0);
|
||||
const [loadError, setLoadError] = useState<string | null>(null);
|
||||
const formRef = useRef<HTMLFormElement>(null);
|
||||
|
||||
// 权限控制
|
||||
const { hasPermission } = usePermission();
|
||||
const canUpdate = hasPermission('document:document:update');
|
||||
|
||||
// 表单状态管理 - 使用受控组件
|
||||
const [formValues, setFormValues] = useState({
|
||||
@@ -476,13 +481,16 @@ export default function DocumentEdit() {
|
||||
>
|
||||
返回列表
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
icon="ri-save-line"
|
||||
form="edit-form"
|
||||
>
|
||||
保存修改
|
||||
</Button>
|
||||
{/* 保存修改按钮 - 需要 document:document:update 权限 */}
|
||||
{canUpdate && (
|
||||
<Button
|
||||
type="primary"
|
||||
icon="ri-save-line"
|
||||
form="edit-form"
|
||||
>
|
||||
保存修改
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
+117
-83
@@ -3,6 +3,7 @@ import { useSearchParams, useLoaderData, useFetcher, useNavigate,Link } from "@r
|
||||
import { type MetaFunction, type ActionFunctionArgs, type LoaderFunctionArgs } from "@remix-run/node";
|
||||
import { Card } from "~/components/ui/Card";
|
||||
import { Button } from "~/components/ui/Button";
|
||||
import { usePermission, PermissionGuard } from "~/hooks/usePermission";
|
||||
// import { Table } from "~/components/ui/Table";
|
||||
import { Pagination } from "~/components/ui/Pagination";
|
||||
import { FileTypeTag } from "~/components/ui/FileTypeTag";
|
||||
@@ -184,6 +185,11 @@ export default function DocumentsIndex() {
|
||||
const fetcher = useFetcher<ActionResponse>();
|
||||
const navigate = useNavigate();
|
||||
|
||||
// 权限控制
|
||||
const { hasPermission } = usePermission();
|
||||
const canView = hasPermission('document:document:view');
|
||||
const canUpdate = hasPermission('document:document:update');
|
||||
|
||||
// 存储从 sessionStorage 获取的 documentTypeIds
|
||||
const [documentTypeIds, setDocumentTypeIds] = useState<number[] | null>(null);
|
||||
|
||||
@@ -1172,29 +1178,39 @@ export default function DocumentsIndex() {
|
||||
<td className="text-xs text-gray-600 px-4 py-3" style={{ width: '10%' }}>{historyDoc.uploadTime}</td>
|
||||
<td className="px-4 py-3" style={{ width: '25%' }}>
|
||||
<div className="operations-cell flex flex-wrap gap-1">
|
||||
<Link
|
||||
to={`/reviews?id=${historyDoc.id}&previousRoute=documents`}
|
||||
className="text-xs px-2 py-1 h-7 mr-1 hover:underline"
|
||||
>
|
||||
<i className="ri-eye-line"></i>
|
||||
查看
|
||||
</Link>
|
||||
<Link
|
||||
to={`/documents/edit?id=${historyDoc.id}`}
|
||||
className="text-xs px-2 py-1 h-7 mr-1 text-gray-500 hover:underline hover:text-gray-700"
|
||||
>
|
||||
<i className="ri-edit-line"></i>
|
||||
修改
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
className="text-xs px-2 py-1 h-7 mr-1 text-gray-500 hover:underline hover:text-gray-700"
|
||||
onClick={() => handleDownload(historyDoc.path)}
|
||||
>
|
||||
<i className="ri-download-line"></i>
|
||||
下载
|
||||
</button>
|
||||
{parentDoc.type === '1' && historyDoc.fileStatus === 'Processed' && (
|
||||
{/* 查看按钮 - 需要 document:document:view 权限 */}
|
||||
{canView && (
|
||||
<Link
|
||||
to={`/reviews?id=${historyDoc.id}&previousRoute=documents`}
|
||||
className="text-xs px-2 py-1 h-7 mr-1 hover:underline"
|
||||
>
|
||||
<i className="ri-eye-line"></i>
|
||||
查看
|
||||
</Link>
|
||||
)}
|
||||
{/* 修改按钮 - 需要 document:document:view 权限 */}
|
||||
{canView && (
|
||||
<Link
|
||||
to={`/documents/edit?id=${historyDoc.id}`}
|
||||
className="text-xs px-2 py-1 h-7 mr-1 text-gray-500 hover:underline hover:text-gray-700"
|
||||
>
|
||||
<i className="ri-edit-line"></i>
|
||||
修改
|
||||
</Link>
|
||||
)}
|
||||
{/* 下载按钮 - 需要 document:document:view 权限 */}
|
||||
{canView && (
|
||||
<button
|
||||
type="button"
|
||||
className="text-xs px-2 py-1 h-7 mr-1 text-gray-500 hover:underline hover:text-gray-700"
|
||||
onClick={() => handleDownload(historyDoc.path)}
|
||||
>
|
||||
<i className="ri-download-line"></i>
|
||||
下载
|
||||
</button>
|
||||
)}
|
||||
{/* 追加附件和上传模板按钮 - 需要 document:document:view 权限 */}
|
||||
{canView && parentDoc.type === '1' && historyDoc.fileStatus === 'Processed' && (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
@@ -1224,14 +1240,17 @@ export default function DocumentsIndex() {
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className="text-xs px-2 py-1 h-7 text-error hover:underline hover:text-red-700"
|
||||
onClick={() => handleDelete(historyDoc.id.toString(), historyDoc.name, historyDoc.fileStatus)}
|
||||
>
|
||||
<i className="ri-delete-bin-line"></i>
|
||||
删除
|
||||
</button>
|
||||
{/* 删除按钮 - 需要 document:document:view 权限 */}
|
||||
{canView && (
|
||||
<button
|
||||
type="button"
|
||||
className="text-xs px-2 py-1 h-7 text-error hover:underline hover:text-red-700"
|
||||
onClick={() => handleDelete(historyDoc.id.toString(), historyDoc.name, historyDoc.fileStatus)}
|
||||
>
|
||||
<i className="ri-delete-bin-line"></i>
|
||||
删除
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -1393,53 +1412,65 @@ export default function DocumentsIndex() {
|
||||
width: "25%",
|
||||
render: (_: unknown, record: DocumentUI) => (
|
||||
<div className="operations-cell flex flex-wrap gap-1">
|
||||
{(record.auditStatus === 0 || record.auditStatus == null) ? (
|
||||
<button
|
||||
onClick={() => handleReviewFileClick(record.id, record.auditStatus)}
|
||||
disabled={record.fileStatus !== 'Processed'}
|
||||
className={`text-xs px-2 py-1 h-7 mr-1 ${
|
||||
record.fileStatus === 'Processed'
|
||||
? 'hover:underline hover:cursor-pointer text-primary'
|
||||
: 'text-gray-400 cursor-not-allowed opacity-60'
|
||||
}`}
|
||||
{/* 查看/开始审核按钮 - 需要 document:document:view 权限 */}
|
||||
{canView && (
|
||||
<>
|
||||
{(record.auditStatus === 0 || record.auditStatus == null) ? (
|
||||
<button
|
||||
onClick={() => handleReviewFileClick(record.id, record.auditStatus)}
|
||||
disabled={record.fileStatus !== 'Processed'}
|
||||
className={`text-xs px-2 py-1 h-7 mr-1 ${
|
||||
record.fileStatus === 'Processed'
|
||||
? 'hover:underline hover:cursor-pointer text-primary'
|
||||
: 'text-gray-400 cursor-not-allowed opacity-60'
|
||||
}`}
|
||||
>
|
||||
<i className="ri-play-circle-line"></i>
|
||||
开始审核
|
||||
</button>
|
||||
) : record.auditStatus === 3 ? (
|
||||
//record.auditStatus === 3 目前这个状态不存在,所以除了待审核(0)-开始审核,其他都是审核中(2)-查看
|
||||
<Link
|
||||
to={`/documents/${record.id}/progress`}
|
||||
className="text-xs px-2 py-1 h-7 mr-1 hover:underline"
|
||||
>
|
||||
<i className="ri-eye-line"></i>
|
||||
查看进度
|
||||
</Link>
|
||||
) : (
|
||||
<Link
|
||||
to={`/reviews?id=${record.id}&previousRoute=documents`}
|
||||
className="text-xs px-2 py-1 h-7 mr-1 hover:underline"
|
||||
>
|
||||
<i className="ri-eye-line"></i>
|
||||
查看
|
||||
</Link>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{/* 修改按钮 - 需要 document:document:view 权限 */}
|
||||
{canView && (
|
||||
<Link
|
||||
to={`/documents/edit?id=${record.id}`}
|
||||
className="text-xs px-2 py-1 h-7 mr-1 text-gray-500 hover:underline hover:text-gray-700"
|
||||
>
|
||||
<i className="ri-play-circle-line"></i>
|
||||
开始审核
|
||||
</button>
|
||||
) : record.auditStatus === 3 ? (
|
||||
//record.auditStatus === 3 目前这个状态不存在,所以除了待审核(0)-开始审核,其他都是审核中(2)-查看
|
||||
<Link
|
||||
to={`/documents/${record.id}/progress`}
|
||||
className="text-xs px-2 py-1 h-7 mr-1 hover:underline"
|
||||
>
|
||||
<i className="ri-eye-line"></i>
|
||||
查看进度
|
||||
</Link>
|
||||
) : (
|
||||
<Link
|
||||
to={`/reviews?id=${record.id}&previousRoute=documents`}
|
||||
className="text-xs px-2 py-1 h-7 mr-1 hover:underline"
|
||||
>
|
||||
<i className="ri-eye-line"></i>
|
||||
查看
|
||||
<i className="ri-edit-line"></i>
|
||||
修改
|
||||
</Link>
|
||||
)}
|
||||
<Link
|
||||
to={`/documents/edit?id=${record.id}`}
|
||||
className="text-xs px-2 py-1 h-7 mr-1 text-gray-500 hover:underline hover:text-gray-700"
|
||||
>
|
||||
<i className="ri-edit-line"></i>
|
||||
修改
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
className="text-xs px-2 py-1 h-7 mr-1 text-gray-500 hover:underline hover:text-gray-700"
|
||||
onClick={() => handleDownload(record.path)}
|
||||
>
|
||||
<i className="ri-download-line"></i>
|
||||
下载
|
||||
</button>
|
||||
{record.type === '1' && record.fileStatus === 'Processed' && (
|
||||
{/* 下载按钮 - 需要 document:document:view 权限 */}
|
||||
{canView && (
|
||||
<button
|
||||
type="button"
|
||||
className="text-xs px-2 py-1 h-7 mr-1 text-gray-500 hover:underline hover:text-gray-700"
|
||||
onClick={() => handleDownload(record.path)}
|
||||
>
|
||||
<i className="ri-download-line"></i>
|
||||
下载
|
||||
</button>
|
||||
)}
|
||||
{/* 追加附件和上传模板按钮 - 需要 document:document:view 权限 */}
|
||||
{canView && record.type === '1' && record.fileStatus === 'Processed' && (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
@@ -1469,14 +1500,17 @@ export default function DocumentsIndex() {
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className="text-xs px-2 py-1 h-7 text-error hover:underline hover:text-red-700"
|
||||
onClick={() => handleDelete(record.id.toString(), record.name, record.fileStatus)}
|
||||
>
|
||||
<i className="ri-delete-bin-line"></i>
|
||||
删除
|
||||
</button>
|
||||
{/* 删除按钮 - 需要 document:document:view 权限 */}
|
||||
{canView && (
|
||||
<button
|
||||
type="button"
|
||||
className="text-xs px-2 py-1 h-7 text-error hover:underline hover:text-red-700"
|
||||
onClick={() => handleDelete(record.id.toString(), record.name, record.fileStatus)}
|
||||
>
|
||||
<i className="ri-delete-bin-line"></i>
|
||||
删除
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
+2
-2
@@ -448,8 +448,8 @@ export default function Home() {
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* 高风险用户 */}
|
||||
{topRiskUsers.available && (
|
||||
{/* 高风险用户 隐藏*/}
|
||||
{topRiskUsers.available && false &&(
|
||||
<Card
|
||||
title="高风险用户 Top 5"
|
||||
icon="ri-shield-user-line"
|
||||
|
||||
Reference in New Issue
Block a user