Pārlūkot izejas kodu

feat: 修改配置

DESKTOP-USV654P\pc 9 mēneši atpakaļ
vecāks
revīzija
7bd5538463

+ 40 - 0
apps/web-baicai/src/adapter/index.ts

@@ -0,0 +1,40 @@
+import { deepMerge } from '#/utils';
+
+export * from './form';
+export * from './vxe-table';
+
+export const useTableGridOptions = (
+  options: Record<string, any>,
+): Record<string, any> => {
+  const defaultOptions = {
+    gridOptions: {
+      toolbarConfig: {
+        refresh: true,
+        print: false,
+        export: false,
+        zoom: true,
+        custom: true,
+      },
+      height: 'auto',
+      keepSource: true,
+    },
+  };
+
+  return deepMerge(defaultOptions, options);
+};
+
+export const useFormOptions = (
+  options: Record<string, any>,
+): Record<string, any> => {
+  const defaultOptions = {
+    showDefaultActions: false,
+    commonConfig: {
+      componentProps: {
+        class: 'w-full',
+      },
+    },
+    wrapperClass: 'grid-cols-1',
+  };
+
+  return deepMerge(defaultOptions, options);
+};

+ 90 - 1
apps/web-baicai/src/adapter/vxe-table.ts

@@ -1,5 +1,7 @@
 import type { Recordable } from '@vben/types';
 
+import type { ActionItem } from '#/components/table-action';
+
 import { h } from 'vue';
 
 import { IconifyIcon } from '@vben/icons';
@@ -8,9 +10,11 @@ import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';
 import { isFunction, isString } from '@vben/utils';
 
 import { objectOmit } from '@vueuse/core';
-import { Button, Image, Popconfirm, Tag } from 'ant-design-vue';
+import { Button, Image, Modal, Popconfirm, Tag } from 'ant-design-vue';
 
+import { TableAction } from '#/components/table-action';
 import { $t } from '#/locales';
+import { deepMerge } from '#/utils';
 
 import { useVbenForm } from './form';
 
@@ -225,6 +229,91 @@ setupVbenVxeTable({
 
     // 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
     // vxeUI.formats.add
+    /**
+     * 注册表格的操作按钮渲染器
+     */
+    vxeUI.renderer.add('CellAction', {
+      renderTableDefault({ attrs, options, props }, { column, row }) {
+        const defaultProps = { size: 'small', type: 'text', ...props };
+        const presets: Recordable<Recordable<any>> = {
+          delete: {
+            danger: true,
+            label: $t('common.delete'),
+            confirm: {
+              title: '删除提示',
+              content: `确定要删除记录 [${row[attrs?.nameField || 'name']}] 吗?`,
+            },
+          },
+          edit: {
+            label: $t('common.edit'),
+          },
+        };
+
+        const actions: ActionItem[] = [];
+        const dropDownActions: ActionItem[] = [];
+
+        (options || ['edit', 'delete']).forEach((opt, index) => {
+          let action: Record<string, any> = {};
+          if (isString(opt)) {
+            action = presets[opt]
+              ? { code: opt, ...presets[opt], ...defaultProps }
+              : {
+                  code: opt,
+                  label: $te(`common.${opt}`) ? $t(`common.${opt}`) : opt,
+                  ...defaultProps,
+                };
+          } else {
+            action = { ...defaultProps, ...presets[opt.code], ...opt };
+          }
+          const optBtn: ActionItem = {};
+          Object.keys(action).forEach((key) => {
+            optBtn[key] = isFunction(action[key])
+              ? action[key](row)
+              : action[key];
+          });
+          optBtn.onClick = () => {
+            if (action.confirm) {
+              const confirmOptions = deepMerge(
+                {
+                  iconType: 'info',
+                  title: '提示',
+                  cancelText: `关闭`,
+                  onOk: () => {
+                    attrs?.onClick?.({
+                      code: action.code,
+                      row,
+                    });
+                  },
+                },
+                action.confirm,
+              );
+              Modal.confirm(confirmOptions);
+            } else {
+              attrs?.onClick?.({
+                code: action.code,
+                row,
+              });
+            }
+          };
+          optBtn.authDisabled = true;
+          if (index < 2) {
+            actions.push(optBtn);
+          } else {
+            dropDownActions.push(optBtn);
+          }
+        });
+
+        if (actions.length === 1) {
+          column.width = 80;
+        } else {
+          column.width = dropDownActions.length > 0 ? 150 : 108;
+        }
+        return h(TableAction, {
+          actions,
+          dropDownActions,
+        });
+      },
+    });
   },
   useVbenForm,
 });

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

@@ -1,9 +1,11 @@
 <script setup lang="ts">
 import type { ButtonType } from 'ant-design-vue/es/button';
 
+import type { PropType } from 'vue';
+
 import type { ActionItem, PopConfirm } from './types';
 
-import { computed, type PropType, toRaw } from 'vue';
+import { computed, toRaw } from 'vue';
 
 import { useAccess } from '@vben/access';
 import { isBoolean, isFunction } from '@vben/utils';
@@ -48,13 +50,28 @@ function isIfShow(action: ActionItem): boolean {
   return isIfShow;
 }
 
+function isIfDisabled(action: ActionItem): boolean {
+  if (action.authDisabled === true && (action.auth || []).length > 0) {
+    return !hasAccessByCodes(action.auth || []);
+  }
+  const ifDisabled = action.disabled;
+
+  let isIfDisabled = false;
+
+  if (isBoolean(ifDisabled)) {
+    isIfDisabled = ifDisabled;
+  }
+  return isIfDisabled;
+}
+
 const getActions = computed(() => {
   return (toRaw(props.actions) || [])
     .filter((action) => {
       return (
-        (hasAccessByCodes(action.auth || []) ||
+        ((hasAccessByCodes(action.auth || []) ||
           (action.auth || []).length === 0) &&
-        isIfShow(action)
+          isIfShow(action)) ||
+        action.authDisabled !== true
       );
     })
     .map((action) => {
@@ -67,6 +84,7 @@ const getActions = computed(() => {
         onConfirm: popConfirm?.confirm,
         onCancel: popConfirm?.cancel,
         enable: !!popConfirm,
+        disabled: isIfDisabled(action),
       };
     });
 });
@@ -76,7 +94,8 @@ const getDropdownList = computed((): any[] => {
       return (
         (hasAccessByCodes(action.auth || []) ||
           (action.auth || []).length === 0) &&
-        isIfShow(action)
+        isIfShow(action) &&
+        action.authDisabled !== true
       );
     })
     .map((action, index) => {
@@ -89,6 +108,7 @@ const getDropdownList = computed((): any[] => {
         text: label,
         divider:
           index < props.dropDownActions.length - 1 ? props.divider : false,
+        disabled: isIfDisabled(action),
       };
     });
 });

+ 1 - 0
apps/web-baicai/src/components/table-action/src/types.d.ts

@@ -23,4 +23,5 @@ export interface ActionItem extends ButtonProps {
   // 业务控制是否显示
   ifShow?: ((action: ActionItem) => boolean) | boolean;
   tooltip?: string | TooltipProps;
+  [key: string]: any;
 }

+ 21 - 13
apps/web-baicai/src/locales/index.ts

@@ -1,10 +1,16 @@
-import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';
 import type { Locale } from 'ant-design-vue/es/locale';
 
 import type { App } from 'vue';
+
+import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';
+
 import { ref } from 'vue';
 
-import { $t, setupI18n as coreSetup, loadLocalesMap } from '@vben/locales';
+import {
+  $t,
+  setupI18n as coreSetup,
+  loadLocalesMapFromDir,
+} from '@vben/locales';
 import { preferences } from '@vben/preferences';
 
 import antdEnLocale from 'ant-design-vue/es/locale/en_US';
@@ -13,10 +19,12 @@ import dayjs from 'dayjs';
 
 const antdLocale = ref<Locale>(antdDefaultLocale);
 
-const modules = import.meta.glob('./langs/*.json');
-
-const localesMap = loadLocalesMap(modules);
+const modules = import.meta.glob('./langs/**/*.json');
 
+const localesMap = loadLocalesMapFromDir(
+  /\.\/langs\/([^/]+)\/(.*)\.json$/,
+  modules,
+);
 /**
  * 加载应用特有的语言包
  * 这里也可以改造为从服务端获取翻译数据
@@ -45,14 +53,14 @@ async function loadThirdPartyMessage(lang: SupportedLanguagesType) {
 async function loadDayjsLocale(lang: SupportedLanguagesType) {
   let locale;
   switch (lang) {
-    case 'zh-CN': {
-      locale = await import('dayjs/locale/zh-cn');
-      break;
-    }
     case 'en-US': {
       locale = await import('dayjs/locale/en');
       break;
     }
+    case 'zh-CN': {
+      locale = await import('dayjs/locale/zh-cn');
+      break;
+    }
     // 默认使用英语
     default: {
       locale = await import('dayjs/locale/en');
@@ -71,14 +79,14 @@ async function loadDayjsLocale(lang: SupportedLanguagesType) {
  */
 async function loadAntdLocale(lang: SupportedLanguagesType) {
   switch (lang) {
-    case 'zh-CN': {
-      antdLocale.value = antdDefaultLocale;
-      break;
-    }
     case 'en-US': {
       antdLocale.value = antdEnLocale;
       break;
     }
+    case 'zh-CN': {
+      antdLocale.value = antdDefaultLocale;
+      break;
+    }
   }
 }
 

+ 70 - 0
apps/web-baicai/src/locales/langs/en-US/demos.json

@@ -0,0 +1,70 @@
+{
+  "title": "Demos",
+  "access": {
+    "frontendPermissions": "Frontend Permissions",
+    "backendPermissions": "Backend Permissions",
+    "pageAccess": "Page Access",
+    "buttonControl": "Button Control",
+    "menuVisible403": "Menu Visible(403)",
+    "superVisible": "Visible to Super",
+    "adminVisible": "Visible to Admin",
+    "userVisible": "Visible to User"
+  },
+  "nested": {
+    "title": "Nested Menu",
+    "menu1": "Menu 1",
+    "menu2": "Menu 2",
+    "menu2_1": "Menu 2-1",
+    "menu3": "Menu 3",
+    "menu3_1": "Menu 3-1",
+    "menu3_2": "Menu 3-2",
+    "menu3_2_1": "Menu 3-2-1"
+  },
+  "outside": {
+    "title": "External Pages",
+    "embedded": "Embedded",
+    "externalLink": "External Link"
+  },
+  "badge": {
+    "title": "Menu Badge",
+    "dot": "Dot Badge",
+    "text": "Text Badge",
+    "color": "Badge Color"
+  },
+  "activeIcon": {
+    "title": "Active Menu Icon",
+    "children": "Children Active Icon"
+  },
+  "fallback": {
+    "title": "Fallback Page"
+  },
+  "features": {
+    "title": "Features",
+    "hideChildrenInMenu": "Hide Menu Children",
+    "loginExpired": "Login Expired",
+    "icons": "Icons",
+    "watermark": "Watermark",
+    "tabs": "Tabs",
+    "tabDetail": "Tab Detail Page",
+    "fullScreen": "FullScreen",
+    "clipboard": "Clipboard",
+    "menuWithQuery": "Menu With Query",
+    "openInNewWindow": "Open in New Window",
+    "fileDownload": "File Download"
+  },
+  "breadcrumb": {
+    "navigation": "Breadcrumb Navigation",
+    "lateral": "Lateral Mode",
+    "lateralDetail": "Lateral Mode Detail",
+    "level": "Level Mode",
+    "levelDetail": "Level Mode Detail"
+  },
+  "vben": {
+    "title": "Project",
+    "about": "About",
+    "document": "Document",
+    "antdv": "Ant Design Vue Version",
+    "naive-ui": "Naive UI Version",
+    "element-plus": "Element Plus Version"
+  }
+}

+ 70 - 0
apps/web-baicai/src/locales/langs/en-US/examples.json

@@ -0,0 +1,70 @@
+{
+  "title": "Examples",
+  "modal": {
+    "title": "Modal"
+  },
+  "drawer": {
+    "title": "Drawer"
+  },
+  "ellipsis": {
+    "title": "EllipsisText"
+  },
+  "form": {
+    "title": "Form",
+    "basic": "Basic Form",
+    "layout": "Custom Layout",
+    "query": "Query Form",
+    "rules": "Form Rules",
+    "dynamic": "Dynamic Form",
+    "custom": "Custom Component",
+    "api": "Api",
+    "merge": "Merge Form"
+  },
+  "vxeTable": {
+    "title": "Vxe Table",
+    "basic": "Basic Table",
+    "remote": "Remote Load",
+    "tree": "Tree Table",
+    "fixed": "Fixed Header/Column",
+    "virtual": "Virtual Scroll",
+    "editCell": "Edit Cell",
+    "editRow": "Edit Row",
+    "custom-cell": "Custom Cell",
+    "form": "Form Table"
+  },
+  "captcha": {
+    "title": "Captcha",
+    "pointSelection": "Point Selection Captcha",
+    "sliderCaptcha": "Slider Captcha",
+    "sliderRotateCaptcha": "Rotate Captcha",
+    "captchaCardTitle": "Please complete the security verification",
+    "pageDescription": "Verify user identity by clicking on specific locations in the image.",
+    "pageTitle": "Captcha Component Example",
+    "basic": "Basic Usage",
+    "titlePlaceholder": "Captcha Title Text",
+    "captchaImageUrlPlaceholder": "Captcha Image (supports img tag src attribute value)",
+    "hintImage": "Hint Image",
+    "hintText": "Hint Text",
+    "hintImagePlaceholder": "Hint Image (supports img tag src attribute value)",
+    "hintTextPlaceholder": "Hint Text",
+    "showConfirm": "Show Confirm",
+    "hideConfirm": "Hide Confirm",
+    "widthPlaceholder": "Captcha Image Width Default 300px",
+    "heightPlaceholder": "Captcha Image Height Default 220px",
+    "paddingXPlaceholder": "Horizontal Padding Default 12px",
+    "paddingYPlaceholder": "Vertical Padding Default 16px",
+    "index": "Index:",
+    "timestamp": "Timestamp:",
+    "x": "x:",
+    "y": "y:"
+  },
+  "resize": {
+    "title": "Resize"
+  },
+  "layout": {
+    "col-page": "ColPage Layout"
+  },
+  "button-group": {
+    "title": "Button Group"
+  }
+}

+ 16 - 0
apps/web-baicai/src/locales/langs/en-US/page.json

@@ -0,0 +1,16 @@
+{
+  "auth": {
+    "login": "Login",
+    "register": "Register",
+    "codeLogin": "Code Login",
+    "qrcodeLogin": "Qr Code Login",
+    "forgetPassword": "Forget Password",
+    "sendingCode": "SMS Code is sending...",
+    "codeSentTo": "Code has been sent to {0}"
+  },
+  "dashboard": {
+    "title": "Dashboard",
+    "analytics": "Analytics",
+    "workspace": "Workspace"
+  }
+}

+ 70 - 0
apps/web-baicai/src/locales/langs/zh-CN/demos.json

@@ -0,0 +1,70 @@
+{
+  "title": "演示",
+  "access": {
+    "frontendPermissions": "前端权限",
+    "backendPermissions": "后端权限",
+    "pageAccess": "页面访问",
+    "buttonControl": "按钮控制",
+    "menuVisible403": "菜单可见(403)",
+    "superVisible": "Super 可见",
+    "adminVisible": "Admin 可见",
+    "userVisible": "User 可见"
+  },
+  "nested": {
+    "title": "嵌套菜单",
+    "menu1": "菜单 1",
+    "menu2": "菜单 2",
+    "menu2_1": "菜单 2-1",
+    "menu3": "菜单 3",
+    "menu3_1": "菜单 3-1",
+    "menu3_2": "菜单 3-2",
+    "menu3_2_1": "菜单 3-2-1"
+  },
+  "outside": {
+    "title": "外部页面",
+    "embedded": "内嵌",
+    "externalLink": "外链"
+  },
+  "badge": {
+    "title": "菜单徽标",
+    "dot": "点徽标",
+    "text": "文本徽标",
+    "color": "徽标颜色"
+  },
+  "activeIcon": {
+    "title": "菜单激活图标",
+    "children": "子级激活图标"
+  },
+  "fallback": {
+    "title": "缺省页"
+  },
+  "features": {
+    "title": "功能",
+    "hideChildrenInMenu": "隐藏子菜单",
+    "loginExpired": "登录过期",
+    "icons": "图标",
+    "watermark": "水印",
+    "tabs": "标签页",
+    "tabDetail": "标签详情页",
+    "fullScreen": "全屏",
+    "clipboard": "剪贴板",
+    "menuWithQuery": "带参菜单",
+    "openInNewWindow": "新窗口打开",
+    "fileDownload": "文件下载"
+  },
+  "breadcrumb": {
+    "navigation": "面包屑导航",
+    "lateral": "平级模式",
+    "level": "层级模式",
+    "levelDetail": "层级模式详情",
+    "lateralDetail": "平级模式详情"
+  },
+  "vben": {
+    "title": "项目",
+    "about": "关于",
+    "document": "文档",
+    "antdv": "Ant Design Vue 版本",
+    "naive-ui": "Naive UI 版本",
+    "element-plus": "Element Plus 版本"
+  }
+}

+ 70 - 0
apps/web-baicai/src/locales/langs/zh-CN/examples.json

@@ -0,0 +1,70 @@
+{
+  "title": "示例",
+  "modal": {
+    "title": "弹窗"
+  },
+  "drawer": {
+    "title": "抽屉"
+  },
+  "ellipsis": {
+    "title": "文本省略"
+  },
+  "resize": {
+    "title": "拖动调整"
+  },
+  "form": {
+    "title": "表单",
+    "basic": "基础表单",
+    "layout": "自定义布局",
+    "query": "查询表单",
+    "rules": "表单校验",
+    "dynamic": "动态表单",
+    "custom": "自定义组件",
+    "api": "Api",
+    "merge": "合并表单"
+  },
+  "vxeTable": {
+    "title": "Vxe 表格",
+    "basic": "基础表格",
+    "remote": "远程加载",
+    "tree": "树形表格",
+    "fixed": "固定表头/列",
+    "virtual": "虚拟滚动",
+    "editCell": "单元格编辑",
+    "editRow": "行编辑",
+    "custom-cell": "自定义单元格",
+    "form": "搜索表单"
+  },
+  "captcha": {
+    "title": "验证码",
+    "pointSelection": "点选验证",
+    "sliderCaptcha": "滑块验证",
+    "sliderRotateCaptcha": "旋转验证",
+    "captchaCardTitle": "请完成安全验证",
+    "pageDescription": "通过点击图片中的特定位置来验证用户身份。",
+    "pageTitle": "验证码组件示例",
+    "basic": "基本使用",
+    "titlePlaceholder": "验证码标题文案",
+    "captchaImageUrlPlaceholder": "验证码图片(支持img标签src属性值)",
+    "hintImage": "提示图片",
+    "hintText": "提示文本",
+    "hintImagePlaceholder": "提示图片(支持img标签src属性值)",
+    "hintTextPlaceholder": "提示文本",
+    "showConfirm": "展示确认",
+    "hideConfirm": "隐藏确认",
+    "widthPlaceholder": "验证码图片宽度 默认300px",
+    "heightPlaceholder": "验证码图片高度 默认220px",
+    "paddingXPlaceholder": "水平内边距 默认12px",
+    "paddingYPlaceholder": "垂直内边距 默认16px",
+    "index": "索引:",
+    "timestamp": "时间戳:",
+    "x": "x:",
+    "y": "y:"
+  },
+  "layout": {
+    "col-page": "双列布局"
+  },
+  "button-group": {
+    "title": "按钮组"
+  }
+}

+ 16 - 0
apps/web-baicai/src/locales/langs/zh-CN/page.json

@@ -0,0 +1,16 @@
+{
+  "auth": {
+    "login": "登录",
+    "register": "注册",
+    "codeLogin": "验证码登录",
+    "qrcodeLogin": "二维码登录",
+    "forgetPassword": "忘记密码",
+    "sendingCode": "正在发送验证码",
+    "codeSentTo": "验证码已发送至{0}"
+  },
+  "dashboard": {
+    "title": "概览",
+    "analytics": "分析页",
+    "workspace": "工作台"
+  }
+}

+ 0 - 1
apps/web-baicai/src/router/guard.ts

@@ -109,7 +109,6 @@ function setupAccessGuard(router: Router) {
       (to.path === DEFAULT_HOME_PATH
         ? userInfo.homePath || DEFAULT_HOME_PATH
         : to.fullPath)) as string;
-
     return {
       ...router.resolve(decodeURIComponent(redirectPath)),
       replace: true,

+ 22 - 0
apps/web-baicai/src/utils/utils.ts

@@ -141,3 +141,25 @@ export function buildUUID(): string {
   }
   return uuid.replaceAll('-', '');
 }
+export function deepMerge(
+  target: Record<string, any>,
+  source: Record<string, any>,
+): Record<string, any> {
+  for (const key in source) {
+    if (Reflect.has(source, key)) {
+      if (
+        typeof source[key] === 'object' &&
+        source[key] !== null &&
+        !Array.isArray(source[key])
+      ) {
+        if (typeof target[key] !== 'object' || target[key] === null) {
+          target[key] = {};
+        }
+        deepMerge(target[key], source[key]);
+      } else {
+        target[key] = source[key];
+      }
+    }
+  }
+  return target;
+}

+ 7 - 6
apps/web-baicai/src/views/system/config/components/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 { ConfigApi } from '#/api';
 
-import { formOptions } from '../data.config';
+import { useSchema } from '../data.config';
 
 defineOptions({
   name: 'ConfigEdit',
@@ -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,

+ 40 - 41
apps/web-baicai/src/views/system/config/data.config.ts

@@ -1,10 +1,13 @@
-import type { VbenFormProps } from '#/adapter/form';
-import type { VxeGridProps } from '#/adapter/vxe-table';
+import type {
+  OnActionClickFn,
+  VbenFormSchema,
+  VxeTableGridOptions,
+} from '#/adapter';
 
 import { ConfigApi } from '#/api';
 
-export const searchFormOptions: VbenFormProps = {
-  schema: [
+export const useSearchSchema = (): VbenFormSchema[] => {
+  return [
     {
       component: 'Input',
       fieldName: 'name',
@@ -15,18 +18,13 @@ export const searchFormOptions: VbenFormProps = {
       fieldName: 'code',
       label: '编码',
     },
-  ],
+  ];
 };
 
-export const gridOptions: VxeGridProps<ConfigApi.RecordItem> = {
-  toolbarConfig: {
-    refresh: true,
-    print: false,
-    export: false,
-    zoom: true,
-    custom: true,
-  },
-  columns: [
+export function useColumns(
+  onActionClick?: OnActionClickFn<ConfigApi.RecordItem>,
+): VxeTableGridOptions<ConfigApi.RecordItem>['columns'] {
+  return [
     { title: '序号', type: 'seq', width: 50 },
     {
       align: 'left',
@@ -38,35 +36,37 @@ export const gridOptions: VxeGridProps<ConfigApi.RecordItem> = {
     { align: 'left', field: 'value', title: '参数值', width: 150 },
     { align: 'left', field: 'remark', title: '备注' },
     {
-      field: 'action',
+      align: 'right',
+      cellRender: {
+        attrs: {
+          nameField: 'name',
+          nameTitle: '配置',
+          onClick: onActionClick,
+        },
+        name: 'CellAction',
+        options: [
+          {
+            code: 'edit',
+            auth: ['config:edit'],
+          },
+          {
+            code: 'delete',
+            auth: ['config:delete'],
+          },
+        ],
+      },
+      field: 'operation',
       fixed: 'right',
-      slots: { default: 'action' },
+      headerAlign: 'center',
+      showOverflow: false,
       title: '操作',
-      width: 110,
-    },
-  ],
-  height: 'auto',
-  keepSource: true,
-  proxyConfig: {
-    ajax: {
-      query: async ({ page }, formValues) => {
-        return await ConfigApi.getPage({
-          pageIndex: page.currentPage,
-          pageSize: page.pageSize,
-          ...formValues,
-        });
-      },
+      width: 100,
     },
-  },
-};
+  ];
+}
 
-export const formOptions: VbenFormProps = {
-  commonConfig: {
-    componentProps: {
-      class: 'w-full',
-    },
-  },
-  schema: [
+export const useSchema = (): VbenFormSchema[] => {
+  return [
     {
       component: 'Input',
       componentProps: {
@@ -111,6 +111,5 @@ export const formOptions: VbenFormProps = {
       fieldName: 'remark',
       label: '备注',
     },
-  ],
-  wrapperClass: 'grid-cols-1',
+  ];
 };

+ 59 - 53
apps/web-baicai/src/views/system/config/index.vue

@@ -1,53 +1,78 @@
 <script lang="ts" setup>
-import { useAccess } from '@vben/access';
+import type { OnActionClickParams, VxeTableGridOptions } from '#/adapter';
+
 import { Page, 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 { ConfigApi } from '#/api';
-import { TableAction } from '#/components/table-action';
 
 import FormEdit from './components/edit.vue';
-import { gridOptions, searchFormOptions } from './data.config';
-
-const { hasAccessByCodes } = useAccess();
-
-const [Grid, { reload }] = useVbenVxeGrid({
-  formOptions: searchFormOptions,
-  gridOptions,
-});
+import { useColumns, useSearchSchema } from './data.config';
 
 const [FormEditModal, formEditApi] = useVbenModal({
   connectedComponent: FormEdit,
+  destroyOnClose: true,
 });
 
-const handleDelete = (id: number) => {
-  Modal.confirm({
-    iconType: 'info',
-    title: '删除提示',
-    content: `确定要删除选择的记录吗?`,
-    cancelText: `关闭`,
-    onOk: async () => {
-      await ConfigApi.deleteDetail(id);
-      message.success('数据删除成功');
-      reload();
-    },
-  });
+const handelSuccess = () => {
+  reload();
 };
-
-const handleEdit = (record: any, isUpdate: boolean) => {
-  formEditApi.setData({
-    isUpdate,
-    baseData: { id: record.id },
-  });
-
-  formEditApi.open();
+const handleDelete = async (id: number) => {
+  await ConfigApi.deleteDetail(id);
+  message.success('数据删除成功');
+  handelSuccess();
 };
 
-const handelSuccess = () => {
-  reload();
+const handleEdit = (record: Record<string, any>, isUpdate: boolean) => {
+  formEditApi
+    .setData({
+      isUpdate,
+      baseData: { id: record.id },
+    })
+    .open();
+};
+/**
+ * 表格操作按钮的回调函数
+ */
+const handleActionClick = async ({
+  code,
+  row,
+}: OnActionClickParams<ConfigApi.RecordItem>) => {
+  switch (code) {
+    case 'delete': {
+      await handleDelete(row.id);
+      break;
+    }
+    case 'edit': {
+      handleEdit(row, true);
+      break;
+    }
+  }
 };
+
+const [Grid, { reload }] = useVbenVxeGrid(
+  useTableGridOptions({
+    formOptions: {
+      schema: useSearchSchema(),
+    },
+    gridOptions: {
+      columns: useColumns(handleActionClick),
+      proxyConfig: {
+        ajax: {
+          query: async ({ page }, formValues) => {
+            return await ConfigApi.getPage({
+              pageIndex: page.currentPage,
+              pageSize: page.pageSize,
+              ...formValues,
+            });
+          },
+        },
+      },
+    } as VxeTableGridOptions,
+  }),
+);
 </script>
 
 <template>
@@ -64,25 +89,6 @@ const handelSuccess = () => {
           新增参数配置
         </Button>
       </template>
-      <template #action="{ row }">
-        <TableAction
-          :actions="[
-            {
-              label: '编辑',
-              type: 'text',
-              disabled: !hasAccessByCodes(['config:edit']),
-              onClick: handleEdit.bind(null, row, true),
-            },
-            {
-              label: '删除',
-              type: 'text',
-              danger: true,
-              disabled: !hasAccessByCodes(['config:delete']),
-              onClick: handleDelete.bind(null, row.id),
-            },
-          ]"
-        />
-      </template>
     </Grid>
   </Page>
 </template>