فهرست منبع

chore: 更新layout与table compoent

gemercheung 2 سال پیش
والد
کامیت
815b5723c9

+ 11 - 5
src/components/Table/src/BasicTable.vue

@@ -25,10 +25,16 @@
       <template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
         <slot :name="item" v-bind="data || {}"></slot>
       </template>
-
-      <template #[`header-${column.dataIndex}`] v-for="(column, index) in columns" :key="index">
+      <template #headerCell="{ column }">
         <HeaderCell :column="column" />
       </template>
+      <!-- 增加对antdv3.x兼容 -->
+      <template #bodyCell="data">
+        <slot name="bodyCell" v-bind="data || {}"></slot>
+      </template>
+      <!--      <template #[`header-${column.dataIndex}`] v-for="(column, index) in columns" :key="index">-->
+      <!--        <HeaderCell :column="column" />-->
+      <!--      </template>-->
     </Table>
   </div>
 </template>
@@ -247,9 +253,9 @@
           footer: unref(getFooterProps),
           ...unref(getExpandOption),
         };
-        if (slots.expandedRowRender) {
-          propsData = omit(propsData, 'scroll');
-        }
+        // if (slots.expandedRowRender) {
+        //   propsData = omit(propsData, 'scroll');
+        // }
 
         propsData = omit(propsData, ['class', 'onChange']);
         return propsData;

+ 2 - 0
src/components/Table/src/componentMap.ts

@@ -7,6 +7,7 @@ import {
   Switch,
   DatePicker,
   TimePicker,
+  AutoComplete,
 } from 'ant-design-vue';
 import type { ComponentType } from './types/componentType';
 import { ApiSelect, ApiTreeSelect } from '/@/components/Form';
@@ -17,6 +18,7 @@ componentMap.set('Input', Input);
 componentMap.set('InputNumber', InputNumber);
 componentMap.set('Select', Select);
 componentMap.set('ApiSelect', ApiSelect);
+componentMap.set('AutoComplete', AutoComplete);
 componentMap.set('ApiTreeSelect', ApiTreeSelect);
 componentMap.set('Switch', Switch);
 componentMap.set('Checkbox', Checkbox);

+ 1 - 1
src/components/Table/src/components/HeaderCell.vue

@@ -29,7 +29,7 @@
       const { prefixCls } = useDesign('basic-table-header-cell');
 
       const getIsEdit = computed(() => !!props.column?.edit);
-      const getTitle = computed(() => props.column?.customTitle);
+      const getTitle = computed(() => props.column?.customTitle || props.column?.title);
       const getHelpMessage = computed(() => props.column?.helpMessage);
 
       return { prefixCls, getIsEdit, getTitle, getHelpMessage };

+ 103 - 60
src/components/Table/src/components/editable/EditableCell.vue

@@ -1,40 +1,4 @@
-<template>
-  <div :class="prefixCls">
-    <div
-      v-show="!isEdit"
-      :class="{ [`${prefixCls}__normal`]: true, 'ellipsis-cell': column.ellipsis }"
-      @click="handleEdit"
-    >
-      <div class="cell-content" :title="column.ellipsis ? getValues ?? '' : ''">
-        {{ getValues || getValues === 0 ? getValues : '&nbsp;' }}
-      </div>
-      <FormOutlined :class="`${prefixCls}__normal-icon`" v-if="!column.editRow" />
-    </div>
-
-    <a-spin v-if="isEdit" :spinning="spinning">
-      <div :class="`${prefixCls}__wrapper`" v-click-outside="onClickOutside">
-        <CellComponent
-          v-bind="getComponentProps"
-          :component="getComponent"
-          :style="getWrapperStyle"
-          :popoverVisible="getRuleVisible"
-          :rule="getRule"
-          :ruleMessage="ruleMessage"
-          :class="getWrapperClass"
-          ref="elRef"
-          @change="handleChange"
-          @options-change="handleOptionsChange"
-          @pressEnter="handleEnter"
-        />
-        <div :class="`${prefixCls}__action`" v-if="!getRowEditable">
-          <CheckOutlined :class="[`${prefixCls}__icon`, 'mx-2']" @click="handleSubmitClick" />
-          <CloseOutlined :class="`${prefixCls}__icon `" @click="handleCancel" />
-        </div>
-      </div>
-    </a-spin>
-  </div>
-</template>
-<script lang="ts">
+<script lang="tsx">
   import type { CSSProperties, PropType } from 'vue';
   import { computed, defineComponent, nextTick, ref, toRaw, unref, watchEffect } from 'vue';
   import type { BasicColumn } from '../../types/table';
@@ -50,13 +14,13 @@
   import { propTypes } from '/@/utils/propTypes';
   import { isArray, isBoolean, isFunction, isNumber, isString } from '/@/utils/is';
   import { createPlaceholderMessage } from './helper';
-  import { omit, pick, set } from 'lodash-es';
+  import { pick, set } from 'lodash-es';
   import { treeToList } from '/@/utils/helper/treeHelper';
   import { Spin } from 'ant-design-vue';
 
   export default defineComponent({
     name: 'EditableCell',
-    components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, ASpin: Spin },
+    components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, Spin },
     directives: {
       clickOutside,
     },
@@ -100,13 +64,6 @@
       });
 
       const getComponentProps = computed(() => {
-        const compProps = props.column?.editComponentProps ?? {};
-        const component = unref(getComponent);
-        const apiSelectProps: Recordable = {};
-        if (component === 'ApiSelect') {
-          apiSelectProps.cache = true;
-        }
-
         const isCheckValue = unref(getIsCheckComp);
 
         const valueField = isCheckValue ? 'checked' : 'value';
@@ -114,19 +71,49 @@
 
         const value = isCheckValue ? (isNumber(val) && isBoolean(val) ? val : !!val) : val;
 
+        let compProps = props.column?.editComponentProps ?? {};
+        const { record, column, index } = props;
+
+        if (isFunction(compProps)) {
+          compProps = compProps({ text: val, record, column, index }) ?? {};
+        }
+        const component = unref(getComponent);
+        const apiSelectProps: Recordable = {};
+        if (component === 'ApiSelect') {
+          apiSelectProps.cache = true;
+        }
+        upEditDynamicDisabled(record, column, value);
         return {
           size: 'small',
           getPopupContainer: () => unref(table?.wrapRef.value) ?? document.body,
-          getCalendarContainer: () => unref(table?.wrapRef.value) ?? document.body,
           placeholder: createPlaceholderMessage(unref(getComponent)),
           ...apiSelectProps,
-          ...omit(compProps, 'onChange'),
+          ...compProps,
           [valueField]: value,
-        };
+          disabled: unref(getDisable),
+        } as any;
+      });
+      function upEditDynamicDisabled(record, column, value) {
+        if (!record) return false;
+        const { key, dataIndex } = column;
+        if (!key && !dataIndex) return;
+        const dataKey = (dataIndex || key) as string;
+        set(record, dataKey, value);
+      }
+      const getDisable = computed(() => {
+        const { editDynamicDisabled } = props.column;
+        let disabled = false;
+        if (isBoolean(editDynamicDisabled)) {
+          disabled = editDynamicDisabled;
+        }
+        if (isFunction(editDynamicDisabled)) {
+          const { record } = props;
+          disabled = editDynamicDisabled({ record });
+        }
+        return disabled;
       });
-
       const getValues = computed(() => {
-        const { editComponentProps, editValueMap } = props.column;
+        const { editValueMap } = props.column;
 
         const value = unref(currentValueRef);
 
@@ -139,7 +126,8 @@
           return value;
         }
 
-        const options: LabelValueOptions = editComponentProps?.options ?? (unref(optionsRef) || []);
+        const options: LabelValueOptions =
+          unref(getComponentProps)?.options ?? (unref(optionsRef) || []);
         const option = options.find((item) => `${item.value}` === `${value}`);
 
         return option?.label ?? value;
@@ -190,14 +178,16 @@
         const component = unref(getComponent);
         if (!e) {
           currentValueRef.value = e;
-        } else if (e?.target && Reflect.has(e.target, 'value')) {
-          currentValueRef.value = (e as ChangeEvent).target.value;
         } else if (component === 'Checkbox') {
           currentValueRef.value = (e as ChangeEvent).target.checked;
-        } else if (isString(e) || isBoolean(e) || isNumber(e)) {
+        } else if (component === 'Switch') {
+          currentValueRef.value = e;
+        } else if (e?.target && Reflect.has(e.target, 'value')) {
+          currentValueRef.value = (e as ChangeEvent).target.value;
+        } else if (isString(e) || isBoolean(e) || isNumber(e) || isArray(e)) {
           currentValueRef.value = e;
         }
-        const onChange = props.column?.editComponentProps?.onChange;
+        const onChange = unref(getComponentProps)?.onChange;
         if (onChange && isFunction(onChange)) onChange(...arguments);
 
         table.emit?.('edit-change', {
@@ -265,7 +255,7 @@
               result = await beforeEditSubmit({
                 record: pick(record, keys),
                 index,
-                key: key as string,
+                key: dataKey as string,
                 value,
               });
             } catch (e) {
@@ -281,7 +271,7 @@
 
         set(record, dataKey, value);
         //const record = await table.updateTableData(index, dataKey, value);
-        needEmit && table.emit?.('edit-end', { record, index, key, value });
+        needEmit && table.emit?.('edit-end', { record, index, key: dataKey, value });
         isEdit.value = false;
       }
 
@@ -322,7 +312,7 @@
 
       // only ApiSelect or TreeSelect
       function handleOptionsChange(options: LabelValueOptions) {
-        const { replaceFields } = props.column?.editComponentProps ?? {};
+        const { replaceFields } = unref(getComponentProps);
         const component = unref(getComponent);
         if (component === 'ApiTreeSelect') {
           const { title = 'title', value = 'value', children = 'children' } = replaceFields || {};
@@ -355,7 +345,7 @@
 
         if (props.column.dataIndex) {
           if (!props.record.editValueRefs) props.record.editValueRefs = {};
-          props.record.editValueRefs[props.column.dataIndex] = currentValueRef;
+          props.record.editValueRefs[props.column.dataIndex as any] = currentValueRef;
         }
         /* eslint-disable  */
         props.record.onCancelEdit = () => {
@@ -398,6 +388,59 @@
         spinning,
       };
     },
+    render() {
+      return (
+        <div class={this.prefixCls}>
+          <div
+            v-show={!this.isEdit}
+            class={{ [`${this.prefixCls}__normal`]: true, 'ellipsis-cell': this.column.ellipsis }}
+            onClick={this.handleEdit}
+          >
+            <div class="cell-content" title={this.column.ellipsis ? this.getValues ?? '' : ''}>
+              {this.column.editRender
+                ? this.column.editRender({
+                    text: this.value,
+                    record: this.record as Recordable,
+                    column: this.column,
+                    index: this.index,
+                  })
+                : this.getValues
+                ? this.getValues
+                : '\u00A0'}
+            </div>
+            {!this.column.editRow && <FormOutlined class={`${this.prefixCls}__normal-icon`} />}
+          </div>
+          {this.isEdit && (
+            <Spin spinning={this.spinning}>
+              <div class={`${this.prefixCls}__wrapper`} v-click-outside={this.onClickOutside}>
+                <CellComponent
+                  {...this.getComponentProps}
+                  component={this.getComponent}
+                  style={this.getWrapperStyle}
+                  popoverVisible={this.getRuleVisible}
+                  rule={this.getRule}
+                  ruleMessage={this.ruleMessage}
+                  class={this.getWrapperClass}
+                  ref="elRef"
+                  onChange={this.handleChange}
+                  onOptionsChange={this.handleOptionsChange}
+                  onPressEnter={this.handleEnter}
+                />
+                {!this.getRowEditable && (
+                  <div class={`${this.prefixCls}__action`}>
+                    <CheckOutlined
+                      class={[`${this.prefixCls}__icon`, 'mx-2']}
+                      onClick={this.handleSubmitClick}
+                    />
+                    <CloseOutlined class={`${this.prefixCls}__icon `} onClick={this.handleCancel} />
+                  </div>
+                )}
+              </div>
+            </Spin>
+          )}
+        </div>
+      );
+    },
   });
 </script>
 <style lang="less">

+ 1 - 1
src/components/Table/src/components/editable/helper.ts

@@ -7,7 +7,7 @@ const { t } = useI18n();
  * @description: 生成placeholder
  */
 export function createPlaceholderMessage(component: ComponentType) {
-  if (component.includes('Input')) {
+  if (component.includes('Input') || component.includes('AutoComplete')) {
     return t('common.inputText');
   }
   if (component.includes('Picker')) {

+ 17 - 9
src/components/Table/src/components/settings/ColumnSetting.vue

@@ -6,7 +6,7 @@
     <Popover
       placement="bottomLeft"
       trigger="click"
-      @visibleChange="handleVisibleChange"
+      @visible-change="handleVisibleChange"
       :overlayClassName="`${prefixCls}__cloumn-list`"
       :getPopupContainer="getPopupContainer"
     >
@@ -111,6 +111,7 @@
     computed,
   } from 'vue';
   import { Tooltip, Popover, Checkbox, Divider } from 'ant-design-vue';
+  import type { CheckboxChangeEvent } from 'ant-design-vue/lib/checkbox/interface';
   import { SettingOutlined, DragOutlined } from '@ant-design/icons-vue';
   import { Icon } from '/@/components/Icon';
   import { ScrollContainer } from '/@/components/Container';
@@ -182,10 +183,12 @@
       });
 
       watchEffect(() => {
-        const columns = table.getColumns();
-        if (columns.length && !state.isInit) {
-          init();
-        }
+        setTimeout(() => {
+          const columns = table.getColumns();
+          if (columns.length && !state.isInit) {
+            init();
+          }
+        }, 0);
       });
 
       watchEffect(() => {
@@ -241,7 +244,7 @@
       }
 
       // checkAll change
-      function onCheckAllChange(e: ChangeEvent) {
+      function onCheckAllChange(e: CheckboxChangeEvent) {
         const checkList = plainOptions.value.map((item) => item.value);
         if (e.target.checked) {
           state.checkedList = checkList;
@@ -313,7 +316,12 @@
               }
 
               plainSortOptions.value = columns;
-              setColumns(columns);
+
+              setColumns(
+                columns
+                  .map((col: Options) => col.value)
+                  .filter((value: string) => state.checkedList.includes(value)),
+              );
             },
           });
           // 记录原始order 序列
@@ -323,14 +331,14 @@
       }
 
       // Control whether the serial number column is displayed
-      function handleIndexCheckChange(e: ChangeEvent) {
+      function handleIndexCheckChange(e: CheckboxChangeEvent) {
         table.setProps({
           showIndexColumn: e.target.checked,
         });
       }
 
       // Control whether the check box is displayed
-      function handleSelectCheckChange(e: ChangeEvent) {
+      function handleSelectCheckChange(e: CheckboxChangeEvent) {
         table.setProps({
           rowSelection: e.target.checked ? defaultRowSelection : undefined,
         });

+ 1 - 1
src/components/Table/src/components/settings/SizeSetting.vue

@@ -4,7 +4,7 @@
       <span>{{ t('component.table.settingDens') }}</span>
     </template>
 
-    <Dropdown placement="bottomCenter" :trigger="['click']" :getPopupContainer="getPopupContainer">
+    <Dropdown placement="bottom" :trigger="['click']" :getPopupContainer="getPopupContainer">
       <ColumnHeightOutlined />
       <template #overlay>
         <Menu @click="handleTitleClick" selectable v-model:selectedKeys="selectedKeysRef">

+ 1 - 1
src/components/Table/src/components/settings/index.vue

@@ -44,7 +44,7 @@
         return {
           redo: true,
           size: true,
-          setting: false,
+          setting: true,
           fullScreen: false,
           ...props.setting,
         };

+ 11 - 11
src/components/Table/src/hooks/useColumns.ts

@@ -1,7 +1,7 @@
 import type { BasicColumn, BasicTableProps, CellFormat, GetColumnsParams } from '../types/table';
 import type { PaginationProps } from '../types/pagination';
 import type { ComputedRef } from 'vue';
-import { computed, Ref, ref, toRaw, unref, watch } from 'vue';
+import { computed, Ref, ref, reactive, toRaw, unref, watch } from 'vue';
 import { renderEditCell } from '../components/editable';
 import { usePermission } from '/@/hooks/web/usePermission';
 import { useI18n } from '/@/hooks/web/useI18n';
@@ -152,10 +152,10 @@ export function useColumns(
         return hasPermission(column.auth) && isIfShow(column);
       })
       .map((column) => {
-        const { slots, dataIndex, customRender, format, edit, editRow, flag } = column;
+        const { slots, customRender, format, edit, editRow, flag } = column;
 
         if (!slots || !slots?.title) {
-          column.slots = { title: `header-${dataIndex}`, ...(slots || {}) };
+          // column.slots = { title: `header-${dataIndex}`, ...(slots || {}) };
           column.customTitle = column.title;
           Reflect.deleteProperty(column, 'title');
         }
@@ -170,7 +170,7 @@ export function useColumns(
         if ((edit || editRow) && !isDefaultAction) {
           column.customRender = renderEditCell(column);
         }
-        return column;
+        return reactive(column);
       });
   });
 
@@ -197,7 +197,7 @@ export function useColumns(
    * set columns
    * @param columnList key|column
    */
-  function setColumns(columnList: Partial<BasicColumn>[] | string[]) {
+  function setColumns(columnList: Partial<BasicColumn>[] | (string | string[])[]) {
     const columns = cloneDeep(columnList);
     if (!isArray(columns)) return;
 
@@ -210,23 +210,23 @@ export function useColumns(
 
     const cacheKeys = cacheColumns.map((item) => item.dataIndex);
 
-    if (!isString(firstColumn)) {
+    if (!isString(firstColumn) && !isArray(firstColumn)) {
       columnsRef.value = columns as BasicColumn[];
     } else {
-      const columnKeys = columns as string[];
+      const columnKeys = (columns as (string | string[])[]).map((m) => m.toString());
       const newColumns: BasicColumn[] = [];
       cacheColumns.forEach((item) => {
         newColumns.push({
           ...item,
-          defaultHidden: !columnKeys.includes(item.dataIndex! || (item.key as string)),
+          defaultHidden: !columnKeys.includes(item.dataIndex?.toString() || (item.key as string)),
         });
       });
       // Sort according to another array
       if (!isEqual(cacheKeys, columns)) {
         newColumns.sort((prev, next) => {
           return (
-            columnKeys.indexOf(prev.dataIndex as string) -
-            columnKeys.indexOf(next.dataIndex as string)
+            columnKeys.indexOf(prev.dataIndex?.toString() as string) -
+            columnKeys.indexOf(next.dataIndex?.toString() as string)
           );
         });
       }
@@ -298,7 +298,7 @@ export function formatCell(text: string, format: CellFormat, record: Recordable,
   try {
     // date type
     const DATE_FORMAT_PREFIX = 'date|';
-    if (isString(format) && format.startsWith(DATE_FORMAT_PREFIX)) {
+    if (isString(format) && format.startsWith(DATE_FORMAT_PREFIX) && text) {
       const dateFormat = format.replace(DATE_FORMAT_PREFIX, '');
 
       if (!dateFormat) {

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

@@ -292,7 +292,7 @@ export function useDataSource(
       const isArrayResult = Array.isArray(res);
 
       let resultItems: Recordable[] = isArrayResult ? res : get(res, listField);
-      const resultTotal: number = isArrayResult ? 0 : get(res, totalField);
+      const resultTotal: number = isArrayResult ? res.length : get(res, totalField);
 
       // 假如数据变少,导致总页数变少并小于当前选中页码,通过getPaginationRef获取到的页码是不正确的,需获取正确的页码再次执行
       if (resultTotal) {

+ 2 - 3
src/components/Table/src/hooks/useTableFooter.ts

@@ -36,14 +36,13 @@ export function useTableFooter(
     nextTick(() => {
       const tableEl = unref(tableElRef);
       if (!tableEl) return;
-      const bodyDomList = tableEl.$el.querySelectorAll('.ant-table-body');
-      const bodyDom = bodyDomList[0];
+      const bodyDom = tableEl.$el.querySelector('.ant-table-content');
       useEventListener({
         el: bodyDom,
         name: 'scroll',
         listener: () => {
           const footerBodyDom = tableEl.$el.querySelector(
-            '.ant-table-footer .ant-table-body',
+            '.ant-table-footer .ant-table-content',
           ) as HTMLDivElement;
           if (!footerBodyDom || !bodyDom) return;
           footerBodyDom.scrollLeft = bodyDom.scrollLeft;

+ 2 - 2
src/components/Table/src/hooks/useTableScroll.ts

@@ -90,7 +90,7 @@ export function useTableScroll(
 
     bodyEl!.style.height = 'unset';
 
-    if (!unref(getCanResize) || tableData.length === 0) return;
+    if (!unref(getCanResize) || !unref(tableData) || tableData.length === 0) return;
 
     await nextTick();
     // Add a delay to get the correct bottomIncludeBody paginationHeight footerHeight headerHeight
@@ -191,7 +191,7 @@ export function useTableScroll(
 
     const columns = unref(columnsRef).filter((item) => !item.defaultHidden);
     columns.forEach((item) => {
-      width += Number.parseInt(item.width as string) || 0;
+      width += Number.parseFloat(item.width as string) || 0;
     });
     const unsetWidthColumns = columns.filter((item) => !Reflect.has(item, 'width'));
 

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

@@ -3,6 +3,7 @@ export type ComponentType =
   | 'InputNumber'
   | 'Select'
   | 'ApiSelect'
+  | 'AutoComplete'
   | 'ApiTreeSelect'
   | 'Checkbox'
   | 'Switch'

+ 17 - 1
src/components/Table/src/types/pagination.ts

@@ -7,9 +7,18 @@ interface PaginationRenderProps {
   originalElement: any;
 }
 
+type PaginationPositon =
+  | 'topLeft'
+  | 'topCenter'
+  | 'topRight'
+  | 'bottomLeft'
+  | 'bottomCenter'
+  | 'bottomRight';
+
 export declare class PaginationConfig extends Pagination {
-  position?: 'top' | 'bottom' | 'both';
+  position?: PaginationPositon[];
 }
+
 export interface PaginationProps {
   /**
    * total number of data items
@@ -96,4 +105,11 @@ export interface PaginationProps {
    * @type Function
    */
   itemRender?: (props: PaginationRenderProps) => VNodeChild | JSX.Element;
+
+  /**
+   * specify the position of Pagination
+   * @default ['bottomRight']
+   * @type string[]
+   */
+  position?: PaginationPositon[];
 }

+ 18 - 2
src/components/Table/src/types/table.ts

@@ -412,7 +412,7 @@ export type CellFormat =
   | Map<string | number, any>;
 
 // @ts-ignore
-export interface BasicColumn extends ColumnProps {
+export interface BasicColumn extends ColumnProps<Recordable> {
   children?: BasicColumn[];
   filters?: {
     text: string;
@@ -441,7 +441,14 @@ export interface BasicColumn extends ColumnProps {
   editRow?: boolean;
   editable?: boolean;
   editComponent?: ComponentType;
-  editComponentProps?: Recordable;
+  editComponentProps?:
+    | ((opt: {
+        text: string | number | boolean | Recordable;
+        record: Recordable;
+        column: BasicColumn;
+        index: number;
+      }) => Recordable)
+    | Recordable;
   editRule?: boolean | ((text: string, record: Recordable) => Promise<string>);
   editValueMap?: (value: any) => string;
   onEditRow?: () => void;
@@ -449,6 +456,15 @@ export interface BasicColumn extends ColumnProps {
   auth?: RoleEnum | RoleEnum[] | string | string[];
   // 业务控制是否显示
   ifShow?: boolean | ((column: BasicColumn) => boolean);
+  // 自定义修改后显示的内容
+  editRender?: (opt: {
+    text: string | number | boolean | Recordable;
+    record: Recordable;
+    column: BasicColumn;
+    index: number;
+  }) => VNodeChild | JSX.Element;
+  // 动态 Disabled
+  editDynamicDisabled?: boolean | ((record: Recordable) => boolean);
 }
 
 export type ColumnChangeParam = {

+ 3 - 0
src/layouts/default/header/components/lock/LockModal.vue

@@ -53,6 +53,9 @@
           {
             field: 'password',
             label: t('layout.header.lockScreenPassword'),
+            colProps: {
+              span: 24,
+            },
             component: 'InputPassword',
             required: true,
           },

+ 1 - 0
src/layouts/default/header/components/user-dropdown/DropMenuItem.vue

@@ -18,6 +18,7 @@
     name: 'DropdownMenuItem',
     components: { MenuItem: Menu.Item, Icon },
     props: {
+      // eslint-disable-next-line
       key: propTypes.string,
       text: propTypes.string,
       icon: propTypes.string,

+ 1 - 1
src/layouts/default/header/index.vue

@@ -39,7 +39,7 @@
 
       <!-- <ErrorAction v-if="getUseErrorHandle" :class="`${prefixCls}-action__item error-action`" /> -->
 
-      <Notify v-if="getShowNotice" :class="`${prefixCls}-action__item notify-item`" />
+      <!-- <Notify v-if="getShowNotice" :class="`${prefixCls}-action__item notify-item`" /> -->
 
       <FullScreen v-if="getShowFullScreen" :class="`${prefixCls}-action__item fullscreen-item`" />
 

+ 1 - 1
src/layouts/default/sider/MixSider.vue

@@ -66,7 +66,7 @@
           :items="childrenMenus"
           :theme="getMenuTheme"
           mixSider
-          @menuClick="handleMenuClick"
+          @menu-click="handleMenuClick"
         />
       </ScrollContainer>
       <div

+ 9 - 5
src/layouts/default/sider/useLayoutSider.ts

@@ -1,26 +1,30 @@
 import type { Ref } from 'vue';
 
-import { computed, unref, onMounted, nextTick, ref } from 'vue';
+import { computed, unref, onMounted, nextTick } from 'vue';
 
 import { TriggerEnum } from '/@/enums/menuEnum';
 
 import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
 import { useDebounceFn } from '@vueuse/core';
+import { useAppStore } from '/@/store/modules/app';
 
 /**
  * Handle related operations of menu events
  */
 export function useSiderEvent() {
-  const brokenRef = ref(false);
-
+  const appStore = useAppStore();
   const { getMiniWidthNumber } = useMenuSetting();
 
   const getCollapsedWidth = computed(() => {
-    return unref(brokenRef) ? 0 : unref(getMiniWidthNumber);
+    return unref(getMiniWidthNumber);
   });
 
   function onBreakpointChange(broken: boolean) {
-    brokenRef.value = broken;
+    appStore.setProjectConfig({
+      menuSetting: {
+        siderHidden: broken,
+      },
+    });
   }
 
   return { getCollapsedWidth, onBreakpointChange };

+ 7 - 1
src/layouts/default/tabs/components/TabContent.vue

@@ -1,5 +1,11 @@
 <template>
-  <Dropdown :dropMenuList="getDropMenuList" :trigger="getTrigger" @menuEvent="handleMenuEvent">
+  <Dropdown
+    :dropMenuList="getDropMenuList"
+    :trigger="getTrigger"
+    placement="bottom"
+    overlayClassName="multiple-tabs__dropdown"
+    @menu-event="handleMenuEvent"
+  >
     <div :class="`${prefixCls}__info`" @contextmenu="handleContext" v-if="getIsTabs">
       <span class="ml-1">{{ getTitle }}</span>
     </div>

+ 25 - 0
src/layouts/default/tabs/index.less

@@ -180,3 +180,28 @@ html[data-theme='light'] {
     }
   }
 }
+
+.ant-tabs-dropdown-menu {
+  &-title-content {
+    display: flex;
+    align-items: center;
+
+    .@{prefix-cls} {
+      &-content__info {
+        width: auto;
+        margin-left: 0;
+        line-height: 28px;
+      }
+    }
+  }
+
+  &-item-remove {
+    margin-left: auto;
+  }
+}
+
+.multiple-tabs__dropdown {
+  .ant-dropdown-content {
+    width: 172px;
+  }
+}

+ 3 - 1
src/layouts/page/index.vue

@@ -17,7 +17,9 @@
         <keep-alive v-if="openCache" :include="getCaches">
           <component :is="Component" :key="route.fullPath" />
         </keep-alive>
-        <component v-else :is="Component" :key="route.fullPath" />
+        <div v-else :key="route.name">
+          <component :is="Component" :key="route.fullPath" />
+        </div>
       </transition>
     </template>
   </RouterView>