|
|
|
@ -159,7 +159,65 @@ |
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-else class="config-table-section"> |
|
|
|
<div class="config-header"> |
|
|
|
<h4>检测到的占位符 (合同ID: {{ currentContractId }})</h4> |
|
|
|
<div class="header-buttons"> |
|
|
|
<!-- 如果没有Word文档,显示上传按钮 --> |
|
|
|
<button |
|
|
|
v-if="!currentTemplateInfo?.contract_template" |
|
|
|
@click="showReuploadSection = true" |
|
|
|
class="btn-upload" |
|
|
|
:disabled="reuploading"> |
|
|
|
{{ reuploading ? '上传中...' : '上传Word文档' }} |
|
|
|
</button> |
|
|
|
<!-- 如果有Word文档,显示重新识别按钮 --> |
|
|
|
<button |
|
|
|
v-if="currentTemplateInfo?.contract_template" |
|
|
|
@click="reidentifyPlaceholders" |
|
|
|
class="btn-reidentify" |
|
|
|
:disabled="reidentifying"> |
|
|
|
{{ reidentifying ? '识别中...' : '重新识别占位符' }} |
|
|
|
</button> |
|
|
|
<!-- 如果有Word文档,也提供重新上传选项 --> |
|
|
|
<button |
|
|
|
v-if="currentTemplateInfo?.contract_template" |
|
|
|
@click="showReuploadSection = !showReuploadSection" |
|
|
|
class="btn-secondary" |
|
|
|
:disabled="reuploading"> |
|
|
|
{{ showReuploadSection ? '取消上传' : '更换文档' }} |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 重新上传Word文档区域 --> |
|
|
|
<div v-if="showReuploadSection" class="reupload-section"> |
|
|
|
<h5>重新上传Word文档</h5> |
|
|
|
<div class="reupload-form"> |
|
|
|
<div class="form-item"> |
|
|
|
<label>Word文档 <span style="color: red;">*</span></label> |
|
|
|
<div class="file-upload-area"> |
|
|
|
<input |
|
|
|
type="file" |
|
|
|
accept=".docx,.doc" |
|
|
|
@change="handleReuploadFileSelect" |
|
|
|
class="file-input" |
|
|
|
ref="reuploadFileInput" |
|
|
|
/> |
|
|
|
<div class="upload-tip">支持 .docx 和 .doc 格式文件,文件大小不超过 10MB</div> |
|
|
|
<div v-if="reuploadFileName" class="file-info"> |
|
|
|
<span>📄 {{ reuploadFileName }}</span> |
|
|
|
<button type="button" @click="clearReuploadFile" class="clear-file-btn">×</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="reupload-actions"> |
|
|
|
<button @click="submitReupload" class="btn-primary" :disabled="reuploading || !reuploadFile"> |
|
|
|
{{ reuploading ? '上传中...' : '确定上传' }} |
|
|
|
</button> |
|
|
|
<button @click="showReuploadSection = false" class="btn-cancel">取消</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="config-table-wrapper"> |
|
|
|
<table class="config-table"> |
|
|
|
<thead> |
|
|
|
@ -412,8 +470,17 @@ const currentContract = ref<ContractTemplate | null>(null) |
|
|
|
const uploading = ref(false) |
|
|
|
const configLoading = ref(false) |
|
|
|
const configList = ref<any[]>([]) |
|
|
|
const reidentifying = ref(false) |
|
|
|
const fileInputKey = ref(0) |
|
|
|
const fileInput = ref<HTMLInputElement>() |
|
|
|
|
|
|
|
// 重新上传Word文档相关状态 |
|
|
|
const showReuploadSection = ref(false) |
|
|
|
const reuploadFile = ref<File | null>(null) |
|
|
|
const reuploadFileName = ref('') |
|
|
|
const reuploading = ref(false) |
|
|
|
const reuploadFileInput = ref<HTMLInputElement>() |
|
|
|
const currentTemplateInfo = ref<any>(null) |
|
|
|
const staffList = ref<any[]>([]) |
|
|
|
const filteredStaffList = ref<any[]>([]) |
|
|
|
const staffLoading = ref(false) |
|
|
|
@ -519,7 +586,10 @@ const updateStatus = async (row: ContractTemplate) => { |
|
|
|
|
|
|
|
const configPlaceholder = async (row: ContractTemplate) => { |
|
|
|
currentContractId.value = row.id |
|
|
|
currentTemplateInfo.value = row // 保存当前模板信息 |
|
|
|
showConfigDialog.value = true |
|
|
|
showReuploadSection.value = false // 重置重新上传区域 |
|
|
|
clearReuploadFile() // 清空重新上传的文件 |
|
|
|
// 加载占位符配置数据 |
|
|
|
await loadPlaceholderConfig(row.id) |
|
|
|
} |
|
|
|
@ -665,6 +735,55 @@ const handleUploadSuccess = () => { |
|
|
|
getList() |
|
|
|
} |
|
|
|
|
|
|
|
// 重新识别占位符 |
|
|
|
const reidentifyPlaceholders = async () => { |
|
|
|
if (!currentContractId.value) { |
|
|
|
ElMessage.error('未找到合同ID') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
reidentifying.value = true |
|
|
|
try { |
|
|
|
console.log('🔍 开始重新识别占位符, 合同ID:', currentContractId.value) |
|
|
|
|
|
|
|
// 调用重新识别接口 |
|
|
|
const { data } = await contractTemplateApi.reidentifyPlaceholders(currentContractId.value) |
|
|
|
console.log('✅ 重新识别成功, 返回数据:', data) |
|
|
|
|
|
|
|
// 展示详细的成功信息 |
|
|
|
const { placeholders, placeholder_count, new_placeholders, removed_placeholders } = data |
|
|
|
let message = `成功识别到 ${placeholder_count} 个占位符` |
|
|
|
|
|
|
|
if (new_placeholders && new_placeholders.length > 0) { |
|
|
|
message += `,新增 ${new_placeholders.length} 个` |
|
|
|
} |
|
|
|
if (removed_placeholders && removed_placeholders.length > 0) { |
|
|
|
message += `,移除 ${removed_placeholders.length} 个` |
|
|
|
} |
|
|
|
|
|
|
|
ElMessage.success(message) |
|
|
|
|
|
|
|
// 重新加载配置数据 |
|
|
|
await loadPlaceholderConfig(currentContractId.value) |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
console.error('❌ 重新识别失败:', error) |
|
|
|
|
|
|
|
// 根据错误类型显示不同的提示 |
|
|
|
let errorMessage = error.message || '未知错误' |
|
|
|
|
|
|
|
if (errorMessage.includes('模板未上传Word文档')) { |
|
|
|
ElMessage.error('请先上传Word文档模板后再进行占位符识别') |
|
|
|
} else if (errorMessage.includes('模板文件不存在')) { |
|
|
|
ElMessage.error('模板文件不存在,请重新上传') |
|
|
|
} else { |
|
|
|
ElMessage.error(`重新识别失败: ${errorMessage}`) |
|
|
|
} |
|
|
|
} finally { |
|
|
|
reidentifying.value = false |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 加载占位符配置 |
|
|
|
const loadPlaceholderConfig = async (contractId: number) => { |
|
|
|
configLoading.value = true |
|
|
|
@ -672,6 +791,11 @@ const loadPlaceholderConfig = async (contractId: number) => { |
|
|
|
const { data } = await contractTemplateApi.getPlaceholderConfig(contractId) |
|
|
|
console.log('API返回数据:', data) |
|
|
|
|
|
|
|
// 更新当前模板信息 |
|
|
|
if (data && typeof data === 'object') { |
|
|
|
currentTemplateInfo.value = data |
|
|
|
} |
|
|
|
|
|
|
|
// 处理API返回的数据格式,支持新的三种数据类型 |
|
|
|
if (data && typeof data === 'object') { |
|
|
|
// 优先检查 data_source_configs 字段(这是API实际返回的字段) |
|
|
|
@ -995,6 +1119,100 @@ const clearFile = () => { |
|
|
|
// fileInputKey.value += 1 // 注释掉,避免意外重新渲染导致文件丢失 |
|
|
|
} |
|
|
|
|
|
|
|
// 重新上传文件选择处理 |
|
|
|
const handleReuploadFileSelect = (event: Event) => { |
|
|
|
const target = event.target as HTMLInputElement |
|
|
|
const file = target.files?.[0] |
|
|
|
|
|
|
|
console.log('📁 重新上传文件选择:', file) |
|
|
|
|
|
|
|
if (!file) { |
|
|
|
reuploadFile.value = null |
|
|
|
reuploadFileName.value = '' |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 检查文件类型 |
|
|
|
const fileName = file.name.toLowerCase() |
|
|
|
const allowedExtensions = ['.docx', '.doc'] |
|
|
|
const isValidType = allowedExtensions.some(ext => fileName.endsWith(ext)) |
|
|
|
|
|
|
|
if (!isValidType) { |
|
|
|
ElMessage.error('只支持上传 .docx 和 .doc 格式的文件!') |
|
|
|
clearReuploadFile() |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 检查文件大小 (10MB) |
|
|
|
if (file.size > 10 * 1024 * 1024) { |
|
|
|
ElMessage.error('文件大小不能超过 10MB!') |
|
|
|
clearReuploadFile() |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 存储文件信息 |
|
|
|
reuploadFile.value = file |
|
|
|
reuploadFileName.value = file.name |
|
|
|
|
|
|
|
console.log('✅ 重新上传文件选择成功:', { name: file.name, size: file.size }) |
|
|
|
} |
|
|
|
|
|
|
|
// 清空重新上传文件 |
|
|
|
const clearReuploadFile = () => { |
|
|
|
reuploadFile.value = null |
|
|
|
reuploadFileName.value = '' |
|
|
|
if (reuploadFileInput.value) { |
|
|
|
reuploadFileInput.value.value = '' |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 提交重新上传 |
|
|
|
const submitReupload = async () => { |
|
|
|
if (!reuploadFile.value) { |
|
|
|
ElMessage.error('请选择Word文档') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
if (!currentContractId.value) { |
|
|
|
ElMessage.error('未找到模板ID') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
reuploading.value = true |
|
|
|
try { |
|
|
|
console.log('🚀 开始重新上传Word文档...', { |
|
|
|
templateId: currentContractId.value, |
|
|
|
fileName: reuploadFile.value.name, |
|
|
|
fileSize: reuploadFile.value.size |
|
|
|
}) |
|
|
|
|
|
|
|
// 构建FormData |
|
|
|
const formData = new FormData() |
|
|
|
formData.append('file', reuploadFile.value) |
|
|
|
|
|
|
|
// 调用更新模板文档的API |
|
|
|
await contractTemplateApi.updateTemplateFile(currentContractId.value, formData) |
|
|
|
|
|
|
|
console.log('✅ 重新上传成功') |
|
|
|
ElMessage.success('Word文档更新成功') |
|
|
|
|
|
|
|
// 重置状态 |
|
|
|
showReuploadSection.value = false |
|
|
|
clearReuploadFile() |
|
|
|
|
|
|
|
// 重新加载模板信息和配置 |
|
|
|
await loadPlaceholderConfig(currentContractId.value) |
|
|
|
// 更新列表中的模板信息 |
|
|
|
getList() |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
console.error('❌ 重新上传失败:', error) |
|
|
|
ElMessage.error(`更新文档失败: ${error.message || '未知错误'}`) |
|
|
|
} finally { |
|
|
|
reuploading.value = false |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 提交上传 |
|
|
|
const submitUpload = async () => { |
|
|
|
console.log('🚀 开始上传流程...') |
|
|
|
@ -1187,6 +1405,114 @@ onMounted(() => { |
|
|
|
margin-bottom: 15px; |
|
|
|
} |
|
|
|
|
|
|
|
.config-header { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
margin-bottom: 15px; |
|
|
|
} |
|
|
|
|
|
|
|
.config-header h4 { |
|
|
|
margin: 0; |
|
|
|
color: #303133; |
|
|
|
} |
|
|
|
|
|
|
|
.header-buttons { |
|
|
|
display: flex; |
|
|
|
gap: 8px; |
|
|
|
align-items: center; |
|
|
|
} |
|
|
|
|
|
|
|
.btn-reidentify { |
|
|
|
padding: 6px 12px; |
|
|
|
border: 1px solid #67c23a; |
|
|
|
background: #67c23a; |
|
|
|
color: white; |
|
|
|
border-radius: 4px; |
|
|
|
cursor: pointer; |
|
|
|
font-size: 12px; |
|
|
|
transition: all 0.3s; |
|
|
|
} |
|
|
|
|
|
|
|
.btn-reidentify:hover:not(:disabled) { |
|
|
|
background: #85ce61; |
|
|
|
border-color: #85ce61; |
|
|
|
} |
|
|
|
|
|
|
|
.btn-reidentify:disabled { |
|
|
|
opacity: 0.6; |
|
|
|
cursor: not-allowed; |
|
|
|
} |
|
|
|
|
|
|
|
.btn-upload { |
|
|
|
padding: 6px 12px; |
|
|
|
border: 1px solid #409eff; |
|
|
|
background: #409eff; |
|
|
|
color: white; |
|
|
|
border-radius: 4px; |
|
|
|
cursor: pointer; |
|
|
|
font-size: 12px; |
|
|
|
transition: all 0.3s; |
|
|
|
} |
|
|
|
|
|
|
|
.btn-upload:hover:not(:disabled) { |
|
|
|
background: #66b1ff; |
|
|
|
border-color: #66b1ff; |
|
|
|
} |
|
|
|
|
|
|
|
.btn-upload:disabled { |
|
|
|
opacity: 0.6; |
|
|
|
cursor: not-allowed; |
|
|
|
} |
|
|
|
|
|
|
|
.btn-secondary { |
|
|
|
padding: 6px 12px; |
|
|
|
border: 1px solid #909399; |
|
|
|
background: #909399; |
|
|
|
color: white; |
|
|
|
border-radius: 4px; |
|
|
|
cursor: pointer; |
|
|
|
font-size: 12px; |
|
|
|
transition: all 0.3s; |
|
|
|
} |
|
|
|
|
|
|
|
.btn-secondary:hover:not(:disabled) { |
|
|
|
background: #a6a9ad; |
|
|
|
border-color: #a6a9ad; |
|
|
|
} |
|
|
|
|
|
|
|
.btn-secondary:disabled { |
|
|
|
opacity: 0.6; |
|
|
|
cursor: not-allowed; |
|
|
|
} |
|
|
|
|
|
|
|
.reupload-section { |
|
|
|
margin: 20px 0; |
|
|
|
padding: 15px; |
|
|
|
background: #f9f9f9; |
|
|
|
border: 1px solid #e4e7ed; |
|
|
|
border-radius: 4px; |
|
|
|
} |
|
|
|
|
|
|
|
.reupload-section h5 { |
|
|
|
margin: 0 0 15px 0; |
|
|
|
color: #303133; |
|
|
|
font-size: 14px; |
|
|
|
font-weight: 500; |
|
|
|
} |
|
|
|
|
|
|
|
.reupload-form { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
gap: 15px; |
|
|
|
} |
|
|
|
|
|
|
|
.reupload-actions { |
|
|
|
display: flex; |
|
|
|
gap: 10px; |
|
|
|
justify-content: flex-end; |
|
|
|
} |
|
|
|
|
|
|
|
.config-table { |
|
|
|
width: 100%; |
|
|
|
border-collapse: collapse; |
|
|
|
|