2796 lines
149 KiB
HTML
2796 lines
149 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>中国烟草AI合同及卷宗审核系统 - 新增评查点</title>
|
||
<link href="https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css" rel="stylesheet">
|
||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||
<!-- 引入外部CSS文件 -->
|
||
<link href="./main.css" rel="stylesheet">
|
||
|
||
<!-- 添加Highlight.js样式 - 使用monokai-sublime主题 -->
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/monokai-sublime.min.css">
|
||
<!-- 引入Highlight.js主要库 -->
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
|
||
<!-- 特别引入JavaScript语言支持 -->
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/javascript.min.js"></script>
|
||
<!-- 特别引入Python语言支持 -->
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/python.min.js"></script>
|
||
|
||
<style>
|
||
/* 新增切换按钮样式 */
|
||
#extraction-method-tabs {
|
||
display: flex;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
background-color: white;
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
#extraction-method-tabs .tab-nav-item {
|
||
padding: 10px 16px;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
border-bottom: 2px solid transparent;
|
||
transition: all 0.3s;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
#extraction-method-tabs .tab-nav-item:hover {
|
||
color: var(--primary-color);
|
||
background-color: rgba(0, 104, 74, 0.05);
|
||
}
|
||
|
||
#extraction-method-tabs .tab-nav-item.active {
|
||
color: var(--primary-color);
|
||
border-bottom-color: var(--primary-color);
|
||
background-color: rgba(0, 104, 74, 0.1);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.extraction-config {
|
||
padding: 12px;
|
||
border: 1px solid #f0f0f0;
|
||
border-radius: 4px;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.field-tags-container {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 6px;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
/* 紧凑型字段标签样式 */
|
||
.extraction-config .chips-container {
|
||
padding: 6px;
|
||
min-height: 36px;
|
||
}
|
||
|
||
.extraction-config .chip {
|
||
padding: 3px 6px;
|
||
margin-right: 6px;
|
||
margin-bottom: 6px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.extraction-config .chip .close-btn {
|
||
margin-left: 4px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
/* 使表单元素更紧凑 */
|
||
.extraction-config .form-input,
|
||
.extraction-config .form-select,
|
||
.extraction-config button.ant-btn {
|
||
padding: 4px 8px;
|
||
font-size: 13px;
|
||
height: auto;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.field-tag {
|
||
background-color: #f5f5f5;
|
||
border: 1px solid #e0e0e0;
|
||
border-radius: 4px;
|
||
padding: 4px 12px;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.field-tag:hover {
|
||
background-color: #e8f5e9;
|
||
border-color: #a5d6a7;
|
||
}
|
||
|
||
.field-tag.selected {
|
||
background-color: var(--primary-color);
|
||
color: white;
|
||
border-color: var(--primary-color);
|
||
}
|
||
|
||
/* 代码编辑器样式 */
|
||
.code-editor-wrapper {
|
||
border: 1px solid #e0e0e0;
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
background-color: #272822; /* Monokai背景色 */
|
||
}
|
||
|
||
.code-editor-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 8px 12px;
|
||
background-color: #2d2d2d;
|
||
border-bottom: 1px solid #444;
|
||
color: #f8f8f2;
|
||
}
|
||
|
||
.code-editor-filename {
|
||
font-family: monospace;
|
||
font-size: 13px;
|
||
color: #f8f8f2;
|
||
}
|
||
|
||
.code-editor-actions {
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
|
||
.code-editor-actions i {
|
||
cursor: pointer;
|
||
color: #d4d4d4;
|
||
}
|
||
|
||
.code-editor-actions i:hover {
|
||
color: #ffffff;
|
||
}
|
||
|
||
.code-editor-container {
|
||
position: relative;
|
||
}
|
||
|
||
.code-editor-textarea {
|
||
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
padding: 12px;
|
||
width: 100%;
|
||
height: 400px; /* 原来是200px,加高2倍 */
|
||
background-color: #272822;
|
||
color: #f8f8f2;
|
||
border: none;
|
||
resize: vertical;
|
||
min-height: 400px; /* 原来是200px,加高2倍 */
|
||
tab-size: 4;
|
||
position: relative;
|
||
z-index: 2; /* 确保输入框在高亮层之上 */
|
||
}
|
||
|
||
.code-editor-textarea:focus {
|
||
outline: none;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.code-editor-textarea::placeholder {
|
||
color: #75715e;
|
||
}
|
||
|
||
.hljs {
|
||
background: #272822 !important;
|
||
padding: 12px !important;
|
||
max-height: 400px; /* 原来是200px,加高2倍 */
|
||
overflow: auto;
|
||
}
|
||
|
||
/* 修改highlight.js样式以更好地匹配编辑器 */
|
||
.hljs-container {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
pointer-events: none; /* 确保不拦截鼠标事件 */
|
||
z-index: 1; /* 确保在编辑器输入框下方 */
|
||
height: 400px; /* 加高2倍 */
|
||
overflow: auto;
|
||
opacity: 1; /* 确保高亮内容可见 */
|
||
}
|
||
|
||
.hljs-container pre {
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
|
||
.hljs-container code {
|
||
display: block;
|
||
padding: 12px !important;
|
||
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
overflow: visible;
|
||
white-space: pre-wrap;
|
||
background: transparent !important;
|
||
}
|
||
|
||
.code-copy-success {
|
||
position: fixed;
|
||
bottom: 20px;
|
||
right: 20px;
|
||
background-color: rgba(0, 104, 74, 0.9);
|
||
color: white;
|
||
padding: 8px 16px;
|
||
border-radius: 4px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||
transition: all 0.3s;
|
||
opacity: 0;
|
||
transform: translateY(20px);
|
||
}
|
||
|
||
.code-copy-success.show {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
|
||
/* Prism.js覆盖样式 */
|
||
pre[class*="language-"] {
|
||
margin: 0;
|
||
border-radius: 0;
|
||
}
|
||
|
||
/* 隐藏的编辑器 */
|
||
.hidden-editor {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
opacity: 0;
|
||
z-index: 2;
|
||
}
|
||
|
||
/* 新增变量标签样式 */
|
||
.var-tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
padding: 4px 8px;
|
||
background-color: rgba(0, 104, 74, 0.1);
|
||
color: var(--primary-color);
|
||
border: 1px solid rgba(0, 104, 74, 0.2);
|
||
border-radius: 4px;
|
||
font-size: 12px;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.var-tag:hover {
|
||
background-color: rgba(0, 104, 74, 0.2);
|
||
border-color: rgba(0, 104, 74, 0.3);
|
||
}
|
||
|
||
.var-tag::before {
|
||
content: '{';
|
||
margin-right: 1px;
|
||
}
|
||
|
||
.var-tag::after {
|
||
content: '}';
|
||
margin-left: 1px;
|
||
}
|
||
|
||
.law-reference {
|
||
background-color: #f0f9ff;
|
||
border: 1px solid #bae0ff;
|
||
border-radius: 4px;
|
||
padding: 12px;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.law-reference-title {
|
||
color: #0958d9;
|
||
font-weight: 500;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.law-reference-articles {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.law-article {
|
||
background-color: #e6f4ff;
|
||
border: 1px solid #91caff;
|
||
border-radius: 12px;
|
||
padding: 2px 8px;
|
||
font-size: 12px;
|
||
color: #0958d9;
|
||
}
|
||
|
||
.law-reference-content {
|
||
font-size: 13px;
|
||
color: #434343;
|
||
line-height: 1.6;
|
||
border-left: 3px solid #bae0ff;
|
||
padding-left: 8px;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.expand-icon {
|
||
transition: transform 0.3s;
|
||
}
|
||
|
||
.expanded .expand-icon {
|
||
transform: rotate(180deg);
|
||
}
|
||
|
||
/* 自定义宽度类 */
|
||
.w-3\/10 {
|
||
width: 30%;
|
||
}
|
||
|
||
.w-7\/10 {
|
||
width: 70%;
|
||
}
|
||
|
||
/* 正则表达式配置行样式优化 */
|
||
.regex-field-row {
|
||
padding: 6px !important;
|
||
margin-bottom: 6px !important;
|
||
}
|
||
|
||
.regex-field-row input {
|
||
padding: 3px 6px;
|
||
font-size: 12px;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="layout-container">
|
||
<!-- 侧边栏 -->
|
||
<div class="sidebar">
|
||
<div class="py-6 px-4 border-b border-gray-100">
|
||
<div class="flex items-center">
|
||
<i class="ri-file-search-line text-primary text-xl mr-2"></i>
|
||
<h2 class="text-lg font-medium">AI审核系统</h2>
|
||
</div>
|
||
</div>
|
||
<div class="py-4">
|
||
<div class="sidebar-menu-item">
|
||
<a href="#" class="flex items-center text-sm font-medium">
|
||
<i class="ri-dashboard-line mr-3"></i>
|
||
<span>首页</span>
|
||
</a>
|
||
</div>
|
||
<div class="sidebar-menu-item">
|
||
<a href="#" class="flex items-center text-sm font-medium">
|
||
<i class="ri-file-upload-line mr-3"></i>
|
||
<span>文件上传</span>
|
||
</a>
|
||
</div>
|
||
<div class="sidebar-menu-item active">
|
||
<a href="#" class="flex items-center text-sm font-medium">
|
||
<i class="ri-list-check-2 mr-3"></i>
|
||
<span>评查规则库</span>
|
||
</a>
|
||
</div>
|
||
<div class="sidebar-menu-item">
|
||
<a href="#" class="flex items-center text-sm font-medium">
|
||
<i class="ri-history-line mr-3"></i>
|
||
<span>审核历史</span>
|
||
</a>
|
||
</div>
|
||
<div class="sidebar-menu-item">
|
||
<a href="#" class="flex items-center text-sm font-medium">
|
||
<i class="ri-settings-3-line mr-3"></i>
|
||
<span>系统设置</span>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 主内容区 -->
|
||
<div class="main-content">
|
||
<!-- 面包屑导航 -->
|
||
<div class="breadcrumb">
|
||
<span class="breadcrumb-item">首页</span>
|
||
<span class="breadcrumb-item">评查规则库</span>
|
||
<span class="breadcrumb-item">合同基本要素检查</span>
|
||
<span class="breadcrumb-item">评查点管理</span>
|
||
<span class="breadcrumb-item">新增评查点</span>
|
||
</div>
|
||
|
||
<!-- 页面头部 -->
|
||
<div class="flex justify-between items-center mb-4">
|
||
<h2 class="text-xl font-medium">新增评查点</h2>
|
||
<div class="flex">
|
||
<button class="ant-btn ant-btn-default mr-2">
|
||
<i class="ri-arrow-left-line"></i> 返回
|
||
</button>
|
||
<button class="ant-btn ant-btn-primary">
|
||
<i class="ri-save-line"></i> 保存
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 基本信息 -->
|
||
<div class="ant-card">
|
||
<div class="ant-card-header">
|
||
<h3>基本信息</h3>
|
||
</div>
|
||
<div class="ant-card-body">
|
||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||
<div>
|
||
<label class="form-label">
|
||
评查点名称 <span class="required-mark">*</span>
|
||
</label>
|
||
<input type="text" class="form-input" placeholder="请输入评查点名称">
|
||
<div class="form-tip">请使用简洁明了的名称,不超过30个字符</div>
|
||
</div>
|
||
<div>
|
||
<label class="form-label">
|
||
评查点编码 <span class="required-mark">*</span>
|
||
</label>
|
||
<input type="text" class="form-input" placeholder="请输入评查点编码">
|
||
<div class="form-tip">用于系统标识的唯一编码</div>
|
||
</div>
|
||
<div>
|
||
<label class="form-label">
|
||
风险等级: <span class="required-mark">*</span>
|
||
</label>
|
||
<select class="form-select">
|
||
<option value="high">高风险</option>
|
||
<option value="medium">中风险</option>
|
||
<option value="low">低风险</option>
|
||
</select>
|
||
<div class="form-tip">请定义评查点的风险等级</div>
|
||
</div>
|
||
<div>
|
||
<label class="form-label">
|
||
评查点类型 <span class="required-mark">*</span>
|
||
</label>
|
||
<select class="form-select" id="checkpointType">
|
||
<option value="">请选择评查点类型</option>
|
||
<option value="essential">基本要素类</option>
|
||
<option value="content">内容合规类</option>
|
||
<option value="format">格式规范类</option>
|
||
<option value="legal">法律风险类</option>
|
||
<option value="business">业务专项类</option>
|
||
</select>
|
||
<div class="form-tip">评查点类型用于分类管理,便于规则统一调用</div>
|
||
</div>
|
||
<div>
|
||
<label class="form-label">所属规则组</label>
|
||
<select class="form-select">
|
||
<option value="contract-base">合同基本要素检查</option>
|
||
<option value="contract-sales">销售合同专项检查</option>
|
||
<option value="contract-purchase">采购合同专项检查</option>
|
||
<option value="license">专卖许可证审核规则</option>
|
||
<option value="punishment">行政处罚规范性检查</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="form-label">是否启用</label>
|
||
<select class="form-select">
|
||
<option value="true">是</option>
|
||
<option value="false">否</option>
|
||
</select>
|
||
<div class="form-tip">创建后是否立即启用此评查点</div>
|
||
</div>
|
||
<div class="col-span-1 md:col-span-3">
|
||
<div class="flex justify-between items-center cursor-pointer" id="description-toggle">
|
||
<label class="form-label mb-0">评查点描述与法律依据</label>
|
||
<i class="ri-arrow-down-s-line text-lg expand-icon"></i>
|
||
</div>
|
||
|
||
<div id="description-section" class="hidden mt-2">
|
||
<div class="mb-4">
|
||
<textarea class="form-textarea" style="min-height: 80px;" placeholder="请输入评查点描述,包括适用场景、评查目的等"></textarea>
|
||
<div class="form-tip">详细描述有助于其他用户了解该评查点的用途</div>
|
||
</div>
|
||
|
||
<!-- 引用法典输入区域 -->
|
||
<div class="border-t border-gray-100 pt-4 mb-4">
|
||
<label class="form-label">引用法典</label>
|
||
|
||
<div class="mb-3">
|
||
<label class="text-sm text-gray-600 mb-1 block">法典名称</label>
|
||
<input type="text" class="form-input" placeholder="例如:《中华人民共和国民法典》" id="law-name">
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="text-sm text-gray-600 mb-1 block">条款号 <span class="text-xs text-gray-400">(多个条款请用逗号分隔)</span></label>
|
||
<input type="text" class="form-input" placeholder="例如:第五百八十五条,第五百八十六条" id="law-articles">
|
||
<div class="form-tip">多个条款用逗号分隔,将自动转换为数组格式</div>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="text-sm text-gray-600 mb-1 block">条款内容</label>
|
||
<textarea class="form-textarea" style="min-height: 60px;" placeholder="例如:当事人应当按照约定全面履行自己的义务。" id="law-content"></textarea>
|
||
</div>
|
||
|
||
<div class="p-3 bg-blue-50 border border-blue-200 rounded-md text-sm text-blue-700 mb-2">
|
||
<i class="ri-information-line mr-1"></i> 引用的法律条文将在评查结果中显示,帮助用户理解评查规则的法律依据
|
||
</div>
|
||
|
||
<!-- 预览区域 -->
|
||
<div class="p-3 border border-gray-200 rounded-md bg-gray-50 mt-3">
|
||
<div class="text-sm font-medium mb-2">预览效果</div>
|
||
<div class="law-reference">
|
||
<div class="law-reference-title" id="preview-law-name">《中华人民共和国民法典》</div>
|
||
<div class="law-reference-articles" id="preview-law-articles">
|
||
<span class="law-article">第五百八十五条</span>
|
||
<span class="law-article">第五百八十六条</span>
|
||
</div>
|
||
<div class="law-reference-content" id="preview-law-content">
|
||
当事人应当按照约定全面履行自己的义务。
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 抽取设置 -->
|
||
<div class="ant-card">
|
||
<div class="ant-card-header">
|
||
<h3>抽取设置</h3>
|
||
</div>
|
||
<div class="ant-card-body">
|
||
<div class="mb-6">
|
||
<!-- 将单选按钮改为切换按钮 -->
|
||
<div class="tab-nav mb-4" id="extraction-method-tabs">
|
||
<div class="tab-nav-item active" data-method="llm_ocr">
|
||
<i class="ri-brain-line mr-1"></i> 大模型抽取
|
||
</div>
|
||
<div class="tab-nav-item" data-method="llm">
|
||
<i class="ri-scan-line mr-1"></i> 多模态抽取
|
||
</div>
|
||
<div class="tab-nav-item" data-method="ocr_regex">
|
||
<i class="ri-code-box-line mr-1"></i> 正则抽取
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 大模型抽取配置(原OCR+LLM) -->
|
||
<div class="extraction-config" id="llm-ocr-config">
|
||
<div class="grid grid-cols-1 gap-3">
|
||
<div class="col-span-1">
|
||
<label class="form-label mb-1">抽取字段</label>
|
||
<div class="flex mb-2">
|
||
<input type="text" class="form-input mr-2" id="field-input-ocr" placeholder="请输入字段名,多个字段可用、或,或空格分隔">
|
||
<button class="ant-btn ant-btn-default" id="add-field-btn-ocr">添加</button>
|
||
</div>
|
||
<div class="chips-container" id="fields-container-ocr">
|
||
<div class="chip">合同编号 <span class="close-btn">×</span></div>
|
||
<div class="chip">合同金额 <span class="close-btn">×</span></div>
|
||
<div class="chip">签订日期 <span class="close-btn">×</span></div>
|
||
<div class="chip">甲方名称 <span class="close-btn">×</span></div>
|
||
<div class="chip">乙方名称 <span class="close-btn">×</span></div>
|
||
</div>
|
||
<div class="form-tip mt-1 text-xs">支持一次输入多个字段</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="grid grid-cols-1 gap-3 mt-3">
|
||
<div class="col-span-1">
|
||
<label class="form-label mb-1">提示词设置</label>
|
||
<div class="flex items-center mb-2">
|
||
<label class="inline-flex items-center mr-6">
|
||
<input type="radio" name="llm-prompt-type" value="system" checked class="form-radio"
|
||
onclick="document.getElementById('llm-custom-prompt-container').style.display='none';
|
||
document.getElementById('llm-system-prompt-info').style.display='block';">
|
||
<span class="ml-2">使用系统默认提示词</span>
|
||
</label>
|
||
<label class="inline-flex items-center">
|
||
<input type="radio" name="llm-prompt-type" value="custom" class="form-radio"
|
||
onclick="document.getElementById('llm-custom-prompt-container').style.display='block';
|
||
document.getElementById('llm-system-prompt-info').style.display='none';">
|
||
<span class="ml-2">使用自定义提示词</span>
|
||
</label>
|
||
</div>
|
||
<div class="bg-gray-50 p-2 rounded text-xs text-gray-600 mb-2" id="llm-system-prompt-info">
|
||
系统将根据评查点类型和抽取目标自动生成适合的提示词,您无需额外配置。
|
||
</div>
|
||
|
||
<div id="llm-custom-prompt-container" style="display: none;" class="border border-dashed border-gray-300 p-3 rounded-md">
|
||
<div class="mb-2">
|
||
<label class="form-label mb-1 text-sm">选择提示词模板</label>
|
||
<select class="form-select" id="llm-prompt-template">
|
||
<option value="">请选择模板</option>
|
||
<option value="1">行政处罚-抽取通用模板</option>
|
||
<option value="4">采购合同-乙方资质抽取</option>
|
||
<option value="5">合同-关键条款抽取</option>
|
||
<option value="6">烟草许可证-信息抽取</option>
|
||
</select>
|
||
</div>
|
||
<div class="mb-2">
|
||
<label class="form-label mb-1 text-sm">提示词内容</label>
|
||
<textarea class="form-textarea" id="llm-prompt-content" rows="4" placeholder="选择模板后自动填充,您也可以进行修改..." readonly></textarea>
|
||
<div class="form-tip mt-1 bg-gray-50 p-2 rounded text-xs">
|
||
<p class="mb-1"><strong>支持的变量</strong>(点击变量将其添加到提示词中):</p>
|
||
<div class="flex flex-wrap gap-1">
|
||
<button type="button" class="var-tag" data-var="docType">docType</button>
|
||
<button type="button" class="var-tag" data-var="fieldsList">fieldsList</button>
|
||
<button type="button" class="var-tag" data-var="companyName">companyName</button>
|
||
<button type="button" class="var-tag" data-var="documentId">documentId</button>
|
||
<button type="button" class="var-tag" data-var="date">date</button>
|
||
<button type="button" class="var-tag" data-var="industry">industry</button>
|
||
<button type="button" class="var-tag" data-var="ocrText">ocrText</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 多模态抽取配置(原LLM抽取) -->
|
||
<div class="extraction-config hidden" id="llm-config">
|
||
<div class="grid grid-cols-1 gap-3">
|
||
<div class="col-span-1">
|
||
<label class="form-label mb-1">抽取字段与类型</label>
|
||
<div class="flex mb-2">
|
||
<input type="text" class="form-input mr-2" id="field-input" placeholder="请输入字段名">
|
||
<select class="form-select mr-2" id="field-type">
|
||
<option value="default">默认</option>
|
||
<option value="seal">印章</option>
|
||
<option value="cross-seal">骑缝章</option>
|
||
<option value="handwriting">手写体</option>
|
||
<option value="print">印刷体</option>
|
||
<option value="english">英文</option>
|
||
<option value="number">数字</option>
|
||
<option value="currency">货币</option>
|
||
</select>
|
||
<button class="ant-btn ant-btn-default" id="add-field-btn">添加</button>
|
||
</div>
|
||
<div class="chips-container" id="fields-container">
|
||
<div class="chip">合同编号 <span class="badge bg-blue-100 text-blue-800 text-xs ml-1">默认</span> <span class="close-btn">×</span></div>
|
||
<div class="chip">合同金额 <span class="badge bg-green-100 text-green-800 text-xs ml-1">货币</span> <span class="close-btn">×</span></div>
|
||
<div class="chip">签订日期 <span class="badge bg-purple-100 text-purple-800 text-xs ml-1">印刷体</span> <span class="close-btn">×</span></div>
|
||
<div class="chip">甲方签章 <span class="badge bg-red-100 text-red-800 text-xs ml-1">印章</span> <span class="close-btn">×</span></div>
|
||
<div class="chip">手写签名 <span class="badge bg-yellow-100 text-yellow-800 text-xs ml-1">手写体</span> <span class="close-btn">×</span></div>
|
||
</div>
|
||
<div class="form-tip mt-1 text-xs">请为每个字段选择适当的抽取类型,有助于提高识别准确率</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="grid grid-cols-1 gap-3 mt-3">
|
||
<div class="col-span-1">
|
||
<label class="form-label mb-1">提示词设置</label>
|
||
<div class="flex items-center mb-2">
|
||
<label class="inline-flex items-center mr-6">
|
||
<input type="radio" name="multimodal-prompt-type" value="system" checked class="form-radio"
|
||
onclick="document.getElementById('multimodal-custom-prompt-container').style.display='none';
|
||
document.getElementById('multimodal-system-prompt-info').style.display='block';">
|
||
<span class="ml-2">使用系统默认提示词</span>
|
||
</label>
|
||
<label class="inline-flex items-center">
|
||
<input type="radio" name="multimodal-prompt-type" value="custom" class="form-radio"
|
||
onclick="document.getElementById('multimodal-custom-prompt-container').style.display='block';
|
||
document.getElementById('multimodal-system-prompt-info').style.display='none';">
|
||
<span class="ml-2">使用自定义提示词</span>
|
||
</label>
|
||
</div>
|
||
<div class="bg-gray-50 p-2 rounded text-xs text-gray-600 mb-2" id="multimodal-system-prompt-info">
|
||
系统将根据评查点类型和抽取目标自动生成适合的提示词,支持图表、印章等图像内容抽取。
|
||
</div>
|
||
|
||
<div id="multimodal-custom-prompt-container" style="display: none;" class="border border-dashed border-gray-300 p-3 rounded-md">
|
||
<div class="mb-2">
|
||
<label class="form-label mb-1 text-sm">选择提示词模板</label>
|
||
<select class="form-select" id="multimodal-prompt-template">
|
||
<option value="">请选择模板</option>
|
||
<option value="1">行政处罚-抽取通用模板</option>
|
||
<option value="4">采购合同-乙方资质抽取</option>
|
||
<option value="7">多模态-印章识别模板</option>
|
||
<option value="8">多模态-表格抽取模板</option>
|
||
<option value="9">多模态-手写内容识别模板</option>
|
||
</select>
|
||
</div>
|
||
<div class="mb-2">
|
||
<label class="form-label mb-1 text-sm">提示词内容</label>
|
||
<textarea class="form-textarea" id="multimodal-prompt-content" rows="4" placeholder="选择模板后自动填充,您也可以进行修改..." readonly></textarea>
|
||
<div class="form-tip mt-1 bg-gray-50 p-2 rounded text-xs">
|
||
<p class="mb-1"><strong>支持的变量</strong>(点击变量将其添加到提示词中):</p>
|
||
<div class="flex flex-wrap gap-1">
|
||
<button type="button" class="var-tag" data-var="docType">docType</button>
|
||
<button type="button" class="var-tag" data-var="fieldsList">fieldsList</button>
|
||
<button type="button" class="var-tag" data-var="companyName">companyName</button>
|
||
<button type="button" class="var-tag" data-var="documentId">documentId</button>
|
||
<button type="button" class="var-tag" data-var="date">date</button>
|
||
<button type="button" class="var-tag" data-var="industry">industry</button>
|
||
<button type="button" class="var-tag" data-var="contentType">contentType</button>
|
||
<button type="button" class="var-tag" data-var="pageRange">pageRange</button>
|
||
<button type="button" class="var-tag" data-var="colorMode">colorMode</button>
|
||
<button type="button" class="var-tag" data-var="ocrText">ocrText</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 正则抽取配置(原OCR+正则) -->
|
||
<div class="extraction-config hidden" id="ocr-regex-config">
|
||
<div class="grid grid-cols-1 gap-3">
|
||
<div class="col-span-1">
|
||
<div class="mb-2">
|
||
<div class="flex justify-between items-center mb-1">
|
||
<label class="form-label m-0">字段正则表达式配置</label>
|
||
<button class="ant-btn ant-btn-default" id="add-regex-field-row">
|
||
<i class="ri-add-line"></i> 添加字段
|
||
</button>
|
||
</div>
|
||
|
||
<div class="mt-2" id="regex-fields-container">
|
||
<!-- 字段-正则表达式配置行 -->
|
||
<div class="regex-field-row flex items-start mb-2 border border-gray-200 rounded-md p-2 bg-gray-50">
|
||
<div class="w-3/10 mr-2">
|
||
<label class="text-xs text-gray-600 mb-0 block">字段名称</label>
|
||
<input type="text" class="form-input regex-field-name" placeholder="如:合同编号">
|
||
</div>
|
||
<div class="w-7/10 mr-2">
|
||
<label class="text-xs text-gray-600 mb-0 block">正则表达式</label>
|
||
<input type="text" class="form-input regex-expression" placeholder="如:\\d{4}[-/年](0?[1-9]|1[0-2])[-/月](0?[1-9]|[12][0-9]|3[01])[日]?">
|
||
</div>
|
||
<div class="flex flex-col justify-end pt-3">
|
||
<button class="text-red-500 hover:text-red-700 remove-regex-field-row">
|
||
<i class="ri-delete-bin-line"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="mt-2">
|
||
<label class="form-label mb-1">常用正则模板</label>
|
||
<div class="flex flex-wrap gap-1 mt-1">
|
||
<div class="chip cursor-pointer regex-template" data-regex="\\d{4}[-/年](0?[1-9]|1[0-2])[-/月](0?[1-9]|[12][0-9]|3[01])[日]?">日期格式:yyyy-mm-dd</div>
|
||
<div class="chip cursor-pointer regex-template" data-regex="[A-Z]{2,5}-\\d{4,10}">合同编号格式</div>
|
||
<div class="chip cursor-pointer regex-template" data-regex="(人民币|RMB)?\\s?(\\d{1,3}(,\\d{3})*(\\.\\d{2})?)\\s?[万元]?">金额格式</div>
|
||
<div class="chip cursor-pointer regex-template" data-regex="\\d{3}-\\d{8}|\\d{4}-\\d{7,8}">座机号码格式</div>
|
||
<div class="chip cursor-pointer regex-template" data-regex="1[3-9]\\d{9}">手机号码格式</div>
|
||
<div class="chip cursor-pointer regex-template" data-regex="[1-9]\\d{5}(19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[\\dXx]">身份证号码格式</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<style>
|
||
/* 新增切换按钮样式 */
|
||
#extraction-method-tabs {
|
||
display: flex;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
background-color: white;
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
#extraction-method-tabs .tab-nav-item {
|
||
padding: 10px 16px;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
border-bottom: 2px solid transparent;
|
||
transition: all 0.3s;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
#extraction-method-tabs .tab-nav-item:hover {
|
||
color: var(--primary-color);
|
||
background-color: rgba(0, 104, 74, 0.05);
|
||
}
|
||
|
||
#extraction-method-tabs .tab-nav-item.active {
|
||
color: var(--primary-color);
|
||
border-bottom-color: var(--primary-color);
|
||
background-color: rgba(0, 104, 74, 0.1);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.extraction-config {
|
||
padding: 12px;
|
||
border: 1px solid #f0f0f0;
|
||
border-radius: 4px;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
/* 自定义宽度类 */
|
||
.w-3\/10 {
|
||
width: 30%;
|
||
}
|
||
|
||
.w-7\/10 {
|
||
width: 70%;
|
||
}
|
||
</style>
|
||
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// 初始化highlight.js
|
||
hljs.configure({
|
||
languages: ['javascript', 'python']
|
||
});
|
||
|
||
// 调试代码 - 确保页面加载后检查所有自定义提示词容器
|
||
// 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("设置提示词类型切换事件");
|
||
|
||
// 直接绑定事件到单选按钮
|
||
document.querySelectorAll('input[name="llm-prompt-type"]').forEach(radio => {
|
||
radio.addEventListener('change', function() {
|
||
// console.log("大模型提示词类型变更:", this.value);
|
||
const customContainer = document.getElementById('llm-custom-prompt-container');
|
||
const systemInfo = document.getElementById('llm-system-prompt-info');
|
||
|
||
if (this.value === 'system') {
|
||
if (customContainer) customContainer.style.display = 'none';
|
||
if (systemInfo) systemInfo.style.display = 'block';
|
||
} else {
|
||
if (customContainer) customContainer.style.display = 'block';
|
||
if (systemInfo) systemInfo.style.display = 'none';
|
||
}
|
||
});
|
||
});
|
||
|
||
document.querySelectorAll('input[name="multimodal-prompt-type"]').forEach(radio => {
|
||
radio.addEventListener('change', function() {
|
||
// console.log("多模态提示词类型变更:", this.value);
|
||
const customContainer = document.getElementById('multimodal-custom-prompt-container');
|
||
const systemInfo = document.getElementById('multimodal-system-prompt-info');
|
||
|
||
if (this.value === 'system') {
|
||
if (customContainer) customContainer.style.display = 'none';
|
||
if (systemInfo) systemInfo.style.display = 'block';
|
||
} else {
|
||
if (customContainer) customContainer.style.display = 'block';
|
||
if (systemInfo) systemInfo.style.display = 'none';
|
||
}
|
||
});
|
||
});
|
||
|
||
// 页面加载完成后,确保自定义提示词容器状态正确
|
||
function initPromptContainers() {
|
||
// console.log("初始化提示词容器状态");
|
||
|
||
// 大模型抽取
|
||
const llmPromptType = document.querySelector('input[name="llm-prompt-type"]:checked');
|
||
if (llmPromptType) {
|
||
// 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';
|
||
}
|
||
}
|
||
|
||
// 多模态抽取
|
||
const multimodalPromptType = document.querySelector('input[name="multimodal-prompt-type"]:checked');
|
||
if (multimodalPromptType) {
|
||
// 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';
|
||
}
|
||
}
|
||
}
|
||
|
||
// 确保初始化在页面完全加载后执行
|
||
setTimeout(initPromptContainers, 100);
|
||
|
||
// 抽取方式切换
|
||
const extractMethodTabs = document.querySelectorAll('#extraction-method-tabs .tab-nav-item');
|
||
const extractConfigs = {
|
||
'llm': document.getElementById('llm-config'),
|
||
'llm_ocr': document.getElementById('llm-ocr-config'),
|
||
'ocr_regex': document.getElementById('ocr-regex-config')
|
||
};
|
||
|
||
extractMethodTabs.forEach(tab => {
|
||
tab.addEventListener('click', function() {
|
||
// 移除所有tab的活动状态
|
||
extractMethodTabs.forEach(t => t.classList.remove('active'));
|
||
|
||
// 添加当前tab的活动状态
|
||
this.classList.add('active');
|
||
|
||
// 隐藏所有配置
|
||
Object.values(extractConfigs).forEach(config => {
|
||
if (config) config.classList.add('hidden');
|
||
});
|
||
|
||
// 显示选中的配置
|
||
const method = this.getAttribute('data-method');
|
||
if (extractConfigs[method]) {
|
||
extractConfigs[method].classList.remove('hidden');
|
||
}
|
||
});
|
||
});
|
||
|
||
// 原有的其他 JavaScript 代码保持不变...
|
||
});
|
||
</script>
|
||
|
||
<!-- 评查设置 -->
|
||
<div class="ant-card">
|
||
<div class="ant-card-header">
|
||
<h3>评查设置</h3>
|
||
</div>
|
||
<div class="ant-card-body">
|
||
<div class="flex items-center justify-between mb-4">
|
||
<div>
|
||
<h5 class="font-medium">评查逻辑规则</h5>
|
||
<div class="text-sm text-secondary mt-1">可添加多个评查规则,通过组合逻辑实现复杂评查</div>
|
||
</div>
|
||
<div>
|
||
<span class="badge rounded-pill bg-primary text-white px-2 py-1" id="logic-count">1个规则</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mb-6">
|
||
<label class="form-label">
|
||
组合逻辑 <span class="required-mark">*</span>
|
||
</label>
|
||
<div class="form-radio-group">
|
||
<label class="form-radio-item">
|
||
<input type="radio" name="ruleLogic" class="form-radio" value="all" checked>
|
||
<span>全部满足(AND)</span>
|
||
</label>
|
||
<label class="form-radio-item">
|
||
<input type="radio" name="ruleLogic" class="form-radio" value="any">
|
||
<span>任一满足(OR)</span>
|
||
</label>
|
||
<label class="form-radio-item">
|
||
<input type="radio" name="ruleLogic" class="form-radio" value="custom">
|
||
<span>自定义组合</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 自定义组合逻辑配置 -->
|
||
<div class="mb-6 hidden" id="rule-custom-logic">
|
||
<label class="form-label">自定义组合逻辑 <span class="required-mark">*</span></label>
|
||
<textarea class="form-textarea" placeholder="请输入自定义组合逻辑,例如:(规则1 AND 规则2) OR 规则3"></textarea>
|
||
<div class="form-tip">使用规则编号和逻辑运算符(AND、OR、NOT)组合</div>
|
||
</div>
|
||
|
||
<!-- 评查规则容器 -->
|
||
<div id="rule-items-container">
|
||
<!-- 第一条评查规则 -->
|
||
<div class="rule-item border border-dashed border-gray-300 rounded-md p-6 mb-6 relative">
|
||
<div class="absolute top-3 right-3 flex gap-2">
|
||
<span class="badge rounded-pill bg-primary text-white px-2 py-1">规则 #1</span>
|
||
<button class="text-gray-400 hover:text-red-500" disabled>
|
||
<i class="ri-delete-bin-line"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="mb-4">
|
||
<label class="form-label">
|
||
评查类型 <span class="required-mark">*</span>
|
||
</label>
|
||
<select class="form-select rule-type-select" data-index="1">
|
||
<option value="">请选择评查类型</option>
|
||
<option value="exists">有无判断</option>
|
||
<option value="consistency">一致性判断</option>
|
||
<option value="format">格式判断</option>
|
||
<option value="logic">逻辑判断</option>
|
||
<option value="regex">正则表达式</option>
|
||
<option value="ai">大模型判断</option>
|
||
<option value="code">自定义代码</option>
|
||
</select>
|
||
<div class="form-tip">选择评查类型后将显示对应的配置项</div>
|
||
</div>
|
||
|
||
<!-- 规则配置区域 - 将动态显示 -->
|
||
<div class="rule-config-container" data-index="1">
|
||
<!-- 配置内容将根据选择的评查类型动态加载 -->
|
||
<div class="rule-placeholder text-center py-6 text-secondary">
|
||
<i class="ri-settings-3-line text-4xl mb-2 block"></i>
|
||
<p>请先选择评查类型</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 添加规则按钮 -->
|
||
<div class="text-center mb-6">
|
||
<button class="ant-btn ant-btn-default" id="add-rule-btn">
|
||
<i class="ri-add-line mr-1"></i> 添加评查规则
|
||
</button>
|
||
</div>
|
||
|
||
<div class="divider"></div>
|
||
|
||
<!-- 评查结果提示信息 -->
|
||
<div class="mb-4">
|
||
<label class="form-label">
|
||
评查结果提示信息
|
||
</label>
|
||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||
<div>
|
||
<label class="form-label text-sm">评查通过信息</label>
|
||
<textarea class="form-textarea" style="height: 80px !important; min-height: 60px !important;" rows="1" placeholder="请输入评查通过时的提示信息">文档检查通过,符合规范要求。</textarea>
|
||
</div>
|
||
<div>
|
||
<label class="form-label text-sm">评查不通过信息</label>
|
||
<textarea class="form-textarea" style="height: 80px !important; min-height: 60px !important;" rows="1" placeholder="请输入评查不通过时的提示信息">文档存在以下问题,请修改后重新提交。</textarea>
|
||
</div>
|
||
<div>
|
||
<label class="form-label text-sm">建议信息</label>
|
||
<textarea class="form-textarea" style="height: 80px !important; min-height: 60px !important;" rows="1" placeholder="请输入对用户的建议信息"></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- 不通过提示类别 -->
|
||
<style>
|
||
/* 隐藏单选按钮 */
|
||
.severity-radio {
|
||
position: absolute;
|
||
opacity: 0;
|
||
width: 0;
|
||
height: 0;
|
||
}
|
||
</style>
|
||
|
||
<div class="mb-4">
|
||
<label class="form-label">建议信息类别</label>
|
||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||
<label class="flex items-center cursor-pointer border-l-4 border-blue-500 bg-blue-50 p-3 hover:bg-blue-100 rounded-r-md severity-option" data-value="info">
|
||
<input type="radio" name="errorSeverity" class="severity-radio" value="info">
|
||
<i class="ri-information-line text-blue-500 text-xl mr-3"></i>
|
||
<div>
|
||
<div class="font-medium">提示 (Info)</div>
|
||
<div class="text-sm text-gray-500">提示性信息,不影响</div>
|
||
</div>
|
||
</label>
|
||
|
||
<label class="flex items-center cursor-pointer border-l-4 border-yellow-500 bg-yellow-50 p-3 hover:bg-yellow-100 rounded-r-md severity-option" data-value="warning">
|
||
<input type="radio" name="errorSeverity" class="severity-radio" value="warning">
|
||
<i class="ri-alert-line text-yellow-500 text-xl mr-3"></i>
|
||
<div>
|
||
<div class="font-medium">警告 (Warning)</div>
|
||
<div class="text-sm text-gray-500">警告信息,建议修改但不强制</div>
|
||
</div>
|
||
</label>
|
||
|
||
<label class="flex items-center cursor-pointer border-l-4 border-red-500 bg-red-50 p-3 hover:bg-red-100 rounded-r-md severity-option" data-value="error">
|
||
<input type="radio" name="errorSeverity" class="severity-radio" value="error" checked>
|
||
<i class="ri-error-warning-line text-red-500 text-xl mr-3"></i>
|
||
<div>
|
||
<div class="font-medium">错误 (Error)</div>
|
||
<div class="text-sm text-gray-500">严重错误,必须修正</div>
|
||
</div>
|
||
</label>
|
||
</div>
|
||
<div class="form-tip">不同类别会影响问题的展示方式和处理流程</div>
|
||
</div>
|
||
|
||
<script>
|
||
// 为不通过提示类别添加单选效果
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
const severityOptions = document.querySelectorAll('.severity-option');
|
||
const severityRadios = document.querySelectorAll('.severity-radio');
|
||
|
||
// 初始化选中状态
|
||
updateSelectedState();
|
||
|
||
// 为每个选项添加点击事件
|
||
severityOptions.forEach(option => {
|
||
option.addEventListener('click', function() {
|
||
const radio = this.querySelector('input[type="radio"]');
|
||
radio.checked = true;
|
||
updateSelectedState();
|
||
});
|
||
});
|
||
|
||
// 更新选中状态的函数
|
||
function updateSelectedState() {
|
||
severityOptions.forEach(option => {
|
||
const radio = option.querySelector('input[type="radio"]');
|
||
if (radio.checked) {
|
||
option.classList.add('selected-severity');
|
||
option.style.borderLeftWidth = '8px';
|
||
option.style.boxShadow = '0 0 0 2px ' + getSeverityColor(radio.value);
|
||
} else {
|
||
option.classList.remove('selected-severity');
|
||
option.style.borderLeftWidth = '4px';
|
||
option.style.boxShadow = 'none';
|
||
}
|
||
});
|
||
}
|
||
|
||
// 获取对应的颜色
|
||
function getSeverityColor(value) {
|
||
switch(value) {
|
||
case 'info': return 'rgba(59, 130, 246, 0.5)'; // 蓝色
|
||
case 'warning': return 'rgba(245, 158, 11, 0.5)'; // 黄色
|
||
case 'error': return 'rgba(239, 68, 68, 0.5)'; // 红色
|
||
default: return 'transparent';
|
||
}
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<!-- 评查后动作 -->
|
||
<div class="mb-4">
|
||
<label class="form-label">
|
||
评查后动作 <span class="required-mark">*</span>
|
||
</label>
|
||
<select class="form-select" id="action-type">
|
||
<option value="none" selected>无</option>
|
||
<option value="manual">人工确认</option>
|
||
<option value="replace">内容替换</option>
|
||
</select>
|
||
</div>
|
||
|
||
<!-- 动作描述区域 -->
|
||
<div class="mb-4 hidden" id="action-description-container">
|
||
<label class="form-label">动作描述</label>
|
||
<textarea class="form-textarea" id="action-description" placeholder="请输入动作描述,说明评查通过或未通过时的处理方式">若合同缺少必要信息,系统将自动提醒用户补充相关内容</textarea>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 操作按钮区 -->
|
||
<div class="flex justify-between mt-6 pb-10">
|
||
<button class="ant-btn ant-btn-default">
|
||
<i class="ri-draft-line"></i> 保存为草稿
|
||
</button>
|
||
<div>
|
||
<button class="ant-btn ant-btn-default mr-2">
|
||
<i class="ri-arrow-left-line"></i> 返回
|
||
</button>
|
||
<button class="ant-btn ant-btn-primary">
|
||
<i class="ri-save-line"></i> 保存
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// 初始化highlight.js
|
||
hljs.configure({
|
||
languages: ['javascript', 'python']
|
||
});
|
||
|
||
// 调试代码 - 确保页面加载后检查所有自定义提示词容器
|
||
// 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("设置提示词类型切换事件");
|
||
|
||
// 直接绑定事件到单选按钮
|
||
document.querySelectorAll('input[name="llm-prompt-type"]').forEach(radio => {
|
||
radio.addEventListener('change', function() {
|
||
// console.log("大模型提示词类型变更:", this.value);
|
||
const customContainer = document.getElementById('llm-custom-prompt-container');
|
||
const systemInfo = document.getElementById('llm-system-prompt-info');
|
||
|
||
if (this.value === 'system') {
|
||
if (customContainer) customContainer.style.display = 'none';
|
||
if (systemInfo) systemInfo.style.display = 'block';
|
||
} else {
|
||
if (customContainer) customContainer.style.display = 'block';
|
||
if (systemInfo) systemInfo.style.display = 'none';
|
||
}
|
||
});
|
||
});
|
||
|
||
document.querySelectorAll('input[name="multimodal-prompt-type"]').forEach(radio => {
|
||
radio.addEventListener('change', function() {
|
||
// console.log("多模态提示词类型变更:", this.value);
|
||
const customContainer = document.getElementById('multimodal-custom-prompt-container');
|
||
const systemInfo = document.getElementById('multimodal-system-prompt-info');
|
||
|
||
if (this.value === 'system') {
|
||
if (customContainer) customContainer.style.display = 'none';
|
||
if (systemInfo) systemInfo.style.display = 'block';
|
||
} else {
|
||
if (customContainer) customContainer.style.display = 'block';
|
||
if (systemInfo) systemInfo.style.display = 'none';
|
||
}
|
||
});
|
||
});
|
||
|
||
// 页面加载完成后,确保自定义提示词容器状态正确
|
||
function initPromptContainers() {
|
||
// console.log("初始化提示词容器状态");
|
||
|
||
// 大模型抽取
|
||
const llmPromptType = document.querySelector('input[name="llm-prompt-type"]:checked');
|
||
if (llmPromptType) {
|
||
// 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';
|
||
}
|
||
}
|
||
|
||
// 多模态抽取
|
||
const multimodalPromptType = document.querySelector('input[name="multimodal-prompt-type"]:checked');
|
||
if (multimodalPromptType) {
|
||
// 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';
|
||
}
|
||
}
|
||
}
|
||
|
||
// 确保初始化在页面完全加载后执行
|
||
setTimeout(initPromptContainers, 100);
|
||
|
||
// 抽取方式切换
|
||
const extractMethodTabs = document.querySelectorAll('#extraction-method-tabs .tab-nav-item');
|
||
const extractConfigs = {
|
||
'llm': document.getElementById('llm-config'),
|
||
'llm_ocr': document.getElementById('llm-ocr-config'),
|
||
'ocr_regex': document.getElementById('ocr-regex-config')
|
||
};
|
||
|
||
extractMethodTabs.forEach(tab => {
|
||
tab.addEventListener('click', function() {
|
||
// 移除所有tab的活动状态
|
||
extractMethodTabs.forEach(t => t.classList.remove('active'));
|
||
|
||
// 添加当前tab的活动状态
|
||
this.classList.add('active');
|
||
|
||
// 隐藏所有配置
|
||
Object.values(extractConfigs).forEach(config => {
|
||
if (config) config.classList.add('hidden');
|
||
});
|
||
|
||
// 显示选中的配置
|
||
const method = this.getAttribute('data-method');
|
||
if (extractConfigs[method]) {
|
||
extractConfigs[method].classList.remove('hidden');
|
||
}
|
||
});
|
||
});
|
||
|
||
// 评查后动作切换
|
||
const actionTypeSelect = document.getElementById('action-type');
|
||
const actionTemplates = {
|
||
'info': document.getElementById('info-template'),
|
||
'manual': document.getElementById('manual-template'),
|
||
'replace': document.getElementById('replace-template')
|
||
};
|
||
const actionDescriptionContainer = document.getElementById('action-description-container');
|
||
|
||
actionTypeSelect.addEventListener('change', function() {
|
||
// 隐藏所有模板
|
||
Object.values(actionTemplates).forEach(template => {
|
||
if (template) template.classList.add('hidden');
|
||
});
|
||
|
||
// 判断是否选择了"无"
|
||
if (this.value === 'none') {
|
||
actionDescriptionContainer.classList.add('hidden');
|
||
} else {
|
||
actionDescriptionContainer.classList.remove('hidden');
|
||
|
||
// 显示选中的模板
|
||
const selectedAction = this.value;
|
||
if (selectedAction && actionTemplates[selectedAction]) {
|
||
actionTemplates[selectedAction].classList.remove('hidden');
|
||
}
|
||
}
|
||
});
|
||
|
||
// 使用模板按钮
|
||
const templateBtns = document.querySelectorAll('.use-template-btn');
|
||
templateBtns.forEach(btn => {
|
||
btn.addEventListener('click', function() {
|
||
const targetId = this.getAttribute('data-target');
|
||
const target = targetId ? document.getElementById(targetId) :
|
||
this.closest('.template-card').previousElementSibling;
|
||
if (target) {
|
||
const template = this.closest('.template-card').querySelector('.template-content').textContent;
|
||
target.value = template;
|
||
target.focus();
|
||
}
|
||
});
|
||
});
|
||
|
||
// 字段添加功能 - LLM抽取
|
||
setupFieldsManager('field-input', 'add-field-btn', 'fields-container');
|
||
|
||
// 字段添加功能 - OCR+LLM
|
||
setupFieldsManager('field-input-ocr', 'add-field-btn-ocr', 'fields-container-ocr');
|
||
|
||
// 模板提示词选择功能
|
||
setupPromptTemplateSelector('prompt-template-select', 'llm-config');
|
||
setupPromptTemplateSelector('prompt-template-select-ocr', 'llm-ocr-config');
|
||
|
||
// 正则表达式模板点击功能
|
||
document.querySelectorAll('.regex-template').forEach(template => {
|
||
template.addEventListener('click', function() {
|
||
const regex = this.getAttribute('data-regex');
|
||
// 获取当前选中/激活的正则表达式输入框
|
||
const activeTextarea = document.activeElement;
|
||
let targetTextarea;
|
||
|
||
// 如果当前激活的元素是正则表达式输入框,则向其添加模板
|
||
if (activeTextarea && activeTextarea.classList.contains('regex-expression')) {
|
||
targetTextarea = activeTextarea;
|
||
} else {
|
||
// 否则查找页面上的最后一个正则表达式输入框
|
||
const allTextareas = document.querySelectorAll('.regex-expression');
|
||
if (allTextareas.length > 0) {
|
||
targetTextarea = allTextareas[allTextareas.length - 1];
|
||
}
|
||
}
|
||
|
||
// 如果找到目标输入框,向其添加正则模板
|
||
if (targetTextarea) {
|
||
targetTextarea.value = regex;
|
||
targetTextarea.focus();
|
||
}
|
||
});
|
||
});
|
||
|
||
// 添加正则字段行
|
||
const addRegexFieldRowBtn = document.getElementById('add-regex-field-row');
|
||
if (addRegexFieldRowBtn) {
|
||
addRegexFieldRowBtn.addEventListener('click', function() {
|
||
addRegexFieldRow();
|
||
});
|
||
}
|
||
|
||
// 初始化已有的删除按钮
|
||
initRegexFieldRowButtons();
|
||
|
||
// 添加正则字段行函数
|
||
function addRegexFieldRow() {
|
||
const container = document.getElementById('regex-fields-container');
|
||
if (container) {
|
||
// 创建新的字段行
|
||
const newRow = document.createElement('div');
|
||
newRow.className = 'regex-field-row flex items-start mb-3 border border-gray-200 rounded-md p-3 bg-gray-50';
|
||
|
||
newRow.innerHTML = `
|
||
<div class="w-3/10 mr-3">
|
||
<label class="text-sm text-gray-600 mb-1 block">字段名称</label>
|
||
<input type="text" class="form-input regex-field-name" placeholder="如:合同编号">
|
||
</div>
|
||
<div class="w-7/10 mr-3">
|
||
<label class="text-sm text-gray-600 mb-1 block">正则表达式</label>
|
||
<input type="text" class="form-input regex-expression" placeholder="如:\\d{4}[-/年](0?[1-9]|1[0-2])[-/月](0?[1-9]|[12][0-9]|3[01])[日]?">
|
||
</div>
|
||
<div class="flex flex-col justify-end pt-5">
|
||
<button class="text-red-500 hover:text-red-700 remove-regex-field-row">
|
||
<i class="ri-delete-bin-line"></i>
|
||
</button>
|
||
</div>
|
||
`;
|
||
|
||
// 添加到容器中
|
||
container.appendChild(newRow);
|
||
|
||
// 绑定删除按钮事件
|
||
const removeBtn = newRow.querySelector('.remove-regex-field-row');
|
||
if (removeBtn) {
|
||
removeBtn.addEventListener('click', function() {
|
||
newRow.remove();
|
||
});
|
||
}
|
||
|
||
// 自动聚焦到新添加的字段名称输入框
|
||
const fieldNameInput = newRow.querySelector('.regex-field-name');
|
||
if (fieldNameInput) {
|
||
fieldNameInput.focus();
|
||
}
|
||
}
|
||
}
|
||
|
||
// 初始化正则字段行按钮
|
||
function initRegexFieldRowButtons() {
|
||
document.querySelectorAll('.remove-regex-field-row').forEach(btn => {
|
||
btn.addEventListener('click', function() {
|
||
this.closest('.regex-field-row').remove();
|
||
});
|
||
});
|
||
}
|
||
|
||
// 通用函数设置字段管理器
|
||
function setupFieldsManager(inputId, btnId, containerId) {
|
||
const fieldInput = document.getElementById(inputId);
|
||
const addFieldBtn = document.getElementById(btnId);
|
||
const fieldsContainer = document.getElementById(containerId);
|
||
const fieldTypeSelect = inputId === 'field-input' ? document.getElementById('field-type') : null; // 仅多模态抽取有类型
|
||
|
||
if (addFieldBtn) {
|
||
addFieldBtn.addEventListener('click', function() {
|
||
if (fieldInput.value.trim()) {
|
||
if (fieldTypeSelect) {
|
||
// 多模态抽取,带类型
|
||
const fieldValue = fieldInput.value.trim();
|
||
const fieldType = fieldTypeSelect.value;
|
||
const fieldTypeName = fieldTypeSelect.options[fieldTypeSelect.selectedIndex].text;
|
||
|
||
// 创建字段标签
|
||
const chip = document.createElement('div');
|
||
chip.className = 'chip';
|
||
|
||
// 设置不同类型的徽章颜色
|
||
let badgeClass = 'bg-blue-100 text-blue-800';
|
||
switch(fieldType) {
|
||
case 'seal': badgeClass = 'bg-red-100 text-red-800'; break;
|
||
case 'cross-seal': badgeClass = 'bg-red-100 text-red-800'; break;
|
||
case 'handwriting': badgeClass = 'bg-yellow-100 text-yellow-800'; break;
|
||
case 'print': badgeClass = 'bg-purple-100 text-purple-800'; break;
|
||
case 'english': badgeClass = 'bg-indigo-100 text-indigo-800'; break;
|
||
case 'number': badgeClass = 'bg-gray-100 text-gray-800'; break;
|
||
case 'currency': badgeClass = 'bg-green-100 text-green-800'; break;
|
||
}
|
||
|
||
chip.innerHTML = `${fieldValue} <span class="badge ${badgeClass} text-xs ml-1" data-type="${fieldType}">${fieldTypeName}</span> <span class="close-btn">×</span>`;
|
||
chip.setAttribute('data-field-type', fieldType);
|
||
fieldsContainer.appendChild(chip);
|
||
|
||
// 绑定删除事件
|
||
chip.querySelector('.close-btn').addEventListener('click', function() {
|
||
chip.remove();
|
||
});
|
||
|
||
// 清空输入框,重置类型选择
|
||
fieldInput.value = '';
|
||
fieldTypeSelect.value = 'default';
|
||
} else {
|
||
// 标准字段管理,分割多个字段
|
||
const fieldValues = fieldInput.value.split(/[\s、,]+/).map(value => value.trim()).filter(value => value !== '');
|
||
|
||
// 添加每个字段
|
||
fieldValues.forEach(fieldValue => {
|
||
if (fieldValue) {
|
||
const chip = document.createElement('div');
|
||
chip.className = 'chip';
|
||
chip.innerHTML = `${fieldValue} <span class="close-btn">×</span>`;
|
||
fieldsContainer.appendChild(chip);
|
||
|
||
// 绑定删除事件
|
||
chip.querySelector('.close-btn').addEventListener('click', function() {
|
||
chip.remove();
|
||
});
|
||
}
|
||
});
|
||
|
||
fieldInput.value = '';
|
||
}
|
||
|
||
fieldInput.focus();
|
||
}
|
||
});
|
||
}
|
||
|
||
// 已有的字段绑定删除事件
|
||
if (fieldsContainer) {
|
||
fieldsContainer.querySelectorAll('.close-btn').forEach(btn => {
|
||
btn.addEventListener('click', function() {
|
||
this.closest('.chip').remove();
|
||
});
|
||
});
|
||
}
|
||
}
|
||
|
||
// 设置提示词模板选择器
|
||
function setupPromptTemplateSelector(selectId, configId) {
|
||
const select = document.getElementById(selectId);
|
||
const container = document.getElementById(configId);
|
||
const textarea = container.querySelector('textarea');
|
||
|
||
if (select && textarea) {
|
||
select.addEventListener('change', function() {
|
||
if (this.value && this.value !== 'custom') {
|
||
// 这里可以根据选择的模板设置不同的提示词
|
||
const templates = {
|
||
'template1': `从合同文本中抽取以下信息:
|
||
1. 合同编号
|
||
2. 合同金额(人民币)
|
||
3. 签订日期
|
||
4. 甲方名称
|
||
5. 乙方名称
|
||
|
||
仅返回JSON格式:
|
||
{
|
||
"合同编号": "",
|
||
"合同金额": "",
|
||
"签订日期": "",
|
||
"甲方名称": "",
|
||
"乙方名称": ""
|
||
}`,
|
||
'template2': `从合同中抽取付款条件相关信息:
|
||
1. 付款方式
|
||
2. 付款时间
|
||
3. 付款条件
|
||
4. 违约金比例
|
||
|
||
仅返回JSON格式`,
|
||
'template3': `从合同中抽取交付方式相关信息:
|
||
1. 交付时间
|
||
2. 交付地点
|
||
3. 交付方式
|
||
4. 验收标准
|
||
|
||
仅返回JSON格式`
|
||
};
|
||
|
||
textarea.value = templates[this.value] || '';
|
||
} else if (this.value === 'custom') {
|
||
// 选择自定义,保留现有内容或清空
|
||
// textarea.value = '';
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
// 评查规则类型切换
|
||
function setupRuleTypeSelect(select) {
|
||
select.addEventListener('change', function() {
|
||
const ruleIndex = this.getAttribute('data-index');
|
||
const configContainer = document.querySelector(`.rule-config-container[data-index="${ruleIndex}"]`);
|
||
const selectedType = this.value;
|
||
|
||
// 清空当前配置
|
||
configContainer.innerHTML = '';
|
||
|
||
if (!selectedType) {
|
||
configContainer.innerHTML = `
|
||
<div class="rule-placeholder text-center py-6 text-secondary">
|
||
<i class="ri-settings-3-line text-4xl mb-2 block"></i>
|
||
<p>请先选择评查类型</p>
|
||
</div>
|
||
`;
|
||
return;
|
||
}
|
||
|
||
// 更新规则项的类型标识
|
||
const ruleItem = this.closest('.rule-item');
|
||
const badge = ruleItem.querySelector('.badge');
|
||
|
||
// 添加评查类型标签
|
||
badge.classList.remove('bg-primary', 'rule-type-exists', 'rule-type-consistency', 'rule-type-format',
|
||
'rule-type-logic', 'rule-type-regex', 'rule-type-ai', 'rule-type-code');
|
||
|
||
switch(selectedType) {
|
||
case 'exists':
|
||
badge.classList.add('rule-type-exists');
|
||
break;
|
||
case 'consistency':
|
||
badge.classList.add('rule-type-consistency');
|
||
break;
|
||
case 'format':
|
||
badge.classList.add('rule-type-format');
|
||
break;
|
||
case 'logic':
|
||
badge.classList.add('rule-type-logic');
|
||
break;
|
||
case 'regex':
|
||
badge.classList.add('rule-type-regex');
|
||
break;
|
||
case 'ai':
|
||
badge.classList.add('rule-type-ai');
|
||
break;
|
||
case 'code':
|
||
badge.classList.add('rule-type-code');
|
||
break;
|
||
default:
|
||
badge.classList.add('bg-primary');
|
||
}
|
||
|
||
// 加载对应类型的配置
|
||
loadRuleConfig(selectedType, configContainer, ruleIndex);
|
||
});
|
||
}
|
||
|
||
// 加载评查规则配置
|
||
function loadRuleConfig(type, container, index) {
|
||
let configHTML = '';
|
||
|
||
switch(type) {
|
||
case 'exists':
|
||
configHTML = `
|
||
<div class="config-section">
|
||
<div class="mb-4">
|
||
<label class="form-label">可选字段 <span class="required-mark">*</span></label>
|
||
<div class="field-tags-container exists-fields-container" id="exists-fields-container-${index}">
|
||
<!-- 这些标签将从抽取设置中动态生成 -->
|
||
</div>
|
||
<div class="form-tip mt-2">点击选择需要判断是否存在的字段,已选中的字段会高亮显示</div>
|
||
</div>
|
||
<div class="mb-4">
|
||
<label class="form-label">判断逻辑 <span class="required-mark">*</span></label>
|
||
<div class="form-radio-group">
|
||
<label class="form-radio-item">
|
||
<input type="radio" name="existsLogic_${index}" class="form-radio" value="all" checked>
|
||
<span>所有字段必须存在</span>
|
||
</label>
|
||
<label class="form-radio-item">
|
||
<input type="radio" name="existsLogic_${index}" class="form-radio" value="any">
|
||
<span>任一字段存在即可</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
break;
|
||
|
||
case 'consistency':
|
||
configHTML = `
|
||
<div class="config-section">
|
||
<div class="mb-4">
|
||
<label class="form-label">比较字段配置 <span class="required-mark">*</span></label>
|
||
<div id="consistency-fields-container-${index}">
|
||
<div class="bg-gray-50 p-4 rounded-md mb-2">
|
||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-2">
|
||
<div>
|
||
<label class="form-label text-sm">源字段</label>
|
||
<select class="form-select">
|
||
<option value="">请选择源字段</option>
|
||
<option value="甲方名称">甲方名称</option>
|
||
<option value="合同金额大写">合同金额大写</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="form-label text-sm">目标字段</label>
|
||
<select class="form-select">
|
||
<option value="">请选择目标字段</option>
|
||
<option value="甲方签章">甲方签章</option>
|
||
<option value="合同金额小写">合同金额小写</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="form-label text-sm">比较方式 <span class="required-mark">*</span></label>
|
||
<select class="form-select">
|
||
<option value="">请选择比较方式</option>
|
||
<option value="exact">精确匹配</option>
|
||
<option value="contains">包含关系</option>
|
||
<option value="semantic">大模型语义匹配</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="flex justify-end">
|
||
<button class="text-red-500 hover:text-red-700 consistency-remove-btn">
|
||
<i class="ri-delete-bin-line"></i> 删除
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<button class="ant-btn ant-btn-default add-consistency-pair-btn" data-index="${index}">
|
||
<i class="ri-add-line"></i> 添加比较对
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="mb-4">
|
||
<label class="form-label">逻辑关系 <span class="required-mark">*</span></label>
|
||
<div class="form-radio-group">
|
||
<label class="form-radio-item">
|
||
<input type="radio" name="logicRelation_${index}" class="form-radio" value="and" checked>
|
||
<span>AND(所有条件都满足)</span>
|
||
</label>
|
||
<label class="form-radio-item">
|
||
<input type="radio" name="logicRelation_${index}" class="form-radio" value="or">
|
||
<span>OR(任一条件满足)</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
break;
|
||
|
||
case 'format':
|
||
configHTML = `
|
||
<div class="config-section">
|
||
<div class="mb-4">
|
||
<label class="form-label">判断字段 <span class="required-mark">*</span></label>
|
||
<select class="form-select">
|
||
<option value="">请选择判断字段</option>
|
||
<option value="签订日期">签订日期</option>
|
||
<option value="合同编号">合同编号</option>
|
||
<option value="联系电话">联系电话</option>
|
||
</select>
|
||
</div>
|
||
<div class="mb-4">
|
||
<label class="form-label">格式类型 <span class="required-mark">*</span></label>
|
||
<select class="form-select format-type" data-index="${index}">
|
||
<option value="">请选择格式类型</option>
|
||
<option value="date">日期格式</option>
|
||
<option value="number">数字格式</option>
|
||
<option value="phone">电话号码</option>
|
||
<option value="email">电子邮箱</option>
|
||
<option value="bankcard">银行卡号</option>
|
||
<option value="idcard">身份证号码</option>
|
||
<option value="zipcode">邮政编码</option>
|
||
<option value="uscc">统一社会信用代码</option>
|
||
</select>
|
||
</div>
|
||
<div class="mb-4">
|
||
<label class="form-label">参数设置</label>
|
||
<input type="text" class="form-input" placeholder="请输入参数设置">
|
||
</div>
|
||
</div>
|
||
`;
|
||
break;
|
||
|
||
case 'logic':
|
||
configHTML = `
|
||
<div class="config-section">
|
||
<div class="mb-4">
|
||
<label class="form-label">条件设置 <span class="required-mark">*</span></label>
|
||
<div class="conditions-container" id="conditions-container-${index}">
|
||
<div class="condition-row bg-gray-50 p-4 rounded-md mb-2">
|
||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-2">
|
||
<div>
|
||
<label class="form-label text-sm">字段</label>
|
||
<select class="form-select">
|
||
<option value="">请选择字段</option>
|
||
<option value="合同金额">合同金额</option>
|
||
<option value="签订日期">签订日期</option>
|
||
<option value="合同期限">合同期限</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="form-label text-sm">运算符</label>
|
||
<select class="form-select">
|
||
<option value="eq">等于 (=)</option>
|
||
<option value="neq"> (≠)</option>
|
||
<option value="gt">大于 (>)</option>
|
||
<option value="gte">大于等于 (≥)</option>
|
||
<option value="lt">小于 (<)</option>
|
||
<option value="lte">小于等于 (≤)</option>
|
||
<option value="contains">包含</option>
|
||
<option value="not_contains">不包含</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="form-label text-sm">值</label>
|
||
<input type="text" class="form-input" placeholder="请输入比较值">
|
||
</div>
|
||
</div>
|
||
<div class="flex justify-end">
|
||
<button class="text-red-500 hover:text-red-700 remove-condition-btn">
|
||
<i class="ri-delete-bin-line"></i> 删除
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="mt-2">
|
||
<button class="ant-btn ant-btn-default add-condition-btn" data-index="${index}">
|
||
<i class="ri-add-line"></i> 添加条件
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="mb-4">
|
||
<label class="form-label">逻辑关系 <span class="required-mark">*</span></label>
|
||
<div class="form-radio-group">
|
||
<label class="form-radio-item">
|
||
<input type="radio" name="logicRelation_${index}" class="form-radio" value="and" checked>
|
||
<span>AND(所有条件都满足)</span>
|
||
</label>
|
||
<label class="form-radio-item">
|
||
<input type="radio" name="logicRelation_${index}" class="form-radio" value="or">
|
||
<span>OR(任一条件满足)</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
break;
|
||
|
||
case 'regex':
|
||
configHTML = `
|
||
<div class="config-section">
|
||
<div class="mb-4">
|
||
<label class="form-label">检查字段 <span class="required-mark">*</span></label>
|
||
<select class="form-select">
|
||
<option value="">请选择检查字段</option>
|
||
<option value="合同编号">合同编号</option>
|
||
<option value="甲方名称">甲方名称</option>
|
||
<option value="合同正文">合同正文</option>
|
||
</select>
|
||
</div>
|
||
<div class="mb-4">
|
||
<label class="form-label">正则表达式 <span class="required-mark">*</span></label>
|
||
<textarea class="form-textarea" placeholder="请输入正则表达式"></textarea>
|
||
</div>
|
||
<div class="mb-4">
|
||
<label class="form-label">匹配类型 <span class="required-mark">*</span></label>
|
||
<div class="form-radio-group">
|
||
<label class="form-radio-item">
|
||
<input type="radio" name="regexMatchType_${index}" class="form-radio" value="match" checked>
|
||
<span>必须匹配(符合为通过)</span>
|
||
</label>
|
||
<label class="form-radio-item">
|
||
<input type="radio" name="regexMatchType_${index}" class="form-radio" value="not_match">
|
||
<span>不得匹配(不符合为通过)</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
break;
|
||
|
||
case 'ai':
|
||
configHTML = `
|
||
<div class="config-section">
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||
<div>
|
||
<label class="form-label">
|
||
模型选择 <span class="required-mark">*</span>
|
||
</label>
|
||
<select class="form-select">
|
||
<option value="deepseek">DeepSeek</option>
|
||
<option value="qwen72b">Qwen72B-VL</option>
|
||
<option value="qwen14b">Qwen14B</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="form-label">温度参数</label>
|
||
<input type="number" class="form-input" placeholder="0.1" value="0.1" min="0" max="1" step="0.1">
|
||
</div>
|
||
<div class="col-span-1 md:col-span-2">
|
||
<label class="form-label">大模型 Prompt <span class="required-mark">*</span></label>
|
||
<textarea class="form-textarea ai-prompt-textarea" placeholder="请输入提示词,引导模型进行判断">请判断以下{字段}内容是否符合规范要求,仅回答"符合"或"不符合",并简要说明理由。
|
||
|
||
{字段内容}</textarea>
|
||
</div>
|
||
<!-- Tag Buttons Section -->
|
||
<div class="col-span-1 md:col-span-2 flex flex-wrap gap-2 mt-2">
|
||
<button class="ant-btn ant-btn-default tag-button" data-tag="合同编号">合同编号</button>
|
||
<button class="ant-btn ant-btn-default tag-button" data-tag="合同金额">合同金额</button>
|
||
<button class="ant-btn ant-btn-default tag-button" data-tag="签订日期">签订日期</button>
|
||
<button class="ant-btn ant-btn-default tag-button" data-tag="甲方名称">甲方名称</button>
|
||
<button class="ant-btn ant-btn-default tag-button" data-tag="乙方名称">乙方名称</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
break;
|
||
|
||
case 'code':
|
||
configHTML = `
|
||
<div class="config-section">
|
||
<div class="mb-4">
|
||
<label class="form-label">代码语言 <span class="required-mark">*</span></label>
|
||
<div class="form-radio-group">
|
||
<label class="form-radio-item">
|
||
<input type="radio" name="codeLanguage_${index}" class="form-radio code-language-radio" value="javascript" checked>
|
||
<span>JavaScript</span>
|
||
</label>
|
||
<label class="form-radio-item">
|
||
<input type="radio" name="codeLanguage_${index}" class="form-radio code-language-radio" value="python">
|
||
<span>Python</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<div class="mb-4">
|
||
<label class="form-label">自定义代码 <span class="required-mark">*</span></label>
|
||
<div class="code-editor-wrapper">
|
||
<div class="code-editor-header">
|
||
<div class="code-editor-filename" id="filename-${index}">script.js</div>
|
||
<div class="code-editor-actions">
|
||
<i class="ri-file-copy-line code-copy-btn" title="复制代码" data-index="${index}"></i>
|
||
</div>
|
||
</div>
|
||
<div class="code-editor-container">
|
||
<textarea class="code-editor-textarea" id="code-editor-${index}" placeholder="请输入自定义代码">// 示例代码
|
||
function checkRule(data) {
|
||
// data 包含抽取的字段
|
||
try {
|
||
// 在此编写检查逻辑
|
||
if (data.fieldName && condition) {
|
||
return {
|
||
pass: true,
|
||
message: "检查通过"
|
||
};
|
||
} else {
|
||
return {
|
||
pass: false,
|
||
message: "检查不通过,原因:..."
|
||
};
|
||
}
|
||
} catch (error) {
|
||
return {
|
||
pass: false,
|
||
message: "执行出错:" + error.message
|
||
};
|
||
}
|
||
}</textarea>
|
||
<div class="hljs-container">
|
||
<pre><code class="language-javascript" id="highlighted-code-${index}"></code></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
break;
|
||
}
|
||
|
||
container.innerHTML = configHTML;
|
||
|
||
// 为新加载的配置添加事件
|
||
setupRuleConfigEvents(container, index, type);
|
||
}
|
||
|
||
// 为规则配置添加事件
|
||
function setupRuleConfigEvents(container, index, type) {
|
||
switch(type) {
|
||
case 'exists':
|
||
// 从当前活跃的抽取设置中获取字段
|
||
const activeExtractConfig = document.querySelector('.extraction-config:not(.hidden)');
|
||
const fieldsContainer = activeExtractConfig.querySelector('.chips-container');
|
||
const existsFieldsContainer = container.querySelector('.exists-fields-container');
|
||
|
||
// 清空现有字段
|
||
existsFieldsContainer.innerHTML = '';
|
||
|
||
// 获取抽取字段并创建可选标签
|
||
if (fieldsContainer) {
|
||
const chips = fieldsContainer.querySelectorAll('.chip');
|
||
chips.forEach(chip => {
|
||
const fieldName = chip.textContent.replace('×', '').trim();
|
||
const fieldTag = document.createElement('div');
|
||
fieldTag.className = 'field-tag';
|
||
fieldTag.setAttribute('data-field', fieldName);
|
||
fieldTag.textContent = fieldName;
|
||
|
||
// 添加点击事件
|
||
fieldTag.addEventListener('click', function() {
|
||
this.classList.toggle('selected');
|
||
});
|
||
|
||
existsFieldsContainer.appendChild(fieldTag);
|
||
});
|
||
}
|
||
|
||
// 如果没有找到字段,添加一些默认字段作为示例
|
||
if (existsFieldsContainer.children.length === 0) {
|
||
const defaultFields = ['合同编号', '甲方名称', '乙方名称', '签订日期', '合同金额'];
|
||
defaultFields.forEach(fieldName => {
|
||
const fieldTag = document.createElement('div');
|
||
fieldTag.className = 'field-tag';
|
||
fieldTag.setAttribute('data-field', fieldName);
|
||
fieldTag.textContent = fieldName;
|
||
|
||
// 添加点击事件
|
||
fieldTag.addEventListener('click', function() {
|
||
this.classList.toggle('selected');
|
||
});
|
||
|
||
existsFieldsContainer.appendChild(fieldTag);
|
||
});
|
||
}
|
||
break;
|
||
|
||
case 'consistency':
|
||
// 一致性判断配置事件
|
||
setupConsistencyEvents(container, index);
|
||
break;
|
||
|
||
case 'logic':
|
||
// 处理逻辑判断的添加条件和删除功能
|
||
const addConditionBtn = container.querySelector('.add-condition-btn');
|
||
if (addConditionBtn) {
|
||
addConditionBtn.addEventListener('click', function() {
|
||
// console.log('添加条件按钮被点击');
|
||
|
||
const conditionsContainer = container.querySelector('.conditions-container');
|
||
if (!conditionsContainer) {
|
||
console.error('找不到条件容器');
|
||
return;
|
||
}
|
||
|
||
const conditionRow = conditionsContainer.querySelector('.condition-row');
|
||
if (!conditionRow) {
|
||
console.error('找不到条件行模板');
|
||
return;
|
||
}
|
||
|
||
const newCondition = conditionRow.cloneNode(true);
|
||
|
||
// 清空选中值
|
||
newCondition.querySelectorAll('select, input').forEach(el => {
|
||
if (el.tagName === 'SELECT') {
|
||
el.value = el.querySelector('option').value;
|
||
} else {
|
||
el.value = '';
|
||
}
|
||
});
|
||
|
||
// 确保删除按钮可见
|
||
const removeBtn = newCondition.querySelector('.remove-condition-btn');
|
||
if (removeBtn) {
|
||
removeBtn.style.display = 'block';
|
||
|
||
// 绑定删除事件
|
||
removeBtn.addEventListener('click', function() {
|
||
if (conditionsContainer.querySelectorAll('.condition-row').length > 1) {
|
||
this.closest('.condition-row').remove();
|
||
}
|
||
});
|
||
}
|
||
|
||
conditionsContainer.appendChild(newCondition);
|
||
|
||
// 显示所有条件行的删除按钮
|
||
const allRemoveBtns = conditionsContainer.querySelectorAll('.remove-condition-btn');
|
||
if (allRemoveBtns.length > 1) {
|
||
allRemoveBtns.forEach(btn => {
|
||
btn.style.display = 'block';
|
||
});
|
||
}
|
||
|
||
// console.log('已添加新的条件行');
|
||
});
|
||
}
|
||
|
||
// 为已有的删除按钮绑定事件
|
||
const removeButtons = container.querySelectorAll('.remove-condition-btn');
|
||
removeButtons.forEach(btn => {
|
||
btn.addEventListener('click', function() {
|
||
const conditionsContainer = this.closest('.conditions-container');
|
||
if (conditionsContainer.querySelectorAll('.condition-row').length > 1) {
|
||
this.closest('.condition-row').remove();
|
||
} else {
|
||
// 如果只有一个条件,隐藏删除按钮
|
||
this.style.display = 'none';
|
||
}
|
||
});
|
||
});
|
||
|
||
// 隐藏第一个删除按钮(如果只有一个条件)
|
||
const firstRemoveBtn = container.querySelector('.remove-condition-btn');
|
||
const conditionsContainer = container.querySelector('.conditions-container');
|
||
if (firstRemoveBtn && conditionsContainer && conditionsContainer.querySelectorAll('.condition-row').length === 1) {
|
||
firstRemoveBtn.style.display = 'none';
|
||
}
|
||
break;
|
||
|
||
case 'format':
|
||
// 格式类型切换
|
||
const formatTypeSelect = container.querySelector('.format-type');
|
||
if (formatTypeSelect) {
|
||
formatTypeSelect.addEventListener('change', function() {
|
||
// 已删除日期格式和自定义格式相关的配置显示/隐藏逻辑
|
||
});
|
||
}
|
||
break;
|
||
|
||
case 'ai':
|
||
// AI判断目标切换
|
||
const aiJudgeTargetRadios = container.querySelectorAll('.ai-judge-target');
|
||
aiJudgeTargetRadios.forEach(radio => {
|
||
radio.addEventListener('change', function() {
|
||
const targetIndex = this.getAttribute('data-target-index');
|
||
const fieldSelect = document.getElementById(`ai-field-select-${targetIndex}`);
|
||
|
||
if (this.value === 'field') {
|
||
fieldSelect.classList.remove('hidden');
|
||
} else {
|
||
fieldSelect.classList.add('hidden');
|
||
}
|
||
});
|
||
});
|
||
break;
|
||
|
||
case 'code':
|
||
// 处理代码编辑器相关事件
|
||
const codeEditor = container.querySelector('.code-editor-textarea');
|
||
const highlightedCode = container.querySelector('.hljs-container code');
|
||
const languageRadios = container.querySelectorAll('.code-language-radio');
|
||
const filenameDisplay = container.querySelector('.code-editor-filename');
|
||
const copyBtn = container.querySelector('.code-copy-btn');
|
||
|
||
// 初始化代码高亮
|
||
if (codeEditor && highlightedCode) {
|
||
// 确保立即执行初始高亮
|
||
setTimeout(() => {
|
||
highlightedCode.textContent = codeEditor.value;
|
||
try {
|
||
hljs.highlightElement(highlightedCode);
|
||
// console.log('代码块已高亮', index);
|
||
} catch (e) {
|
||
console.error('代码高亮失败:', e);
|
||
}
|
||
}, 0);
|
||
|
||
// 实时更新高亮
|
||
codeEditor.addEventListener('input', function() {
|
||
highlightedCode.textContent = this.value;
|
||
try {
|
||
hljs.highlightElement(highlightedCode);
|
||
} catch (e) {
|
||
console.error('更新高亮失败:', e);
|
||
}
|
||
});
|
||
|
||
// 处理Tab键
|
||
codeEditor.addEventListener('keydown', function(e) {
|
||
if (e.key === 'Tab') {
|
||
e.preventDefault();
|
||
|
||
// 获取光标位置
|
||
const start = this.selectionStart;
|
||
const end = this.selectionEnd;
|
||
|
||
// 在光标位置插入Tab
|
||
this.value = this.value.substring(0, start) + ' ' + this.value.substring(end);
|
||
|
||
// 将光标移动到Tab之后
|
||
this.selectionStart = this.selectionEnd = start + 4;
|
||
|
||
// 更新高亮代码
|
||
highlightedCode.textContent = this.value;
|
||
hljs.highlightElement(highlightedCode);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 语言切换
|
||
if (languageRadios && highlightedCode && filenameDisplay && codeEditor) {
|
||
languageRadios.forEach(radio => {
|
||
radio.addEventListener('change', function() {
|
||
if (this.checked) {
|
||
// 更改文件名显示
|
||
if (this.value === 'javascript') {
|
||
filenameDisplay.textContent = 'script.js';
|
||
highlightedCode.className = 'language-javascript';
|
||
// JavaScript 示例代码
|
||
codeEditor.value = `// 示例代码
|
||
function checkRule(data) {
|
||
// data 包含抽取的字段
|
||
try {
|
||
// 在此编写检查逻辑
|
||
if (data.fieldName && condition) {
|
||
return {
|
||
pass: true,
|
||
message: "检查通过"
|
||
};
|
||
} else {
|
||
return {
|
||
pass: false,
|
||
message: "检查不通过,原因:..."
|
||
};
|
||
}
|
||
} catch (error) {
|
||
return {
|
||
pass: false,
|
||
message: "执行出错:" + error.message
|
||
};
|
||
}
|
||
}`;
|
||
} else if (this.value === 'python') {
|
||
filenameDisplay.textContent = 'script.py';
|
||
highlightedCode.className = 'language-python';
|
||
// Python 示例代码
|
||
codeEditor.value = `# 示例代码
|
||
def check_rule(data):
|
||
# data 包含抽取的字段
|
||
try:
|
||
# 在此编写检查逻辑
|
||
if data.get('field_name') and condition:
|
||
return {
|
||
'pass': True,
|
||
'message': "检查通过"
|
||
}
|
||
else:
|
||
return {
|
||
'pass': False,
|
||
'message': "检查不通过,原因:..."
|
||
}
|
||
except Exception as error:
|
||
return {
|
||
'pass': False,
|
||
'message': f"执行出错:{str(error)}"
|
||
}`;
|
||
}
|
||
|
||
// 重新高亮
|
||
highlightedCode.textContent = codeEditor.value;
|
||
try {
|
||
hljs.highlightElement(highlightedCode);
|
||
} catch (e) {
|
||
console.error('切换语言后高亮失败:', e);
|
||
}
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
// 复制代码功能
|
||
if (copyBtn && codeEditor) {
|
||
copyBtn.addEventListener('click', function() {
|
||
// 获取代码内容
|
||
const code = codeEditor.value;
|
||
|
||
// 复制到剪贴板
|
||
navigator.clipboard.writeText(code).then(() => {
|
||
// 显示复制成功提示
|
||
let notification = document.querySelector('.code-copy-success');
|
||
if (!notification) {
|
||
notification = document.createElement('div');
|
||
notification.className = 'code-copy-success';
|
||
notification.textContent = '代码已复制到剪贴板';
|
||
document.body.appendChild(notification);
|
||
}
|
||
|
||
// 显示提示
|
||
setTimeout(() => {
|
||
notification.classList.add('show');
|
||
|
||
// 3秒后隐藏提示
|
||
setTimeout(() => {
|
||
notification.classList.remove('show');
|
||
}, 3000);
|
||
}, 10);
|
||
}).catch(err => {
|
||
console.error('复制失败:', err);
|
||
});
|
||
});
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 添加评查规则
|
||
function setupAddRuleBtn() {
|
||
const addRuleBtn = document.getElementById('add-rule-btn');
|
||
const ruleItemsContainer = document.getElementById('rule-items-container');
|
||
const ruleCountElement = document.getElementById('logic-count');
|
||
|
||
if (addRuleBtn && ruleItemsContainer) {
|
||
addRuleBtn.addEventListener('click', function() {
|
||
const ruleItems = ruleItemsContainer.querySelectorAll('.rule-item');
|
||
const newIndex = ruleItems.length + 1;
|
||
|
||
// 创建一个新规则区域
|
||
const newRuleHTML = `
|
||
<div class="rule-item border border-dashed border-gray-300 rounded-md p-6 mb-6 relative">
|
||
<div class="absolute top-3 right-3 flex gap-2">
|
||
<span class="badge rounded-pill bg-primary text-white px-2 py-1">规则 #${newIndex}</span>
|
||
<button class="text-red-500 hover:text-red-700 delete-rule-btn">
|
||
<i class="ri-delete-bin-line"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="mb-4">
|
||
<label class="form-label">
|
||
评查类型 <span class="required-mark">*</span>
|
||
</label>
|
||
<select class="form-select rule-type-select" data-index="${newIndex}">
|
||
<option value="">请选择评查类型</option>
|
||
<option value="exists">有无判断</option>
|
||
<option value="consistency">一致性判断</option>
|
||
<option value="format">格式判断</option>
|
||
<option value="logic">逻辑判断</option>
|
||
<option value="regex">正则表达式</option>
|
||
<option value="ai">大模型判断</option>
|
||
<option value="code">自定义代码</option>
|
||
</select>
|
||
<div class="form-tip">选择评查类型后将显示对应的配置项</div>
|
||
</div>
|
||
|
||
<div class="rule-config-container" data-index="${newIndex}">
|
||
<div class="rule-placeholder text-center py-6 text-secondary">
|
||
<i class="ri-settings-3-line text-4xl mb-2 block"></i>
|
||
<p>请先选择评查类型</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
// 添加新规则到容器
|
||
ruleItemsContainer.insertAdjacentHTML('beforeend', newRuleHTML);
|
||
|
||
// 获取新添加的规则项
|
||
const newRuleElement = ruleItemsContainer.lastElementChild;
|
||
|
||
// 绑定删除按钮事件
|
||
const deleteBtn = newRuleElement.querySelector('.delete-rule-btn');
|
||
deleteBtn.addEventListener('click', function() {
|
||
newRuleElement.remove();
|
||
// 重新编号
|
||
reindexRules();
|
||
});
|
||
|
||
// 绑定类型选择事件
|
||
const typeSelect = newRuleElement.querySelector('.rule-type-select');
|
||
setupRuleTypeSelect(typeSelect);
|
||
|
||
// 更新规则计数
|
||
updateRuleCount();
|
||
});
|
||
}
|
||
}
|
||
|
||
// 重新编号评查规则
|
||
function reindexRules() {
|
||
const ruleItems = document.querySelectorAll('.rule-item');
|
||
ruleItems.forEach((item, index) => {
|
||
const newIndex = index + 1;
|
||
|
||
// 更新编号
|
||
const badge = item.querySelector('.badge');
|
||
if (badge) {
|
||
badge.textContent = `规则 #${newIndex}`;
|
||
}
|
||
|
||
// 更新数据索引
|
||
const typeSelect = item.querySelector('.rule-type-select');
|
||
typeSelect.setAttribute('data-index', newIndex);
|
||
|
||
const configContainer = item.querySelector('.rule-config-container');
|
||
configContainer.setAttribute('data-index', newIndex);
|
||
|
||
// 更新删除按钮状态
|
||
const deleteBtn = item.querySelector('.delete-rule-btn');
|
||
if (deleteBtn) {
|
||
if (newIndex === 1) {
|
||
deleteBtn.disabled = true;
|
||
deleteBtn.classList.add('text-gray-400');
|
||
deleteBtn.classList.remove('text-red-500');
|
||
} else {
|
||
deleteBtn.disabled = false;
|
||
deleteBtn.classList.remove('text-gray-400');
|
||
deleteBtn.classList.add('text-red-500');
|
||
}
|
||
}
|
||
});
|
||
|
||
// 更新规则计数
|
||
updateRuleCount();
|
||
}
|
||
|
||
// 更新规则计数
|
||
function updateRuleCount() {
|
||
const ruleCount = document.getElementById('logic-count');
|
||
const count = document.querySelectorAll('.rule-item').length;
|
||
if (ruleCount) {
|
||
ruleCount.textContent = `${count}个规则`;
|
||
}
|
||
}
|
||
|
||
// 自定义组合逻辑切换
|
||
const ruleLogicRadios = document.querySelectorAll('input[name="ruleLogic"]');
|
||
const ruleCustomLogic = document.getElementById('rule-custom-logic');
|
||
|
||
ruleLogicRadios.forEach(radio => {
|
||
radio.addEventListener('change', function() {
|
||
if (this.value === 'custom') {
|
||
ruleCustomLogic.classList.remove('hidden');
|
||
} else {
|
||
ruleCustomLogic.classList.add('hidden');
|
||
}
|
||
});
|
||
});
|
||
|
||
// 为已存在的第一个规则设置事件
|
||
const firstRuleTypeSelect = document.querySelector('.rule-type-select');
|
||
if (firstRuleTypeSelect) {
|
||
setupRuleTypeSelect(firstRuleTypeSelect);
|
||
}
|
||
|
||
// 为删除按钮添加事件
|
||
document.querySelectorAll('.delete-rule-btn').forEach(btn => {
|
||
btn.addEventListener('click', function() {
|
||
const ruleItem = this.closest('.rule-item');
|
||
const ruleItems = document.querySelectorAll('.rule-item');
|
||
|
||
// 只有当不是第一个规则时才可以删除
|
||
if (ruleItems.length > 1 && !Array.from(ruleItems).indexOf(ruleItem) === 0) {
|
||
ruleItem.remove();
|
||
reindexRules();
|
||
}
|
||
});
|
||
});
|
||
|
||
// 初始化添加规则按钮
|
||
setupAddRuleBtn();
|
||
|
||
// 初始化规则计数
|
||
updateRuleCount();
|
||
|
||
// 一致性判断配置 - 添加比较对
|
||
function setupConsistencyEvents(container, index) {
|
||
const addPairBtn = container.querySelector('.add-consistency-pair-btn');
|
||
if (addPairBtn) {
|
||
addPairBtn.addEventListener('click', function() {
|
||
const consistencyFieldsContainer = document.getElementById(`consistency-fields-container-${index}`);
|
||
const firstPair = consistencyFieldsContainer.querySelector('.bg-gray-50').cloneNode(true);
|
||
|
||
// 重置选择项
|
||
firstPair.querySelectorAll('select').forEach(select => {
|
||
select.value = '';
|
||
});
|
||
|
||
// 显示移除按钮
|
||
const removeBtn = firstPair.querySelector('.consistency-remove-btn');
|
||
removeBtn.style.display = 'block';
|
||
|
||
// 绑定删除事件
|
||
removeBtn.addEventListener('click', function() {
|
||
firstPair.remove();
|
||
|
||
// 如果只剩一个对比对,隐藏其移除按钮
|
||
const remainingPairs = consistencyFieldsContainer.querySelectorAll('.bg-gray-50');
|
||
if (remainingPairs.length === 1) {
|
||
remainingPairs[0].querySelector('.consistency-remove-btn').style.display = 'none';
|
||
}
|
||
});
|
||
|
||
consistencyFieldsContainer.appendChild(firstPair);
|
||
|
||
// 显示所有对比对的移除按钮
|
||
const allPairs = consistencyFieldsContainer.querySelectorAll('.bg-gray-50');
|
||
if (allPairs.length > 1) {
|
||
allPairs.forEach(pair => {
|
||
pair.querySelector('.consistency-remove-btn').style.display = 'block';
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
// 初始移除按钮事件
|
||
container.querySelectorAll('.consistency-remove-btn').forEach(btn => {
|
||
btn.addEventListener('click', function() {
|
||
const pair = this.closest('.bg-gray-50');
|
||
const consistencyFieldsContainer = pair.parentElement;
|
||
|
||
if (consistencyFieldsContainer.querySelectorAll('.bg-gray-50').length > 1) {
|
||
pair.remove();
|
||
|
||
// 如果只剩一个对比对,隐藏其移除按钮
|
||
const remainingPairs = consistencyFieldsContainer.querySelectorAll('.bg-gray-50');
|
||
if (remainingPairs.length === 1) {
|
||
remainingPairs[0].querySelector('.consistency-remove-btn').style.display = 'none';
|
||
}
|
||
}
|
||
});
|
||
});
|
||
|
||
// 初始状态下,如果只有一个比较对,隐藏其删除按钮
|
||
const initialPairs = container.querySelectorAll('.bg-gray-50');
|
||
if (initialPairs.length === 1) {
|
||
initialPairs[0].querySelector('.consistency-remove-btn').style.display = 'none';
|
||
}
|
||
}
|
||
|
||
// 为字段标签添加点击事件
|
||
document.querySelectorAll('.field-tag').forEach(tag => {
|
||
tag.addEventListener('click', function() {
|
||
this.classList.toggle('selected'); // 切换选中状态
|
||
});
|
||
});
|
||
|
||
// Tag button functionality
|
||
const tagButtons = container.querySelectorAll('.tag-button');
|
||
const promptTextarea = container.querySelector('.ai-prompt-textarea');
|
||
|
||
tagButtons.forEach(button => {
|
||
button.addEventListener('click', function() {
|
||
const tagText = this.getAttribute('data-tag');
|
||
if (promptTextarea) {
|
||
promptTextarea.value += `{${tagText}}`;
|
||
promptTextarea.focus();
|
||
}
|
||
});
|
||
});
|
||
|
||
// 不通过提示类别选中效果
|
||
const severityOptions = document.querySelectorAll('input[name="errorSeverity"]');
|
||
const severityDivs = document.querySelectorAll('.severity-option');
|
||
|
||
severityOptions.forEach((radio, index) => {
|
||
radio.addEventListener('change', function() {
|
||
// 移除所有选中效果
|
||
severityDivs.forEach(div => {
|
||
div.classList.remove('severity-selected');
|
||
div.classList.remove('bg-blue-300', 'bg-yellow-300', 'bg-red-300', 'bg-purple-300');
|
||
});
|
||
|
||
// 添加当前选中效果
|
||
if (this.checked) {
|
||
severityDivs[index].classList.add('severity-selected');
|
||
|
||
// 根据类型添加更明显的背景色
|
||
switch(this.value) {
|
||
case 'info':
|
||
severityDivs[index].classList.add('bg-blue-300');
|
||
break;
|
||
case 'warning':
|
||
severityDivs[index].classList.add('bg-yellow-300');
|
||
break;
|
||
case 'error':
|
||
severityDivs[index].classList.add('bg-red-300');
|
||
break;
|
||
case 'critical':
|
||
severityDivs[index].classList.add('bg-purple-300');
|
||
break;
|
||
}
|
||
}
|
||
});
|
||
});
|
||
|
||
// 大模型抽取 - 提示词类型切换
|
||
document.querySelectorAll('input[name="llm-prompt-type"]').forEach(radio => {
|
||
radio.addEventListener('change', function() {
|
||
if (this.value === 'system') {
|
||
document.getElementById('llm-custom-prompt-container').style.display = 'none';
|
||
document.getElementById('llm-system-prompt-info').style.display = 'block';
|
||
} else {
|
||
document.getElementById('llm-custom-prompt-container').style.display = 'block';
|
||
document.getElementById('llm-system-prompt-info').style.display = 'none';
|
||
}
|
||
});
|
||
});
|
||
|
||
// 多模态抽取 - 提示词类型切换
|
||
document.querySelectorAll('input[name="multimodal-prompt-type"]').forEach(radio => {
|
||
radio.addEventListener('change', function() {
|
||
if (this.value === 'system') {
|
||
document.getElementById('multimodal-custom-prompt-container').style.display = 'none';
|
||
document.getElementById('multimodal-system-prompt-info').style.display = 'block';
|
||
} else {
|
||
document.getElementById('multimodal-custom-prompt-container').style.display = 'block';
|
||
document.getElementById('multimodal-system-prompt-info').style.display = 'none';
|
||
}
|
||
});
|
||
});
|
||
|
||
// 大模型抽取 - 提示词模板选择
|
||
document.getElementById('llm-prompt-template').addEventListener('change', function() {
|
||
const promptContent = document.getElementById('llm-prompt-content');
|
||
if (this.value !== '') {
|
||
// 获取模板内容
|
||
const templateData = getPromptTemplateById(this.value);
|
||
if (templateData) {
|
||
// 填充提示词内容
|
||
promptContent.value = templateData.template_content;
|
||
|
||
// 自动填充字段列表
|
||
const fieldsContainer = document.getElementById('fields-container-ocr');
|
||
if (fieldsContainer) {
|
||
const fields = Array.from(fieldsContainer.querySelectorAll('.chip')).map(
|
||
chip => chip.textContent.replace('×', '').trim()
|
||
);
|
||
|
||
if (fields.length > 0) {
|
||
// 替换{fieldsList}变量
|
||
const fieldListStr = fields.map((field, idx) => `${idx+1}. ${field}`).join('\n');
|
||
promptContent.value = promptContent.value.replace('{fieldsList}', fieldListStr);
|
||
}
|
||
}
|
||
|
||
// 允许编辑
|
||
promptContent.removeAttribute('readonly');
|
||
}
|
||
} else {
|
||
promptContent.value = '';
|
||
promptContent.setAttribute('readonly', 'readonly');
|
||
}
|
||
});
|
||
|
||
// 多模态抽取 - 提示词模板选择
|
||
document.getElementById('multimodal-prompt-template').addEventListener('change', function() {
|
||
const promptContent = document.getElementById('multimodal-prompt-content');
|
||
if (this.value !== '') {
|
||
// 获取模板内容
|
||
const templateData = getPromptTemplateById(this.value);
|
||
if (templateData) {
|
||
// 填充提示词内容
|
||
promptContent.value = templateData.template_content;
|
||
|
||
// 自动填充字段列表
|
||
const fieldsContainer = document.getElementById('fields-container');
|
||
if (fieldsContainer) {
|
||
const fields = Array.from(fieldsContainer.querySelectorAll('.chip')).map(chip => {
|
||
const fieldName = chip.textContent.split('×')[0].trim();
|
||
const fieldType = chip.querySelector('.badge')?.textContent.trim() || '默认';
|
||
return `${fieldName} (${fieldType})`;
|
||
});
|
||
|
||
if (fields.length > 0) {
|
||
// 替换{fieldsList}变量
|
||
const fieldListStr = fields.map((field, idx) => `${idx+1}. ${field}`).join('\n');
|
||
promptContent.value = promptContent.value.replace('{fieldsList}', fieldListStr);
|
||
}
|
||
}
|
||
|
||
// 允许编辑
|
||
promptContent.removeAttribute('readonly');
|
||
}
|
||
} else {
|
||
promptContent.value = '';
|
||
promptContent.setAttribute('readonly', 'readonly');
|
||
}
|
||
});
|
||
|
||
// 模拟获取提示词模板数据
|
||
function getPromptTemplateById(id) {
|
||
// 模拟的模板数据,实际应用中应从服务器获取
|
||
const templates = {
|
||
'1': {
|
||
id: 1,
|
||
template_name: '行政处罚-抽取通用模板',
|
||
template_type: 'Extraction',
|
||
template_content: `你是一个专业的文档信息抽取助手。请从以下{docType}文档中抽取关键信息:
|
||
|
||
{fieldsList}
|
||
|
||
请将结果以JSON格式输出,包含以上字段。如果某个字段在文档中未找到,则该字段的值设为null。`
|
||
},
|
||
'4': {
|
||
id: 4,
|
||
template_name: '采购合同-乙方资质抽取',
|
||
template_type: 'Extraction',
|
||
template_content: `你是一个专业的合同信息抽取助手。请从以下{docType}中抽取乙方的资质信息:
|
||
|
||
需要抽取的信息包括:
|
||
{fieldsList}
|
||
|
||
{companyName}要求所有供应商必须提供完整的资质信息。请将结果以JSON格式输出,包含以上字段。`
|
||
},
|
||
'5': {
|
||
id: 5,
|
||
template_name: '合同-关键条款抽取',
|
||
template_type: 'Extraction',
|
||
template_content: `请作为{industry}行业的专业合同审核员,从提供的{docType}中提取以下关键条款信息:
|
||
|
||
{fieldsList}
|
||
|
||
文档ID: {documentId}
|
||
审核日期: {date}
|
||
|
||
请以JSON格式输出结果,对于未明确指定的条款需标记为"未明确约定"。`
|
||
},
|
||
'6': {
|
||
id: 6,
|
||
template_name: '烟草许可证-信息抽取',
|
||
template_type: 'Extraction',
|
||
template_content: `请从下列烟草专卖许可证文件中抽取以下关键信息:
|
||
|
||
{fieldsList}
|
||
|
||
这些信息将用于{companyName}内部数据库更新。请确保许可证编号和有效期格式准确无误。`
|
||
},
|
||
'7': {
|
||
id: 7,
|
||
template_name: '多模态-印章识别模板',
|
||
template_type: 'Multimodal',
|
||
template_content: `请识别并提取文档中的所有印章信息,包括:
|
||
|
||
{fieldsList}
|
||
|
||
文档类型: {docType}
|
||
页面范围: {pageRange}
|
||
|
||
请注意区分公章、法人章和合同专用章,并分析印章的清晰度和完整性。`
|
||
},
|
||
'8': {
|
||
id: 8,
|
||
template_name: '多模态-表格抽取模板',
|
||
template_type: 'Multimodal',
|
||
template_content: `请从文档中的表格提取以下信息:
|
||
|
||
{fieldsList}
|
||
|
||
文档类型: {docType}
|
||
表格可能跨页,请确保完整提取所有内容。表格中的数值需保留原始精度。`
|
||
},
|
||
'9': {
|
||
id: 9,
|
||
template_name: '多模态-手写内容识别模板',
|
||
template_type: 'Multimodal',
|
||
template_content: `请识别文档中的手写内容,特别关注:
|
||
|
||
{fieldsList}
|
||
|
||
文档类型: {docType}
|
||
内容类型: {contentType}
|
||
|
||
对于难以辨认的手写内容,请标注为"[难以辨认]"并尽可能给出可能的解读。`
|
||
}
|
||
};
|
||
|
||
return templates[id] || null;
|
||
}
|
||
|
||
});
|
||
</script>
|
||
|
||
<!-- 添加JavaScript实现展开/收起功能和预览更新 -->
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// 展开/收起功能
|
||
const descriptionToggle = document.getElementById('description-toggle');
|
||
const descriptionSection = document.getElementById('description-section');
|
||
|
||
descriptionToggle.addEventListener('click', function() {
|
||
this.classList.toggle('expanded');
|
||
if (descriptionSection.classList.contains('hidden')) {
|
||
descriptionSection.classList.remove('hidden');
|
||
} else {
|
||
descriptionSection.classList.add('hidden');
|
||
}
|
||
});
|
||
|
||
// 法律条文预览更新
|
||
const lawName = document.getElementById('law-name');
|
||
const lawArticles = document.getElementById('law-articles');
|
||
const lawContent = document.getElementById('law-content');
|
||
|
||
const previewLawName = document.getElementById('preview-law-name');
|
||
const previewLawArticles = document.getElementById('preview-law-articles');
|
||
const previewLawContent = document.getElementById('preview-law-content');
|
||
|
||
// 更新法典名称预览
|
||
lawName.addEventListener('input', function() {
|
||
previewLawName.textContent = this.value || '《中华人民共和国民法典》';
|
||
});
|
||
|
||
// 更新条款号预览
|
||
lawArticles.addEventListener('input', function() {
|
||
const articlesArray = this.value.split(',').map(item => item.trim()).filter(item => item);
|
||
|
||
previewLawArticles.innerHTML = '';
|
||
if (articlesArray.length > 0) {
|
||
articlesArray.forEach(article => {
|
||
const span = document.createElement('span');
|
||
span.className = 'law-article';
|
||
span.textContent = article;
|
||
previewLawArticles.appendChild(span);
|
||
});
|
||
} else {
|
||
previewLawArticles.innerHTML = '<span class="law-article">第五百八十五条</span><span class="law-article">第五百八十六条</span>';
|
||
}
|
||
});
|
||
|
||
// 更新条款内容预览
|
||
lawContent.addEventListener('input', function() {
|
||
previewLawContent.textContent = this.value || '当事人应当按照约定全面履行自己的义务。';
|
||
});
|
||
});
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|