@vrojs/element-plus 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +56 -0
- package/src/index.ts +13 -0
- package/src/locale/index.ts +3 -0
- package/src/locale/lang/zh-cn.ts +22 -0
- package/src/locale/types.ts +8 -0
- package/src/locale/useLocale.ts +42 -0
- package/src/style/base.scss +2 -0
- package/src/style/css.ts +2 -0
- package/src/style/deps.ts +9 -0
- package/src/style/index.scss +12 -0
- package/src/style/index.ts +2 -0
- package/src/utils/datePickerValueFormat.ts +6 -0
- package/src/utils/index.ts +2 -0
- package/src/vro-el-checkbox-group/README.md +83 -0
- package/src/vro-el-checkbox-group/index.ts +16 -0
- package/src/vro-el-checkbox-group/style/css.ts +2 -0
- package/src/vro-el-checkbox-group/style/deps.ts +2 -0
- package/src/vro-el-checkbox-group/style/index.scss +1 -0
- package/src/vro-el-checkbox-group/style/index.ts +2 -0
- package/src/vro-el-checkbox-group/types.ts +18 -0
- package/src/vro-el-checkbox-group/vro-el-checkbox-group.vue +33 -0
- package/src/vro-el-config-provider/README.md +65 -0
- package/src/vro-el-config-provider/index.ts +16 -0
- package/src/vro-el-config-provider/style/css.ts +2 -0
- package/src/vro-el-config-provider/style/deps.ts +0 -0
- package/src/vro-el-config-provider/style/index.scss +0 -0
- package/src/vro-el-config-provider/style/index.ts +2 -0
- package/src/vro-el-config-provider/types.ts +18 -0
- package/src/vro-el-config-provider/vro-el-config-provider.vue +19 -0
- package/src/vro-el-file-upload/README.md +89 -0
- package/src/vro-el-file-upload/index.ts +17 -0
- package/src/vro-el-file-upload/style/css.ts +2 -0
- package/src/vro-el-file-upload/style/deps.ts +2 -0
- package/src/vro-el-file-upload/style/index.scss +30 -0
- package/src/vro-el-file-upload/style/index.ts +2 -0
- package/src/vro-el-file-upload/types.ts +50 -0
- package/src/vro-el-file-upload/utils.ts +7 -0
- package/src/vro-el-file-upload/vro-el-file-upload.vue +95 -0
- package/src/vro-el-icon/README.md +68 -0
- package/src/vro-el-icon/index.ts +16 -0
- package/src/vro-el-icon/style/css.ts +2 -0
- package/src/vro-el-icon/style/deps.ts +1 -0
- package/src/vro-el-icon/style/index.scss +1 -0
- package/src/vro-el-icon/style/index.ts +2 -0
- package/src/vro-el-icon/types.ts +12 -0
- package/src/vro-el-icon/vro-el-icon.vue +28 -0
- package/src/vro-el-image-upload/README.md +99 -0
- package/src/vro-el-image-upload/index.ts +17 -0
- package/src/vro-el-image-upload/style/css.ts +2 -0
- package/src/vro-el-image-upload/style/deps.ts +4 -0
- package/src/vro-el-image-upload/style/index.scss +55 -0
- package/src/vro-el-image-upload/style/index.ts +2 -0
- package/src/vro-el-image-upload/types.ts +42 -0
- package/src/vro-el-image-upload/utils.ts +7 -0
- package/src/vro-el-image-upload/vro-el-image-upload.vue +134 -0
- package/src/vro-el-schema-form-dialog/README.md +64 -0
- package/src/vro-el-schema-form-dialog/function-call.ts +12 -0
- package/src/vro-el-schema-form-dialog/index.ts +17 -0
- package/src/vro-el-schema-form-dialog/style/css.ts +2 -0
- package/src/vro-el-schema-form-dialog/style/deps.ts +0 -0
- package/src/vro-el-schema-form-dialog/style/index.scss +1 -0
- package/src/vro-el-schema-form-dialog/style/index.ts +2 -0
- package/src/vro-el-schema-form-dialog/types.ts +5 -0
- package/src/vro-el-schema-form-dialog/vro-el-schema-form-dialog.vue +32 -0
- package/src/vro-el-select/README.md +83 -0
- package/src/vro-el-select/index.ts +16 -0
- package/src/vro-el-select/style/css.ts +2 -0
- package/src/vro-el-select/style/deps.ts +2 -0
- package/src/vro-el-select/style/index.scss +1 -0
- package/src/vro-el-select/style/index.ts +2 -0
- package/src/vro-el-select/types.ts +18 -0
- package/src/vro-el-select/vro-el-select.vue +33 -0
- package/src/vro-el-skeleton/README.md +128 -0
- package/src/vro-el-skeleton/index.ts +16 -0
- package/src/vro-el-skeleton/style/css.ts +3 -0
- package/src/vro-el-skeleton/style/deps.ts +3 -0
- package/src/vro-el-skeleton/style/index.scss +24 -0
- package/src/vro-el-skeleton/style/index.ts +2 -0
- package/src/vro-el-skeleton/types.ts +86 -0
- package/src/vro-el-skeleton/vro-el-skeleton.vue +73 -0
- package/src/vro-el-with-config/README.md +75 -0
- package/src/vro-el-with-config/index.ts +16 -0
- package/src/vro-el-with-config/style/css.ts +3 -0
- package/src/vro-el-with-config/style/deps.ts +2 -0
- package/src/vro-el-with-config/style/index.scss +0 -0
- package/src/vro-el-with-config/style/index.ts +2 -0
- package/src/vro-el-with-config/types.ts +18 -0
- package/src/vro-el-with-config/vro-el-with-config.vue +48 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ExtractPropTypes, PropType } from 'vue'
|
|
2
|
+
|
|
3
|
+
export interface VroElFileUploadCallback<T = any> {
|
|
4
|
+
(
|
|
5
|
+
files: File[],
|
|
6
|
+
options: {
|
|
7
|
+
params: T
|
|
8
|
+
},
|
|
9
|
+
): Promise<string[]>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const vroElFileUploadProps = {
|
|
13
|
+
/**
|
|
14
|
+
* 绑定值。单文件时可传字符串,多文件时传字符串数组。
|
|
15
|
+
*/
|
|
16
|
+
modelValue: {
|
|
17
|
+
type: [String, Array] as PropType<string | string[]>,
|
|
18
|
+
default: '',
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 原生文件选择 accept 属性。
|
|
23
|
+
*/
|
|
24
|
+
accept: String,
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 最大上传数量。
|
|
28
|
+
*/
|
|
29
|
+
max: {
|
|
30
|
+
type: Number,
|
|
31
|
+
default: 1,
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 是否禁用上传和删除。
|
|
36
|
+
*/
|
|
37
|
+
disabled: Boolean,
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 上传时透传给 upload 回调的自定义参数。
|
|
41
|
+
*/
|
|
42
|
+
params: Object as PropType<Record<string, any>>,
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 上传回调,接收本次选择的文件列表,返回文件访问地址列表。
|
|
46
|
+
*/
|
|
47
|
+
upload: Function as PropType<VroElFileUploadCallback>,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type VroElFileUploadProps = ExtractPropTypes<typeof vroElFileUploadProps>
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="vro-el-file-upload">
|
|
3
|
+
<el-button
|
|
4
|
+
v-if="computeValue.length < max && !disabled"
|
|
5
|
+
class="vro-el-file-upload-btn"
|
|
6
|
+
:loading="loading"
|
|
7
|
+
:disabled="disabled"
|
|
8
|
+
type="primary"
|
|
9
|
+
icon="upload"
|
|
10
|
+
>
|
|
11
|
+
{{ t('fileUpload.btnText') }}
|
|
12
|
+
<input type="file" :accept="accept" :multiple="max > 1" @change="handleUpload" />
|
|
13
|
+
</el-button>
|
|
14
|
+
|
|
15
|
+
<ul class="vro-el-file-upload-content">
|
|
16
|
+
<li class="vro-el-file-upload-item" v-for="(item, index) in computeValue" :key="index">
|
|
17
|
+
<a :href="item" target="_blank">{{ item }}</a>
|
|
18
|
+
<el-icon v-if="!disabled" @click="handleDelete(index)">
|
|
19
|
+
<circle-close-filled />
|
|
20
|
+
</el-icon>
|
|
21
|
+
</li>
|
|
22
|
+
</ul>
|
|
23
|
+
</div>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<script setup lang="ts">
|
|
27
|
+
import { isArray, isUndefined, omitBy } from '@daysnap/utils'
|
|
28
|
+
import { CircleCloseFilled } from '@element-plus/icons-vue'
|
|
29
|
+
import { useAsyncTask } from '@vrojs/use'
|
|
30
|
+
import { ElButton, ElIcon } from 'element-plus'
|
|
31
|
+
import { computed } from 'vue'
|
|
32
|
+
|
|
33
|
+
import { useLocale } from '../locale'
|
|
34
|
+
import { type VroElFileUploadProps, vroElFileUploadProps } from './types'
|
|
35
|
+
import { getVroElFileUploadOptions } from './utils'
|
|
36
|
+
|
|
37
|
+
defineOptions({ name: 'VroElFileUpload' })
|
|
38
|
+
|
|
39
|
+
const emit = defineEmits<{
|
|
40
|
+
(event: 'update:modelValue', value: string | string[]): void
|
|
41
|
+
}>()
|
|
42
|
+
|
|
43
|
+
const rawProps = defineProps(vroElFileUploadProps)
|
|
44
|
+
|
|
45
|
+
const { t } = useLocale()
|
|
46
|
+
|
|
47
|
+
const props = computed(() => {
|
|
48
|
+
return {
|
|
49
|
+
...getVroElFileUploadOptions(),
|
|
50
|
+
...omitBy(rawProps, isUndefined),
|
|
51
|
+
} as VroElFileUploadProps
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
const computeValue = computed(() => {
|
|
55
|
+
const { modelValue } = props.value
|
|
56
|
+
return isArray(modelValue) ? modelValue : modelValue ? [modelValue] : []
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const handleDelete = (index: number) => {
|
|
60
|
+
let value: string | string[] = ''
|
|
61
|
+
if (isArray(props.value.modelValue)) {
|
|
62
|
+
value = [...props.value.modelValue]
|
|
63
|
+
value.splice(index, 1)
|
|
64
|
+
}
|
|
65
|
+
emit('update:modelValue', value)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const { loading, trigger: handleUpload } = useAsyncTask(
|
|
69
|
+
async (event: Event) => {
|
|
70
|
+
const target = event.target as HTMLInputElement
|
|
71
|
+
const files = Array.from(target.files ?? [])
|
|
72
|
+
target.value = ''
|
|
73
|
+
if (!files?.length) {
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const { modelValue, max, upload, params } = props.value
|
|
78
|
+
|
|
79
|
+
if (!upload) {
|
|
80
|
+
throw new Error('not set upload')
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const res = await upload(files.slice(0, max - computeValue.value.length), { params })
|
|
84
|
+
|
|
85
|
+
let value: string | string[] = res[0]
|
|
86
|
+
if (isArray(modelValue)) {
|
|
87
|
+
value = [...modelValue, ...res]
|
|
88
|
+
}
|
|
89
|
+
emit('update:modelValue', value)
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
throwError: true,
|
|
93
|
+
},
|
|
94
|
+
)
|
|
95
|
+
</script>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# VroElIcon
|
|
2
|
+
|
|
3
|
+
### 介绍
|
|
4
|
+
|
|
5
|
+
基于 `ElIcon` 的图标封装。`name` 传入 Element Plus 图标组件或大写组件名时按组件渲染,传入普通字符串时按 `iconfont` 类名渲染。
|
|
6
|
+
|
|
7
|
+
## 代码演示
|
|
8
|
+
|
|
9
|
+
### 基础用法
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<template>
|
|
13
|
+
<vro-el-icon :name="Search" />
|
|
14
|
+
<vro-el-icon name="icon-search" />
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script setup lang="ts">
|
|
18
|
+
import { Search } from '@element-plus/icons-vue'
|
|
19
|
+
</script>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 使用插槽
|
|
23
|
+
|
|
24
|
+
```html
|
|
25
|
+
<vro-el-icon>
|
|
26
|
+
<search />
|
|
27
|
+
</vro-el-icon>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## API
|
|
31
|
+
|
|
32
|
+
### 属性 Props
|
|
33
|
+
|
|
34
|
+
<table>
|
|
35
|
+
<tbody>
|
|
36
|
+
<tr>
|
|
37
|
+
<td>名称</td>
|
|
38
|
+
<td>类型</td>
|
|
39
|
+
<td>默认值</td>
|
|
40
|
+
</tr>
|
|
41
|
+
<tr v-for="(item, key) in vroElIconProps" :key="key">
|
|
42
|
+
<td>{{ key }}</td>
|
|
43
|
+
<td>{{ parseType(item.type || item) }}</td>
|
|
44
|
+
<td>{{ reserve(item.default, '-') }}</td>
|
|
45
|
+
</tr>
|
|
46
|
+
</tbody>
|
|
47
|
+
</table>
|
|
48
|
+
|
|
49
|
+
### 插槽 Slots
|
|
50
|
+
|
|
51
|
+
<table>
|
|
52
|
+
<tbody>
|
|
53
|
+
<tr>
|
|
54
|
+
<td>名称</td>
|
|
55
|
+
<td>说明</td>
|
|
56
|
+
</tr>
|
|
57
|
+
<tr>
|
|
58
|
+
<td>default</td>
|
|
59
|
+
<td>自定义图标内容</td>
|
|
60
|
+
</tr>
|
|
61
|
+
</tbody>
|
|
62
|
+
</table>
|
|
63
|
+
|
|
64
|
+
<script setup lang="ts">
|
|
65
|
+
import { reserve } from '@daysnap/utils'
|
|
66
|
+
import { VroElIcon, vroElIconProps } from '.'
|
|
67
|
+
import { parseType } from '../utils'
|
|
68
|
+
</script>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { withInstall } from '@vrojs/base'
|
|
2
|
+
|
|
3
|
+
import Component from './vro-el-icon.vue'
|
|
4
|
+
|
|
5
|
+
export * from './types'
|
|
6
|
+
|
|
7
|
+
export const VroElIcon = withInstall<typeof Component>(Component)
|
|
8
|
+
export default VroElIcon
|
|
9
|
+
|
|
10
|
+
export type VroElIconInstance = InstanceType<typeof VroElIcon>
|
|
11
|
+
|
|
12
|
+
declare module 'vue' {
|
|
13
|
+
export interface GlobalComponents {
|
|
14
|
+
VroElIcon: typeof VroElIcon
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import 'element-plus/es/components/icon/style/css'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.vro-el-icon { }
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { iconProps } from 'element-plus'
|
|
2
|
+
import type { ExtractPropTypes, PropType, Raw } from 'vue'
|
|
3
|
+
|
|
4
|
+
export const vroElIconProps = {
|
|
5
|
+
...iconProps,
|
|
6
|
+
name: {
|
|
7
|
+
type: [String, Object] as PropType<string | Raw<object>>,
|
|
8
|
+
default: '',
|
|
9
|
+
},
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type VroElIconProps = ExtractPropTypes<typeof vroElIconProps>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-icon class="vro-el-icon" v-bind="props">
|
|
3
|
+
<slot>
|
|
4
|
+
<component v-if="isElement" :is="name" />
|
|
5
|
+
<i v-else class="iconfont" :class="[name]"></i>
|
|
6
|
+
</slot>
|
|
7
|
+
</el-icon>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script setup lang="ts">
|
|
11
|
+
import { isString } from '@daysnap/utils'
|
|
12
|
+
import { ElIcon } from 'element-plus'
|
|
13
|
+
import { computed } from 'vue'
|
|
14
|
+
|
|
15
|
+
import { vroElIconProps } from './types'
|
|
16
|
+
|
|
17
|
+
defineOptions({ name: 'VroElIcon' })
|
|
18
|
+
const props = defineProps(vroElIconProps)
|
|
19
|
+
|
|
20
|
+
const isElement = computed(() => {
|
|
21
|
+
const { name } = props
|
|
22
|
+
if (isString(name)) {
|
|
23
|
+
const char = name.substring(0, 1)
|
|
24
|
+
return char >= 'A' && char <= 'Z'
|
|
25
|
+
}
|
|
26
|
+
return true
|
|
27
|
+
})
|
|
28
|
+
</script>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# VroElImageUpload
|
|
2
|
+
|
|
3
|
+
### 介绍
|
|
4
|
+
|
|
5
|
+
基于 Element Plus Image 的图片上传组件。组件负责图片选择、预览、删除和拖拽排序,实际上传逻辑由 `upload` 回调提供。
|
|
6
|
+
|
|
7
|
+
## 代码演示
|
|
8
|
+
|
|
9
|
+
### 基础用法
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<template>
|
|
13
|
+
<vro-el-image-upload v-model="value" :upload="upload" />
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script setup lang="ts">
|
|
17
|
+
import { ref } from 'vue'
|
|
18
|
+
|
|
19
|
+
const value = ref('')
|
|
20
|
+
|
|
21
|
+
const upload = async (files: File[]) => {
|
|
22
|
+
return files.map((file) => URL.createObjectURL(file))
|
|
23
|
+
}
|
|
24
|
+
</script>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 多图上传
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<vro-el-image-upload v-model="value" :max="3" :upload="upload" />
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 图片压缩
|
|
34
|
+
|
|
35
|
+
```html
|
|
36
|
+
<vro-el-image-upload v-model="value" compressible :upload="upload" />
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 全局上传配置
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { setVroElImageUploadOptions } from '@vrojs/element-plus'
|
|
43
|
+
|
|
44
|
+
setVroElImageUploadOptions({
|
|
45
|
+
compressible: false,
|
|
46
|
+
imageProps: {
|
|
47
|
+
fit: 'cover',
|
|
48
|
+
},
|
|
49
|
+
upload: async (files, { compress, params }) => {
|
|
50
|
+
return files.map((file) => `${params.domain}/${compress ? 'compressed' : 'raw'}/${file.name}`)
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## API
|
|
56
|
+
|
|
57
|
+
### 属性 Props
|
|
58
|
+
|
|
59
|
+
<table>
|
|
60
|
+
<tbody>
|
|
61
|
+
<tr>
|
|
62
|
+
<td>名称</td>
|
|
63
|
+
<td>类型</td>
|
|
64
|
+
<td>默认值</td>
|
|
65
|
+
</tr>
|
|
66
|
+
<tr v-for="(item, key) in vroElImageUploadProps" :key="key">
|
|
67
|
+
<td>{{ key }}</td>
|
|
68
|
+
<td>{{ parseType(item.type || item) }}</td>
|
|
69
|
+
<td>{{ reserve(item.default, '-') }}</td>
|
|
70
|
+
</tr>
|
|
71
|
+
</tbody>
|
|
72
|
+
</table>
|
|
73
|
+
|
|
74
|
+
### 插槽 Slots
|
|
75
|
+
|
|
76
|
+
暂无。
|
|
77
|
+
|
|
78
|
+
### 事件 Events
|
|
79
|
+
|
|
80
|
+
<table>
|
|
81
|
+
<tbody>
|
|
82
|
+
<tr>
|
|
83
|
+
<td>名称</td>
|
|
84
|
+
<td>参数</td>
|
|
85
|
+
<td>说明</td>
|
|
86
|
+
</tr>
|
|
87
|
+
<tr>
|
|
88
|
+
<td>update:modelValue</td>
|
|
89
|
+
<td>value: string | string[]</td>
|
|
90
|
+
<td>上传、删除或排序后触发</td>
|
|
91
|
+
</tr>
|
|
92
|
+
</tbody>
|
|
93
|
+
</table>
|
|
94
|
+
|
|
95
|
+
<script setup lang="ts">
|
|
96
|
+
import { reserve } from '@daysnap/utils'
|
|
97
|
+
import { VroElImageUpload, vroElImageUploadProps } from '.'
|
|
98
|
+
import { parseType } from '../utils'
|
|
99
|
+
</script>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { withInstall } from '@vrojs/base'
|
|
2
|
+
|
|
3
|
+
import Component from './vro-el-image-upload.vue'
|
|
4
|
+
|
|
5
|
+
export * from './types'
|
|
6
|
+
export * from './utils'
|
|
7
|
+
|
|
8
|
+
export const VroElImageUpload = withInstall<typeof Component>(Component)
|
|
9
|
+
export default VroElImageUpload
|
|
10
|
+
|
|
11
|
+
export type VroElImageUploadInstance = InstanceType<typeof VroElImageUpload>
|
|
12
|
+
|
|
13
|
+
declare module 'vue' {
|
|
14
|
+
export interface GlobalComponents {
|
|
15
|
+
VroElImageUpload: typeof VroElImageUpload
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
.vro-el-image-upload-content {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-wrap: wrap;
|
|
4
|
+
margin-top: -10px;
|
|
5
|
+
}
|
|
6
|
+
.vro-el-image-upload-item {
|
|
7
|
+
cursor: pointer;
|
|
8
|
+
position: relative;
|
|
9
|
+
box-sizing: border-box;
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
justify-content: center;
|
|
13
|
+
margin-top: 10px;
|
|
14
|
+
margin-right: 10px;
|
|
15
|
+
font-size: 24px;
|
|
16
|
+
border-radius: 4px;
|
|
17
|
+
width: 100px;
|
|
18
|
+
height: 100px;
|
|
19
|
+
border: 1px #ccc dashed;
|
|
20
|
+
.vro-el-image-upload-image,
|
|
21
|
+
img {
|
|
22
|
+
position: absolute;
|
|
23
|
+
width: 100%;
|
|
24
|
+
height: 100%;
|
|
25
|
+
top: 0;
|
|
26
|
+
left: 0;
|
|
27
|
+
object-position: center;
|
|
28
|
+
object-fit: cover;
|
|
29
|
+
border-radius: 4px;
|
|
30
|
+
transform: translate3d(0, 0, 0);
|
|
31
|
+
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAlQTFRFyMjI////1tbWF77ztQAAABZJREFUeJxjYGAIDWUggggNbWAgggAA918Ooanz2WEAAAAASUVORK5CYII=)
|
|
32
|
+
center !important;
|
|
33
|
+
background-size: j(8) !important;
|
|
34
|
+
}
|
|
35
|
+
input {
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
position: absolute;
|
|
38
|
+
top: 0;
|
|
39
|
+
left: 0;
|
|
40
|
+
width: 100%;
|
|
41
|
+
height: 100%;
|
|
42
|
+
border-radius: 4px;
|
|
43
|
+
opacity: 0;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
.vro-el-image-upload-clear {
|
|
47
|
+
position: absolute;
|
|
48
|
+
color: #fff;
|
|
49
|
+
border-radius: 50%;
|
|
50
|
+
cursor: pointer;
|
|
51
|
+
font-size: 20px;
|
|
52
|
+
right: -6px;
|
|
53
|
+
top: -6px;
|
|
54
|
+
background: red;
|
|
55
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ElImage } from 'element-plus'
|
|
2
|
+
import type { ExtractPropTypes, PropType } from 'vue'
|
|
3
|
+
|
|
4
|
+
export type VroElImageUploadImageProps = InstanceType<typeof ElImage>['$props']
|
|
5
|
+
|
|
6
|
+
export interface VroElImageUploadCallback<T = any> {
|
|
7
|
+
(
|
|
8
|
+
/** 当前待上传的图片文件列表 */
|
|
9
|
+
files: File[],
|
|
10
|
+
options: {
|
|
11
|
+
/** 是否开启压缩 */
|
|
12
|
+
compress: boolean
|
|
13
|
+
/** 上传时透传的自定义参数 */
|
|
14
|
+
params: T
|
|
15
|
+
},
|
|
16
|
+
): Promise<string[]>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const vroElImageUploadProps = {
|
|
20
|
+
/** 绑定值,字符串为单图模式,数组为多图模式 */
|
|
21
|
+
modelValue: {
|
|
22
|
+
type: [String, Array] as PropType<string | string[]>,
|
|
23
|
+
default: '',
|
|
24
|
+
},
|
|
25
|
+
/** 最多可上传的图片数量 */
|
|
26
|
+
max: {
|
|
27
|
+
type: Number,
|
|
28
|
+
default: 1,
|
|
29
|
+
},
|
|
30
|
+
/** 是否禁用上传、删除和排序 */
|
|
31
|
+
disabled: Boolean,
|
|
32
|
+
/** 是否显示压缩开关,传入对象时可作为响应式默认值 */
|
|
33
|
+
compressible: [Boolean, Object] as PropType<boolean | { value: boolean }>,
|
|
34
|
+
/** 上传时透传给 upload 回调的自定义参数 */
|
|
35
|
+
params: Object as PropType<Record<string, any>>,
|
|
36
|
+
/** 透传给 Element Plus Image 的属性 */
|
|
37
|
+
imageProps: Object as PropType<Partial<VroElImageUploadImageProps>>,
|
|
38
|
+
/** 自定义上传方法,需要返回图片访问地址列表 */
|
|
39
|
+
upload: Function as PropType<VroElImageUploadCallback>,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type VroElImageUploadProps = ExtractPropTypes<typeof vroElImageUploadProps>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createFactory } from '@daysnap/utils'
|
|
2
|
+
|
|
3
|
+
import type { VroElImageUploadProps } from './types'
|
|
4
|
+
|
|
5
|
+
export const [setVroElImageUploadOptions, getVroElImageUploadOptions] = createFactory<
|
|
6
|
+
Partial<Pick<VroElImageUploadProps, 'compressible' | 'upload' | 'imageProps'>>
|
|
7
|
+
>({})
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="vro-el-image-upload">
|
|
3
|
+
<vue-draggable
|
|
4
|
+
class="vro-el-image-upload-content"
|
|
5
|
+
:disabled="props.disabled || props.max <= 1"
|
|
6
|
+
:animation="150"
|
|
7
|
+
:model-value="computeValue"
|
|
8
|
+
filter=".vro-el-image-upload-btn"
|
|
9
|
+
@update:model-value="handleUpdate"
|
|
10
|
+
>
|
|
11
|
+
<div class="vro-el-image-upload-item" v-for="(item, index) in computeValue" :key="item">
|
|
12
|
+
<el-image
|
|
13
|
+
class="vro-el-image-upload-image"
|
|
14
|
+
v-bind="props.imageProps"
|
|
15
|
+
:src="item"
|
|
16
|
+
:preview-src-list="computeValue"
|
|
17
|
+
:initial-index="index"
|
|
18
|
+
/>
|
|
19
|
+
<el-icon
|
|
20
|
+
v-if="!props.disabled"
|
|
21
|
+
class="vro-el-image-upload-clear"
|
|
22
|
+
@click="handleDelete(index)"
|
|
23
|
+
>
|
|
24
|
+
<circle-close-filled />
|
|
25
|
+
</el-icon>
|
|
26
|
+
</div>
|
|
27
|
+
<div
|
|
28
|
+
v-if="computeValue.length < props.max && !props.disabled"
|
|
29
|
+
v-loading="loading"
|
|
30
|
+
class="vro-el-image-upload-item vro-el-image-upload-btn"
|
|
31
|
+
>
|
|
32
|
+
<el-icon class="vro-el-image-upload-add"><plus /></el-icon>
|
|
33
|
+
<input type="file" accept="image/*" :multiple="props.max > 1" @change="handleUpload" />
|
|
34
|
+
</div>
|
|
35
|
+
</vue-draggable>
|
|
36
|
+
<el-checkbox v-if="!props.disabled && props.compressible" v-model="compress">
|
|
37
|
+
{{ t('imageUpload.compressText') }}
|
|
38
|
+
</el-checkbox>
|
|
39
|
+
</div>
|
|
40
|
+
</template>
|
|
41
|
+
|
|
42
|
+
<script setup lang="ts">
|
|
43
|
+
import { isArray, isBoolean, isUndefined, omitBy } from '@daysnap/utils'
|
|
44
|
+
import { CircleCloseFilled, Plus } from '@element-plus/icons-vue'
|
|
45
|
+
import { useAsyncTask } from '@vrojs/use'
|
|
46
|
+
import { ElCheckbox, ElIcon, ElImage, ElLoading } from 'element-plus'
|
|
47
|
+
import { computed, ref } from 'vue'
|
|
48
|
+
import { VueDraggable } from 'vue-draggable-plus'
|
|
49
|
+
|
|
50
|
+
import { useLocale } from '../locale'
|
|
51
|
+
import { type VroElImageUploadProps, vroElImageUploadProps } from './types'
|
|
52
|
+
import { getVroElImageUploadOptions } from './utils'
|
|
53
|
+
|
|
54
|
+
defineOptions({ name: 'VroElImageUpload' })
|
|
55
|
+
|
|
56
|
+
const emit = defineEmits<{
|
|
57
|
+
'update:modelValue': [value: string | string[]]
|
|
58
|
+
}>()
|
|
59
|
+
const rawProps = defineProps(vroElImageUploadProps)
|
|
60
|
+
const { t } = useLocale()
|
|
61
|
+
|
|
62
|
+
const props = computed(() => {
|
|
63
|
+
const {
|
|
64
|
+
compressible = false,
|
|
65
|
+
upload,
|
|
66
|
+
...rest
|
|
67
|
+
} = {
|
|
68
|
+
...getVroElImageUploadOptions(),
|
|
69
|
+
...omitBy(rawProps, isUndefined),
|
|
70
|
+
} as VroElImageUploadProps
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
upload,
|
|
74
|
+
compressible,
|
|
75
|
+
compress: isBoolean(compressible) ? compressible : compressible.value,
|
|
76
|
+
...rest,
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
const vLoading = ElLoading.directive
|
|
81
|
+
const compress = ref(props.value.compress)
|
|
82
|
+
|
|
83
|
+
const computeValue = computed(() => {
|
|
84
|
+
const { modelValue } = props.value
|
|
85
|
+
return isArray(modelValue) ? modelValue : modelValue ? [modelValue] : []
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
const handleUpdate = (value: string[]) => {
|
|
89
|
+
if (isArray(props.value.modelValue)) {
|
|
90
|
+
emit('update:modelValue', value)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const handleDelete = (index: number) => {
|
|
95
|
+
let value: string | string[] = ''
|
|
96
|
+
if (isArray(props.value.modelValue)) {
|
|
97
|
+
value = [...props.value.modelValue]
|
|
98
|
+
value.splice(index, 1)
|
|
99
|
+
}
|
|
100
|
+
emit('update:modelValue', value)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const { loading, trigger: handleUpload } = useAsyncTask(
|
|
104
|
+
async (event: Event) => {
|
|
105
|
+
const target = event.target as HTMLInputElement
|
|
106
|
+
const files = Array.from(target.files ?? [])
|
|
107
|
+
|
|
108
|
+
target.value = ''
|
|
109
|
+
if (!files?.length) {
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const { max, upload, params } = props.value
|
|
114
|
+
|
|
115
|
+
if (!upload) {
|
|
116
|
+
throw new Error('not set upload')
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const res = await upload(files.slice(0, max - computeValue.value.length), {
|
|
120
|
+
compress: compress.value,
|
|
121
|
+
params,
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
let value: string | string[] = res[0]
|
|
125
|
+
if (isArray(props.value.modelValue)) {
|
|
126
|
+
value = [...props.value.modelValue, ...res]
|
|
127
|
+
}
|
|
128
|
+
emit('update:modelValue', value)
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
throwError: true,
|
|
132
|
+
},
|
|
133
|
+
)
|
|
134
|
+
</script>
|