feat: 1. 完善全局路由的访问权限的验证。 2. 完善接口返回的树形路由结构 3.优化评查点列表的查询,改用表连接的方式,废弃使用数据库的rpc函数,同时进行地区隔离和权限隔离。
4. 删除冗余的评查文件列表。 5.完善上传文档 页面初始化查询数据的时候 查询文件类型(改成动态指定) 6. 添加获取入口模块的查询接口。 7.完善服务端中判断token的有效性,失效则跳转到登录页。 8. 重构layout和sidebar的页面,改成由动态权限路由来渲染对应的菜单栏。 9.重构入口页面,通过动态查询根据不同地区的人返回不同的入口。
This commit is contained in:
+110
-26
@@ -26,7 +26,7 @@
|
||||
*/
|
||||
|
||||
import { type MetaFunction } from "@remix-run/node";
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { useState, useEffect, useCallback, useRef } from "react";
|
||||
import { BasicInfo } from "~/components/rules/new/BasicInfo";
|
||||
import { ExtractionSettings } from "~/components/rules/new/ExtractionSettings";
|
||||
import { ReviewSettings } from "~/components/rules/new/ReviewSettings";
|
||||
@@ -138,13 +138,17 @@ export default function RuleNew() {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const [isEditMode, setIsEditMode] = useState(false);
|
||||
const [isCopyMode, setIsCopyMode] = useState(false); // 添加复制模式状态
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [instanceKey, setInstanceKey] = useState<string>('new');
|
||||
// 从root路由获取用户角色和JWT token
|
||||
const rootData = useRouteLoaderData("root") as { userRole: UserRole; frontendJWT?: string };
|
||||
const userRole = rootData?.userRole || 'common';
|
||||
const frontendJWT = rootData?.frontendJWT;
|
||||
|
||||
|
||||
// 使用 ref 跟踪当前加载的 URL,避免重复加载
|
||||
const loadedUrlRef = useRef<string>('');
|
||||
|
||||
const [formData, setFormData] = useState<EvaluationPoint>({});
|
||||
const [evaluationPointGroups, setEvaluationPointGroups] = useState<EvaluationPointGroup[]>([]);
|
||||
|
||||
@@ -266,11 +270,12 @@ export default function RuleNew() {
|
||||
* 获取评查点数据
|
||||
* 编辑模式下从API获取指定ID的评查点数据
|
||||
* @param id 评查点ID
|
||||
* @param isCopy 是否为复制模式
|
||||
*/
|
||||
const fetchEvaluationPoint = useCallback(async (id: number) => {
|
||||
const fetchEvaluationPoint = useCallback(async (id: number, isCopy = false) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
// console.log(`获取评查点数据,ID: ${id}`);
|
||||
// console.log(`获取评查点数据,ID: ${id}, 复制模式: ${isCopy}`);
|
||||
// 使用 postgrestGet 替代直接调用 fetch
|
||||
const postgrestParams = {
|
||||
filter: {
|
||||
@@ -283,23 +288,43 @@ export default function RuleNew() {
|
||||
if (response.data) {
|
||||
// 使用extractApiData从响应中提取数据
|
||||
const evaluationPoints = extractApiData<EvaluationPoint[]>(response.data);
|
||||
|
||||
|
||||
if (evaluationPoints && Array.isArray(evaluationPoints) && evaluationPoints.length > 0) {
|
||||
try {
|
||||
// 使用JSON序列化和反序列化来进行深拷贝,避免浏览器差异
|
||||
const originalData = evaluationPoints[0];
|
||||
const jsonString = JSON.stringify(originalData);
|
||||
const data = JSON.parse(jsonString);
|
||||
|
||||
|
||||
// 🔄 复制模式:删除不应该复制的字段
|
||||
if (isCopy) {
|
||||
delete data.id;
|
||||
delete data.created_at;
|
||||
delete data.updated_at;
|
||||
delete data.usage_count;
|
||||
|
||||
// console.log('📋 复制模式:已清除不应复制的字段(id, created_at, updated_at, usage_count)');
|
||||
}
|
||||
|
||||
// 🔑 清洗评查点编码:移除最后一个 '--' 及其后面的字符
|
||||
// 例如:'code-mis--mz' --> 'code-mis', 'code-mbs--alsi--gz' --> 'code-mbs--alsi'
|
||||
if (data.code) {
|
||||
const lastDoubleHyphenIndex = data.code.lastIndexOf('--');
|
||||
if (lastDoubleHyphenIndex !== -1) {
|
||||
data.code = data.code.substring(0, lastDoubleHyphenIndex);
|
||||
// console.log('🔑 已清洗评查点编码:', data.code);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置表单数据
|
||||
setFormData(data);
|
||||
|
||||
|
||||
// 初始化extractionFields
|
||||
const extractedFields = extractFieldsFromFormData(data);
|
||||
setExtractionFields(extractedFields);
|
||||
|
||||
// 设置编辑模式的实例键
|
||||
setInstanceKey(`edit_${id}_${Date.now()}`);
|
||||
|
||||
// 设置实例键
|
||||
setInstanceKey(isCopy ? `copy_${id}_${Date.now()}` : `edit_${id}_${Date.now()}`);
|
||||
} catch (jsonError) {
|
||||
console.error('JSON处理错误:', jsonError);
|
||||
toastService.error(`数据处理错误: ${jsonError instanceof Error ? jsonError.message : '未知错误'}`);
|
||||
@@ -332,14 +357,30 @@ export default function RuleNew() {
|
||||
*/
|
||||
const fetchEvaluationPointGroups = useCallback(async () => {
|
||||
try {
|
||||
// console.log("获取评查点组数据");
|
||||
// console.log("🔍 [fetchEvaluationPointGroups] 开始获取评查点组数据");
|
||||
const response = await postgrestGet('evaluation_point_groups', { token: frontendJWT });
|
||||
|
||||
if (response.data && Array.isArray(response.data) && response.data.length > 0) {
|
||||
setEvaluationPointGroups(response.data);
|
||||
// console.log("🔍 [fetchEvaluationPointGroups] API响应:", response);
|
||||
|
||||
if (response.data) {
|
||||
// 使用 extractApiData 提取数据(处理可能的包装格式)
|
||||
const extractedData = extractApiData<EvaluationPointGroup[]>(response.data);
|
||||
// console.log("🔍 [fetchEvaluationPointGroups] 提取后的数据:", extractedData);
|
||||
|
||||
if (extractedData && Array.isArray(extractedData) && extractedData.length > 0) {
|
||||
setEvaluationPointGroups(extractedData);
|
||||
// console.log(`✅ [fetchEvaluationPointGroups] 成功加载 ${extractedData.length} 个评查点组`);
|
||||
} else {
|
||||
console.warn("⚠️ [fetchEvaluationPointGroups] 提取的数据为空或格式不正确");
|
||||
setEvaluationPointGroups([]);
|
||||
}
|
||||
} else if (response.error) {
|
||||
console.error('❌ [fetchEvaluationPointGroups] API返回错误:', response.error);
|
||||
setEvaluationPointGroups([]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取评查点组数据失败:', error);
|
||||
console.error('❌ [fetchEvaluationPointGroups] 获取评查点组数据失败:', error);
|
||||
setEvaluationPointGroups([]);
|
||||
// 显示错误提示但不影响应用继续使用
|
||||
toastService.error(`获取评查点组数据失败: ${error instanceof Error ? error.message : '未知错误'}\n将使用默认数据`);
|
||||
}
|
||||
@@ -761,6 +802,7 @@ export default function RuleNew() {
|
||||
let response;
|
||||
if (isEditMode) {
|
||||
response = await postgrestPut('evaluation_points', finalData, {id: formData.id!}, frontendJWT);
|
||||
// console.log("最终提交的数据", finalData)
|
||||
} else {
|
||||
response = await postgrestPost('evaluation_points', finalData, frontendJWT);
|
||||
}
|
||||
@@ -909,46 +951,85 @@ export default function RuleNew() {
|
||||
* 3. 获取评查点组数据(用于表单选择项)
|
||||
*/
|
||||
useEffect(() => {
|
||||
const searchParams = new URLSearchParams(location.search);
|
||||
const id = searchParams.get('id');
|
||||
const currentUrl = location.search;
|
||||
const currentPathname = location.pathname;
|
||||
const fullUrl = `${currentPathname}${currentUrl}`;
|
||||
|
||||
// 🔑 如果 URL 没有变化,不重复加载(避免无限循环)
|
||||
// 使用完整路径(pathname + search)进行比较,避免新增页面被拦截
|
||||
if (loadedUrlRef.current === fullUrl) {
|
||||
console.log('🔄 [useEffect] URL未变化,跳过重复加载:', fullUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
// console.log('🔄 [useEffect] URL变化,开始加载数据:', { previous: loadedUrlRef.current, current: fullUrl });
|
||||
|
||||
const searchParams = new URLSearchParams(currentUrl);
|
||||
const id = searchParams.get('id');
|
||||
const mode = searchParams.get('mode');
|
||||
|
||||
|
||||
// 判断是否为复制模式
|
||||
const isCopy = mode === 'copy';
|
||||
|
||||
// 编辑或复制模式下设置加载状态
|
||||
if (id || mode === 'copy') {
|
||||
if (id || isCopy) {
|
||||
setIsLoading(true);
|
||||
}
|
||||
|
||||
// 设置编辑模式
|
||||
if (mode && mode === 'copy') {
|
||||
|
||||
// 设置复制模式状态
|
||||
setIsCopyMode(isCopy);
|
||||
|
||||
// 设置编辑模式(复制模式不是编辑模式)
|
||||
if (isCopy) {
|
||||
setIsEditMode(false);
|
||||
} else {
|
||||
setIsEditMode(!!id);
|
||||
}
|
||||
|
||||
|
||||
if (id) {
|
||||
// 编辑模式:获取数据
|
||||
fetchEvaluationPoint(parseInt(id));
|
||||
// 编辑或复制模式:获取数据(传入复制模式标志)
|
||||
console.log('📝 [useEffect] 编辑/复制模式,加载评查点数据,ID:', id);
|
||||
fetchEvaluationPoint(parseInt(id), isCopy);
|
||||
} else {
|
||||
// 新建模式:重置表单数据
|
||||
console.log('📝 [useEffect] 新建模式,重置表单数据');
|
||||
resetFormData();
|
||||
}
|
||||
|
||||
// 获取评查点组数据
|
||||
// console.log('📝 [useEffect] 获取评查点组数据');
|
||||
fetchEvaluationPointGroups();
|
||||
// 获取VLM字段类型选项
|
||||
// console.log('📝 [useEffect] 获取VLM字段类型选项');
|
||||
fetchVlmFieldTypeOptions();
|
||||
}, [location.search, fetchEvaluationPoint, fetchEvaluationPointGroups, fetchVlmFieldTypeOptions, resetFormData]);
|
||||
|
||||
// 记录已加载的 URL(使用完整路径)
|
||||
loadedUrlRef.current = fullUrl;
|
||||
}, [location.search, location.pathname, fetchEvaluationPoint, fetchEvaluationPointGroups, fetchVlmFieldTypeOptions, resetFormData]);
|
||||
|
||||
// 渲染页面内容
|
||||
return (
|
||||
<div className="container">
|
||||
{/* 页面标题和右上角保存按钮 */}
|
||||
<PageHeader
|
||||
title={isEditMode ? (isReadOnly ? "查看评查点" : "编辑评查点") : "新增评查点"}
|
||||
title={isCopyMode ? "复制评查点" : (isEditMode ? (isReadOnly ? "查看评查点" : "编辑评查点") : "新增评查点")}
|
||||
onSave={handleSave}
|
||||
showSaveButton={!isReadOnly}
|
||||
/>
|
||||
|
||||
{/* 复制模式提示 */}
|
||||
{isCopyMode && !isLoading && (
|
||||
<div className="mb-4 p-1 bg-blue-50 border border-blue-200 rounded-md">
|
||||
<div className="flex items-center">
|
||||
<i className="ri-information-line text-blue-500 text-xl mr-2"></i>
|
||||
<div className="text-sm text-blue-800">
|
||||
<span className="font-medium">复制模式:</span>
|
||||
请检查并修改评查点信息后保存。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 加载状态显示 */}
|
||||
{isLoading ? (
|
||||
<div className="flex justify-center items-center p-12">
|
||||
@@ -965,6 +1046,7 @@ export default function RuleNew() {
|
||||
{/* 评查点基本信息设置 */}
|
||||
<div className="mb-8">
|
||||
<BasicInfo
|
||||
key={instanceKey}
|
||||
onChange={handleBasicInfoChange}
|
||||
initialData={formData}
|
||||
evaluationPointGroups={evaluationPointGroups}
|
||||
@@ -975,6 +1057,7 @@ export default function RuleNew() {
|
||||
{/* 抽取设置 - 配置从文档中提取的字段 */}
|
||||
<div className="mb-8">
|
||||
<ExtractionSettings
|
||||
key={instanceKey}
|
||||
onChange={handleExtractionSettingsChange}
|
||||
initialData={formData}
|
||||
promptTypeOptions={EVALUATION_OPTIONS.llmPromptTypeOptions}
|
||||
@@ -985,6 +1068,7 @@ export default function RuleNew() {
|
||||
{/* 评查设置 - 配置评查规则、消息等 */}
|
||||
<div className="mb-8">
|
||||
<ReviewSettings
|
||||
key={instanceKey}
|
||||
onChange={handleReviewSettingsChange}
|
||||
initialData={{
|
||||
rules: formData.evaluation_config?.rules || [],
|
||||
|
||||
Reference in New Issue
Block a user