Commit 3f6920f7a9775fc06a34dead90b1724b23b7759c
1 parent
fa828fd9
perf(component): optimize tree and upload components
Showing
17 changed files
with
156 additions
and
154 deletions
src/components/Tree/index.ts
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
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
src/components/Upload/index.ts
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
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 '/@/hooks/web/useI18n'; |
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); | ... | ... |