!117 Merge remote-tracking branch 'yudao/dev' into dev
Merge pull request !117 from Jason/devpull/118/head
						commit
						77ccb9a5d8
					
				|  | @ -12,10 +12,11 @@ import { useVbenDrawer } from '@vben/common-ui'; | |||
| import { IconifyIcon } from '@vben/icons'; | ||||
| 
 | ||||
| import { | ||||
|   Divider, | ||||
|   Col, | ||||
|   Input, | ||||
|   Radio, | ||||
|   RadioGroup, | ||||
|   Row, | ||||
|   TabPane, | ||||
|   Tabs, | ||||
|   Tooltip, | ||||
|  | @ -91,8 +92,8 @@ const getDeptNames = (deptIds: number[]): string => { | |||
| 
 | ||||
| // 使用 VbenDrawer | ||||
| const [Drawer, drawerApi] = useVbenDrawer({ | ||||
|   header: false, | ||||
|   closable: false, | ||||
|   header: true, | ||||
|   closable: true, | ||||
|   onCancel() { | ||||
|     drawerApi.close(); | ||||
|   }, | ||||
|  | @ -142,6 +143,7 @@ defineExpose({ showStartUserNodeConfig }); | |||
| </script> | ||||
| <template> | ||||
|   <Drawer> | ||||
|     <template #title> | ||||
|       <div class="config-header"> | ||||
|         <!--    TODO v-mountedFocus 自动聚集 需要迁移一下 --> | ||||
|         <Input | ||||
|  | @ -161,9 +163,8 @@ defineExpose({ showStartUserNodeConfig }); | |||
|             @click="clickIcon()" | ||||
|           /> | ||||
|         </div> | ||||
|       <Divider /> | ||||
|       </div> | ||||
| 
 | ||||
|     </template> | ||||
|     <Tabs v-model:active-key="activeTabName" type="card"> | ||||
|       <TabPane tab="权限" key="user"> | ||||
|         <TypographyText | ||||
|  | @ -212,69 +213,76 @@ defineExpose({ showStartUserNodeConfig }); | |||
|         key="fields" | ||||
|         v-if="formType === BpmModelFormType.NORMAL" | ||||
|       > | ||||
|         <div class="field-setting-pane"> | ||||
|           <div class="field-setting-desc">字段权限</div> | ||||
|           <div class="field-permit-title"> | ||||
|             <div class="setting-title-label first-title">字段名称</div> | ||||
|             <div class="other-titles"> | ||||
|         <div class="p-1"> | ||||
|           <div class="mb-4 text-[16px] font-bold">字段权限</div> | ||||
| 
 | ||||
|           <!-- 表头 --> | ||||
|           <Row class="border border-gray-200 px-4 py-3"> | ||||
|             <Col :span="8" class="font-bold">字段名称</Col> | ||||
|             <Col :span="16"> | ||||
|               <Row> | ||||
|                 <Col :span="8" class="flex items-center justify-center"> | ||||
|                   <span | ||||
|                 class="setting-title-label cursor-pointer" | ||||
|                     class="cursor-pointer font-bold" | ||||
|                     @click="updatePermission('READ')" | ||||
|                   > | ||||
|                     只读 | ||||
|                   </span> | ||||
|                 </Col> | ||||
|                 <Col :span="8" class="flex items-center justify-center"> | ||||
|                   <span | ||||
|                 class="setting-title-label cursor-pointer" | ||||
|                     class="cursor-pointer font-bold" | ||||
|                     @click="updatePermission('WRITE')" | ||||
|                   > | ||||
|                     可编辑 | ||||
|                   </span> | ||||
|                 </Col> | ||||
|                 <Col :span="8" class="flex items-center justify-center"> | ||||
|                   <span | ||||
|                 class="setting-title-label cursor-pointer" | ||||
|                     class="cursor-pointer font-bold" | ||||
|                     @click="updatePermission('NONE')" | ||||
|                   > | ||||
|                     隐藏 | ||||
|                   </span> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div | ||||
|             class="field-setting-item" | ||||
|             v-for="(item, index) in fieldsPermissionConfig" | ||||
|             :key="index" | ||||
|           > | ||||
|             <div class="field-setting-item-label">{{ item.title }}</div> | ||||
|             <RadioGroup | ||||
|               class="field-setting-item-group" | ||||
|               v-model:value="item.permission" | ||||
|             > | ||||
|               <div class="item-radio-wrap"> | ||||
|                 </Col> | ||||
|               </Row> | ||||
|             </Col> | ||||
|           </Row> | ||||
| 
 | ||||
|           <!-- 表格内容 --> | ||||
|           <div v-for="(item, index) in fieldsPermissionConfig" :key="index"> | ||||
|             <Row class="border border-t-0 border-gray-200 px-4 py-2"> | ||||
|               <Col :span="8" class="flex items-center truncate"> | ||||
|                 {{ item.title }} | ||||
|               </Col> | ||||
|               <Col :span="16"> | ||||
|                 <RadioGroup v-model:value="item.permission" class="w-full"> | ||||
|                   <Row> | ||||
|                     <Col :span="8" class="flex items-center justify-center"> | ||||
|                       <Radio | ||||
|                         :value="FieldPermissionType.READ" | ||||
|                         size="large" | ||||
|                         :label="FieldPermissionType.READ" | ||||
|                 > | ||||
|                   <span></span> | ||||
|                 </Radio> | ||||
|               </div> | ||||
|               <div class="item-radio-wrap"> | ||||
|                       /> | ||||
|                     </Col> | ||||
|                     <Col :span="8" class="flex items-center justify-center"> | ||||
|                       <Radio | ||||
|                         :value="FieldPermissionType.WRITE" | ||||
|                         size="large" | ||||
|                         :label="FieldPermissionType.WRITE" | ||||
|                 > | ||||
|                   <span></span> | ||||
|                 </Radio> | ||||
|               </div> | ||||
|               <div class="item-radio-wrap"> | ||||
|                       /> | ||||
|                     </Col> | ||||
|                     <Col :span="8" class="flex items-center justify-center"> | ||||
|                       <Radio | ||||
|                         :value="FieldPermissionType.NONE" | ||||
|                         size="large" | ||||
|                         :label="FieldPermissionType.NONE" | ||||
|                 > | ||||
|                   <span></span> | ||||
|                 </Radio> | ||||
|               </div> | ||||
|                       /> | ||||
|                     </Col> | ||||
|                   </Row> | ||||
|                 </RadioGroup> | ||||
|               </Col> | ||||
|             </Row> | ||||
|           </div> | ||||
|         </div> | ||||
|       </TabPane> | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,48 @@ | |||
| import { APPROVE_TYPE, ApproveType, TimeUnitType } from '../../consts'; | ||||
| 
 | ||||
| /** 获取条件节点默认的名称 */ | ||||
| export const getDefaultConditionNodeName = ( | ||||
|   index: number, | ||||
|   defaultFlow: boolean | undefined, | ||||
| ): string => { | ||||
|   if (defaultFlow) { | ||||
|     return '其它情况'; | ||||
|   } | ||||
|   return `条件${index + 1}`; | ||||
| }; | ||||
| 
 | ||||
| /** 获取包容分支条件节点默认的名称 */ | ||||
| export const getDefaultInclusiveConditionNodeName = ( | ||||
|   index: number, | ||||
|   defaultFlow: boolean | undefined, | ||||
| ): string => { | ||||
|   if (defaultFlow) { | ||||
|     return '其它情况'; | ||||
|   } | ||||
|   return `包容条件${index + 1}`; | ||||
| }; | ||||
| 
 | ||||
| /** 转换时间单位字符串为枚举值 */ | ||||
| export const convertTimeUnit = (strTimeUnit: string) => { | ||||
|   if (strTimeUnit === 'M') { | ||||
|     return TimeUnitType.MINUTE; | ||||
|   } | ||||
|   if (strTimeUnit === 'H') { | ||||
|     return TimeUnitType.HOUR; | ||||
|   } | ||||
|   if (strTimeUnit === 'D') { | ||||
|     return TimeUnitType.DAY; | ||||
|   } | ||||
|   return TimeUnitType.HOUR; | ||||
| }; | ||||
| 
 | ||||
| /** 根据审批类型获取对应的文本描述 */ | ||||
| export const getApproveTypeText = (approveType: ApproveType): string => { | ||||
|   let approveTypeText = ''; | ||||
|   APPROVE_TYPE.forEach((item) => { | ||||
|     if (item.value === approveType) { | ||||
|       approveTypeText = item.label; | ||||
|     } | ||||
|   }); | ||||
|   return approveTypeText; | ||||
| }; | ||||
|  | @ -0,0 +1,138 @@ | |||
| <script setup lang="ts"> | ||||
| import type { Ref } from 'vue'; | ||||
| 
 | ||||
| import type { SimpleFlowNode } from '../../consts'; | ||||
| 
 | ||||
| import { inject, ref } from 'vue'; | ||||
| 
 | ||||
| import { IconifyIcon } from '@vben/icons'; | ||||
| 
 | ||||
| import { Input } from 'ant-design-vue'; | ||||
| 
 | ||||
| import { NODE_DEFAULT_TEXT, NodeType } from '../../consts'; | ||||
| import { useNodeName2, useTaskStatusClass, useWatchNode } from '../../helpers'; | ||||
| import UserTaskNodeConfig from '../nodes-config/user-task-node-config.vue'; | ||||
| import NodeHandler from './node-handler.vue'; | ||||
| 
 | ||||
| defineOptions({ name: 'UserTaskNode' }); | ||||
| 
 | ||||
| const props = defineProps({ | ||||
|   flowNode: { | ||||
|     type: Object as () => SimpleFlowNode, | ||||
|     required: true, | ||||
|   }, | ||||
| }); | ||||
| const emits = defineEmits<{ | ||||
|   findParentNode: [nodeList: SimpleFlowNode[], nodeType: NodeType]; | ||||
|   'update:flowNode': [node: SimpleFlowNode | undefined]; | ||||
| }>(); | ||||
| 
 | ||||
| // 是否只读 | ||||
| const readonly = inject<Boolean>('readonly'); | ||||
| const tasks = inject<Ref<any[]>>('tasks', ref([])); | ||||
| // 监控节点变化 | ||||
| const currentNode = useWatchNode(props); | ||||
| // 节点名称编辑 | ||||
| const { showInput, blurEvent, clickTitle } = useNodeName2( | ||||
|   currentNode, | ||||
|   NodeType.START_USER_NODE, | ||||
| ); | ||||
| const nodeSetting = ref(); | ||||
| 
 | ||||
| const nodeClick = () => { | ||||
|   if (readonly) { | ||||
|     if (tasks && tasks.value) { | ||||
|       // 只读模式,弹窗显示任务信息 TODO 待实现 | ||||
|       console.warn('只读模式,弹窗显示任务信息待实现'); | ||||
|     } | ||||
|   } else { | ||||
|     // 编辑模式,打开节点配置、把当前节点传递给配置组件 | ||||
|     nodeSetting.value.showUserTaskNodeConfig(currentNode.value); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| const deleteNode = () => { | ||||
|   emits('update:flowNode', currentNode.value.childNode); | ||||
| }; | ||||
| // 查找可以驳回用户节点 | ||||
| const findReturnTaskNodes = ( | ||||
|   matchNodeList: SimpleFlowNode[], // 匹配的节点 | ||||
| ) => { | ||||
|   // 从父节点查找 | ||||
|   emits('findParentNode', matchNodeList, NodeType.USER_TASK_NODE); | ||||
| }; | ||||
| 
 | ||||
| // const selectTasks = ref<any[] | undefined>([]); // 选中的任务数组 | ||||
| </script> | ||||
| <template> | ||||
|   <div class="node-wrapper"> | ||||
|     <div class="node-container"> | ||||
|       <div | ||||
|         class="node-box" | ||||
|         :class="[ | ||||
|           { 'node-config-error': !currentNode.showText }, | ||||
|           `${useTaskStatusClass(currentNode?.activityStatus)}`, | ||||
|         ]" | ||||
|       > | ||||
|         <div class="node-title-container"> | ||||
|           <div | ||||
|             :class="`node-title-icon ${currentNode.type === NodeType.TRANSACTOR_NODE ? 'transactor-task' : 'user-task'}`" | ||||
|           > | ||||
|             <span | ||||
|               :class="`iconfont ${currentNode.type === NodeType.TRANSACTOR_NODE ? 'icon-transactor' : 'icon-approve'}`" | ||||
|             > | ||||
|             </span> | ||||
|           </div> | ||||
|           <Input | ||||
|             v-if="!readonly && showInput" | ||||
|             type="text" | ||||
|             class="editable-title-input" | ||||
|             @blur="blurEvent()" | ||||
|             v-model="currentNode.name" | ||||
|             :placeholder="currentNode.name" | ||||
|           /> | ||||
|           <div v-else class="node-title" @click="clickTitle"> | ||||
|             {{ currentNode.name }} | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="node-content" @click="nodeClick"> | ||||
|           <div | ||||
|             class="node-text" | ||||
|             :title="currentNode.showText" | ||||
|             v-if="currentNode.showText" | ||||
|           > | ||||
|             {{ currentNode.showText }} | ||||
|           </div> | ||||
|           <div class="node-text" v-else> | ||||
|             {{ NODE_DEFAULT_TEXT.get(currentNode.type) }} | ||||
|           </div> | ||||
|           <IconifyIcon icon="ep:arrow-right-bold" v-if="!readonly" /> | ||||
|         </div> | ||||
|         <div v-if="!readonly" class="node-toolbar"> | ||||
|           <div class="toolbar-icon"> | ||||
|             <IconifyIcon | ||||
|               color="#0089ff" | ||||
|               icon="ep:circle-close-filled" | ||||
|               :size="18" | ||||
|               @click="deleteNode" | ||||
|             /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <!-- 传递子节点给添加节点组件。会在子节点前面添加节点 --> | ||||
|       <NodeHandler | ||||
|         v-if="currentNode" | ||||
|         v-model:child-node="currentNode.childNode" | ||||
|         :current-node="currentNode" | ||||
|       /> | ||||
|     </div> | ||||
|   </div> | ||||
|   <UserTaskNodeConfig | ||||
|     v-if="currentNode" | ||||
|     ref="nodeSetting" | ||||
|     :flow-node="currentNode" | ||||
|     @find-return-task-nodes="findReturnTaskNodes" | ||||
|   /> | ||||
|   <!--  TODO 审批记录 --> | ||||
| </template> | ||||
| <style lang="scss" scoped></style> | ||||
|  | @ -5,6 +5,7 @@ import { NodeType } from '../consts'; | |||
| import { useWatchNode } from '../helpers'; | ||||
| import EndEventNode from './nodes/end-event-node.vue'; | ||||
| import StartUserNode from './nodes/start-user-node.vue'; | ||||
| import UserTaskNode from './nodes/user-task-node.vue'; | ||||
| 
 | ||||
| defineOptions({ name: 'ProcessNodeTree' }); | ||||
| const props = defineProps({ | ||||
|  | @ -29,16 +30,12 @@ const emits = defineEmits<{ | |||
| const currentNode = useWatchNode(props); | ||||
| 
 | ||||
| // 用于删除节点 | ||||
| // eslint-disable-next-line unused-imports/no-unused-vars, no-unused-vars | ||||
| 
 | ||||
| const handleModelValueUpdate = (updateValue: any) => { | ||||
|   emits('update:flowNode', updateValue); | ||||
| }; | ||||
| 
 | ||||
| // eslint-disable-next-line unused-imports/no-unused-vars, no-unused-vars | ||||
| const triggerFromParentNode = ( | ||||
|   nodeList: SimpleFlowNode[], | ||||
|   nodeType: number, | ||||
| ) => { | ||||
| const findParentNode = (nodeList: SimpleFlowNode[], nodeType: number) => { | ||||
|   emits('recursiveFindParentNode', nodeList, props.parentNode, nodeType); | ||||
| }; | ||||
| 
 | ||||
|  | @ -69,7 +66,7 @@ const recursiveFindParentNode = ( | |||
|     :flow-node="currentNode" | ||||
|   /> | ||||
|   <!-- 审批节点 --> | ||||
|   <!-- <UserTaskNode | ||||
|   <UserTaskNode | ||||
|     v-if=" | ||||
|       currentNode && | ||||
|       (currentNode.type === NodeType.USER_TASK_NODE || | ||||
|  | @ -77,8 +74,8 @@ const recursiveFindParentNode = ( | |||
|     " | ||||
|     :flow-node="currentNode" | ||||
|     @update:flow-node="handleModelValueUpdate" | ||||
|     @find:parent-node="findFromParentNode" | ||||
|   /> --> | ||||
|     @find-parent-node="findParentNode" | ||||
|   /> | ||||
|   <!-- 抄送节点 --> | ||||
|   <!-- <CopyTaskNode | ||||
|     v-if="currentNode && currentNode.type === NodeType.COPY_TASK_NODE" | ||||
|  |  | |||
|  | @ -44,82 +44,6 @@ | |||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // 表单字段权限 | ||||
| .field-setting-pane { | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   font-size: 14px; | ||||
| 
 | ||||
|   .field-setting-desc { | ||||
|     padding-right: 8px; | ||||
|     margin-bottom: 16px; | ||||
|     font-size: 16px; | ||||
|     font-weight: 700; | ||||
|   } | ||||
| 
 | ||||
|   .field-permit-title { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
|     height: 45px; | ||||
|     padding-left: 12px; | ||||
|     line-height: 45px; | ||||
|     background-color: #f8fafc0a; | ||||
|     border: 1px solid #1f38581a; | ||||
| 
 | ||||
|     .first-title { | ||||
|       text-align: left !important; | ||||
|     } | ||||
| 
 | ||||
|     .other-titles { | ||||
|       display: flex; | ||||
|       justify-content: space-between; | ||||
|     } | ||||
| 
 | ||||
|     .setting-title-label { | ||||
|       display: inline-block; | ||||
|       width: 110px; | ||||
|       padding: 5px 0; | ||||
|       font-size: 13px; | ||||
|       font-weight: 700; | ||||
|       color: #000; | ||||
|       text-align: center; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   .field-setting-item { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
|     height: 38px; | ||||
|     padding-left: 12px; | ||||
|     border: 1px solid #1f38581a; | ||||
|     border-top: 0; | ||||
| 
 | ||||
|     .field-setting-item-label { | ||||
|       display: inline-block; | ||||
|       width: 110px; | ||||
|       min-height: 16px; | ||||
|       overflow: hidden; | ||||
|       text-overflow: ellipsis; | ||||
|       white-space: nowrap; | ||||
|       cursor: text; | ||||
|     } | ||||
| 
 | ||||
|     .field-setting-item-group { | ||||
|       display: flex; | ||||
|       justify-content: space-between; | ||||
| 
 | ||||
|       .item-radio-wrap { | ||||
|         display: inline-block; | ||||
|         width: 110px; | ||||
|         text-align: center; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // 节点连线气泡卡片样式 | ||||
| .handler-item-wrapper { | ||||
|   display: flex; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 xingyu
						xingyu