Bläddra i källkod

feat: 调整界面

DESKTOP-USV654P\pc 8 månader sedan
förälder
incheckning
96cab9bf9a

+ 19 - 20
apps/web-baicai/src/views/system/config/components/edit.vue

@@ -1,5 +1,5 @@
 <script lang="ts" setup>
-import { onMounted, ref, unref } from 'vue';
+import { computed, ref, unref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
@@ -23,7 +23,7 @@ const [Form, { validate, setValues, getValues }] = useVbenForm(
   }),
 );
 
-const [Modal, { close, setState, getData }] = useVbenModal({
+const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
   fullscreenButton: false,
   draggable: true,
   onCancel() {
@@ -32,21 +32,21 @@ const [Modal, { close, setState, getData }] = useVbenModal({
   onConfirm: async () => {
     try {
       const { valid } = await validate();
-      if (valid) {
-        const values = await getValues();
-        setState({ confirmLoading: true });
-        const postParams = unref(modelRef);
-        Object.assign(postParams, values);
-        await (unref(isUpdate)
-          ? ConfigApi.editDetail(postParams as ConfigApi.RecordItem)
-          : ConfigApi.addDetail(postParams as ConfigApi.BasicRecordItem));
-        message.success('操作成功');
+      if (!valid) return;
 
-        close();
-        emit('success');
-      }
+      const values = await getValues();
+      lock();
+      const postParams = unref(modelRef);
+      Object.assign(postParams, values);
+      await (unref(isUpdate)
+        ? ConfigApi.editDetail(postParams as ConfigApi.RecordItem)
+        : ConfigApi.addDetail(postParams as ConfigApi.BasicRecordItem));
+      message.success('操作成功');
+
+      emit('success');
+      close();
     } finally {
-      setState({ confirmLoading: false });
+      unlock();
     }
   },
   onOpenChange: async (isOpen: boolean) => {
@@ -55,7 +55,6 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       const data = getData<Record<string, any>>();
       isUpdate.value = !!data.isUpdate;
       modelRef.value = { ...data.baseData };
-      setState({ title: unref(isUpdate) ? '编辑系统配置' : '新增系统配置' });
 
       if (unref(isUpdate)) {
         const entity = await ConfigApi.getDetail(data.baseData.id);
@@ -65,13 +64,13 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       setState({ loading: false });
     }
   },
-  title: '新增系统配置',
 });
-
-onMounted(async () => {});
+const getTitle = computed(() =>
+  unref(isUpdate) ? '编辑系统配置' : '新增系统配置',
+);
 </script>
 <template>
-  <Modal class="w-[1000px]">
+  <Modal class="w-[1000px]" :title="getTitle">
     <Form />
   </Modal>
 </template>

+ 17 - 22
apps/web-baicai/src/views/system/department/components/edit.vue

@@ -1,5 +1,5 @@
 <script lang="ts" setup>
-import { onMounted, ref, unref } from 'vue';
+import { computed, ref, unref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
@@ -23,7 +23,7 @@ const [Form, { validate, setValues, getValues }] = useVbenForm(
   }),
 );
 
-const [Modal, { close, setState, getData }] = useVbenModal({
+const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
   fullscreenButton: false,
   draggable: true,
   onCancel() {
@@ -32,23 +32,21 @@ const [Modal, { close, setState, getData }] = useVbenModal({
   onConfirm: async () => {
     try {
       const { valid } = await validate();
-      if (valid) {
-        const values = await getValues();
-        setState({ confirmLoading: true });
-        const postParams = unref(modelRef);
-        Object.assign(postParams, values);
-        await (unref(isUpdate)
-          ? DepartmentApi.editDetail(postParams as DepartmentApi.RecordItem)
-          : DepartmentApi.addDetail(
-              postParams as DepartmentApi.BasicRecordItem,
-            ));
-        message.success('操作成功');
+      if (!valid) return;
 
-        close();
-        emit('success');
-      }
+      const values = await getValues();
+      lock();
+      const postParams = unref(modelRef);
+      Object.assign(postParams, values);
+      await (unref(isUpdate)
+        ? DepartmentApi.editDetail(postParams as DepartmentApi.RecordItem)
+        : DepartmentApi.addDetail(postParams as DepartmentApi.BasicRecordItem));
+      message.success('操作成功');
+
+      emit('success');
+      close();
     } finally {
-      setState({ confirmLoading: false });
+      unlock();
     }
   },
   onOpenChange: async (isOpen: boolean) => {
@@ -57,7 +55,6 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       const data = getData<Record<string, any>>();
       isUpdate.value = !!data.isUpdate;
       modelRef.value = { ...data.baseData };
-      setState({ title: unref(isUpdate) ? '编辑系统配置' : '新增系统配置' });
 
       if (unref(isUpdate)) {
         const entity = await DepartmentApi.getDetail(data.baseData.id);
@@ -67,13 +64,11 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       setState({ loading: false });
     }
   },
-  title: '新增系统配置',
 });
-
-onMounted(async () => {});
+const getTitle = computed(() => (unref(isUpdate) ? '编辑组织' : '新增组织'));
 </script>
 <template>
-  <Modal class="w-[1000px]">
+  <Modal class="w-[1000px]" :title="getTitle">
     <Form />
   </Modal>
 </template>

+ 21 - 25
apps/web-baicai/src/views/system/design/database/components/edit.vue

@@ -1,7 +1,7 @@
 <script lang="ts" setup>
 import type { OnActionClickParams, VxeTableGridOptions } from '#/adapter';
 
-import { ref, unref } from 'vue';
+import { computed, ref, unref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
@@ -36,7 +36,7 @@ const [FormEditModal, formEditApi] = useVbenModal({
   connectedComponent: FormEdit,
 });
 
-const [Modal, { close, setState, getData }] = useVbenModal({
+const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
   // fullscreenButton: true,
   fullscreen: true,
   draggable: true,
@@ -46,27 +46,24 @@ const [Modal, { close, setState, getData }] = useVbenModal({
   onConfirm: async () => {
     try {
       const { valid } = await validate();
-      if (valid) {
-        const values = await getValues();
-        setState({ confirmLoading: true });
-        const postParams = unref(modelRef);
-        Object.assign(postParams, values);
-
-        const data = gridApi.grid.getTableData();
-        postParams.columns = data.fullData;
-
-        await (unref(isUpdate)
-          ? DatabaseApi.editDetail(postParams as DatabaseApi.RecordItem)
-          : DatabaseApi.addDetail(postParams as DatabaseApi.BasicRecordItem));
-        message.success('操作成功');
-
-        close();
-        emit('success');
-      }
-    } catch {
-      message.error('操作失败');
+      if (!valid) return;
+      const values = await getValues();
+      lock();
+      const postParams = unref(modelRef);
+      Object.assign(postParams, values);
+
+      const data = gridApi.grid.getTableData();
+      postParams.columns = data.fullData;
+
+      await (unref(isUpdate)
+        ? DatabaseApi.editDetail(postParams as DatabaseApi.RecordItem)
+        : DatabaseApi.addDetail(postParams as DatabaseApi.BasicRecordItem));
+      message.success('操作成功');
+
+      emit('success');
+      close();
     } finally {
-      setState({ confirmLoading: false });
+      unlock();
     }
   },
   onOpenChange: async (isOpen: boolean) => {
@@ -75,7 +72,6 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       const data = getData<Record<string, any>>();
       isUpdate.value = !!data.isUpdate;
       modelRef.value = { ...data.baseData };
-      setState({ title: unref(isUpdate) ? '编辑表' : '新增表' });
 
       if (unref(isUpdate)) {
         const entity = await DatabaseApi.getDetail(data.baseData.id);
@@ -102,8 +98,8 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       setState({ loading: false });
     }
   },
-  title: '新增表',
 });
+const getTitle = computed(() => (unref(isUpdate) ? '编辑表' : '新增表'));
 
 const handleDelete = (record: any) => {
   gridApi.grid.remove(record);
@@ -183,7 +179,7 @@ const [Grid, gridApi] = useVbenVxeGrid(
 );
 </script>
 <template>
-  <Modal class="h-[800px] w-[1000px]">
+  <Modal class="h-[800px] w-[1000px]" :title="getTitle">
     <FormEditModal :close-on-click-modal="false" @success="handelSuccess" />
     <div class="h-full">
       <div class="h-[178px]">

+ 15 - 18
apps/web-baicai/src/views/system/design/database/components/editColumn.vue

@@ -1,5 +1,5 @@
 <script lang="ts" setup>
-import { onMounted, ref, unref } from 'vue';
+import { computed, ref, unref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
@@ -22,7 +22,7 @@ const [Form, { validate, setValues, getValues }] = useVbenForm(
   }),
 );
 
-const [Modal, { close, setState, getData }] = useVbenModal({
+const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
   fullscreenButton: false,
   draggable: true,
   onCancel() {
@@ -31,22 +31,21 @@ const [Modal, { close, setState, getData }] = useVbenModal({
   onConfirm: async () => {
     try {
       const { valid } = await validate();
-      if (valid) {
-        const values = await getValues();
-        setState({ confirmLoading: true });
-        const postParams = { ...unref(modelRef) };
-        Object.assign(postParams, values);
+      if (!valid) return;
+      const values = await getValues();
+      lock();
+      const postParams = { ...unref(modelRef) };
+      Object.assign(postParams, values);
 
-        close();
-        emit('success', {
-          isUpdate: unref(isUpdate),
-          data: postParams,
-        });
-      }
+      emit('success', {
+        isUpdate: unref(isUpdate),
+        data: postParams,
+      });
+      close();
     } catch {
       message.error('操作失败');
     } finally {
-      setState({ confirmLoading: false });
+      unlock();
     }
   },
   onOpenChange: async (isOpen: boolean) => {
@@ -55,7 +54,6 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       const data = getData<Record<string, any>>();
       isUpdate.value = !!data.isUpdate;
       modelRef.value = { ...data.baseData };
-      setState({ title: unref(isUpdate) ? '编辑列' : '新增列' });
 
       if (unref(isUpdate)) {
         setValues({ ...data.baseData });
@@ -63,13 +61,12 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       setState({ loading: false });
     }
   },
-  title: '新增列',
 });
 
-onMounted(async () => {});
+const getTitle = computed(() => (unref(isUpdate) ? '编辑列' : '新增列'));
 </script>
 <template>
-  <Modal class="w-[1000px]">
+  <Modal class="w-[1000px]" :title="getTitle">
     <Form />
   </Modal>
 </template>

+ 4 - 4
apps/web-baicai/src/views/system/design/query/components/edit.vue

@@ -1,7 +1,7 @@
 <script lang="ts" setup>
 import type { BasicOptionResult } from '#/api/model';
 
-import { reactive, ref, unref } from 'vue';
+import { computed, reactive, ref, unref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
@@ -101,7 +101,6 @@ const [Modal, { close, getData, setState }] = useVbenModal({
       isUpdate.value = !!data.isUpdate;
       modelRef.value = { ...data.baseData };
       setState({
-        title: unref(isUpdate) ? '编辑查询' : '新增查询',
         cancelText: '取消',
         confirmText: '下一步',
       });
@@ -116,11 +115,12 @@ const [Modal, { close, getData, setState }] = useVbenModal({
       setState({ loading: false });
     }
   },
-  title: '新增查询',
 });
+
+const getTitle = computed(() => (unref(isUpdate) ? '编辑查询' : '新增查询'));
 </script>
 <template>
-  <Modal class="w-[1000px]">
+  <Modal class="w-[1000px]" :title="getTitle">
     <div>
       <Steps
         :current="state.stepIndex"

+ 3 - 4
apps/web-baicai/src/views/system/design/table/components/edit.vue

@@ -1,7 +1,7 @@
 <script lang="ts" setup>
 import type { BasicOptionResult } from '#/api/model';
 
-import { provide, reactive, ref, unref } from 'vue';
+import { computed, provide, reactive, ref, unref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
@@ -139,7 +139,6 @@ const [Modal, { close, getData, setState }] = useVbenModal({
       isUpdate.value = !!data.isUpdate;
       modelRef.value = { ...data.baseData };
       setState({
-        title: unref(isUpdate) ? '编辑页面' : '新增页面',
         cancelText: '取消',
         confirmText: '下一步',
       });
@@ -154,11 +153,11 @@ const [Modal, { close, getData, setState }] = useVbenModal({
       setState({ loading: false });
     }
   },
-  title: '新增页面',
 });
+const getTitle = computed(() => (unref(isUpdate) ? '编辑页面' : '新增页面'));
 </script>
 <template>
-  <Modal class="w-[1000px]">
+  <Modal class="w-[1000px]" :title="getTitle">
     <div class="h-full">
       <Steps
         :current="state.stepIndex"

+ 1 - 2
apps/web-baicai/src/views/system/design/table/components/preview.vue

@@ -37,7 +37,6 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       setState({ title: `预览${data.baseData.name}` });
     }
   },
-  title: '预览表格',
 });
 
 const handelLoadData = () => {
@@ -45,7 +44,7 @@ const handelLoadData = () => {
 };
 </script>
 <template>
-  <Modal class="w-[1000px]">
+  <Modal class="w-[1000px]" title="预览表格">
     <TablePage :table-query-code="modelRef" @success="handelLoadData" />
   </Modal>
 </template>

+ 21 - 22
apps/web-baicai/src/views/system/dict/item/edit.vue

@@ -1,5 +1,5 @@
 <script lang="ts" setup>
-import { onMounted, ref, unref } from 'vue';
+import { computed, ref, unref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
@@ -11,7 +11,7 @@ import { DictionaryApi } from '#/api';
 import { useSchema } from './data.config';
 
 defineOptions({
-  name: 'UserEdit',
+  name: 'DictItemEdit',
 });
 const emit = defineEmits(['success']);
 const modelRef = ref<Record<string, any>>({});
@@ -23,7 +23,7 @@ const [Form, { validate, setValues, getValues }] = useVbenForm(
   }),
 );
 
-const [Modal, { close, setState, getData }] = useVbenModal({
+const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
   fullscreenButton: false,
   draggable: true,
   onCancel() {
@@ -32,23 +32,22 @@ const [Modal, { close, setState, getData }] = useVbenModal({
   onConfirm: async () => {
     try {
       const { valid } = await validate();
-      if (valid) {
-        const values = await getValues();
-        setState({ confirmLoading: true });
-        const postParams = unref(modelRef);
-        Object.assign(postParams, values);
-        await (unref(isUpdate)
-          ? DictionaryApi.editItemDetail(postParams as DictionaryApi.RecordItem)
-          : DictionaryApi.addItemDetail(
-              postParams as DictionaryApi.BasicRecordItem,
-            ));
-        message.success('操作成功');
+      if (!valid) return;
+      const values = await getValues();
+      lock();
+      const postParams = unref(modelRef);
+      Object.assign(postParams, values);
+      await (unref(isUpdate)
+        ? DictionaryApi.editItemDetail(postParams as DictionaryApi.RecordItem)
+        : DictionaryApi.addItemDetail(
+            postParams as DictionaryApi.BasicRecordItem,
+          ));
+      message.success('操作成功');
 
-        close();
-        emit('success');
-      }
+      emit('success');
+      close();
     } finally {
-      setState({ confirmLoading: false });
+      unlock();
     }
   },
   onOpenChange: async (isOpen: boolean) => {
@@ -57,7 +56,6 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       const data = getData<Record<string, any>>();
       isUpdate.value = !!data.isUpdate;
       modelRef.value = { ...data.baseData };
-      setState({ title: unref(isUpdate) ? '编辑字典项' : '新增字典项' });
 
       if (unref(isUpdate)) {
         const entity = await DictionaryApi.getItemDetail(data.baseData.id);
@@ -67,13 +65,14 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       setState({ loading: false });
     }
   },
-  title: '新增字典项',
 });
 
-onMounted(async () => {});
+const getTitle = computed(() =>
+  unref(isUpdate) ? '编辑字典项' : '新增字典项',
+);
 </script>
 <template>
-  <Modal class="w-[1000px]">
+  <Modal class="w-[1000px]" :title="getTitle">
     <Form />
   </Modal>
 </template>

+ 20 - 22
apps/web-baicai/src/views/system/dict/type/edit.vue

@@ -1,5 +1,5 @@
 <script lang="ts" setup>
-import { ref, unref } from 'vue';
+import { computed, ref, unref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
@@ -23,31 +23,28 @@ const [Form, { validate, setValues, getValues }] = useVbenForm(
   }),
 );
 
-const [Modal, { close, setState, getData }] = useVbenModal({
+const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
   fullscreenButton: false,
   draggable: true,
   onConfirm: async () => {
     try {
       const { valid } = await validate();
-      if (valid) {
-        const values = await getValues();
-        setState({ confirmLoading: true });
-        const postParams = unref(modelRef);
-        Object.assign(postParams, values);
-        await (unref(isUpdate)
-          ? DictionaryApi.editTypeDetail(postParams as DictionaryApi.RecordItem)
-          : DictionaryApi.addTypeDetail(
-              postParams as DictionaryApi.BasicRecordItem,
-            ));
-        message.success('操作成功');
+      if (!valid) return;
+      const values = await getValues();
+      lock();
+      const postParams = unref(modelRef);
+      Object.assign(postParams, values);
+      await (unref(isUpdate)
+        ? DictionaryApi.editTypeDetail(postParams as DictionaryApi.RecordItem)
+        : DictionaryApi.addTypeDetail(
+            postParams as DictionaryApi.BasicRecordItem,
+          ));
+      message.success('操作成功');
 
-        close();
-        emit('success');
-      }
-    } catch {
-      message.error('操作失败');
+      emit('success');
+      close();
     } finally {
-      setState({ confirmLoading: false });
+      unlock();
     }
   },
   onOpenChange: async (isOpen: boolean) => {
@@ -56,7 +53,6 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       const data = getData<Record<string, any>>();
       isUpdate.value = !!data.isUpdate;
       modelRef.value = { ...data.baseData };
-      setState({ title: unref(isUpdate) ? '编辑字典类型' : '新增字典类型' });
 
       if (unref(isUpdate)) {
         const entity = await DictionaryApi.getTypeDetail(data.baseData.id);
@@ -66,11 +62,13 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       setState({ loading: false });
     }
   },
-  title: '新增字典类型',
 });
+const getTitle = computed(() =>
+  unref(isUpdate) ? '编辑字典类型' : '新增字典类型',
+);
 </script>
 <template>
-  <Modal class="w-[1000px]">
+  <Modal class="w-[1000px]" :title="getTitle">
     <Form />
   </Modal>
 </template>

+ 17 - 21
apps/web-baicai/src/views/system/menu/components/edit.vue

@@ -1,5 +1,5 @@
 <script lang="ts" setup>
-import { onMounted, ref, unref } from 'vue';
+import { computed, ref, unref } from 'vue';
 
 import { useVbenDrawer } from '@vben/common-ui';
 
@@ -28,32 +28,30 @@ const [Form, { validate, setValues, getValues }] = useVbenForm(
   }),
 );
 
-const [Drawer, { close, setState, getData }] = useVbenDrawer({
+const [Drawer, { close, setState, getData, lock, unlock }] = useVbenDrawer({
   onCancel() {
     close();
   },
   onConfirm: async () => {
     try {
       const { valid } = await validate();
-      if (valid) {
-        const values = await getValues();
-        setState({ confirmLoading: true });
-        const postParams = unref(modelRef);
+      if (!valid) return;
 
-        Object.assign(postParams, values);
+      const values = await getValues();
+      lock();
+      const postParams = unref(modelRef);
 
-        await (unref(isUpdate)
-          ? MenuApi.editDetail(postParams as MenuApi.RecordItem)
-          : MenuApi.addDetail(postParams as MenuApi.BasicRecordItem));
-        message.success('操作成功');
+      Object.assign(postParams, values);
 
-        close();
-        emit('success');
-      }
-    } catch {
-      message.error('操作失败');
+      await (unref(isUpdate)
+        ? MenuApi.editDetail(postParams as MenuApi.RecordItem)
+        : MenuApi.addDetail(postParams as MenuApi.BasicRecordItem));
+      message.success('操作成功');
+
+      emit('success');
+      close();
     } finally {
-      setState({ confirmLoading: false });
+      unlock();
     }
   },
   onOpenChange: async (isOpen: boolean) => {
@@ -62,7 +60,6 @@ const [Drawer, { close, setState, getData }] = useVbenDrawer({
       const data = getData<Record<string, any>>();
       isUpdate.value = !!data.isUpdate;
       modelRef.value = { ...data.baseData };
-      setState({ title: unref(isUpdate) ? '编辑菜单' : '新增菜单' });
 
       if (unref(isUpdate)) {
         const entity = await MenuApi.getDetail(data.baseData.id);
@@ -75,13 +72,12 @@ const [Drawer, { close, setState, getData }] = useVbenDrawer({
       setState({ loading: false });
     }
   },
-  title: '新增菜单',
 });
 
-onMounted(async () => {});
+const getTitle = computed(() => (unref(isUpdate) ? '编辑菜单' : '新增菜单'));
 </script>
 <template>
-  <Drawer class="w-[1000px]">
+  <Drawer class="w-[1000px]" :title="getTitle">
     <Form />
   </Drawer>
 </template>

+ 16 - 21
apps/web-baicai/src/views/system/menu/components/editMenu.vue

@@ -1,5 +1,5 @@
 <script lang="ts" setup>
-import { onMounted, ref, unref } from 'vue';
+import { computed, ref, unref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
@@ -24,7 +24,7 @@ const [Form, { validate, setValues, getValues }] = useVbenForm(
   }),
 );
 
-const [Modal, { close, setState, getData }] = useVbenModal({
+const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
   fullscreen: false,
   draggable: true,
   onCancel() {
@@ -33,25 +33,22 @@ const [Modal, { close, setState, getData }] = useVbenModal({
   onConfirm: async () => {
     try {
       const { valid } = await validate();
-      if (valid) {
-        const values = await getValues();
-        setState({ confirmLoading: true });
-        const postParams = unref(modelRef);
+      if (!valid) return;
+      const values = await getValues();
+      lock();
+      const postParams = unref(modelRef);
 
-        Object.assign(postParams, values, { type: 1, isMake: 1 });
+      Object.assign(postParams, values, { type: 1, isMake: 1 });
 
-        await (unref(isUpdate)
-          ? MenuApi.editDetail(postParams as MenuApi.RecordItem)
-          : MenuApi.addDetail(postParams as MenuApi.BasicRecordItem));
-        message.success('操作成功');
+      await (unref(isUpdate)
+        ? MenuApi.editDetail(postParams as MenuApi.RecordItem)
+        : MenuApi.addDetail(postParams as MenuApi.BasicRecordItem));
+      message.success('操作成功');
 
-        close();
-        emit('success');
-      }
-    } catch {
-      message.error('操作失败');
+      emit('success');
+      close();
     } finally {
-      setState({ confirmLoading: false });
+      unlock();
     }
   },
   onOpenChange: async (isOpen: boolean) => {
@@ -60,7 +57,6 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       const data = getData<Record<string, any>>();
       isUpdate.value = !!data.isUpdate;
       modelRef.value = { ...data.baseData };
-      setState({ title: unref(isUpdate) ? '编辑菜单' : '新增菜单' });
 
       if (unref(isUpdate)) {
         const entity = await MenuApi.getDetail(data.baseData.id);
@@ -73,13 +69,12 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       setState({ loading: false });
     }
   },
-  title: '新增菜单',
 });
 
-onMounted(async () => {});
+const getTitle = computed(() => (unref(isUpdate) ? '编辑菜单' : '新增菜单'));
 </script>
 <template>
-  <Modal class="w-[1000px]">
+  <Modal class="w-[1000px]" :title="getTitle">
     <Form />
   </Modal>
 </template>

+ 81 - 29
apps/web-baicai/src/views/system/menu/components/grant.vue

@@ -1,16 +1,18 @@
 <script lang="ts" setup>
+import type { DataNode } from 'ant-design-vue/es/tree';
+
 import type { Recordable } from '@vben/types';
 
 import type { RelationRequest } from '#/api/model';
 
 import { onMounted, reactive, ref, unref } from 'vue';
 
-import { useVbenDrawer } from '@vben/common-ui';
+import { useVbenDrawer, VbenTree } from '@vben/common-ui';
 
-import { message } from 'ant-design-vue';
+import { message, Spin } from 'ant-design-vue';
 
+import { useVbenForm } from '#/adapter';
 import { MenuApi, RoleApi, TenantApi } from '#/api';
-import { BcTree } from '#/components/bc-tree';
 import { Icon } from '#/components/icon';
 
 defineOptions({
@@ -21,9 +23,24 @@ const emit = defineEmits(['success']);
 const modelRef = ref<Recordable<any>>({});
 
 const state = reactive<{
-  checkedKeys: number[] | string[];
+  loadingTree: boolean;
+  treeData: DataNode[];
 }>({
-  checkedKeys: [],
+  treeData: [],
+  loadingTree: false,
+});
+
+const [Form, { setValues, validate, getValues }] = useVbenForm({
+  schema: [
+    {
+      component: 'Input',
+      fieldName: 'permissions',
+      formItemClass: 'items-start',
+      label: '菜单列表',
+      modelPropName: 'modelValue',
+    },
+  ],
+  showDefaultActions: false,
 });
 
 const getRoleDetailData = async () => {
@@ -31,16 +48,21 @@ const getRoleDetailData = async () => {
     modelRef.value.type === 'tenant'
       ? await TenantApi.getMenuIds(unref(modelRef).id)
       : await RoleApi.getMenuIds(unref(modelRef).id);
-  state.checkedKeys = data || [];
+
+  setValues({ permissions: data });
 };
 
-const [Drawer, { close, setState, getData }] = useVbenDrawer({
+const [Drawer, { close, setState, getData, lock, unlock }] = useVbenDrawer({
   onConfirm: async () => {
+    const { valid } = await validate();
+    if (!valid) return;
+
+    const values = await getValues();
     try {
-      setState({ confirmLoading: true });
+      lock();
       const postData: RelationRequest = {
         id: unref(modelRef).id,
-        relationIds: state.checkedKeys,
+        relationIds: values.permissions,
       };
       modelRef.value.type === 'tenant'
         ? await TenantApi.updateGrant(postData)
@@ -51,7 +73,7 @@ const [Drawer, { close, setState, getData }] = useVbenDrawer({
     } catch {
       message.error('操作失败');
     } finally {
-      setState({ confirmLoading: false });
+      unlock();
     }
   },
   onOpenChange: async (isOpen: boolean) => {
@@ -59,35 +81,65 @@ const [Drawer, { close, setState, getData }] = useVbenDrawer({
       setState({ loading: true });
       const data = getData<Recordable<any>>();
       modelRef.value = { ...data.baseData };
+
+      if (state.treeData.length === 0) {
+        loadTreeData();
+      }
+
       await getRoleDetailData();
+
       setState({ loading: false });
     }
   },
 });
 
 onMounted(async () => {});
-const handleCheck = (value: any) => {
-  state.checkedKeys = [...value];
+
+function getNodeClass(node: Recordable<any>) {
+  const classes: string[] = [];
+  if (node.value?.type === 2) {
+    classes.push('inline-flex');
+    if (node.index % 5 >= 1) {
+      classes.push('!pl-0');
+    }
+  }
+
+  return classes.join(' ');
+}
+const loadTreeData = async () => {
+  state.loadingTree = true;
+  try {
+    const res = await MenuApi.getList({});
+    state.treeData = res as unknown as DataNode[];
+  } finally {
+    state.loadingTree = false;
+  }
 };
 </script>
 <template>
   <Drawer class="w-[1000px]" title="授权菜单">
-    <div class="h-full">
-      <BcTree
-        :api="{ url: MenuApi.getList }"
-        :field-names="{ label: 'name', value: 'id', children: 'children' }"
-        :checkable="true"
-        :checked-keys="state.checkedKeys"
-        @check="handleCheck"
-        title="菜单列表"
-      >
-        <template #title="{ meta }">
-          <div class="flex items-center">
-            <Icon v-if="meta.icon" :icon="meta.icon" class="mr-1" />
-            <span>{{ meta.title }}</span>
-          </div>
-        </template>
-      </BcTree>
-    </div>
+    <Form>
+      <template #permissions="slotProps">
+        <Spin :spinning="state.loadingTree">
+          <VbenTree
+            :tree-data="state.treeData"
+            multiple
+            :bordered="false"
+            v-bind="slotProps"
+            :default-expanded-level="2"
+            :get-node-class="getNodeClass"
+            value-field="id"
+            label-field="meta.title"
+            icon-field="meta.icon"
+          >
+            <template #node="{ value }">
+              <Icon v-if="value.meta.icon" :icon="value.meta.icon" />
+              {{ $t(value.meta.title) }}
+            </template>
+          </VbenTree>
+        </Spin>
+      </template>
+    </Form>
   </Drawer>
 </template>
+<style lang="less" scoped></style>

+ 16 - 21
apps/web-baicai/src/views/system/post/components/edit.vue

@@ -1,5 +1,5 @@
 <script lang="ts" setup>
-import { onMounted, ref, unref } from 'vue';
+import { computed, ref, unref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
@@ -23,7 +23,7 @@ const [Form, { validate, setValues, getValues }] = useVbenForm(
   }),
 );
 
-const [Modal, { close, setState, getData }] = useVbenModal({
+const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
   fullscreenButton: false,
   draggable: true,
   onCancel() {
@@ -32,23 +32,20 @@ const [Modal, { close, setState, getData }] = useVbenModal({
   onConfirm: async () => {
     try {
       const { valid } = await validate();
-      if (valid) {
-        const values = await getValues();
-        setState({ confirmLoading: true });
-        const postParams = unref(modelRef);
-        Object.assign(postParams, values);
-        await (unref(isUpdate)
-          ? PostApi.editDetail(postParams as PostApi.RecordItem)
-          : PostApi.addDetail(postParams as PostApi.BasicRecordItem));
-        message.success('操作成功');
+      if (!valid) return;
+      const values = await getValues();
+      lock();
+      const postParams = unref(modelRef);
+      Object.assign(postParams, values);
+      await (unref(isUpdate)
+        ? PostApi.editDetail(postParams as PostApi.RecordItem)
+        : PostApi.addDetail(postParams as PostApi.BasicRecordItem));
+      message.success('操作成功');
 
-        close();
-        emit('success');
-      }
-    } catch {
-      message.error('操作失败');
+      emit('success');
+      close();
     } finally {
-      setState({ confirmLoading: false });
+      unlock();
     }
   },
   onOpenChange: async (isOpen: boolean) => {
@@ -57,7 +54,6 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       const data = getData<Record<string, any>>();
       isUpdate.value = !!data.isUpdate;
       modelRef.value = { ...data.baseData };
-      setState({ title: unref(isUpdate) ? '编辑岗位' : '新增岗位' });
 
       if (unref(isUpdate)) {
         const entity = await PostApi.getDetail(data.baseData.id);
@@ -67,13 +63,12 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       setState({ loading: false });
     }
   },
-  title: '新增岗位',
 });
 
-onMounted(async () => {});
+const getTitle = computed(() => (unref(isUpdate) ? '编辑岗位' : '新增岗位'));
 </script>
 <template>
-  <Modal class="w-[1000px]">
+  <Modal class="w-[1000px]" :title="getTitle">
     <Form />
   </Modal>
 </template>

+ 16 - 21
apps/web-baicai/src/views/system/role/components/edit.vue

@@ -1,5 +1,5 @@
 <script lang="ts" setup>
-import { onMounted, ref, unref } from 'vue';
+import { computed, ref, unref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
@@ -23,7 +23,7 @@ const [Form, { validate, setValues, getValues }] = useVbenForm(
   }),
 );
 
-const [Modal, { close, setState, getData }] = useVbenModal({
+const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
   fullscreenButton: false,
   draggable: true,
   onCancel() {
@@ -32,23 +32,20 @@ const [Modal, { close, setState, getData }] = useVbenModal({
   onConfirm: async () => {
     try {
       const { valid } = await validate();
-      if (valid) {
-        const values = await getValues();
-        setState({ confirmLoading: true });
-        const postParams = unref(modelRef);
-        Object.assign(postParams, values);
-        await (unref(isUpdate)
-          ? RoleApi.editDetail(postParams as RoleApi.RecordItem)
-          : RoleApi.addDetail(postParams as RoleApi.BasicRecordItem));
-        message.success('操作成功');
+      if (!valid) return;
+      const values = await getValues();
+      lock();
+      const postParams = unref(modelRef);
+      Object.assign(postParams, values);
+      await (unref(isUpdate)
+        ? RoleApi.editDetail(postParams as RoleApi.RecordItem)
+        : RoleApi.addDetail(postParams as RoleApi.BasicRecordItem));
+      message.success('操作成功');
 
-        close();
-        emit('success');
-      }
-    } catch {
-      message.error('操作失败');
+      emit('success');
+      close();
     } finally {
-      setState({ confirmLoading: false });
+      unlock();
     }
   },
   onOpenChange: async (isOpen: boolean) => {
@@ -57,7 +54,6 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       const data = getData<Record<string, any>>();
       isUpdate.value = !!data.isUpdate;
       modelRef.value = { ...data.baseData };
-      setState({ title: unref(isUpdate) ? '编辑角色' : '新增角色' });
 
       if (unref(isUpdate)) {
         const entity = await RoleApi.getDetail(data.baseData.id);
@@ -67,13 +63,12 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       setState({ loading: false });
     }
   },
-  title: '新增角色',
 });
 
-onMounted(async () => {});
+const getTitle = computed(() => (unref(isUpdate) ? '编辑角色' : '新增角色'));
 </script>
 <template>
-  <Modal class="w-[1000px]">
+  <Modal class="w-[1000px]" :title="getTitle">
     <Form />
   </Modal>
 </template>

+ 16 - 21
apps/web-baicai/src/views/system/tenant/components/edit.vue

@@ -1,5 +1,5 @@
 <script lang="ts" setup>
-import { onMounted, ref, unref } from 'vue';
+import { computed, ref, unref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
@@ -24,7 +24,7 @@ const [Form, { validate, setValues, getValues }] = useVbenForm(
   }),
 );
 
-const [Modal, { close, setState, getData }] = useVbenModal({
+const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
   fullscreenButton: false,
   draggable: true,
   onCancel() {
@@ -33,23 +33,20 @@ const [Modal, { close, setState, getData }] = useVbenModal({
   onConfirm: async () => {
     try {
       const { valid } = await validate();
-      if (valid) {
-        const values = await getValues();
-        setState({ confirmLoading: true });
-        const postParams = unref(modelRef);
-        Object.assign(postParams, values);
-        await (unref(isUpdate)
-          ? TenantApi.editDetail(postParams as TenantApi.RecordItem)
-          : TenantApi.addDetail(postParams as TenantApi.BasicRecordItem));
-        message.success('操作成功');
+      if (!valid) return;
+      const values = await getValues();
+      lock();
+      const postParams = unref(modelRef);
+      Object.assign(postParams, values);
+      await (unref(isUpdate)
+        ? TenantApi.editDetail(postParams as TenantApi.RecordItem)
+        : TenantApi.addDetail(postParams as TenantApi.BasicRecordItem));
+      message.success('操作成功');
 
-        close();
-        emit('success');
-      }
-    } catch {
-      message.error('操作失败');
+      emit('success');
+      close();
     } finally {
-      setState({ confirmLoading: false });
+      unlock();
     }
   },
   onOpenChange: async (isOpen: boolean) => {
@@ -58,7 +55,6 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       const data = getData<Record<string, any>>();
       isUpdate.value = !!data.isUpdate;
       modelRef.value = { ...data.baseData };
-      setState({ title: unref(isUpdate) ? '编辑租户' : '新增租户' });
 
       if (unref(isUpdate)) {
         const entity = await TenantApi.getDetail(data.baseData.id);
@@ -68,13 +64,12 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       setState({ loading: false });
     }
   },
-  title: '新增租户',
 });
 
-onMounted(async () => {});
+const getTitle = computed(() => (unref(isUpdate) ? '编辑租户' : '新增租户'));
 </script>
 <template>
-  <Modal class="w-[1000px]">
+  <Modal class="w-[1000px]" :title="getTitle">
     <Form />
   </Modal>
 </template>

+ 20 - 25
apps/web-baicai/src/views/system/user/components/edit.vue

@@ -1,5 +1,5 @@
 <script lang="ts" setup>
-import { onMounted, ref, unref } from 'vue';
+import { computed, ref, unref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
@@ -25,7 +25,7 @@ const [Form, { validate, setValues, getValues, updateSchema }] = useVbenForm(
   }),
 );
 
-const [Modal, { close, setState, getData }] = useVbenModal({
+const [Modal, { close, setState, getData, lock, unlock }] = useVbenModal({
   fullscreenButton: false,
   draggable: true,
   onCancel() {
@@ -34,27 +34,24 @@ const [Modal, { close, setState, getData }] = useVbenModal({
   onConfirm: async () => {
     try {
       const { valid } = await validate();
-      if (valid) {
-        const values = await getValues();
-        setState({ confirmLoading: true });
-        const postParams = unref(modelRef);
-        const data: any = {};
-        if (values.password) {
-          data.password = encrypt(values.password);
-        }
-        Object.assign(postParams, values, { ...data });
-        await (unref(isUpdate)
-          ? UserApi.editDetail(postParams as UserApi.RecordItem)
-          : UserApi.addDetail(postParams as UserApi.BasicRecordItem));
-        message.success('操作成功');
-
-        close();
-        emit('success');
+      if (!valid) return;
+      const values = await getValues();
+      lock();
+      const postParams = unref(modelRef);
+      const data: any = {};
+      if (values.password) {
+        data.password = encrypt(values.password);
       }
-    } catch {
-      message.error('操作失败');
+      Object.assign(postParams, values, { ...data });
+      await (unref(isUpdate)
+        ? UserApi.editDetail(postParams as UserApi.RecordItem)
+        : UserApi.addDetail(postParams as UserApi.BasicRecordItem));
+      message.success('操作成功');
+
+      emit('success');
+      close();
     } finally {
-      setState({ confirmLoading: false });
+      unlock();
     }
   },
   onOpenChange: async (isOpen: boolean) => {
@@ -63,7 +60,6 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       const data = getData<Record<string, any>>();
       isUpdate.value = !!data.isUpdate;
       modelRef.value = { ...data.baseData };
-      setState({ title: unref(isUpdate) ? '编辑用户' : '新增用户' });
 
       if (unref(isUpdate)) {
         const entity = await UserApi.getDetail(data.baseData.id);
@@ -81,13 +77,12 @@ const [Modal, { close, setState, getData }] = useVbenModal({
       setState({ loading: false });
     }
   },
-  title: '新增用户',
 });
 
-onMounted(async () => {});
+const getTitle = computed(() => (unref(isUpdate) ? '编辑用户' : '新增用户'));
 </script>
 <template>
-  <Modal class="w-[1000px]">
+  <Modal class="w-[1000px]" :title="getTitle">
     <Form />
   </Modal>
 </template>