Files
leaudit-platform-frontend/app/components/rules/new/BasicInfo.tsx
T

486 lines
18 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState, useEffect } from 'react';
interface BasicInfoProps {
onChange?: (data: Record<string, unknown>) => void;
initialData?: FormDataType;
evaluationPointGroups?: Array<{id: number, pid: number, code: string, name: string, is_enabled: boolean}>;
}
// 定义表单数据类型
interface FormDataType {
name: string;
code: string;
risk: string;
is_enabled: boolean;
description: string;
references_laws: {
name: string;
articles: string[];
content: string;
};
evaluation_point_groups_id: number | null;
evaluation_point_groups_pid: number | null;
type: string;
id?: number;
}
export function BasicInfo({ onChange, initialData, evaluationPointGroups = [] }: BasicInfoProps) {
const [formData, setFormData] = useState<FormDataType>({
name: '',
code: '',
risk: 'medium',
is_enabled: true,
description: '',
references_laws: {
name: '',
articles: [],
content: ''
},
evaluation_point_groups_id: null,
evaluation_point_groups_pid: null,
type: ''
});
const [isDescExpanded, setIsDescExpanded] = useState(false);
const [lawArticlesInput, setLawArticlesInput] = useState('');
const [filteredRuleGroups, setFilteredRuleGroups] = useState<Array<{id: number, pid: number, code: string, name: string, is_enabled: boolean}>>([]);
// 当initialData变化时更新表单数据
useEffect(() => {
if (initialData) {
const newFormData = {
name: initialData.name || '',
code: initialData.code || '',
risk: initialData.risk || 'medium',
is_enabled: initialData.is_enabled !== undefined ? initialData.is_enabled : true,
description: initialData.description || '',
references_laws: initialData.references_laws || {
name: '',
articles: [],
content: ''
},
evaluation_point_groups_id: initialData.evaluation_point_groups_id || null,
evaluation_point_groups_pid: initialData.evaluation_point_groups_pid || null,
type: initialData.type || ''
};
setFormData(newFormData);
// 更新法律条款输入框
if (initialData.references_laws && Array.isArray(initialData.references_laws.articles)) {
setLawArticlesInput(initialData.references_laws.articles.join(','));
}
// 如果有描述或法律依据,默认展开详细信息
if (initialData.description ||
(initialData.references_laws &&
(initialData.references_laws.name ||
initialData.references_laws.content ||
(initialData.references_laws.articles && initialData.references_laws.articles.length > 0)))) {
setIsDescExpanded(true);
}
}
}, [initialData]);
// 当评查点类型或评查点组数据变化时,过滤规则组列表
useEffect(() => {
if (evaluationPointGroups && evaluationPointGroups.length > 0) {
console.log("评查点组数据更新,当前类型:", formData.type);
console.log("评查点组数据:", evaluationPointGroups);
if (formData.type) {
// 获取所选评查点类型的组ID
const typeGroup = evaluationPointGroups.find(group =>
group.pid === 0 &&
group.code === formData.type
);
console.log("找到的类型组:", typeGroup);
if (typeGroup) {
// 更新评查点类型组ID
if (formData.evaluation_point_groups_pid !== typeGroup.id) {
const newData = {
...formData,
evaluation_point_groups_pid: typeGroup.id
};
setFormData(newData);
if (onChange) onChange(newData);
}
// 过滤出属于该类型的规则组(pid等于类型组ID的项)
const groups = evaluationPointGroups.filter(group =>
group.pid === typeGroup.id &&
group.is_enabled
);
console.log("过滤后的规则组:", groups);
setFilteredRuleGroups(groups);
// 如果当前选择的规则组不在过滤结果中,重置选择
if (formData.evaluation_point_groups_id &&
!groups.some(group => group.id === formData.evaluation_point_groups_id)) {
console.log("当前选择的规则组不在过滤结果中,重置选择");
const newData = {
...formData,
evaluation_point_groups_id: null
};
setFormData(newData);
if (onChange) onChange(newData);
}
} else {
console.log("未找到对应的类型组");
setFilteredRuleGroups([]);
// 重置评查点类型组ID
if (formData.evaluation_point_groups_pid !== null) {
const newData = {
...formData,
evaluation_point_groups_pid: null
};
setFormData(newData);
if (onChange) onChange(newData);
}
}
} else {
console.log("未选择评查点类型");
setFilteredRuleGroups([]);
// 重置评查点类型组ID
if (formData.evaluation_point_groups_pid !== null) {
const newData = {
...formData,
evaluation_point_groups_pid: null
};
setFormData(newData);
if (onChange) onChange(newData);
}
}
}
}, [formData.type, evaluationPointGroups, formData.evaluation_point_groups_id, formData.evaluation_point_groups_pid, onChange]);
// 获取评查点类型选项(pid=0的数据)
const getCheckpointTypeOptions = () => {
if (!evaluationPointGroups || evaluationPointGroups.length === 0) {
console.log("无评查点组数据,使用默认类型选项");
return (
<>
<option value=""></option>
<option value="essential"></option>
<option value="content"></option>
<option value="format"></option>
<option value="legal"></option>
<option value="business"></option>
</>
);
}
const typeGroups = evaluationPointGroups.filter(group => group.pid === 0 && group.is_enabled);
console.log("可用的评查点类型:", typeGroups);
return (
<>
<option value=""></option>
{typeGroups.map(group => (
<option key={group.id} value={group.code}>
{group.name}
</option>
))}
</>
);
};
const handleToggleDescription = () => {
setIsDescExpanded(!isDescExpanded);
};
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
const { id, value } = e.target;
const newData = { ...formData };
// 映射id到表单字段名
switch(id) {
case 'rule-name':
newData.name = value;
break;
case 'rule-code':
newData.code = value;
break;
case 'risk-level':
newData.risk = value;
break;
case 'is-enabled':
newData.is_enabled = value === 'true';
break;
case 'rule-description':
newData.description = value;
break;
case 'law-name':
newData.references_laws.name = value;
break;
case 'law-content':
newData.references_laws.content = value;
break;
case 'law-articles':
setLawArticlesInput(value);
break;
case 'evaluation-point-group':
newData.evaluation_point_groups_id = value ? parseInt(value) : null;
break;
case 'checkpoint-type':
newData.type = value;
// 重置规则组选择
newData.evaluation_point_groups_id = null;
// 设置评查点类型组ID
if (value) {
const typeGroup = evaluationPointGroups.find(group =>
group.pid === 0 &&
group.code === value
);
newData.evaluation_point_groups_pid = typeGroup ? typeGroup.id : null;
} else {
newData.evaluation_point_groups_pid = null;
}
break;
}
setFormData(newData);
if (onChange) {
onChange(newData);
}
};
const handleLawArticlesChange = (value: string) => {
setLawArticlesInput(value);
const articles = value.split(',')
.map(article => article.trim())
.filter(article => article !== '');
const newData = {
...formData,
references_laws: {
...formData.references_laws,
articles
}
};
setFormData(newData);
if (onChange) {
onChange(newData);
}
};
return (
<div className="ant-card">
<div className="ant-card-header">
<h3></h3>
</div>
<div className="ant-card-body">
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div>
<label className="form-label" htmlFor="rule-name">
<span className="required-mark">*</span>
</label>
<input
type="text"
id="rule-name"
className="form-input"
placeholder="请输入评查点名称,简洁明了"
value={formData.name}
onChange={handleInputChange}
/>
<div className="form-tip">使30</div>
</div>
<div>
<label className="form-label" htmlFor="rule-code">
<span className="required-mark">*</span>
</label>
<input
type="text"
id="rule-code"
className="form-input"
placeholder="请输入评查点编码"
value={formData.code}
onChange={handleInputChange}
/>
<div className="form-tip"></div>
</div>
<div>
<label className="form-label" htmlFor="risk-level">
<span className="required-mark">*</span>
</label>
<select
id="risk-level"
className="form-select"
value={formData.risk}
onChange={handleInputChange}
>
<option value="high"></option>
<option value="medium"></option>
<option value="low"></option>
</select>
<div className="form-tip"></div>
</div>
<div>
<label className="form-label" htmlFor="checkpoint-type">
<span className="required-mark">*</span>
</label>
<select
id="checkpoint-type"
className="form-select"
value={formData.type}
onChange={handleInputChange}
>
{getCheckpointTypeOptions()}
</select>
<div className="form-tip">便</div>
</div>
<div>
<label className="form-label" htmlFor="evaluation-point-group">
<span className="required-mark">*</span>
</label>
<select
id="evaluation-point-group"
className={`form-select ${!formData.type || filteredRuleGroups.length === 0 ? 'bg-gray-100 cursor-not-allowed' : ''}`}
value={formData.evaluation_point_groups_id?.toString() || ""}
onChange={handleInputChange}
disabled={!formData.type || filteredRuleGroups.length === 0}
>
<option value="">
{!formData.type ? "请先选择评查点类型" :
filteredRuleGroups.length === 0 ? "该类型下暂无可用规则组" :
"请选择规则组"}
</option>
{filteredRuleGroups.map(group => (
<option key={group.id} value={group.id.toString()}>
{group.name}
</option>
))}
</select>
<div className="form-tip">
{!formData.type ? "请先选择评查点类型" :
filteredRuleGroups.length === 0 ? "该类型下暂无可用规则组" :
"选择评查点所属的规则组"}
</div>
</div>
<div>
<label className="form-label" htmlFor="is-enabled"></label>
<select
id="is-enabled"
className="form-select"
value={formData.is_enabled ? 'true' : 'false'}
onChange={handleInputChange}
>
<option value="true"></option>
<option value="false"></option>
</select>
<div className="form-tip"></div>
</div>
</div>
<div className="mt-8">
<div
className={`flex justify-between items-center cursor-pointer ${isDescExpanded ? 'expanded' : ''}`}
onClick={handleToggleDescription}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
handleToggleDescription();
}
}}
tabIndex={0}
role="button"
>
<label className="form-label mb-0" htmlFor="description-section"></label>
<i className={`ri-arrow-${isDescExpanded ? 'up' : 'down'}-s-line text-lg expand-icon`}></i>
</div>
<div className={`mt-2 ${isDescExpanded ? '' : 'hidden'}`} id="description-section">
<div className="mb-4">
<textarea
id="rule-description"
className="form-textarea"
placeholder="请输入评查点的详细描述"
style={{ minHeight: '80px' }}
value={formData.description}
onChange={handleInputChange}
></textarea>
<div className="form-tip"></div>
</div>
{/* 引用法典输入区域 */}
<div className="mb-4">
<label className="form-label" htmlFor="law-section"></label>
<div className="mb-3" id="law-section">
<label className="text-sm text-gray-600 mb-1 block" htmlFor="law-name"></label>
<input
type="text"
className="form-input"
placeholder="例如:《中华人民共和国民法典》"
id="law-name"
value={formData.references_laws.name}
onChange={handleInputChange}
/>
</div>
<div className="mb-3">
<label className="text-sm text-gray-600 mb-1 block" htmlFor="law-articles"> <span className="text-xs text-gray-400">()</span></label>
<input
type="text"
className="form-input"
placeholder="例如:第五百八十五条,第五百八十六条"
id="law-articles"
value={lawArticlesInput}
onChange={(e) => handleLawArticlesChange(e.target.value)}
/>
<div className="form-tip"></div>
</div>
<div className="mb-4">
<label className="text-sm text-gray-600 mb-1 block" htmlFor="law-content"></label>
<textarea
className="form-textarea"
style={{ minHeight: '60px' }}
placeholder="例如:当事人应当按照约定全面履行自己的义务。"
id="law-content"
value={formData.references_laws.content}
onChange={handleInputChange}
></textarea>
</div>
<div className="p-3 bg-blue-50 border border-blue-200 rounded-md text-sm text-blue-700 mb-2">
<i className="ri-information-line mr-1"></i>
</div>
{/* 预览区域 */}
<div className="mt-3">
<div className="text-sm font-medium mb-2"></div>
<div className="law-reference">
<div className="law-reference-title" id="preview-law-name">
{formData.references_laws.name || '《中华人民共和国民法典》'}
</div>
<div className="law-reference-articles" id="preview-law-articles">
{formData.references_laws.articles.length > 0 ?
formData.references_laws.articles.map((article, index) => (
<span key={index} className="law-article">{article}</span>
)) : (
<>
<span className="law-article"></span>
<span className="law-article"></span>
</>
)}
</div>
<div className="law-reference-content" id="preview-law-content">
{formData.references_laws.content || '当事人应当按照约定全面履行自己的义务。'}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}