Commit 3f6920f7a9775fc06a34dead90b1724b23b7759c

Authored by Vben
1 parent fa828fd9

perf(component): optimize tree and upload components

src/components/Tree/index.ts
... ... @@ -2,4 +2,4 @@ import BasicTree from './src/Tree.vue';
2 2  
3 3 export { BasicTree };
4 4 export type { ContextMenuItem } from '/@/hooks/web/useContextMenu';
5   -export * from './src/types';
  5 +export * from './src/typing';
... ...
src/components/Tree/src/Tree.vue
1 1 <script lang="tsx">
2   - import type { ReplaceFields, Keys, CheckKeys, TreeActionType, TreeItem } from './types';
  2 + import type { ReplaceFields, Keys, CheckKeys, TreeActionType, TreeItem } from './typing';
3 3  
4 4 import {
5 5 defineComponent,
... ... @@ -30,7 +30,7 @@
30 30 import { basicProps } from './props';
31 31 import { CreateContextOptions } from '/@/components/ContextMenu';
32 32  
33   - import { CheckEvent } from './types';
  33 + import { CheckEvent } from './typing';
34 34  
35 35 interface State {
36 36 expandedKeys: Keys;
... ...
src/components/Tree/src/TreeHeader.vue
... ... @@ -43,7 +43,14 @@
43 43 import { useI18n } from '/@/hooks/web/useI18n';
44 44 import { useDebounceFn } from '@vueuse/core';
45 45  
46   - import { ToolbarEnum } from './enum';
  46 + enum ToolbarEnum {
  47 + SELECT_ALL,
  48 + UN_SELECT_ALL,
  49 + EXPAND_ALL,
  50 + UN_EXPAND_ALL,
  51 + CHECK_STRICTLY,
  52 + CHECK_UN_STRICTLY,
  53 + }
47 54  
48 55 interface MenuInfo {
49 56 key: ToolbarEnum;
... ...
src/components/Tree/src/enum.ts deleted 100644 → 0
1   -export enum ToolbarEnum {
2   - SELECT_ALL,
3   - UN_SELECT_ALL,
4   - EXPAND_ALL,
5   - UN_EXPAND_ALL,
6   - CHECK_STRICTLY,
7   - CHECK_UN_STRICTLY,
8   -}
src/components/Tree/src/props.ts
1 1 import type { PropType } from 'vue';
2   -import type { ReplaceFields, ActionItem, Keys, CheckKeys, ContextMenuOptions } from './types';
  2 +import type { ReplaceFields, ActionItem, Keys, CheckKeys, ContextMenuOptions } from './typing';
3 3 import type { ContextMenuItem } from '/@/hooks/web/useContextMenu';
4 4 import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
5 5 import { propTypes } from '/@/utils/propTypes';
... ...
src/components/Tree/src/types.ts renamed to src/components/Tree/src/typing.ts
src/components/Tree/src/useTree.ts
1   -import type { InsertNodeParams, Keys, ReplaceFields } from './types';
  1 +import type { InsertNodeParams, Keys, ReplaceFields } from './typing';
2 2 import type { Ref, ComputedRef } from 'vue';
3 3 import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
4 4  
... ...
src/components/Upload/index.ts
1   -export { default as BasicUpload } from './src/BasicUpload.vue';
  1 +import { withInstall } from '/@/utils';
  2 +import basicUpload from './src/BasicUpload.vue';
  3 +
  4 +export const BasicUpload = withInstall(basicUpload);
... ...
src/components/Upload/src/BasicUpload.vue
... ... @@ -7,14 +7,14 @@
7 7 <Tooltip placement="bottom" v-if="showPreview">
8 8 <template #title>
9 9 {{ t('component.upload.uploaded') }}
10   - <template v-if="fileListRef.length">
11   - {{ fileListRef.length }}
  10 + <template v-if="fileList.length">
  11 + {{ fileList.length }}
12 12 </template>
13 13 </template>
14 14 <a-button @click="openPreviewModal">
15 15 <Icon icon="bi:eye" />
16   - <template v-if="fileListRef.length && showPreviewNumber">
17   - {{ fileListRef.length }}
  16 + <template v-if="fileList.length && showPreviewNumber">
  17 + {{ fileList.length }}
18 18 </template>
19 19 </a-button>
20 20 </Tooltip>
... ... @@ -22,13 +22,14 @@
22 22  
23 23 <UploadModal
24 24 v-bind="bindValue"
25   - :previewFileList="fileListRef"
  25 + :previewFileList="fileList"
26 26 @register="registerUploadModal"
27 27 @change="handleChange"
  28 + @delete="handleDelete"
28 29 />
29 30  
30 31 <UploadPreviewModal
31   - :value="fileListRef"
  32 + :value="fileList"
32 33 @register="registerPreviewModal"
33 34 @list-change="handlePreviewChange"
34 35 />
... ... @@ -36,14 +37,11 @@
36 37 </template>
37 38 <script lang="ts">
38 39 import { defineComponent, ref, watch, unref, computed } from 'vue';
39   -
40 40 import UploadModal from './UploadModal.vue';
41 41 import UploadPreviewModal from './UploadPreviewModal.vue';
42   - import Icon from '/@/components/Icon';
  42 + import { Icon } from '/@/components/Icon';
43 43 import { Tooltip } from 'ant-design-vue';
44   -
45 44 import { useModal } from '/@/components/Modal';
46   -
47 45 import { uploadContainerProps } from './props';
48 46 import { omit } from 'lodash-es';
49 47 import { useI18n } from '/@/hooks/web/useI18n';
... ... @@ -52,7 +50,7 @@
52 50 name: 'BasicUpload',
53 51 components: { UploadModal, UploadPreviewModal, Icon, Tooltip },
54 52 props: uploadContainerProps,
55   - emits: ['change'],
  53 + emits: ['change', 'delete'],
56 54  
57 55 setup(props, { emit, attrs }) {
58 56 const { t } = useI18n();
... ... @@ -62,12 +60,12 @@
62 60 // 预览modal
63 61 const [registerPreviewModal, { openModal: openPreviewModal }] = useModal();
64 62  
65   - const fileListRef = ref<string[]>([]);
  63 + const fileList = ref<string[]>([]);
66 64  
67 65 const showPreview = computed(() => {
68 66 const { emptyHidePreview } = props;
69 67 if (!emptyHidePreview) return true;
70   - return emptyHidePreview ? fileListRef.value.length > 0 : true;
  68 + return emptyHidePreview ? fileList.value.length > 0 : true;
71 69 });
72 70  
73 71 const bindValue = computed(() => {
... ... @@ -78,21 +76,25 @@
78 76 watch(
79 77 () => props.value,
80 78 (value = []) => {
81   - fileListRef.value = value;
  79 + fileList.value = value;
82 80 },
83 81 { immediate: true }
84 82 );
85 83  
86 84 // 上传modal保存操作
87 85 function handleChange(urls: string[]) {
88   - fileListRef.value = [...unref(fileListRef), ...(urls || [])];
89   - emit('change', fileListRef.value);
  86 + fileList.value = [...unref(fileList), ...(urls || [])];
  87 + emit('change', fileList.value);
90 88 }
91 89  
92 90 // 预览modal保存操作
93 91 function handlePreviewChange(urls: string[]) {
94   - fileListRef.value = [...(urls || [])];
95   - emit('change', fileListRef.value);
  92 + fileList.value = [...(urls || [])];
  93 + emit('change', fileList.value);
  94 + }
  95 +
  96 + function handleDelete(record: Recordable) {
  97 + emit('delete', record);
96 98 }
97 99  
98 100 return {
... ... @@ -102,9 +104,10 @@
102 104 handlePreviewChange,
103 105 registerPreviewModal,
104 106 openPreviewModal,
105   - fileListRef,
  107 + fileList,
106 108 showPreview,
107 109 bindValue,
  110 + handleDelete,
108 111 t,
109 112 };
110 113 },
... ...
src/components/Upload/src/FileList.less deleted 100644 → 0
1   -.file-table {
2   - width: 100%;
3   - border-collapse: collapse;
4   -
5   - .center {
6   - text-align: center;
7   - }
8   -
9   - .left {
10   - text-align: left;
11   - }
12   -
13   - .right {
14   - text-align: right;
15   - }
16   -
17   - &-th,
18   - &-td {
19   - padding: 12px 8px;
20   - }
21   -
22   - thead {
23   - background-color: @background-color-light;
24   - }
25   -
26   - table,
27   - td,
28   - th {
29   - border: 1px solid @border-color-base;
30   - }
31   -}
src/components/Upload/src/FileList.tsx renamed to src/components/Upload/src/FileList.vue
1   -import { defineComponent, CSSProperties, watch, nextTick } from 'vue';
2   -import { fileListProps } from './props';
3   -import { isFunction } from '/@/utils/is';
4   -import './FileList.less';
5   -import { useModalContext } from '/@/components/Modal/src/hooks/useModalContext';
  1 +<script lang="tsx">
  2 + import { defineComponent, CSSProperties, watch, nextTick } from 'vue';
  3 + import { fileListProps } from './props';
  4 + import { isFunction } from '/@/utils/is';
  5 + import { useModalContext } from '/@/components/Modal/src/hooks/useModalContext';
6 6  
7   -export default defineComponent({
8   - name: 'FileList',
9   - props: fileListProps,
10   - setup(props) {
11   - const modalFn = useModalContext();
12   - watch(
13   - () => props.dataSource,
14   - () => {
15   - nextTick(() => {
16   - modalFn?.redoModalHeight?.();
17   - });
18   - }
19   - );
20   - return () => {
21   - const { columns, actionColumn, dataSource } = props;
22   - const columnList = [...columns, actionColumn];
23   - return (
24   - <table class="file-table">
25   - <colgroup>
26   - {columnList.map((item) => {
27   - const { width = 0, dataIndex } = item;
28   -
29   - const style: CSSProperties = {
30   - width: `${width}px`,
31   - minWidth: `${width}px`,
32   - };
33   -
34   - return <col style={width ? style : {}} key={dataIndex} />;
35   - })}
36   - </colgroup>
37   - <thead>
38   - <tr class="file-table-tr">
  7 + export default defineComponent({
  8 + name: 'FileList',
  9 + props: fileListProps,
  10 + setup(props) {
  11 + const modalFn = useModalContext();
  12 + watch(
  13 + () => props.dataSource,
  14 + () => {
  15 + nextTick(() => {
  16 + modalFn?.redoModalHeight?.();
  17 + });
  18 + }
  19 + );
  20 + return () => {
  21 + const { columns, actionColumn, dataSource } = props;
  22 + const columnList = [...columns, actionColumn];
  23 + return (
  24 + <table class="file-table">
  25 + <colgroup>
39 26 {columnList.map((item) => {
40   - const { title = '', align = 'center', dataIndex } = item;
  27 + const { width = 0, dataIndex } = item;
  28 + const style: CSSProperties = {
  29 + width: `${width}px`,
  30 + minWidth: `${width}px`,
  31 + };
  32 + return <col style={width ? style : {}} key={dataIndex} />;
  33 + })}
  34 + </colgroup>
  35 + <thead>
  36 + <tr class="file-table-tr">
  37 + {columnList.map((item) => {
  38 + const { title = '', align = 'center', dataIndex } = item;
  39 + return (
  40 + <th class={['file-table-th', align]} key={dataIndex}>
  41 + {title}
  42 + </th>
  43 + );
  44 + })}
  45 + </tr>
  46 + </thead>
  47 + <tbody>
  48 + {dataSource.map((record = {}, index) => {
41 49 return (
42   - <th class={['file-table-th', align]} key={dataIndex}>
43   - {title}
44   - </th>
  50 + <tr class="file-table-tr" key={`${index + record.name || ''}`}>
  51 + {columnList.map((item) => {
  52 + const { dataIndex = '', customRender, align = 'center' } = item;
  53 + const render = customRender && isFunction(customRender);
  54 + return (
  55 + <td class={['file-table-td', align]} key={dataIndex}>
  56 + {render
  57 + ? customRender?.({ text: record[dataIndex], record })
  58 + : record[dataIndex]}
  59 + </td>
  60 + );
  61 + })}
  62 + </tr>
45 63 );
46 64 })}
47   - </tr>
48   - </thead>
49   - <tbody>
50   - {dataSource.map((record = {}, index) => {
51   - return (
52   - <tr class="file-table-tr" key={`${index + record.name || ''}`}>
53   - {columnList.map((item) => {
54   - const { dataIndex = '', customRender, align = 'center' } = item;
55   - const render = customRender && isFunction(customRender);
56   - return (
57   - <td class={['file-table-td', align]} key={dataIndex}>
58   - {render
59   - ? customRender?.({ text: record[dataIndex], record })
60   - : record[dataIndex]}
61   - </td>
62   - );
63   - })}
64   - </tr>
65   - );
66   - })}
67   - </tbody>
68   - </table>
69   - );
70   - };
71   - },
72   -});
  65 + </tbody>
  66 + </table>
  67 + );
  68 + };
  69 + },
  70 + });
  71 +</script>
  72 +<style lang="less">
  73 + .file-table {
  74 + width: 100%;
  75 + border-collapse: collapse;
  76 +
  77 + .center {
  78 + text-align: center;
  79 + }
  80 +
  81 + .left {
  82 + text-align: left;
  83 + }
  84 +
  85 + .right {
  86 + text-align: right;
  87 + }
  88 +
  89 + &-th,
  90 + &-td {
  91 + padding: 12px 8px;
  92 + }
  93 +
  94 + thead {
  95 + background-color: @background-color-light;
  96 + }
  97 +
  98 + table,
  99 + td,
  100 + th {
  101 + border: 1px solid @border-color-base;
  102 + }
  103 + }
  104 +</style>
... ...
src/components/Upload/src/UploadModal.vue
... ... @@ -50,7 +50,7 @@
50 50 import { useUploadType } from './useUpload';
51 51 import { useMessage } from '/@/hooks/web/useMessage';
52 52 // types
53   - import { FileItem, UploadResultStatus } from './types';
  53 + import { FileItem, UploadResultStatus } from './typing';
54 54 import { basicProps } from './props';
55 55 import { createTableColumns, createActionColumn } from './data';
56 56 // utils
... ... @@ -58,9 +58,9 @@
58 58 import { buildUUID } from '/@/utils/uuid';
59 59 import { isFunction } from '/@/utils/is';
60 60 import { warn } from '/@/utils/log';
61   - import FileList from './FileList';
62   -
  61 + import FileList from './FileList.vue';
63 62 import { useI18n } from '/@/hooks/web/useI18n';
  63 +
64 64 export default defineComponent({
65 65 components: { BasicModal, Upload, Alert, FileList },
66 66 props: {
... ... @@ -70,20 +70,20 @@
70 70 default: () => [],
71 71 },
72 72 },
73   - emits: ['change', 'register'],
  73 + emits: ['change', 'register', 'delete'],
74 74 setup(props, { emit }) {
75   - const { t } = useI18n();
  75 + const state = reactive<{ fileList: FileItem[] }>({
  76 + fileList: [],
  77 + });
76 78  
77 79 // 是否正在上传
78 80 const isUploadingRef = ref(false);
79 81 const fileListRef = ref<FileItem[]>([]);
80   - const state = reactive<{ fileList: FileItem[] }>({
81   - fileList: [],
82   - });
  82 + const { accept, helpText, maxNumber, maxSize } = toRefs(props);
83 83  
  84 + const { t } = useI18n();
84 85 const [register, { closeModal }] = useModalInner();
85 86  
86   - const { accept, helpText, maxNumber, maxSize } = toRefs(props);
87 87 const { getAccept, getStringAccept, getHelpText } = useUploadType({
88 88 acceptRef: accept,
89 89 helpTextRef: helpText,
... ... @@ -162,10 +162,12 @@
162 162 }
163 163 return false;
164 164 }
  165 +
165 166 // 删除
166 167 function handleRemove(record: FileItem) {
167 168 const index = fileListRef.value.findIndex((item) => item.uuid === record.uuid);
168 169 index !== -1 && fileListRef.value.splice(index, 1);
  170 + emit('delete', record);
169 171 }
170 172  
171 173 // 预览
... ...
src/components/Upload/src/UploadPreviewModal.vue
... ... @@ -12,18 +12,15 @@
12 12 </template>
13 13 <script lang="ts">
14 14 import { defineComponent, watch, ref } from 'vue';
15   -
16 15 // import { BasicTable, useTable } from '/@/components/Table';
17   - import FileList from './FileList';
18   -
  16 + import FileList from './FileList.vue';
19 17 import { BasicModal, useModalInner } from '/@/components/Modal';
20 18 import { previewProps } from './props';
21   - import { PreviewFileItem } from './types';
  19 + import { PreviewFileItem } from './typing';
22 20 import { downloadByUrl } from '/@/utils/file/download';
23   -
24 21 import { createPreviewColumns, createPreviewActionColumn } from './data';
25   -
26 22 import { useI18n } from '/@/hooks/web/useI18n';
  23 +
27 24 export default defineComponent({
28 25 components: { BasicModal, FileList },
29 26 props: previewProps,
... ...
src/components/Upload/src/data.tsx
1 1 import type { BasicColumn, ActionItem } from '/@/components/Table';
2   -
3   -import { FileItem, PreviewFileItem, UploadResultStatus } from './types';
  2 +import { FileItem, PreviewFileItem, UploadResultStatus } from './typing';
4 3 import {
5 4 // checkImgType,
6 5 isImgTypeByName,
7 6 } from './helper';
8 7 import { Progress, Tag } from 'ant-design-vue';
9   -
10 8 import TableAction from '/@/components/Table/src/components/TableAction.vue';
11 9 import ThumbUrl from './ThumbUrl.vue';
12 10 import { useI18n } from '/@/hooks/web/useI18n';
  11 +
13 12 const { t } = useI18n();
14 13  
15 14 // 文件上传列表
... ...
src/components/Upload/src/props.ts
1 1 import type { PropType } from 'vue';
2   -import { FileBasicColumn } from './types';
  2 +import { FileBasicColumn } from './typing';
3 3  
4 4 export const basicProps = {
5 5 helpText: {
... ...
src/components/Upload/src/types.ts renamed to src/components/Upload/src/typing.ts
src/components/Upload/src/useUpload.ts
... ... @@ -3,20 +3,17 @@ import { useI18n } from &#39;/@/hooks/web/useI18n&#39;;
3 3 const { t } = useI18n();
4 4 export function useUploadType({
5 5 acceptRef,
6   - // uploadTypeRef,
7 6 helpTextRef,
8 7 maxNumberRef,
9 8 maxSizeRef,
10 9 }: {
11 10 acceptRef: Ref<string[]>;
12   - // uploadTypeRef: Ref<UploadTypeEnum>;
13 11 helpTextRef: Ref<string>;
14 12 maxNumberRef: Ref<number>;
15 13 maxSizeRef: Ref<number>;
16 14 }) {
17 15 // 文件类型限制
18 16 const getAccept = computed(() => {
19   - // const uploadType = unref(uploadTypeRef);
20 17 const accept = unref(acceptRef);
21 18 if (accept && accept.length > 0) {
22 19 return accept;
... ... @@ -28,6 +25,7 @@ export function useUploadType({
28 25 .map((item) => `.${item}`)
29 26 .join(',');
30 27 });
  28 +
31 29 // 支持jpg、jpeg、png格式,不超过2M,最多可选择10张图片,。
32 30 const getHelpText = computed(() => {
33 31 const helpText = unref(helpTextRef);
... ...