提交 3f6920f7 编写于 作者: V Vben

perf(component): optimize tree and upload components

上级 fa828fd9
......@@ -2,4 +2,4 @@ import BasicTree from './src/Tree.vue';
export { BasicTree };
export type { ContextMenuItem } from '/@/hooks/web/useContextMenu';
export * from './src/types';
export * from './src/typing';
<script lang="tsx">
import type { ReplaceFields, Keys, CheckKeys, TreeActionType, TreeItem } from './types';
import type { ReplaceFields, Keys, CheckKeys, TreeActionType, TreeItem } from './typing';
import {
defineComponent,
......@@ -30,7 +30,7 @@
import { basicProps } from './props';
import { CreateContextOptions } from '/@/components/ContextMenu';
import { CheckEvent } from './types';
import { CheckEvent } from './typing';
interface State {
expandedKeys: Keys;
......
......@@ -43,7 +43,14 @@
import { useI18n } from '/@/hooks/web/useI18n';
import { useDebounceFn } from '@vueuse/core';
import { ToolbarEnum } from './enum';
enum ToolbarEnum {
SELECT_ALL,
UN_SELECT_ALL,
EXPAND_ALL,
UN_EXPAND_ALL,
CHECK_STRICTLY,
CHECK_UN_STRICTLY,
}
interface MenuInfo {
key: ToolbarEnum;
......
export enum ToolbarEnum {
SELECT_ALL,
UN_SELECT_ALL,
EXPAND_ALL,
UN_EXPAND_ALL,
CHECK_STRICTLY,
CHECK_UN_STRICTLY,
}
import type { PropType } from 'vue';
import type { ReplaceFields, ActionItem, Keys, CheckKeys, ContextMenuOptions } from './types';
import type { ReplaceFields, ActionItem, Keys, CheckKeys, ContextMenuOptions } from './typing';
import type { ContextMenuItem } from '/@/hooks/web/useContextMenu';
import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
import { propTypes } from '/@/utils/propTypes';
......
import type { InsertNodeParams, Keys, ReplaceFields } from './types';
import type { InsertNodeParams, Keys, ReplaceFields } from './typing';
import type { Ref, ComputedRef } from 'vue';
import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
......
export { default as BasicUpload } from './src/BasicUpload.vue';
import { withInstall } from '/@/utils';
import basicUpload from './src/BasicUpload.vue';
export const BasicUpload = withInstall(basicUpload);
......@@ -7,14 +7,14 @@
<Tooltip placement="bottom" v-if="showPreview">
<template #title>
{{ t('component.upload.uploaded') }}
<template v-if="fileListRef.length">
{{ fileListRef.length }}
<template v-if="fileList.length">
{{ fileList.length }}
</template>
</template>
<a-button @click="openPreviewModal">
<Icon icon="bi:eye" />
<template v-if="fileListRef.length && showPreviewNumber">
{{ fileListRef.length }}
<template v-if="fileList.length && showPreviewNumber">
{{ fileList.length }}
</template>
</a-button>
</Tooltip>
......@@ -22,13 +22,14 @@
<UploadModal
v-bind="bindValue"
:previewFileList="fileListRef"
:previewFileList="fileList"
@register="registerUploadModal"
@change="handleChange"
@delete="handleDelete"
/>
<UploadPreviewModal
:value="fileListRef"
:value="fileList"
@register="registerPreviewModal"
@list-change="handlePreviewChange"
/>
......@@ -36,14 +37,11 @@
</template>
<script lang="ts">
import { defineComponent, ref, watch, unref, computed } from 'vue';
import UploadModal from './UploadModal.vue';
import UploadPreviewModal from './UploadPreviewModal.vue';
import Icon from '/@/components/Icon';
import { Icon } from '/@/components/Icon';
import { Tooltip } from 'ant-design-vue';
import { useModal } from '/@/components/Modal';
import { uploadContainerProps } from './props';
import { omit } from 'lodash-es';
import { useI18n } from '/@/hooks/web/useI18n';
......@@ -52,7 +50,7 @@
name: 'BasicUpload',
components: { UploadModal, UploadPreviewModal, Icon, Tooltip },
props: uploadContainerProps,
emits: ['change'],
emits: ['change', 'delete'],
setup(props, { emit, attrs }) {
const { t } = useI18n();
......@@ -62,12 +60,12 @@
// 预览modal
const [registerPreviewModal, { openModal: openPreviewModal }] = useModal();
const fileListRef = ref<string[]>([]);
const fileList = ref<string[]>([]);
const showPreview = computed(() => {
const { emptyHidePreview } = props;
if (!emptyHidePreview) return true;
return emptyHidePreview ? fileListRef.value.length > 0 : true;
return emptyHidePreview ? fileList.value.length > 0 : true;
});
const bindValue = computed(() => {
......@@ -78,21 +76,25 @@
watch(
() => props.value,
(value = []) => {
fileListRef.value = value;
fileList.value = value;
},
{ immediate: true }
);
// 上传modal保存操作
function handleChange(urls: string[]) {
fileListRef.value = [...unref(fileListRef), ...(urls || [])];
emit('change', fileListRef.value);
fileList.value = [...unref(fileList), ...(urls || [])];
emit('change', fileList.value);
}
// 预览modal保存操作
function handlePreviewChange(urls: string[]) {
fileListRef.value = [...(urls || [])];
emit('change', fileListRef.value);
fileList.value = [...(urls || [])];
emit('change', fileList.value);
}
function handleDelete(record: Recordable) {
emit('delete', record);
}
return {
......@@ -102,9 +104,10 @@
handlePreviewChange,
registerPreviewModal,
openPreviewModal,
fileListRef,
fileList,
showPreview,
bindValue,
handleDelete,
t,
};
},
......
.file-table {
width: 100%;
border-collapse: collapse;
.center {
text-align: center;
}
.left {
text-align: left;
}
.right {
text-align: right;
}
&-th,
&-td {
padding: 12px 8px;
}
thead {
background-color: @background-color-light;
}
table,
td,
th {
border: 1px solid @border-color-base;
}
}
import { defineComponent, CSSProperties, watch, nextTick } from 'vue';
import { fileListProps } from './props';
import { isFunction } from '/@/utils/is';
import './FileList.less';
import { useModalContext } from '/@/components/Modal/src/hooks/useModalContext';
export default defineComponent({
name: 'FileList',
props: fileListProps,
setup(props) {
const modalFn = useModalContext();
watch(
() => props.dataSource,
() => {
nextTick(() => {
modalFn?.redoModalHeight?.();
});
}
);
return () => {
const { columns, actionColumn, dataSource } = props;
const columnList = [...columns, actionColumn];
return (
<table class="file-table">
<colgroup>
{columnList.map((item) => {
const { width = 0, dataIndex } = item;
const style: CSSProperties = {
width: `${width}px`,
minWidth: `${width}px`,
};
return <col style={width ? style : {}} key={dataIndex} />;
})}
</colgroup>
<thead>
<tr class="file-table-tr">
{columnList.map((item) => {
const { title = '', align = 'center', dataIndex } = item;
return (
<th class={['file-table-th', align]} key={dataIndex}>
{title}
</th>
);
})}
</tr>
</thead>
<tbody>
{dataSource.map((record = {}, index) => {
return (
<tr class="file-table-tr" key={`${index + record.name || ''}`}>
{columnList.map((item) => {
const { dataIndex = '', customRender, align = 'center' } = item;
const render = customRender && isFunction(customRender);
return (
<td class={['file-table-td', align]} key={dataIndex}>
{render
? customRender?.({ text: record[dataIndex], record })
: record[dataIndex]}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
);
};
},
});
<script lang="tsx">
import { defineComponent, CSSProperties, watch, nextTick } from 'vue';
import { fileListProps } from './props';
import { isFunction } from '/@/utils/is';
import { useModalContext } from '/@/components/Modal/src/hooks/useModalContext';
export default defineComponent({
name: 'FileList',
props: fileListProps,
setup(props) {
const modalFn = useModalContext();
watch(
() => props.dataSource,
() => {
nextTick(() => {
modalFn?.redoModalHeight?.();
});
}
);
return () => {
const { columns, actionColumn, dataSource } = props;
const columnList = [...columns, actionColumn];
return (
<table class="file-table">
<colgroup>
{columnList.map((item) => {
const { width = 0, dataIndex } = item;
const style: CSSProperties = {
width: `${width}px`,
minWidth: `${width}px`,
};
return <col style={width ? style : {}} key={dataIndex} />;
})}
</colgroup>
<thead>
<tr class="file-table-tr">
{columnList.map((item) => {
const { title = '', align = 'center', dataIndex } = item;
return (
<th class={['file-table-th', align]} key={dataIndex}>
{title}
</th>
);
})}
</tr>
</thead>
<tbody>
{dataSource.map((record = {}, index) => {
return (
<tr class="file-table-tr" key={`${index + record.name || ''}`}>
{columnList.map((item) => {
const { dataIndex = '', customRender, align = 'center' } = item;
const render = customRender && isFunction(customRender);
return (
<td class={['file-table-td', align]} key={dataIndex}>
{render
? customRender?.({ text: record[dataIndex], record })
: record[dataIndex]}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
);
};
},
});
</script>
<style lang="less">
.file-table {
width: 100%;
border-collapse: collapse;
.center {
text-align: center;
}
.left {
text-align: left;
}
.right {
text-align: right;
}
&-th,
&-td {
padding: 12px 8px;
}
thead {
background-color: @background-color-light;
}
table,
td,
th {
border: 1px solid @border-color-base;
}
}
</style>
......@@ -50,7 +50,7 @@
import { useUploadType } from './useUpload';
import { useMessage } from '/@/hooks/web/useMessage';
// types
import { FileItem, UploadResultStatus } from './types';
import { FileItem, UploadResultStatus } from './typing';
import { basicProps } from './props';
import { createTableColumns, createActionColumn } from './data';
// utils
......@@ -58,9 +58,9 @@
import { buildUUID } from '/@/utils/uuid';
import { isFunction } from '/@/utils/is';
import { warn } from '/@/utils/log';
import FileList from './FileList';
import FileList from './FileList.vue';
import { useI18n } from '/@/hooks/web/useI18n';
export default defineComponent({
components: { BasicModal, Upload, Alert, FileList },
props: {
......@@ -70,20 +70,20 @@
default: () => [],
},
},
emits: ['change', 'register'],
emits: ['change', 'register', 'delete'],
setup(props, { emit }) {
const { t } = useI18n();
const state = reactive<{ fileList: FileItem[] }>({
fileList: [],
});
// 是否正在上传
const isUploadingRef = ref(false);
const fileListRef = ref<FileItem[]>([]);
const state = reactive<{ fileList: FileItem[] }>({
fileList: [],
});
const { accept, helpText, maxNumber, maxSize } = toRefs(props);
const { t } = useI18n();
const [register, { closeModal }] = useModalInner();
const { accept, helpText, maxNumber, maxSize } = toRefs(props);
const { getAccept, getStringAccept, getHelpText } = useUploadType({
acceptRef: accept,
helpTextRef: helpText,
......@@ -162,10 +162,12 @@
}
return false;
}
// 删除
function handleRemove(record: FileItem) {
const index = fileListRef.value.findIndex((item) => item.uuid === record.uuid);
index !== -1 && fileListRef.value.splice(index, 1);
emit('delete', record);
}
// 预览
......
......@@ -12,18 +12,15 @@
</template>
<script lang="ts">
import { defineComponent, watch, ref } from 'vue';
// import { BasicTable, useTable } from '/@/components/Table';
import FileList from './FileList';
import FileList from './FileList.vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { previewProps } from './props';
import { PreviewFileItem } from './types';
import { PreviewFileItem } from './typing';
import { downloadByUrl } from '/@/utils/file/download';
import { createPreviewColumns, createPreviewActionColumn } from './data';
import { useI18n } from '/@/hooks/web/useI18n';
export default defineComponent({
components: { BasicModal, FileList },
props: previewProps,
......
import type { BasicColumn, ActionItem } from '/@/components/Table';
import { FileItem, PreviewFileItem, UploadResultStatus } from './types';
import { FileItem, PreviewFileItem, UploadResultStatus } from './typing';
import {
// checkImgType,
isImgTypeByName,
} from './helper';
import { Progress, Tag } from 'ant-design-vue';
import TableAction from '/@/components/Table/src/components/TableAction.vue';
import ThumbUrl from './ThumbUrl.vue';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n();
// 文件上传列表
......
import type { PropType } from 'vue';
import { FileBasicColumn } from './types';
import { FileBasicColumn } from './typing';
export const basicProps = {
helpText: {
......
......@@ -3,20 +3,17 @@ import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n();
export function useUploadType({
acceptRef,
// uploadTypeRef,
helpTextRef,
maxNumberRef,
maxSizeRef,
}: {
acceptRef: Ref<string[]>;
// uploadTypeRef: Ref<UploadTypeEnum>;
helpTextRef: Ref<string>;
maxNumberRef: Ref<number>;
maxSizeRef: Ref<number>;
}) {
// 文件类型限制
const getAccept = computed(() => {
// const uploadType = unref(uploadTypeRef);
const accept = unref(acceptRef);
if (accept && accept.length > 0) {
return accept;
......@@ -28,6 +25,7 @@ export function useUploadType({
.map((item) => `.${item}`)
.join(',');
});
// 支持jpg、jpeg、png格式,不超过2M,最多可选择10张图片,。
const getHelpText = computed(() => {
const helpText = unref(helpTextRef);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册