瀏覽代碼

feat: 字典

DESKTOP-USV654P\pc 9 月之前
父節點
當前提交
33125e2e5d

+ 8 - 3
apps/web-baicai/src/adapter/vxe-table.ts

@@ -296,17 +296,22 @@ setupVbenVxeTable({
             }
           };
           optBtn.authDisabled = true;
+
           if (index < 2) {
             actions.push(optBtn);
           } else {
+            optBtn.type = 'link';
             dropDownActions.push(optBtn);
           }
         });
-
+        let width = 0;
         if (actions.length === 1) {
-          column.width = 80;
+          width = 80;
         } else {
-          column.width = dropDownActions.length > 0 ? 150 : 108;
+          width = dropDownActions.length > 0 ? 150 : 108;
+        }
+        if (width > Number(column.width || 0)) {
+          column.width = width;
         }
         return h(TableAction, {
           actions,

+ 10 - 4
apps/web-baicai/src/components/table-action/src/table-action.vue

@@ -92,9 +92,9 @@ const getDropdownList = computed((): any[] => {
   return (toRaw(props.dropDownActions) || [])
     .filter((action) => {
       return (
-        (hasAccessByCodes(action.auth || []) ||
+        ((hasAccessByCodes(action.auth || []) ||
           (action.auth || []).length === 0) &&
-        isIfShow(action) &&
+          isIfShow(action)) ||
         action.authDisabled !== true
       );
     })
@@ -198,7 +198,13 @@ const handleMenuClick = (e: any) => {
               </Popconfirm>
             </template>
             <template v-else>
-              <div
+              <Button v-bind="getButtonProps(action)">
+                <template v-if="action.icon" #icon>
+                  <Icon :icon="action.icon" />
+                </template>
+                {{ action.label }}
+              </Button>
+              <!-- <div
                 :class="
                   action.disabled === true
                     ? 'cursor-not-allowed text-gray-300'
@@ -207,7 +213,7 @@ const handleMenuClick = (e: any) => {
               >
                 <Icon v-if="action.icon" :icon="action.icon" />
                 {{ action.label }}
-              </div>
+              </div> -->
             </template>
           </MenuItem>
         </Menu>

+ 63 - 40
apps/web-baicai/src/views/system/dict/item/data.config.ts

@@ -1,12 +1,14 @@
-import type { VbenFormProps } from '#/adapter/form';
-import type { VxeGridProps } from '#/adapter/vxe-table';
+import type {
+  OnActionClickFn,
+  VbenFormProps,
+  VbenFormSchema,
+  VxeTableGridOptions,
+} from '#/adapter';
 
 import { DictionaryApi } from '#/api';
-import { formatterStatus } from '#/api/model';
 
-export const searchFormOptions: VbenFormProps = {
-  showCollapseButton: false,
-  schema: [
+export const useSearchSchema = (): VbenFormSchema[] => {
+  return [
     {
       component: 'Input',
       fieldName: 'code',
@@ -17,22 +19,13 @@ export const searchFormOptions: VbenFormProps = {
       fieldName: 'value',
       label: '值',
     },
-  ],
+  ];
 };
 
-export const gridOptions: VxeGridProps<DictionaryApi.RecordItem> = {
-  toolbarConfig: {
-    refresh: true,
-    print: false,
-    export: false,
-    zoom: true,
-    custom: true,
-  },
-  treeConfig: {
-    rowField: 'id',
-    childrenField: 'children',
-  },
-  columns: [
+export function useColumns(
+  onActionClick?: OnActionClickFn<DictionaryApi.RecordItem>,
+): VxeTableGridOptions<DictionaryApi.RecordItem>['columns'] {
+  return [
     { title: '序号', type: 'seq', width: 50 },
     { align: 'left', field: 'value', title: '值', width: 200, treeNode: true },
     { align: 'left', field: 'code', title: '编码', width: 120 },
@@ -41,31 +34,46 @@ export const gridOptions: VxeGridProps<DictionaryApi.RecordItem> = {
     {
       field: 'status',
       title: '状态',
-      width: 60,
-      formatter: formatterStatus,
+      width: 82,
+      cellRender: { name: 'CellTag' },
     },
     {
-      field: 'action',
+      align: 'right',
+      cellRender: {
+        attrs: {
+          nameField: 'code',
+          nameTitle: '字典项',
+          onClick: onActionClick,
+        },
+        name: 'CellAction',
+        options: [
+          {
+            code: 'append',
+            label: '添加子项',
+            auth: ['dict-detail:add'],
+          },
+          {
+            code: 'edit',
+            auth: ['dict-detail:edit'],
+          },
+          {
+            code: 'delete',
+            auth: ['dict-detail:delete'],
+          },
+        ],
+      },
+      field: 'operation',
       fixed: 'right',
-      slots: { default: 'action' },
+      headerAlign: 'center',
+      showOverflow: false,
       title: '操作',
-      width: 180,
+      width: 168,
     },
-  ],
-  height: 'auto',
-  keepSource: true,
-  pagerConfig: {
-    enabled: false,
-  },
-};
+  ];
+}
 
-export const formOptions: VbenFormProps = {
-  commonConfig: {
-    componentProps: {
-      class: 'w-full',
-    },
-  },
-  schema: [
+export const useSchema = (): VbenFormSchema[] => {
+  return [
     {
       component: 'Input',
       componentProps: {
@@ -101,6 +109,21 @@ export const formOptions: VbenFormProps = {
       fieldName: 'remark',
       label: '备注',
     },
+  ];
+};
+
+export const searchFormOptions: VbenFormProps = {
+  showCollapseButton: false,
+  schema: [
+    {
+      component: 'Input',
+      fieldName: 'code',
+      label: '编码',
+    },
+    {
+      component: 'Input',
+      fieldName: 'value',
+      label: '值',
+    },
   ],
-  wrapperClass: 'grid-cols-1',
 };

+ 7 - 8
apps/web-baicai/src/views/system/dict/item/edit.vue

@@ -5,10 +5,10 @@ import { useVbenModal } from '@vben/common-ui';
 
 import { message } from 'ant-design-vue';
 
-import { useVbenForm } from '#/adapter/form';
+import { useFormOptions, useVbenForm } from '#/adapter';
 import { DictionaryApi } from '#/api';
 
-import { formOptions } from './data.config';
+import { useSchema } from './data.config';
 
 defineOptions({
   name: 'UserEdit',
@@ -17,10 +17,11 @@ const emit = defineEmits(['success']);
 const modelRef = ref<Record<string, any>>({});
 const isUpdate = ref(true);
 
-const [Form, { validate, setValues, getValues }] = useVbenForm({
-  showDefaultActions: false,
-  ...formOptions,
-});
+const [Form, { validate, setValues, getValues }] = useVbenForm(
+  useFormOptions({
+    schema: useSchema(),
+  }),
+);
 
 const [Modal, { close, setState, getData }] = useVbenModal({
   fullscreenButton: false,
@@ -46,8 +47,6 @@ const [Modal, { close, setState, getData }] = useVbenModal({
         close();
         emit('success');
       }
-    } catch {
-      message.error('操作失败');
     } finally {
       setState({ confirmLoading: false });
     }

+ 77 - 81
apps/web-baicai/src/views/system/dict/item/index.vue

@@ -1,16 +1,18 @@
 <script lang="ts" setup>
-import { type PropType, watch } from 'vue';
+import type { PropType } from 'vue';
+
+import type { OnActionClickParams, VxeTableGridOptions } from '#/adapter';
+
+import { watch } from 'vue';
 
-import { useAccess } from '@vben/access';
 import { useVbenModal } from '@vben/common-ui';
 
-import { Button, message, Modal } from 'ant-design-vue';
+import { Button, message } from 'ant-design-vue';
 
-import { useVbenVxeGrid } from '#/adapter/vxe-table';
+import { useTableGridOptions, useVbenVxeGrid } from '#/adapter';
 import { DictionaryApi } from '#/api';
-import { TableAction } from '#/components/table-action';
 
-import { gridOptions, searchFormOptions } from './data.config';
+import { useColumns, useSearchSchema } from './data.config';
 import FormEdit from './edit.vue';
 
 defineOptions({
@@ -24,52 +26,18 @@ const props = defineProps({
   },
 });
 
-const { hasAccessByCodes } = useAccess();
-
-const [Grid, { reload }] = useVbenVxeGrid({
-  formOptions: searchFormOptions,
-  gridOptions: {
-    ...gridOptions,
-
-    proxyConfig: {
-      autoLoad: false,
-      ajax: {
-        query: async (_: any, formValues: any) => {
-          const postData = { ...formValues };
-          postData.type = props.type;
-          return await DictionaryApi.getItemTree({
-            ...postData,
-          });
-        },
-      },
-    },
-  },
-});
-
 const [FormEditModal, formEditApi] = useVbenModal({
   connectedComponent: FormEdit,
 });
 
-watch(
-  () => props.type,
-  () => {
-    reload();
-  },
-  { deep: true },
-);
+const handelSuccess = () => {
+  reload();
+};
 
-const handleDelete = (id: number) => {
-  Modal.confirm({
-    iconType: 'info',
-    title: '删除提示',
-    content: `确定要删除选择的记录吗?`,
-    cancelText: `关闭`,
-    onOk: async () => {
-      await DictionaryApi.deleteItemDetail(id);
-      message.success('数据删除成功');
-      reload();
-    },
-  });
+const handleDelete = async (id: number) => {
+  await DictionaryApi.deleteItemDetail(id);
+  message.success('数据删除成功');
+  reload();
 };
 
 const handleEdit = (record: any, isUpdate: boolean) => {
@@ -77,17 +45,71 @@ const handleEdit = (record: any, isUpdate: boolean) => {
     message.warning('请先选择字典类型');
     return;
   }
-  formEditApi.setData({
-    isUpdate,
-    baseData: { ...record, dictionaryCode: props.type },
-  });
-
-  formEditApi.open();
+  formEditApi
+    .setData({
+      isUpdate,
+      baseData: { ...record, dictionaryCode: props.type },
+    })
+    .open();
 };
 
-const handelSuccess = () => {
-  reload();
+const handleActionClick = async ({
+  code,
+  row,
+}: OnActionClickParams<DictionaryApi.RecordItem>) => {
+  switch (code) {
+    case 'append': {
+      handleEdit({ parentId: row.id }, false);
+      break;
+    }
+    case 'delete': {
+      await handleDelete(row.id);
+      break;
+    }
+    case 'edit': {
+      handleEdit({ id: row.id }, true);
+      break;
+    }
+  }
 };
+
+const [Grid, { reload }] = useVbenVxeGrid(
+  useTableGridOptions({
+    formOptions: {
+      schema: useSearchSchema(),
+    },
+    gridOptions: {
+      pagerConfig: {
+        enabled: false,
+      },
+      treeConfig: {
+        rowField: 'id',
+        childrenField: 'children',
+      },
+      columns: useColumns(handleActionClick),
+      proxyConfig: {
+        autoLoad: false,
+        ajax: {
+          query: async (_: any, formValues: any) => {
+            const postData = { ...formValues };
+            postData.type = props.type;
+            return await DictionaryApi.getItemTree({
+              ...postData,
+            });
+          },
+        },
+      },
+    } as VxeTableGridOptions,
+  }),
+);
+
+watch(
+  () => props.type,
+  () => {
+    reload();
+  },
+  { deep: true },
+);
 </script>
 <template>
   <div class="h-full">
@@ -103,32 +125,6 @@ const handelSuccess = () => {
           新增字典项
         </Button>
       </template>
-      <template #action="{ row }">
-        <TableAction
-          :actions="[
-            {
-              label: '添加子项',
-              type: 'text',
-              disabled: !hasAccessByCodes(['dict-detail:add']),
-              onClick: handleEdit.bind(null, { parentId: row.id }, false),
-            },
-            {
-              label: '编辑',
-              type: 'text',
-              disabled: !hasAccessByCodes(['dict-detail:edit']),
-              onClick: handleEdit.bind(null, { id: row.id }, true),
-            },
-          ]"
-          :drop-down-actions="[
-            {
-              label: '删除',
-              type: 'text',
-              disabled: !hasAccessByCodes(['dict-detail:delete']),
-              onClick: handleDelete.bind(null, row.id),
-            },
-          ]"
-        />
-      </template>
     </Grid>
   </div>
 </template>

+ 41 - 48
apps/web-baicai/src/views/system/dict/type/data.config.ts

@@ -1,12 +1,13 @@
-import type { VbenFormProps } from '#/adapter/form';
-import type { VxeGridProps } from '#/adapter/vxe-table';
+import type {
+  OnActionClickFn,
+  VbenFormSchema,
+  VxeTableGridOptions,
+} from '#/adapter';
 
 import { DictionaryApi } from '#/api';
-import { formatterStatus } from '#/api/model';
 
-export const searchFormOptions: VbenFormProps = {
-  showCollapseButton: false,
-  schema: [
+export const useSearchSchema = (): VbenFormSchema[] => {
+  return [
     {
       component: 'Input',
       fieldName: 'code',
@@ -17,22 +18,13 @@ export const searchFormOptions: VbenFormProps = {
       fieldName: 'name',
       label: '名称',
     },
-  ],
+  ];
 };
 
-export const gridOptions: VxeGridProps<DictionaryApi.RecordItem> = {
-  toolbarConfig: {
-    refresh: true,
-    print: false,
-    export: false,
-    zoom: true,
-    custom: true,
-  },
-  rowConfig: {
-    isCurrent: true,
-    isHover: true,
-  },
-  columns: [
+export function useColumns(
+  onActionClick?: OnActionClickFn<DictionaryApi.RecordItem>,
+): VxeTableGridOptions<DictionaryApi.RecordItem>['columns'] {
+  return [
     { title: '序号', type: 'seq', width: 50 },
     { align: 'left', field: 'code', title: '编码', width: 120 },
     { align: 'left', field: 'name', title: '名称', width: 200 },
@@ -41,39 +33,41 @@ export const gridOptions: VxeGridProps<DictionaryApi.RecordItem> = {
     {
       field: 'status',
       title: '状态',
-      width: 60,
-      formatter: formatterStatus,
+      width: 82,
+      cellRender: { name: 'CellTag' },
     },
     {
-      field: 'action',
+      align: 'right',
+      cellRender: {
+        attrs: {
+          nameField: 'code',
+          nameTitle: '字典项',
+          onClick: onActionClick,
+        },
+        name: 'CellAction',
+        options: [
+          {
+            code: 'edit',
+            auth: ['dict:edit'],
+          },
+          {
+            code: 'delete',
+            auth: ['dict:delete'],
+          },
+        ],
+      },
+      field: 'operation',
       fixed: 'right',
-      slots: { default: 'action' },
+      headerAlign: 'center',
+      showOverflow: false,
       title: '操作',
       width: 100,
     },
-  ],
-  height: 'auto',
-  keepSource: true,
-  proxyConfig: {
-    ajax: {
-      query: async ({ page }, formValues) => {
-        return await DictionaryApi.getTypePage({
-          pageIndex: page.currentPage,
-          pageSize: page.pageSize,
-          ...formValues,
-        });
-      },
-    },
-  },
-};
+  ];
+}
 
-export const formOptions: VbenFormProps = {
-  commonConfig: {
-    componentProps: {
-      class: 'w-full',
-    },
-  },
-  schema: [
+export const useSchema = (): VbenFormSchema[] => {
+  return [
     {
       component: 'Input',
       componentProps: {
@@ -109,6 +103,5 @@ export const formOptions: VbenFormProps = {
       fieldName: 'remark',
       label: '备注',
     },
-  ],
-  wrapperClass: 'grid-cols-1',
+  ];
 };

+ 7 - 6
apps/web-baicai/src/views/system/dict/type/edit.vue

@@ -5,10 +5,10 @@ import { useVbenModal } from '@vben/common-ui';
 
 import { message } from 'ant-design-vue';
 
-import { useVbenForm } from '#/adapter/form';
+import { useFormOptions, useVbenForm } from '#/adapter';
 import { DictionaryApi } from '#/api';
 
-import { formOptions } from './data.config';
+import { useSchema } from './data.config';
 
 defineOptions({
   name: 'DictionaryTypeEdit',
@@ -17,10 +17,11 @@ const emit = defineEmits(['success']);
 const modelRef = ref<Record<string, any>>({});
 const isUpdate = ref(true);
 
-const [Form, { validate, setValues, getValues }] = useVbenForm({
-  showDefaultActions: false,
-  ...formOptions,
-});
+const [Form, { validate, setValues, getValues }] = useVbenForm(
+  useFormOptions({
+    schema: useSchema(),
+  }),
+);
 
 const [Modal, { close, setState, getData }] = useVbenModal({
   fullscreenButton: false,

+ 67 - 55
apps/web-baicai/src/views/system/dict/type/index.vue

@@ -1,16 +1,18 @@
 <script lang="ts" setup>
-import type { VxeGridListeners } from '#/adapter/vxe-table';
+import type {
+  OnActionClickParams,
+  VxeGridListeners,
+  VxeTableGridOptions,
+} from '#/adapter';
 
-import { useAccess } from '@vben/access';
 import { useVbenModal } from '@vben/common-ui';
 
-import { Button, message, Modal } from 'ant-design-vue';
+import { Button, message } from 'ant-design-vue';
 
-import { useVbenVxeGrid } from '#/adapter/vxe-table';
+import { useTableGridOptions, useVbenVxeGrid } from '#/adapter';
 import { DictionaryApi } from '#/api';
-import { TableAction } from '#/components/table-action';
 
-import { gridOptions, searchFormOptions } from './data.config';
+import { useColumns, useSearchSchema } from './data.config';
 import FormEdit from './edit.vue';
 
 defineOptions({
@@ -18,49 +20,77 @@ defineOptions({
 });
 
 const emit = defineEmits(['change']);
-const { hasAccessByCodes } = useAccess();
-const gridEvents: VxeGridListeners<DictionaryApi.RecordItem> = {
-  currentChange: ({ row }) => {
-    emit('change', row.code);
-  },
-};
-
-const [Grid, { reload }] = useVbenVxeGrid({
-  gridEvents,
-  formOptions: searchFormOptions,
-  gridOptions,
-});
 
 const [FormEditModal, formEditApi] = useVbenModal({
   connectedComponent: FormEdit,
 });
+const handelSuccess = () => {
+  reload();
+};
 
-const handleDelete = (id: number) => {
-  Modal.confirm({
-    iconType: 'info',
-    title: '删除提示',
-    content: `确定要删除选择的记录吗?`,
-    cancelText: `关闭`,
-    onOk: async () => {
-      await DictionaryApi.deleteTypeDetail(id);
-      message.success('数据删除成功');
-      reload();
-    },
-  });
+const handleDelete = async (id: number) => {
+  await DictionaryApi.deleteTypeDetail(id);
+  message.success('数据删除成功');
+  reload();
 };
 
 const handleEdit = (record: any, isUpdate: boolean) => {
-  formEditApi.setData({
-    isUpdate,
-    baseData: { id: record.id },
-  });
+  formEditApi
+    .setData({
+      isUpdate,
+      baseData: { id: record.id },
+    })
+    .open();
+};
 
-  formEditApi.open();
+const handleActionClick = async ({
+  code,
+  row,
+}: OnActionClickParams<DictionaryApi.RecordItem>) => {
+  switch (code) {
+    case 'delete': {
+      await handleDelete(row.id);
+      break;
+    }
+    case 'edit': {
+      handleEdit(row, true);
+      break;
+    }
+  }
 };
 
-const handelSuccess = () => {
-  reload();
+const gridEvents: VxeGridListeners<DictionaryApi.RecordItem> = {
+  currentChange: ({ row }) => {
+    emit('change', row.code);
+  },
 };
+
+const [Grid, { reload }] = useVbenVxeGrid(
+  useTableGridOptions({
+    gridEvents,
+    formOptions: {
+      schema: useSearchSchema(),
+    },
+    gridOptions: {
+      rowConfig: {
+        isCurrent: true,
+        isHover: true,
+      },
+      columns: useColumns(handleActionClick),
+      proxyConfig: {
+        ajax: {
+          query: async ({ page }, formValues) => {
+            return await DictionaryApi.getTypePage({
+              pageIndex: page.currentPage,
+              pageSize: page.pageSize,
+              ...formValues,
+            });
+          },
+        },
+      },
+    } as VxeTableGridOptions,
+  }),
+);
 </script>
 <template>
   <div class="h-full">
@@ -76,24 +106,6 @@ const handelSuccess = () => {
           新增字典类型
         </Button>
       </template>
-      <template #action="{ row }">
-        <TableAction
-          :actions="[
-            {
-              label: '编辑',
-              type: 'text',
-              disabled: !hasAccessByCodes(['dict:edit']),
-              onClick: handleEdit.bind(null, row, true),
-            },
-            {
-              label: '删除',
-              type: 'text',
-              disabled: !hasAccessByCodes(['dict:delete']),
-              onClick: handleDelete.bind(null, row.id),
-            },
-          ]"
-        />
-      </template>
     </Grid>
   </div>
 </template>