文件选择器支持image类型的多选
This commit is contained in:
@@ -8,7 +8,27 @@
|
|||||||
<el-option v-for="item, index in listAllData" :key="index" :value="String(item[props.valueKey])"
|
<el-option v-for="item, index in listAllData" :key="index" :value="String(item[props.valueKey])"
|
||||||
:label="item.name" />
|
:label="item.name" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<div v-if="props.inputType === 'image'" style="position: relative;" class="form-display"
|
|
||||||
|
<div v-if="props.inputType === 'image' && props.multiple"
|
||||||
|
style="width: 100%; display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 4px;">
|
||||||
|
<el-image v-for="item, index in (data || [])" :src="item" :key="index" fit="scale-down" class="itemList"
|
||||||
|
:style="{ width: props.inputSize + 'px', aspectRatio: '1 / 1' }" />
|
||||||
|
<div style="position: relative;" :style="{ width: props.inputSize + 'px', height: props.inputSize + 'px' }">
|
||||||
|
<div
|
||||||
|
style="position: absolute; left: 0; top: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center;">
|
||||||
|
<el-icon :size="24">
|
||||||
|
<Plus />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
<div @click="selectVisiable = true && !props.disabled" class="addControllorHover"
|
||||||
|
:style="{ cursor: props.disabled ? 'not-allowed' : 'pointer' }"></div>
|
||||||
|
<el-icon v-show="(!!data && !props.disabled) && !props.multiple" class="closeHover" :size="16"
|
||||||
|
@click="clear">
|
||||||
|
<Close />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="props.inputType === 'image' && !props.multiple" class="form-display" style="position: relative;"
|
||||||
@mouseenter="formDisplayEnter" @mouseleave="formDisplayLeave"
|
@mouseenter="formDisplayEnter" @mouseleave="formDisplayLeave"
|
||||||
:style="{ width: props.inputSize + 'px', height: props.inputSize + 'px' }">
|
:style="{ width: props.inputSize + 'px', height: props.inputSize + 'px' }">
|
||||||
<el-image :src="data" fit="scale-down" :style="{ width: props.inputSize + 'px', aspectRatio: '1 / 1' }">
|
<el-image :src="data" fit="scale-down" :style="{ width: props.inputSize + 'px', aspectRatio: '1 / 1' }">
|
||||||
@@ -24,10 +44,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div @click="selectVisiable = true && !props.disabled" class="addControllorHover"
|
<div @click="selectVisiable = true && !props.disabled" class="addControllorHover"
|
||||||
:style="{ cursor: props.disabled ? 'not-allowed' : 'pointer' }"></div>
|
:style="{ cursor: props.disabled ? 'not-allowed' : 'pointer' }"></div>
|
||||||
<el-icon v-show="!!data && !props.disabled" class="closeHover" :size="16" @click="clear">
|
<el-icon v-show="(!!data && !props.disabled) && !props.multiple" class="closeHover" :size="16" @click="clear">
|
||||||
<Close />
|
<Close />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="props.inputType === 'video'" class="form-display" @mouseenter="formDisplayEnter"
|
<div v-if="props.inputType === 'video'" class="form-display" @mouseenter="formDisplayEnter"
|
||||||
@mouseleave="formDisplayLeave"
|
@mouseleave="formDisplayLeave"
|
||||||
style="position: relative; display: flex; align-items: center; justify-items: center;"
|
style="position: relative; display: flex; align-items: center; justify-items: center;"
|
||||||
@@ -46,6 +67,7 @@
|
|||||||
<Close />
|
<Close />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="props.inputType === 'audio'" class="form-display" @mouseenter="formDisplayEnter"
|
<div v-if="props.inputType === 'audio'" class="form-display" @mouseenter="formDisplayEnter"
|
||||||
@mouseleave="formDisplayLeave"
|
@mouseleave="formDisplayLeave"
|
||||||
style="position: relative; display: flex; align-items: center; justify-items: center;"
|
style="position: relative; display: flex; align-items: center; justify-items: center;"
|
||||||
@@ -199,7 +221,7 @@ const props = defineProps({
|
|||||||
tabsShow: { type: Number, default: SHOW.ALL },
|
tabsShow: { type: Number, default: SHOW.ALL },
|
||||||
|
|
||||||
// 是否可以多选,默认单选
|
// 是否可以多选,默认单选
|
||||||
// 该值为true时inputType必须是selector(暂不支持其他type的多选)
|
// 该值为true时inputType必须是selector或image(暂不支持其他type的多选)
|
||||||
multiple: { type: Boolean, default: false },
|
multiple: { type: Boolean, default: false },
|
||||||
|
|
||||||
// 是否可选,该参数用于只上传和展示而不选择和绑定model的情况
|
// 是否可选,该参数用于只上传和展示而不选择和绑定model的情况
|
||||||
@@ -274,6 +296,7 @@ const onItemClick = async (e: MouseEvent) => {
|
|||||||
while (!target.dataset.id) target = target.parentElement as HTMLElement;
|
while (!target.dataset.id) target = target.parentElement as HTMLElement;
|
||||||
let fileId = target.dataset.id;
|
let fileId = target.dataset.id;
|
||||||
if (props.multiple) {
|
if (props.multiple) {
|
||||||
|
if (!!!data.value) data.value = [];
|
||||||
if (target.classList.contains('active')) { target.classList.remove('active'); flat = -1; }
|
if (target.classList.contains('active')) { target.classList.remove('active'); flat = -1; }
|
||||||
else { target.classList.add('active'); flat = 1; }
|
else { target.classList.add('active'); flat = 1; }
|
||||||
if (data.value.length) {
|
if (data.value.length) {
|
||||||
@@ -394,7 +417,8 @@ const onDataChange = (value: any) => {
|
|||||||
defineExpose({ data, onDataChange, selectVisiable, clearState, clear });
|
defineExpose({ data, onDataChange, selectVisiable, clearState, clear });
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.multiple && props.inputType !== 'selector')
|
|
||||||
|
if (props.multiple && !['selector', 'image'].includes(props.inputType))
|
||||||
throw new Error('FileSelector组件属性multiple为true时inputType必须为selector');
|
throw new Error('FileSelector组件属性multiple为true时inputType必须为selector');
|
||||||
listRequestAll();
|
listRequestAll();
|
||||||
console.log('fileselector tenentmdoe', isTenentMode);
|
console.log('fileselector tenentmdoe', isTenentMode);
|
||||||
@@ -475,4 +499,9 @@ onMounted(() => {
|
|||||||
top: 2px;
|
top: 2px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.itemList {
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1,253 +1,254 @@
|
|||||||
import * as api from './api';
|
import * as api from './api';
|
||||||
import {
|
import {
|
||||||
UserPageQuery,
|
UserPageQuery,
|
||||||
AddReq,
|
AddReq,
|
||||||
DelReq,
|
DelReq,
|
||||||
EditReq,
|
EditReq,
|
||||||
CrudExpose,
|
CrudExpose,
|
||||||
CrudOptions,
|
CrudOptions,
|
||||||
CreateCrudOptionsProps,
|
CreateCrudOptionsProps,
|
||||||
CreateCrudOptionsRet,
|
CreateCrudOptionsRet,
|
||||||
dict
|
dict
|
||||||
} from '@fast-crud/fast-crud';
|
} from '@fast-crud/fast-crud';
|
||||||
import fileSelector from '/@/components/fileSelector/index.vue';
|
import fileSelector from '/@/components/fileSelector/index.vue';
|
||||||
import { shallowRef } from 'vue';
|
|
||||||
|
|
||||||
export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||||
const pageRequest = async (query: UserPageQuery) => {
|
const pageRequest = async (query: UserPageQuery) => {
|
||||||
return await api.GetList(query);
|
return await api.GetList(query);
|
||||||
};
|
};
|
||||||
const editRequest = async ({ form, row }: EditReq) => {
|
const editRequest = async ({ form, row }: EditReq) => {
|
||||||
form.id = row.id;
|
form.id = row.id;
|
||||||
return await api.UpdateObj(form);
|
return await api.UpdateObj(form);
|
||||||
};
|
};
|
||||||
const delRequest = async ({ row }: DelReq) => {
|
const delRequest = async ({ row }: DelReq) => {
|
||||||
return await api.DelObj(row.id);
|
return await api.DelObj(row.id);
|
||||||
};
|
};
|
||||||
const addRequest = async ({ form }: AddReq) => {
|
const addRequest = async ({ form }: AddReq) => {
|
||||||
return await api.AddObj(form);
|
return await api.AddObj(form);
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
crudOptions: {
|
crudOptions: {
|
||||||
actionbar: {
|
actionbar: {
|
||||||
buttons: {
|
buttons: {
|
||||||
add: {
|
add: {
|
||||||
show: true,
|
show: true,
|
||||||
click: () => context.openAddHandle?.()
|
click: () => context.openAddHandle?.()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
request: {
|
request: {
|
||||||
pageRequest,
|
pageRequest,
|
||||||
addRequest,
|
addRequest,
|
||||||
editRequest,
|
editRequest,
|
||||||
delRequest,
|
delRequest,
|
||||||
},
|
},
|
||||||
tabs: {
|
tabs: {
|
||||||
show: true,
|
show: true,
|
||||||
name: 'file_type',
|
name: 'file_type',
|
||||||
type: '',
|
type: '',
|
||||||
options: [
|
options: [
|
||||||
{ value: 0, label: '图片' },
|
{ value: 0, label: '图片' },
|
||||||
{ value: 1, label: '视频' },
|
{ value: 1, label: '视频' },
|
||||||
{ value: 2, label: '音频' },
|
{ value: 2, label: '音频' },
|
||||||
{ value: 3, label: '其他' },
|
{ value: 3, label: '其他' },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
rowHandle: {
|
rowHandle: {
|
||||||
//固定右侧
|
//固定右侧
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
width: 200,
|
width: 200,
|
||||||
show: false,
|
show: false,
|
||||||
buttons: {
|
buttons: {
|
||||||
view: {
|
view: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
edit: {
|
edit: {
|
||||||
iconRight: 'Edit',
|
iconRight: 'Edit',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
remove: {
|
remove: {
|
||||||
iconRight: 'Delete',
|
iconRight: 'Delete',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
columns: {
|
columns: {
|
||||||
_index: {
|
_index: {
|
||||||
title: '序号',
|
title: '序号',
|
||||||
form: { show: false },
|
form: { show: false },
|
||||||
column: {
|
column: {
|
||||||
//type: 'index',
|
//type: 'index',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: '70px',
|
width: '70px',
|
||||||
columnSetDisabled: true, //禁止在列设置中选择
|
columnSetDisabled: true, //禁止在列设置中选择
|
||||||
formatter: (context) => {
|
formatter: (context) => {
|
||||||
//计算序号,你可以自定义计算规则,此处为翻页累加
|
//计算序号,你可以自定义计算规则,此处为翻页累加
|
||||||
let index = context.index ?? 1;
|
let index = context.index ?? 1;
|
||||||
let pagination = crudExpose!.crudBinding.value.pagination;
|
let pagination = crudExpose!.crudBinding.value.pagination;
|
||||||
return ((pagination!.currentPage ?? 1) - 1) * pagination!.pageSize + index + 1;
|
return ((pagination!.currentPage ?? 1) - 1) * pagination!.pageSize + index + 1;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
search: {
|
search: {
|
||||||
title: '关键词',
|
title: '关键词',
|
||||||
column: {
|
column: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
search: {
|
search: {
|
||||||
show: true,
|
show: true,
|
||||||
component: {
|
component: {
|
||||||
props: {
|
props: {
|
||||||
clearable: true,
|
clearable: true,
|
||||||
},
|
},
|
||||||
placeholder: '请输入关键词',
|
placeholder: '请输入关键词',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
show: false,
|
show: false,
|
||||||
component: {
|
component: {
|
||||||
props: {
|
props: {
|
||||||
clearable: true,
|
clearable: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
title: '文件名称',
|
title: '文件名称',
|
||||||
search: {
|
search: {
|
||||||
show: true,
|
show: true,
|
||||||
},
|
},
|
||||||
type: 'input',
|
type: 'input',
|
||||||
column: {
|
column: {
|
||||||
minWidth: 200,
|
minWidth: 200,
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
component: {
|
component: {
|
||||||
placeholder: '请输入文件名称',
|
placeholder: '请输入文件名称',
|
||||||
clearable: true
|
clearable: true
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
preview: {
|
preview: {
|
||||||
title: '预览',
|
title: '预览',
|
||||||
column: {
|
column: {
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
align: 'center'
|
align: 'center'
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
url: {
|
url: {
|
||||||
title: '文件地址',
|
title: '文件地址',
|
||||||
type: 'file-uploader',
|
type: 'file-uploader',
|
||||||
search: {
|
search: {
|
||||||
disabled: true,
|
disabled: true,
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
minWidth: 360,
|
minWidth: 360,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
md5sum: {
|
md5sum: {
|
||||||
title: '文件MD5',
|
title: '文件MD5',
|
||||||
search: {
|
search: {
|
||||||
disabled: true,
|
disabled: true,
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
minWidth: 300,
|
minWidth: 300,
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
disabled: false
|
disabled: false
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mime_type: {
|
mime_type: {
|
||||||
title: '文件类型',
|
title: '文件类型',
|
||||||
type: 'input',
|
type: 'input',
|
||||||
form: {
|
form: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
minWidth: 160
|
minWidth: 160
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
file_type: {
|
file_type: {
|
||||||
title: '文件类型',
|
title: '文件类型',
|
||||||
type: 'dict-select',
|
type: 'dict-select',
|
||||||
dict: dict({
|
dict: dict({
|
||||||
data: [
|
data: [
|
||||||
{ label: '图片', value: 0, color: 'success' },
|
{ label: '图片', value: 0, color: 'success' },
|
||||||
{ label: '视频', value: 1, color: 'warning' },
|
{ label: '视频', value: 1, color: 'warning' },
|
||||||
{ label: '音频', value: 2, color: 'danger' },
|
{ label: '音频', value: 2, color: 'danger' },
|
||||||
{ label: '其他', value: 3, color: 'primary' },
|
{ label: '其他', value: 3, color: 'primary' },
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
column: {
|
column: {
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
search: {
|
search: {
|
||||||
show: true
|
show: true
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
show: false,
|
show: false,
|
||||||
component: {
|
component: {
|
||||||
placeholder: '请选择文件类型'
|
placeholder: '请选择文件类型'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
title: '文件大小',
|
title: '文件大小',
|
||||||
column: {
|
column: {
|
||||||
minWidth: 120
|
minWidth: 120
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
upload_method: {
|
upload_method: {
|
||||||
title: '上传方式',
|
title: '上传方式',
|
||||||
type: 'dict-select',
|
type: 'dict-select',
|
||||||
dict: dict({
|
dict: dict({
|
||||||
data: [
|
data: [
|
||||||
{ label: '默认上传', value: 0, color: 'primary' },
|
{ label: '默认上传', value: 0, color: 'primary' },
|
||||||
{ label: '文件选择器上传', value: 1, color: 'warning' },
|
{ label: '文件选择器上传', value: 1, color: 'warning' },
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
column: {
|
column: {
|
||||||
minWidth: 140
|
minWidth: 140
|
||||||
},
|
},
|
||||||
search: {
|
search: {
|
||||||
show: true
|
show: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
create_datetime: {
|
create_datetime: {
|
||||||
title: '创建时间',
|
title: '创建时间',
|
||||||
column: {
|
column: {
|
||||||
minWidth: 160
|
minWidth: 160
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// fileselectortest: {
|
fileselectortest: {
|
||||||
// title: '文件选择器测试',
|
title: '文件选择器测试',
|
||||||
// type: 'file-selector',
|
type: 'file-selector',
|
||||||
// width: 200,
|
column: {
|
||||||
// form: {
|
minWidth: 200
|
||||||
// component: {
|
},
|
||||||
// name: shallowRef(fileSelector),
|
form: {
|
||||||
// vModel: 'modelValue',
|
component: {
|
||||||
// tabsShow: 0b0100,
|
name: fileSelector,
|
||||||
// itemSize: 100,
|
vModel: 'modelValue',
|
||||||
// multiple: false,
|
tabsShow: 0b1111,
|
||||||
// selectable: true,
|
itemSize: 100,
|
||||||
// showInput: true,
|
multiple: true,
|
||||||
// inputType: 'video',
|
selectable: true,
|
||||||
// valueKey: 'url',
|
showInput: true,
|
||||||
// }
|
inputType: 'image',
|
||||||
// }
|
valueKey: 'url',
|
||||||
// }
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
};
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user