删除所有console.log输出,优化评查结果的表格的显示,添加新的页码获取逻辑
This commit is contained in:
@@ -1,3 +1,56 @@
|
||||
# 智慧法务系统 - 权限认证系统
|
||||
|
||||
## 认证系统概述
|
||||
|
||||
本系统实现了一个简单的基于角色的权限认证系统,支持以下功能:
|
||||
|
||||
1. 用户可以以不同角色登录系统:
|
||||
- `common`:普通用户,只能访问基本功能
|
||||
- `developer`:开发者,可以访问所有功能,包括系统设置
|
||||
|
||||
2. 权限控制:
|
||||
- 根据用户角色显示或隐藏菜单项
|
||||
- 防止通过URL直接访问未授权页面
|
||||
|
||||
## 技术实现
|
||||
|
||||
权限系统基于以下核心技术实现:
|
||||
|
||||
1. **Cookie会话存储**:使用Remix的`createCookieSessionStorage`创建基于Cookie的会话存储
|
||||
2. **角色权限控制**:将用户角色存储在会话中,并在全局loader中检查访问权限
|
||||
3. **界面适配**:根据用户角色动态过滤显示菜单项
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 登录系统
|
||||
|
||||
1. 访问登录页面(`/login`)
|
||||
2. 输入用户名和密码
|
||||
3. 选择用户角色:
|
||||
- **普通用户**:只能看到基础功能菜单
|
||||
- **开发者**:可以看到所有菜单,包括系统设置
|
||||
|
||||
### 权限验证
|
||||
|
||||
系统会自动执行以下权限验证:
|
||||
|
||||
1. 未登录用户会被重定向到登录页面
|
||||
2. 普通用户试图访问系统设置等受限页面会被重定向到首页
|
||||
3. 侧边栏菜单会根据用户角色动态显示
|
||||
|
||||
## 关键文件
|
||||
|
||||
- `app/root.tsx`:实现会话管理和全局权限检查
|
||||
- `app/components/layout/Sidebar.tsx`:根据用户角色显示不同菜单
|
||||
- `app/routes/login.tsx`:提供角色选择功能
|
||||
|
||||
## 进一步优化建议
|
||||
|
||||
1. 实现真实的用户认证系统,如接入数据库验证用户
|
||||
2. 添加更细粒度的权限控制
|
||||
3. 实现用户角色和权限的管理界面
|
||||
4. 使用环境变量管理会话密钥等敏感信息
|
||||
|
||||
# Welcome to Remix!
|
||||
|
||||
- 📖 [Remix docs](https://remix.run/docs)
|
||||
|
||||
@@ -98,7 +98,7 @@ function buildUrl(endpoint: string, params?: QueryParams): string {
|
||||
* 获取模拟响应数据
|
||||
*/
|
||||
function getMockResponse<T>(endpoint: string): ApiResponse<T> {
|
||||
console.log(`[开发模式] 使用模拟数据: ${endpoint}`);
|
||||
// console.log(`[开发模式] 使用模拟数据: ${endpoint}`);
|
||||
|
||||
// 移除开头的斜杠以便于匹配
|
||||
const path = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
|
||||
@@ -176,7 +176,7 @@ export async function apiRequest<T>(
|
||||
|
||||
// 针对 PostgREST 的额外处理
|
||||
if (endpoint.includes('evaluation_point_groups') && (options.method === 'POST' || options.method === 'PATCH')) {
|
||||
console.log('使用 PostgREST 特定配置处理请求');
|
||||
// console.log('使用 PostgREST 特定配置处理请求');
|
||||
// 确保请求体是有效的 JSON 对象
|
||||
if (options.body && typeof options.body === 'string') {
|
||||
try {
|
||||
@@ -188,15 +188,15 @@ export async function apiRequest<T>(
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`📦 axios-client.ts->请求URL: ${decodeUrlForDisplay(url)}`);
|
||||
console.log(`axios-client.ts->发送 ${options.method || 'GET'} 请求到: ${decodeUrlForDisplay(url)}`);
|
||||
// console.log(`📦 axios-client.ts->请求URL: ${decodeUrlForDisplay(url)}`);
|
||||
// console.log(`axios-client.ts->发送 ${options.method || 'GET'} 请求到: ${decodeUrlForDisplay(url)}`);
|
||||
|
||||
// 处理body参数,转换为data
|
||||
if (options.body) {
|
||||
console.log(`axios-client.ts->请求体: \n${options.body}`);
|
||||
// console.log(`axios-client.ts->请求体: \n${options.body}`);
|
||||
options.data = options.body;
|
||||
} else if (options.data) {
|
||||
console.log(`axios-client.ts->请求体: \n${typeof options.data === 'string' ? options.data : JSON.stringify(options.data)}`);
|
||||
// console.log(`axios-client.ts->请求体: \n${typeof options.data === 'string' ? options.data : JSON.stringify(options.data)}`);
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
@@ -344,7 +344,7 @@ export async function downloadFile(path: string): Promise<Blob> {
|
||||
const downloadUrl = `${DOCUMENT_URL}${path}`;
|
||||
|
||||
try {
|
||||
console.log(`📦 axios-client.ts->下载文件: ${decodeUrlForDisplay(downloadUrl)}`);
|
||||
// console.log(`📦 axios-client.ts->下载文件: ${decodeUrlForDisplay(downloadUrl)}`);
|
||||
const response = await axios.get(downloadUrl, {
|
||||
responseType: 'blob'
|
||||
});
|
||||
|
||||
+6
-6
@@ -90,7 +90,7 @@ const fetchWithTimeout = async (url: string, options: RequestInit, timeout = 500
|
||||
const id = setTimeout(() => controller.abort(), timeout);
|
||||
|
||||
try {
|
||||
console.log(`📦 client.ts->请求URL: ${decodeUrlForDisplay(url)}`);
|
||||
// console.log(`📦 client.ts->请求URL: ${decodeUrlForDisplay(url)}`);
|
||||
const response = await fetch(url, {
|
||||
...options,
|
||||
signal: controller.signal
|
||||
@@ -114,7 +114,7 @@ const fetchWithTimeout = async (url: string, options: RequestInit, timeout = 500
|
||||
* 获取模拟响应数据
|
||||
*/
|
||||
function getMockResponse<T>(endpoint: string): ApiResponse<T> {
|
||||
console.log(`[开发模式] 使用模拟数据: ${endpoint}`);
|
||||
// console.log(`[开发模式] 使用模拟数据: ${endpoint}`);
|
||||
|
||||
// 移除开头的斜杠以便于匹配
|
||||
const path = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
|
||||
@@ -185,7 +185,7 @@ export async function apiRequest<T>(
|
||||
|
||||
// 针对 PostgREST 的额外处理
|
||||
if (endpoint.includes('evaluation_point_groups') && (options.method === 'POST' || options.method === 'PATCH')) {
|
||||
console.log('使用 PostgREST 特定配置处理请求');
|
||||
// console.log('使用 PostgREST 特定配置处理请求');
|
||||
// 确保请求体是有效的 JSON 对象
|
||||
if (options.body && typeof options.body === 'string') {
|
||||
try {
|
||||
@@ -197,9 +197,9 @@ export async function apiRequest<T>(
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`client.ts->发送 ${options.method || 'GET'} 请求到: ${decodeUrlForDisplay(url)}`);
|
||||
// console.log(`client.ts->发送 ${options.method || 'GET'} 请求到: ${decodeUrlForDisplay(url)}`);
|
||||
if (options.body) {
|
||||
console.log(`client.ts->请求体: \n${options.body}`);
|
||||
// console.log(`client.ts->请求体: \n${options.body}`);
|
||||
}
|
||||
|
||||
// 发送请求,10秒超时
|
||||
@@ -226,7 +226,7 @@ export async function apiRequest<T>(
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('解析响应失败:', e);
|
||||
console.log('原始响应:', responseText);
|
||||
// console.log('原始响应:', responseText);
|
||||
}
|
||||
|
||||
// 收集响应头信息
|
||||
|
||||
@@ -213,7 +213,7 @@ export async function getContractTemplates(searchParams: TemplateSearchParams =
|
||||
if (categoryResponse.data) {
|
||||
const categories = extractApiData<ContractCategory[]>(categoryResponse.data) || [];
|
||||
matchingCategoryIds = categories.map(cat => cat.id);
|
||||
console.log('匹配的分类ID:', matchingCategoryIds);
|
||||
// console.log('匹配的分类ID:', matchingCategoryIds);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('查询分类失败:', error);
|
||||
@@ -229,8 +229,8 @@ export async function getContractTemplates(searchParams: TemplateSearchParams =
|
||||
];
|
||||
|
||||
params.or = `(${searchConditions.join(',')})`;
|
||||
console.log('搜索关键词:', cleanKeyword);
|
||||
console.log('搜索条件:', params.or);
|
||||
// console.log('搜索关键词:', cleanKeyword);
|
||||
// console.log('搜索条件:', params.or);
|
||||
}
|
||||
|
||||
// 如果有分类名称,需要先获取分类ID
|
||||
|
||||
@@ -251,7 +251,7 @@ export async function getDocumentTypes(searchParams: DocumentTypeSearchParams =
|
||||
|
||||
params.filter = filter;
|
||||
|
||||
console.log('获取文档类型列表,参数:', params);
|
||||
// console.log('获取文档类型列表,参数:', params);
|
||||
const response = await postgrestGet<DocumentType[]>('document_types', params);
|
||||
|
||||
if (response.error) {
|
||||
@@ -286,7 +286,7 @@ export async function getDocumentTypes(searchParams: DocumentTypeSearchParams =
|
||||
groupIds = [];
|
||||
}
|
||||
|
||||
console.log(`文档类型 ${type.id} 的分组IDs:`, groupIds);
|
||||
// console.log(`文档类型 ${type.id} 的分组IDs:`, groupIds);
|
||||
|
||||
// 获取这些ID对应的分组信息
|
||||
const groupsResponse = await getEvaluationPointGroupsByIds(groupIds);
|
||||
@@ -486,7 +486,7 @@ export async function getDocumentType(id: string): Promise<{
|
||||
groupIds = [];
|
||||
}
|
||||
|
||||
console.log(`文档类型 ${id} 的分组IDs:`, groupIds);
|
||||
// console.log(`文档类型 ${id} 的分组IDs:`, groupIds);
|
||||
|
||||
const groupsResponse = await getEvaluationPointGroupsByIds(groupIds);
|
||||
|
||||
@@ -606,7 +606,7 @@ export async function createDocumentType(documentType: DocumentTypeCreateDTO): P
|
||||
return { error: response.error, status: response.status };
|
||||
}
|
||||
|
||||
console.log('创建文档类型响应数据:', JSON.stringify(response.data, null, 2));
|
||||
// console.log('创建文档类型响应数据:', JSON.stringify(response.data, null, 2));
|
||||
|
||||
// 处理响应数据
|
||||
const newDocumentType = extractApiData<DocumentType>(response.data);
|
||||
@@ -712,7 +712,7 @@ export async function updateDocumentType(id: string, documentType: DocumentTypeU
|
||||
prompt_config: promptConfig
|
||||
};
|
||||
|
||||
console.log('更新文档类型请求数据:', JSON.stringify(apiDocumentType, null, 2));
|
||||
// console.log('更新文档类型请求数据:', JSON.stringify(apiDocumentType, null, 2));
|
||||
// throw new Error('测试错误');
|
||||
// 发送更新请求
|
||||
const response = await postgrestPut<DocumentType, typeof apiDocumentType>(
|
||||
@@ -726,7 +726,7 @@ export async function updateDocumentType(id: string, documentType: DocumentTypeU
|
||||
return { error: response.error, status: response.status };
|
||||
}
|
||||
|
||||
console.log('更新文档类型响应数据:', JSON.stringify(response.data, null, 2));
|
||||
// console.log('更新文档类型响应数据:', JSON.stringify(response.data, null, 2));
|
||||
|
||||
// 处理响应数据
|
||||
const updatedDocumentType = extractApiData<DocumentType>(response.data);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { postgrestGet, type PostgrestParams, postgrestPut, postgrestPost } from "../postgrest-client";
|
||||
import {getDocument} from "~/api/files/documents";
|
||||
import dayjs from "dayjs";
|
||||
import { formatDate } from "~/utils";
|
||||
|
||||
/**
|
||||
@@ -344,22 +345,22 @@ export async function getReviewPoints(fileId: string) {
|
||||
evaluatedPointResultsLog: evaluatedPointResultsLog || {}
|
||||
// evaluatedPointResultsLog: {
|
||||
// rules:[
|
||||
// {
|
||||
// "id": "0",
|
||||
// "type": "consistency",
|
||||
// "res": true,
|
||||
// "config": {
|
||||
// "logic": "all",
|
||||
// "pairs": [
|
||||
// {
|
||||
// "sourceField": {"证据先行登记保存批准书-负责人意见并签名-时间": {page: 1,value: ''}},
|
||||
// "targetField": {"证据先行登记保存批准书-负责人意见并签名-签名": {page: 2,value: '有无判断类型'}},
|
||||
// "compareMethod": "exact",
|
||||
// "res": true
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "id": "0",
|
||||
// "type": "consistency",
|
||||
// "res": true,
|
||||
// "config": {
|
||||
// "logic": "all",
|
||||
// "pairs": [
|
||||
// {
|
||||
// "sourceField": {"证据先行登记保存批准书-负责人意见并签名-时间": {page: 1,value: ''}},
|
||||
// "targetField": {"证据先行登记保存批准书-负责人意见并签名-签名": {page: 2,value: '有无判断类型'}},
|
||||
// "compareMethod": "exact",
|
||||
// "res": true
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "id": "1",
|
||||
// "type": "consistency",
|
||||
@@ -611,7 +612,7 @@ export async function getReviewPoints(fileId: string) {
|
||||
|
||||
// 构建评查信息对象
|
||||
const reviewInfo = {
|
||||
reviewTime: formatDate(latestUpdatedAt),
|
||||
reviewTime: dayjs.utc(latestUpdatedAt).format('YYYY-MM-DD HH:mm:ss'),
|
||||
reviewModel: 'DeepSeek',
|
||||
ruleGroup: uniqueGroups.join('、'),
|
||||
result: issueCount > 0 ? 'warning' : 'success',
|
||||
@@ -661,7 +662,7 @@ export async function updateReviewResult(resultId: string, editAuditStatusId: st
|
||||
|
||||
// 判断是否是重新审核操作
|
||||
const isReview = result === 'review';
|
||||
console.log('isReview-------', result);
|
||||
// console.log('isReview-------', result);
|
||||
|
||||
// 构建要更新的数据,保留原有字段
|
||||
const updatedEvaluatedResults = {
|
||||
@@ -689,8 +690,8 @@ export async function updateReviewResult(resultId: string, editAuditStatusId: st
|
||||
// 确定edit_audit_status的值:
|
||||
// 如果是重新审核操作,值为0;否则值为1
|
||||
const editAuditStatusValue = isReview ? 0 : 1;
|
||||
console.log('editAuditStatusValue-------', editAuditStatusValue);
|
||||
console.log('editAuditStatusId-------', editAuditStatusId);
|
||||
// console.log('editAuditStatusValue-------', editAuditStatusValue);
|
||||
// console.log('editAuditStatusId-------', editAuditStatusId);
|
||||
if (editAuditStatusId && editAuditStatusId !== '') {
|
||||
// 更新现有审核状态记录
|
||||
const auditStatusResponse = await postgrestPut(
|
||||
|
||||
@@ -442,7 +442,7 @@ export async function createRuleGroup(groupData: RuleGroupCreateUpdateDto): Prom
|
||||
is_enabled: groupData.is_enabled
|
||||
};
|
||||
|
||||
console.log('创建评查点分组请求数据:', JSON.stringify(apiGroup, null, 2));
|
||||
// console.log('创建评查点分组请求数据:', JSON.stringify(apiGroup, null, 2));
|
||||
|
||||
// 直接发送到 PostgreSQL 表
|
||||
const response = await postgrestPost<ApiResponse<ApiRuleGroup> | ApiRuleGroup, ApiRuleGroup>(
|
||||
@@ -455,7 +455,7 @@ export async function createRuleGroup(groupData: RuleGroupCreateUpdateDto): Prom
|
||||
return { error: response.error, status: response.status };
|
||||
}
|
||||
|
||||
console.log('创建评查点分组响应数据:', JSON.stringify(response.data, null, 2));
|
||||
// console.log('创建评查点分组响应数据:', JSON.stringify(response.data, null, 2));
|
||||
|
||||
// 处理响应数据 - 适配不同的API响应格式
|
||||
const apiResponse = extractApiData<ApiRuleGroup>(response.data);
|
||||
|
||||
@@ -313,7 +313,7 @@ export async function getReviewFiles(searchParams: DocumentSearchParams = {}): P
|
||||
// }
|
||||
|
||||
params.filter = filter;
|
||||
console.log('params-----',params);
|
||||
// console.log('params-----',params);
|
||||
|
||||
// 发送API请求获取文档列表
|
||||
const response = await postgrestGet<Document[]>('documents', params);
|
||||
|
||||
@@ -141,7 +141,7 @@ function mapApiRuleToFrontendModel(apiRule: ApiRule): Rule {
|
||||
priority: priorityMap[apiRule.risk] || 'medium',
|
||||
description: apiRule.description || '',
|
||||
isActive: apiRule.is_enabled === undefined ? false : apiRule.is_enabled,
|
||||
createdAt: apiRule.created_at ,
|
||||
createdAt: apiRule.created_at,
|
||||
updatedAt: apiRule.updated_at
|
||||
};
|
||||
}
|
||||
@@ -365,7 +365,7 @@ export async function getRulesList(params: RulesQueryParams): Promise<{data: Rul
|
||||
|
||||
|
||||
// 将API返回的数据映射到前端模型,并附加分组名称
|
||||
console.log("groupsMap",groupsMap);
|
||||
// console.log("groupsMap",groupsMap);
|
||||
const mappedRules = filteredRules.map(apiRule => {
|
||||
// 创建修改版的apiRule,添加从分组映射获取的名称
|
||||
const enhancedApiRule = {
|
||||
@@ -620,7 +620,7 @@ export async function updateRule(id: string, ruleData: Partial<Omit<Rule, 'id' |
|
||||
*/
|
||||
export async function deleteRule(id: string): Promise<{data: Rule; error?: never} | {data?: never; error: string; status?: number}> {
|
||||
try {
|
||||
console.log(`开始删除评查点, ID: ${id}`);
|
||||
// console.log(`开始删除评查点, ID: ${id}`);
|
||||
|
||||
// 使用 PostgREST 语法,通过查询参数指定要删除的行
|
||||
const postgrestParams: PostgrestParams = {
|
||||
@@ -635,7 +635,7 @@ export async function deleteRule(id: string): Promise<{data: Rule; error?: never
|
||||
// 使用postgrestDelete删除评查点
|
||||
const response = await postgrestDelete('evaluation_points', postgrestParams);
|
||||
|
||||
console.log('删除请求响应:', JSON.stringify(response, null, 2));
|
||||
// console.log('删除请求响应:', JSON.stringify(response, null, 2));
|
||||
|
||||
// 检查是否有错误响应
|
||||
if (response.error) {
|
||||
@@ -842,7 +842,7 @@ export async function getRuleTypes(): Promise<{data: RuleType[]; error?: never}
|
||||
return { error: '9000接口返回数据格式不正确', status: 500 };
|
||||
}
|
||||
}else if(Array.isArray(response.data) && response.data.length > 0){
|
||||
console.log("评查点类型列表",response.data);
|
||||
// console.log("评查点类型列表",response.data);
|
||||
const ruleTypes = response.data.map(item => ({
|
||||
id: item.id.toString(),
|
||||
pid: item.pid.toString(),
|
||||
@@ -924,7 +924,7 @@ export async function getRuleGroupsByType(typeId: string): Promise<{data: RuleGr
|
||||
return { error: '9000接口返回数据格式不正确', status: 500 };
|
||||
}
|
||||
}else if(Array.isArray(response.data) && response.data.length > 0){
|
||||
console.log("评查点类型列表",response.data);
|
||||
// console.log("评查点类型列表",response.data);
|
||||
const ruleGroups = response.data.map(item => ({
|
||||
id: item.id.toString(),
|
||||
name: item.name,
|
||||
@@ -1080,7 +1080,7 @@ export async function getEvaluationPoint(id: number): Promise<{
|
||||
status?: number;
|
||||
}> {
|
||||
try {
|
||||
console.log(`获取评查点数据,ID: ${id}`);
|
||||
// console.log(`获取评查点数据,ID: ${id}`);
|
||||
|
||||
// 使用 postgrestGet 替代直接调用 fetch
|
||||
const postgrestParams: PostgrestParams = {
|
||||
@@ -1140,7 +1140,7 @@ export async function getEvaluationPointGroups(): Promise<{
|
||||
status?: number;
|
||||
}> {
|
||||
try {
|
||||
console.log("获取评查点组数据");
|
||||
// console.log("获取评查点组数据");
|
||||
|
||||
// 使用 postgrestGet 替代直接调用 fetch
|
||||
const postgrestParams: PostgrestParams = {
|
||||
@@ -1256,7 +1256,7 @@ export async function saveEvaluationPoint(evaluationPoint: EvaluationPointInput,
|
||||
status?: number;
|
||||
}> {
|
||||
try {
|
||||
console.log(`${isEditMode ? '更新' : '创建'}评查点数据`);
|
||||
// console.log(`${isEditMode ? '更新' : '创建'}评查点数据`);
|
||||
|
||||
// 创建一个符合数据库模式的数据副本
|
||||
const cleanedData = {
|
||||
@@ -1393,7 +1393,7 @@ export async function saveEvaluationPoint(evaluationPoint: EvaluationPointInput,
|
||||
});
|
||||
}
|
||||
|
||||
console.log("准备发送到API的数据大小:", JSON.stringify(cleanedData).length, "字节");
|
||||
// console.log("准备发送到API的数据大小:", JSON.stringify(cleanedData).length, "字节");
|
||||
|
||||
// 使用 postgrest-client 替代直接 fetch 调用
|
||||
let response;
|
||||
|
||||
@@ -448,7 +448,7 @@ export async function updateDocument(id: string, document: Partial<DocumentUI> &
|
||||
apiDocument.remark = document.remark;
|
||||
}
|
||||
|
||||
console.log('更新文档API数据:', apiDocument);
|
||||
// console.log('更新文档API数据:', apiDocument);
|
||||
|
||||
const response = await postgrestPut<Document, Partial<Document>>(
|
||||
'documents',
|
||||
|
||||
@@ -131,7 +131,7 @@ export async function uploadDocumentToServer(
|
||||
isTestDocument: boolean = false
|
||||
): Promise<{data: FileUploadResponse; error?: never} | {data?: never; error: string; status?: number}> {
|
||||
try {
|
||||
console.log('【调试】开始上传文档:', { fileName, fileSize: binaryData.byteLength });
|
||||
// console.log('【调试】开始上传文档:', { fileName, fileSize: binaryData.byteLength });
|
||||
|
||||
// 创建FormData对象
|
||||
const formData = new FormData();
|
||||
@@ -139,7 +139,7 @@ export async function uploadDocumentToServer(
|
||||
// 将二进制数据转换为Blob并添加到FormData
|
||||
const blob = new Blob([binaryData], { type: fileType });
|
||||
formData.append('file', blob, fileName);
|
||||
console.log('【调试】Blob已创建,文件大小:', blob.size);
|
||||
// console.log('【调试】Blob已创建,文件大小:', blob.size);
|
||||
|
||||
// 将信息添加到一个JSON对象中
|
||||
const uploadInfo = {
|
||||
@@ -152,14 +152,14 @@ export async function uploadDocumentToServer(
|
||||
|
||||
// 添加JSON字符串到FormData
|
||||
formData.append('upload_info', JSON.stringify(uploadInfo));
|
||||
console.log('【调试】FormData准备完成:', JSON.stringify(uploadInfo));
|
||||
// console.log('【调试】FormData准备完成:', JSON.stringify(uploadInfo));
|
||||
|
||||
console.log('【调试】准备发送请求到服务器:', 'http://172.16.0.58:8008/admin/documents/upload');
|
||||
// console.log('【调试】准备发送请求到服务器:', 'http://172.16.0.58:8008/admin/documents/upload');
|
||||
|
||||
// 发送请求
|
||||
// const response = await fetch(`${API_BASE_URL}/admin/documents/upload`, {
|
||||
try {
|
||||
console.log('【调试】开始fetch请求...');
|
||||
// console.log('【调试】开始fetch请求...');
|
||||
const response = await fetch('http://172.16.0.58:8008/admin/documents/upload', {
|
||||
// const response = await fetch('http://172.16.0.55:8000/admin/documents/upload', {
|
||||
// const response = await fetch('http://172.16.0.119:8000/admin/documents/upload', {
|
||||
@@ -170,7 +170,7 @@ export async function uploadDocumentToServer(
|
||||
body: formData
|
||||
});
|
||||
|
||||
console.log('【调试】收到服务器响应:', { status: response.status, statusText: response.statusText });
|
||||
// console.log('【调试】收到服务器响应:', { status: response.status, statusText: response.statusText });
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
@@ -181,11 +181,11 @@ export async function uploadDocumentToServer(
|
||||
};
|
||||
}
|
||||
|
||||
console.log('【调试】开始解析JSON响应');
|
||||
// console.log('【调试】开始解析JSON响应');
|
||||
let responseData;
|
||||
try {
|
||||
responseData = await response.json();
|
||||
console.log('【调试】JSON响应解析成功:', responseData);
|
||||
// console.log('【调试】JSON响应解析成功:', responseData);
|
||||
} catch (jsonError) {
|
||||
console.error('【调试】JSON解析失败:', jsonError);
|
||||
return {
|
||||
@@ -195,14 +195,14 @@ export async function uploadDocumentToServer(
|
||||
}
|
||||
|
||||
const extractedData = extractApiData<FileUploadResponse>(responseData);
|
||||
console.log('【调试】提取的数据:', extractedData);
|
||||
// console.log('【调试】提取的数据:', extractedData);
|
||||
|
||||
if (!extractedData) {
|
||||
console.error('【调试】无法提取数据');
|
||||
return { error: '处理上传响应失败', status: 500 };
|
||||
}
|
||||
|
||||
console.log('【调试】上传成功,返回数据');
|
||||
// console.log('【调试】上传成功,返回数据');
|
||||
return { data: extractedData };
|
||||
} catch (fetchError) {
|
||||
console.error('【调试】fetch请求失败:', fetchError);
|
||||
@@ -227,7 +227,7 @@ export async function uploadDocumentToServer(
|
||||
export async function getTodayDocuments(): Promise<{data: Document[]; error?: never} | {data?: never; error: string; status?: number}> {
|
||||
try {
|
||||
const today = dayjs().startOf('day').format('YYYY-MM-DD');
|
||||
console.log('查询当天文档,日期范围:', today);
|
||||
// console.log('查询当天文档,日期范围:', today);
|
||||
|
||||
const params: PostgrestParams = {
|
||||
select: `
|
||||
|
||||
@@ -225,7 +225,7 @@ export async function getHomeData(): Promise<HomeStatistics> {
|
||||
? parseFloat(((lastMonthTotal / lastMonthReviewed) * 100).toFixed(1))
|
||||
: 0;
|
||||
|
||||
console.log('上个月-------', lastMonthPassRate);
|
||||
// console.log('上个月-------', lastMonthPassRate);
|
||||
|
||||
// 计算通过率同比增长
|
||||
let passRateGrowthValue = 0;
|
||||
@@ -242,8 +242,8 @@ export async function getHomeData(): Promise<HomeStatistics> {
|
||||
passRateGrowthIsUp = true;
|
||||
}
|
||||
|
||||
console.log('上月通过率-------', lastMonthPassRate);
|
||||
console.log('本月通过率-------', monthlyPassRate);
|
||||
// console.log('上月通过率-------', lastMonthPassRate);
|
||||
// console.log('本月通过率-------', monthlyPassRate);
|
||||
|
||||
// 4. 检查出的问题总数(从评估结果表中统计)
|
||||
const thisMonthIssuesParams: PostgrestParams = {
|
||||
|
||||
+16
-16
@@ -55,22 +55,22 @@ function logPostgrestQuery(endpoint: string, params?: QueryParams, method: strin
|
||||
// 确保 endpoint 格式正确
|
||||
const normalizedEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
|
||||
|
||||
console.log('\n📦 PostgREST 查询日志 ======================start=============');
|
||||
console.log(`📦 HTTP 方法: ${method}`);
|
||||
console.log(`📦 API 端点: ${decodeUrlForDisplay(`${baseUrl}/${normalizedEndpoint}`)}`);
|
||||
// console.log('\n📦 PostgREST 查询日志 ======================start=============');
|
||||
// console.log(`📦 HTTP 方法: ${method}`);
|
||||
// console.log(`📦 API 端点: ${decodeUrlForDisplay(`${baseUrl}/${normalizedEndpoint}`)}`);
|
||||
|
||||
if (params && Object.keys(params).length > 0) {
|
||||
console.log('📦 查询参数:');
|
||||
// if (params && Object.keys(params).length > 0) {
|
||||
// console.log('📦 查询参数:');
|
||||
|
||||
// 以可读格式单独打印每个参数
|
||||
Object.entries(params).forEach(([key, value]) => {
|
||||
if (value !== undefined) {
|
||||
console.log(` - ${key}: ${JSON.stringify(value)}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
// // 以可读格式单独打印每个参数
|
||||
// Object.entries(params).forEach(([key, value]) => {
|
||||
// if (value !== undefined) {
|
||||
// console.log(` - ${key}: ${JSON.stringify(value)}`);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
console.log('PostgREST 查询日志=============================end============\n');
|
||||
// console.log('PostgREST 查询日志=============================end============\n');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,8 +305,8 @@ export async function postgrestPost<T, D = Record<string, unknown>>(endpoint: st
|
||||
|
||||
// 确保数据是合法的JSON对象
|
||||
const requestBody = JSON.stringify(processedData);
|
||||
console.log(`准备发送 PostgreSQL 插入请求到: ${apiEndpoint}`);
|
||||
console.log(`请求体: ${requestBody}`);
|
||||
// console.log(`准备发送 PostgreSQL 插入请求到: ${apiEndpoint}`);
|
||||
// console.log(`请求体: ${requestBody}`);
|
||||
|
||||
try {
|
||||
const response = await apiRequest<T>(
|
||||
@@ -327,7 +327,7 @@ export async function postgrestPost<T, D = Record<string, unknown>>(endpoint: st
|
||||
throw new Error(response.error);
|
||||
}
|
||||
|
||||
console.log(`POST请求成功,响应: `, response.data);
|
||||
// console.log(`POST请求成功,响应: `, response.data);
|
||||
return { data: response.data as T };
|
||||
} catch (error) {
|
||||
// 捕获并处理 API 请求错误
|
||||
|
||||
@@ -121,7 +121,7 @@ export async function getPromptTemplates(searchParams: PromptSearchParams = {}):
|
||||
status?: number;
|
||||
}> {
|
||||
try {
|
||||
console.log('获取提示词模板列表,参数:', searchParams);
|
||||
// console.log('获取提示词模板列表,参数:', searchParams);
|
||||
|
||||
const page = searchParams.page || 1;
|
||||
const pageSize = searchParams.pageSize || 10;
|
||||
@@ -177,7 +177,7 @@ export async function getPromptTemplates(searchParams: PromptSearchParams = {}):
|
||||
params.filter = filter;
|
||||
|
||||
// 发送API请求
|
||||
console.log('API请求参数:', params);
|
||||
// console.log('API请求参数:', params);
|
||||
const response = await postgrestGet<PromptTemplate[]>('prompt_templates', params);
|
||||
|
||||
if (response.error) {
|
||||
@@ -320,7 +320,7 @@ export async function createPromptTemplate(template: Partial<PromptTemplateUI>):
|
||||
};
|
||||
|
||||
if(apiTemplate){
|
||||
console.log('apiTemplate', apiTemplate);
|
||||
// console.log('apiTemplate', apiTemplate);
|
||||
// throw new Error('测试错误');
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ export function TemplateCard({ template, onClick }: TemplateCardProps) {
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
console.log('开始下载文件:', cleanFileName);
|
||||
// console.log('开始下载文件:', cleanFileName);
|
||||
} catch (error) {
|
||||
console.error('下载文件失败:', error);
|
||||
alert('下载失败,请稍后重试');
|
||||
@@ -86,7 +86,7 @@ export function TemplateCard({ template, onClick }: TemplateCardProps) {
|
||||
navigate(`/contract-template/detail/${template.id}`);
|
||||
break;
|
||||
default:
|
||||
console.log(`执行操作: ${action}`, template.id);
|
||||
// console.log(`执行操作: ${action}`, template.id);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ export function ErrorBoundary({ status, statusText, message }: ErrorBoundaryProp
|
||||
</Link>
|
||||
</div>
|
||||
<div className="mt-12 text-center">
|
||||
<p className="text-sm text-gray-500">如果问题持续存在,请联系系统管理员</p>
|
||||
<p className="text-sm text-gray-500 mt-1">技术支持:support@tobacco-ai-system.com</p>
|
||||
<p className="text-sm text-gray-500">如果问题持续存在,请联系技术开发团队</p>
|
||||
{/* <p className="text-sm text-gray-500 mt-1">技术支持:support@tobacco-ai-system.com</p> */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -3,9 +3,11 @@ import { Sidebar } from './Sidebar';
|
||||
// import { Header } from './Header';
|
||||
import { Breadcrumb } from './Breadcrumb';
|
||||
import { useMatches, useLocation } from '@remix-run/react';
|
||||
import type { UserRole } from '~/root';
|
||||
|
||||
interface LayoutProps {
|
||||
children: React.ReactNode;
|
||||
userRole?: UserRole;
|
||||
}
|
||||
|
||||
// 添加一个接口表示路由handle可能包含的属性
|
||||
@@ -20,7 +22,7 @@ interface Match {
|
||||
data: unknown;
|
||||
}
|
||||
|
||||
export function Layout({ children }: LayoutProps) {
|
||||
export function Layout({ children, userRole = 'developer' }: LayoutProps) {
|
||||
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
|
||||
const matches = useMatches() as Match[];
|
||||
const location = useLocation();
|
||||
@@ -58,6 +60,7 @@ export function Layout({ children }: LayoutProps) {
|
||||
<Sidebar
|
||||
collapsed={sidebarCollapsed}
|
||||
onToggle={toggleSidebar}
|
||||
userRole={userRole}
|
||||
/>
|
||||
|
||||
<div className={`main-content ${sidebarCollapsed ? 'sidebar-collapsed' : ''}`}>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Link, useLocation } from '@remix-run/react';
|
||||
import type { UserRole } from '~/root';
|
||||
|
||||
interface MenuItem {
|
||||
id: string;
|
||||
@@ -7,15 +8,17 @@ interface MenuItem {
|
||||
path: string;
|
||||
icon: string;
|
||||
hideBreadcrumb?: boolean;
|
||||
requiredRole?: UserRole;
|
||||
children?: MenuItem[];
|
||||
}
|
||||
|
||||
interface SidebarProps {
|
||||
onToggle: () => void;
|
||||
collapsed: boolean;
|
||||
userRole: UserRole;
|
||||
}
|
||||
|
||||
export function Sidebar({ onToggle, collapsed }: SidebarProps) {
|
||||
export function Sidebar({ onToggle, collapsed, userRole }: SidebarProps) {
|
||||
const location = useLocation();
|
||||
const [expandedMenus, setExpandedMenus] = useState<Record<string, boolean>>({});
|
||||
|
||||
@@ -109,12 +112,14 @@ export function Sidebar({ onToggle, collapsed }: SidebarProps) {
|
||||
title: '系统设置',
|
||||
path: '/settings',
|
||||
icon: 'ri-settings-4-line',
|
||||
requiredRole: 'developer',
|
||||
children: [
|
||||
{
|
||||
id: 'config-lists',
|
||||
title: '配置列表',
|
||||
path: '/config-lists',
|
||||
icon: 'ri-list-check-3'
|
||||
icon: 'ri-list-check-3',
|
||||
requiredRole: 'developer'
|
||||
},
|
||||
// {
|
||||
// id: 'basic-settings',
|
||||
@@ -126,13 +131,15 @@ export function Sidebar({ onToggle, collapsed }: SidebarProps) {
|
||||
id: 'document-types',
|
||||
title: '文档类型',
|
||||
path: '/document-types',
|
||||
icon: 'ri-file-list-line'
|
||||
icon: 'ri-file-list-line',
|
||||
requiredRole: 'developer'
|
||||
},
|
||||
{
|
||||
id: 'prompt-management',
|
||||
title: '提示词管理',
|
||||
path: '/prompts',
|
||||
icon: 'ri-chat-1-line'
|
||||
icon: 'ri-chat-1-line',
|
||||
requiredRole: 'developer'
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -150,11 +157,10 @@ export function Sidebar({ onToggle, collapsed }: SidebarProps) {
|
||||
}, []);
|
||||
|
||||
const toggleMenu = (id: string, e: React.MouseEvent) => {
|
||||
// 防止事件冒泡和默认行为
|
||||
e.preventDefault();
|
||||
// 我们只防止事件冒泡,不阻止默认行为
|
||||
e.stopPropagation();
|
||||
|
||||
// console.log('%c父菜单展开/折叠 ===> ', 'background: #f5222d; color: white; padding: 2px 4px; border-radius: 2px;', id);
|
||||
// console.log('父菜单展开/折叠:', id);
|
||||
|
||||
setExpandedMenus(prev => ({
|
||||
...prev,
|
||||
@@ -168,18 +174,27 @@ export function Sidebar({ onToggle, collapsed }: SidebarProps) {
|
||||
|
||||
// 处理侧边栏切换事件
|
||||
const handleToggleSidebar = (e: React.MouseEvent) => {
|
||||
// console.log('%c侧边栏折叠/展开 ===> ', 'background: #1890ff; color: white; padding: 2px 4px; border-radius: 2px;');
|
||||
e.preventDefault();
|
||||
// console.log('侧边栏折叠/展开');
|
||||
// 只防止事件冒泡,不阻止默认行为
|
||||
e.stopPropagation();
|
||||
onToggle();
|
||||
};
|
||||
|
||||
// 处理子菜单项点击事件
|
||||
const handleSubMenuClick = (child: MenuItem, e: React.MouseEvent) => {
|
||||
// 需要阻止冒泡,否则会触发父级菜单的展开/折叠事件
|
||||
// 只需要阻止冒泡,不阻止默认行为
|
||||
e.stopPropagation();
|
||||
// console.log('%c子菜单点击 ===> ', 'background: #00684a; color: white; padding: 2px 4px; border-radius: 2px;', child.title, '路径:', child.path);
|
||||
// console.log('子菜单点击:', child.title, '路径:', child.path);
|
||||
};
|
||||
|
||||
// 根据用户角色过滤菜单项
|
||||
const filteredMenuItems = menuItems.filter(item => {
|
||||
// 如果菜单项需要特定角色但用户没有
|
||||
if (item.requiredRole && item.requiredRole !== userRole) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={`sidebar ${collapsed ? 'collapsed' : ''}`}>
|
||||
@@ -211,15 +226,16 @@ export function Sidebar({ onToggle, collapsed }: SidebarProps) {
|
||||
)} */}
|
||||
|
||||
<div className="py-4 px-[10px]">
|
||||
{menuItems.map((item) => (
|
||||
{filteredMenuItems.map((item) => (
|
||||
<div key={item.id} className={`${collapsed ? 'px-0' : ''}`}>
|
||||
{!item.children ? (
|
||||
<Link
|
||||
to={item.path}
|
||||
className={`sidebar-menu-item ${isActive(item.path) ? 'active' : ''} flex items-center ${collapsed ? 'justify-center' : ''}`}
|
||||
onClick={(e) => {
|
||||
// 只阻止冒泡,不阻止默认行为
|
||||
e.stopPropagation();
|
||||
// console.log('%c单级菜单点击 ===> ', 'background: #52c41a; color: white; padding: 2px 4px; border-radius: 2px;', item.title, '路径:', item.path);
|
||||
// console.log('单级菜单点击:', item.title, '路径:', item.path);
|
||||
}}
|
||||
>
|
||||
<i className={`${item.icon} ${collapsed ? 'text-xl' : 'mr-3'}`}></i>
|
||||
@@ -258,7 +274,9 @@ export function Sidebar({ onToggle, collapsed }: SidebarProps) {
|
||||
className={`submenu-container ${collapsed ? 'border-l-0 pl-0' : 'border-l border-gray-100 ml-4 pl-3'} z-20`}
|
||||
id={`submenu-${item.id}`}
|
||||
>
|
||||
{item.children.map((child) => (
|
||||
{item.children
|
||||
.filter(child => !child.requiredRole || child.requiredRole === userRole)
|
||||
.map((child) => (
|
||||
<Link
|
||||
key={child.id}
|
||||
to={child.path}
|
||||
|
||||
@@ -139,7 +139,7 @@ export function FileDetails({ fileInfo, contractInfo, reviewInfo }: FileDetailsP
|
||||
{renderInfoRow('文件格式', fileInfo.fileFormat)}
|
||||
{renderInfoRow('页数', `${fileInfo.pageCount}页`)}
|
||||
{renderInfoRow('上传时间', fileInfo.uploadTime)}
|
||||
{renderInfoRow('上传用户', fileInfo.uploadUser)}
|
||||
{/* {renderInfoRow('上传用户', fileInfo.uploadUser)} */}
|
||||
</div>
|
||||
))}
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ export function FilePreview({ fileContent, activeReviewPointResultId, targetPage
|
||||
|
||||
const pageElement = document.getElementById(pageElementId);
|
||||
if (pageElement) {
|
||||
console.log(`跳转到第${newTargetPage}页,对应评查点结果ID: ${activeReviewPointResultId}`);
|
||||
// console.log(`跳转到第${newTargetPage}页,对应评查点结果ID: ${activeReviewPointResultId}`);
|
||||
pageElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
} else {
|
||||
console.warn(`未找到页面元素: ${pageElementId}`);
|
||||
@@ -262,7 +262,7 @@ export function FilePreview({ fileContent, activeReviewPointResultId, targetPage
|
||||
// PDF文档加载成功回调函数
|
||||
function onDocumentLoadSuccess({ numPages }: { numPages: number }) {
|
||||
setNumPages(numPages);
|
||||
console.log("PDF加载成功,页数:", numPages);
|
||||
// console.log("PDF加载成功,页数:", numPages);
|
||||
}
|
||||
|
||||
// 计算页面在缩放后的实际间距
|
||||
|
||||
@@ -131,13 +131,6 @@ interface Statistics {
|
||||
score: number;
|
||||
}
|
||||
|
||||
// 统一规则的类型
|
||||
// interface pointRule {
|
||||
// id: string;
|
||||
// type: string;
|
||||
// config: Record<string, unknown>;
|
||||
// }
|
||||
|
||||
interface ReviewPointsListProps {
|
||||
reviewPoints: ReviewPoint[];
|
||||
statistics: Statistics;
|
||||
@@ -240,11 +233,14 @@ const ReactTableTooltip = ({ content }: { content: string }) => {
|
||||
const [showTooltip, setShowTooltip] = useState(false);
|
||||
const textRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const isTableLike = content.includes('\t') && content.includes('\n');
|
||||
|
||||
useEffect(() => {
|
||||
const checkTextOverflow = () => {
|
||||
const element = textRef.current;
|
||||
if (element) {
|
||||
setShowTooltip(element.scrollHeight > element.clientHeight);
|
||||
// 如果是表格格式,总是显示tooltip;否则只在文本溢出时显示
|
||||
setShowTooltip(isTableLike || element.scrollHeight > element.clientHeight);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -253,7 +249,7 @@ const ReactTableTooltip = ({ content }: { content: string }) => {
|
||||
return () => {
|
||||
window.removeEventListener('resize', checkTextOverflow);
|
||||
};
|
||||
}, [content]);
|
||||
}, [content, isTableLike]);
|
||||
|
||||
// 解析表格数据
|
||||
const parseTableData = (text: string) => {
|
||||
@@ -268,7 +264,7 @@ const ReactTableTooltip = ({ content }: { content: string }) => {
|
||||
const hasHeader = tableData.length > 0;
|
||||
|
||||
return (
|
||||
<div className="overflow-auto max-h-[400px]">
|
||||
<div>
|
||||
<table className="min-w-full border-collapse border border-gray-300">
|
||||
{hasHeader && (
|
||||
<thead>
|
||||
@@ -307,8 +303,7 @@ const ReactTableTooltip = ({ content }: { content: string }) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 检测内容是否像表格
|
||||
const isTableLike = content.includes('\t') && content.includes('\n');
|
||||
|
||||
|
||||
return (
|
||||
<div className="text-xs p-1 rounded cursor-text w-full text-left">
|
||||
@@ -321,6 +316,8 @@ const ReactTableTooltip = ({ content }: { content: string }) => {
|
||||
showArrow={true}
|
||||
className="tooltip-custom-offset"
|
||||
// fixedPlacement={true}
|
||||
// scrollable={true}
|
||||
maxHeight={400}
|
||||
>
|
||||
<div className="text-gray-800 break-all overflow-hidden line-clamp-2" ref={textRef}>
|
||||
{content}
|
||||
@@ -352,8 +349,8 @@ export function ReviewPointsList({
|
||||
// 添加重新审核意见的状态/ 用户输入的修改内容 / 用户提前写好的修改内容
|
||||
const [manualReviewNotes, setManualReviewNotes] = useState<Record<string, string>>({});
|
||||
|
||||
// 存放属于有无判断,格式判断,逻辑判断,正则表达式这一类的评查点规则设置
|
||||
// const [otherRule, setOtherRule] = useState<Record<string, unknown>[]>([]);
|
||||
// 存放评查点ID与有效页码的映射
|
||||
const [effectivePages, setEffectivePages] = useState<Record<string, number>>({});
|
||||
|
||||
// 初始化建议文本
|
||||
useEffect(() => {
|
||||
@@ -874,6 +871,35 @@ export function ReviewPointsList({
|
||||
// 处理配对数据
|
||||
const pairs = config.pairs;
|
||||
|
||||
// 获取第一个有效页码
|
||||
if (reviewPoint.id && !effectivePages[reviewPoint.id]) {
|
||||
for (const pair of pairs) {
|
||||
// 检查sourceField中是否有有效页码
|
||||
const sourceFieldKey = Object.keys(pair.sourceField)[0];
|
||||
if (sourceFieldKey && pair.sourceField[sourceFieldKey].page &&
|
||||
Number(pair.sourceField[sourceFieldKey].page) > 0) {
|
||||
// 保存页码
|
||||
setEffectivePages(prev => ({
|
||||
...prev,
|
||||
[reviewPoint.id || '']: Number(pair.sourceField[sourceFieldKey].page)
|
||||
}));
|
||||
break;
|
||||
}
|
||||
|
||||
// 如果sourceField没有有效页码,检查targetField
|
||||
const targetFieldKey = Object.keys(pair.targetField)[0];
|
||||
if (targetFieldKey && pair.targetField[targetFieldKey].page &&
|
||||
Number(pair.targetField[targetFieldKey].page) > 0) {
|
||||
// 保存页码
|
||||
setEffectivePages(prev => ({
|
||||
...prev,
|
||||
[reviewPoint.id || '']: Number(pair.targetField[targetFieldKey].page)
|
||||
}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查找链条关系
|
||||
const findChains = () => {
|
||||
type ChainItem = {
|
||||
@@ -1169,7 +1195,11 @@ export function ReviewPointsList({
|
||||
if (reviewPointId && typeof onReviewPointSelect === 'function') {
|
||||
onReviewPointSelect(reviewPointId, Number(item.data.page));
|
||||
}
|
||||
}else{
|
||||
}
|
||||
else if(reviewPoint.contentPage && reviewPoint.contentPage[item.field]){
|
||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[item.field]));
|
||||
}
|
||||
else{
|
||||
toastService.error(`没有找到${item.field}对应的索引内容`);
|
||||
}
|
||||
}}
|
||||
@@ -1177,7 +1207,7 @@ export function ReviewPointsList({
|
||||
>
|
||||
<div className="flex justify-between w-full">
|
||||
<ReactTableTooltip content={item.data.value?.toString() || ''} />
|
||||
{!item.data.page && !item.data.value && (
|
||||
{!item.data.page && (reviewPoint.contentPage && !reviewPoint.contentPage[item.field]) && (
|
||||
<i className="ri-information-line text-red-500 text-xs" title="没有找到对应的文书内容"></i>
|
||||
)}
|
||||
</div>
|
||||
@@ -1248,14 +1278,18 @@ export function ReviewPointsList({
|
||||
if (reviewPointId && typeof onReviewPointSelect === 'function') {
|
||||
onReviewPointSelect(reviewPointId, chain[0].data.page);
|
||||
}
|
||||
}else{
|
||||
}
|
||||
else if(reviewPoint.contentPage && reviewPoint.contentPage[chain[0].field]){
|
||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[chain[0].field]));
|
||||
}
|
||||
else{
|
||||
toastService.error(`没有找到${chain[0].field}对应的索引内容`);
|
||||
}
|
||||
}}
|
||||
aria-label={`查看${chain[0].field}内容详情`}
|
||||
>
|
||||
<div className="value-source text-xs text-gray-500 mb-1">{chain[0].field}
|
||||
{!chain[0].data.page && !chain[0].data.value && (
|
||||
{!chain[0].data.page && (reviewPoint.contentPage && !reviewPoint.contentPage[chain[0].field]) && (
|
||||
<i className="ri-information-line text-red-500 text-xs ml-1" title="没有找到对应的文书内容"></i>
|
||||
)}
|
||||
</div>
|
||||
@@ -1270,14 +1304,18 @@ export function ReviewPointsList({
|
||||
if (reviewPointId && typeof onReviewPointSelect === 'function') {
|
||||
onReviewPointSelect(reviewPointId, chain[1].data.page);
|
||||
}
|
||||
}else{
|
||||
}
|
||||
else if(reviewPoint.contentPage && reviewPoint.contentPage[chain[1].field]){
|
||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[chain[1].field]));
|
||||
}
|
||||
else{
|
||||
toastService.error(`没有找到${chain[1].field}对应的索引内容`);
|
||||
}
|
||||
}}
|
||||
aria-label={`查看${chain[1].field}内容详情`}
|
||||
>
|
||||
<div className="value-source text-xs text-gray-500 mb-1">{chain[1].field}
|
||||
{!chain[1].data.page && !chain[1].data.value && (
|
||||
{!chain[1].data.page && (reviewPoint.contentPage && !reviewPoint.contentPage[chain[1].field]) && (
|
||||
<i className="ri-information-line text-red-500 text-xs ml-1" title="没有找到对应的文书内容"></i>
|
||||
)}
|
||||
</div>
|
||||
@@ -1404,6 +1442,8 @@ export function ReviewPointsList({
|
||||
e.stopPropagation();
|
||||
if (mainTypeValue.page && typeof onReviewPointSelect === 'function') {
|
||||
onReviewPointSelect(reviewPoint.id, Number(mainTypeValue.page));
|
||||
}else if(reviewPoint.contentPage && reviewPoint.contentPage[fieldKey]){
|
||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[fieldKey]));
|
||||
}else{
|
||||
toastService.error(`没有找到${fieldKey}对应的索引内容`);
|
||||
}
|
||||
@@ -1425,7 +1465,7 @@ export function ReviewPointsList({
|
||||
{/* 字段名称 */}
|
||||
<div className="text-xs text-gray-500 mb-1">
|
||||
{fieldKey}
|
||||
{!mainTypeValue.page && !mainTypeValue.value && (
|
||||
{!mainTypeValue.page && (reviewPoint.contentPage && !reviewPoint.contentPage[fieldKey]) && (
|
||||
<i className="ri-information-line text-red-500 text-xs ml-1" title="没有找到对应的文书内容"></i>
|
||||
)}
|
||||
{/* 缺失显示 */}
|
||||
@@ -1492,6 +1532,19 @@ export function ReviewPointsList({
|
||||
|
||||
// 如果配置不存在,不渲染任何内容
|
||||
if (!config) return null;
|
||||
|
||||
// 获取第一个有效页码
|
||||
if (reviewPoint.id && !effectivePages[reviewPoint.id] && config.fields) {
|
||||
for (const field of Object.values(config.fields || {})) {
|
||||
if (field.page && Number(field.page) > 0) {
|
||||
setEffectivePages(prev => ({
|
||||
...prev,
|
||||
[reviewPoint.id || '']: Number(field.page)
|
||||
}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建一个数组来存储需要渲染的JSX元素
|
||||
const fieldElements: JSX.Element[] = [];
|
||||
@@ -1510,6 +1563,8 @@ export function ReviewPointsList({
|
||||
e.stopPropagation();
|
||||
if (value.page && typeof onReviewPointSelect === 'function') {
|
||||
onReviewPointSelect(reviewPoint.id, Number(value.page));
|
||||
}else if(reviewPoint.contentPage && reviewPoint.contentPage[key]){
|
||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key]));
|
||||
}else{
|
||||
toastService.error(`没有找到${key}对应的索引内容`);
|
||||
}
|
||||
@@ -1520,6 +1575,8 @@ export function ReviewPointsList({
|
||||
e.preventDefault();
|
||||
if (value.page && typeof onReviewPointSelect === 'function') {
|
||||
onReviewPointSelect(reviewPoint.id, Number(value.page));
|
||||
}else if(reviewPoint.contentPage && reviewPoint.contentPage[key]){
|
||||
onReviewPointSelect(reviewPoint.id, Number(reviewPoint.contentPage[key]));
|
||||
}else{
|
||||
toastService.error(`没有找到${key}对应的索引内容`);
|
||||
}
|
||||
@@ -1533,7 +1590,7 @@ export function ReviewPointsList({
|
||||
<div className="text-xs text-left text-gray-500 mb-1">
|
||||
{key}
|
||||
{/* 没有抽取到目录内容,page和value都为空 */}
|
||||
{!value.page && !value.value && (
|
||||
{!value.page && (reviewPoint.contentPage && !reviewPoint.contentPage[key]) && (
|
||||
<i className="ri-information-line text-red-500 text-xs ml-1" title="没有找到对应的文书内容"></i>
|
||||
)}
|
||||
{/* 缺失显示 */}
|
||||
@@ -1851,6 +1908,34 @@ export function ReviewPointsList({
|
||||
for (const key in fieldKeyMap) {
|
||||
mergedRules.push(fieldKeyMap[key]);
|
||||
}
|
||||
|
||||
// 获取第一个有效页码
|
||||
if (reviewPoint.id && !effectivePages[reviewPoint.id]) {
|
||||
// 遍历合并后的规则数组,查找第一个有效页码
|
||||
for (const rule of mergedRules) {
|
||||
// 遍历字段类型对象
|
||||
const typeEntries = Object.entries(rule.fieldValue.type);
|
||||
|
||||
// 遍历每种类型规则
|
||||
for (const [, typeValue] of typeEntries) {
|
||||
// 检查是否有有效页码
|
||||
if (typeValue.page && Number(typeValue.page) > 0) {
|
||||
// 找到有效页码,设置状态并跳出循环
|
||||
setEffectivePages(prev => ({
|
||||
...prev,
|
||||
[reviewPoint.id || '']: Number(typeValue.page)
|
||||
}));
|
||||
// 使用break跳出当前循环
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果已经找到有效页码,跳出外层循环
|
||||
if (reviewPoint.id && effectivePages[reviewPoint.id]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 返回合并后的规则数组
|
||||
return mergedRules;
|
||||
@@ -2148,24 +2233,19 @@ export function ReviewPointsList({
|
||||
const reviewPoint = reviewPoints.find(result => result.id === id);
|
||||
|
||||
// 如果评查点存在
|
||||
if (reviewPoint) {
|
||||
// // 使用checkContentPage方法获取页码和key
|
||||
// const { pageIndex, key } = checkContentPage(reviewPoint);
|
||||
|
||||
// // 如果有有效页码,传递ID和页码
|
||||
// if (pageIndex > 0) {
|
||||
// console.log(`跳转到页面 ${pageIndex},对应内容 ${key || '未知'}`);
|
||||
// onReviewPointSelect(id, pageIndex);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // 没有有效页码,只传递ID
|
||||
onReviewPointSelect(id);
|
||||
// console.log(`没有有效页码---评查点ID:${reviewPoint.pointId},评查点结果ID:${id}`);
|
||||
if (reviewPoint) {
|
||||
// 如果effectivePages有值,使用它
|
||||
if (reviewPoint.id && effectivePages[reviewPoint.id]) {
|
||||
// console.log('effectivePages', effectivePages[reviewPoint.id]);
|
||||
onReviewPointSelect(id, effectivePages[reviewPoint.id]);
|
||||
// return;
|
||||
} else {
|
||||
// 没有有效页码,只传递ID
|
||||
onReviewPointSelect(id);
|
||||
}
|
||||
} else {
|
||||
// // 没有找到评查点,只传递ID
|
||||
// 没有找到评查点,只传递ID
|
||||
onReviewPointSelect(id);
|
||||
// console.log(`没有找到评查点---评查点结果ID:${id}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2225,7 +2305,7 @@ export function ReviewPointsList({
|
||||
tabIndex={0}
|
||||
style={{ userSelect: 'text' }}
|
||||
onClick={() => {
|
||||
console.log('reviewPoint', reviewPoint);
|
||||
// console.log('reviewPoint', reviewPoint);
|
||||
handleReviewPointClick(reviewPoint.id);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
|
||||
@@ -3,25 +3,30 @@ interface ActionButtonsProps {
|
||||
onSave?: () => void;
|
||||
onSaveDraft?: () => void;
|
||||
isEditMode?: boolean;
|
||||
showButtons?: boolean;
|
||||
}
|
||||
|
||||
export function ActionButtons({ onSave, onSaveDraft, isEditMode }: ActionButtonsProps) {
|
||||
export function ActionButtons({ onSave, onSaveDraft, isEditMode, showButtons = true }: ActionButtonsProps) {
|
||||
return (
|
||||
<div className="flex justify-center space-x-4 mt-8 mb-4">
|
||||
<button
|
||||
type="button"
|
||||
className="ant-btn ant-btn-primary min-w-[120px]"
|
||||
onClick={onSave}
|
||||
>
|
||||
<i className="ri-save-line mr-1"></i> {isEditMode ? '保存修改' : '保存'}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="ant-btn ant-btn-default min-w-[120px] !hidden"
|
||||
onClick={onSaveDraft}
|
||||
>
|
||||
<i className="ri-draft-line mr-1"></i> {isEditMode ? '另存为草稿' : '保存草稿'}
|
||||
</button>
|
||||
{showButtons && (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
className="ant-btn ant-btn-primary min-w-[120px]"
|
||||
onClick={onSave}
|
||||
>
|
||||
<i className="ri-save-line mr-1"></i> {isEditMode ? '保存修改' : '保存'}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="ant-btn ant-btn-default min-w-[120px] !hidden"
|
||||
onClick={onSaveDraft}
|
||||
>
|
||||
<i className="ri-draft-line mr-1"></i> {isEditMode ? '另存为草稿' : '保存草稿'}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
<Button
|
||||
type="default"
|
||||
className="min-w-[120px] focus:!ring-gray-300"
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
interface PageHeaderProps {
|
||||
title: string;
|
||||
onSave?: () => void;
|
||||
showSaveButton?: boolean;
|
||||
}
|
||||
|
||||
export function PageHeader({ title, onSave }: PageHeaderProps) {
|
||||
export function PageHeader({ title, onSave, showSaveButton = true }: PageHeaderProps) {
|
||||
return (
|
||||
<div className="flex justify-between items-center pb-2 mb-4 border-b border-gray-200">
|
||||
<h1 className="text-xl font-medium text-gray-800">{title}</h1>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
className="ant-btn ant-btn-primary"
|
||||
onClick={onSave}
|
||||
>
|
||||
<i className="ri-save-line mr-1"></i> 保存
|
||||
</button>
|
||||
{showSaveButton && (
|
||||
<button
|
||||
type="button"
|
||||
className="ant-btn ant-btn-primary"
|
||||
onClick={onSave}
|
||||
>
|
||||
<i className="ri-save-line mr-1"></i> 保存
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -243,7 +243,7 @@ export function ReviewSettings({
|
||||
}
|
||||
|
||||
// 记录初始化处理
|
||||
console.log("ReviewSettings开始初始化,数据:", initialData);
|
||||
// console.log("ReviewSettings开始初始化,数据:", initialData);
|
||||
|
||||
// 保存初始数据引用,用于后续比较
|
||||
initialDataRef.current = JSON.parse(JSON.stringify(initialData));
|
||||
@@ -255,7 +255,7 @@ export function ReviewSettings({
|
||||
if (initialData) {
|
||||
// 处理初始规则数据
|
||||
if (initialData.rules && Array.isArray(initialData.rules) && initialData.rules.length > 0) {
|
||||
console.log("设置初始规则数据:", initialData.rules);
|
||||
// console.log("设置初始规则数据:", initialData.rules);
|
||||
|
||||
const validRules = initialData.rules.map(rule => {
|
||||
// 确保每个规则都有id
|
||||
@@ -394,7 +394,7 @@ export function ReviewSettings({
|
||||
const newFields = uniqueFields.filter((field: string) => !availableFields.includes(field));
|
||||
|
||||
if (newFields.length > 0 || deletedFields.length > 0) {
|
||||
console.log('Updating fields in checkAndUpdateFields - deleted:', deletedFields, 'new:', newFields);
|
||||
// console.log('Updating fields in checkAndUpdateFields - deleted:', deletedFields, 'new:', newFields);
|
||||
// 设置最新的可用字段列表
|
||||
setAvailableFields(uniqueFields);
|
||||
|
||||
@@ -420,7 +420,7 @@ export function ReviewSettings({
|
||||
|
||||
// 处理已删除字段的函数
|
||||
const handleDeletedFields = (deletedFields: string[]) => {
|
||||
console.log("处理已删除字段:", deletedFields);
|
||||
// console.log("处理已删除字段:", deletedFields);
|
||||
|
||||
// 如果没有删除的字段,则直接返回
|
||||
if (!deletedFields || deletedFields.length === 0) return;
|
||||
@@ -513,7 +513,7 @@ export function ReviewSettings({
|
||||
|
||||
// 如果配置有实质性修改,记录日志
|
||||
if (configModified) {
|
||||
console.log(`规则(ID: ${rule.id}, 类型: ${rule.type})已清除对已删除字段的引用`);
|
||||
// console.log(`规则(ID: ${rule.id}, 类型: ${rule.type})已清除对已删除字段的引用`);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -877,7 +877,7 @@ export function ReviewSettings({
|
||||
!(config.availableFields as string[]).every((field) => availableFields.includes(field))))) {
|
||||
// 延迟更新以避免在渲染过程中修改状态
|
||||
setTimeout(() => {
|
||||
console.log('Updating rule config with new available fields:', availableFields);
|
||||
// console.log('Updating rule config with new available fields:', availableFields);
|
||||
const updatedConfig = { ...config, availableFields: availableFields };
|
||||
handleRuleConfigChange(id, updatedConfig);
|
||||
}, 0);
|
||||
@@ -915,7 +915,7 @@ export function ReviewSettings({
|
||||
value="and"
|
||||
checked={!config.logic || config.logic === 'and'}
|
||||
onChange={(e) => {
|
||||
console.log(`[调试] 选择判断逻辑 and,规则ID: ${id}, 当前值: ${config.logic}`);
|
||||
// console.log(`[调试] 选择判断逻辑 and,规则ID: ${id}, 当前值: ${config.logic}`);
|
||||
handleRuleConfigChange(id, { logic: e.target.value });
|
||||
// 直接触发配置更新
|
||||
generateEvaluationConfig();
|
||||
@@ -932,7 +932,7 @@ export function ReviewSettings({
|
||||
value="or"
|
||||
checked={config.logic === 'or'}
|
||||
onChange={(e) => {
|
||||
console.log(`[调试] 选择判断逻辑 or,规则ID: ${id}, 当前值: ${config.logic}`);
|
||||
// console.log(`[调试] 选择判断逻辑 or,规则ID: ${id}, 当前值: ${config.logic}`);
|
||||
handleRuleConfigChange(id, { logic: e.target.value });
|
||||
// 直接触发配置更新
|
||||
generateEvaluationConfig();
|
||||
|
||||
@@ -93,12 +93,12 @@ export function DateRangePicker({
|
||||
try {
|
||||
// 检查并记录showPicker是否可用
|
||||
const hasShowPicker = typeof inputRef.current.showPicker === 'function';
|
||||
console.log('showPicker API available:', hasShowPicker);
|
||||
// console.log('showPicker API available:', hasShowPicker);
|
||||
|
||||
// 尝试使用showPicker API
|
||||
if (hasShowPicker) {
|
||||
inputRef.current.showPicker();
|
||||
console.log('showPicker called successfully');
|
||||
// console.log('showPicker called successfully');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to show date picker:', error);
|
||||
@@ -236,7 +236,7 @@ export function SimpleDateRangePicker({
|
||||
// 处理日期输入框全局点击
|
||||
const handleWrapperClick = (inputRef: React.RefObject<HTMLInputElement>) => {
|
||||
if (inputRef.current) {
|
||||
console.log('Wrapper clicked, triggering date input');
|
||||
// console.log('Wrapper clicked, triggering date input');
|
||||
// 点击整个包装器区域时,触发输入框点击
|
||||
inputRef.current.focus();
|
||||
inputRef.current.click();
|
||||
@@ -244,12 +244,12 @@ export function SimpleDateRangePicker({
|
||||
try {
|
||||
// 检查并记录showPicker是否可用
|
||||
const hasShowPicker = typeof inputRef.current.showPicker === 'function';
|
||||
console.log('showPicker API available:', hasShowPicker);
|
||||
// console.log('showPicker API available:', hasShowPicker);
|
||||
|
||||
// 尝试使用showPicker API
|
||||
if (hasShowPicker) {
|
||||
inputRef.current.showPicker();
|
||||
console.log('showPicker called successfully');
|
||||
// console.log('showPicker called successfully');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to show date picker:', error);
|
||||
|
||||
@@ -24,6 +24,8 @@ export interface TooltipProps {
|
||||
className?: string; // 自定义类名
|
||||
onVisibleChange?: (visible: boolean) => void; // 显示状态变化回调
|
||||
fixedPlacement?: boolean; // 是否固定显示位置,不自动切换
|
||||
maxHeight?: number | string; // 最大高度,超出将显示滚动条
|
||||
scrollable?: boolean; // 是否可滚动
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,7 +47,9 @@ export function Tooltip({
|
||||
maxWidth = 320,
|
||||
className = '',
|
||||
onVisibleChange,
|
||||
fixedPlacement = false // 默认不固定位置
|
||||
fixedPlacement = false, // 默认不固定位置
|
||||
maxHeight = 300, // 默认最大高度300px
|
||||
scrollable = true // 默认允许滚动
|
||||
}: TooltipProps) {
|
||||
// 使用内部状态管理提示框显示状态(非受控模式)
|
||||
const [visible, setVisible] = useState(false);
|
||||
@@ -59,6 +63,7 @@ export function Tooltip({
|
||||
// 引用DOM元素
|
||||
const triggerRef = useRef<HTMLDivElement>(null);
|
||||
const tooltipRef = useRef<HTMLDivElement>(null);
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// 保存当前实际显示位置
|
||||
const [actualPlacement, setActualPlacement] = useState<TooltipPlacement>(placement);
|
||||
@@ -99,6 +104,17 @@ export function Tooltip({
|
||||
? `${maxWidth}px`
|
||||
: String(maxWidth);
|
||||
|
||||
// 如果内容可滚动,设置最大高度,但仅应用于内容容器而不是整个tooltip
|
||||
if (scrollable && contentRef.current) {
|
||||
contentRef.current.style.maxHeight = typeof maxHeight === 'number'
|
||||
? `${maxHeight}px`
|
||||
: String(maxHeight);
|
||||
|
||||
// 确保只有内容区域显示滚动条,整个tooltip容器不滚动
|
||||
contentRef.current.style.overflowY = 'auto';
|
||||
tooltipRef.current.style.overflow = 'visible';
|
||||
}
|
||||
|
||||
// 计算各个方向的位置
|
||||
let top = 0, left = 0;
|
||||
let arrowTop = 0, arrowLeft = 0;
|
||||
@@ -154,7 +170,7 @@ export function Tooltip({
|
||||
if (top < 0) {
|
||||
if (currentPlacement === 'top') {
|
||||
// 如果上方放不下,切换到下方
|
||||
top = triggerRect.bottom + arrowSize;
|
||||
top = triggerRect.bottom + arrowSize - 8;
|
||||
arrowTop = -arrowSize;
|
||||
|
||||
// 更新实际位置为bottom
|
||||
@@ -347,19 +363,22 @@ export function Tooltip({
|
||||
|
||||
// 渲染提示框内容
|
||||
const renderTooltipContent = () => {
|
||||
// 根据是否启用滚动来确定内容容器类名
|
||||
const contentClassName = scrollable ? 'tooltip-content-inner tooltip-scrollable' : 'tooltip-content-inner';
|
||||
|
||||
if (rich) {
|
||||
return (
|
||||
<div className="tooltip-content">
|
||||
<div className="tooltip-content" ref={contentRef}>
|
||||
{header && <div className="tooltip-header">{header}</div>}
|
||||
<div className="tooltip-body">{content}</div>
|
||||
<div className={contentClassName}>{content}</div>
|
||||
{footer && <div className="tooltip-footer">{footer}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="tooltip-content">
|
||||
<div>{content}</div>
|
||||
<div className="tooltip-content" ref={contentRef}>
|
||||
<div className={contentClassName}>{content}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
+128
-134
@@ -9,14 +9,14 @@ import {
|
||||
isRouteErrorResponse,
|
||||
useRouteError,
|
||||
type MetaFunction,
|
||||
// useLoaderData
|
||||
useLoaderData
|
||||
} from "@remix-run/react";
|
||||
// import {
|
||||
// LoaderFunctionArgs,
|
||||
// redirect,
|
||||
// createCookieSessionStorage,
|
||||
// ActionFunctionArgs
|
||||
// } from "@remix-run/node";
|
||||
import {
|
||||
LoaderFunctionArgs,
|
||||
redirect,
|
||||
createCookieSessionStorage,
|
||||
ActionFunctionArgs
|
||||
} from "@remix-run/node";
|
||||
import { Layout } from "~/components/layout/Layout";
|
||||
import { ErrorBoundary as AppErrorBoundary } from "~/components/error/ErrorBoundary";
|
||||
import { MessageModalProvider } from "~/components/ui/MessageModal";
|
||||
@@ -30,115 +30,127 @@ import LoadingBarContainer from "~/components/ui/LoadingBar";
|
||||
import RouteChangeLoader from "~/components/ui/RouteChangeLoader";
|
||||
// import { useState, useEffect } from "react";
|
||||
|
||||
// 定义用户角色类型
|
||||
export type UserRole = 'common' | 'developer';
|
||||
|
||||
// 定义需要高级权限的路径
|
||||
export const developerOnlyPaths = [
|
||||
'/settings',
|
||||
'/config-lists',
|
||||
'/document-types',
|
||||
'/prompts'
|
||||
];
|
||||
|
||||
// 创建基于Cookie的会话存储
|
||||
// 在实际应用中,应该使用环境变量来设置密钥
|
||||
// const sessionStorage = createCookieSessionStorage({
|
||||
// cookie: {
|
||||
// name: "__session",
|
||||
// httpOnly: true,
|
||||
// path: "/",
|
||||
// sameSite: "lax",
|
||||
// secrets: ["s3cr3t"], // 应该从环境变量读取
|
||||
// secure: process.env.NODE_ENV === "production",
|
||||
// },
|
||||
// });
|
||||
const sessionStorage = createCookieSessionStorage({
|
||||
cookie: {
|
||||
name: "__session",
|
||||
httpOnly: true,
|
||||
path: "/",
|
||||
sameSite: "lax",
|
||||
secrets: ["s3cr3t"], // 应该从环境变量读取
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
},
|
||||
});
|
||||
|
||||
// // 获取会话对象
|
||||
// export async function getSession(request: Request) {
|
||||
// const cookie = request.headers.get("Cookie");
|
||||
// return sessionStorage.getSession(cookie);
|
||||
// }
|
||||
// 获取会话对象
|
||||
export async function getSession(request: Request) {
|
||||
const cookie = request.headers.get("Cookie");
|
||||
return sessionStorage.getSession(cookie);
|
||||
}
|
||||
|
||||
// // 获取用户登录状态
|
||||
// export async function getUserSession(request: Request) {
|
||||
// const session = await getSession(request);
|
||||
// return {
|
||||
// isAuthenticated: session.get("isAuthenticated") === true,
|
||||
// };
|
||||
// }
|
||||
// 获取用户登录状态
|
||||
export async function getUserSession(request: Request) {
|
||||
const session = await getSession(request);
|
||||
return {
|
||||
isAuthenticated: session.get("isAuthenticated") === true,
|
||||
userRole: session.get("userRole") || 'common' as UserRole
|
||||
};
|
||||
}
|
||||
|
||||
// // 创建登录会话
|
||||
// export async function createUserSession(isAuthenticated: boolean, redirectTo: string) {
|
||||
// const session = await sessionStorage.getSession();
|
||||
// session.set("isAuthenticated", isAuthenticated);
|
||||
// 创建登录会话
|
||||
export async function createUserSession(isAuthenticated: boolean, userRole: UserRole, redirectTo: string) {
|
||||
const session = await sessionStorage.getSession();
|
||||
session.set("isAuthenticated", isAuthenticated);
|
||||
session.set("userRole", userRole);
|
||||
|
||||
// return redirect(redirectTo, {
|
||||
// headers: {
|
||||
// "Set-Cookie": await sessionStorage.commitSession(session),
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
return redirect(redirectTo, {
|
||||
headers: {
|
||||
"Set-Cookie": await sessionStorage.commitSession(session),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// // 销毁会话(登出)
|
||||
// export async function logout(request: Request) {
|
||||
// const session = await getSession(request);
|
||||
// 销毁会话(登出)
|
||||
export async function logout(request: Request) {
|
||||
const session = await getSession(request);
|
||||
|
||||
// return redirect("/login", {
|
||||
// headers: {
|
||||
// "Set-Cookie": await sessionStorage.destroySession(session),
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
return redirect("/login", {
|
||||
headers: {
|
||||
"Set-Cookie": await sessionStorage.destroySession(session),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// // 添加action处理登录/登出请求
|
||||
// export async function action({ request }: ActionFunctionArgs) {
|
||||
// const formData = await request.formData();
|
||||
// const intent = formData.get("intent");
|
||||
// 添加action处理登录/登出请求
|
||||
export async function action({ request }: ActionFunctionArgs) {
|
||||
const formData = await request.formData();
|
||||
const intent = formData.get("intent");
|
||||
|
||||
// if (intent === "logout") {
|
||||
// return logout(request);
|
||||
// }
|
||||
if (intent === "logout") {
|
||||
return logout(request);
|
||||
}
|
||||
|
||||
// return null;
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
// // 添加loader函数进行全局认证检查
|
||||
// export async function loader({ request }: LoaderFunctionArgs) {
|
||||
// // 获取当前路径
|
||||
// const url = new URL(request.url);
|
||||
// const pathname = url.pathname;
|
||||
// 添加loader函数进行全局认证检查
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
// 获取当前路径
|
||||
const url = new URL(request.url);
|
||||
const pathname = url.pathname;
|
||||
|
||||
// // 排除不需要登录验证的路径
|
||||
// const publicPaths = ['/login', '/favicon.ico'];
|
||||
// const isPublicPath = publicPaths.some(path => pathname.startsWith(path));
|
||||
// 排除不需要登录验证的路径
|
||||
const publicPaths = ['/login', '/favicon.ico'];
|
||||
const isPublicPath = publicPaths.some(path => pathname.startsWith(path));
|
||||
|
||||
// // 获取用户会话
|
||||
// const { isAuthenticated } = await getUserSession(request);
|
||||
// 获取用户会话
|
||||
const { isAuthenticated, userRole } = await getUserSession(request);
|
||||
// console.log("Auth status:", { isAuthenticated, userRole, pathname });
|
||||
|
||||
// // 如果访问需要认证的路径但未登录,重定向到登录页
|
||||
// if (!isPublicPath && !isAuthenticated) {
|
||||
// // 保存请求的URL,以便登录后重定向回来
|
||||
// const session = await getSession(request);
|
||||
// session.set("redirectTo", pathname);
|
||||
// 如果访问需要认证的路径但未登录,重定向到登录页
|
||||
if (!isPublicPath && !isAuthenticated) {
|
||||
// 保存请求的URL,以便登录后重定向回来
|
||||
const session = await getSession(request);
|
||||
|
||||
// return redirect("/login", {
|
||||
// headers: {
|
||||
// "Set-Cookie": await sessionStorage.commitSession(session),
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// 如果路径是/home,则将重定向目标设置为/
|
||||
const redirectTarget = pathname === "/home" ? "/" : pathname;
|
||||
// 保存重定向目标
|
||||
session.set("redirectTo", redirectTarget);
|
||||
|
||||
return redirect("/login", {
|
||||
headers: {
|
||||
"Set-Cookie": await sessionStorage.commitSession(session),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// // 如果已登录且访问登录页,重定向到首页
|
||||
// if (pathname === "/login" && isAuthenticated) {
|
||||
// return redirect("/home");
|
||||
// }
|
||||
// 如果已登录且访问登录页,重定向到首页
|
||||
if (pathname === "/login" && isAuthenticated) {
|
||||
// console.log("Already authenticated, redirecting from login to /");
|
||||
return redirect("/");
|
||||
}
|
||||
|
||||
// // 向组件传递认证状态和当前路径
|
||||
// return Response.json({ isAuthenticated, pathname });
|
||||
// }
|
||||
// 检查访问权限 - 如果是common用户访问了开发者专属页面,重定向到首页
|
||||
if (userRole === 'common' && developerOnlyPaths.some(path => pathname.startsWith(path))) {
|
||||
return redirect("/");
|
||||
}
|
||||
|
||||
// 向组件传递认证状态和当前路径
|
||||
return Response.json({ isAuthenticated, userRole, pathname });
|
||||
}
|
||||
|
||||
// 添加客户端hydration错误处理
|
||||
// if (typeof window !== "undefined") {
|
||||
// window.addEventListener("error", (event) => {
|
||||
// if (event.message && event.message.includes("Hydration failed")) {
|
||||
// console.warn("Hydration error detected, refreshing page...");
|
||||
// setTimeout(() => {
|
||||
// window.location.reload();
|
||||
// }, 100);
|
||||
// event.preventDefault();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
export const meta: MetaFunction = () => {
|
||||
return [
|
||||
@@ -163,11 +175,8 @@ export function links() {
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
// const { pathname } = useLoaderData<typeof loader>();
|
||||
const { userRole } = useLoaderData<typeof loader>();
|
||||
|
||||
// // 确定哪些路径不需要Layout
|
||||
// const noLayoutPaths = ['/login', '/home'];
|
||||
// const needsLayout = !noLayoutPaths.includes(pathname);
|
||||
|
||||
return (
|
||||
<html lang="zh-CN">
|
||||
@@ -193,18 +202,9 @@ export default function App() {
|
||||
<body className="font-sans">
|
||||
<MessageModalProvider>
|
||||
<ToastProvider>
|
||||
{/* {needsLayout ? (
|
||||
<Layout>
|
||||
<Outlet />
|
||||
</Layout>
|
||||
) : (
|
||||
<Layout userRole={userRole}>
|
||||
<Outlet />
|
||||
)} */}
|
||||
|
||||
<Layout>
|
||||
<Outlet />
|
||||
</Layout>
|
||||
|
||||
</Layout>
|
||||
<RouteChangeLoader />
|
||||
</ToastProvider>
|
||||
</MessageModalProvider>
|
||||
@@ -219,38 +219,32 @@ export default function App() {
|
||||
export function ErrorBoundary() {
|
||||
const error = useRouteError();
|
||||
|
||||
// 为错误页面设置标题和描述
|
||||
let title = "发生错误";
|
||||
let message = "发生了一个未知错误,请稍后重试";
|
||||
|
||||
if (isRouteErrorResponse(error)) {
|
||||
return (
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<Meta />
|
||||
<Links />
|
||||
<title>错误 {error.status}</title>
|
||||
</head>
|
||||
<body>
|
||||
<AppErrorBoundary
|
||||
status={error.status}
|
||||
statusText={error.statusText}
|
||||
message={error.data?.message || "发生了一个错误,请稍后重试"}
|
||||
/>
|
||||
<Scripts />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
title = `错误 ${error.status}`;
|
||||
message = error.data?.message || "发生了一个错误,请稍后重试";
|
||||
} else {
|
||||
title = "意外错误";
|
||||
message = "服务器发生了意外错误,请稍后重试";
|
||||
}
|
||||
|
||||
return (
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<Meta />
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<meta name="description" content={message} />
|
||||
<title>{title}</title>
|
||||
<Links />
|
||||
<title>意外错误</title>
|
||||
</head>
|
||||
<body>
|
||||
<AppErrorBoundary
|
||||
status={500}
|
||||
statusText="服务器错误"
|
||||
message="服务器发生了意外错误,请稍后重试"
|
||||
status={isRouteErrorResponse(error) ? error.status : 500}
|
||||
statusText={isRouteErrorResponse(error) ? error.statusText : "服务器错误"}
|
||||
message={message}
|
||||
/>
|
||||
<Scripts />
|
||||
</body>
|
||||
|
||||
+19
-12
@@ -3,7 +3,7 @@ import { useNavigate, Form } from '@remix-run/react';
|
||||
import { type MetaFunction, type ActionFunctionArgs, LoaderFunctionArgs, redirect } from "@remix-run/node";
|
||||
import styles from "~/styles/pages/home.css?url";
|
||||
import dayjs from 'dayjs';
|
||||
// import { getUserSession, logout } from "~/root";
|
||||
import { getUserSession, logout } from "~/root";
|
||||
|
||||
export const links = () => [
|
||||
{ rel: "stylesheet", href: styles }
|
||||
@@ -22,22 +22,21 @@ export async function action({ request }: ActionFunctionArgs) {
|
||||
const intent = formData.get("intent");
|
||||
|
||||
if (intent === "logout") {
|
||||
// return logout(request);
|
||||
return logout(request);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// 验证用户登录状态
|
||||
// export async function loader({ request }: LoaderFunctionArgs) {
|
||||
// const { isAuthenticated } = await getUserSession(request);
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const { isAuthenticated } = await getUserSession(request);
|
||||
|
||||
// if (!isAuthenticated) {
|
||||
// return redirect("/login");
|
||||
// }
|
||||
|
||||
// return Response.json({ isAuthenticated });
|
||||
// }
|
||||
if (!isAuthenticated) {
|
||||
return redirect("/login");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export default function Index() {
|
||||
const navigate = useNavigate();
|
||||
@@ -68,6 +67,7 @@ export default function Index() {
|
||||
|
||||
// 处理模块点击
|
||||
const handleModuleClick = (path: string) => {
|
||||
// console.log("导航到路径:", path);
|
||||
navigate(path);
|
||||
};
|
||||
|
||||
@@ -80,6 +80,13 @@ export default function Index() {
|
||||
|
||||
// 处理登出
|
||||
const handleLogout = () => {
|
||||
// 清除sessionStorage中的用户角色信息
|
||||
if (typeof window !== 'undefined') {
|
||||
sessionStorage.removeItem('userRole');
|
||||
// 可以根据需要清除其他会话数据
|
||||
sessionStorage.clear();
|
||||
}
|
||||
|
||||
// 使用Form组件提交登出请求
|
||||
const form = document.getElementById('logout-form') as HTMLFormElement;
|
||||
if (form) {
|
||||
@@ -127,8 +134,8 @@ export default function Index() {
|
||||
{/* 合同管理模块 */}
|
||||
<div
|
||||
className="module-card"
|
||||
onClick={() => handleModuleClick('/documents')}
|
||||
onKeyDown={(e) => handleKeyDown('/documents', e)}
|
||||
onClick={() => handleModuleClick('/contract-template/search')}
|
||||
onKeyDown={(e) => handleKeyDown('/contract-template/search', e)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="合同管理"
|
||||
|
||||
@@ -45,8 +45,8 @@ export async function loader({ params }: LoaderFunctionArgs) {
|
||||
}
|
||||
|
||||
// 添加调试信息
|
||||
console.log('模板详情数据:', response.data);
|
||||
console.log('分类信息:', response.data.category);
|
||||
// console.log('模板详情数据:', response.data);
|
||||
// console.log('分类信息:', response.data.category);
|
||||
|
||||
return { template: response.data };
|
||||
} catch (error) {
|
||||
@@ -90,7 +90,7 @@ export default function ContractTemplateDetail() {
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
console.log('开始下载文件:', cleanFileName);
|
||||
// console.log('开始下载文件:', cleanFileName);
|
||||
} catch (error) {
|
||||
console.error('下载文件失败:', error);
|
||||
alert('下载失败,请稍后重试');
|
||||
@@ -108,7 +108,7 @@ export default function ContractTemplateDetail() {
|
||||
};
|
||||
|
||||
const handlePreview = () => {
|
||||
console.log('预览模板:', template.id);
|
||||
// console.log('预览模板:', template.id);
|
||||
// 页面内预览,滚动到预览区域
|
||||
const previewElement = document.getElementById('template-preview');
|
||||
if (previewElement) {
|
||||
|
||||
@@ -296,7 +296,7 @@ export default function DocumentEdit() {
|
||||
|
||||
const onDocumentLoadSuccess = ({numPages}: {numPages: number}) => {
|
||||
setNumPages(numPages);
|
||||
console.log('文档加载成功', numPages);
|
||||
// console.log('文档加载成功', numPages);
|
||||
}
|
||||
|
||||
const renderDocumentContent = () => {
|
||||
|
||||
+77
-77
@@ -121,7 +121,7 @@ async function uploadFileToServer(
|
||||
isTestDocument: boolean
|
||||
): Promise<FileUploadResponse> {
|
||||
// 在实际应用中,这里会使用fetch或axios发送请求到后端API
|
||||
console.log(`[API] 上传文件: ${fileName}, 大小: ${binaryData.byteLength} 字节`);
|
||||
// console.log(`[API] 上传文件: ${fileName}, 大小: ${binaryData.byteLength} 字节`);
|
||||
|
||||
try {
|
||||
// 使用封装的上传函数
|
||||
@@ -206,7 +206,7 @@ export async function action({ request }: ActionFunctionArgs) {
|
||||
|
||||
// 获取文件信息
|
||||
if (fileUpload) {
|
||||
console.log(`接收到文件: ${fileUpload.name}, 大小: ${fileUpload.size}, 类型: ${fileUpload.type}`);
|
||||
// console.log(`接收到文件: ${fileUpload.name}, 大小: ${fileUpload.size}, 类型: ${fileUpload.type}`);
|
||||
}
|
||||
|
||||
// 注意: 在实际的Remix action中,我们无法直接处理文件内容
|
||||
@@ -356,7 +356,7 @@ export default function FilesUpload() {
|
||||
|
||||
// useEffect 处理上传队列状态检查定时器 - 只在组件卸载时清除
|
||||
useEffect(() => {
|
||||
console.log('设置上传队列状态检查定时器');
|
||||
// console.log('设置上传队列状态检查定时器');
|
||||
|
||||
// 标记组件已挂载
|
||||
isMountedRef.current = true;
|
||||
@@ -367,7 +367,7 @@ export default function FilesUpload() {
|
||||
|
||||
// 只在组件卸载时清除
|
||||
return () => {
|
||||
console.log('组件卸载,清除上传队列状态检查定时器');
|
||||
// console.log('组件卸载,清除上传队列状态检查定时器');
|
||||
// 标记组件已卸载
|
||||
isMountedRef.current = false;
|
||||
if (statusCheckIntervalRef.current) {
|
||||
@@ -387,16 +387,16 @@ export default function FilesUpload() {
|
||||
.filter(file => file.status !== DocumentStatus.PROCESSED && file.id)
|
||||
.map(file => file.id);
|
||||
|
||||
console.log('未完成的文档ID:', incompleteIds);
|
||||
// console.log('未完成的文档ID:', incompleteIds);
|
||||
|
||||
if (incompleteIds.length === 0) {
|
||||
console.log('没有未完成的文档,跳过状态检查');
|
||||
// console.log('没有未完成的文档,跳过状态检查');
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取这些文档的最新状态
|
||||
const statusResponse = await getDocumentsStatus(incompleteIds);
|
||||
console.log('状态检查响应:', statusResponse);
|
||||
// console.log('状态检查响应:', statusResponse);
|
||||
|
||||
if (statusResponse.data) {
|
||||
// 更新队列中的文档状态
|
||||
@@ -404,7 +404,7 @@ export default function FilesUpload() {
|
||||
const updatedFiles = prevFiles.map(file => {
|
||||
const updatedStatus = statusResponse.data.find(doc => doc.id === file.id);
|
||||
if (updatedStatus) {
|
||||
console.log(`文档 ${file.id} 状态更新: ${file.status} -> ${updatedStatus.status}`);
|
||||
// console.log(`文档 ${file.id} 状态更新: ${file.status} -> ${updatedStatus.status}`);
|
||||
return { ...file, status: updatedStatus.status };
|
||||
}
|
||||
return file;
|
||||
@@ -456,7 +456,7 @@ export default function FilesUpload() {
|
||||
const value = e.target.value;
|
||||
// 确保只有选择了有效的文件类型才进行设置
|
||||
if (value) {
|
||||
console.log('【调试-handleFileTypeChange】文件类型变更为:', value);
|
||||
// console.log('【调试-handleFileTypeChange】文件类型变更为:', value);
|
||||
setFileType(value as FileType);
|
||||
// 立即清除错误状态
|
||||
setFileTypeError(null);
|
||||
@@ -464,12 +464,12 @@ export default function FilesUpload() {
|
||||
// 检查是否选择了合同类型
|
||||
const selectedType = documentTypes.find(t => t.id.toString() === value);
|
||||
const isContract = !!(selectedType && selectedType.name.includes('合同'));
|
||||
console.log('【调试-handleFileTypeChange】文件类型检查:', {
|
||||
selectedType,
|
||||
isContract,
|
||||
typeName: selectedType?.name,
|
||||
currentFiles: currentFiles.length
|
||||
});
|
||||
// console.log('【调试-handleFileTypeChange】文件类型检查:', {
|
||||
// selectedType,
|
||||
// isContract,
|
||||
// typeName: selectedType?.name,
|
||||
// currentFiles: currentFiles.length
|
||||
// });
|
||||
|
||||
setIsContractType(isContract);
|
||||
|
||||
@@ -480,10 +480,10 @@ export default function FilesUpload() {
|
||||
|
||||
// 如果已经有选中的文件,且选择了文件类型,且不是合同类型,则开始上传
|
||||
if (currentFiles.length > 0 && !isContract) {
|
||||
console.log('【调试-handleFileTypeChange】自动开始上传非合同类型文件');
|
||||
// console.log('【调试-handleFileTypeChange】自动开始上传非合同类型文件');
|
||||
startUpload(currentFiles);
|
||||
} else if (currentFiles.length > 0 && isContract) {
|
||||
console.log('【调试-handleFileTypeChange】合同类型需要手动点击开始上传按钮');
|
||||
// console.log('【调试-handleFileTypeChange】合同类型需要手动点击开始上传按钮');
|
||||
// 合同类型不自动上传,需要用户先上传主文件和附件,然后点击开始上传按钮
|
||||
setCurrentFiles([]);
|
||||
}
|
||||
@@ -499,11 +499,11 @@ export default function FilesUpload() {
|
||||
// 处理合同主文件选择
|
||||
const handleContractMainFilesSelected = (files: FileList) => {
|
||||
try {
|
||||
console.log('【调试-handleContractMainFilesSelected】开始处理合同主文件选择, 文件数量:', files.length);
|
||||
// console.log('【调试-handleContractMainFilesSelected】开始处理合同主文件选择, 文件数量:', files.length);
|
||||
|
||||
// 检查组件是否已卸载
|
||||
if (!isMountedRef.current) {
|
||||
console.error('【调试-handleContractMainFilesSelected】组件已卸载,取消处理');
|
||||
// console.error('【调试-handleContractMainFilesSelected】组件已卸载,取消处理');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -532,15 +532,15 @@ export default function FilesUpload() {
|
||||
}
|
||||
|
||||
if (validFiles.length > 0 && isMountedRef.current) {
|
||||
console.log('【调试-handleContractMainFilesSelected】有效文件数量:', validFiles.length);
|
||||
console.log('【调试-handleContractMainFilesSelected】有效文件:', validFiles.map(f => ({ name: f.name, size: f.size, type: f.type })));
|
||||
// console.log('【调试-handleContractMainFilesSelected】有效文件数量:', validFiles.length);
|
||||
// console.log('【调试-handleContractMainFilesSelected】有效文件:', validFiles.map(f => ({ name: f.name, size: f.size, type: f.type })));
|
||||
|
||||
setContractMainFiles(validFiles);
|
||||
} else {
|
||||
console.error('【调试-handleContractMainFilesSelected】没有有效的PDF文件或组件已卸载');
|
||||
}
|
||||
} else {
|
||||
console.log('【调试-handleContractMainFilesSelected】未选择任何文件');
|
||||
// console.log('【调试-handleContractMainFilesSelected】未选择任何文件');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('【调试-handleContractMainFilesSelected】处理合同主文件选择时发生错误:', error);
|
||||
@@ -550,7 +550,7 @@ export default function FilesUpload() {
|
||||
// 处理合同附件选择
|
||||
const handleContractAttachmentFilesSelected = (files: FileList) => {
|
||||
try {
|
||||
console.log('【调试-handleContractAttachmentFilesSelected】开始处理合同附件选择, 文件数量:', files.length);
|
||||
// console.log('【调试-handleContractAttachmentFilesSelected】开始处理合同附件选择, 文件数量:', files.length);
|
||||
|
||||
// 检查组件是否已卸载
|
||||
if (!isMountedRef.current) {
|
||||
@@ -583,15 +583,15 @@ export default function FilesUpload() {
|
||||
}
|
||||
|
||||
if (validFiles.length > 0 && isMountedRef.current) {
|
||||
console.log('【调试-handleContractAttachmentFilesSelected】有效文件数量:', validFiles.length);
|
||||
console.log('【调试-handleContractAttachmentFilesSelected】有效文件:', validFiles.map(f => ({ name: f.name, size: f.size, type: f.type })));
|
||||
// console.log('【调试-handleContractAttachmentFilesSelected】有效文件数量:', validFiles.length);
|
||||
// console.log('【调试-handleContractAttachmentFilesSelected】有效文件:', validFiles.map(f => ({ name: f.name, size: f.size, type: f.type })));
|
||||
|
||||
setContractAttachmentFiles(validFiles);
|
||||
} else {
|
||||
console.error('【调试-handleContractAttachmentFilesSelected】没有有效的PDF文件或组件已卸载');
|
||||
}
|
||||
} else {
|
||||
console.log('【调试-handleContractAttachmentFilesSelected】未选择任何文件');
|
||||
// console.log('【调试-handleContractAttachmentFilesSelected】未选择任何文件');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('【调试-handleContractAttachmentFilesSelected】处理合同附件选择时发生错误:', error);
|
||||
@@ -601,11 +601,11 @@ export default function FilesUpload() {
|
||||
// 检查并准备上传
|
||||
const checkAndPrepareUpload = (mainFiles: File[], attachmentFiles: File[]) => {
|
||||
try {
|
||||
console.log('【调试-checkAndPrepareUpload】开始检查并准备上传文件', {
|
||||
mainFilesCount: mainFiles.length,
|
||||
attachmentFilesCount: attachmentFiles.length,
|
||||
fileType
|
||||
});
|
||||
// console.log('【调试-checkAndPrepareUpload】开始检查并准备上传文件', {
|
||||
// mainFilesCount: mainFiles.length,
|
||||
// attachmentFilesCount: attachmentFiles.length,
|
||||
// fileType
|
||||
// });
|
||||
|
||||
// 检查组件是否已卸载
|
||||
if (!isMountedRef.current) {
|
||||
@@ -624,14 +624,14 @@ export default function FilesUpload() {
|
||||
const selectedType = documentTypes.find(t => t.id.toString() === fileType);
|
||||
const isContract = !!(selectedType && selectedType.name.includes('合同'));
|
||||
|
||||
console.log('【调试-checkAndPrepareUpload】文件类型检查', {
|
||||
selectedType,
|
||||
isContract,
|
||||
typeName: selectedType?.name
|
||||
});
|
||||
// console.log('【调试-checkAndPrepareUpload】文件类型检查', {
|
||||
// selectedType,
|
||||
// isContract,
|
||||
// typeName: selectedType?.name
|
||||
// });
|
||||
|
||||
if (isContract) {
|
||||
console.log('【调试-checkAndPrepareUpload】合同文档类型特殊处理');
|
||||
// console.log('【调试-checkAndPrepareUpload】合同文档类型特殊处理');
|
||||
|
||||
// 检查主文件
|
||||
if(mainFiles.length === 0) {
|
||||
@@ -641,11 +641,11 @@ export default function FilesUpload() {
|
||||
}
|
||||
|
||||
// 记录主文件和附件文件信息
|
||||
console.log('【调试-checkAndPrepareUpload】合同主文件:', mainFiles.map(f => ({ name: f.name, size: f.size, type: f.type })));
|
||||
// console.log('【调试-checkAndPrepareUpload】合同主文件:', mainFiles.map(f => ({ name: f.name, size: f.size, type: f.type })));
|
||||
if (attachmentFiles.length > 0) {
|
||||
console.log('【调试-checkAndPrepareUpload】合同附件文件:', attachmentFiles.map(f => ({ name: f.name, size: f.size, type: f.type })));
|
||||
// console.log('【调试-checkAndPrepareUpload】合同附件文件:', attachmentFiles.map(f => ({ name: f.name, size: f.size, type: f.type })));
|
||||
} else {
|
||||
console.log('【调试-checkAndPrepareUpload】无合同附件文件');
|
||||
// console.log('【调试-checkAndPrepareUpload】无合同附件文件');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -658,7 +658,7 @@ export default function FilesUpload() {
|
||||
allFiles = [...allFiles, ...attachmentFiles];
|
||||
}
|
||||
|
||||
console.log('【调试-checkAndPrepareUpload】合并文件后总数:', allFiles.length);
|
||||
// console.log('【调试-checkAndPrepareUpload】合并文件后总数:', allFiles.length);
|
||||
|
||||
// 检查组件是否已卸载
|
||||
if (!isMountedRef.current) {
|
||||
@@ -670,7 +670,7 @@ export default function FilesUpload() {
|
||||
setCurrentFiles(allFiles);
|
||||
|
||||
// 将准备上传的操作移到这里,暂时不执行
|
||||
console.log('【调试-checkAndPrepareUpload】准备上传', allFiles.length, '个文件');
|
||||
// console.log('【调试-checkAndPrepareUpload】准备上传', allFiles.length, '个文件');
|
||||
|
||||
if (fileType) {
|
||||
try {
|
||||
@@ -680,7 +680,7 @@ export default function FilesUpload() {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('【调试-checkAndPrepareUpload】开始调用startUpload函数');
|
||||
// console.log('【调试-checkAndPrepareUpload】开始调用startUpload函数');
|
||||
|
||||
// 使用 setTimeout 延迟调用,确保状态已更新
|
||||
setTimeout(() => {
|
||||
@@ -725,7 +725,7 @@ export default function FilesUpload() {
|
||||
// 开始上传文件
|
||||
const startUpload = async (files: File[]) => {
|
||||
try {
|
||||
console.log('【调试-startUpload】开始上传过程,文件数量:', files.length);
|
||||
// console.log('【调试-startUpload】开始上传过程,文件数量:', files.length);
|
||||
|
||||
// 检查组件是否已卸载
|
||||
if (!isMountedRef.current) {
|
||||
@@ -750,7 +750,7 @@ export default function FilesUpload() {
|
||||
const totalSize = files.reduce((sum, file) => sum + file.size, 0);
|
||||
let uploadedSize = 0;
|
||||
|
||||
console.log('【调试-startUpload】总文件大小:', formatFileSize(totalSize));
|
||||
// console.log('【调试-startUpload】总文件大小:', formatFileSize(totalSize));
|
||||
|
||||
// 更新步骤状态
|
||||
const updatedSteps = [...processingSteps];
|
||||
@@ -761,12 +761,12 @@ export default function FilesUpload() {
|
||||
if (isMountedRef.current) {
|
||||
setProcessingSteps(updatedSteps);
|
||||
} else {
|
||||
console.log('【调试-startUpload】组件已卸载,不更新处理步骤');
|
||||
// console.log('【调试-startUpload】组件已卸载,不更新处理步骤');
|
||||
return;
|
||||
}
|
||||
|
||||
// 转换文件为二进制格式
|
||||
console.log("【调试-startUpload】开始转换文件到二进制格式...");
|
||||
// console.log("【调试-startUpload】开始转换文件到二进制格式...");
|
||||
|
||||
// 模拟上传进度
|
||||
if (progressIntervalRef.current) {
|
||||
@@ -795,21 +795,21 @@ export default function FilesUpload() {
|
||||
|
||||
for (const file of files) {
|
||||
try {
|
||||
console.log(`【调试-startUpload】准备上传文件: ${file.name}, 大小: ${formatFileSize(file.size)}`);
|
||||
// console.log(`【调试-startUpload】准备上传文件: ${file.name}, 大小: ${formatFileSize(file.size)}`);
|
||||
|
||||
// 转换文件为二进制格式
|
||||
console.log(`【调试-startUpload】开始转换文件 ${file.name} 为二进制格式`);
|
||||
// console.log(`【调试-startUpload】开始转换文件 ${file.name} 为二进制格式`);
|
||||
let binaryData: ArrayBuffer;
|
||||
try {
|
||||
binaryData = await uploadFileToBinary(file);
|
||||
console.log(`【调试-startUpload】文件 ${file.name} 二进制转换成功,大小: ${binaryData.byteLength} 字节`);
|
||||
// console.log(`【调试-startUpload】文件 ${file.name} 二进制转换成功,大小: ${binaryData.byteLength} 字节`);
|
||||
} catch (binaryError) {
|
||||
console.error(`【调试-startUpload】文件 ${file.name} 二进制转换失败:`, binaryError);
|
||||
throw new Error(`文件 ${file.name} 转换失败: ${binaryError instanceof Error ? binaryError.message : '未知错误'}`);
|
||||
}
|
||||
|
||||
let response: FileUploadResponse;
|
||||
console.log(`【调试-startUpload】开始上传文件 ${file.name} 到服务器,文件类型: ${fileType}`);
|
||||
// console.log(`【调试-startUpload】开始上传文件 ${file.name} 到服务器,文件类型: ${fileType}`);
|
||||
|
||||
try {
|
||||
// 上传文件
|
||||
@@ -819,7 +819,7 @@ export default function FilesUpload() {
|
||||
return { success: false, error: '组件已卸载' } as FileUploadResponse;
|
||||
}
|
||||
|
||||
console.log(`【调试-startUpload】准备上传文件 ${file.name} 到服务器`);
|
||||
// console.log(`【调试-startUpload】准备上传文件 ${file.name} 到服务器`);
|
||||
|
||||
// 使用Promise.race添加超时处理
|
||||
const uploadPromise = uploadFileToServer(
|
||||
@@ -848,7 +848,7 @@ export default function FilesUpload() {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`【调试-startUpload】文件 ${file.name} 上传响应:`, response);
|
||||
// console.log(`【调试-startUpload】文件 ${file.name} 上传响应:`, response);
|
||||
} catch (error) {
|
||||
// 检查组件是否已卸载
|
||||
if (!isMountedRef.current) {
|
||||
@@ -884,7 +884,7 @@ export default function FilesUpload() {
|
||||
}
|
||||
};
|
||||
|
||||
console.log(`【调试-startUpload】文件 ${file.name} 上传成功,文件ID: ${newFile.id}`);
|
||||
// console.log(`【调试-startUpload】文件 ${file.name} 上传成功,文件ID: ${newFile.id}`);
|
||||
uploadedFiles.push(newFile);
|
||||
} catch (fileError) {
|
||||
console.error(`【调试-startUpload】处理文件 ${file.name} 时发生错误:`, fileError);
|
||||
@@ -916,14 +916,14 @@ export default function FilesUpload() {
|
||||
};
|
||||
});
|
||||
|
||||
console.log(`【调试-startUpload】所有文件上传完成,更新队列`);
|
||||
// console.log(`【调试-startUpload】所有文件上传完成,更新队列`);
|
||||
setQueueFiles(prev => [...newDocuments, ...prev]);
|
||||
|
||||
// 设置当前文件为已上传的文件
|
||||
setCompletedFiles(uploadedFiles);
|
||||
|
||||
// 完成上传后开始处理流程
|
||||
console.log(`【调试-startUpload】开始文件处理流程`);
|
||||
// console.log(`【调试-startUpload】开始文件处理流程`);
|
||||
startProcessing(uploadedFiles);
|
||||
} catch (error) {
|
||||
console.error("【调试-startUpload】文件上传过程发生错误:", error);
|
||||
@@ -959,7 +959,7 @@ export default function FilesUpload() {
|
||||
// 开始处理上传的文件
|
||||
const startProcessing = (files: UploadedFile[]) => {
|
||||
try {
|
||||
console.log('【调试-startProcessing】开始处理上传的文件:', files.length, '个文件');
|
||||
// console.log('【调试-startProcessing】开始处理上传的文件:', files.length, '个文件');
|
||||
|
||||
// 检查组件是否已卸载
|
||||
if (!isMountedRef.current) {
|
||||
@@ -981,14 +981,14 @@ export default function FilesUpload() {
|
||||
|
||||
// 获取文件ID列表
|
||||
const fileIds = files.map(file => file.id).filter(id => id > 0);
|
||||
console.log('【调试-startProcessing】文件ID列表:', fileIds);
|
||||
// console.log('【调试-startProcessing】文件ID列表:', fileIds);
|
||||
|
||||
if (fileIds.length === 0) {
|
||||
console.error('【调试-startProcessing】没有有效的文件ID,无法开始处理');
|
||||
throw new Error('没有有效的文件ID,无法开始处理');
|
||||
}
|
||||
|
||||
console.log('【调试-startProcessing】开始处理文件,设置文件处理进度定时器');
|
||||
// console.log('【调试-startProcessing】开始处理文件,设置文件处理进度定时器');
|
||||
|
||||
// 清除之前的进度定时器(如果存在)
|
||||
if (progressIntervalRef.current) {
|
||||
@@ -997,7 +997,7 @@ export default function FilesUpload() {
|
||||
|
||||
// 立即开始检查状态
|
||||
try {
|
||||
console.log('【调试-startProcessing】立即开始检查处理状态');
|
||||
// console.log('【调试-startProcessing】立即开始检查处理状态');
|
||||
checkProcessingStatus(fileIds);
|
||||
} catch (statusError) {
|
||||
console.error('【调试-startProcessing】首次检查状态失败:', statusError);
|
||||
@@ -1005,7 +1005,7 @@ export default function FilesUpload() {
|
||||
|
||||
// 设置文件处理进度定时器,每10秒检查一次状态
|
||||
progressIntervalRef.current = setInterval(() => {
|
||||
console.log('【调试-startProcessing】文件处理进度定时器触发,检查文件状态');
|
||||
// console.log('【调试-startProcessing】文件处理进度定时器触发,检查文件状态');
|
||||
try {
|
||||
checkProcessingStatus(fileIds);
|
||||
} catch (intervalError) {
|
||||
@@ -1050,7 +1050,7 @@ export default function FilesUpload() {
|
||||
// 检查文件处理状态
|
||||
const checkProcessingStatus = async (fileIds: number[]) => {
|
||||
try {
|
||||
console.log('【调试-checkProcessingStatus】检查文件处理状态:', fileIds);
|
||||
// console.log('【调试-checkProcessingStatus】检查文件处理状态:', fileIds);
|
||||
|
||||
// 检查组件是否已卸载
|
||||
if (!isMountedRef.current) {
|
||||
@@ -1060,12 +1060,12 @@ export default function FilesUpload() {
|
||||
|
||||
// 如果没有文件ID,不执行检查
|
||||
if (!fileIds.length) {
|
||||
console.log('【调试-checkProcessingStatus】没有需要检查的文件');
|
||||
// console.log('【调试-checkProcessingStatus】没有需要检查的文件');
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取文件状态
|
||||
console.log('【调试-checkProcessingStatus】发送请求获取文件状态');
|
||||
// console.log('【调试-checkProcessingStatus】发送请求获取文件状态');
|
||||
const response = await getDocumentsStatus(fileIds);
|
||||
|
||||
if (response.error) {
|
||||
@@ -1073,26 +1073,26 @@ export default function FilesUpload() {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('【调试-checkProcessingStatus】文件状态响应:', response.data);
|
||||
// console.log('【调试-checkProcessingStatus】文件状态响应:', response.data);
|
||||
|
||||
if (!response.data || !response.data.length) {
|
||||
console.log('【调试-checkProcessingStatus】没有返回文件状态数据');
|
||||
// console.log('【调试-checkProcessingStatus】没有返回文件状态数据');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否所有文件都已完成处理
|
||||
const allCompleted = response.data.every(doc => doc.status === DocumentStatus.PROCESSED);
|
||||
console.log('【调试-checkProcessingStatus】文件处理状态:', { allCompleted, statusList: response.data.map(doc => doc.status) });
|
||||
// console.log('【调试-checkProcessingStatus】文件处理状态:', { allCompleted, statusList: response.data.map(doc => doc.status) });
|
||||
|
||||
// 更新步骤状态
|
||||
if (allCompleted) {
|
||||
console.log('【调试-checkProcessingStatus】所有文件处理完成,更新步骤状态为完成');
|
||||
// console.log('【调试-checkProcessingStatus】所有文件处理完成,更新步骤状态为完成');
|
||||
|
||||
// 清除文件处理进度定时器
|
||||
if (progressIntervalRef.current) {
|
||||
clearInterval(progressIntervalRef.current);
|
||||
progressIntervalRef.current = null;
|
||||
console.log('【调试-checkProcessingStatus】文件处理完成,清除文件处理进度定时器');
|
||||
// console.log('【调试-checkProcessingStatus】文件处理完成,清除文件处理进度定时器');
|
||||
}
|
||||
|
||||
// 更新为全部完成状态
|
||||
@@ -1112,7 +1112,7 @@ export default function FilesUpload() {
|
||||
} else {
|
||||
// 根据当前状态更新步骤
|
||||
const currentStatus = response.data[0].status;
|
||||
console.log('【调试-checkProcessingStatus】根据当前状态更新步骤:', currentStatus);
|
||||
// console.log('【调试-checkProcessingStatus】根据当前状态更新步骤:', currentStatus);
|
||||
updateProcessingSteps(currentStatus);
|
||||
}
|
||||
|
||||
@@ -1127,7 +1127,7 @@ export default function FilesUpload() {
|
||||
|
||||
// 更新处理步骤状态
|
||||
const updateProcessingSteps = (status: DocumentStatus) => {
|
||||
console.log('更新处理步骤状态:', status);
|
||||
// console.log('更新处理步骤状态:', status);
|
||||
|
||||
const updatedSteps = [...processingSteps];
|
||||
|
||||
@@ -1182,7 +1182,7 @@ export default function FilesUpload() {
|
||||
const updateQueueFilesStatus = (updatedDocs: Document[]) => {
|
||||
if (!updatedDocs.length) return;
|
||||
|
||||
console.log('更新队列中文件状态:', updatedDocs);
|
||||
// console.log('更新队列中文件状态:', updatedDocs);
|
||||
|
||||
setQueueFiles(prevFiles => {
|
||||
// 创建文件ID到状态的映射
|
||||
@@ -1273,18 +1273,18 @@ export default function FilesUpload() {
|
||||
// 处理查看文件
|
||||
const handleViewFile = async (record: Document) => {
|
||||
try {
|
||||
console.log('【调试-handleViewFile】开始处理查看文件,文件ID:', record.id);
|
||||
// console.log('【调试-handleViewFile】开始处理查看文件,文件ID:', record.id);
|
||||
|
||||
// 检查audit_status是否为0,如果是则更新为2
|
||||
if (record.audit_status === 0 || record.audit_status === null) {
|
||||
try {
|
||||
console.log('【调试-handleViewFile】更新文件审核状态,文件ID:', record.id);
|
||||
// console.log('【调试-handleViewFile】更新文件审核状态,文件ID:', record.id);
|
||||
const response = await updateDocumentAuditStatus(record.id.toString(), 2);
|
||||
if (response.error) {
|
||||
console.error('【调试-handleViewFile】更新文件审核状态失败:', response.error);
|
||||
toastService.error('更新文件审核状态失败:' + (response.error || '未知错误'));
|
||||
} else {
|
||||
console.log('【调试-handleViewFile】更新文件审核状态成功');
|
||||
// console.log('【调试-handleViewFile】更新文件审核状态成功');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
@@ -1294,7 +1294,7 @@ export default function FilesUpload() {
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`【调试-handleViewFile】准备导航到文件详情页,文件ID: ${record.id}`);
|
||||
// console.log(`【调试-handleViewFile】准备导航到文件详情页,文件ID: ${record.id}`);
|
||||
|
||||
// 检查组件是否已卸载
|
||||
if (!isMountedRef.current) {
|
||||
@@ -1306,7 +1306,7 @@ export default function FilesUpload() {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
if (isMountedRef.current) {
|
||||
console.log(`【调试-handleViewFile】执行导航,URL: /reviews?id=${record.id}&previousRoute=filesUpload`);
|
||||
// console.log(`【调试-handleViewFile】执行导航,URL: /reviews?id=${record.id}&previousRoute=filesUpload`);
|
||||
navigate(`/reviews?id=${record.id}&previousRoute=filesUpload`);
|
||||
} else {
|
||||
console.error('【调试-handleViewFile】组件已卸载,取消延迟导航');
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
// import React from 'react';
|
||||
import { type MetaFunction, type LoaderFunctionArgs, redirect } from "@remix-run/node";
|
||||
import { type MetaFunction } from "@remix-run/node";
|
||||
import { useLoaderData } from "@remix-run/react";
|
||||
import { Card } from "~/components/ui/Card";
|
||||
import { Button } from "~/components/ui/Button";
|
||||
@@ -43,7 +43,7 @@ export const meta: MetaFunction = () => {
|
||||
// }
|
||||
|
||||
// 添加认证检查
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
export async function loader() {
|
||||
// 检查用户登录状态
|
||||
// const { isAuthenticated } = await getUserSession(request);
|
||||
|
||||
@@ -65,11 +65,11 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
return Response.json({ error: responseDocuments.error }, { status: responseDocuments.status || 500 });
|
||||
}
|
||||
const recentFiles = responseDocuments.data?.documents || [];
|
||||
console.log("recentFiles-------",recentFiles);
|
||||
// console.log("recentFiles-------",recentFiles);
|
||||
|
||||
|
||||
const homeData = await getHomeData();
|
||||
console.log("homeData-------",homeData);
|
||||
// console.log("homeData-------",homeData);
|
||||
|
||||
|
||||
return Response.json({ homeData, recentFiles });
|
||||
@@ -125,7 +125,7 @@ export default function Home() {
|
||||
order: 'updated_at.desc'
|
||||
};
|
||||
|
||||
console.log('定时获取最新文档数据...');
|
||||
// console.log('定时获取最新文档数据...');
|
||||
const responseDocuments = await getDocuments(documentSearchParams);
|
||||
|
||||
if (responseDocuments.error) {
|
||||
@@ -138,7 +138,7 @@ export default function Home() {
|
||||
|
||||
// 检查数据是否有变化
|
||||
if (JSON.stringify(newRecentFiles) !== JSON.stringify(recentFiles)) {
|
||||
console.log('文档数据已更新,直接更新状态');
|
||||
// console.log('文档数据已更新,直接更新状态');
|
||||
// 直接更新状态,不需要刷新页面
|
||||
setRecentFiles(newRecentFiles);
|
||||
}
|
||||
@@ -152,7 +152,7 @@ export default function Home() {
|
||||
|
||||
// 组件卸载时清除定时器
|
||||
return () => {
|
||||
console.log('清除文档数据自动更新定时器');
|
||||
// console.log('清除文档数据自动更新定时器');
|
||||
clearInterval(timerID);
|
||||
};
|
||||
}, []); // 不再依赖recentFiles,避免循环依赖
|
||||
|
||||
+27
-8
@@ -1,8 +1,8 @@
|
||||
import { useState } from "react";
|
||||
import { Form, useActionData, useNavigation } from "@remix-run/react";
|
||||
import { type MetaFunction, type ActionFunctionArgs, redirect, json, type LoaderFunctionArgs } from "@remix-run/node";
|
||||
import { type MetaFunction, type ActionFunctionArgs, redirect, type LoaderFunctionArgs } from "@remix-run/node";
|
||||
import styles from "~/styles/pages/login.css?url";
|
||||
import { createUserSession, getUserSession, getSession } from "~/root";
|
||||
import { createUserSession, getUserSession, getSession, type UserRole } from "~/root";
|
||||
|
||||
export const links = () => [
|
||||
{ rel: "stylesheet", href: styles }
|
||||
@@ -20,21 +20,24 @@ export async function action({ request }: ActionFunctionArgs) {
|
||||
const formData = await request.formData();
|
||||
const username = formData.get("username") as string;
|
||||
const password = formData.get("password") as string;
|
||||
const userRole = formData.get("userRole") as UserRole || 'common';
|
||||
|
||||
// 简单的登录验证,实际应用中应该进行真正的身份验证
|
||||
if (!username || !password) {
|
||||
return json({ error: "用户名和密码不能为空" });
|
||||
return Response.json({ error: "用户名和密码不能为空" });
|
||||
}
|
||||
|
||||
// 在实际应用中,这里应该是对用户名和密码的验证逻辑
|
||||
// 简化起见,我们直接视为登录成功
|
||||
|
||||
// 获取session中存储的重定向URL,如果没有则默认到/home
|
||||
// 获取session中存储的重定向URL,如果没有则默认到/
|
||||
const session = await getSession(request);
|
||||
const redirectTo = session.get("redirectTo") || "/home";
|
||||
// 查看session中存储的redirectTo值
|
||||
const redirectTo = session.get("redirectTo") || "/";
|
||||
// console.log("登录后重定向到:", redirectTo);
|
||||
|
||||
// 创建登录会话并重定向
|
||||
return createUserSession(true, redirectTo);
|
||||
return createUserSession(true, userRole, redirectTo);
|
||||
}
|
||||
|
||||
// 加载器,获取当前会话状态
|
||||
@@ -43,7 +46,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
|
||||
// 如果已登录,重定向到首页
|
||||
if (isAuthenticated) {
|
||||
return redirect("/home");
|
||||
return redirect("/");
|
||||
}
|
||||
|
||||
return Response.json({ isAuthenticated });
|
||||
@@ -52,6 +55,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
export default function Login() {
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [userRole, setUserRole] = useState<UserRole>("common");
|
||||
const actionData = useActionData<typeof action>();
|
||||
const navigation = useNavigation();
|
||||
|
||||
@@ -62,7 +66,7 @@ export default function Login() {
|
||||
<div className="login-page">
|
||||
<div className="login-container">
|
||||
<div className="login-header">
|
||||
<img src="/logo.png" alt="中国烟草" className="login-logo" />
|
||||
{/* <img src="/logo.png" alt="中国烟草" className="login-logo" /> */}
|
||||
<h1 className="login-title">中国烟草AI合同及卷宗审核系统</h1>
|
||||
</div>
|
||||
|
||||
@@ -101,6 +105,21 @@ export default function Login() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="userRole">用户角色</label>
|
||||
<select
|
||||
id="userRole"
|
||||
name="userRole"
|
||||
value={userRole}
|
||||
onChange={(e) => setUserRole(e.target.value as UserRole)}
|
||||
className="form-input"
|
||||
required
|
||||
>
|
||||
<option value="common">普通用户</option>
|
||||
{/* <option value="developer">开发者</option> */}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="login-button"
|
||||
|
||||
@@ -54,7 +54,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const page = parseInt(url.searchParams.get('page') || '1', 10);
|
||||
const pageSize = parseInt(url.searchParams.get('pageSize') || '10', 10);
|
||||
|
||||
console.log('加载提示词模板参数:', { name, type, status, page, pageSize });
|
||||
// console.log('加载提示词模板参数:', { name, type, status, page, pageSize });
|
||||
|
||||
// 从 API 获取数据
|
||||
const result = await getPromptTemplates({
|
||||
@@ -79,7 +79,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`成功加载${result.data?.templates.length || 0}条提示词模板数据`);
|
||||
// console.log(`成功加载${result.data?.templates.length || 0}条提示词模板数据`);
|
||||
|
||||
return Response.json({
|
||||
templates: result.data?.templates || [],
|
||||
|
||||
@@ -389,11 +389,11 @@ export default function ReviewDetails() {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('评查点状态更新成功:', {
|
||||
id: reviewPointResultId,
|
||||
result: boolResult,
|
||||
message: message
|
||||
});
|
||||
// console.log('评查点状态更新成功:', {
|
||||
// id: reviewPointResultId,
|
||||
// result: boolResult,
|
||||
// message: message
|
||||
// });
|
||||
|
||||
// 更新本地状态
|
||||
if (reviewData) {
|
||||
@@ -451,7 +451,7 @@ export default function ReviewDetails() {
|
||||
toastService.success('评查点状态已更新');
|
||||
}
|
||||
|
||||
console.log("newReviewPoints",updatedReviewPoints);
|
||||
// console.log("newReviewPoints",updatedReviewPoints);
|
||||
|
||||
// 如果是review操作才调用API刷新
|
||||
// if (document && document.id && newStatus === 'review') {
|
||||
|
||||
@@ -89,11 +89,11 @@ function mapApiToFrontend(apiGroup: ApiRuleGroup): RuleGroup {
|
||||
|
||||
// 数据加载器
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
console.log("rule-groups.new loader被调用,URL:", request.url);
|
||||
// console.log("rule-groups.new loader被调用,URL:", request.url);
|
||||
try {
|
||||
const url = new URL(request.url);
|
||||
const id = url.searchParams.get("id");
|
||||
console.log("获取到的ID参数:", id);
|
||||
// console.log("获取到的ID参数:", id);
|
||||
|
||||
// 获取一级分组列表 (用于选择父级分组)
|
||||
const parentGroupsResponse = await getRuleGroups();
|
||||
|
||||
@@ -50,6 +50,7 @@ import type { EvaluationPointGroup } from "~/models/evaluation_point_groups";
|
||||
import { RuleContext } from "~/contexts/RuleContext";
|
||||
import { postgrestGet, postgrestPost, postgrestPut } from "~/api/postgrest-client";
|
||||
import { toastService } from '~/components/ui/Toast';
|
||||
import type { UserRole } from '~/root';
|
||||
|
||||
export const meta: MetaFunction = () => {
|
||||
return [
|
||||
@@ -152,10 +153,13 @@ export default function RuleNew() {
|
||||
const [isEditMode, setIsEditMode] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [instanceKey, setInstanceKey] = useState<string>('new');
|
||||
|
||||
const [userRole, setUserRole] = useState<UserRole>('common');
|
||||
const [formData, setFormData] = useState<EvaluationPoint>({});
|
||||
const [evaluationPointGroups, setEvaluationPointGroups] = useState<EvaluationPointGroup[]>([]);
|
||||
|
||||
// 检查用户是否为开发者角色
|
||||
const isDeveloper = userRole === 'developer';
|
||||
|
||||
// 添加用于共享的字段数据状态
|
||||
const [extractionFields, setExtractionFields] = useState<string[]>([]);
|
||||
|
||||
@@ -195,7 +199,7 @@ export default function RuleNew() {
|
||||
* 重置表单数据到默认状态
|
||||
*/
|
||||
const resetFormData = useCallback(() => {
|
||||
console.log("重置表单数据到默认状态");
|
||||
// console.log("重置表单数据到默认状态");
|
||||
setFormData({
|
||||
name: '',
|
||||
code: '',
|
||||
@@ -250,7 +254,7 @@ export default function RuleNew() {
|
||||
const fetchEvaluationPoint = useCallback(async (id: number) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
console.log(`获取评查点数据,ID: ${id}`);
|
||||
// console.log(`获取评查点数据,ID: ${id}`);
|
||||
// 使用 postgrestGet 替代直接调用 fetch
|
||||
const postgrestParams = {
|
||||
filter: {
|
||||
@@ -268,7 +272,7 @@ export default function RuleNew() {
|
||||
const jsonString = JSON.stringify(originalData);
|
||||
const data = JSON.parse(jsonString);
|
||||
|
||||
console.log("数据已经过深拷贝处理,避免浏览器兼容性问题");
|
||||
// console.log("数据已经过深拷贝处理,避免浏览器兼容性问题");
|
||||
|
||||
// 设置表单数据
|
||||
setFormData(data);
|
||||
@@ -311,7 +315,7 @@ export default function RuleNew() {
|
||||
*/
|
||||
const fetchEvaluationPointGroups = useCallback(async () => {
|
||||
try {
|
||||
console.log("获取评查点组数据");
|
||||
// console.log("获取评查点组数据");
|
||||
const response = await postgrestGet('evaluation_point_groups');
|
||||
|
||||
if (response.data && Array.isArray(response.data) && response.data.length > 0) {
|
||||
@@ -325,7 +329,7 @@ export default function RuleNew() {
|
||||
}, []);
|
||||
|
||||
const handleSave = async () => {
|
||||
console.log("保存评查点", formData);
|
||||
// console.log("保存评查点", formData);
|
||||
|
||||
// 验证必填字段
|
||||
if (!formData.name?.trim()) {
|
||||
@@ -405,7 +409,7 @@ export default function RuleNew() {
|
||||
|
||||
// 去重,确保不会有重复字段
|
||||
const validFields = [...new Set(currentExtractionFields)];
|
||||
console.log("当前有效的抽取字段:", validFields);
|
||||
// console.log("当前有效的抽取字段:", validFields);
|
||||
|
||||
// 重要:这段代码解决了字段删除后,评查配置中仍保留已删除字段的问题
|
||||
// 在保存前,我们会确保所有规则中引用的字段都是当前有效的抽取字段
|
||||
@@ -548,8 +552,8 @@ export default function RuleNew() {
|
||||
throw new Error(`数据大小超过限制 (${dataLength} > ${maxLength})`);
|
||||
}
|
||||
|
||||
console.log("准备提交到API的数据(已经过深拷贝处理):", finalData);
|
||||
console.log("JSON数据长度:", dataLength);
|
||||
// console.log("准备提交到API的数据(已经过深拷贝处理):", finalData);
|
||||
// console.log("JSON数据长度:", dataLength);
|
||||
|
||||
let response;
|
||||
if (isEditMode) {
|
||||
@@ -706,6 +710,12 @@ export default function RuleNew() {
|
||||
const id = searchParams.get('id');
|
||||
const mode = searchParams.get('mode');
|
||||
|
||||
// 从sessionStorage获取用户角色
|
||||
if (typeof window !== 'undefined') {
|
||||
const userRoleFromSession = sessionStorage.getItem('userRole') as UserRole || 'common';
|
||||
setUserRole(userRoleFromSession);
|
||||
}
|
||||
|
||||
// 编辑或复制模式下设置加载状态
|
||||
if (id || mode === 'copy') {
|
||||
setIsLoading(true);
|
||||
@@ -737,6 +747,7 @@ export default function RuleNew() {
|
||||
<PageHeader
|
||||
title={isEditMode ? "编辑评查点" : "新增评查点"}
|
||||
onSave={handleSave}
|
||||
showSaveButton={isDeveloper}
|
||||
/>
|
||||
|
||||
{/* 加载状态显示 */}
|
||||
@@ -805,6 +816,7 @@ export default function RuleNew() {
|
||||
onSave={handleSave}
|
||||
onSaveDraft={handleSaveDraft}
|
||||
isEditMode={isEditMode}
|
||||
showButtons={isDeveloper}
|
||||
/>
|
||||
</div>
|
||||
</RuleContext.Provider>
|
||||
|
||||
+39
-16
@@ -22,6 +22,7 @@ import {
|
||||
type RuleType as ApiRuleType,
|
||||
type RuleGroup
|
||||
} from '~/api/evaluation_points/rules';
|
||||
import type { UserRole } from '~/root';
|
||||
|
||||
export const links = () => [
|
||||
{ rel: "stylesheet", href: rulesStyles }
|
||||
@@ -44,6 +45,7 @@ export type LoaderData = {
|
||||
pageSize: number;
|
||||
totalPages: number;
|
||||
ruleTypes: ApiRuleType[]; // 添加评查点类型
|
||||
userRole: UserRole; // 添加用户角色
|
||||
};
|
||||
|
||||
// API返回的数据映射到前端模型
|
||||
@@ -118,13 +120,19 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const apiRules = response.data?.rules || [];
|
||||
const totalCount = response.data?.totalCount || 0;
|
||||
const rules = apiRules.map((apiRule: ApiRule) => mapApiRuleToModel(apiRule));
|
||||
|
||||
// 从sessionStorage获取用户角色
|
||||
const userRoleFromSession = typeof document !== 'undefined'
|
||||
? sessionStorage.getItem('userRole') || 'common'
|
||||
: 'common';
|
||||
|
||||
return Response.json({
|
||||
rules,
|
||||
totalCount,
|
||||
currentPage: params.page,
|
||||
pageSize: params.pageSize,
|
||||
ruleTypes
|
||||
ruleTypes,
|
||||
userRole: userRoleFromSession as UserRole
|
||||
}, {
|
||||
headers: {
|
||||
"Cache-Control": "max-age=60, s-maxage=180"
|
||||
@@ -152,7 +160,7 @@ export async function action({ request }: LoaderFunctionArgs) {
|
||||
try {
|
||||
if (_action === 'delete') {
|
||||
// 调用API删除评查点
|
||||
console.log(`删除评查点 ${ruleId}`);
|
||||
// console.log(`删除评查点 ${ruleId}`);
|
||||
|
||||
const deleteResponse = await deleteRule(ruleId as string);
|
||||
|
||||
@@ -178,12 +186,15 @@ const priorityLabels = {
|
||||
|
||||
export default function RulesIndex() {
|
||||
const loaderData = useLoaderData<typeof loader>();
|
||||
const { rules, totalCount, currentPage, pageSize } = loaderData;
|
||||
const { rules, totalCount, currentPage, pageSize, userRole } = loaderData;
|
||||
const ruleTypes = loaderData.ruleTypes || []; // 添加默认空数组避免undefined
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const navigate = useNavigate();
|
||||
const fetcher = useFetcher<ActionResponse>();
|
||||
|
||||
// 检查用户是否为开发者角色
|
||||
const isDeveloper = userRole === 'developer';
|
||||
|
||||
// 状态管理
|
||||
const [ruleGroups, setRuleGroups] = useState<RuleGroup[]>([]);
|
||||
const [loadingGroups, setLoadingGroups] = useState(false);
|
||||
@@ -240,7 +251,7 @@ export default function RulesIndex() {
|
||||
toastService.success(fetcher.data.message);
|
||||
} else if (!fetcher.data.result) {
|
||||
if(fetcher.data.message.includes("evaluation_results_evaluation_point_id_fkey")) {
|
||||
toastService.error("对表“evaluation_points”进行更新或删除违反了表“evaluation results”上的外键约束“evaluations results_evaluation _point_id_fkey”");
|
||||
toastService.error('对表evaluation_points进行更新或删除违反了表evaluation results上的外键约束evaluations results_evaluation _point_id_fkey');
|
||||
} else {
|
||||
toastService.error(fetcher.data.message);
|
||||
}
|
||||
@@ -424,15 +435,25 @@ export default function RulesIndex() {
|
||||
width: "10%",
|
||||
render: (_: unknown, record: Rule) => (
|
||||
<div className="operations-cell">
|
||||
<Link to={`/rules-new?id=${record.id}`} className="operation-btn">
|
||||
<i className="ri-edit-line"></i> 编辑
|
||||
</Link>
|
||||
<button className="operation-btn" onClick={() => handleCopy(record)}>
|
||||
<i className="ri-file-copy-line"></i> 复制
|
||||
</button>
|
||||
<button className="operation-btn operation-btn-danger" onClick={() => handleDeleteClick(record)}>
|
||||
<i className="ri-delete-bin-line"></i> 删除
|
||||
</button>
|
||||
{isDeveloper ? (
|
||||
// 开发者可以看到编辑、复制、删除
|
||||
<>
|
||||
<Link to={`/rules-new?id=${record.id}`} className="operation-btn">
|
||||
<i className="ri-edit-line"></i> 编辑
|
||||
</Link>
|
||||
<button className="operation-btn" onClick={() => handleCopy(record)}>
|
||||
<i className="ri-file-copy-line"></i> 复制
|
||||
</button>
|
||||
<button className="operation-btn operation-btn-danger" onClick={() => handleDeleteClick(record)}>
|
||||
<i className="ri-delete-bin-line"></i> 删除
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
// 普通用户只能查看
|
||||
<Link to={`/rules-new?id=${record.id}&mode=view`} className="operation-btn">
|
||||
<i className="ri-eye-line"></i> 查看
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -443,9 +464,11 @@ export default function RulesIndex() {
|
||||
{/* 页面头部 */}
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h2 className="text-xl font-medium">评查点管理</h2>
|
||||
<Button type="primary" icon="ri-add-line" to="/rules-new" className="btn-add-rule">
|
||||
新增评查点
|
||||
</Button>
|
||||
{isDeveloper && (
|
||||
<Button type="primary" icon="ri-add-line" to="/rules-new" className="btn-add-rule">
|
||||
新增评查点
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 筛选区域 */}
|
||||
|
||||
@@ -169,7 +169,7 @@ export default function Documents() {
|
||||
*/
|
||||
function onDocumentLoadSuccess({ numPages }: DocumentLoadSuccess) {
|
||||
setNumPages(numPages);
|
||||
console.log("PDF加载成功,页数:", numPages);
|
||||
// console.log("PDF加载成功,页数:", numPages);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,7 +177,7 @@ export default function Documents() {
|
||||
* @param info 调试信息文本
|
||||
*/
|
||||
const addDebugInfo = (info: string) => {
|
||||
console.log(info);
|
||||
// console.log(info);
|
||||
setDebugInfo(prev => [...prev, `${new Date().toISOString().split('T')[1].split('.')[0]}: ${info}`]);
|
||||
};
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
max-width: 320px;
|
||||
transition: opacity 0.3s ease, visibility 0.3s ease;
|
||||
pointer-events: none;
|
||||
overflow: visible; /* 确保容器不显示滚动条 */
|
||||
}
|
||||
|
||||
.tooltip-visible {
|
||||
@@ -23,11 +24,57 @@
|
||||
|
||||
.tooltip-content {
|
||||
position: relative;
|
||||
padding: 0.75rem 1rem;
|
||||
padding: 0.75rem 0.5rem 0.75rem 0.75rem;
|
||||
border-radius: 0.375rem;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
overflow: visible; /* 确保外层容器不显示滚动条 */
|
||||
}
|
||||
|
||||
.tooltip-content-inner {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 可滚动的提示框内容样式 */
|
||||
.tooltip-scrollable {
|
||||
overflow-y: auto;
|
||||
scrollbar-width: none; /* Firefox */
|
||||
scrollbar-color: rgba(0, 0, 0, 0.3) transparent;
|
||||
/* 创建一个合适的内边距来容纳自定义滚动条 */
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
/* 隐藏默认滚动条 */
|
||||
.tooltip-scrollable::-webkit-scrollbar {
|
||||
width: 3px;
|
||||
}
|
||||
|
||||
.tooltip-scrollable::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.tooltip-scrollable::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.tooltip-scrollable:hover::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* 深色主题滚动条样式 */
|
||||
.tooltip-dark .tooltip-scrollable::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.tooltip-dark .tooltip-scrollable:hover::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.tooltip-dark .tooltip-scrollable {
|
||||
scrollbar-color: rgba(255, 255, 255, 0.3) transparent;
|
||||
}
|
||||
|
||||
.tooltip-arrow {
|
||||
@@ -159,6 +206,8 @@
|
||||
|
||||
.tooltip-body {
|
||||
padding: 0.75rem 1rem;
|
||||
max-height: inherit;
|
||||
overflow-y: inherit;
|
||||
}
|
||||
|
||||
.tooltip-footer {
|
||||
|
||||
+2
-2
@@ -72,11 +72,11 @@ export function getArrayDifference<T>(current: T[], previous: T[]): { added: T[]
|
||||
|
||||
|
||||
|
||||
// 格式化日期时间
|
||||
// 格式化日期时间utc的格林威治时间
|
||||
export function formatDate(dateTime: string): string {
|
||||
if (!dateTime) return '';
|
||||
try {
|
||||
return dayjs.utc(dateTime).format('YYYY-MM-DD HH:mm:ss');
|
||||
return dayjs(dateTime).local().format('YYYY-MM-DD HH:mm:ss');
|
||||
} catch (error) {
|
||||
console.error('日期格式化失败:', error);
|
||||
return dateTime;
|
||||
|
||||
+12
-12
@@ -673,20 +673,20 @@ function logPostgrestQuery(endpoint: string, params?: QueryParams, method: strin
|
||||
const baseUrl = 'http://nas.7bm.co:3000';
|
||||
const normalizedEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
|
||||
|
||||
console.log('\n📦 PostgREST 查询日志 ======================start=============');
|
||||
console.log(`📦 HTTP 方法: ${method}`);
|
||||
console.log(`📦 API 端点: ${decodeUrlForDisplay(`${baseUrl}/${normalizedEndpoint}`)}`);
|
||||
// console.log('\n📦 PostgREST 查询日志 ======================start=============');
|
||||
// console.log(`📦 HTTP 方法: ${method}`);
|
||||
// console.log(`📦 API 端点: ${decodeUrlForDisplay(`${baseUrl}/${normalizedEndpoint}`)}`);
|
||||
|
||||
if (params && Object.keys(params).length > 0) {
|
||||
console.log('📦 查询参数:');
|
||||
Object.entries(params).forEach(([key, value]) => {
|
||||
if (value !== undefined) {
|
||||
console.log(` - ${key}: ${JSON.stringify(value)}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
// if (params && Object.keys(params).length > 0) {
|
||||
// console.log('📦 查询参数:');
|
||||
// Object.entries(params).forEach(([key, value]) => {
|
||||
// if (value !== undefined) {
|
||||
// console.log(` - ${key}: ${JSON.stringify(value)}`);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
console.log('PostgREST 查询日志=============================end============\n');
|
||||
// console.log('PostgREST 查询日志=============================end============\n');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1512,7 +1512,7 @@
|
||||
const textarea = this.closest('.search-box').querySelector('.search-textarea');
|
||||
const query = textarea.value.trim();
|
||||
if (query) {
|
||||
console.log('搜索查询:', query);
|
||||
// console.log('搜索查询:', query);
|
||||
// 这里可以添加实际的搜索逻辑
|
||||
}
|
||||
});
|
||||
@@ -1523,7 +1523,7 @@
|
||||
categoryCards.forEach(card => {
|
||||
card.addEventListener('click', function() {
|
||||
const title = this.querySelector('.category-title').textContent;
|
||||
console.log('选择分类:', title);
|
||||
// console.log('选择分类:', title);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1533,7 +1533,7 @@
|
||||
card.addEventListener('click', function(e) {
|
||||
if (!e.target.closest('button')) {
|
||||
const title = this.querySelector('.template-title').textContent;
|
||||
console.log('查看模板详情:', title);
|
||||
// console.log('查看模板详情:', title);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1544,7 +1544,7 @@
|
||||
btn.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
const action = this.textContent.trim();
|
||||
console.log('执行操作:', action);
|
||||
// console.log('执行操作:', action);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1554,7 +1554,7 @@
|
||||
tab.addEventListener('click', function() {
|
||||
filterTabs.forEach(t => t.classList.remove('active'));
|
||||
this.classList.add('active');
|
||||
console.log('筛选:', this.textContent);
|
||||
// console.log('筛选:', this.textContent);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+5
-5
@@ -1514,7 +1514,7 @@
|
||||
const textarea = this.closest('.search-box').querySelector('.search-textarea');
|
||||
const query = textarea.value.trim();
|
||||
if (query) {
|
||||
console.log('搜索查询:', query);
|
||||
// console.log('搜索查询:', query);
|
||||
// 这里可以添加实际的搜索逻辑
|
||||
}
|
||||
});
|
||||
@@ -1525,7 +1525,7 @@
|
||||
categoryCards.forEach(card => {
|
||||
card.addEventListener('click', function() {
|
||||
const title = this.querySelector('.category-title').textContent;
|
||||
console.log('选择分类:', title);
|
||||
// console.log('选择分类:', title);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1535,7 +1535,7 @@
|
||||
card.addEventListener('click', function(e) {
|
||||
if (!e.target.closest('button')) {
|
||||
const title = this.querySelector('.template-title').textContent;
|
||||
console.log('查看模板详情:', title);
|
||||
// console.log('查看模板详情:', title);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1546,7 +1546,7 @@
|
||||
btn.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
const action = this.textContent.trim();
|
||||
console.log('执行操作:', action);
|
||||
// console.log('执行操作:', action);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1556,7 +1556,7 @@
|
||||
tab.addEventListener('click', function() {
|
||||
filterTabs.forEach(t => t.classList.remove('active'));
|
||||
this.classList.add('active');
|
||||
console.log('筛选:', this.textContent);
|
||||
// console.log('筛选:', this.textContent);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+2
-2
@@ -537,7 +537,7 @@
|
||||
const type = document.getElementById('search-type').value;
|
||||
const status = document.getElementById('search-status').value;
|
||||
|
||||
console.log('搜索条件:', {
|
||||
// console.log('搜索条件:', {
|
||||
name: name,
|
||||
type: type,
|
||||
status: status
|
||||
@@ -576,7 +576,7 @@
|
||||
function deleteTemplate(id) {
|
||||
if (confirm('确定要删除该模板吗?删除后无法恢复。')) {
|
||||
// 实际应该调用API删除数据
|
||||
console.log('删除模板ID:', id);
|
||||
// console.log('删除模板ID:', id);
|
||||
alert('删除成功!');
|
||||
// 刷新页面
|
||||
window.location.reload();
|
||||
|
||||
+1
-1
@@ -700,7 +700,7 @@
|
||||
created_by: 'admin' // 当前登录用户
|
||||
};
|
||||
|
||||
console.log('保存数据:', formData);
|
||||
// console.log('保存数据:', formData);
|
||||
|
||||
// 实际应用中应使用AJAX请求保存数据
|
||||
alert('保存成功!');
|
||||
|
||||
+1
-1
@@ -502,7 +502,7 @@
|
||||
};
|
||||
|
||||
// 实际应用中应该使用AJAX请求发送数据
|
||||
console.log('保存文档修改:', formData);
|
||||
// console.log('保存文档修改:', formData);
|
||||
|
||||
// 模拟保存成功
|
||||
alert('文档信息已成功更新!');
|
||||
|
||||
+6
-6
@@ -499,7 +499,7 @@
|
||||
const fileName = tr.querySelector('.file-name').textContent;
|
||||
|
||||
if(confirm(`确认删除文档 "${fileName}"?`)) {
|
||||
console.log('删除文档:', fileName);
|
||||
// console.log('删除文档:', fileName);
|
||||
// 实际应用中调用API删除文档
|
||||
tr.remove();
|
||||
}
|
||||
@@ -518,7 +518,7 @@
|
||||
}
|
||||
|
||||
if(confirm(`确认删除选中的 ${selectedIds.length} 个文档?`)) {
|
||||
console.log('批量删除文档IDs:', selectedIds);
|
||||
// console.log('批量删除文档IDs:', selectedIds);
|
||||
// 实际应用中调用API批量删除文档
|
||||
selectedIds.forEach(id => {
|
||||
document.querySelector(`.row-checkbox[data-id="${id}"]`).closest('tr').remove();
|
||||
@@ -533,7 +533,7 @@
|
||||
const fileName = tr.querySelector('.file-name').textContent;
|
||||
const docId = tr.querySelector('.row-checkbox').getAttribute('data-id');
|
||||
|
||||
console.log('查看/审核文档:', fileName, 'ID:', docId);
|
||||
// console.log('查看/审核文档:', fileName, 'ID:', docId);
|
||||
window.location.href = `评查详情页面.html?id=${docId}`;
|
||||
});
|
||||
});
|
||||
@@ -545,7 +545,7 @@
|
||||
const fileName = tr.querySelector('.file-name').textContent;
|
||||
const docId = tr.querySelector('.row-checkbox').getAttribute('data-id');
|
||||
|
||||
console.log('修改文档:', fileName, 'ID:', docId);
|
||||
// console.log('修改文档:', fileName, 'ID:', docId);
|
||||
window.location.href = `文档-修改.html?id=${docId}`;
|
||||
});
|
||||
});
|
||||
@@ -557,7 +557,7 @@
|
||||
const tr = this.closest('tr');
|
||||
const fileName = tr.querySelector('.file-name').textContent;
|
||||
|
||||
console.log('下载文档:', fileName);
|
||||
// console.log('下载文档:', fileName);
|
||||
// 实际应用中调用API下载文档
|
||||
alert(`开始下载 ${fileName}`);
|
||||
});
|
||||
@@ -575,7 +575,7 @@
|
||||
dateTo: document.querySelector('input[type="date"]:nth-of-type(2)').value
|
||||
};
|
||||
|
||||
console.log('搜索条件:', filters);
|
||||
// console.log('搜索条件:', filters);
|
||||
// 实际应用中调用API搜索文档
|
||||
});
|
||||
|
||||
|
||||
+2
-2
@@ -955,7 +955,7 @@
|
||||
statusText.textContent = '上传成功';
|
||||
|
||||
// 实际应用中应该使用AJAX请求上传文件
|
||||
console.log('文件上传成功:', fileName, metadata);
|
||||
// console.log('文件上传成功:', fileName, metadata);
|
||||
|
||||
// 检查是否所有文件都已上传
|
||||
const allUploaded = Array.from(document.querySelectorAll('.file-status')).every(
|
||||
@@ -1010,7 +1010,7 @@
|
||||
// })
|
||||
// .then(response => response.json())
|
||||
// .then(data => {
|
||||
// console.log('上传成功:', data);
|
||||
// // console.log('上传成功:', data);
|
||||
// statusText.textContent = '上传成功';
|
||||
// progressBar.style.width = '100%';
|
||||
//
|
||||
|
||||
+2
-2
@@ -318,7 +318,7 @@
|
||||
if (!confirm('确定要删除该文档类型吗?此操作不会影响关联的评查点分组,但可能会影响使用该类型的文档评查。')) {
|
||||
e.preventDefault();
|
||||
} else {
|
||||
console.log('删除文档类型ID:', typeId);
|
||||
// console.log('删除文档类型ID:', typeId);
|
||||
// 实际应调用API删除数据
|
||||
alert('删除成功!');
|
||||
// 刷新页面
|
||||
@@ -333,7 +333,7 @@
|
||||
const nameInput = document.querySelector('.form-input').value;
|
||||
const groupSelect = document.querySelector('.form-select').value;
|
||||
|
||||
console.log('搜索条件:', {
|
||||
// console.log('搜索条件:', {
|
||||
name: nameInput,
|
||||
groupId: groupSelect
|
||||
});
|
||||
|
||||
+1
-1
@@ -388,7 +388,7 @@
|
||||
checkpoint_group_ids: selectedGroups
|
||||
};
|
||||
|
||||
console.log('提交数据:', formData);
|
||||
// console.log('提交数据:', formData);
|
||||
|
||||
// 实际应用中应通过AJAX提交数据
|
||||
alert('保存成功!');
|
||||
|
||||
+3
-3
@@ -2048,7 +2048,7 @@
|
||||
}
|
||||
|
||||
// 在实际应用中应调用API保存草稿
|
||||
console.log('保存人工审核草稿:', {
|
||||
// console.log('保存人工审核草稿:', {
|
||||
reviewId: reviewId,
|
||||
opinion: opinion
|
||||
});
|
||||
@@ -2068,7 +2068,7 @@
|
||||
}
|
||||
|
||||
// 在实际应用中应调用API提交审核结果
|
||||
console.log('通过人工审核:', {
|
||||
// console.log('通过人工审核:', {
|
||||
reviewId: reviewId,
|
||||
opinion: opinion,
|
||||
result: 'approved'
|
||||
@@ -2118,7 +2118,7 @@
|
||||
}
|
||||
|
||||
// 在实际应用中应调用API提交审核结果
|
||||
console.log('不通过人工审核:', {
|
||||
// console.log('不通过人工审核:', {
|
||||
reviewId: reviewId,
|
||||
opinion: opinion,
|
||||
result: 'rejected'
|
||||
|
||||
+3
-3
@@ -2048,7 +2048,7 @@
|
||||
}
|
||||
|
||||
// 在实际应用中应调用API保存草稿
|
||||
console.log('保存人工审核草稿:', {
|
||||
// console.log('保存人工审核草稿:', {
|
||||
reviewId: reviewId,
|
||||
opinion: opinion
|
||||
});
|
||||
@@ -2068,7 +2068,7 @@
|
||||
}
|
||||
|
||||
// 在实际应用中应调用API提交审核结果
|
||||
console.log('通过人工审核:', {
|
||||
// console.log('通过人工审核:', {
|
||||
reviewId: reviewId,
|
||||
opinion: opinion,
|
||||
result: 'approved'
|
||||
@@ -2118,7 +2118,7 @@
|
||||
}
|
||||
|
||||
// 在实际应用中应调用API提交审核结果
|
||||
console.log('不通过人工审核:', {
|
||||
// console.log('不通过人工审核:', {
|
||||
reviewId: reviewId,
|
||||
opinion: opinion,
|
||||
result: 'rejected'
|
||||
|
||||
+1
-1
@@ -870,7 +870,7 @@
|
||||
.filter(f => !f.includes('(全部)') && !f.includes('上传时间 ↓'));
|
||||
|
||||
if (filters.length > 0) {
|
||||
console.log('应用筛选:', filters.join(', '));
|
||||
// console.log('应用筛选:', filters.join(', '));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
+6
-6
@@ -354,7 +354,7 @@
|
||||
filterSelects.forEach(select => {
|
||||
select.addEventListener('change', function() {
|
||||
// 这里可以根据选择的值进行筛选,实际应用中可以通过AJAX请求后端接口
|
||||
console.log('筛选条件变更:', select.value);
|
||||
// console.log('筛选条件变更:', select.value);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -364,7 +364,7 @@
|
||||
if (searchBtn) {
|
||||
searchBtn.addEventListener('click', function() {
|
||||
// 这里可以根据输入的关键词进行搜索,实际应用中可以通过AJAX请求后端接口
|
||||
console.log('搜索关键词:', searchInput.value);
|
||||
// console.log('搜索关键词:', searchInput.value);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@
|
||||
// 给当前点击的页码添加active状态
|
||||
this.classList.add('ant-pagination-item-active');
|
||||
// 这里可以根据页码加载不同页的数据,实际应用中可以通过AJAX请求后端接口
|
||||
console.log('切换到页码:', this.textContent);
|
||||
// console.log('切换到页码:', this.textContent);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -391,7 +391,7 @@
|
||||
const row = this.closest('tr');
|
||||
const id = row.children[0].textContent;
|
||||
// 编辑操作,可以跳转到编辑页面或打开编辑模态框
|
||||
console.log('编辑评查点:', id);
|
||||
// console.log('编辑评查点:', id);
|
||||
window.location.href = `新增评查点.html?id=${id}&mode=edit`;
|
||||
});
|
||||
});
|
||||
@@ -402,7 +402,7 @@
|
||||
const id = row.children[0].textContent;
|
||||
const name = row.children[1].textContent;
|
||||
// 复制操作
|
||||
console.log('复制评查点:', id, name);
|
||||
// console.log('复制评查点:', id, name);
|
||||
// 在实际应用中,这里可以弹出确认对话框,然后进行复制操作
|
||||
alert(`确认复制评查点: ${name}?`);
|
||||
});
|
||||
@@ -414,7 +414,7 @@
|
||||
const id = row.children[0].textContent;
|
||||
const name = row.children[1].textContent;
|
||||
// 删除操作
|
||||
console.log('删除评查点:', id, name);
|
||||
// console.log('删除评查点:', id, name);
|
||||
// 在实际应用中,这里可以弹出确认对话框,然后进行删除操作
|
||||
if (confirm(`确认删除评查点: ${name}?`)) {
|
||||
// 执行删除操作,实际应用中可以通过AJAX请求后端接口
|
||||
|
||||
+19
-19
@@ -825,23 +825,23 @@
|
||||
});
|
||||
|
||||
// 调试代码 - 确保页面加载后检查所有自定义提示词容器
|
||||
console.log("页面加载完成,检查自定义提示词容器");
|
||||
// console.log("页面加载完成,检查自定义提示词容器");
|
||||
const customPromptContainers = [
|
||||
document.getElementById('llm-custom-prompt-container'),
|
||||
document.getElementById('multimodal-custom-prompt-container')
|
||||
];
|
||||
|
||||
customPromptContainers.forEach((container, index) => {
|
||||
console.log(`容器 ${index + 1} 状态:`, container ? container.style.display : '未找到元素');
|
||||
// console.log(`容器 ${index + 1} 状态:`, container ? container.style.display : '未找到元素');
|
||||
});
|
||||
|
||||
// 确保提示词类型切换正常工作
|
||||
console.log("设置提示词类型切换事件");
|
||||
// console.log("设置提示词类型切换事件");
|
||||
|
||||
// 直接绑定事件到单选按钮
|
||||
document.querySelectorAll('input[name="llm-prompt-type"]').forEach(radio => {
|
||||
radio.addEventListener('change', function() {
|
||||
console.log("大模型提示词类型变更:", this.value);
|
||||
// console.log("大模型提示词类型变更:", this.value);
|
||||
const customContainer = document.getElementById('llm-custom-prompt-container');
|
||||
const systemInfo = document.getElementById('llm-system-prompt-info');
|
||||
|
||||
@@ -857,7 +857,7 @@
|
||||
|
||||
document.querySelectorAll('input[name="multimodal-prompt-type"]').forEach(radio => {
|
||||
radio.addEventListener('change', function() {
|
||||
console.log("多模态提示词类型变更:", this.value);
|
||||
// console.log("多模态提示词类型变更:", this.value);
|
||||
const customContainer = document.getElementById('multimodal-custom-prompt-container');
|
||||
const systemInfo = document.getElementById('multimodal-system-prompt-info');
|
||||
|
||||
@@ -873,12 +873,12 @@
|
||||
|
||||
// 页面加载完成后,确保自定义提示词容器状态正确
|
||||
function initPromptContainers() {
|
||||
console.log("初始化提示词容器状态");
|
||||
// console.log("初始化提示词容器状态");
|
||||
|
||||
// 大模型抽取
|
||||
const llmPromptType = document.querySelector('input[name="llm-prompt-type"]:checked');
|
||||
if (llmPromptType) {
|
||||
console.log("当前大模型提示词类型:", llmPromptType.value);
|
||||
// console.log("当前大模型提示词类型:", llmPromptType.value);
|
||||
if (llmPromptType.value === 'custom') {
|
||||
document.getElementById('llm-custom-prompt-container').style.display = 'block';
|
||||
document.getElementById('llm-system-prompt-info').style.display = 'none';
|
||||
@@ -888,7 +888,7 @@
|
||||
// 多模态抽取
|
||||
const multimodalPromptType = document.querySelector('input[name="multimodal-prompt-type"]:checked');
|
||||
if (multimodalPromptType) {
|
||||
console.log("当前多模态提示词类型:", multimodalPromptType.value);
|
||||
// console.log("当前多模态提示词类型:", multimodalPromptType.value);
|
||||
if (multimodalPromptType.value === 'custom') {
|
||||
document.getElementById('multimodal-custom-prompt-container').style.display = 'block';
|
||||
document.getElementById('multimodal-system-prompt-info').style.display = 'none';
|
||||
@@ -1182,23 +1182,23 @@
|
||||
});
|
||||
|
||||
// 调试代码 - 确保页面加载后检查所有自定义提示词容器
|
||||
console.log("页面加载完成,检查自定义提示词容器");
|
||||
// console.log("页面加载完成,检查自定义提示词容器");
|
||||
const customPromptContainers = [
|
||||
document.getElementById('llm-custom-prompt-container'),
|
||||
document.getElementById('multimodal-custom-prompt-container')
|
||||
];
|
||||
|
||||
customPromptContainers.forEach((container, index) => {
|
||||
console.log(`容器 ${index + 1} 状态:`, container ? container.style.display : '未找到元素');
|
||||
// console.log(`容器 ${index + 1} 状态:`, container ? container.style.display : '未找到元素');
|
||||
});
|
||||
|
||||
// 确保提示词类型切换正常工作
|
||||
console.log("设置提示词类型切换事件");
|
||||
// console.log("设置提示词类型切换事件");
|
||||
|
||||
// 直接绑定事件到单选按钮
|
||||
document.querySelectorAll('input[name="llm-prompt-type"]').forEach(radio => {
|
||||
radio.addEventListener('change', function() {
|
||||
console.log("大模型提示词类型变更:", this.value);
|
||||
// console.log("大模型提示词类型变更:", this.value);
|
||||
const customContainer = document.getElementById('llm-custom-prompt-container');
|
||||
const systemInfo = document.getElementById('llm-system-prompt-info');
|
||||
|
||||
@@ -1214,7 +1214,7 @@
|
||||
|
||||
document.querySelectorAll('input[name="multimodal-prompt-type"]').forEach(radio => {
|
||||
radio.addEventListener('change', function() {
|
||||
console.log("多模态提示词类型变更:", this.value);
|
||||
// console.log("多模态提示词类型变更:", this.value);
|
||||
const customContainer = document.getElementById('multimodal-custom-prompt-container');
|
||||
const systemInfo = document.getElementById('multimodal-system-prompt-info');
|
||||
|
||||
@@ -1230,12 +1230,12 @@
|
||||
|
||||
// 页面加载完成后,确保自定义提示词容器状态正确
|
||||
function initPromptContainers() {
|
||||
console.log("初始化提示词容器状态");
|
||||
// console.log("初始化提示词容器状态");
|
||||
|
||||
// 大模型抽取
|
||||
const llmPromptType = document.querySelector('input[name="llm-prompt-type"]:checked');
|
||||
if (llmPromptType) {
|
||||
console.log("当前大模型提示词类型:", llmPromptType.value);
|
||||
// console.log("当前大模型提示词类型:", llmPromptType.value);
|
||||
if (llmPromptType.value === 'custom') {
|
||||
document.getElementById('llm-custom-prompt-container').style.display = 'block';
|
||||
document.getElementById('llm-system-prompt-info').style.display = 'none';
|
||||
@@ -1245,7 +1245,7 @@
|
||||
// 多模态抽取
|
||||
const multimodalPromptType = document.querySelector('input[name="multimodal-prompt-type"]:checked');
|
||||
if (multimodalPromptType) {
|
||||
console.log("当前多模态提示词类型:", multimodalPromptType.value);
|
||||
// console.log("当前多模态提示词类型:", multimodalPromptType.value);
|
||||
if (multimodalPromptType.value === 'custom') {
|
||||
document.getElementById('multimodal-custom-prompt-container').style.display = 'block';
|
||||
document.getElementById('multimodal-system-prompt-info').style.display = 'none';
|
||||
@@ -2011,7 +2011,7 @@ function checkRule(data) {
|
||||
const addConditionBtn = container.querySelector('.add-condition-btn');
|
||||
if (addConditionBtn) {
|
||||
addConditionBtn.addEventListener('click', function() {
|
||||
console.log('添加条件按钮被点击');
|
||||
// console.log('添加条件按钮被点击');
|
||||
|
||||
const conditionsContainer = container.querySelector('.conditions-container');
|
||||
if (!conditionsContainer) {
|
||||
@@ -2059,7 +2059,7 @@ function checkRule(data) {
|
||||
});
|
||||
}
|
||||
|
||||
console.log('已添加新的条件行');
|
||||
// console.log('已添加新的条件行');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2127,7 +2127,7 @@ function checkRule(data) {
|
||||
highlightedCode.textContent = codeEditor.value;
|
||||
try {
|
||||
hljs.highlightElement(highlightedCode);
|
||||
console.log('代码块已高亮', index);
|
||||
// console.log('代码块已高亮', index);
|
||||
} catch (e) {
|
||||
console.error('代码高亮失败:', e);
|
||||
}
|
||||
|
||||
+1
-1
@@ -375,7 +375,7 @@
|
||||
if (!confirm('确定要删除该分组吗?此操作将同时删除该分组下的所有评查点,且不可恢复。')) {
|
||||
e.preventDefault();
|
||||
} else {
|
||||
console.log('删除分组ID:', groupId);
|
||||
// console.log('删除分组ID:', groupId);
|
||||
// 实际应调用API删除数据
|
||||
alert('删除成功!');
|
||||
// 刷新页面
|
||||
|
||||
+1
-1
@@ -462,7 +462,7 @@
|
||||
}
|
||||
|
||||
// 实际应调用API保存数据
|
||||
console.log('保存分组数据:', groupData);
|
||||
// console.log('保存分组数据:', groupData);
|
||||
|
||||
// 模拟保存成功
|
||||
alert(groupData.id ? '分组更新成功!' : '分组添加成功!');
|
||||
|
||||
+4
-4
@@ -365,7 +365,7 @@
|
||||
const environment = document.getElementById('search-environment').value;
|
||||
const status = document.getElementById('search-status').value;
|
||||
|
||||
console.log('搜索参数:', { name, module, environment, status });
|
||||
// console.log('搜索参数:', { name, module, environment, status });
|
||||
// 实际应用中应通过AJAX请求获取数据并更新表格
|
||||
alert('执行搜索...');
|
||||
}
|
||||
@@ -373,7 +373,7 @@
|
||||
// 查看配置详情
|
||||
function viewConfig(id) {
|
||||
// 实际应用中应通过AJAX请求获取数据
|
||||
console.log('查看配置:', id);
|
||||
// console.log('查看配置:', id);
|
||||
|
||||
// 模拟数据
|
||||
let configData = {
|
||||
@@ -434,7 +434,7 @@
|
||||
|
||||
// 编辑配置
|
||||
function editConfig(id) {
|
||||
console.log('编辑配置:', id);
|
||||
// console.log('编辑配置:', id);
|
||||
window.location.href = `配置-新增.html?id=${id}`;
|
||||
}
|
||||
|
||||
@@ -444,7 +444,7 @@
|
||||
const statusText = newStatus ? '启用' : '禁用';
|
||||
|
||||
if (confirm(`确定要${statusText}该配置吗?`)) {
|
||||
console.log('切换配置状态:', id, '新状态:', newStatus);
|
||||
// console.log('切换配置状态:', id, '新状态:', newStatus);
|
||||
// 实际应用中应通过AJAX请求更新状态
|
||||
alert('状态已更新');
|
||||
// 刷新页面或更新UI
|
||||
|
||||
+1
-1
@@ -591,7 +591,7 @@
|
||||
config_data: configDataObj
|
||||
};
|
||||
|
||||
console.log('提交数据:', formData);
|
||||
// console.log('提交数据:', formData);
|
||||
|
||||
// 实际应用中应通过AJAX提交数据
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -1133,7 +1133,7 @@ var require_react_development = __commonJS({
|
||||
function disableLogs() {
|
||||
{
|
||||
if (disabledDepth === 0) {
|
||||
prevLog = console.log;
|
||||
prevLog = // console.log;
|
||||
prevInfo = console.info;
|
||||
prevWarn = console.warn;
|
||||
prevError = console.error;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -8195,7 +8195,7 @@ function RemixRootDefaultErrorBoundary({
|
||||
let heyDeveloper = /* @__PURE__ */ React4.createElement("script", {
|
||||
dangerouslySetInnerHTML: {
|
||||
__html: `
|
||||
console.log(
|
||||
// console.log(
|
||||
"\u{1F4BF} Hey developer \u{1F44B}. You can provide a way better UX than this when your app throws errors. Check out https://remix.run/guides/errors for more information."
|
||||
);
|
||||
`
|
||||
@@ -8270,7 +8270,7 @@ function RemixRootDefaultHydrateFallback() {
|
||||
}, /* @__PURE__ */ React5.createElement("script", {
|
||||
dangerouslySetInnerHTML: {
|
||||
__html: `
|
||||
console.log(
|
||||
// console.log(
|
||||
"\u{1F4BF} Hey developer \u{1F44B}. You can provide a way better UX than this " +
|
||||
"when your app is loading JS modules and/or running \`clientLoader\` " +
|
||||
"functions. Check out https://remix.run/route/hydrate-fallback " +
|
||||
@@ -9493,15 +9493,15 @@ var LiveReload = (
|
||||
ws.onmessage = async (message) => {
|
||||
let event = JSON.parse(message.data);
|
||||
if (event.type === "LOG") {
|
||||
console.log(event.message);
|
||||
// console.log(event.message);
|
||||
}
|
||||
if (event.type === "RELOAD") {
|
||||
console.log("💿 Reloading window ...");
|
||||
// console.log("💿 Reloading window ...");
|
||||
window.location.reload();
|
||||
}
|
||||
if (event.type === "HMR") {
|
||||
if (!window.__hmr__ || !window.__hmr__.contexts) {
|
||||
console.log("💿 [HMR] No HMR context, reloading window ...");
|
||||
// console.log("💿 [HMR] No HMR context, reloading window ...");
|
||||
window.location.reload();
|
||||
return;
|
||||
}
|
||||
@@ -9509,10 +9509,10 @@ var LiveReload = (
|
||||
let updateAccepted = false;
|
||||
let needsRevalidation = new Set();
|
||||
for (let update of event.updates) {
|
||||
console.log("[HMR] " + update.reason + " [" + update.id +"]")
|
||||
// console.log("[HMR] " + update.reason + " [" + update.id +"]")
|
||||
if (update.revalidate) {
|
||||
needsRevalidation.add(update.routeId);
|
||||
console.log("[HMR] Revalidating [" + update.routeId + "]");
|
||||
// console.log("[HMR] Revalidating [" + update.routeId + "]");
|
||||
}
|
||||
let imported = await import(update.url + '?t=' + event.assetsManifest.hmr.timestamp);
|
||||
if (window.__hmr__.contexts[update.id]) {
|
||||
@@ -9520,7 +9520,7 @@ var LiveReload = (
|
||||
imported
|
||||
);
|
||||
if (accepted) {
|
||||
console.log("[HMR] Update accepted by", update.id);
|
||||
// console.log("[HMR] Update accepted by", update.id);
|
||||
updateAccepted = true;
|
||||
}
|
||||
}
|
||||
@@ -9530,12 +9530,12 @@ var LiveReload = (
|
||||
{ needsRevalidation, assetsManifest: event.assetsManifest }
|
||||
);
|
||||
if (accepted) {
|
||||
console.log("[HMR] Update accepted by", "remix:manifest");
|
||||
// console.log("[HMR] Update accepted by", "remix:manifest");
|
||||
updateAccepted = true;
|
||||
}
|
||||
}
|
||||
if (!updateAccepted) {
|
||||
console.log("[HMR] Update rejected, reloading...");
|
||||
// console.log("[HMR] Update rejected, reloading...");
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
@@ -9547,7 +9547,7 @@ var LiveReload = (
|
||||
};
|
||||
ws.onclose = (event) => {
|
||||
if (event.code === 1006) {
|
||||
console.log("Remix dev asset server web socket closed. Reconnecting...");
|
||||
// console.log("Remix dev asset server web socket closed. Reconnecting...");
|
||||
setTimeout(
|
||||
() =>
|
||||
remixLiveReloadConnect({
|
||||
@@ -9558,7 +9558,7 @@ var LiveReload = (
|
||||
}
|
||||
};
|
||||
ws.onerror = (error) => {
|
||||
console.log("Remix dev asset server web socket error:");
|
||||
// console.log("Remix dev asset server web socket error:");
|
||||
console.error(error);
|
||||
};
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1316,7 +1316,7 @@ var require_react_dom_development = __commonJS({
|
||||
function disableLogs() {
|
||||
{
|
||||
if (disabledDepth === 0) {
|
||||
prevLog = console.log;
|
||||
prevLog = // console.log;
|
||||
prevInfo = console.info;
|
||||
prevWarn = console.warn;
|
||||
prevError = console.error;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -176,7 +176,7 @@ var require_react_jsx_dev_runtime_development = __commonJS({
|
||||
function disableLogs() {
|
||||
{
|
||||
if (disabledDepth === 0) {
|
||||
prevLog = console.log;
|
||||
prevLog = // console.log;
|
||||
prevInfo = console.info;
|
||||
prevWarn = console.warn;
|
||||
prevError = console.error;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -176,7 +176,7 @@ var require_react_jsx_runtime_development = __commonJS({
|
||||
function disableLogs() {
|
||||
{
|
||||
if (disabledDepth === 0) {
|
||||
prevLog = console.log;
|
||||
prevLog = // console.log;
|
||||
prevInfo = console.info;
|
||||
prevWarn = console.warn;
|
||||
prevError = console.error;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -21,6 +21,10 @@ export default defineConfig({
|
||||
}),
|
||||
tsconfigPaths(),
|
||||
],
|
||||
define: {
|
||||
// 在构建时为客户端代码提供 process.env.NODE_ENV 变量
|
||||
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || "development"),
|
||||
},
|
||||
server: {
|
||||
host: '0.0.0.0',
|
||||
port: 5173,
|
||||
|
||||
Reference in New Issue
Block a user