Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
Z
zrch-risk-39
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
Administrator
zrch-risk-39
Commits
c9c33644
提交
c9c33644
authored
2月 04, 2026
作者:
kxjia
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Tb11.vue
上级
723b3f68
显示空白字符变更
内嵌
并排
正在显示
1 个修改的文件
包含
650 行增加
和
48 行删除
+650
-48
Tb11.vue
...sk-client-39/src/views/baosong/report/components/Tb11.vue
+650
-48
没有找到文件。
zrch-risk-client-39/src/views/baosong/report/components/Tb11.vue
浏览文件 @
c9c33644
<
template
>
<
template
>
<div
class=
"bank-report-table"
style=
"height:80vh;"
>
<div
class=
"bank-report-table"
style=
"height:80vh;"
@
click=
"closeAllTooltips"
>
<vxe-toolbar>
<vxe-toolbar>
<template
#
buttons
>
<template
#
buttons
>
<div
style=
"margin:10px"
>
<div
style=
"margin:10px"
>
...
@@ -8,6 +8,7 @@
...
@@ -8,6 +8,7 @@
</div>
</div>
</
template
>
</
template
>
<
template
#
tools
>
<
template
#
tools
>
<!--
<vxe-button
status=
"primary"
icon=
"vxe-icon-edit"
@
click=
"checkData()"
>
校验
</vxe-button>
-->
<vxe-button
status=
"primary"
icon=
"vxe-icon-save"
@
click=
"saveBatch()"
>
保存
</vxe-button>
<vxe-button
status=
"primary"
icon=
"vxe-icon-save"
@
click=
"saveBatch()"
>
保存
</vxe-button>
</
template
>
</
template
>
</vxe-toolbar>
</vxe-toolbar>
...
@@ -54,14 +55,80 @@
...
@@ -54,14 +55,80 @@
<vxe-radio
label=
"否"
content=
"否"
></vxe-radio>
<vxe-radio
label=
"否"
content=
"否"
></vxe-radio>
</vxe-radio-group>
</vxe-radio-group>
</
template
>
</
template
>
<
template
v-else-if=
"item.type === 'textarea'"
>
<vxe-textarea
v-model=
"formData[row.code +'_'+ item.field]"
size=
"mini"
class=
"table-textarea"
:rows=
"2"
:autosize=
"
{ minRows: 2, maxRows: 4 }"
/>
</
template
>
<
template
v-else
>
<div
class=
"input-wrapper"
v-if=
"item.hasRight !== false"
>
<vxe-input
<vxe-input
v-else
v-if=
"item.type !== 'checkbox'"
:type=
"item.type
"
:type=
"item.type === 'date' ? 'date' : 'text'
"
v-model=
"formData[row.code +'_'+ item.field]"
v-model=
"formData[row.code +'_'+ item.field]"
size=
"mini"
size=
"mini"
class=
"table-input"
class=
"table-input"
:disabled=
"!item.hasRight"
@
blur=
"handleInputBlur(row.code, item.field, item.matchedFormula?.formula)"
/>
<vxe-checkbox-group
v-else-if=
"item.type === 'checkbox'"
v-model=
"formData[row.code +'_'+ item.field]"
>
>
</vxe-input>
<vxe-checkbox
v-for=
"option in item.options || []"
:key=
"option.value"
:label=
"option.label"
:value=
"option.value"
/>
</vxe-checkbox-group>
<span
v-if=
"showHelpIcon(row.code, item.field, item)"
class=
"help-icon"
@
click
.
stop=
"toggleTooltip(row.code, item.field)"
title=
"点击查看校验规则"
>
?
</span>
<span
v-if=
"inputErrors[getFieldKey(row.code, item.field)]"
class=
"error-icon"
@
click
.
stop=
"toggleErrorTooltip(row.code, item.field)"
title=
"点击查看错误详情"
>
<i
class=
"vxe-icon-error"
>
✗
</i>
</span>
<div
v-if=
"showTooltip && hoveredKey === getFieldKey(row.code, item.field)"
class=
"tooltip"
@
click
.
stop
>
{{
item
.
matchedFormula
?.
des
||
'暂无校验规则'
}}
</div>
<div
v-if=
"showErrorTooltip && hoveredErrorKey === getFieldKey(row.code, item.field)"
class=
"error-tooltip"
@
click
.
stop
>
{{
inputErrors
[
getFieldKey
(
row
.
code
,
item
.
field
)]?.
message
||
'未知错误'
}}
<br
v-if=
"inputErrors[getFieldKey(row.code, item.field)]?.formula"
>
<span
v-if=
"inputErrors[getFieldKey(row.code, item.field)]?.formula"
style=
"color: #ffcccc;"
>
公式:
{{
inputErrors
[
getFieldKey
(
row
.
code
,
item
.
field
)]?.
formula
}}
</span>
<template
v-if=
"inputErrors[getFieldKey(row.code, item.field)]?.error"
>
<br>
<span
style=
"color: #ff9999; font-size: 11px;"
>
错误:
{{
inputErrors
[
getFieldKey
(
row
.
code
,
item
.
field
)]?.
error
}}
</span>
</
template
>
</div>
</div>
<span
v-else
style=
"color: #999; font-style: italic;"
>
无权限
</span>
</template>
</template>
</template>
</template>
</template>
</div>
</div>
...
@@ -69,32 +136,47 @@
...
@@ -69,32 +136,47 @@
</vxe-column>
</vxe-column>
<vxe-column
field=
"remarks"
title=
"备注"
width=
"200"
>
<vxe-column
field=
"remarks"
title=
"备注"
width=
"200"
>
<
template
#
default=
"{ row }"
>
<
template
#
default=
"{ row }"
>
<vxe-textarea
:rows=
"row.remarks.rows"
v-model=
"formData[row.code+'_'+row.remarks.field]"
>
<vxe-textarea
:rows=
"row.remarks?.rows || 2"
v-model=
"formData[row.code+'_'+(row.remarks?.field || 'remarks')]"
:disabled=
"!row.remarks?.hasRight"
>
</vxe-textarea>
</vxe-textarea>
</
template
>
</
template
>
</vxe-column>
</vxe-column>
</vxe-table>
</vxe-table>
<ValidationDrawer
ref=
"validationDrawerRef"
v-model=
"drawerVisible"
:tableFormData=
"tableFormData"
@
validationResultClick=
"handleValidationResultClick"
/>
</div>
</div>
</template>
</template>
<
script
lang=
"ts"
setup
>
<
script
lang=
"ts"
setup
>
import
AttachTable
from
'../tableComponents/AttachTable.vue'
import
AttachTable
from
'../tableComponents/AttachTable.vue'
import
ValidationDrawer
from
'./check/ValidationDrawer.vue'
import
{
tableFormData
}
from
'../../data/tb11.data'
;
import
{
tableFormData
}
from
'../../data/tb11.data'
;
import
{
ref
,
reactive
,
onMounted
}
from
'vue'
import
{
ref
,
reactive
,
onMounted
,
nextTick
,
watch
}
from
'vue'
import
{
VxeUI
}
from
'vxe-table'
import
{
VxeUI
}
from
'vxe-table'
import
{
batchSaveOrUpdateBeforeDelete
,
queryRecord
}
from
'../../record/BaosongTaskRecord.api'
import
{
batchSaveOrUpdateBeforeDelete
,
queryRecord
}
from
'../../record/BaosongTaskRecord.api'
import
{
allTplItems
}
from
'../../tpl/BaosongTplItem.api'
import
{
allTplItems
}
from
'../../tpl/BaosongTplItem.api'
import
{
findUserRightForTplItem
}
from
'../../alloc/BaosongTaskAlloc.api'
import
{
getTblvalidFormula
}
from
'../../tpl/BaosongDataValid.api'
import
{
useRoute
}
from
'vue-router'
;
import
{
useRoute
}
from
'vue-router'
;
const
route
=
useRoute
();
const
route
=
useRoute
();
const
tableRef
=
ref
();
const
tableRef
=
ref
();
const
tplItemMap
=
ref
({});
const
tplItemMap
=
ref
<
Record
<
string
,
any
>>
({});
const
validationDrawerRef
=
ref
();
const
queryParam
=
ref
({
const
queryParam
=
ref
({
taskId
:
-
1
,
taskId
:
-
1
,
taskName
:
''
,
taskName
:
''
,
tplId
:
-
1
,
tplId
:
-
1
,
tplName
:
''
,
tplName
:
''
,
tplCode
:
''
tplCode
:
''
})
})
interface
FormData
{
interface
FormData
{
...
@@ -108,7 +190,32 @@ interface FormData {
...
@@ -108,7 +190,32 @@ interface FormData {
rind
:
number
rind
:
number
}
}
onMounted
(
async
()
=>
{
interface
FormulaItem
{
formula
:
string
des
:
string
[
key
:
string
]:
any
}
interface
InputError
{
message
:
string
formula
:
string
error
?:
string
}
const
loading
=
ref
(
false
)
const
formData
=
reactive
<
Record
<
string
,
any
>>
({});
const
formValues
=
ref
<
FormData
[]
>
([])
const
userAllocItems
=
ref
<
string
[]
>
([])
const
validFormula
=
ref
<
any
[]
>
([])
const
drawerVisible
=
ref
(
false
)
const
showTooltip
=
ref
(
false
)
const
hoveredKey
=
ref
(
''
)
const
showErrorTooltip
=
ref
(
false
)
const
hoveredErrorKey
=
ref
(
''
)
const
inputErrors
=
ref
<
Record
<
string
,
InputError
>>
({})
const
isInitialized
=
ref
(
false
)
onMounted
(
async
()
=>
{
if
(
route
.
query
.
taskId
)
{
if
(
route
.
query
.
taskId
)
{
queryParam
.
value
.
taskId
=
Number
(
route
.
query
.
taskId
);
queryParam
.
value
.
taskId
=
Number
(
route
.
query
.
taskId
);
}
}
...
@@ -125,23 +232,69 @@ onMounted(async ()=>{
...
@@ -125,23 +232,69 @@ onMounted(async ()=>{
queryParam
.
value
.
tplCode
=
String
(
route
.
query
.
tplCode
);
queryParam
.
value
.
tplCode
=
String
(
route
.
query
.
tplCode
);
}
}
try
{
if
(
queryParam
.
value
.
tplId
>
0
&&
queryParam
.
value
.
taskId
>
0
)
{
userAllocItems
.
value
=
await
findUserRightForTplItem
({
tplid
:
queryParam
.
value
.
tplId
,
taskid
:
queryParam
.
value
.
taskId
})
validFormula
.
value
=
await
getTblvalidFormula
({
tplid
:
queryParam
.
value
.
tplId
,
})
}
}
catch
(
error
)
{
console
.
error
(
'获取权限或验证公式失败:'
,
error
)
VxeUI
.
modal
.
message
({
content
:
'获取表单权限或校验规则失败,部分功能可能受限'
,
status
:
'warning'
})
}
await
setTplItemMap
()
await
setTplItemMap
()
await
setData
();
setFormItemRight
()
}
)
await
setData
(
)
const
loading
=
ref
(
false
)
isInitialized
.
value
=
true
const
formData
=
reactive
({});
const
formValues
=
ref
<
FormData
[]
>
([])
await
nextTick
()
refreshHelpIcons
()
})
const
saveBatch
=
async
()
=>
{
const
saveBatch
=
async
()
=>
{
try
{
try
{
loading
.
value
=
true
formValues
.
value
=
[]
formValues
.
value
=
[]
// 检查必填项
const
requiredErrors
:
string
[]
=
[]
tableFormData
.
forEach
((
row
:
any
)
=>
{
if
(
row
.
content
&&
Array
.
isArray
(
row
.
content
))
{
row
.
content
.
forEach
((
item
:
any
)
=>
{
if
(
item
.
field
&&
item
.
required
&&
item
.
hasRight
!==
false
)
{
const
key
=
getFieldKey
(
row
.
code
,
item
.
field
)
const
value
=
formData
[
key
]
if
(
!
value
||
(
Array
.
isArray
(
value
)
&&
value
.
length
===
0
)
||
value
===
''
)
{
requiredErrors
.
push
(
`
${
row
.
project
||
''
}
-
${
item
.
label
||
item
.
field
}
`
)
}
}
})
}
})
if
(
requiredErrors
.
length
>
0
)
{
VxeUI
.
modal
.
message
({
content
:
`以下必填项未填写:\n
${
requiredErrors
.
join
(
'
\
n'
)}
`
,
status
:
'error'
,
duration
:
5000
})
return
}
for
(
const
strKey
in
formData
)
{
for
(
const
strKey
in
formData
)
{
const
valData
=
formData
[
strKey
]
const
valData
=
formData
[
strKey
]
if
(
valData
)
{
if
(
valData
!==
undefined
&&
valData
!==
null
&&
valData
!==
''
)
{
let
tmpAry
=
strKey
.
split
(
"_"
)
const
tmpAry
=
strKey
.
split
(
"_"
)
await
setFormValues
(
tmpAry
[
0
],
tmpAry
[
1
],
valData
,
1
)
if
(
tmpAry
.
length
>=
2
)
{
await
setFormValues
(
tmpAry
[
0
],
tmpAry
[
1
],
valData
,
1
)
}
}
}
}
}
...
@@ -153,14 +306,19 @@ const saveBatch = async () => {
...
@@ -153,14 +306,19 @@ const saveBatch = async () => {
}
else
{
}
else
{
VxeUI
.
modal
.
message
({
content
:
'没有需要保存的数据'
,
status
:
'warning'
})
VxeUI
.
modal
.
message
({
content
:
'没有需要保存的数据'
,
status
:
'warning'
})
}
}
}
catch
(
error
)
{
}
catch
(
error
:
any
)
{
VxeUI
.
modal
.
message
({
content
:
`保存失败:
${
error
.
message
}
`
,
status
:
'error'
})
console
.
error
(
'保存失败:'
,
error
)
VxeUI
.
modal
.
message
({
content
:
`保存失败:
${
error
.
message
||
'未知错误'
}
`
,
status
:
'error'
,
duration
:
5000
})
}
finally
{
}
finally
{
loading
.
value
=
false
loading
.
value
=
false
}
}
}
}
const
childAttachTableRefs
=
ref
({})
const
childAttachTableRefs
=
ref
<
Record
<
string
,
any
>>
({})
const
setAttachTableRef
=
(
el
:
any
,
index
:
string
)
=>
{
const
setAttachTableRef
=
(
el
:
any
,
index
:
string
)
=>
{
if
(
el
)
{
if
(
el
)
{
childAttachTableRefs
.
value
[
index
]
=
el
;
childAttachTableRefs
.
value
[
index
]
=
el
;
...
@@ -170,21 +328,36 @@ const setAttachTableRef = (el: any, index: string) => {
...
@@ -170,21 +328,36 @@ const setAttachTableRef = (el: any, index: string) => {
const
getAttachTableFormData
=
async
()
=>
{
const
getAttachTableFormData
=
async
()
=>
{
for
(
const
pcode
in
childAttachTableRefs
.
value
)
{
for
(
const
pcode
in
childAttachTableRefs
.
value
)
{
const
child
=
childAttachTableRefs
.
value
[
pcode
];
const
child
=
childAttachTableRefs
.
value
[
pcode
];
if
(
child
)
{
if
(
child
&&
typeof
child
.
getFormData
===
'function'
)
{
try
{
const
datas
=
child
.
getFormData
()
const
datas
=
child
.
getFormData
()
if
(
datas
&&
typeof
datas
===
'object'
)
{
for
(
const
code
in
datas
)
{
for
(
const
code
in
datas
)
{
await
setFormValues
(
pcode
,
code
,
datas
[
code
],
1
)
await
setFormValues
(
pcode
,
code
,
datas
[
code
],
1
)
}
}
}
catch
(
error
)
{
console
.
error
(
`获取附件表格
${
pcode
}
数据失败:`
,
error
)
}
}
}
}
}
}
};
};
const
setFormValues
=
async
(
pcode
,
code
,
valData
,
rind
)
=>
{
const
setFormValues
=
async
(
pcode
:
string
,
code
:
string
,
valData
:
any
,
rind
:
number
)
=>
{
if
(
!
valData
)
return
;
if
(
valData
===
undefined
||
valData
===
null
)
return
;
let
vals
=
Array
.
isArray
(
valData
)
?
valData
.
join
(
','
)
:
valData
let
strKey
=
pcode
+
"_"
+
code
let
vals
:
string
;
if
(
Array
.
isArray
(
valData
))
{
vals
=
valData
.
filter
(
item
=>
item
!==
null
&&
item
!==
undefined
&&
item
!==
''
).
join
(
','
)
}
else
{
vals
=
String
(
valData
).
trim
()
}
if
(
!
vals
)
return
;
const
strKey
=
pcode
+
"_"
+
code
const
item
=
tplItemMap
.
value
[
strKey
];
const
item
=
tplItemMap
.
value
[
strKey
];
const
{
pid
,
itemid
}
=
item
??
{};
const
{
pid
,
itemid
}
=
item
||
{};
let
tempForm
:
FormData
=
{
let
tempForm
:
FormData
=
{
id
:
null
,
id
:
null
,
...
@@ -204,42 +377,77 @@ async function setData() {
...
@@ -204,42 +377,77 @@ async function setData() {
loading
.
value
=
true
loading
.
value
=
true
const
taskId
=
queryParam
.
value
.
taskId
const
taskId
=
queryParam
.
value
.
taskId
const
tplid
=
queryParam
.
value
.
tplId
const
tplid
=
queryParam
.
value
.
tplId
Object
.
keys
(
formData
).
forEach
(
key
=>
delete
formData
[
key
])
// 清空现有数据
Object
.
keys
(
formData
).
forEach
(
key
=>
{
delete
formData
[
key
]
})
await
setTplItemMap
();
await
setTplItemMap
();
if
(
taskId
<=
0
||
tplid
<=
0
)
{
console
.
warn
(
'taskId 或 tplId 无效,跳过数据加载'
)
return
}
const
recordData
=
await
queryRecord
({
taskid
:
taskId
,
tplid
:
tplid
})
const
recordData
=
await
queryRecord
({
taskid
:
taskId
,
tplid
:
tplid
})
let
valueObj
=
{}
let
valueObj
:
Record
<
string
,
string
>
=
{}
if
(
recordData
&&
Array
.
isArray
(
recordData
))
{
for
(
let
data
of
recordData
)
{
for
(
let
data
of
recordData
)
{
valueObj
[
data
.
itempid
+
"_"
+
data
.
itemid
+
"_"
+
data
.
rind
]
=
data
[
"content"
]
const
key
=
`
${
data
.
itempid
}
_
${
data
.
itemid
}
_
${
data
.
rind
}
`
valueObj
[
key
]
=
data
.
content
||
''
}
}
}
// 加载主表数据
Object
.
keys
(
tplItemMap
.
value
).
forEach
(
strKey
=>
{
Object
.
keys
(
tplItemMap
.
value
).
forEach
(
strKey
=>
{
const
item
=
tplItemMap
.
value
[
strKey
];
const
item
=
tplItemMap
.
value
[
strKey
];
const
{
pid
,
itemid
,
formTp
}
=
item
??
{};
const
{
pid
,
itemid
,
formTp
}
=
item
||
{};
const
dataVal
=
valueObj
[
pid
+
"_"
+
itemid
+
"_1"
]
const
dataVal
=
valueObj
[
`
${
pid
}
_
${
itemid
}
_1`
]
if
(
dataVal
!==
undefined
)
{
if
(
formTp
==
'checkbox'
)
{
if
(
formTp
==
'checkbox'
)
{
formData
[
strKey
]
=
dataVal
?.
split
(
","
)
formData
[
strKey
]
=
dataVal
?
dataVal
.
split
(
","
).
filter
(
Boolean
)
:
[]
}
else
{
}
else
{
formData
[
strKey
]
=
dataVal
formData
[
strKey
]
=
dataVal
}
}
}
});
});
// 加载附件表格数据
Object
.
keys
(
childAttachTableRefs
.
value
).
forEach
(
pcode
=>
{
Object
.
keys
(
childAttachTableRefs
.
value
).
forEach
(
pcode
=>
{
const
child
=
childAttachTableRefs
.
value
[
pcode
];
const
child
=
childAttachTableRefs
.
value
[
pcode
];
if
(
child
&&
typeof
child
.
setFormData
===
'function'
)
{
const
matchingKeys
=
Object
.
keys
(
tplItemMap
.
value
).
filter
(
key
=>
key
.
startsWith
(
pcode
+
'_'
));
const
matchingKeys
=
Object
.
keys
(
tplItemMap
.
value
).
filter
(
key
=>
key
.
startsWith
(
pcode
+
'_'
));
const
matchingObjects
=
matchingKeys
.
map
(
key
=>
tplItemMap
.
value
[
key
]);
const
matchingObjects
=
matchingKeys
.
map
(
key
=>
tplItemMap
.
value
[
key
]);
let
attachTableData
=
{}
let
attachTableData
:
Record
<
string
,
any
>
=
{}
for
(
let
tmpData
of
matchingObjects
)
{
for
(
let
tmpData
of
matchingObjects
)
{
const
{
pid
,
itemid
,
formTp
,
code
}
=
tmpData
??
{};
const
{
pid
,
itemid
,
formTp
,
code
}
=
tmpData
||
{};
const
dataVal
=
valueObj
[
`
${
pid
}
_
${
itemid
}
_1`
]
if
(
dataVal
!==
undefined
)
{
if
(
formTp
==
'checkbox'
)
{
if
(
formTp
==
'checkbox'
)
{
attachTableData
[
code
]
=
valueObj
[
pid
+
"_"
+
itemid
+
"_1"
]?.
split
(
","
)
attachTableData
[
code
]
=
dataVal
?
dataVal
.
split
(
","
).
filter
(
Boolean
)
:
[]
}
else
{
}
else
{
attachTableData
[
code
]
=
valueObj
[
pid
+
"_"
+
itemid
+
"_1"
]
attachTableData
[
code
]
=
dataVal
}
}
}
}
}
if
(
Object
.
keys
(
attachTableData
).
length
>
0
)
{
child
.
setFormData
(
attachTableData
)
child
.
setFormData
(
attachTableData
)
}
}
})
}
catch
(
error
:
any
)
{
console
.
error
(
'加载数据失败:'
,
error
)
VxeUI
.
modal
.
message
({
content
:
`加载数据失败:
${
error
.
message
||
'未知错误'
}
`
,
status
:
'error'
,
duration
:
3000
})
})
}
catch
(
error
)
{
VxeUI
.
modal
.
message
({
content
:
`加载数据失败:
${
error
.
message
}
`
,
status
:
'error'
})
}
finally
{
}
finally
{
loading
.
value
=
false
loading
.
value
=
false
}
}
...
@@ -248,18 +456,289 @@ async function setData() {
...
@@ -248,18 +456,289 @@ async function setData() {
async
function
setTplItemMap
()
{
async
function
setTplItemMap
()
{
try
{
try
{
const
tplid
=
queryParam
.
value
.
tplId
const
tplid
=
queryParam
.
value
.
tplId
if
(
tplid
<=
0
)
{
console
.
warn
(
'tplId 无效,跳过加载模板项'
)
return
}
const
tplItem
=
await
allTplItems
({
const
tplItem
=
await
allTplItems
({
tplid
:
tplid
,
tplid
:
tplid
,
})
})
tplItemMap
.
value
=
{}
tplItem
.
forEach
(
item
=>
{
tplItem
.
forEach
(
item
=>
{
let
strKey
=
item
.
pcode
+
"_"
+
item
.
xmlcode
;
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
,
label
:
item
.
label
};
})
console
.
log
(
'tplItemMap 加载完成,数量:'
,
Object
.
keys
(
tplItemMap
.
value
).
length
)
}
catch
(
error
:
any
)
{
console
.
error
(
'加载模板项失败:'
,
error
)
VxeUI
.
modal
.
message
({
content
:
`加载模板配置失败:
${
error
.
message
||
'未知错误'
}
`
,
status
:
'error'
,
duration
:
3000
})
})
}
catch
(
error
)
{
VxeUI
.
modal
.
message
({
content
:
`加载数据失败:
${
error
.
message
}
`
,
status
:
'error'
})
}
}
}
}
const
checkData
=
()
=>
{
drawerVisible
.
value
=
true
validationDrawerRef
.
value
?.
setValidateData
(
validFormula
.
value
,
formData
)
}
const
handleInputBlur
=
(
rowCode
:
string
,
field
:
string
,
formula
?:
string
)
=>
{
if
(
!
formula
)
return
;
const
key
=
getFieldKey
(
rowCode
,
field
);
const
value
=
formData
[
key
];
if
(
!
value
||
value
===
''
)
{
delete
inputErrors
.
value
[
key
];
return
;
}
validateFieldFormula
(
rowCode
,
field
,
formula
);
};
const
validateFieldFormula
=
(
rowCode
:
string
,
field
:
string
,
formula
:
string
)
=>
{
const
key
=
getFieldKey
(
rowCode
,
field
);
try
{
const
expression
=
buildExpression
(
formula
,
rowCode
);
const
isValid
=
eval
(
expression
);
if
(
!
isValid
)
{
inputErrors
.
value
[
key
]
=
{
message
:
"公式校验失败,请检查填写内容"
,
formula
};
}
else
{
delete
inputErrors
.
value
[
key
];
}
}
catch
(
error
:
any
)
{
inputErrors
.
value
[
key
]
=
{
message
:
"公式校验失败,请检查填写内容"
,
formula
,
error
:
error
.
message
};
}
};
const
buildExpression
=
(
formula
:
string
,
rowCode
:
string
):
string
=>
{
const
fieldNames
=
formula
.
match
(
/
\b[
A-Za-z
][
A-Za-z0-9_
]
*
\b
/g
)
||
[];
const
uniqueFields
=
[...
new
Set
(
fieldNames
.
filter
(
f
=>
!
[
'and'
,
'or'
,
'not'
,
'equal'
,
'less'
,
'greater'
,
'if'
,
'else'
,
'true'
,
'false'
]
.
includes
(
f
.
toLowerCase
())
))];
uniqueFields
.
sort
((
a
,
b
)
=>
b
.
length
-
a
.
length
);
let
expression
=
formula
;
for
(
const
fieldName
of
uniqueFields
)
{
const
key
=
getFieldKey
(
rowCode
,
fieldName
);
const
value
=
formData
[
key
];
if
(
value
!==
undefined
&&
value
!==
null
&&
value
!==
''
)
{
const
numValue
=
Number
(
value
);
if
(
!
isNaN
(
numValue
))
{
expression
=
expression
.
replace
(
new
RegExp
(
`\\b
${
fieldName
}
\\b`
,
'g'
),
numValue
.
toString
()
);
}
}
}
return
expression
;
};
const
toggleTooltip
=
(
rowCode
:
string
,
field
:
string
)
=>
{
const
key
=
getFieldKey
(
rowCode
,
field
);
if
(
hoveredKey
.
value
===
key
)
{
showTooltip
.
value
=
false
;
hoveredKey
.
value
=
''
;
}
else
{
showTooltip
.
value
=
true
;
hoveredKey
.
value
=
key
;
showErrorTooltip
.
value
=
false
;
hoveredErrorKey
.
value
=
''
;
}
};
const
toggleErrorTooltip
=
(
rowCode
:
string
,
field
:
string
)
=>
{
const
key
=
getFieldKey
(
rowCode
,
field
);
if
(
hoveredErrorKey
.
value
===
key
)
{
showErrorTooltip
.
value
=
false
;
hoveredErrorKey
.
value
=
''
;
}
else
{
showErrorTooltip
.
value
=
true
;
hoveredErrorKey
.
value
=
key
;
showTooltip
.
value
=
false
;
hoveredKey
.
value
=
''
;
}
};
const
closeAllTooltips
=
()
=>
{
showTooltip
.
value
=
false
;
hoveredKey
.
value
=
''
;
showErrorTooltip
.
value
=
false
;
hoveredErrorKey
.
value
=
''
;
};
const
showHelpIcon
=
(
rowCode
:
string
,
field
:
string
,
item
:
any
):
boolean
=>
{
if
(
!
item
||
item
.
hasRight
===
false
)
{
return
false
;
}
if
(
item
.
hasValidFormula
!==
undefined
)
{
return
item
.
hasValidFormula
===
true
;
}
const
key
=
getFieldKey
(
rowCode
,
field
);
const
hasRight
=
userAllocItems
.
value
.
includes
(
key
);
if
(
!
hasRight
)
return
false
;
const
formulaResult
=
findEarliestFormulaForField
(
validFormula
.
value
,
field
);
return
!!
formulaResult
.
formula
;
};
const
setFormItemRight
=
()
=>
{
console
.
log
(
'开始设置表单权限...'
)
console
.
log
(
'userAllocItems 数量:'
,
userAllocItems
.
value
?.
length
||
0
)
console
.
log
(
'validFormula 数量:'
,
validFormula
.
value
?.
length
||
0
)
if
(
!
tableFormData
||
!
Array
.
isArray
(
tableFormData
))
{
console
.
warn
(
'tableFormData 不存在或不是数组'
)
return
}
tableFormData
.
forEach
((
row
:
any
)
=>
{
if
(
row
.
content
&&
Array
.
isArray
(
row
.
content
))
{
row
.
content
.
forEach
((
item
:
any
)
=>
{
if
(
item
&&
item
.
field
)
{
const
key
=
getFieldKey
(
row
.
code
,
item
.
field
)
item
.
hasRight
=
userAllocItems
.
value
.
includes
(
key
)
if
(
item
.
hasRight
)
{
const
formulaResult
=
findEarliestFormulaForField
(
validFormula
.
value
,
item
.
field
)
item
.
hasValidFormula
=
!!
formulaResult
.
formula
item
.
matchedFormula
=
formulaResult
.
formula
||
null
}
else
{
item
.
hasValidFormula
=
false
item
.
matchedFormula
=
null
}
}
})
}
// 设置备注权限
if
(
row
.
remarks
&&
row
.
remarks
.
field
)
{
const
remarksKey
=
getFieldKey
(
row
.
code
,
row
.
remarks
.
field
)
row
.
remarks
.
hasRight
=
userAllocItems
.
value
.
includes
(
remarksKey
)
}
})
console
.
log
(
'表单权限设置完成'
)
}
const
findEarliestFormulaForField
=
(
formulas
:
FormulaItem
[],
field
:
string
):
{
formula
:
FormulaItem
|
null
,
index
:
number
}
=>
{
let
result
=
{
formula
:
null
,
index
:
Infinity
}
if
(
!
formulas
||
!
Array
.
isArray
(
formulas
))
{
return
result
}
formulas
.
forEach
((
f
:
FormulaItem
,
idx
:
number
)
=>
{
if
(
f
&&
f
.
formula
)
{
const
text
=
f
.
formula
const
escapedField
=
field
.
replace
(
/
[
.*+?^${}()|[
\]\\]
/g
,
'
\\
$&'
)
const
regex
=
new
RegExp
(
`\\b
${
escapedField
}
\\b(?!\\w)`
,
'g'
)
const
match
=
regex
.
exec
(
text
)
if
(
match
&&
match
.
index
<
result
.
index
)
{
result
=
{
formula
:
f
,
index
:
match
.
index
}
}
}
})
return
result
}
const
refreshHelpIcons
=
()
=>
{
console
.
log
(
'刷新帮助图标...'
)
if
(
!
tableFormData
||
!
Array
.
isArray
(
tableFormData
))
return
tableFormData
.
forEach
((
row
:
any
)
=>
{
if
(
row
.
content
&&
Array
.
isArray
(
row
.
content
))
{
row
.
content
.
forEach
((
item
:
any
)
=>
{
if
(
item
&&
item
.
field
)
{
const
key
=
getFieldKey
(
row
.
code
,
item
.
field
)
const
hasRight
=
userAllocItems
.
value
.
includes
(
key
)
if
(
hasRight
)
{
const
formulaResult
=
findEarliestFormulaForField
(
validFormula
.
value
,
item
.
field
)
item
.
hasValidFormula
=
!!
formulaResult
.
formula
item
.
matchedFormula
=
formulaResult
.
formula
||
null
}
else
{
item
.
hasValidFormula
=
false
item
.
matchedFormula
=
null
}
}
})
}
})
}
const
getFieldKey
=
(
pcode
:
string
|
undefined
,
field
:
string
):
string
=>
{
return
pcode
?
`
${
pcode
}
_
${
field
}
`
:
field
}
const
handleValidationResultClick
=
(
result
:
any
)
=>
{
if
(
!
result
)
return
const
message
=
`字段
${
result
.
field
||
'未知'
}
的校验结果:
${
result
.
isValid
?
'通过'
:
'失败'
}
`
const
status
=
result
.
isValid
?
'success'
:
'error'
VxeUI
.
modal
.
message
({
content
:
message
,
status
})
}
// 监听数据变化,自动校验
watch
(
formData
,
(
newVal
,
oldVal
)
=>
{
if
(
!
isInitialized
.
value
)
return
// 找到变化的字段
const
changedKeys
:
string
[]
=
[]
Object
.
keys
(
newVal
).
forEach
(
key
=>
{
if
(
newVal
[
key
]
!==
oldVal
[
key
])
{
changedKeys
.
push
(
key
)
}
})
// 对新字段进行校验
changedKeys
.
forEach
(
key
=>
{
const
[
rowCode
,
field
]
=
key
.
split
(
'_'
)
if
(
rowCode
&&
field
)
{
// 查找对应的校验规则
const
row
=
tableFormData
.
find
((
r
:
any
)
=>
r
.
code
===
rowCode
)
if
(
row
&&
row
.
content
)
{
const
item
=
row
.
content
.
find
((
c
:
any
)
=>
c
.
field
===
field
)
if
(
item
&&
item
.
matchedFormula
?.
formula
)
{
handleInputBlur
(
rowCode
,
field
,
item
.
matchedFormula
.
formula
)
}
}
}
})
},
{
deep
:
true
})
</
script
>
</
script
>
<
style
lang=
"less"
scoped
>
<
style
lang=
"less"
scoped
>
...
@@ -288,7 +767,12 @@ async function setTplItemMap() {
...
@@ -288,7 +767,12 @@ async function setTplItemMap() {
}
}
.table-input {
.table-input {
width: 80px;
width: 120px;
margin: 0 2px;
}
.table-textarea {
width: 200px;
margin: 0 2px;
margin: 0 2px;
}
}
...
@@ -301,6 +785,123 @@ async function setTplItemMap() {
...
@@ -301,6 +785,123 @@ async function setTplItemMap() {
border-left: none;
border-left: none;
border-right: none;
border-right: none;
background: transparent;
background: transparent;
line-height: 50px;
line-height: 1.5;
}
.vxe-textarea {
font-size: 12px;
}
.input-wrapper {
position: relative;
display: inline-block;
vertical-align: middle;
}
.help-icon {
margin-left: 5px;
cursor: pointer;
color: #1890ff;
font-weight: bold;
font-size: 14px;
display: inline-block;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
background: #e6f7ff;
border-radius: 50%;
transition: all 0.3s;
opacity: 0;
animation: fadeIn 0.5s forwards;
animation-delay: 0.3s;
&:hover {
background: #bae7ff;
transform: scale(1.1);
}
}
@keyframes fadeIn {
from {
opacity: 0;
transform: scale(0.8);
}
to {
opacity: 1;
transform: scale(1);
}
}
.error-icon {
margin-left: 5px;
cursor: pointer;
color: #ff4d4f;
font-size: 16px;
display: inline-block;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
transition: all 0.3s;
&:hover {
transform: scale(1.1);
}
}
.tooltip, .error-tooltip {
position: absolute;
top: 100%;
left: 0;
margin-top: 5px;
padding: 10px;
font-size: 12px;
border-radius: 4px;
z-index: 1000;
white-space: pre-wrap;
max-width: 300px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
pointer-events: none;
}
.tooltip {
background: #333;
color: #fff;
&::before {
content: '';
position: absolute;
bottom: 100%;
left: 10px;
border-width: 5px;
border-style: solid;
border-color: transparent transparent #333 transparent;
}
}
.error-tooltip {
background: #8b0000;
color: #fff;
&::before {
content: '';
position: absolute;
bottom: 100%;
left: 10px;
border-width: 5px;
border-style: solid;
border-color: transparent transparent #8b0000 transparent;
}
}
// 添加必填项标识
.input-wrapper.required::before {
content: '*';
color: #ff4d4f;
position: absolute;
left: -8px;
top: 0;
font-size: 14px;
}
}
</
style
>
</
style
>
\ No newline at end of file
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论