Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
753e44cc
authored
Jan 15, 2025
by
芋道源码
Committed by
Gitee
Jan 15, 2025
Browse files
Options
Browse Files
Download
Plain Diff
!655 Simple设计器完善及优化
Merge pull request !655 from Lesan/feature/bpm-n
parents
c391ba76
42c16182
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
293 additions
and
270 deletions
+293
-270
src/api/bpm/processInstance/index.ts
+1
-0
src/components/SimpleProcessDesignerV2/src/NodeHandler.vue
+8
-8
src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue
+3
-3
src/components/SimpleProcessDesignerV2/src/consts.ts
+5
-7
src/components/SimpleProcessDesignerV2/src/nodes-config/ConditionNodeConfig.vue
+31
-203
src/components/SimpleProcessDesignerV2/src/nodes-config/RouterNodeConfig.vue
+24
-15
src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue
+61
-8
src/components/SimpleProcessDesignerV2/src/nodes-config/components/Condition.vue
+38
-19
src/components/SimpleProcessDesignerV2/src/nodes/RouterNode.vue
+5
-5
src/views/bpm/processInstance/detail/ProcessInstanceOperationButton.vue
+23
-1
src/views/bpm/processInstance/detail/ProcessInstanceSimpleViewer.vue
+1
-1
src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue
+9
-0
src/views/bpm/processInstance/detail/SignDialog.vue
+84
-0
No files found.
src/api/bpm/processInstance/index.ts
View file @
753e44cc
...
@@ -36,6 +36,7 @@ export type ApprovalTaskInfo = {
...
@@ -36,6 +36,7 @@ export type ApprovalTaskInfo = {
assigneeUser
:
User
assigneeUser
:
User
status
:
number
status
:
number
reason
:
string
reason
:
string
sign
:
string
}
}
// 审批节点信息
// 审批节点信息
...
...
src/components/SimpleProcessDesignerV2/src/NodeHandler.vue
View file @
753e44cc
...
@@ -46,7 +46,7 @@
...
@@ -46,7 +46,7 @@
</div>
</div>
<div
class=
"handler-item-text"
>
延迟器
</div>
<div
class=
"handler-item-text"
>
延迟器
</div>
</div>
</div>
<div
class=
"handler-item"
@
click=
"addNode(NodeType.ROUTE_BRANCH_NODE)"
>
<div
class=
"handler-item"
@
click=
"addNode(NodeType.ROUTE
R
_BRANCH_NODE)"
>
<!-- TODO @芋艿 需要更换一下iconfont的图标 -->
<!-- TODO @芋艿 需要更换一下iconfont的图标 -->
<div
class=
"handler-item-icon copy"
>
<div
class=
"handler-item-icon copy"
>
<span
class=
"iconfont icon-size icon-copy"
></span>
<span
class=
"iconfont icon-size icon-copy"
></span>
...
@@ -67,12 +67,13 @@ import {
...
@@ -67,12 +67,13 @@ import {
ApproveMethodType
,
ApproveMethodType
,
AssignEmptyHandlerType
,
AssignEmptyHandlerType
,
AssignStartUserHandlerType
,
AssignStartUserHandlerType
,
ConditionType
,
NODE_DEFAULT_NAME
,
NODE_DEFAULT_NAME
,
NodeType
,
NodeType
,
RejectHandlerType
,
RejectHandlerType
,
SimpleFlowNode
SimpleFlowNode
}
from
'./consts'
}
from
'./consts'
import
{
generateUUID
}
from
'@/utils'
import
{
generateUUID
}
from
'@/utils'
defineOptions
({
defineOptions
({
name
:
'NodeHandler'
name
:
'NodeHandler'
...
@@ -163,7 +164,7 @@ const addNode = (type: number) => {
...
@@ -163,7 +164,7 @@ const addNode = (type: number) => {
showText
:
''
,
showText
:
''
,
type
:
NodeType
.
CONDITION_NODE
,
type
:
NodeType
.
CONDITION_NODE
,
childNode
:
undefined
,
childNode
:
undefined
,
conditionType
:
1
,
conditionType
:
ConditionType
.
RULE
,
defaultFlow
:
false
defaultFlow
:
false
},
},
{
{
...
@@ -241,14 +242,13 @@ const addNode = (type: number) => {
...
@@ -241,14 +242,13 @@ const addNode = (type: number) => {
}
}
emits
(
'update:childNode'
,
data
)
emits
(
'update:childNode'
,
data
)
}
}
if
(
type
===
NodeType
.
ROUTE_BRANCH_NODE
)
{
if
(
type
===
NodeType
.
ROUTE
R
_BRANCH_NODE
)
{
const
data
:
SimpleFlowNode
=
{
const
data
:
SimpleFlowNode
=
{
id
:
'GateWay_'
+
generateUUID
(),
id
:
'GateWay_'
+
generateUUID
(),
name
:
NODE_DEFAULT_NAME
.
get
(
NodeType
.
ROUTE_BRANCH_NODE
)
as
string
,
name
:
NODE_DEFAULT_NAME
.
get
(
NodeType
.
ROUTE
R
_BRANCH_NODE
)
as
string
,
showText
:
''
,
showText
:
''
,
type
:
NodeType
.
ROUTE_BRANCH_NODE
,
type
:
NodeType
.
ROUTER_BRANCH_NODE
,
childNode
:
props
.
childNode
,
childNode
:
props
.
childNode
defaultFlowId
:
'Flow_'
+
generateUUID
()
}
}
emits
(
'update:childNode'
,
data
)
emits
(
'update:childNode'
,
data
)
}
}
...
...
src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue
View file @
753e44cc
...
@@ -45,8 +45,8 @@
...
@@ -45,8 +45,8 @@
@
update:flow-node=
"handleModelValueUpdate"
@
update:flow-node=
"handleModelValueUpdate"
/>
/>
<!-- 路由分支节点 -->
<!-- 路由分支节点 -->
<RouteNode
<Route
r
Node
v-if=
"currentNode && currentNode.type === NodeType.ROUTE_BRANCH_NODE"
v-if=
"currentNode && currentNode.type === NodeType.ROUTE
R
_BRANCH_NODE"
:flow-node=
"currentNode"
:flow-node=
"currentNode"
@
update:flow-node=
"handleModelValueUpdate"
@
update:flow-node=
"handleModelValueUpdate"
/>
/>
...
@@ -73,7 +73,7 @@ import ExclusiveNode from './nodes/ExclusiveNode.vue'
...
@@ -73,7 +73,7 @@ import ExclusiveNode from './nodes/ExclusiveNode.vue'
import
ParallelNode
from
'./nodes/ParallelNode.vue'
import
ParallelNode
from
'./nodes/ParallelNode.vue'
import
InclusiveNode
from
'./nodes/InclusiveNode.vue'
import
InclusiveNode
from
'./nodes/InclusiveNode.vue'
import
DelayTimerNode
from
'./nodes/DelayTimerNode.vue'
import
DelayTimerNode
from
'./nodes/DelayTimerNode.vue'
import
Route
Node
from
'./nodes/Route
Node.vue'
import
Route
rNode
from
'./nodes/Router
Node.vue'
import
{
SimpleFlowNode
,
NodeType
}
from
'./consts'
import
{
SimpleFlowNode
,
NodeType
}
from
'./consts'
import
{
useWatchNode
}
from
'./node'
import
{
useWatchNode
}
from
'./node'
defineOptions
({
defineOptions
({
...
...
src/components/SimpleProcessDesignerV2/src/consts.ts
View file @
753e44cc
...
@@ -48,7 +48,7 @@ export enum NodeType {
...
@@ -48,7 +48,7 @@ export enum NodeType {
/**
/**
* 路由分支节点
* 路由分支节点
*/
*/
ROUTE_BRANCH_NODE
=
54
ROUTE
R
_BRANCH_NODE
=
54
}
}
export
enum
NodeId
{
export
enum
NodeId
{
...
@@ -116,7 +116,7 @@ export interface SimpleFlowNode {
...
@@ -116,7 +116,7 @@ export interface SimpleFlowNode {
// 延迟设置
// 延迟设置
delaySetting
?:
DelaySetting
delaySetting
?:
DelaySetting
// 路由分支
// 路由分支
routerGroups
?:
RouteCondition
[]
routerGroups
?:
Route
r
Condition
[]
defaultFlowId
?:
string
defaultFlowId
?:
string
// 签名
// 签名
signEnable
?:
boolean
signEnable
?:
boolean
...
@@ -439,8 +439,6 @@ export enum OperationButtonType {
...
@@ -439,8 +439,6 @@ export enum OperationButtonType {
* 条件规则结构定义
* 条件规则结构定义
*/
*/
export
type
ConditionRule
=
{
export
type
ConditionRule
=
{
type
:
number
opName
:
string
opCode
:
string
opCode
:
string
leftSide
:
string
leftSide
:
string
rightSide
:
string
rightSide
:
string
...
@@ -471,7 +469,7 @@ NODE_DEFAULT_TEXT.set(NodeType.COPY_TASK_NODE, '请配置抄送人')
...
@@ -471,7 +469,7 @@ NODE_DEFAULT_TEXT.set(NodeType.COPY_TASK_NODE, '请配置抄送人')
NODE_DEFAULT_TEXT
.
set
(
NodeType
.
CONDITION_NODE
,
'请设置条件'
)
NODE_DEFAULT_TEXT
.
set
(
NodeType
.
CONDITION_NODE
,
'请设置条件'
)
NODE_DEFAULT_TEXT
.
set
(
NodeType
.
START_USER_NODE
,
'请设置发起人'
)
NODE_DEFAULT_TEXT
.
set
(
NodeType
.
START_USER_NODE
,
'请设置发起人'
)
NODE_DEFAULT_TEXT
.
set
(
NodeType
.
DELAY_TIMER_NODE
,
'请设置延迟器'
)
NODE_DEFAULT_TEXT
.
set
(
NodeType
.
DELAY_TIMER_NODE
,
'请设置延迟器'
)
NODE_DEFAULT_TEXT
.
set
(
NodeType
.
ROUTE_BRANCH_NODE
,
'请设置路由节点'
)
NODE_DEFAULT_TEXT
.
set
(
NodeType
.
ROUTE
R
_BRANCH_NODE
,
'请设置路由节点'
)
export
const
NODE_DEFAULT_NAME
=
new
Map
<
number
,
string
>
()
export
const
NODE_DEFAULT_NAME
=
new
Map
<
number
,
string
>
()
NODE_DEFAULT_NAME
.
set
(
NodeType
.
USER_TASK_NODE
,
'审批人'
)
NODE_DEFAULT_NAME
.
set
(
NodeType
.
USER_TASK_NODE
,
'审批人'
)
...
@@ -479,7 +477,7 @@ NODE_DEFAULT_NAME.set(NodeType.COPY_TASK_NODE, '抄送人')
...
@@ -479,7 +477,7 @@ NODE_DEFAULT_NAME.set(NodeType.COPY_TASK_NODE, '抄送人')
NODE_DEFAULT_NAME
.
set
(
NodeType
.
CONDITION_NODE
,
'条件'
)
NODE_DEFAULT_NAME
.
set
(
NodeType
.
CONDITION_NODE
,
'条件'
)
NODE_DEFAULT_NAME
.
set
(
NodeType
.
START_USER_NODE
,
'发起人'
)
NODE_DEFAULT_NAME
.
set
(
NodeType
.
START_USER_NODE
,
'发起人'
)
NODE_DEFAULT_NAME
.
set
(
NodeType
.
DELAY_TIMER_NODE
,
'延迟器'
)
NODE_DEFAULT_NAME
.
set
(
NodeType
.
DELAY_TIMER_NODE
,
'延迟器'
)
NODE_DEFAULT_NAME
.
set
(
NodeType
.
ROUTE_BRANCH_NODE
,
'路由分支'
)
NODE_DEFAULT_NAME
.
set
(
NodeType
.
ROUTE
R
_BRANCH_NODE
,
'路由分支'
)
// 候选人策略。暂时不从字典中取。 后续可能调整。控制显示顺序
// 候选人策略。暂时不从字典中取。 后续可能调整。控制显示顺序
export
const
CANDIDATE_STRATEGY
:
DictDataVO
[]
=
[
export
const
CANDIDATE_STRATEGY
:
DictDataVO
[]
=
[
...
@@ -660,7 +658,7 @@ export const DELAY_TYPE = [
...
@@ -660,7 +658,7 @@ export const DELAY_TYPE = [
/**
/**
* 路由分支结构定义
* 路由分支结构定义
*/
*/
export
type
RouteCondition
=
{
export
type
Route
r
Condition
=
{
nodeId
:
string
nodeId
:
string
conditionType
:
ConditionType
conditionType
:
ConditionType
conditionExpression
:
string
conditionExpression
:
string
...
...
src/components/SimpleProcessDesignerV2/src/nodes-config/ConditionNodeConfig.vue
View file @
753e44cc
This diff is collapsed.
Click to expand it.
src/components/SimpleProcessDesignerV2/src/nodes-config/RouteNodeConfig.vue
→
src/components/SimpleProcessDesignerV2/src/nodes-config/Route
r
NodeConfig.vue
View file @
753e44cc
...
@@ -37,16 +37,19 @@
...
@@ -37,16 +37,19 @@
:value=
"node.value"
:value=
"node.value"
/>
/>
</el-select>
</el-select>
<el-button
class=
"mla"
type=
"danger"
link
@
click=
"deleteRouteGroup(index)"
<el-button
class=
"mla"
type=
"danger"
link
@
click=
"deleteRoute
r
Group(index)"
>
删除
</el-button
>
删除
</el-button
>
>
</div>
</div>
</
template
>
</
template
>
<Condition
v-model=
"routerGroups[index]"
/>
<Condition
:ref=
"($event) => (conditionRef[index] = $event)"
v-model=
"routerGroups[index]"
/>
</el-card>
</el-card>
</el-form>
</el-form>
<el-button
class=
"w-1/1"
type=
"primary"
:icon=
"Plus"
@
click=
"addRouteGroup"
>
<el-button
class=
"w-1/1"
type=
"primary"
:icon=
"Plus"
@
click=
"addRoute
r
Group"
>
新增路由分支
新增路由分支
</el-button>
</el-button>
</div>
</div>
...
@@ -61,11 +64,11 @@
...
@@ -61,11 +64,11 @@
</template>
</template>
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
Plus
}
from
'@element-plus/icons-vue'
import
{
Plus
}
from
'@element-plus/icons-vue'
import
{
SimpleFlowNode
,
NodeType
,
ConditionType
,
RouteCondition
}
from
'../consts'
import
{
SimpleFlowNode
,
NodeType
,
ConditionType
,
Route
r
Condition
}
from
'../consts'
import
{
useWatchNode
,
useDrawer
,
useNodeName
}
from
'../node'
import
{
useWatchNode
,
useDrawer
,
useNodeName
}
from
'../node'
import
Condition
from
'./components/Condition.vue'
import
Condition
from
'./components/Condition.vue'
defineOptions
({
defineOptions
({
name
:
'RouteNodeConfig'
name
:
'Route
r
NodeConfig'
})
})
const
message
=
useMessage
()
// 消息弹窗
const
message
=
useMessage
()
// 消息弹窗
const
props
=
defineProps
({
const
props
=
defineProps
({
...
@@ -80,12 +83,21 @@ const { settingVisible, closeDrawer, openDrawer } = useDrawer()
...
@@ -80,12 +83,21 @@ const { settingVisible, closeDrawer, openDrawer } = useDrawer()
// 当前节点
// 当前节点
const
currentNode
=
useWatchNode
(
props
)
const
currentNode
=
useWatchNode
(
props
)
// 节点名称
// 节点名称
const
{
nodeName
,
showInput
,
clickIcon
,
blurEvent
}
=
useNodeName
(
NodeType
.
ROUTE_BRANCH_NODE
)
const
{
nodeName
,
showInput
,
clickIcon
,
blurEvent
}
=
useNodeName
(
NodeType
.
ROUTE
R
_BRANCH_NODE
)
const
routerGroups
=
ref
<
RouteCondition
[]
>
([])
const
routerGroups
=
ref
<
Route
r
Condition
[]
>
([])
const
nodeOptions
=
ref
()
const
nodeOptions
=
ref
()
const
conditionRef
=
ref
([])
// 保存配置
// 保存配置
const
saveConfig
=
async
()
=>
{
const
saveConfig
=
async
()
=>
{
// 校验表单
let
valid
=
true
for
(
const
item
of
conditionRef
.
value
)
{
if
(
!
(
await
item
.
validate
()))
{
valid
=
false
}
}
if
(
!
valid
)
return
false
const
showText
=
getShowText
()
const
showText
=
getShowText
()
if
(
!
showText
)
return
false
if
(
!
showText
)
return
false
currentNode
.
value
.
name
=
nodeName
.
value
!
currentNode
.
value
.
name
=
nodeName
.
value
!
...
@@ -96,7 +108,7 @@ const saveConfig = async () => {
...
@@ -96,7 +108,7 @@ const saveConfig = async () => {
}
}
// 显示路由分支节点配置, 由父组件传过来
// 显示路由分支节点配置, 由父组件传过来
const
showRouteNodeConfig
=
(
node
:
SimpleFlowNode
)
=>
{
const
showRouteNodeConfig
=
(
node
:
SimpleFlowNode
)
=>
{
getRout
able
Node
()
getRout
er
Node
()
routerGroups
.
value
=
[]
routerGroups
.
value
=
[]
nodeName
.
value
=
node
.
name
nodeName
.
value
=
node
.
name
if
(
node
.
routerGroups
)
{
if
(
node
.
routerGroups
)
{
...
@@ -132,7 +144,7 @@ const getShowText = () => {
...
@@ -132,7 +144,7 @@ const getShowText = () => {
return
`
${
routerGroups
.
value
.
length
}
条路由分支`
return
`
${
routerGroups
.
value
.
length
}
条路由分支`
}
}
const
addRouteGroup
=
()
=>
{
const
addRoute
r
Group
=
()
=>
{
routerGroups
.
value
.
push
({
routerGroups
.
value
.
push
({
nodeId
:
''
,
nodeId
:
''
,
conditionType
:
ConditionType
.
RULE
,
conditionType
:
ConditionType
.
RULE
,
...
@@ -144,8 +156,6 @@ const addRouteGroup = () => {
...
@@ -144,8 +156,6 @@ const addRouteGroup = () => {
and
:
true
,
and
:
true
,
rules
:
[
rules
:
[
{
{
type
:
1
,
opName
:
'等于'
,
opCode
:
'=='
,
opCode
:
'=='
,
leftSide
:
''
,
leftSide
:
''
,
rightSide
:
''
rightSide
:
''
...
@@ -157,12 +167,11 @@ const addRouteGroup = () => {
...
@@ -157,12 +167,11 @@ const addRouteGroup = () => {
})
})
}
}
const
deleteRouteGroup
=
(
index
:
number
)
=>
{
const
deleteRoute
r
Group
=
(
index
:
number
)
=>
{
routerGroups
.
value
.
splice
(
index
,
1
)
routerGroups
.
value
.
splice
(
index
,
1
)
}
}
// TODO @lesan:还有一些 router 的命名,没改过来呢
const
getRouterNode
=
()
=>
{
const
getRoutableNode
=
()
=>
{
// TODO @lesan 还需要满足以下要求
// TODO @lesan 还需要满足以下要求
// 并行分支、包容分支内部节点不能跳转到外部节点
// 并行分支、包容分支内部节点不能跳转到外部节点
// 条件分支节点可以向上跳转到外部节点
// 条件分支节点可以向上跳转到外部节点
...
@@ -170,7 +179,7 @@ const getRoutableNode = () => {
...
@@ -170,7 +179,7 @@ const getRoutableNode = () => {
nodeOptions
.
value
=
[]
nodeOptions
.
value
=
[]
while
(
true
)
{
while
(
true
)
{
if
(
!
node
)
break
if
(
!
node
)
break
if
(
node
.
type
!==
NodeType
.
ROUTE_BRANCH_NODE
)
{
if
(
node
.
type
!==
NodeType
.
ROUTE
R
_BRANCH_NODE
)
{
nodeOptions
.
value
.
push
({
nodeOptions
.
value
.
push
({
label
:
node
.
name
,
label
:
node
.
name
,
value
:
node
.
id
value
:
node
.
id
...
...
src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue
View file @
753e44cc
...
@@ -359,11 +359,7 @@
...
@@ -359,11 +359,7 @@
<el-divider
content-position=
"left"
>
是否需要签名
</el-divider>
<el-divider
content-position=
"left"
>
是否需要签名
</el-divider>
<el-form-item
prop=
"signEnable"
>
<el-form-item
prop=
"signEnable"
>
<el-switch
<el-switch
v-model=
"configForm.signEnable"
active-text=
"是"
inactive-text=
"否"
/>
v-model=
"configForm.signEnable"
active-text=
"是"
inactive-text=
"否"
/>
</el-form-item>
</el-form-item>
</el-form>
</el-form>
</div>
</div>
...
@@ -445,7 +441,7 @@
...
@@ -445,7 +441,7 @@
</div>
</div>
</el-tab-pane>
</el-tab-pane>
<el-tab-pane
label=
"监听器"
name=
"listener"
>
<el-tab-pane
label=
"监听器"
name=
"listener"
>
<el-form
:model=
"configForm"
label-position=
"top"
>
<el-form
ref=
"listenerFormRef"
:model=
"configForm"
label-position=
"top"
>
<div
v-for=
"(listener, listenerIdx) in taskListener"
:key=
"listenerIdx"
>
<div
v-for=
"(listener, listenerIdx) in taskListener"
:key=
"listenerIdx"
>
<el-divider
content-position=
"left"
>
<el-divider
content-position=
"left"
>
<el-text
tag=
"b"
size=
"large"
>
{{ listener.name }}
</el-text>
<el-text
tag=
"b"
size=
"large"
>
{{ listener.name }}
</el-text>
...
@@ -484,7 +480,16 @@
...
@@ -484,7 +480,16 @@
:key=
"index"
:key=
"index"
>
>
<div
class=
"mr-2"
>
<div
class=
"mr-2"
>
<el-form-item
:prop=
"`task${listener.type}ListenerHeader.${index}.key`"
:rules=
"{
required: true,
message: '参数名不能为空',
trigger: 'blur'
}"
>
<el-input
class=
"w-160px"
v-model=
"item.key"
/>
<el-input
class=
"w-160px"
v-model=
"item.key"
/>
</el-form-item>
</div>
</div>
<div
class=
"mr-2"
>
<div
class=
"mr-2"
>
<el-select
class=
"w-100px!"
v-model=
"item.type"
>
<el-select
class=
"w-100px!"
v-model=
"item.type"
>
...
@@ -497,11 +502,28 @@
...
@@ -497,11 +502,28 @@
</el-select>
</el-select>
</div>
</div>
<div
class=
"mr-2"
>
<div
class=
"mr-2"
>
<el-form-item
:prop=
"`task${listener.type}ListenerHeader.${index}.value`"
:rules=
"{
required: true,
message: '参数值不能为空',
trigger: 'blur'
}"
>
<el-input
<el-input
v-if=
"item.type === ListenerParamTypeEnum.FIXED_VALUE"
v-if=
"item.type === ListenerParamTypeEnum.FIXED_VALUE"
class=
"w-160px"
class=
"w-160px"
v-model=
"item.value"
v-model=
"item.value"
/>
/>
</el-form-item>
<el-form-item
:prop=
"`task${listener.type}ListenerHeader.${index}.value`"
:rules=
"{
required: true,
message: '参数值不能为空',
trigger: 'change'
}"
>
<el-select
<el-select
v-if=
"item.type === ListenerParamTypeEnum.FROM_FORM"
v-if=
"item.type === ListenerParamTypeEnum.FROM_FORM"
class=
"w-160px!"
class=
"w-160px!"
...
@@ -515,6 +537,7 @@
...
@@ -515,6 +537,7 @@
:disabled=
"!field.required"
:disabled=
"!field.required"
/>
/>
</el-select>
</el-select>
</el-form-item>
</div>
</div>
<div
class=
"mr-1 flex items-center"
>
<div
class=
"mr-1 flex items-center"
>
<Icon
<Icon
...
@@ -544,7 +567,16 @@
...
@@ -544,7 +567,16 @@
:key=
"index"
:key=
"index"
>
>
<div
class=
"mr-2"
>
<div
class=
"mr-2"
>
<el-form-item
:prop=
"`task${listener.type}ListenerBody.${index}.key`"
:rules=
"{
required: true,
message: '参数名不能为空',
trigger: 'blur'
}"
>
<el-input
class=
"w-160px"
v-model=
"item.key"
/>
<el-input
class=
"w-160px"
v-model=
"item.key"
/>
</el-form-item>
</div>
</div>
<div
class=
"mr-2"
>
<div
class=
"mr-2"
>
<el-select
class=
"w-100px!"
v-model=
"item.type"
>
<el-select
class=
"w-100px!"
v-model=
"item.type"
>
...
@@ -557,11 +589,28 @@
...
@@ -557,11 +589,28 @@
</el-select>
</el-select>
</div>
</div>
<div
class=
"mr-2"
>
<div
class=
"mr-2"
>
<el-form-item
:prop=
"`task${listener.type}ListenerBody.${index}.value`"
:rules=
"{
required: true,
message: '参数值不能为空',
trigger: 'blur'
}"
>
<el-input
<el-input
v-if=
"item.type === ListenerParamTypeEnum.FIXED_VALUE"
v-if=
"item.type === ListenerParamTypeEnum.FIXED_VALUE"
class=
"w-160px"
class=
"w-160px"
v-model=
"item.value"
v-model=
"item.value"
/>
/>
</el-form-item>
<el-form-item
:prop=
"`task${listener.type}ListenerBody.${index}.value`"
:rules=
"{
required: true,
message: '参数值不能为空',
trigger: 'change'
}"
>
<el-select
<el-select
v-if=
"item.type === ListenerParamTypeEnum.FROM_FORM"
v-if=
"item.type === ListenerParamTypeEnum.FROM_FORM"
class=
"w-160px!"
class=
"w-160px!"
...
@@ -575,6 +624,7 @@
...
@@ -575,6 +624,7 @@
:disabled=
"!field.required"
:disabled=
"!field.required"
/>
/>
</el-select>
</el-select>
</el-form-item>
</div>
</div>
<div
class=
"mr-1 flex items-center"
>
<div
class=
"mr-1 flex items-center"
>
<Icon
<Icon
...
@@ -792,6 +842,8 @@ const {
...
@@ -792,6 +842,8 @@ const {
cTimeoutMaxRemindCount
cTimeoutMaxRemindCount
}
=
useTimeoutHandler
()
}
=
useTimeoutHandler
()
const
listenerFormRef
=
ref
()
// 保存配置
// 保存配置
const
saveConfig
=
async
()
=>
{
const
saveConfig
=
async
()
=>
{
activeTabName
.
value
=
'user'
activeTabName
.
value
=
'user'
...
@@ -807,7 +859,8 @@ const saveConfig = async () => {
...
@@ -807,7 +859,8 @@ const saveConfig = async () => {
}
}
if
(
!
formRef
)
return
false
if
(
!
formRef
)
return
false
const
valid
=
await
formRef
.
value
.
validate
()
if
(
!
listenerFormRef
)
return
false
const
valid
=
(
await
formRef
.
value
.
validate
())
&&
(
await
listenerFormRef
.
value
.
validate
())
if
(
!
valid
)
return
false
if
(
!
valid
)
return
false
const
showText
=
getShowText
()
const
showText
=
getShowText
()
if
(
!
showText
)
return
false
if
(
!
showText
)
return
false
...
@@ -937,7 +990,7 @@ const showUserTaskNodeConfig = (node: SimpleFlowNode) => {
...
@@ -937,7 +990,7 @@ const showUserTaskNodeConfig = (node: SimpleFlowNode) => {
configForm
.
value
.
taskCompleteListenerHeader
=
node
.
taskCompleteListener
?.
header
??
[]
configForm
.
value
.
taskCompleteListenerHeader
=
node
.
taskCompleteListener
?.
header
??
[]
configForm
.
value
.
taskCompleteListenerBody
=
node
.
taskCompleteListener
?.
body
??
[]
configForm
.
value
.
taskCompleteListenerBody
=
node
.
taskCompleteListener
?.
body
??
[]
// 6. 签名
// 6. 签名
configForm
.
value
.
signEnable
=
node
.
signEnable
??
false
configForm
.
value
.
signEnable
=
node
?
.
signEnable
??
false
}
}
defineExpose
({
openDrawer
,
showUserTaskNodeConfig
})
// 暴露方法给父组件
defineExpose
({
openDrawer
,
showUserTaskNodeConfig
})
// 暴露方法给父组件
...
...
src/components/SimpleProcessDesignerV2/src/nodes-config/components/Condition.vue
View file @
753e44cc
<!-- TODO @lesan:其它路由条件,可以使用这个哇? -->
<
template
>
<
template
>
<el-form
ref=
"formRef"
:model=
"condition"
:rules=
"formRules"
label-position=
"top"
>
<el-form
ref=
"formRef"
:model=
"condition"
:rules=
"formRules"
label-position=
"top"
>
<!-- TODO @lesan:1)默认选中 条件规则;2)条件规则放前面,因为更常用!-->
<el-form-item
label=
"配置方式"
prop=
"conditionType"
>
<el-form-item
label=
"配置方式"
prop=
"conditionType"
>
<el-radio-group
v-model=
"condition.conditionType"
>
<el-radio-group
v-model=
"condition.conditionType"
>
<el-radio
<el-radio
...
@@ -14,18 +12,6 @@
...
@@ -14,18 +12,6 @@
</el-radio>
</el-radio>
</el-radio-group>
</el-radio-group>
</el-form-item>
</el-form-item>
<el-form-item
v-if=
"condition.conditionType === ConditionType.EXPRESSION"
label=
"条件表达式"
prop=
"conditionExpression"
>
<el-input
type=
"textarea"
v-model=
"condition.conditionExpression"
clearable
style=
"width: 100%"
/>
</el-form-item>
<el-form-item
v-if=
"condition.conditionType === ConditionType.RULE"
label=
"条件规则"
>
<el-form-item
v-if=
"condition.conditionType === ConditionType.RULE"
label=
"条件规则"
>
<div
class=
"condition-group-tool"
>
<div
class=
"condition-group-tool"
>
<div
class=
"flex items-center"
>
<div
class=
"flex items-center"
>
...
@@ -73,6 +59,14 @@
...
@@ -73,6 +59,14 @@
<div
class=
"flex pt-2"
v-for=
"(rule, rIdx) in equation.rules"
:key=
"rIdx"
>
<div
class=
"flex pt-2"
v-for=
"(rule, rIdx) in equation.rules"
:key=
"rIdx"
>
<div
class=
"mr-2"
>
<div
class=
"mr-2"
>
<el-form-item
:prop=
"`conditionGroups.conditions.${cIdx}.rules.${rIdx}.leftSide`"
:rules=
"{
required: true,
message: '左值不能为空',
trigger: 'change'
}"
>
<el-select
style=
"width: 160px"
v-model=
"rule.leftSide"
>
<el-select
style=
"width: 160px"
v-model=
"rule.leftSide"
>
<el-option
<el-option
v-for=
"(field, fIdx) in fieldOptions"
v-for=
"(field, fIdx) in fieldOptions"
...
@@ -82,6 +76,7 @@
...
@@ -82,6 +76,7 @@
:disabled=
"!field.required"
:disabled=
"!field.required"
/>
/>
</el-select>
</el-select>
</el-form-item>
</div>
</div>
<div
class=
"mr-2"
>
<div
class=
"mr-2"
>
<el-select
v-model=
"rule.opCode"
style=
"width: 100px"
>
<el-select
v-model=
"rule.opCode"
style=
"width: 100px"
>
...
@@ -94,7 +89,16 @@
...
@@ -94,7 +89,16 @@
</el-select>
</el-select>
</div>
</div>
<div
class=
"mr-2"
>
<div
class=
"mr-2"
>
<el-form-item
:prop=
"`conditionGroups.conditions.${cIdx}.rules.${rIdx}.rightSide`"
:rules=
"{
required: true,
message: '右值不能为空',
trigger: 'blur'
}"
>
<el-input
v-model=
"rule.rightSide"
style=
"width: 160px"
/>
<el-input
v-model=
"rule.rightSide"
style=
"width: 160px"
/>
</el-form-item>
</div>
</div>
<div
class=
"mr-1 flex items-center"
v-if=
"equation.rules.length > 1"
>
<div
class=
"mr-1 flex items-center"
v-if=
"equation.rules.length > 1"
>
<Icon
icon=
"ep:delete"
:size=
"18"
@
click=
"deleteConditionRule(equation, rIdx)"
/>
<Icon
icon=
"ep:delete"
:size=
"18"
@
click=
"deleteConditionRule(equation, rIdx)"
/>
...
@@ -114,13 +118,25 @@
...
@@ -114,13 +118,25 @@
/>
/>
</div>
</div>
</el-form-item>
</el-form-item>
<el-form-item
v-if=
"condition.conditionType === ConditionType.EXPRESSION"
label=
"条件表达式"
prop=
"conditionExpression"
>
<el-input
type=
"textarea"
v-model=
"condition.conditionExpression"
clearable
style=
"width: 100%"
/>
</el-form-item>
</el-form>
</el-form>
</template>
</template>
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
import
{
CONDITION_CONFIG_TYPES
,
COMPARISON_OPERATORS
,
COMPARISON_OPERATORS
,
CONDITION_CONFIG_TYPES
,
ConditionType
,
ConditionType
,
ProcessVariableEnum
ProcessVariableEnum
}
from
'../../consts'
}
from
'../../consts'
...
@@ -181,8 +197,6 @@ const deleteConditionRule = (condition, index) => {
...
@@ -181,8 +197,6 @@ const deleteConditionRule = (condition, index) => {
const
addConditionRule
=
(
condition
,
index
)
=>
{
const
addConditionRule
=
(
condition
,
index
)
=>
{
const
rule
=
{
const
rule
=
{
type
:
1
,
opName
:
'等于'
,
opCode
:
'=='
,
opCode
:
'=='
,
leftSide
:
''
,
leftSide
:
''
,
rightSide
:
''
rightSide
:
''
...
@@ -195,8 +209,6 @@ const addConditionGroup = (conditions) => {
...
@@ -195,8 +209,6 @@ const addConditionGroup = (conditions) => {
and
:
true
,
and
:
true
,
rules
:
[
rules
:
[
{
{
type
:
1
,
// TODO @lesan:枚举~
opName
:
'等于'
,
opCode
:
'=='
,
opCode
:
'=='
,
leftSide
:
''
,
leftSide
:
''
,
rightSide
:
''
rightSide
:
''
...
@@ -205,6 +217,13 @@ const addConditionGroup = (conditions) => {
...
@@ -205,6 +217,13 @@ const addConditionGroup = (conditions) => {
}
}
conditions
.
push
(
condition
)
conditions
.
push
(
condition
)
}
}
const
validate
=
async
()
=>
{
if
(
!
formRef
)
return
false
return
await
formRef
.
value
.
validate
()
}
defineExpose
({
validate
})
</
script
>
</
script
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
...
...
src/components/SimpleProcessDesignerV2/src/nodes/RouteNode.vue
→
src/components/SimpleProcessDesignerV2/src/nodes/Route
r
Node.vue
View file @
753e44cc
...
@@ -31,7 +31,7 @@
...
@@ -31,7 +31,7 @@
{{
currentNode
.
showText
}}
{{
currentNode
.
showText
}}
</div>
</div>
<div
class=
"node-text"
v-else
>
<div
class=
"node-text"
v-else
>
{{
NODE_DEFAULT_TEXT
.
get
(
NodeType
.
ROUTE_BRANCH_NODE
)
}}
{{
NODE_DEFAULT_TEXT
.
get
(
NodeType
.
ROUTE
R
_BRANCH_NODE
)
}}
</div>
</div>
<Icon
v-if=
"!readonly"
icon=
"ep:arrow-right-bold"
/>
<Icon
v-if=
"!readonly"
icon=
"ep:arrow-right-bold"
/>
</div>
</div>
...
@@ -49,17 +49,17 @@
...
@@ -49,17 +49,17 @@
:current-node=
"currentNode"
:current-node=
"currentNode"
/>
/>
</div>
</div>
<RouteNodeConfig
v-if=
"!readonly && currentNode"
ref=
"nodeSetting"
:flow-node=
"currentNode"
/>
<Route
r
NodeConfig
v-if=
"!readonly && currentNode"
ref=
"nodeSetting"
:flow-node=
"currentNode"
/>
</div>
</div>
</
template
>
</
template
>
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
SimpleFlowNode
,
NodeType
,
NODE_DEFAULT_TEXT
}
from
'../consts'
import
{
SimpleFlowNode
,
NodeType
,
NODE_DEFAULT_TEXT
}
from
'../consts'
import
NodeHandler
from
'../NodeHandler.vue'
import
NodeHandler
from
'../NodeHandler.vue'
import
{
useNodeName2
,
useWatchNode
,
useTaskStatusClass
}
from
'../node'
import
{
useNodeName2
,
useWatchNode
,
useTaskStatusClass
}
from
'../node'
import
Route
NodeConfig
from
'../nodes-config/Route
NodeConfig.vue'
import
Route
rNodeConfig
from
'../nodes-config/Router
NodeConfig.vue'
defineOptions
({
defineOptions
({
name
:
'RouteNode'
name
:
'Route
r
Node'
})
})
const
props
=
defineProps
({
const
props
=
defineProps
({
...
@@ -77,7 +77,7 @@ const readonly = inject<Boolean>('readonly')
...
@@ -77,7 +77,7 @@ const readonly = inject<Boolean>('readonly')
// 监控节点的变化
// 监控节点的变化
const
currentNode
=
useWatchNode
(
props
)
const
currentNode
=
useWatchNode
(
props
)
// 节点名称编辑
// 节点名称编辑
const
{
showInput
,
blurEvent
,
clickTitle
}
=
useNodeName2
(
currentNode
,
NodeType
.
ROUTE_BRANCH_NODE
)
const
{
showInput
,
blurEvent
,
clickTitle
}
=
useNodeName2
(
currentNode
,
NodeType
.
ROUTE
R
_BRANCH_NODE
)
const
nodeSetting
=
ref
()
const
nodeSetting
=
ref
()
// 打开节点配置
// 打开节点配置
...
...
src/views/bpm/processInstance/detail/ProcessInstanceOperationButton.vue
View file @
753e44cc
...
@@ -44,6 +44,12 @@
...
@@ -44,6 +44,12 @@
:rows=
"4"
:rows=
"4"
/>
/>
</el-form-item>
</el-form-item>
<el-form-item
v-if=
"runningTask.signEnable"
label=
"签名"
prop=
"sign"
ref=
"approveSignFormRef"
>
<el-button
@
click=
"signRef.open()"
>
点击签名
</el-button>
<el-image
class=
"w-90px h-40px ml-5px"
v-if=
"approveReasonForm.sign"
:src=
"approveReasonForm.sign"
:preview-src-list=
"[approveReasonForm.sign]"
/>
</el-form-item>
<el-form-item>
<el-form-item>
<el-button
:disabled=
"formLoading"
type=
"success"
@
click=
"handleAudit(true, approveFormRef)"
>
<el-button
:disabled=
"formLoading"
type=
"success"
@
click=
"handleAudit(true, approveFormRef)"
>
{{ getButtonDisplayName(OperationButtonType.APPROVE) }}
{{ getButtonDisplayName(OperationButtonType.APPROVE) }}
...
@@ -471,6 +477,8 @@
...
@@ -471,6 +477,8 @@
<Icon
:size=
"14"
icon=
"ep:refresh"
/>
再次提交
<Icon
:size=
"14"
icon=
"ep:refresh"
/>
再次提交
</div>
</div>
</div>
</div>
<SignDialog
ref=
"signRef"
@
success=
"handleSignFinish"
/>
</template>
</template>
<
script
lang=
"ts"
setup
>
<
script
lang=
"ts"
setup
>
import
{
useUserStoreWithOut
}
from
'@/store/modules/user'
import
{
useUserStoreWithOut
}
from
'@/store/modules/user'
...
@@ -484,6 +492,7 @@ import {
...
@@ -484,6 +492,7 @@ import {
}
from
'@/components/SimpleProcessDesignerV2/src/consts'
}
from
'@/components/SimpleProcessDesignerV2/src/consts'
import
{
BpmProcessInstanceStatus
,
BpmModelFormType
}
from
'@/utils/constants'
import
{
BpmProcessInstanceStatus
,
BpmModelFormType
}
from
'@/utils/constants'
import
type
{
FormInstance
,
FormRules
}
from
'element-plus'
import
type
{
FormInstance
,
FormRules
}
from
'element-plus'
import
SignDialog
from
"./SignDialog.vue"
;
defineOptions
({
name
:
'ProcessInstanceBtnContainer'
})
defineOptions
({
name
:
'ProcessInstanceBtnContainer'
})
const
router
=
useRouter
()
// 路由
const
router
=
useRouter
()
// 路由
...
@@ -522,11 +531,15 @@ const approveFormFApi = ref<any>({}) // approveForms 的 fAPi
...
@@ -522,11 +531,15 @@ const approveFormFApi = ref<any>({}) // approveForms 的 fAPi
// 审批通过意见表单
// 审批通过意见表单
const
approveFormRef
=
ref
<
FormInstance
>
()
const
approveFormRef
=
ref
<
FormInstance
>
()
const
signRef
=
ref
()
const
approveSignFormRef
=
ref
()
const
approveReasonForm
=
reactive
({
const
approveReasonForm
=
reactive
({
reason
:
''
reason
:
''
,
sign
:
''
})
})
const
approveReasonRule
=
reactive
<
FormRules
<
typeof
approveReasonForm
>>
({
const
approveReasonRule
=
reactive
<
FormRules
<
typeof
approveReasonForm
>>
({
reason
:
[{
required
:
true
,
message
:
'审批意见不能为空'
,
trigger
:
'blur'
}],
reason
:
[{
required
:
true
,
message
:
'审批意见不能为空'
,
trigger
:
'blur'
}],
sign
:
[{
required
:
true
,
message
:
'签名不能为空'
,
trigger
:
'change'
}]
})
})
// 拒绝表单
// 拒绝表单
const
rejectFormRef
=
ref
<
FormInstance
>
()
const
rejectFormRef
=
ref
<
FormInstance
>
()
...
@@ -672,6 +685,10 @@ const handleAudit = async (pass: boolean, formRef: FormInstance | undefined) =>
...
@@ -672,6 +685,10 @@ const handleAudit = async (pass: boolean, formRef: FormInstance | undefined) =>
reason
:
approveReasonForm
.
reason
,
reason
:
approveReasonForm
.
reason
,
variables
// 审批通过, 把修改的字段值赋于流程实例变量
variables
// 审批通过, 把修改的字段值赋于流程实例变量
}
}
// 签名
if
(
runningTask
.
value
.
signEnable
)
{
data
.
sign
=
approveReasonForm
.
sign
}
// 多表单处理,并且有额外的 approveForm 表单,需要校验 + 拼接到 data 表单里提交
// 多表单处理,并且有额外的 approveForm 表单,需要校验 + 拼接到 data 表单里提交
// TODO 芋艿 任务有多表单这里要如何处理,会和可编辑的字段冲突
// TODO 芋艿 任务有多表单这里要如何处理,会和可编辑的字段冲突
const
formCreateApi
=
approveFormFApi
.
value
const
formCreateApi
=
approveFormFApi
.
value
...
@@ -966,6 +983,11 @@ const getUpdatedProcessInstanceVaiables = ()=> {
...
@@ -966,6 +983,11 @@ const getUpdatedProcessInstanceVaiables = ()=> {
return
variables
return
variables
}
}
const
handleSignFinish
=
(
url
)
=>
{
approveReasonForm
.
sign
=
url
approveSignFormRef
.
value
.
validate
(
'change'
)
}
defineExpose
({
loadTodoTask
})
defineExpose
({
loadTodoTask
})
</
script
>
</
script
>
...
...
src/views/bpm/processInstance/detail/ProcessInstanceSimpleViewer.vue
View file @
753e44cc
...
@@ -128,7 +128,7 @@ const setSimpleModelNodeTaskStatus = (
...
@@ -128,7 +128,7 @@ const setSimpleModelNodeTaskStatus = (
simpleModel
.
type
===
NodeType
.
CONDITION_BRANCH_NODE
||
simpleModel
.
type
===
NodeType
.
CONDITION_BRANCH_NODE
||
simpleModel
.
type
===
NodeType
.
PARALLEL_BRANCH_NODE
||
simpleModel
.
type
===
NodeType
.
PARALLEL_BRANCH_NODE
||
simpleModel
.
type
===
NodeType
.
INCLUSIVE_BRANCH_NODE
||
simpleModel
.
type
===
NodeType
.
INCLUSIVE_BRANCH_NODE
||
simpleModel
.
type
===
NodeType
.
ROUTE_BRANCH_NODE
simpleModel
.
type
===
NodeType
.
ROUTE
R
_BRANCH_NODE
)
{
)
{
// 网关节点。只有通过和未执行状态
// 网关节点。只有通过和未执行状态
if
(
finishedActivityIds
.
includes
(
simpleModel
.
id
))
{
if
(
finishedActivityIds
.
includes
(
simpleModel
.
id
))
{
...
...
src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue
View file @
753e44cc
...
@@ -123,6 +123,15 @@
...
@@ -123,6 +123,15 @@
>
>
审批意见:{{ task.reason }}
审批意见:{{ task.reason }}
</div>
</div>
<div
v-if=
"task.sign && activity.nodeType === NodeType.USER_TASK_NODE"
class=
"text-#a5a5a5 text-13px mt-1 w-full bg-#f8f8fa p2 rounded-md"
>
签名:
<el-image
class=
"w-90px h-40px ml-5px"
:src=
"task.sign"
:preview-src-list=
"[task.sign]"
/>
</div>
</teleport>
</teleport>
</div>
</div>
<!-- 情况二:遍历每个审批节点下的【候选的】task 任务。例如说,1)依次审批,2)未来的审批任务等 -->
<!-- 情况二:遍历每个审批节点下的【候选的】task 任务。例如说,1)依次审批,2)未来的审批任务等 -->
...
...
src/views/bpm/processInstance/detail/SignDialog.vue
0 → 100644
View file @
753e44cc
<
template
>
<el-dialog
v-model=
"signDialogVisible"
title=
"签名"
width=
"935"
>
<div
class=
"position-relative"
>
<Vue3Signature
class=
"b b-solid b-gray"
ref=
"signature"
w=
"900px"
h=
"400px"
/>
<el-button
style=
"position: absolute; bottom: 20px; right: 10px"
type=
"primary"
text
size=
"small"
@
click=
"signature.clear()"
>
<Icon
icon=
"ep:delete"
class=
"mr-5px"
/>
清除
</el-button>
</div>
<template
#
footer
>
<div
class=
"dialog-footer"
>
<el-button
@
click=
"signDialogVisible = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"submit"
>
提交
</el-button>
</div>
</
template
>
</el-dialog>
</template>
<
script
setup
lang=
"ts"
>
import
Vue3Signature
from
"vue3-signature"
import
*
as
FileApi
from
'@/api/infra/file'
const
message
=
useMessage
()
// 消息弹窗
const
signDialogVisible
=
ref
(
false
)
const
signature
=
ref
()
const
open
=
async
()
=>
{
signDialogVisible
.
value
=
true
}
defineExpose
({
open
})
const
emits
=
defineEmits
([
'success'
])
const
submit
=
async
()
=>
{
message
.
success
(
'签名上传中请稍等。。。'
)
const
res
=
await
FileApi
.
updateFile
({
file
:
base64ToFile
(
signature
.
value
.
save
(
'image/png'
),
'签名'
)})
emits
(
'success'
,
res
.
data
)
signDialogVisible
.
value
=
false
}
const
base64ToFile
=
(
base64
,
fileName
)
=>
{
// 将base64按照 , 进行分割 将前缀 与后续内容分隔开
let
data
=
base64
.
split
(
','
);
// 利用正则表达式 从前缀中获取图片的类型信息(image/png、image/jpeg、image/webp等)
let
type
=
data
[
0
].
match
(
/:
(
.*
?)
;/
)[
1
];
// 从图片的类型信息中 获取具体的文件格式后缀(png、jpeg、webp)
let
suffix
=
type
.
split
(
'/'
)[
1
];
// 使用atob()对base64数据进行解码 结果是一个文件数据流 以字符串的格式输出
const
bstr
=
window
.
atob
(
data
[
1
]);
// 获取解码结果字符串的长度
let
n
=
bstr
.
length
// 根据解码结果字符串的长度创建一个等长的整形数字数组
// 但在创建时 所有元素初始值都为 0
const
u8arr
=
new
Uint8Array
(
n
)
// 将整形数组的每个元素填充为解码结果字符串对应位置字符的UTF-16 编码单元
while
(
n
--
)
{
// charCodeAt():获取给定索引处字符对应的 UTF-16 代码单元
u8arr
[
n
]
=
bstr
.
charCodeAt
(
n
)
}
// 利用构造函数创建File文件对象
// new File(bits, name, options)
const
file
=
new
File
([
u8arr
],
`
${
fileName
}
.
${
suffix
}
`
,
{
type
:
type
})
// 将File文件对象返回给方法的调用者
return
file
;
}
</
script
>
<
style
scoped
>
</
style
>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment