Kaynağa Gözat

Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin

# Conflicts:
#	src/directives/permission.ts
shizhongming 2 yıl önce
ebeveyn
işleme
367294c419

+ 18 - 0
.github/workflows/stale.yml

@@ -0,0 +1,18 @@
+name: "Close stale issues"
+
+on:
+  schedule:
+  - cron: "30 1 * * *"
+
+jobs:
+  stale:
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/stale@v3
+      with:
+        repo-token: ${{ secrets.OPER_TOKEN }}
+        stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days'
+        stale-pr-message: 'This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days'
+        exempt-issue-labels: 'bug,enhancement'
+        days-before-stale: 60
+        days-before-close: 7

+ 1 - 0
.vscode/extensions.json

@@ -9,5 +9,6 @@
     "antfu.iconify",
     "antfu.unocss",
     "mikestead.dotenv",
+    "warmthsea.vscode-custom-code-color",
   ]
 }

+ 9 - 3
.vscode/settings.json

@@ -108,7 +108,11 @@
   "i18n-ally.sortKeys": true,
   "i18n-ally.namespace": true,
   "i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}",
-  "i18n-ally.enabledParsers": ["json","ts","js"],
+  "i18n-ally.enabledParsers": [
+    "json",
+    "ts",
+    "js"
+  ],
   "i18n-ally.sourceLanguage": "en",
   "i18n-ally.displayLanguage": "zh-CN",
   "i18n-ally.enabledFrameworks": [
@@ -182,5 +186,7 @@
     ".eslintrc.cjs": ".eslintignore,.prettierignore,.stylelintignore,.commitlintrc.*,.prettierrc.*,.stylelintrc.*"
   },
   "terminal.integrated.scrollback": 10000,
-  "nuxt.isNuxtApp": false
-}
+  "nuxt.isNuxtApp": false,
+  "vscodeCustomCodeColor.highlightValue": "v-auth",
+  "vscodeCustomCodeColor.highlightValueColor": "#6366f1",
+}

+ 75 - 71
src/components/Modal/src/index.less

@@ -1,3 +1,5 @@
+@prefix-cls: ~'@{namespace}-basic-modal-wrap';
+
 .fullscreen-modal {
   overflow: hidden;
 
@@ -18,103 +20,105 @@
   }
 }
 
-.ant-modal {
-  width: 520px;
-  padding-bottom: 0;
+.@{prefix-cls} {
+  .ant-modal {
+    width: 520px;
+    padding-bottom: 0;
 
-  .ant-modal-body > .scrollbar {
-    padding: 14px;
-  }
+    .ant-modal-body > .scrollbar {
+      padding: 14px;
+    }
 
-  &-title {
-    font-size: 16px;
-    font-weight: bold;
+    &-title {
+      font-size: 16px;
+      font-weight: bold;
 
-    .base-title {
-      cursor: move !important;
+      .base-title {
+        cursor: move !important;
+      }
     }
-  }
 
-  .ant-modal-body {
-    padding: 0;
+    .ant-modal-body {
+      padding: 0;
 
-    > .scrollbar > .scrollbar__bar.is-horizontal {
-      display: none;
+      > .scrollbar > .scrollbar__bar.is-horizontal {
+        display: none;
+      }
     }
-  }
 
-  &-large {
-    top: 60px;
+    &-large {
+      top: 60px;
 
-    &--mini {
-      top: 16px;
+      &--mini {
+        top: 16px;
+      }
     }
-  }
 
-  &-header {
-    padding: 16px;
-    border-bottom: 1px solid @border-color-base;
-  }
+    &-header {
+      padding: 16px;
+      border-bottom: 1px solid @border-color-base;
+    }
 
-  &-content {
-    padding: 0 !important;
-    box-shadow:
-      0 4px 8px 0 rgb(0 0 0 / 20%),
-      0 6px 20px 0 rgb(0 0 0 / 19%);
-  }
+    &-content {
+      padding: 0 !important;
+      box-shadow:
+        0 4px 8px 0 rgb(0 0 0 / 20%),
+        0 6px 20px 0 rgb(0 0 0 / 19%);
+    }
 
-  &-footer {
-    padding: 10px 16px;
-    border-top: 1px solid @border-color-base;
+    &-footer {
+      padding: 10px 16px;
+      border-top: 1px solid @border-color-base;
 
-    button + button {
-      margin-left: 10px;
+      button + button {
+        margin-left: 10px;
+      }
     }
-  }
 
-  &-close {
-    top: 0 !important;
-    right: 0 !important;
-    width: auto !important;
-    outline: none;
-    background: transparent !important;
-    font-weight: normal;
-  }
+    &-close {
+      top: 0 !important;
+      right: 0 !important;
+      width: auto !important;
+      outline: none;
+      background: transparent !important;
+      font-weight: normal;
+    }
 
-  &-close-x {
-    display: inline-block;
-    width: 96px;
-    height: 56px;
-    line-height: 56px !important;
-  }
+    &-close-x {
+      display: inline-block;
+      width: 96px;
+      height: 56px;
+      line-height: 56px !important;
+    }
 
-  &-confirm-body {
-    .ant-modal-confirm-content {
-      > * {
-        color: @text-color-help-dark;
+    &-confirm-body {
+      .ant-modal-confirm-content {
+        > * {
+          color: @text-color-help-dark;
+        }
       }
     }
-  }
 
-  &-confirm-confirm.error .ant-modal-confirm-body > .anticon {
-    color: @error-color;
-  }
+    &-confirm-confirm.error .ant-modal-confirm-body > .anticon {
+      color: @error-color;
+    }
 
-  &-confirm-btns {
-    .ant-btn:last-child {
-      margin-right: 0;
+    &-confirm-btns {
+      .ant-btn:last-child {
+        margin-right: 0;
+      }
     }
-  }
 
-  &-confirm-info {
-    .ant-modal-confirm-body > .anticon {
-      color: @warning-color;
+    &-confirm-info {
+      .ant-modal-confirm-body > .anticon {
+        color: @warning-color;
+      }
     }
-  }
 
-  &-confirm-confirm.success {
-    .ant-modal-confirm-body > .anticon {
-      color: @success-color;
+    &-confirm-confirm.success {
+      .ant-modal-confirm-body > .anticon {
+        color: @success-color;
+      }
     }
   }
 }

+ 2 - 0
src/components/Table/src/BasicTable.vue

@@ -144,6 +144,7 @@
     getDataSourceRef,
     getDataSource,
     getRawDataSource,
+    getSearchInfo,
     setTableData,
     updateTableDataRecord,
     deleteTableDataRecord,
@@ -300,6 +301,7 @@
     setLoading,
     getDataSource,
     getRawDataSource,
+    getSearchInfo,
     setProps,
     getRowSelection,
     getPaginationRef: getPagination,

+ 8 - 1
src/components/Table/src/hooks/useDataSource.ts

@@ -50,6 +50,7 @@ export function useDataSource(
   });
   const dataSourceRef = ref<Recordable[]>([]);
   const rawDataSourceRef = ref<Recordable>({});
+  const searchInfoRef = ref<Recordable>({});
 
   watchEffect(() => {
     tableData.value = unref(dataSourceRef);
@@ -275,7 +276,7 @@ export function useDataSource(
       if (beforeFetch && isFunction(beforeFetch)) {
         params = (await beforeFetch(params)) || params;
       }
-
+      searchInfoRef.value = params;
       const res = await api(params);
       rawDataSourceRef.value = res;
 
@@ -339,6 +340,10 @@ export function useDataSource(
     return await fetch(opt);
   }
 
+  function getSearchInfo<T = Recordable>() {
+    return searchInfoRef.value as T;
+  }
+
   onMounted(() => {
     useTimeoutFn(() => {
       unref(propsRef).immediate && fetch();
@@ -349,6 +354,8 @@ export function useDataSource(
     getDataSourceRef,
     getDataSource,
     getRawDataSource,
+    searchInfoRef,
+    getSearchInfo,
     getRowKey,
     setTableData,
     getAutoCreateKey,

+ 3 - 0
src/components/Table/src/hooks/useTable.ts

@@ -89,6 +89,9 @@ export function useTable(tableProps?: Props): [
     getRawDataSource: () => {
       return getTableInstance().getRawDataSource();
     },
+    getSearchInfo: () => {
+      return getTableInstance().getSearchInfo();
+    },
     getColumns: ({ ignoreIndex = false }: { ignoreIndex?: boolean } = {}) => {
       const columns = getTableInstance().getColumns({ ignoreIndex }) || [];
       return toRaw(columns);

+ 1 - 0
src/components/Table/src/types/table.ts

@@ -114,6 +114,7 @@ export interface TableActionType {
   setColumns: (columns: BasicColumn[] | string[]) => void;
   getDataSource: <T = Recordable>() => T[];
   getRawDataSource: <T = Recordable>() => T;
+  getSearchInfo: <T = Recordable>() => T;
   setLoading: (loading: boolean) => void;
   setProps: (props: Partial<BasicTableProps>) => void;
   redoHeight: () => void;

+ 1 - 0
src/components/Tree/src/types/tree.ts

@@ -91,6 +91,7 @@ export const treeProps = buildProps({
 
   expandedKeys: {
     type: Array as PropType<KeyType[]>,
+    default: () => [],
   },
 
   selectedKeys: {

+ 2 - 1
src/directives/permission.ts

@@ -8,6 +8,7 @@ import type { App, Directive, DirectiveBinding } from 'vue';
 import { usePermission } from '@/hooks/web/usePermission';
 import { unref } from 'vue';
 import { NoPermissionModeEnum } from '@/enums/appEnum';
+import { RoleEnum } from '@/enums/roleEnum';
 
 function isAuth(el: Element, binding: any) {
   const { hasPermission } = usePermission();
@@ -19,7 +20,7 @@ function isAuth(el: Element, binding: any) {
   }
 }
 
-const mounted = (el: Element, binding: DirectiveBinding<any>) => {
+const mounted = (el: Element, binding: DirectiveBinding<string | string[] | RoleEnum[]>) => {
   isAuth(el, binding);
 };
 

+ 6 - 1
src/views/demo/system/account/index.vue

@@ -4,6 +4,7 @@
     <BasicTable @register="registerTable" class="w-3/4 xl:w-4/5" :searchInfo="searchInfo">
       <template #toolbar>
         <a-button type="primary" @click="handleCreate">新增账号</a-button>
+        <a-button type="primary" @click="handleExport">导出账号</a-button>
       </template>
       <template #bodyCell="{ column, record }">
         <template v-if="column.key === 'action'">
@@ -56,7 +57,7 @@
   const go = useGo();
   const [registerModal, { openModal }] = useModal();
   const searchInfo = reactive<Recordable>({});
-  const [registerTable, { reload, updateTableDataRecord }] = useTable({
+  const [registerTable, { reload, updateTableDataRecord, getSearchInfo }] = useTable({
     title: '账号列表',
     api: getAccountList,
     rowKey: 'id',
@@ -99,6 +100,10 @@
     console.log(record);
   }
 
+  function handleExport() {
+    console.log(getSearchInfo());
+  }
+
   function handleSuccess({ isUpdate, values }) {
     if (isUpdate) {
       // 演示不刷新表格直接更新内部数据。

+ 11 - 0
types/directives.d.ts

@@ -0,0 +1,11 @@
+import type { Directive } from 'vue';
+import { RoleEnum } from '@/enums/roleEnum';
+
+declare module 'vue' {
+  export interface ComponentCustomProperties {
+    vLoading: Directive<Element, boolean>;
+    vAuth: Directive<Element, string | string[] | RoleEnum[]>;
+  }
+}
+
+export {};