feat: 新增Uload

This commit is contained in:
kailong321200875 2023-07-23 12:49:57 +08:00
parent 040476fe24
commit c181887f7f
10 changed files with 191 additions and 156 deletions

View File

@ -17,7 +17,8 @@ import {
ElTransfer,
ElAutocomplete,
ElDivider,
ElTreeSelect
ElTreeSelect,
ElUpload
} from 'element-plus'
import { InputPassword } from '@/components/InputPassword'
import { Editor } from '@/components/Editor'
@ -45,7 +46,8 @@ const componentMap: Recordable<Component, ComponentName> = {
SelectV2: ElSelectV2,
InputPassword: InputPassword,
Editor: Editor,
TreeSelect: ElTreeSelect
TreeSelect: ElTreeSelect,
Upload: ElUpload
}
export { componentMap }

View File

@ -17,7 +17,8 @@ import {
DatePickerProps,
FormItemProps as ElFormItemProps,
FormProps as ElFormProps,
ISelectProps
ISelectProps,
UploadProps
} from 'element-plus'
import { IEditorConfig } from '@wangeditor/editor'
import { CSSProperties } from 'vue'
@ -51,7 +52,8 @@ export enum ComponentNameEnum {
SELECT_V2 = 'SelectV2',
INPUT_PASSWORD = 'InputPassword',
EDITOR = 'Editor',
TREE_SELECT = 'TreeSelect'
TREE_SELECT = 'TreeSelect',
UPLOAD = 'Upload'
}
type CamelCaseComponentName = keyof typeof ComponentNameEnum extends infer K
@ -505,6 +507,16 @@ export interface FormItemProps extends Partial<ElFormItemProps> {
}
}
export interface UploadComponentProps extends Partial<UploadProps> {
slots?: {
default?: (...args: any[]) => JSX.Element | null
trigger?: (...args: any[]) => JSX.Element | null
tip?: (...args: any[]) => JSX.Element | null
file?: (...args: any[]) => JSX.Element | null
}
style?: CSSProperties
}
export interface TreeSelectComponentProps
extends Omit<Partial<SelectComponentProps>, 'props' | 'on' | 'slots'> {
data?: any[]
@ -607,6 +619,7 @@ export interface FormSchema {
| TimePickerComponentProps
| InputPasswordComponentProps
| TreeSelectComponentProps
| UploadComponentProps
/**
* formItem组件属性element-plus文档

View File

@ -7,7 +7,7 @@ import {
ElTooltipProps,
ElImage
} from 'element-plus'
import { defineComponent, PropType, ref, computed, unref, watch, onMounted, nextTick } from 'vue'
import { defineComponent, PropType, ref, computed, unref, watch, onMounted } from 'vue'
import { propTypes } from '@/utils/propTypes'
import { setIndex } from './helper'
import type { TableProps, TableColumn, Pagination, TableSetProps } from './types'
@ -15,8 +15,8 @@ import { set } from 'lodash-es'
import { CSSProperties } from 'vue'
import { getSlot } from '@/utils/tsxHelper'
import TableActions from './components/TableActions.vue'
import Sortable from 'sortablejs'
import { Icon } from '@/components/Icon'
// import Sortable from 'sortablejs'
// import { Icon } from '@/components/Icon'
export default defineComponent({
name: 'Table',
@ -62,7 +62,7 @@ export default defineComponent({
type: Array as PropType<string[]>,
default: () => []
},
sortable: propTypes.bool.def(false),
// sortable: propTypes.bool.def(false),
height: propTypes.oneOfType([Number, String]),
maxHeight: propTypes.oneOfType([Number, String]),
stripe: propTypes.bool.def(false),
@ -213,32 +213,32 @@ export default defineComponent({
return propsObj
})
const sortableEl = ref()
// const sortableEl = ref()
//
const initDropTable = () => {
const el = unref(elTableRef)?.$el.querySelector('.el-table__body tbody')
if (!el) return
if (unref(sortableEl)) unref(sortableEl).destroy()
// const initDropTable = () => {
// const el = unref(elTableRef)?.$el.querySelector('.el-table__body tbody')
// if (!el) return
// if (unref(sortableEl)) unref(sortableEl).destroy()
sortableEl.value = Sortable.create(el, {
handle: '.table-move',
animation: 180,
onEnd(e: any) {
emit('sortable-change', e)
}
})
}
// sortableEl.value = Sortable.create(el, {
// handle: '.table-move',
// animation: 180,
// onEnd(e: any) {
// emit('sortable-change', e)
// }
// })
// }
watch(
() => getProps.value.sortable,
async (v) => {
await nextTick()
v && initDropTable()
},
{
immediate: true
}
)
// watch(
// () => getProps.value.sortable,
// async (v) => {
// await nextTick()
// v && initDropTable()
// },
// {
// immediate: true
// }
// )
const setProps = (props: TableProps = {}) => {
mergeProps.value = Object.assign(unref(mergeProps), props)
@ -495,19 +495,19 @@ export default defineComponent({
tableSlots['append'] = (...args: any[]) => getSlot(slots, 'append', args)
}
const { sortable } = unref(getProps)
// const { sortable } = unref(getProps)
const sortableEl = sortable ? (
<ElTableColumn
className="table-move cursor-move"
type="sortable"
prop="sortable"
width="60px"
align="center"
>
<Icon icon="ant-design:drag-outlined" />
</ElTableColumn>
) : null
// const sortableEl = sortable ? (
// <ElTableColumn
// className="table-move cursor-move"
// type="sortable"
// prop="sortable"
// width="60px"
// align="center"
// >
// <Icon icon="ant-design:drag-outlined" />
// </ElTableColumn>
// ) : null
return (
<div v-loading={unref(getProps).loading}>
@ -520,7 +520,7 @@ export default defineComponent({
) : null}
<ElTable ref={elTableRef} data={unref(getProps).data} {...unref(getBindValue)}>
{{
default: () => [sortableEl, ...renderTableColumn()],
default: () => renderTableColumn(),
...tableSlots
}}
</ElTable>

View File

@ -5,16 +5,16 @@ import {
ElDropdown,
ElDropdownMenu,
ElDropdownItem,
ComponentSize,
ElPopover,
ElTree
ComponentSize
// ElPopover,
// ElTree
} from 'element-plus'
import { Icon } from '@/components/Icon'
import { useI18n } from '@/hooks/web/useI18n'
import { useAppStore } from '@/store/modules/app'
import { TableColumn } from '../types'
import { cloneDeep } from 'lodash-es'
import { eachTree } from '@/utils/tree'
// import { eachTree } from '@/utils/tree'
const appStore = useAppStore()
const sizeMap = computed(() => appStore.sizeMap)
@ -39,16 +39,6 @@ export default defineComponent({
emit('changSize', size)
}
const defaultCheckeds = computed(() => {
const checkeds: string[] = []
eachTree(unref(columns), (item: TableColumn) => {
if (!item.hidden) {
checkeds.push(item.field)
}
})
return checkeds
})
const columns = computed(() => {
return cloneDeep(props.columns).filter((v) => {
// typeselectionexpand
@ -68,81 +58,6 @@ export default defineComponent({
}
)
//
function updateTreeData(treeData, draggedNode, targetNode, placement) {
let updatedTreeData = cloneDeep(treeData) //
//
function findNodes(nodeId, nodes) {
for (const node of nodes) {
if (node?.field === nodeId) {
return node
}
if (node.children && node.children.length) {
const foundNode = findNodes(nodeId, node.children)
if (foundNode) {
return foundNode
}
}
}
return null
}
const draggedNodeToUpdate = findNodes(draggedNode?.data?.field, updatedTreeData)
const targetNodeToUpdate = targetNode
? findNodes(targetNode?.data?.field, updatedTreeData)
: null
if (!draggedNodeToUpdate || (targetNode && !targetNodeToUpdate)) {
//
console.error('无法找到要更新的节点或目标节点')
return treeData //
}
//
function removeNode(node) {
const parent = updatedTreeData.find((n) => n.children.includes(node))
if (parent) {
parent.children = parent.children.filter((n) => n?.field !== node?.field)
} else {
updatedTreeData = updatedTreeData.filter((n) => n?.field !== node?.field)
}
}
removeNode(draggedNodeToUpdate)
//
function insertNode(placement) {
if (placement === 'before' || placement === 'after') {
const parent = updatedTreeData.find((n) => n.children.includes(targetNodeToUpdate))
const index = parent.children.findIndex((n) => n?.field === targetNodeToUpdate?.data?.id)
const insertionIndex = placement === 'before' ? index : index + 1
parent.children.splice(insertionIndex, 0, draggedNodeToUpdate)
} else if (placement === 'inner') {
targetNodeToUpdate.children.push(draggedNodeToUpdate)
}
}
if (targetNode) {
insertNode(placement)
} else {
// targetNode
updatedTreeData.push(draggedNodeToUpdate)
}
return updatedTreeData
}
const onNodeDragEnd = (before: any, after: any, inner: string) => {
if (inner === 'none') return
console.log(before, after, inner)
const cloneDeepColumns = cloneDeep(unref(props.columns))
const newColumns = updateTreeData(cloneDeepColumns, after, before, inner)
console.log(newColumns)
}
const onCheckChange = (data: TableColumn, isChecked: boolean, childrenHasChecked) => {
console.log(data, isChecked, childrenHasChecked)
}
return () => (
<>
<div class="text-right h-28px flex items-center justify-end">
@ -189,7 +104,7 @@ export default defineComponent({
</ElTooltip>
{/* <ElTooltip content={t('common.columnSetting')} placement="top"> */}
<ElPopover trigger="click" placement="left">
{/* <ElPopover trigger="click" placement="left">
{{
default: () => {
return (
@ -223,7 +138,7 @@ export default defineComponent({
)
}
}}
</ElPopover>
</ElPopover> */}
{/* </ElTooltip> */}
</div>
</>

View File

@ -18,7 +18,7 @@ export interface TableColumn {
minWidth?: string | number
fixed?: boolean | 'left' | 'right'
renderHeader?: (...args: any[]) => JSX.Element | null
sortable?: boolean | 'custom'
// sortable?: boolean
sortMethod?: (...args: any[]) => number
sortBy?: string | string[] | ((...args: any[]) => string | string[])
sortOrders?: (string | null)[]

View File

@ -154,14 +154,14 @@ export const useTable = (config: UseTableConfig) => {
refresh: () => {
methods.getList()
},
sortableChange: (e: any) => {
console.log('sortableChange', e)
const { oldIndex, newIndex } = e
dataList.value.splice(newIndex, 0, dataList.value.splice(oldIndex, 1)[0])
// to do something
}
// sortableChange: (e: any) => {
// console.log('sortableChange', e)
// const { oldIndex, newIndex } = e
// dataList.value.splice(newIndex, 0, dataList.value.splice(oldIndex, 1)[0])
// // to do something
// }
// // 删除数据
// delList: async (ids: string[] | number[], multiple: boolean, message = true) => {
// const tableRef = await getTable()

View File

@ -302,7 +302,10 @@ export default {
// 自定义节点内容
customContent: 'Custom content',
// 懒加载
lazyLoad: 'Lazy load'
lazyLoad: 'Lazy load',
upload: 'Upload',
// 用户头像
userAvatar: 'User avatar'
},
guideDemo: {
guide: 'Guide',

View File

@ -299,7 +299,9 @@ export default {
multiple: '多选',
filterable: '可筛选',
customContent: '自定义内容',
lazyLoad: '懒加载'
lazyLoad: '懒加载',
upload: '上传',
userAvatar: '用户头像'
},
guideDemo: {
guide: '引导页',

View File

@ -13,7 +13,10 @@ import {
ElRadioButton,
ElCheckbox,
ElCheckboxButton,
ElInput
ElInput,
ElMessage,
ElMessageBox,
ElIcon
} from 'element-plus'
import { getDictOneApi } from '@/api/common'
import { Icon } from '@/components/Icon'
@ -441,6 +444,8 @@ const treeSelectData = [
let id = 0
const imageUrl = ref('')
const schema = reactive<FormSchema[]>([
{
field: 'field1',
@ -1663,6 +1668,88 @@ const schema = reactive<FormSchema[]>([
},
data: treeSelectData
}
},
{
field: 'field82',
component: 'Divider',
label: `${t('formDemo.upload')}`
},
{
field: 'field83',
component: 'Upload',
label: `${t('formDemo.default')}`,
componentProps: {
limit: 3,
action: 'https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15',
fileList: [
{
name: 'element-plus-logo.svg',
url: 'https://element-plus.org/images/element-plus-logo.svg'
},
{
name: 'element-plus-logo2.svg',
url: 'https://element-plus.org/images/element-plus-logo.svg'
}
],
multiple: true,
onPreview: (uploadFile) => {
console.log(uploadFile)
},
onRemove: (file) => {
console.log(file)
},
beforeRemove: (uploadFile) => {
return ElMessageBox.confirm(`Cancel the transfer of ${uploadFile.name} ?`).then(
() => true,
() => false
)
},
onExceed: (files, uploadFiles) => {
ElMessage.warning(
`The limit is 3, you selected ${files.length} files this time, add up to ${
files.length + uploadFiles.length
} totally`
)
},
slots: {
default: () => <ElButton type="primary">Click to upload</ElButton>,
tip: () => <div class="el-upload__tip">jpg/png files with a size less than 500KB.</div>
}
}
},
{
field: 'field84',
component: 'Upload',
label: `${t('formDemo.userAvatar')}`,
componentProps: {
action: 'https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15',
showFileList: false,
onSuccess: (_response, uploadFile) => {
imageUrl.value = URL.createObjectURL(uploadFile.raw!)
},
beforeUpload: (rawFile) => {
if (rawFile.type !== 'image/jpeg') {
ElMessage.error('Avatar picture must be JPG format!')
return false
} else if (rawFile.size / 1024 / 1024 > 2) {
ElMessage.error('Avatar picture size can not exceed 2MB!')
return false
}
return true
},
slots: {
default: () => (
<>
{imageUrl.value ? <img src={imageUrl.value} class="avatar" /> : null}
{!imageUrl.value ? (
<ElIcon class="avatar-uploader-icon" size="large">
add
</ElIcon>
) : null}
</>
)
}
}
}
])
</script>
@ -1714,4 +1801,25 @@ const schema = reactive<FormSchema[]>([
padding: 6px 5px;
margin-left: 15px;
}
.el-upload {
position: relative;
overflow: hidden;
cursor: pointer;
border: 1px dashed var(--el-border-color);
border-radius: 6px;
transition: var(--el-transition-duration-fast);
}
.el-upload:hover {
border-color: var(--el-color-primary);
}
.el-icon.avatar-uploader-icon {
width: 178px;
height: 178px;
font-size: 28px;
color: #8c939d;
text-align: center;
}
</style>

View File

@ -21,8 +21,7 @@ const { tableRegister, tableMethods, tableState } = useTable({
}
})
const { loading, dataList, total, currentPage, pageSize } = tableState
const { setProps, setColumn, getElTableExpose, addColumn, delColumn, refresh, sortableChange } =
tableMethods
const { setProps, setColumn, getElTableExpose, addColumn, delColumn, refresh } = tableMethods
const { t } = useI18n()
@ -214,11 +213,6 @@ const getSelections = async () => {
const selections = elTableRef?.getSelectionRows()
console.log(selections)
}
const sortable = ref(false)
const showOrHiddenSortable = () => {
sortable.value = !unref(sortable)
}
</script>
<template>
@ -251,7 +245,7 @@ const showOrHiddenSortable = () => {
<ElButton @click="getSelections">{{ t('tableDemo.getSelections') }}</ElButton>
<ElButton @click="showOrHiddenSortable">{{ t('tableDemo.showOrHiddenSortable') }}</ElButton>
<!-- <ElButton @click="showOrHiddenSortable">{{ t('tableDemo.showOrHiddenSortable') }}</ElButton> -->
</ContentWrap>
<ContentWrap :title="`UseTable ${t('tableDemo.example')}`">
<Table
@ -261,7 +255,6 @@ const showOrHiddenSortable = () => {
:columns="columns"
:data="dataList"
:loading="loading"
:sortable="sortable"
:pagination="
canShowPagination
? {
@ -271,7 +264,6 @@ const showOrHiddenSortable = () => {
"
@register="tableRegister"
@refresh="refresh"
@sortable-change="sortableChange"
/>
</ContentWrap>
</template>