提交 0f145c05 authored 作者: kxjia's avatar kxjia

提交

上级 73cbfed5
<template>
<div class="bank-report-table">
<div class="bank-report-table" @click="closeTooltip">
<!-- 加载遮罩层 -->
<div v-if="loading" class="loading-overlay">
<div class="loading-spinner">
......@@ -16,6 +16,7 @@
</div>
</template>
<template #tools>
<vxe-button status="primary" icon="vxe-icon-edit" @click="validateAndShowResults()" :disabled="loading">校验</vxe-button>
<vxe-button status="primary" icon="vxe-icon-save" @click="saveBatch()" :disabled="loading">保存</vxe-button>
</template>
</vxe-toolbar>
......@@ -29,7 +30,7 @@
height="auto"
class="custom-table"
:merge-cells="mergeCells"
:loading="loading" <!-- 添加表格loading -->
:loading="loading"
>
<vxe-column field="serialNumber" title="序号" width="50"></vxe-column>
<vxe-column field="project" title="项目" width="40">
......@@ -57,6 +58,7 @@
</template>
<template v-else-if="row.type === 'AttachTable'">
<AttachTable
:disabled="!row.hasRight"
:title="row.project"
:records="row.datas"
:fields="row.content"
......@@ -68,6 +70,7 @@
<template v-else-if="row.type === 'ExportTable'">
<ExportTable
:disabled="!row.hasRight"
:title="row.project"
:records="row.datas"
:fields="row.content"
......@@ -88,7 +91,7 @@
</span>
<span v-else-if="item.type === 'radio-group'" class="radio-group">
<vxe-radio-group v-model="formData[row.code +'_'+ item.field]">
<vxe-radio-group v-model="formData[row.code +'_'+ item.field]" :disabled="!item.hasRight">
<vxe-radio
v-for="(opt, optIndex) in item.options"
:key="optIndex"
......@@ -100,7 +103,7 @@
<div v-else-if="item.type === 'checkbox-group'" class="checkbox-group">
<span class="checkbox-group">
<vxe-checkbox-group v-model="formData[row.code+'_'+item.field]">
<vxe-checkbox-group v-model="formData[row.code+'_'+item.field]" :disabled="!item.hasRight">
<vxe-checkbox v-for="(opt, optIndex) in item.options" :key="optIndex" :label="opt">
{{ opt }}
</vxe-checkbox>
......@@ -116,7 +119,8 @@
</div>
<template v-else-if="item.type === 'textarea'">
<vxe-textarea
<vxe-textarea
:disabled="!item.hasRight"
v-model="formData[row.code +'_'+ item.field]"
size="mini"
class="table-input"
......@@ -128,18 +132,28 @@
</template>
<template v-else>
<vxe-input
:type="item.type"
v-model="formData[row.code +'_'+ item.field]"
size="mini"
class="table-input"
:style="{width:item.width}"
>
</vxe-input>
<span class="unit"> {{ item.unit }}</span>
<div class="input-wrapper">
<vxe-input
:disabled="!item.hasRight"
:type="item.type"
v-model="formData[row.code +'_'+ item.field]"
size="mini"
class="table-input"
:style="{width:item.width}"
:status="getInputStatus(row.code, item.field)"
@input="handleInputChange(row.code, item.field)"
>
</vxe-input>
<span class="unit"> {{ item.unit }}</span>
<span v-if="item.hasValidFormula" class="help-icon" @click.stop="toggleTooltip(row.code, item.field)">?</span>
<div v-if="getInputStatus(row.code, item.field) === 'error'" class="error-tip">
{{ getErrorMessage(row.code, item.field) }}
</div>
<div v-if="showTooltip && hoveredKey === row.code +'_'+ item.field" class="tooltip" @click.stop>
{{ getValidationRule(row.code, item.field) }}
</div>
</div>
</template>
</template>
</template>
</div>
......@@ -147,11 +161,79 @@
</vxe-column>
<vxe-column field="remarks" title="备注" width="60">
<template #default="{ row }">
<vxe-textarea :rows="row.remarks.rows" v-model="formData[row.code+'_'+row.remarks.field]">
<vxe-textarea :disabled="row.remarks.hasRight" :rows="row.remarks.rows" v-model="formData[row.code+'_'+row.remarks.field]">
</vxe-textarea>
</template>
</vxe-column>
</vxe-table>
<!-- 校验结果抽屉 -->
<vxe-drawer
v-model="drawerVisible"
placement="right"
@show="onDrawerShow"
title="校验结果"
width="40%"
:footer="{ show: true }"
>
<template #default>
<div class="validation-results">
<div class="result-summary">
<div class="summary-item">
<span class="summary-label">校验字段数:</span>
<span class="summary-value">{{ validationResultsList.length }}</span>
</div>
<div class="summary-item">
<span class="summary-label">通过:</span>
<span class="summary-value success">{{ validationResultsList.filter(item => item.isValid).length }}</span>
</div>
<div class="summary-item">
<span class="summary-label">失败:</span>
<span class="summary-value error">{{ validationResultsList.filter(item => !item.isValid).length }}</span>
</div>
</div>
<div class="result-list">
<div
v-for="(item, index) in validationResultsList"
:key="index"
class="result-item"
:class="{ success: item.isValid, error: !item.isValid }"
>
<div class="result-item-header">
<span class="result-item-name">{{ item.fieldTitle || item.fieldName }}</span>
<span class="result-item-status" :class="{ success: item.isValid, error: !item.isValid }">
{{ item.isValid ? '通过' : '失败' }}
</span>
</div>
<div class="result-item-content">
<div class="result-item-formula">
<span class="formula-label">验证公式:</span>
<span class="formula-value">{{ item.formula }}</span>
</div>
<div class="result-item-result">
<span class="result-label">验证结果:</span>
<span class="result-value">{{ item.resultMessage }}</span>
</div>
<div class="result-item-values" v-if="item.fieldValues">
<span class="values-label">字段值:</span>
<pre class="values-value">{{ formatJSON(item.fieldValues) }}</pre>
</div>
<div class="result-item-process" v-if="item.process">
<span class="process-label">校验过程:</span>
<div class="process-content">
<div v-for="(step, stepIndex) in item.process" :key="stepIndex" class="process-step">
<span class="step-number">{{ stepIndex + 1 }}</span>
<span class="step-text">{{ step }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
</vxe-drawer>
</div>
</template>
......@@ -164,13 +246,39 @@ import { tableFormData } from '../../data/tb3.data';
import { ref, reactive,nextTick,onMounted,toRaw } from 'vue'
import { VxeUI,VxeTablePropTypes,VxeToolbarPropTypes } from 'vxe-table'
import { batchSaveOrUpdate, queryRecord,batchSaveOrUpdateBeforeDelete } from '../../record/BaosongTaskRecord.api'
import { queryAllTplItemForUser } from '../../alloc/BaosongTaskAlloc.api'
import { findUserRightForTplItem } from '../../alloc/BaosongTaskAlloc.api'
import { allTplItems } from '../../tpl/BaosongTplItem.api'
import { getTblvalidFormula } from '../../tpl/BaosongDataValid.api'
import { useRoute } from 'vue-router';
const route = useRoute();
const tableRef = ref();
const tplItemMap = ref({});
const userAllocItems = ref([])
const validFormula = ref([])
const validationResults = ref<Record<string, string>>({})
const validationMessages = ref<Record<string, string>>({})
const formData = reactive({});
const formValues = ref<FormData[]>([])
const showTooltip = ref(false)
const hoveredKey = ref('')
// 校验结果抽屉相关
const drawerVisible = ref(false)
const validationResultsList = ref<any[]>([])
interface ValidationResult {
fieldTitle: string
fieldName: string
formula: string
isValid: boolean
resultMessage: string
process?: string[]
}
const queryParam = ref({
taskId:-1,
taskName:'',
......@@ -211,8 +319,19 @@ onMounted(async ()=>{
}
try {
userAllocItems.value = await findUserRightForTplItem({
tplid:queryParam.value.tplId,
taskid:queryParam.value.taskId
});
validFormula.value = await getTblvalidFormula({
tplid:queryParam.value.tplId,
});
await setFormItemRight();
await setTplItemMap()
await setData();
await validateAllInputs();
} catch (error) {
VxeUI.modal.message({
content: `初始化页面失败: ${error.message}`,
......@@ -223,11 +342,32 @@ onMounted(async ()=>{
}
})
const formData = reactive({});
const formValues = ref<FormData[]>([])
const setFormItemRight = async () => {
tableFormData.forEach(row => {
if (row.content && Array.isArray(row.content)) {
row.content.forEach(item => {
if (item.field) {
let tmpKey = `${row.code}_${item.field}`;
item["hasRight"] = userAllocItems.value.indexOf(tmpKey)>-1
item["hasValidFormula"] = validFormula.value?.length > 0 &&
validFormula.value.some((f: any) => {
const formulaText = (f.formula || '').toString()
return formulaText.includes(item.field)
})
}
});
}
if (row.remarks && row.remarks.field) {
let tmpKey = `${row.code}_${row.remarks.field}`;
row.remarks["hasRight"] = userAllocItems.value.indexOf(tmpKey)>-1
row.remarks["hasValidFormula"] = validFormula.value?.length > 0 &&
validFormula.value.some((f: any) => {
const formulaText = (f.formula || '').toString()
return formulaText.includes(row.remarks.field)
})
}
});
}
const saveBatch = async () => {
try {
......@@ -321,6 +461,7 @@ const setFormValues = async (pcode,code,valData,rind) => {
};
formValues.value.push(tempForm)
}
async function setData() {
try {
loading.value = true; // 开始加载
......@@ -335,12 +476,14 @@ async function setData() {
valueObj[key] = data.content;
}
for (const row of tableFormData) {
if(!row.type&&row.content) {
for (const cdata of row.content) {
if(cdata.field&&cdata.field.length>0) {
const strKey = `${row.code}_${cdata.field}`;
const item = tplItemMap.value[strKey];
if (!item) continue;
const { pid, itemid, formTp } = item;
const dataVal = valueObj[`${pid}_${itemid}_1`];
......@@ -423,21 +566,30 @@ async function setData() {
}
async function setTplItemMap() {
try {
loading.value = true; // 开始加载
loading.value = true;
const tplid = queryParam.value.tplId
const tplItem = await allTplItems({
tplid: tplid,
})
tplItem.forEach(item => {
let strKey = item.pcode + "_" + item.xmlcode;
tplItemMap.value[strKey] = {pid:item.pid,itemid:item.id,formTp:item.formTp,code:item.xmlcode};
tplItemMap.value[strKey] = {
pid:item.pid,
itemid:item.id,
formTp:item.formTp,
code:item.xmlcode,
isDisable:!userAllocItems.value.some(itemid=>itemid==item.id)
}
})
} catch (error) {
VxeUI.modal.message({ content: `加载数据失败: ${error.message}`, status: 'error' })
} finally {
loading.value = false; // 结束加载
}
}
const mergeCells = ref<VxeTablePropTypes.MergeCells>([
{ row: 0, col: 1, rowspan: 9, colspan: 1 },
{ row: 9, col: 1, rowspan: 1, colspan: 2 },
......@@ -448,6 +600,374 @@ const mergeCells = ref<VxeTablePropTypes.MergeCells>([
{ row: 9, col: 3, rowspan: 1, colspan: 2 },
])
const handleInputChange = (rowCode: string, itemField: string) => {
const key = `${rowCode}_${itemField}`
validateInput(key)
}
const getInputStatus = (rowCode: string, itemField: string): 'default' | 'error' => {
const key = `${rowCode}_${itemField}`
return validationResults.value[key] || ''
}
const getErrorMessage = (rowCode: string, itemField: string): string => {
const key = `${rowCode}_${itemField}`
return validationMessages.value[key] || ''
}
const toggleTooltip = (rowCode: string, itemField: string) => {
const key = `${rowCode}_${itemField}`
if (hoveredKey.value === key) {
showTooltip.value = false
hoveredKey.value = ''
} else {
showTooltip.value = true
hoveredKey.value = key
}
}
const getValidationRule = (rowCode: string, itemField: string): string => {
if (!validFormula.value || validFormula.value.length === 0) {
return ''
}
try {
const formulaItems = validFormula.value
const field = itemField
const targetFormula = formulaItems.find((f: any) => {
const formulaText = (f.formula || '').toString()
const regex = new RegExp(`\\b${field}\\b`, 'gi')
return regex.test(formulaText)
})
if (targetFormula) {
return targetFormula.des || `验证规则: ${targetFormula.formula}`
}
return ''
} catch (error) {
console.error('获取验证规则失败:', error)
return '获取验证规则失败'
}
}
const closeTooltip = (event: Event) => {
const target = event.target as HTMLElement
if (!target.closest('.help-icon')) {
showTooltip.value = false
hoveredKey.value = ''
}
}
const formatJSON = (obj: any): string => {
if (!obj) {
return ''
}
try {
return JSON.stringify(obj, null, 2)
} catch (error) {
return JSON.stringify({ error: '序列化失败' })
}
}
const onDrawerShow = () => {
// 抽屉显示时,设置容器高度为屏幕高度
setTimeout(() => {
const drawer = document.querySelector('.vxe-drawer--body')
if (drawer) {
const availableHeight = window.innerHeight - 280 // 减去顶部和底部的空间
const resultList = drawer.querySelector('.result-list')
if (resultList) {
resultList.classList.add('result-list--scrolling')
resultList.style.maxHeight = `${availableHeight}px`
}
}
}, 100)
}
const validateAndShowResults = async () => {
if (!validFormula.value || validFormula.value.length === 0) {
VxeUI.modal.message({ content: '没有配置验证规则', status: 'warning' })
return
}
try {
loading.value = true
validationResultsList.value = []
const codeVal = await buildCodeValueMap()
const formulaItems = validFormula.value
for (const strKey in formData) {
const val = formData[strKey]
if (val === undefined || val === null || val === '') {
continue
}
const field = strKey.split('_')[1]
const targetFormula = formulaItems.find((f: any) => {
const formulaText = (f.formula || '').toString()
const regex = new RegExp(`\\b${field}\\b`, 'gi')
return regex.test(formulaText)
})
if (targetFormula) {
const formulaText = (targetFormula.formula || '').toString()
let isValid = false
let resultMessage = ''
let process: string[] = []
let fieldTitle = ''
// 获取字段标题
for (const key in tplItemMap.value) {
if (key.endsWith(`_${field}`)) {
const item = tplItemMap.value[key]
if (item && item.name) {
fieldTitle = item.name
break
}
}
}
try {
process.push(`开始校验字段: ${field}`)
process.push(`验证公式: ${formulaText}`)
process.push(`字段值: ${JSON.stringify(codeVal)}`)
const result = await evaluateFormulaWithProcess(formulaText, codeVal, process)
isValid = result.isValid
resultMessage = result.message
if (isValid) {
process.push(`校验结果: 通过`)
} else {
process.push(`校验结果: 失败 - ${resultMessage}`)
}
} catch (error) {
isValid = true
resultMessage = `校验跳过: ${error.message}`
process.push(`校验异常: ${error.message}`)
}
validationResultsList.value.push({
fieldTitle: fieldTitle,
fieldName: field,
formula: formulaText,
isValid,
resultMessage,
process,
fieldValues: codeVal
})
}
}
if (validationResultsList.value.length > 0) {
drawerVisible.value = true
} else {
VxeUI.modal.message({ content: '没有找到需要校验的字段', status: 'warning' })
}
} catch (error) {
console.error('校验失败:', error)
VxeUI.modal.message({ content: `校验失败: ${error.message}`, status: 'error' })
} finally {
loading.value = false
}
}
const evaluateFormulaWithProcess = async (
formula: string,
codeVal: Record<string, string>,
process: string[]
): Promise<{ isValid: boolean; message: string }> => {
try {
process.push('检查公式中用到的字段...')
const fieldPattern = /\b([a-zA-Z_][a-zA-Z0-9_]*)\b/g
const fieldsInFormula = new Set<string>()
let match
while ((match = fieldPattern.exec(formula)) !== null) {
fieldsInFormula.add(match[1])
}
process.push(`公式中用到的字段: ${Array.from(fieldsInFormula).join(', ')}`)
for (const field of fieldsInFormula) {
if (!codeVal.hasOwnProperty(field) ||
codeVal[field] === undefined ||
codeVal[field] === null ||
codeVal[field] === '' ||
codeVal[field] === 'undefined' ||
codeVal[field] === 'null') {
process.push(`字段 ${field} 为空,跳过校验`)
return { isValid: true, message: `字段 ${field} 为空,跳过校验` }
}
}
process.push('所有字段都有值,开始执行公式计算...')
let processedFormula = formula
for (const [key, value] of Object.entries(codeVal)) {
const paramRegex = new RegExp(`\\b${key}\\b`, 'g')
processedFormula = processedFormula.replace(paramRegex, value)
}
process.push(`处理后的公式: ${processedFormula}`)
const result = eval(processedFormula)
const resultStr = String(result)
if (resultStr === 'true' || resultStr === 'True' || resultStr === '1' || result === true) {
process.push(`公式计算结果: ${resultStr} (通过)`)
return { isValid: true, message: `通过 (${resultStr})` }
} else {
process.push(`公式计算结果: ${resultStr} (失败)`)
return { isValid: false, message: `不通过 (${resultStr})` }
}
} catch (error) {
process.push(`公式计算失败: ${error.message}`)
return { isValid: true, message: `校验跳过 - ${error.message}` }
}
}
const validateInput = async (key: string) => {
if (!validFormula.value || validFormula.value.length === 0) {
validationResults.value[key] = 'default'
validationMessages.value[key] = ''
return
}
try {
const formulaItems = validFormula.value
const field = key.split('_')[1]
const targetFormula = formulaItems.find((f: any) => {
const formulaText = (f.formula || '').toString()
const regex = new RegExp(`\\b${field}\\b`, 'gi')
return regex.test(formulaText)
})
if (targetFormula) {
const codeVal = await buildCodeValueMap()
const formulaText = (targetFormula.formula || '').toString()
const isValid = await evaluateFormula(formulaText, codeVal)
if (isValid) {
validationResults.value[key] = 'default'
validationMessages.value[key] = ''
} else {
validationResults.value[key] = 'error'
validationMessages.value[key] = targetFormula.des || `验证失败: ${formulaText}`
}
} else {
validationResults.value[key] = 'default'
validationMessages.value[key] = ''
}
} catch (error) {
console.error('验证失败:', error)
validationResults.value[key] = 'error'
validationMessages.value[key] = '验证计算失败'
}
}
const buildCodeValueMap = async (): Promise<Record<string, string>> => {
const codeVal: Record<string, string> = {}
for (const strKey in formData) {
const val = formData[strKey]
if (val !== undefined && val !== null && val !== '') {
const parts = strKey.split('_')
if (parts.length >= 2) {
const field = parts[1]
codeVal[field] = Array.isArray(val) ? val.join(',') : String(val)
}
}
}
return codeVal
}
const evaluateFormula = async (formula: string, codeVal: Record<string, string>): Promise<boolean> => {
try {
// 提取公式中用到的所有字段名(假设字段名是字母数字下划线组合)
const fieldPattern = /\b([a-zA-Z_][a-zA-Z0-9_]*)\b/g
const fieldsInFormula = new Set<string>()
let match
while ((match = fieldPattern.exec(formula)) !== null) {
fieldsInFormula.add(match[1])
}
// 检查所有用到的字段是否都有值
for (const field of fieldsInFormula) {
// 如果字段在 codeVal 中但值为空,或者不在 codeVal 中,都认为是空
if (!codeVal.hasOwnProperty(field) ||
codeVal[field] === undefined ||
codeVal[field] === null ||
codeVal[field] === '' ||
codeVal[field] === 'undefined' ||
codeVal[field] === 'null') {
return true // 有字段为空,不进行校验,默认通过
}
}
let processedFormula = formula
for (const [key, value] of Object.entries(codeVal)) {
const paramRegex = new RegExp(`\\b${key}\\b`, 'g')
processedFormula = processedFormula.replace(paramRegex, value)
}
const result = eval(processedFormula)
return Boolean(result)
} catch (error) {
console.error('公式计算失败:', error, '公式:', formula)
return true // 计算失败时也通过,避免因为计算错误导致验证失败
}
}
const validateAllInputs = async () => {
if (!validFormula.value || validFormula.value.length === 0) {
return
}
try {
const formulaItems = validFormula.value
const codeVal = await buildCodeValueMap()
validationResults.value = {}
validationMessages.value = {}
for (const strKey in formData) {
const val = formData[strKey]
if (val !== undefined && val !== null && val !== '') {
const field = strKey.split('_')[1]
const targetFormula = formulaItems.find((f: any) => {
const formulaText = (f.formula || '').toString()
const regex = new RegExp(`\\b${field}\\b`, 'gi')
return regex.test(formulaText)
})
if (targetFormula) {
const formulaText = (targetFormula.formula || '').toString()
const isValid = await evaluateFormula(formulaText, codeVal)
if (isValid) {
validationResults.value[strKey] = 'default'
validationMessages.value[strKey] = ''
} else {
validationResults.value[strKey] = 'error'
validationMessages.value[strKey] = targetFormula.des || `验证失败: ${formulaText}`
}
}
}
}
} catch (error) {
console.error('全量验证失败:', error)
}
}
</script>
<style lang="less" scoped>
.bank-report-table {
......@@ -630,4 +1150,345 @@ blockquote {
cursor: pointer;
}
.input-wrapper {
position: relative;
display: inline-block;
}
.input-wrapper .unit {
margin-left: 4px;
}
.input-wrapper .error-tip {
position: absolute;
top: 100%;
left: 0;
margin-top: 2px;
padding: 4px 8px;
background: #fff2f0;
border: 1px solid #ffccc7;
border-radius: 4px;
font-size: 11px;
color: #ff4d4f;
line-height: 1.4;
max-width: 200px;
word-wrap: break-word;
z-index: 1000;
white-space: normal;
box-shadow: 0 2px 8px rgba(255, 77, 79, 0.15);
}
.input-wrapper .error-tip::before {
content: '';
position: absolute;
top: -5px;
left: 10px;
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 5px solid #ffccc7;
}
.vxe-input.status--error .vxe-input--inner {
border-color: #ff4d4f !important;
background-color: #fff2f0 !important;
}
.input-wrapper .help-icon {
display: inline-block;
width: 16px;
height: 16px;
background: #1890ff;
color: white;
border-radius: 50%;
text-align: center;
line-height: 16px;
font-size: 12px;
font-weight: bold;
cursor: pointer;
margin-left: 4px;
user-select: none;
transition: all 0.3s;
}
.input-wrapper .help-icon:hover {
background: #40a9ff;
transform: scale(1.1);
}
.input-wrapper .tooltip {
position: absolute;
top: 100%;
left: 0;
margin-top: 2px;
padding: 6px 10px;
background: #1f1f1f;
color: white;
border-radius: 6px;
font-size: 12px;
line-height: 1.5;
max-width: 250px;
word-wrap: break-word;
z-index: 1001;
white-space: normal;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
.input-wrapper .tooltip::before {
content: '';
position: absolute;
top: -5px;
left: 12px;
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 5px solid #1f1f1f;
}
/* 校验结果抽屉样式 */
.validation-results {
padding: 16px;
height: 90vh;
}
.result-summary {
display: flex;
gap: 16px;
margin-bottom: 16px;
padding: 12px;
background: #f5f5f5;
border-radius: 8px;
}
.summary-item {
display: flex;
flex-direction: column;
gap: 4px;
}
.summary-label {
font-size: 12px;
color: #666;
}
.summary-value {
font-size: 16px;
font-weight: bold;
}
.summary-value.success {
color: #52c41a;
}
.summary-value.error {
color: #ff4d4f;
}
.result-list {
display: flex;
flex-direction: column;
gap: 12px;
max-height: 100%;
overflow-y: auto;
}
.result-item {
border: 1px solid #e8e8e8;
border-radius: 8px;
padding: 12px;
transition: all 0.3s;
}
.result-item.success {
border-color: #52c41a;
background: #f6ffed;
}
.result-item.error {
border-color: #ff4d4f;
background: #fff2f0;
}
.result-item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
padding-bottom: 8px;
border-bottom: 1px solid #e8e8e8;
}
.result-item-name {
font-weight: bold;
font-size: 14px;
}
.result-item-status {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
}
.result-item-status.success {
background: #f6ffed;
color: #52c41a;
border: 1px solid #95de64;
}
.result-item-status.error {
background: #fff2f0;
color: #ff4d4f;
border: 1px solid #ffccc7;
}
.result-item-content {
display: flex;
flex-direction: column;
gap: 8px;
}
.result-item-formula,
.result-item-result,
.result-item-process {
display: flex;
gap: 8px;
align-items: flex-start;
}
.result-item-formula {
font-family: 'Courier New', monospace;
background: #fafafa;
padding: 8px;
border-radius: 4px;
border: 1px solid #e8e8e8;
}
.formula-label,
.result-label,
.formula-label,
.result-label,
.process-label,
.values-label {
font-weight: bold;
font-size: 12px;
color: #666;
min-width: 80px;
}
.formula-value,
.result-value,
.values-value {
font-size: 12px;
flex: 1;
}
.result-value {
color: #333;
}
.process-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
}
.process-step {
display: flex;
gap: 8px;
align-items: flex-start;
font-size: 12px;
color: #666;
}
.step-number {
display: inline-flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
background: #1890ff;
color: white;
border-radius: 50%;
font-size: 10px;
font-weight: bold;
flex-shrink: 0;
}
.step-text {
flex: 1;
}
.result-item-process {
border-top: 1px solid #e8e8e8;
padding-top: 8px;
}
.result-item-values {
display: flex;
gap: 8px;
align-items: flex-start;
}
.values-label {
font-weight: bold;
font-size: 12px;
color: #666;
min-width: 80px;
}
.values-value {
font-family: 'Courier New', monospace;
font-size: 11px;
line-height: 1.5;
background: #fafafa;
padding: 8px;
border-radius: 4px;
border: 1px solid #e8e8e8;
overflow-x: auto;
max-height: 200px;
overflow-y: auto;
flex: 1;
white-space: pre;
word-break: break-all;
}
/* 抽屉样式调整 */
.vxe-drawer--right {
width: 700px !important;
}
.vxe-drawer--header {
border-bottom: 1px solid #e8e8e8;
padding-bottom: 12px;
}
.vxe-drawer--title {
font-size: 16px;
font-weight: bold;
color: #333;
}
.vxe-drawer--body {
padding: 16px;
max-height: calc(100vh - 140px);
overflow-y: auto;
}
.result-list {
display: flex;
flex-direction: column;
gap: 12px;
max-height: 500px;
overflow-y: auto;
}
.result-list--scrolling {
max-height: calc(100vh - 280px) !important;
}
</style>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论