提交 072342b1 authored 作者: kxjia's avatar kxjia

修改验证功能

上级 0bdc8778
......@@ -278,7 +278,6 @@
<vxe-textarea
:rows="row.remarks.rows"
v-model="formData[getFieldKey(row.code, row.remarks.field)]"
:disabled="!row.hasRight"
/>
</template>
</vxe-column>
......@@ -921,10 +920,26 @@ const buildExpression = (formula: string, rowCode: string): string => {
for (const fieldName of uniqueFields) {
const key = getFieldKey(rowCode, fieldName)
const value = formData[key]
if (value !== undefined) {
// 检查字段类型,如果是日期类型,转换为时间戳进行比较
const row = tableFormData.find((r: TableRow) => r.code === rowCode)
let processedValue = value
if (row && row.content && Array.isArray(row.content)) {
const fieldItem = row.content.find((c: ContentItem) => c.field === fieldName)
if (fieldItem && fieldItem.type === 'date') {
// 将日期字符串转换为时间戳(毫秒)
const date = new Date(value)
if (!isNaN(date.getTime())) {
processedValue = date.getTime()
}
}
}
expression = expression.replace(
new RegExp(`\\b${fieldName}\\b`, 'g'),
`Number(${value})`
`Number(${processedValue})`
)
}
}
......
......@@ -11,6 +11,39 @@
>
<template #default>
<div class="validation-results">
<!-- Tab 切换 -->
<div class="result-tabs">
<div
class="tab-item"
:class="{ active: activeTab === 'all' }"
@click="activeTab = 'all'"
>
全部 ({{ validationResultsList.length }})
</div>
<div
class="tab-item"
:class="{ active: activeTab === 'passed' }"
@click="activeTab = 'passed'"
>
通过 ({{ validationResultsList.filter(item => item.isValid).length }})
</div>
<div
class="tab-item"
:class="{ active: activeTab === 'failed' }"
@click="activeTab = 'failed'"
>
未通过 ({{ validationResultsList.filter(item => !item.isValid).length }})
</div>
<div
class="tab-item"
:class="{ active: activeTab === 'unfilled' }"
@click="activeTab = 'unfilled'"
>
未填报 ({{ unfilledFields.length }})
</div>
</div>
<!-- 统计信息 -->
<div class="result-summary">
<div class="summary-item">
<span class="summary-label">校验字段数:</span>
......@@ -24,7 +57,12 @@
<span class="summary-label">失败:</span>
<span class="summary-value error">{{ validationResultsList.filter(item => !item.isValid).length }}</span>
</div>
<div class="summary-item">
<span class="summary-label">未填报:</span>
<span class="summary-value warning">{{ unfilledFields.length }}</span>
</div>
</div>
<div class="process-log" v-if="showProcessLog && validationProcess.length > 0">
<h4>执行过程:</h4>
<div class="process-content">
......@@ -33,17 +71,39 @@
</div>
</div>
</div>
<div class="results-list">
<!-- 未填报字段列表 -->
<div v-if="activeTab === 'unfilled'" class="results-list">
<div
v-for="(field, index) in unfilledFields"
:key="index"
class="result-item unfilled"
>
<div class="result-field">{{ field.rowCode }} - {{ field.fieldName }}</div>
<div class="result-desc">{{ field.description }}</div>
</div>
</div>
<!-- 校验结果列表 -->
<div v-else class="results-list">
<div
v-for="(result, index) in validationResultsList"
v-for="(result, index) in filteredResults"
:key="index"
class="result-item"
:class="{ success: result.isValid, error: !result.isValid }"
@click="handleValidationResultClick(result)"
>
<div class="result-field">{{ result.description }}{{ result.field }}</div>
<div class="result-field">{{ result.description }}</div>
<div class="result-formula">公式:{{ result.formula }}</div>
<div class="result-value">值:{{ formatFieldValue(result.fieldValue) }}</div>
<div v-if="result.fieldValues && Object.keys(result.fieldValues).length > 0" class="result-params">
<span class="params-title">参数值:</span>
<span v-for="(value, key, index) in result.fieldValues" :key="key" class="param-item">
<span class="param-name">{{ key }} = {{ formatFieldValue(value) }}</span>
<span v-if="index < Object.keys(result.fieldValues).length - 1" class="param-separator"></span>
</span>
</div>
<div v-if="result.evaluatedFormula" class="result-evaluated">替换后公式:{{ result.evaluatedFormula }}</div>
<div class="result-value">当前字段值:{{ formatFieldValue(result.fieldValue) }}</div>
<div v-if="!result.isValid" class="result-error">失败原因:{{ result.description }}</div>
</div>
</div>
......@@ -72,7 +132,7 @@
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { ref, watch, computed } from 'vue'
interface ValidationResult {
field: string
......@@ -81,6 +141,8 @@ interface ValidationResult {
isValid: boolean
fieldValue: any
rowCode: string
fieldValues: Record<string, any>
evaluatedFormula: string
}
interface ValidationFormula {
......@@ -92,10 +154,17 @@ interface TableRow {
code: string
content: Array<{
field: string
type?: string
[key: string]: any
}>
}
interface UnfilledField {
rowCode: string
fieldName: string
description: string
}
const props = defineProps({
modelValue: {
type: Boolean,
......@@ -116,11 +185,52 @@ const showProcessLog = ref(false)
const validationTooltipVisible = ref(false)
const validationTooltipPosition = ref({ left: 0, top: 0 })
const validationTooltipContent = ref('')
const activeTab = ref('all')
// 通过外部传入的数据
const validFormula = ref<ValidationFormula[]>([])
const formData = ref<Record<string, any>>({})
// 计算属性:过滤后的结果
const filteredResults = computed(() => {
if (activeTab.value === 'all') {
return validationResultsList.value
} else if (activeTab.value === 'passed') {
return validationResultsList.value.filter(item => item.isValid)
} else if (activeTab.value === 'failed') {
return validationResultsList.value.filter(item => !item.isValid)
}
return validationResultsList.value
})
// 计算属性:未填报字段
const unfilledFields = computed<UnfilledField[]>(() => {
const fields: UnfilledField[] = []
props.tableFormData.forEach((row) => {
if (row.content && Array.isArray(row.content)) {
row.content.forEach((item) => {
if (item.field) {
const key = `${row.code}_${item.field}`
const value = formData.value[key]
if (value === undefined || value === null || value === '') {
// 查找该字段的校验公式
const formula = validFormula.value.find(f => f.formula.includes(item.field))
fields.push({
rowCode: row.code,
fieldName: item.field,
description: formula?.des || '未填报'
})
}
}
})
}
})
return fields
})
watch(() => props.modelValue, (newVal) => {
drawerVisible.value = newVal
})
......@@ -141,6 +251,7 @@ const performValidation = () => {
validationProcess.value.push(`找到 ${validFormula.value.length} 个验证公式`)
validFormula.value.forEach((formulaItem: ValidationFormula) => {
validationProcess.value.push(`开始校验公式: ${formulaItem.des}`)
const result = evaluateFormula(formulaItem.formula, formulaItem.des)
......@@ -170,6 +281,8 @@ const evaluateFormula = (formula: string, description: string): ValidationResult
r.content?.some((c: any) => c.field === fieldName)
)
console.log(row)
if (!row) {
validationProcess.value.push(`跳过: 未找到字段 ${fieldName} 所在的行`)
return null
......@@ -207,14 +320,29 @@ const evaluateFormula = (formula: string, description: string): ValidationResult
uniqueFields.sort((a, b) => b.length - a.length);
const fieldValues: Record<string, any> = {};
let expression = formula;
for (const fieldName of uniqueFields) {
const key = `${row.code}_${fieldName}`;
const value = formData.value[key];
fieldValues[fieldName] = value;
if (value !== undefined && value !== '') {
// 检查字段类型,如果是日期类型,转换为时间戳进行比较
const fieldItem = row.content.find((c: any) => c.field === fieldName);
let processedValue = value;
if (fieldItem && fieldItem.type === 'date') {
// 将日期字符串转换为时间戳(毫秒)
const date = new Date(value);
if (!isNaN(date.getTime())) {
processedValue = date.getTime();
}
}
expression = expression.replace(
new RegExp(`\\b${fieldName}\\b`, 'g'),
`Number(${value})`
`${processedValue}`
);
}
}
......@@ -232,7 +360,9 @@ const evaluateFormula = (formula: string, description: string): ValidationResult
formula: formula,
isValid: isValid,
fieldValue: fieldValue,
rowCode: row.code
rowCode: row.code,
fieldValues: fieldValues,
evaluatedFormula: expression
}
} catch (error) {
validationProcess.value.push(`公式执行错误: ${error instanceof Error ? error.message : String(error)}`)
......@@ -323,6 +453,38 @@ defineExpose({
flex-direction: column;
}
.result-tabs {
display: flex;
gap: 8px;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 2px solid #e8e8e8;
}
.tab-item {
padding: 8px 16px;
cursor: pointer;
border-radius: 4px 4px 0 0;
font-size: 14px;
color: #666;
background-color: #f5f5f5;
transition: all 0.3s;
border: 1px solid #e8e8e8;
border-bottom: none;
&:hover {
background-color: #e6f7ff;
color: #1890ff;
}
&.active {
background-color: #1890ff;
color: white;
border-color: #1890ff;
font-weight: bold;
}
}
.result-summary {
display: flex;
gap: 20px;
......@@ -355,6 +517,10 @@ defineExpose({
color: #ff4d4f;
}
.summary-value.warning {
color: #faad14;
}
.process-log {
margin: 15px 0;
padding: 10px;
......@@ -422,6 +588,15 @@ defineExpose({
}
}
.result-item.unfilled {
background-color: #fffbe6;
border-left: 4px solid #faad14;
&:hover {
background-color: #fff1b8;
}
}
.result-field {
font-weight: bold;
margin-bottom: 5px;
......@@ -445,6 +620,53 @@ defineExpose({
word-break: break-all;
}
.result-params {
margin: 8px 0;
padding: 8px;
background-color: rgba(24, 144, 255, 0.05);
border-radius: 4px;
border: 1px dashed #1890ff;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 4px;
}
.params-title {
font-size: 12px;
color: #1890ff;
font-weight: bold;
}
.param-item {
display: inline-flex;
align-items: center;
font-size: 12px;
}
.param-name {
color: #333;
font-family: monospace;
font-weight: 500;
}
.param-separator {
color: #999;
margin: 0 2px;
}
.result-evaluated {
font-size: 12px;
color: #52c41a;
font-family: monospace;
margin-bottom: 5px;
background-color: rgba(82, 196, 26, 0.05);
padding: 4px 6px;
border-radius: 2px;
word-break: break-all;
border-left: 3px solid #52c41a;
}
.result-value {
font-size: 12px;
color: #999;
......
......@@ -175,7 +175,7 @@
record['token']=allReportData.value;
let retData = await downLoadTaskXml(record);
goToFile(retData);
handleDownloadFile(retData);
}
function setRowkey(row) {
......@@ -190,6 +190,14 @@
message.warning('没有找到要下载的文件');
}
}
const handleDownloadFile = (filePath) => {
const globOnlineViewUrl: string = import.meta.env.VITE_GLOB_ONLINE_VIEW_URL;
const url = globOnlineViewUrl + filePath;
if (url) {
window.open(url);
}
};
</script>
<style scoped></style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论