fix: 一些基本功能
This commit is contained in:
32
apps/web-antd/src/components/form/component-map.ts
Normal file
32
apps/web-antd/src/components/form/component-map.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import type { CustomComponentType } from './types';
|
||||
|
||||
import type { Component } from 'vue';
|
||||
|
||||
import { getFileNameWithoutExtension, toPascalCase } from '#/util/tool';
|
||||
|
||||
const componentMap = new Map<CustomComponentType | string, Component>();
|
||||
// import.meta.glob() 直接引入所有的模块 Vite 独有的功能
|
||||
const modules = import.meta.glob(
|
||||
['./components/**/*.vue', '../../views/**/components/form/*.vue'],
|
||||
{ eager: true },
|
||||
);
|
||||
// 加入到路由集合中
|
||||
Object.keys(modules).forEach((key) => {
|
||||
if (!key.includes('-ignore')) {
|
||||
const mod = (modules as any)[key].default || {};
|
||||
// ./components/ApiDict.vue
|
||||
// 获取ApiDict
|
||||
const compName = getFileNameWithoutExtension(key);
|
||||
componentMap.set(toPascalCase(compName), mod);
|
||||
}
|
||||
});
|
||||
/**
|
||||
* 注册组件
|
||||
* @param components
|
||||
*/
|
||||
export const registerComponent = (components: any) => {
|
||||
componentMap.forEach((value, key) => {
|
||||
components[key] = value as Component;
|
||||
});
|
||||
};
|
||||
export { componentMap };
|
||||
62
apps/web-antd/src/components/form/components/avatar.vue
Normal file
62
apps/web-antd/src/components/form/components/avatar.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core';
|
||||
import { Upload } from 'ant-design-vue';
|
||||
|
||||
import { uploadFile } from '#/api/core/upload';
|
||||
import { Icon } from '#/components/icon';
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(['update:value']);
|
||||
const mValue = useVModel(props, 'value', emits, {
|
||||
defaultValue: props.value,
|
||||
passive: true,
|
||||
});
|
||||
const customRequest = (e: any) => {
|
||||
uploadFile({
|
||||
file: e.file,
|
||||
}).then((data: any) => {
|
||||
mValue.value = data.url;
|
||||
});
|
||||
};
|
||||
const handleRemove = (e: Event) => {
|
||||
e.stopPropagation();
|
||||
mValue.value = '';
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<Upload
|
||||
:custom-request="customRequest"
|
||||
:show-upload-list="false"
|
||||
list-type="picture-card"
|
||||
>
|
||||
<div v-if="mValue" class="m-avatar-wrap">
|
||||
<Icon
|
||||
class="m-avatar-icon-delete"
|
||||
icon="ant-design:delete-outlined"
|
||||
@click="handleRemove"
|
||||
/>
|
||||
<img :src="value" width="100%" />
|
||||
</div>
|
||||
<Icon v-else icon="ant-design:plus-outlined" />
|
||||
</Upload>
|
||||
</template>
|
||||
<style lang="less" scoped>
|
||||
.m-avatar-wrap {
|
||||
position: relative;
|
||||
height: 102px;
|
||||
.m-avatar-icon-delete {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
162
apps/web-antd/src/components/form/components/upload.vue
Normal file
162
apps/web-antd/src/components/form/components/upload.vue
Normal file
@@ -0,0 +1,162 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, type PropType, ref, useAttrs, watch } from 'vue';
|
||||
|
||||
import { useAccessStore } from '@vben/stores';
|
||||
|
||||
import { Button } from 'ant-design-vue';
|
||||
import {
|
||||
message,
|
||||
Upload,
|
||||
type UploadChangeParam,
|
||||
type UploadFile,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
import { getFileInfoByIds } from '#/api/core/upload';
|
||||
import { Icon } from '#/components/icon';
|
||||
import { omit } from '#/util/tool';
|
||||
|
||||
defineOptions({
|
||||
name: 'Upload',
|
||||
inheritAttrs: false,
|
||||
});
|
||||
const props = defineProps({
|
||||
value: {
|
||||
// 文件id,多个使用英文逗号分割
|
||||
type: [String] as PropType<string>,
|
||||
default: undefined,
|
||||
},
|
||||
action: {
|
||||
// 上传的地址
|
||||
type: String,
|
||||
default: `${import.meta.env.VITE_GLOB_API_URL}/sys/fileInfo/upload`,
|
||||
},
|
||||
headers: {
|
||||
// 上传请求的 headers
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
disabled: {
|
||||
// 是否禁用
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
listType: {
|
||||
// 上传类型
|
||||
type: String as PropType<'picture' | 'picture-card' | 'text'>,
|
||||
default: 'text',
|
||||
},
|
||||
maxCount: {
|
||||
// 最大上传数量
|
||||
type: Number,
|
||||
default: undefined,
|
||||
},
|
||||
uploadName: {
|
||||
// 文件上传字段名,name被字段名覆写了,要换成uploadName
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
separator: {
|
||||
// 文件id分隔符
|
||||
type: String,
|
||||
default: ',',
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(['update:modelValue']);
|
||||
const accessStore = useAccessStore();
|
||||
const fileList = ref<UploadFile[]>([]);
|
||||
const attrs = useAttrs();
|
||||
const bindProps = computed(() => {
|
||||
return {
|
||||
...omit(attrs, ['onChange', 'onInput', 'onBlur', 'name']),
|
||||
...props,
|
||||
name: props.uploadName || 'file',
|
||||
};
|
||||
});
|
||||
const _getFileInfoByIds = (val: string | string[] | undefined) => {
|
||||
if (!val) return;
|
||||
getFileInfoByIds({
|
||||
fileInfoIds: val,
|
||||
}).then((res) => {
|
||||
fileList.value = res || [];
|
||||
});
|
||||
};
|
||||
const mValue = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(val) {
|
||||
emits('update:modelValue', val);
|
||||
},
|
||||
});
|
||||
const mHeaders = {
|
||||
Authorization: `Bearer ${accessStore.accessToken}`,
|
||||
...props.headers,
|
||||
};
|
||||
const handleChange = (info: UploadChangeParam) => {
|
||||
if (info.file.status === 'done') {
|
||||
// 更新file-list当前file的uid
|
||||
fileList.value = fileList.value.map((item) => {
|
||||
if (item.uid === info.file.uid) {
|
||||
return {
|
||||
...item,
|
||||
uid: info.file.response.data.fileInfoId,
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
mValue.value = fileList.value
|
||||
.map((item) => {
|
||||
return item.uid;
|
||||
})
|
||||
.join(props.separator);
|
||||
} else if (info.file.status === 'error') {
|
||||
message.error(`${info.file.name} file upload failed.`);
|
||||
}
|
||||
};
|
||||
const handleRemove = (file: any) => {
|
||||
mValue.value = fileList.value
|
||||
.filter((item: any) => item.uid !== file.uid)
|
||||
.map((item: any) => item.uid)
|
||||
.join(props.separator);
|
||||
return true;
|
||||
};
|
||||
watch(
|
||||
() => props.value,
|
||||
(val) => {
|
||||
_getFileInfoByIds(val);
|
||||
},
|
||||
);
|
||||
onMounted(() => {
|
||||
_getFileInfoByIds(props.value);
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<Upload
|
||||
v-model:file-list="fileList"
|
||||
v-bind="bindProps"
|
||||
:action="action"
|
||||
:disabled="disabled"
|
||||
:headers="mHeaders"
|
||||
:list-type="listType"
|
||||
:max-count="maxCount"
|
||||
@change="handleChange"
|
||||
@remove="handleRemove"
|
||||
>
|
||||
<template #default>
|
||||
<Icon
|
||||
v-if="listType === 'picture-card'"
|
||||
:size="24"
|
||||
icon="ant-design:plus-outlined"
|
||||
/>
|
||||
<Button v-else>
|
||||
上传文件
|
||||
<template #icon>
|
||||
<Icon icon="ant-design:cloud-upload-outlined" />
|
||||
</template>
|
||||
</Button>
|
||||
</template>
|
||||
<template v-for="item in Object.keys($slots)" #[item]="data">
|
||||
<slot :name="item" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
</Upload>
|
||||
</template>
|
||||
7
apps/web-antd/src/components/form/index.ts
Normal file
7
apps/web-antd/src/components/form/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
// export { default as ApiCheckboxGroup } from './components/api-checkbox-group.vue';
|
||||
// export { default as ApiDict } from './components/api-dict.vue';
|
||||
// export { default as ApiRadioGroup } from './components/api-radio-group.vue';
|
||||
// export { default as ApiSelect } from './components/api-select.vue';
|
||||
// export { default as ApiTreeSelect } from './components/api-tree-select.vue';
|
||||
// export { default as IconPicker } from './components/icon-picker.vue';
|
||||
export { default as Upload } from './components/upload.vue';
|
||||
7
apps/web-antd/src/components/form/types/index.d.ts
vendored
Normal file
7
apps/web-antd/src/components/form/types/index.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export type CustomComponentType =
|
||||
| 'ApiCheckboxGroup'
|
||||
| 'ApiDict'
|
||||
| 'ApiRadioGroup'
|
||||
| 'ApiSelect'
|
||||
| 'ApiTreeSelect'
|
||||
| 'IconPicker';
|
||||
Reference in New Issue
Block a user