From 6b988bd582bfcd17fee48c476a5a6e5cc172b0d5 Mon Sep 17 00:00:00 2001
From: baoshiwei <baoshiwei@shlanbao.cn>
Date: 星期三, 12 三月 2025 10:08:33 +0800
Subject: [PATCH] dev-2

---
 src/bpmn/panel/TaskPanel.vue |  491 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 491 insertions(+), 0 deletions(-)

diff --git a/src/bpmn/panel/TaskPanel.vue b/src/bpmn/panel/TaskPanel.vue
new file mode 100644
index 0000000..a42de8a
--- /dev/null
+++ b/src/bpmn/panel/TaskPanel.vue
@@ -0,0 +1,491 @@
+<template>
+  <div>
+    <el-form ref="formRef" size="default" :model="formData" :rules="formRules" label-width="100px">
+      <el-collapse v-model="currentCollapseItem">
+        <el-collapse-item name="1">
+          <template #title>
+            <div class="collapse__title">
+              <el-icon>
+                <InfoFilled />
+              </el-icon>
+              甯歌
+            </div>
+          </template>
+          <div>
+            <el-form-item prop="id" label="鑺傜偣 ID">
+              <el-input v-model="formData.id" @change="idChange"> </el-input>
+            </el-form-item>
+            <el-form-item prop="name" label="鑺傜偣鍚嶇О">
+              <el-input v-model="formData.name" @change="nameChange"> </el-input>
+            </el-form-item>
+            <el-form-item v-if="showConfig.skipExpression" prop="skipExpression" label="璺宠繃琛ㄨ揪寮�">
+              <el-input v-model="formData.skipExpression" @change="skipExpressionChange"> </el-input>
+            </el-form-item>
+            <el-form-item v-loading="formManageListLoading" prop="formKey" label="琛ㄥ崟鍦板潃">
+              <el-select v-model="formData.formKey" clearable filterable placeholder="璇烽�夋嫨琛ㄥ崟" style="width: 260px" @change="formKeyChange">
+                <el-option
+                  v-for="item in formManageList"
+                  :key="item.id"
+                  :label="item.formTypeName + ':' + item.formName"
+                  :value="item.formType + ':' + item.id"
+                />
+              </el-select>
+            </el-form-item>
+          </div>
+        </el-collapse-item>
+        <el-collapse-item name="2">
+          <template #title>
+            <div class="collapse__title">
+              <el-icon>
+                <Checked />
+              </el-icon>
+              浠诲姟
+            </div>
+          </template>
+          <div>
+            <el-form-item v-if="showConfig.async" prop="sync" label="鏄惁寮傛">
+              <el-switch v-model="formData.async" inline-prompt active-text="鏄�" inactive-text="鍚�" @change="syncChange" />
+            </el-form-item>
+
+            <el-tabs tab-position="left" class="demo-tabs">
+              <el-tab-pane label="韬唤瀛樺偍">
+                <el-form-item label="鍒嗛厤浜哄憳">
+                  <el-input v-model="formData.assignee" @blur="blurAssignee(formData.assignee)">
+                    <template #append>
+                      <el-button icon="Search" type="primary" @click="openSingleUserSelect" />
+                    </template>
+                  </el-input>
+                </el-form-item>
+                <el-form-item label="鍊欓�変汉鍛�">
+                  <el-badge :value="selectUserLength" :max="99">
+                    <el-button size="small" type="primary" @click="openUserSelect">閫夋嫨浜哄憳</el-button>
+                  </el-badge>
+                </el-form-item>
+                <el-form-item label="鍊欓�夌粍">
+                  <el-badge :value="selectRoleLength" :max="99">
+                    <el-button size="small" type="primary" @click="openRoleSelect">閫夋嫨缁�</el-button>
+                  </el-badge>
+                </el-form-item>
+              </el-tab-pane>
+
+              <!-- <el-tab-pane label="鍥哄畾鍊�">
+                <el-form-item prop="auditUserType" label="鍒嗛厤绫诲瀷">
+                  <el-select v-model="formData.allocationType">
+                    <el-option v-for="item in AllocationTypeSelect" :key="item.id" :value="item.value" :label="item.label"> </el-option>
+                  </el-select>
+                </el-form-item>
+                <el-form-item v-if="formData.allocationType === AllocationTypeEnum.USER" label="鍒嗛厤浜哄憳">
+                  <el-input v-model="formData.assignee">
+                    <template #append>
+                      <el-button icon="Search" type="primary" @click="openSingleUserSelect" />
+                    </template>
+                  </el-input>
+                </el-form-item>
+                <div v-if="formData.allocationType === AllocationTypeEnum.CANDIDATE">
+                  <el-form-item label="鍊欓�変汉鍛�">
+                    <el-badge :value="selectUserLength" :max="99">
+                      <el-button size="small" type="primary" @click="openUserSelect">閫夋嫨浜哄憳</el-button>
+                    </el-badge>
+                  </el-form-item>
+                  <el-form-item label="鍊欓�夌粍">
+                    <el-badge :value="selectRoleLength" :max="99">
+                      <el-button size="small" type="primary" @click="openRoleSelect">閫夋嫨缁�</el-button>
+                    </el-badge>
+                  </el-form-item>
+                </div>
+                <el-form-item v-if="formData.allocationType === AllocationTypeEnum.SPECIFY && showConfig.specifyDesc" style="">
+                  <el-radio-group v-model="formData.specifyDesc" class="ml-4">
+                    <el-radio v-for="item in SpecifyDesc" :key="item.id" :value="item.value" size="large">{{ item.label }}</el-radio>
+                  </el-radio-group>
+                </el-form-item>
+              </el-tab-pane> -->
+            </el-tabs>
+
+            <el-form-item v-if="showConfig.dueDate" prop="dueDate" label="鍒版湡鏃堕棿">
+              <el-input v-model="formData.dueDate" clearable @change="dueDateChange" @click="openDueDate">
+                <template #append>
+                  <el-button icon="Search" type="primary" @click="openDueDate" />
+                </template>
+              </el-input>
+            </el-form-item>
+            <el-form-item v-if="showConfig.priority" prop="priority" label="浼樺厛绾�">
+              <el-input-number v-model="formData.priority" :min="0" @change="priorityChange"> </el-input-number>
+            </el-form-item>
+          </div>
+        </el-collapse-item>
+        <el-collapse-item name="3">
+          <template #title>
+            <div class="collapse__title">
+              <el-icon>
+                <HelpFilled />
+              </el-icon>
+              澶氬疄渚�
+            </div>
+          </template>
+          <div>
+            <el-form-item label="澶氬疄渚嬬被鍨�">
+              <el-select v-model="formData.multiInstanceType" @change="multiInstanceTypeChange">
+                <el-option v-for="item in constant.MultiInstanceType" :key="item.id" :value="item.value" :label="item.label"> </el-option>
+              </el-select>
+            </el-form-item>
+
+            <div v-if="formData.multiInstanceType !== MultiInstanceTypeEnum.NONE">
+              <el-form-item label="闆嗗悎">
+                <template #label>
+                  <span>
+                    闆嗗悎
+                    <el-tooltip placement="top">
+                      <el-icon><QuestionFilled /></el-icon>
+                      <template #content>
+                        灞炴�т細浣滀负琛ㄨ揪寮忚繘琛岃В鏋愩�傚鏋滆〃杈惧紡瑙f瀽涓哄瓧绗︿覆鑰屼笉鏄竴涓泦鍚堬紝<br />
+                        涓嶈鏄洜涓烘湰韬厤缃殑灏辨槸闈欐�佸瓧绗︿覆鍊硷紝杩樻槸琛ㄨ揪寮忚绠楃粨鏋滀负瀛楃涓诧紝<br />
+                        杩欎釜瀛楃涓查兘浼氳褰撳仛鍙橀噺鍚嶏紝骞朵粠娴佺▼鍙橀噺涓敤浜庤幏鍙栧疄闄呯殑闆嗗悎銆�
+                      </template>
+                    </el-tooltip>
+                  </span>
+                </template>
+                <el-input v-model="formData.collection" @change="collectionChange"></el-input>
+              </el-form-item>
+              <el-form-item label="鍏冪礌鍙橀噺">
+                <template #label>
+                  <span>
+                    鍏冪礌鍙橀噺
+                    <el-tooltip placement="top">
+                      <el-icon><QuestionFilled /></el-icon>
+                      <template #content>
+                        姣忓垱寤轰竴涓敤鎴蜂换鍔″墠锛屽厛浠ヨ鍏冪礌鍙橀噺涓簂abel锛岄泦鍚堜腑鐨勪竴椤逛负value锛�<br />
+                        鍒涘缓锛堝眬閮級娴佺▼鍙橀噺锛岃灞�閮ㄦ祦绋嬪彉閲忚鐢ㄤ簬鎸囨淳鐢ㄦ埛浠诲姟銆�<br />
+                        涓�鑸潵璇达紝璇ュ瓧绗︿覆搴斾笌鎸囧畾浜哄憳鍙橀噺鐩稿悓銆�
+                      </template>
+                    </el-tooltip>
+                  </span>
+                </template>
+                <el-input v-model="formData.elementVariable" @change="elementVariableChange"> </el-input>
+              </el-form-item>
+              <el-form-item label="瀹屾垚鏉′欢">
+                <template #label>
+                  <span>
+                    瀹屾垚鏉′欢
+                    <el-tooltip placement="top">
+                      <el-icon><QuestionFilled /></el-icon>
+                      <template #content>
+                        澶氬疄渚嬫椿鍔ㄥ湪鎵�鏈夊疄渚嬮兘瀹屾垚鏃剁粨鏉燂紝鐒惰�屼篃鍙互鎸囧畾涓�涓〃杈惧紡锛屽湪姣忎釜瀹炰緥<br />
+                        缁撴潫鏃惰繘琛岃绠椼�傚綋琛ㄨ揪寮忚绠椾负true鏃讹紝灏嗛攢姣佹墍鏈夊墿浣欑殑瀹炰緥锛屽苟缁撴潫澶氬疄渚�<br />
+                        娲诲姩锛岀户缁墽琛屾祦绋嬨�備緥濡� ${nrOfCompletedInstances/nrOfInstances >= 0.6 }锛�<br />
+                        琛ㄧず褰撲换鍔″畬鎴�60%鏃讹紝璇ヨ妭鐐瑰氨绠楀畬鎴�
+                      </template>
+                    </el-tooltip>
+                  </span>
+                </template>
+                <el-input v-model="formData.completionCondition" @change="completionConditionChange"> </el-input>
+              </el-form-item>
+            </div>
+          </div>
+        </el-collapse-item>
+        <el-collapse-item v-if="showConfig.taskListener" name="4">
+          <template #title>
+            <div class="collapse__title">
+              <el-icon>
+                <BellFilled />
+              </el-icon>
+              浠诲姟鐩戝惉鍣�
+            </div>
+          </template>
+          <div>
+            <TaskListener v-if="showConfig.taskListener" :element="element"></TaskListener>
+          </div>
+        </el-collapse-item>
+        <el-collapse-item v-if="showConfig.executionListener" name="5">
+          <template #title>
+            <div class="collapse__title">
+              <el-icon>
+                <BellFilled />
+              </el-icon>
+              鎵ц鐩戝惉鍣�
+            </div>
+          </template>
+          <div>
+            <ExecutionListener v-if="showConfig.executionListener" :element="element"></ExecutionListener>
+          </div>
+        </el-collapse-item>
+
+        <el-form-item v-if="showConfig.isForCompensation" prop="isForCompensation" label="鏄惁涓鸿ˉ鍋�">
+          <el-switch v-model="formData.isForCompensation" inline-prompt active-text="鏄�" inactive-text="鍚�" />
+        </el-form-item>
+        <el-form-item v-if="showConfig.triggerServiceTask" prop="triggerServiceTask" label="鏈嶅姟浠诲姟鍙Е鍙�">
+          <el-switch v-model="formData.triggerServiceTask" inline-prompt active-text="鏄�" inactive-text="鍚�" />
+        </el-form-item>
+        <el-form-item v-if="showConfig.autoStoreVariables" prop="autoStoreVariables" label="鑷姩瀛樺偍鍙橀噺">
+          <el-switch v-model="formData.autoStoreVariables" inline-prompt active-text="鏄�" inactive-text="鍚�" />
+        </el-form-item>
+        <el-form-item v-if="showConfig.ruleVariablesInput" prop="skipExpression" label="杈撳叆鍙橀噺">
+          <el-input v-model="formData.ruleVariablesInput"> </el-input>
+        </el-form-item>
+        <el-form-item v-if="showConfig.exclude" prop="exclude" label="鎺掗櫎">
+          <el-switch v-model="formData.exclude" inline-prompt active-text="鏄�" inactive-text="鍚�" />
+        </el-form-item>
+        <el-form-item v-if="showConfig.class" prop="class" label="绫�">
+          <el-input v-model="formData.class"> </el-input>
+        </el-form-item>
+      </el-collapse>
+    </el-form>
+    <UserSelect ref="userSelectRef" :data="formData.candidateUsers" @confirm-call-back="userSelectCallBack"></UserSelect>
+    <UserSelect ref="singleUserSelectRef" :data="formData.assignee" :multiple="false" @confirm-call-back="singleUserSelectCallBack"></UserSelect>
+    <RoleSelect ref="roleSelectRef" :data="formData.candidateGroups" @confirm-call-back="roleSelectCallBack"></RoleSelect>
+    <DueDate ref="dueDateRef" v-model="formData.dueDate" :data="formData.dueDate" @confirm-call-back="dueDateCallBack"></DueDate>
+  </div>
+</template>
+<script setup lang="ts">
+import useParseElement from '../hooks/useParseElement';
+import usePanel from '../hooks/usePanel';
+import UserSelect from '@/components/UserSelect';
+import RoleSelect from '@/components/RoleSelect';
+import ExecutionListener from './property/ExecutionListener.vue';
+import TaskListener from './property/TaskListener.vue';
+import DueDate from './property/DueDate.vue';
+import type { ModdleElement } from 'bpmn';
+import type { TaskPanel } from 'bpmnDesign';
+import { AllocationTypeEnum, MultiInstanceTypeEnum, SpecifyDescEnum } from '@/enums/bpmn/IndexEnums';
+import { UserVO } from '@/api/system/user/types';
+import { RoleVO } from '@/api/system/role/types';
+import { selectListFormManage } from '@/api/workflow/formManage';
+import { FormManageVO } from '@/api/workflow/formManage/types';
+const formManageList = ref<FormManageVO[]>([]);
+const formManageListLoading = ref(false);
+interface PropType {
+  element: ModdleElement;
+}
+const props = withDefaults(defineProps<PropType>(), {});
+const { showConfig, nameChange, formKeyChange, idChange, updateProperties, getExtensionElements, createModdleElement, constant } = usePanel({
+  element: toRaw(props.element)
+});
+const { parseData } = useParseElement({
+  element: toRaw(props.element)
+});
+
+const initFormData = {
+  id: '',
+  name: '',
+  dueDate: '',
+  multiInstanceType: MultiInstanceTypeEnum.NONE,
+  allocationType: AllocationTypeEnum.USER,
+  specifyDesc: SpecifyDescEnum.SPECIFY_SINGLE
+};
+const formData = ref({ ...initFormData, ...parseData<TaskPanel>() });
+const assignee = ref<Partial<UserVO>>({
+  userName: ''
+});
+const currentCollapseItem = ref(['1', '2']);
+const userSelectRef = ref<InstanceType<typeof UserSelect>>();
+const singleUserSelectRef = ref<InstanceType<typeof UserSelect>>();
+const roleSelectRef = ref<InstanceType<typeof RoleSelect>>();
+const dueDateRef = ref<InstanceType<typeof DueDate>>();
+
+const openUserSelect = () => {
+  userSelectRef.value.open();
+};
+const openSingleUserSelect = () => {
+  if (formData.value.assignee?.includes('$')) {
+    formData.value.assignee = '';
+  }
+  singleUserSelectRef.value.open();
+};
+const openRoleSelect = () => {
+  roleSelectRef.value.open();
+};
+const openDueDate = (e) => {
+  dueDateRef.value.openDialog();
+};
+const blurAssignee = (assignee) => {
+  updateProperties({ 'flowable:assignee': assignee ? assignee : undefined });
+};
+const singleUserSelectCallBack = (data: UserVO[]) => {
+  const user: UserVO = data.length !== 0 ? data[0] : undefined;
+  updateProperties({ 'flowable:assignee': user?.userId });
+  assignee.value = user ? user : { userName: '' };
+  formData.value.assignee = String(user?.userId);
+  let extensionElements = getExtensionElements();
+  extensionElements.values = extensionElements.get('values').filter((item) => item.$type !== 'flowable:extAssignee');
+  if (user) {
+    const extAssigneeElement = createModdleElement('flowable:extAssignee', { body: '' }, extensionElements);
+    extensionElements.get('values').push(extAssigneeElement);
+    extAssigneeElement.body = JSON.stringify({ userName: user.userName, userId: user.userId });
+  }
+  if (extensionElements.values.length === 0) {
+    extensionElements = undefined;
+  }
+  updateProperties({ extensionElements: extensionElements });
+};
+const userSelectCallBack = (data: UserVO[]) => {
+  let extensionElements = getExtensionElements();
+  extensionElements.values = extensionElements.values.filter((item) => item.$type !== 'flowable:extCandidateUsers');
+  if (data.length === 0) {
+    formData.value.candidateUsers = undefined;
+    updateProperties({ 'flowable:candidateUsers': undefined });
+  } else {
+    const userIds = data.map((item) => item.userId).join(',');
+    formData.value.candidateUsers = userIds;
+    updateProperties({ 'flowable:candidateUsers': userIds });
+    const extCandidateUsersElement = createModdleElement('flowable:extCandidateUsers', { body: '' }, extensionElements);
+    extensionElements.values.push(extCandidateUsersElement);
+    const users = data.map((item) => {
+      return {
+        userId: item.userId,
+        userName: item.userName
+      };
+    });
+    extCandidateUsersElement.body = JSON.stringify(users);
+  }
+  if (extensionElements.values.length === 0) {
+    extensionElements = undefined;
+  }
+  updateProperties({ extensionElements: extensionElements });
+};
+const roleSelectCallBack = (data: RoleVO[]) => {
+  if (data.length === 0) {
+    formData.value.candidateGroups = '';
+    updateProperties({ 'flowable:candidateGroups': undefined });
+  } else {
+    const roleIds = data.map((item) => item.roleId).join(',');
+    formData.value.candidateGroups = roleIds;
+    updateProperties({ 'flowable:candidateGroups': roleIds });
+  }
+};
+const dueDateCallBack = (data: string) => {
+  updateProperties({ 'flowable:dueDate': data });
+};
+
+const taskTabClick = (e) => {
+  formData.value.candidateGroups = '';
+  formData.value.candidateUsers = '';
+  formData.value.assignee = '';
+  // formData.value.fixedAssignee = '';
+  assignee.value = {};
+};
+
+const syncChange = (newVal) => {
+  updateProperties({ 'flowable:async': newVal });
+};
+const skipExpressionChange = (newVal) => {
+  updateProperties({ 'flowable:skipExpression': newVal && newVal.length > 0 ? newVal : undefined });
+};
+const priorityChange = (newVal) => {
+  updateProperties({ 'flowable:priority': newVal });
+};
+const fixedAssigneeChange = (newVal) => {
+  updateProperties({ 'flowable:assignee': newVal && newVal.length > 0 ? newVal : undefined });
+};
+const multiInstanceTypeChange = (newVal) => {
+  if (newVal !== MultiInstanceTypeEnum.NONE) {
+    let loopCharacteristics = props.element.businessObject.get('loopCharacteristics');
+    if (!loopCharacteristics) {
+      loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject);
+    }
+    loopCharacteristics.isSequential = newVal === MultiInstanceTypeEnum.SERIAL;
+    updateProperties({ loopCharacteristics: loopCharacteristics });
+  } else {
+    updateProperties({ loopCharacteristics: undefined });
+  }
+};
+const collectionChange = (newVal) => {
+  let loopCharacteristics = props.element.businessObject.get('loopCharacteristics');
+  if (!loopCharacteristics) {
+    loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject);
+  }
+  loopCharacteristics.collection = newVal && newVal.length > 0 ? newVal : undefined;
+  updateProperties({ loopCharacteristics: loopCharacteristics });
+};
+const elementVariableChange = (newVal) => {
+  let loopCharacteristics = props.element.businessObject.get('loopCharacteristics');
+  if (!loopCharacteristics) {
+    loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject);
+  }
+  loopCharacteristics.elementVariable = newVal && newVal.length > 0 ? newVal : undefined;
+  updateProperties({ loopCharacteristics: loopCharacteristics });
+};
+const completionConditionChange = (newVal) => {
+  let loopCharacteristics = props.element.businessObject.get<ModdleElement>('loopCharacteristics');
+  if (!loopCharacteristics) {
+    loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject);
+  }
+  if (newVal && newVal.length > 0) {
+    if (!loopCharacteristics.completionCondition) {
+      loopCharacteristics.completionCondition = createModdleElement('bpmn:Expression', { body: newVal }, loopCharacteristics);
+    } else {
+      loopCharacteristics.completionCondition.body = newVal;
+    }
+  } else {
+    loopCharacteristics.completionCondition = undefined;
+  }
+  updateProperties({ loopCharacteristics: loopCharacteristics });
+};
+const dueDateChange = (newVal) => {
+  updateProperties({ 'flowable:dueDate': newVal && newVal.length > 0 ? newVal : undefined });
+};
+const selectUserLength = computed(() => {
+  if (formData.value.candidateUsers) {
+    return formData.value.candidateUsers.split(',').length;
+  } else {
+    return 0;
+  }
+});
+const selectRoleLength = computed(() => {
+  if (formData.value.candidateGroups) {
+    return formData.value.candidateGroups.split(',').length;
+  } else {
+    return 0;
+  }
+});
+
+onBeforeMount(() => {
+  const extensionElements = getExtensionElements(false);
+  if (extensionElements && extensionElements.get('values')) {
+    let extAssigneeElement = extensionElements.get('values').find((item) => item.$type === 'flowable:extAssignee');
+    if (extAssigneeElement) {
+      assignee.value = JSON.parse(extAssigneeElement.body);
+    }
+  }
+
+  if (formData.value.loopCharacteristics) {
+    const loopCharacteristics = formData.value.loopCharacteristics;
+    formData.value.collection = loopCharacteristics.collection || '';
+    formData.value.elementVariable = loopCharacteristics.elementVariable || '';
+    formData.value.completionCondition = loopCharacteristics.completionCondition?.body || '';
+    formData.value.multiInstanceType = loopCharacteristics.isSequential ? MultiInstanceTypeEnum.SERIAL : MultiInstanceTypeEnum.PARALLEL;
+  }
+
+  if (formData.value.assignee) {
+    formData.value.fixedAssignee = formData.value.assignee;
+  }
+});
+
+const formRules = ref<ElFormRules>({
+  id: [{ required: true, message: '璇疯緭鍏�', trigger: 'blur' }],
+  name: [{ required: true, message: '璇疯緭鍏�', trigger: 'blur' }]
+});
+
+const AllocationTypeSelect = [
+  { id: 'b9cdf970-dd91-47c0-819f-42a7010ca2a6', label: '鎸囧畾浜哄憳', value: AllocationTypeEnum.USER },
+  { id: '3f7ccbcd-c464-4602-bb9d-e96649d10585', label: '鍊欓�変汉鍛�', value: AllocationTypeEnum.CANDIDATE },
+  { id: 'c49065e0-7f2d-4c09-aedb-ab2d47d9a454', label: '鍙戣捣浜鸿嚜宸�', value: AllocationTypeEnum.YOURSELF },
+  { id: '6ef40a03-7e9a-4898-89b2-c88fe9064542', label: '鍙戣捣浜烘寚瀹�', value: AllocationTypeEnum.SPECIFY }
+];
+const SpecifyDesc = [
+  { id: 'fa253b34-4335-458c-b1bc-b039e2a2b7a6', label: '鎸囧畾涓�涓汉', value: 'specifySingle' },
+  { id: '7365ff54-2e05-4312-9bfb-0b8edd779c5b', label: '鎸囧畾澶氫釜浜�', value: 'specifyMultiple' }
+];
+
+const listFormManage = async () => {
+  formManageListLoading.value = true;
+  const res = await selectListFormManage();
+  formManageList.value = res.data;
+  formManageListLoading.value = false;
+};
+onMounted(() => {
+  nextTick(() => {
+    listFormManage();
+  });
+});
+</script>
+
+<style lang="scss" scoped></style>

--
Gitblit v1.9.3