Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Lucky高
vue-vben-admin
提交
746d4a74
V
vue-vben-admin
项目概览
Lucky高
/
vue-vben-admin
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vue-vben-admin
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
746d4a74
编写于
11月 12, 2020
作者:
J
jq
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
wip: add upload component
上级
2b95be80
变更
19
隐藏空白更改
内联
并排
Showing
19 changed file
with
847 addition
and
21 deletion
+847
-21
.env.development
.env.development
+1
-1
src/api/demo/model/uploadModel.ts
src/api/demo/model/uploadModel.ts
+5
-0
src/api/demo/upload.ts
src/api/demo/upload.ts
+23
-0
src/components/Table/src/types/tableAction.ts
src/components/Table/src/types/tableAction.ts
+1
-0
src/components/Upload/index.ts
src/components/Upload/index.ts
+2
-0
src/components/Upload/src/ThumnUrl.vue
src/components/Upload/src/ThumnUrl.vue
+29
-0
src/components/Upload/src/UploadContainer.vue
src/components/Upload/src/UploadContainer.vue
+62
-0
src/components/Upload/src/UploadModal.vue
src/components/Upload/src/UploadModal.vue
+244
-0
src/components/Upload/src/UploadPreviewModal.vue
src/components/Upload/src/UploadPreviewModal.vue
+93
-0
src/components/Upload/src/data.tsx
src/components/Upload/src/data.tsx
+159
-0
src/components/Upload/src/props.ts
src/components/Upload/src/props.ts
+42
-0
src/components/Upload/src/types.ts
src/components/Upload/src/types.ts
+25
-0
src/components/Upload/src/useUpload.ts
src/components/Upload/src/useUpload.ts
+55
-0
src/components/Upload/src/utils.ts
src/components/Upload/src/utils.ts
+28
-0
src/router/menus/modules/demo/comp.ts
src/router/menus/modules/demo/comp.ts
+4
-0
src/router/routes/modules/demo/comp.ts
src/router/routes/modules/demo/comp.ts
+8
-0
src/utils/http/axios/Axios.ts
src/utils/http/axios/Axios.ts
+38
-20
src/utils/http/axios/types.ts
src/utils/http/axios/types.ts
+11
-0
src/views/demo/comp/upload/index.vue
src/views/demo/comp/upload/index.vue
+17
-0
未找到文件。
.env.development
浏览文件 @
746d4a74
...
...
@@ -5,7 +5,7 @@ VITE_USE_MOCK = true
VITE_PUBLIC_PATH = /
# Cross-domain proxy, you can configure multiple
VITE_PROXY=[["/api","http://localhost:3000"]]
VITE_PROXY=[["/api","http://localhost:3000"]
,["/upload","http://localhost:3001/upload"]
]
# VITE_PROXY=[["/api","https://vvbin.cn/test"]]
# Delete console
...
...
src/api/demo/model/uploadModel.ts
0 → 100644
浏览文件 @
746d4a74
export
interface
UploadApiResult
{
message
:
string
;
code
:
number
;
url
:
string
;
}
src/api/demo/upload.ts
0 → 100644
浏览文件 @
746d4a74
import
{
UploadApiResult
}
from
'
./model/uploadModel
'
;
import
{
defHttp
}
from
'
/@/utils/http/axios
'
;
import
{
UploadFileParams
}
from
'
/@/utils/http/axios/types
'
;
enum
Api
{
UPLOAD_URL
=
'
/upload
'
,
}
/**
* @description: 上传接口
*/
export
function
uploadApi
(
params
:
UploadFileParams
,
onUploadProgress
:
(
progressEvent
:
ProgressEvent
)
=>
void
)
{
return
defHttp
.
uploadFile
<
UploadApiResult
>
(
{
url
:
Api
.
UPLOAD_URL
,
onUploadProgress
,
},
params
);
}
src/components/Table/src/types/tableAction.ts
浏览文件 @
746d4a74
export
interface
ActionItem
{
on
?:
any
;
onClick
?:
any
;
label
:
string
;
disabled
?:
boolean
;
color
?:
'
success
'
|
'
error
'
|
'
warning
'
;
...
...
src/components/Upload/index.ts
0 → 100644
浏览文件 @
746d4a74
export
{
default
as
UploadContainer
}
from
'
./src/UploadContainer.vue
'
;
// export * from './src/types';
src/components/Upload/src/ThumnUrl.vue
0 → 100644
浏览文件 @
746d4a74
<
template
>
<span>
<img
v-if=
"fileUrl"
:src=
"fileUrl"
/>
<span
v-else
>
{{
fileType
}}
</span>
</span>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
}
from
'
vue
'
;
export
default
defineComponent
({
props
:
{
fileUrl
:
{
type
:
String
,
default
:
''
,
},
fileType
:
{
type
:
String
,
default
:
''
,
},
fileName
:
{
type
:
String
,
default
:
''
,
},
},
setup
()
{
return
{};
},
});
</
script
>
src/components/Upload/src/UploadContainer.vue
0 → 100644
浏览文件 @
746d4a74
<
template
>
<div>
<a-button-group>
<a-button
type=
"primary"
@
click=
"openUploadModal"
>
上传
</a-button>
<a-button
@
click=
"openPreviewModal"
>
<Icon
icon=
"ant-design:eye-outlined"
/>
</a-button>
</a-button-group>
<UploadModal
v-bind=
"$props"
@
register=
"registerUploadModal"
@
change=
"handleChange"
/>
<UploadPreviewModal
:value=
"fileListRef"
@
register=
"registerPreviewModal"
@
change=
"handlePreviewChange"
/>
</div>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
,
ref
,
watch
,
unref
}
from
'
vue
'
;
import
{
useModal
}
from
'
/@/components/Modal
'
;
import
UploadModal
from
'
./UploadModal.vue
'
;
import
{
uploadContainerProps
}
from
'
./props
'
;
import
UploadPreviewModal
from
'
./UploadPreviewModal.vue
'
;
import
Icon
from
'
/@/components/Icon/index
'
;
export
default
defineComponent
({
components
:
{
UploadModal
,
UploadPreviewModal
,
Icon
},
props
:
uploadContainerProps
,
setup
(
props
,
{
emit
})
{
// 上传modal
const
[
registerUploadModal
,
{
openModal
:
openUploadModal
}]
=
useModal
();
// 预览modal
const
[
registerPreviewModal
,
{
openModal
:
openPreviewModal
}]
=
useModal
();
const
fileListRef
=
ref
<
string
[]
>
([]);
watch
(
()
=>
props
.
value
,
(
value
)
=>
{
fileListRef
.
value
=
[...(
value
||
[])];
},
{
immediate
:
true
}
);
// 上传modal保存操作
function
handleChange
(
urls
:
string
[])
{
fileListRef
.
value
=
[...
unref
(
fileListRef
),
...(
urls
||
[])];
emit
(
'
change
'
,
fileListRef
.
value
);
}
// 预览modal保存操作
function
handlePreviewChange
(
urls
:
string
[])
{
fileListRef
.
value
=
[...(
urls
||
[])];
emit
(
'
change
'
,
fileListRef
.
value
);
}
return
{
registerUploadModal
,
openUploadModal
,
handleChange
,
handlePreviewChange
,
registerPreviewModal
,
openPreviewModal
,
fileListRef
,
};
},
});
</
script
>
src/components/Upload/src/UploadModal.vue
0 → 100644
浏览文件 @
746d4a74
<
template
>
<BasicModal
v-bind=
"$attrs"
@
register=
"register"
@
ok=
"handleOk"
:closeFunc=
"handleCloseFunc"
:maskClosable=
"false"
width=
"800px"
title=
"上传组件"
wrapClassName=
"upload-modal"
:okButtonProps=
"
{ disabled: isUploadingRef }"
:cancelButtonProps="{ disabled: isUploadingRef }"
>
<template
#centerdFooter
>
<a-button
@
click=
"handleStartUpload"
color=
"success"
:loading=
"isUploadingRef"
>
{{
isUploadingRef
?
'
上传中
'
:
'
开始上传
'
}}
</a-button>
</
template
>
<Upload
:accept=
"getStringAccept"
:multiple=
"multiple"
:before-upload=
"beforeUpload"
>
<a-button
type=
"primary"
>
选择文件
</a-button>
<span
class=
"px-2"
>
{{ getHelpText }}
</span>
</Upload>
<BasicTable
@
register=
"registerTable"
:dataSource=
"fileListRef"
/>
</BasicModal>
</template>
<
script
lang=
"ts"
>
import
{
defineComponent
,
reactive
,
ref
,
toRef
,
unref
}
from
'
vue
'
;
import
{
Upload
}
from
'
ant-design-vue
'
;
import
{
BasicModal
,
useModalInner
}
from
'
/@/components/Modal
'
;
import
{
BasicTable
,
useTable
}
from
'
/@/components/Table
'
;
// hooks
import
{
useUploadType
}
from
'
./useUpload
'
;
import
{
useMessage
}
from
'
/@/hooks/web/useMessage
'
;
// types
import
{
FileItem
,
UploadResultStatus
}
from
'
./types
'
;
import
{
basicProps
}
from
'
./props
'
;
import
{
createTableColumns
,
createActionColumn
}
from
'
./data
'
;
// utils
import
{
checkFileType
,
checkImgType
,
getBase64WithFile
}
from
'
./utils
'
;
import
{
buildUUID
}
from
'
/@/utils/uuid
'
;
import
{
createImgPreview
}
from
'
/@/components/Preview/index
'
;
import
{
uploadApi
}
from
'
/@/api/demo/upload
'
;
export
default
defineComponent
({
components
:
{
BasicModal
,
Upload
,
BasicTable
},
props
:
basicProps
,
setup
(
props
,
{
emit
})
{
const
[
register
,
{
closeModal
}]
=
useModalInner
();
const
{
getAccept
,
getStringAccept
,
getHelpText
}
=
useUploadType
({
acceptRef
:
toRef
(
props
,
'
accept
'
),
helpTextRef
:
toRef
(
props
,
'
helpText
'
),
maxNumberRef
:
toRef
(
props
,
'
maxNumber
'
),
maxSizeRef
:
toRef
(
props
,
'
maxSize
'
),
});
const
fileListRef
=
ref
<
FileItem
[]
>
([]);
const
state
=
reactive
<
{
fileList
:
FileItem
[]
}
>
({
fileList
:
[]
});
const
{
createMessage
}
=
useMessage
();
// 上传前校验
function
beforeUpload
(
file
:
File
)
{
const
{
size
,
name
}
=
file
;
const
{
maxSize
}
=
props
;
const
accept
=
unref
(
getAccept
);
// 设置最大值,则判断
if
(
maxSize
&&
file
.
size
/
1024
/
1024
>=
maxSize
)
{
createMessage
.
error
(
`只能上传不超过
${
maxSize
}
MB的文件!`
);
return
false
;
}
// 设置类型,则判断
if
(
accept
.
length
>
0
&&
!
checkFileType
(
file
,
accept
))
{
createMessage
.
error
!
(
`只能上传
${
accept
.
join
(
'
,
'
)}
格式文件`
);
return
false
;
}
// 生成图片缩略图
if
(
checkImgType
(
file
))
{
// beforeUpload,如果异步会调用自带上传方法
// file.thumbUrl = await getBase64(file);
getBase64WithFile
(
file
).
then
(({
result
:
thumbUrl
})
=>
{
fileListRef
.
value
=
[
...
unref
(
fileListRef
),
{
uuid
:
buildUUID
(),
file
,
thumbUrl
,
size
,
name
,
percent
:
0
,
type
:
name
.
split
(
'
.
'
).
pop
(),
},
];
});
}
else
{
fileListRef
.
value
=
[
...
unref
(
fileListRef
),
{
uuid
:
buildUUID
(),
file
,
size
,
name
,
percent
:
0
,
type
:
name
.
split
(
'
.
'
).
pop
(),
},
];
}
return
false
;
}
// 删除
function
handleRemove
(
record
:
FileItem
)
{
const
index
=
fileListRef
.
value
.
findIndex
((
item
)
=>
item
.
uuid
===
record
.
uuid
);
index
!==
-
1
&&
fileListRef
.
value
.
splice
(
index
,
1
);
}
// 预览
function
handlePreview
(
record
:
FileItem
)
{
const
{
thumbUrl
=
''
}
=
record
;
createImgPreview
({
imageList
:
[
thumbUrl
],
});
}
const
[
registerTable
]
=
useTable
({
columns
:
createTableColumns
(),
actionColumn
:
createActionColumn
(
handleRemove
,
handlePreview
),
pagination
:
false
,
});
// 是否正在上传
const
isUploadingRef
=
ref
(
false
);
async
function
uploadApiByItem
(
item
:
FileItem
)
{
try
{
item
.
status
=
UploadResultStatus
.
UPLOADING
;
const
{
data
}
=
await
uploadApi
(
{
file
:
item
.
file
,
},
function
onUploadProgress
(
progressEvent
:
ProgressEvent
)
{
const
complete
=
((
progressEvent
.
loaded
/
progressEvent
.
total
)
*
100
)
|
0
;
item
.
percent
=
complete
;
}
);
item
.
status
=
UploadResultStatus
.
SUCCESS
;
item
.
responseData
=
data
;
return
{
success
:
true
,
error
:
null
,
};
}
catch
(
e
)
{
console
.
log
(
e
);
item
.
status
=
UploadResultStatus
.
ERROR
;
return
{
success
:
false
,
error
:
e
,
};
}
}
// 点击开始上传
async
function
handleStartUpload
()
{
try
{
isUploadingRef
.
value
=
true
;
const
data
=
await
Promise
.
all
(
unref
(
fileListRef
).
map
((
item
)
=>
{
return
uploadApiByItem
(
item
);
})
);
isUploadingRef
.
value
=
false
;
// 生产环境:抛出错误
const
errorList
=
data
.
filter
((
item
)
=>
!
item
.
success
);
if
(
errorList
.
length
>
0
)
{
throw
errorList
;
}
}
catch
(
e
)
{
isUploadingRef
.
value
=
false
;
throw
e
;
}
}
// 点击保存
function
handleOk
()
{
// TODO: 没起作用:okButtonProps={{ disabled: state.isUploading }}
if
(
isUploadingRef
.
value
)
{
createMessage
.
warning
(
'
请等待文件上传后,保存
'
);
return
;
}
const
fileList
:
string
[]
=
[];
for
(
const
item
of
fileListRef
.
value
)
{
const
{
status
,
responseData
}
=
item
;
if
(
status
===
UploadResultStatus
.
SUCCESS
&&
responseData
)
{
fileList
.
push
(
responseData
.
url
);
}
}
// 存在一个上传成功的即可保存
if
(
fileList
.
length
<=
0
)
{
createMessage
.
warning
(
'
没有上传成功的文件,无法保存
'
);
return
;
}
console
.
log
(
fileList
);
emit
(
'
change
'
,
fileList
);
fileListRef
.
value
=
[];
closeModal
();
}
// 点击关闭:则所有操作不保存,包括上传的
function
handleCloseFunc
()
{
if
(
!
isUploadingRef
.
value
)
{
fileListRef
.
value
=
[];
return
true
;
}
else
{
createMessage
.
warning
(
'
请等待文件上传结束后操作
'
);
return
false
;
}
}
return
{
register
,
closeModal
,
getHelpText
,
getStringAccept
,
beforeUpload
,
registerTable
,
fileListRef
,
state
,
isUploadingRef
,
handleStartUpload
,
handleOk
,
handleCloseFunc
,
};
},
});
</
script
>
<
style
lang=
"less"
>
// /deep/ .ant-upload-list {
// display: none;
// }
.upload-modal {
.ant-upload-list {
display: none;
}
.ant-table-wrapper .ant-spin-nested-loading {
padding: 0;
}
}
</
style
>
src/components/Upload/src/UploadPreviewModal.vue
0 → 100644
浏览文件 @
746d4a74
<
template
>
<BasicModal
wrapClassName=
"upload-preview-modal"
v-bind=
"$attrs"
width=
"800px"
@
register=
"register"
title=
"预览"
:showOkBtn=
"false"
>
<BasicTable
@
register=
"registerTable"
:dataSource=
"fileListRef"
/>
</BasicModal>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
,
watch
,
ref
,
unref
}
from
'
vue
'
;
import
{
BasicTable
,
useTable
}
from
'
/@/components/Table
'
;
import
{
createPreviewColumns
,
createPreviewActionColumn
}
from
'
./data
'
;
import
{
BasicModal
,
useModalInner
}
from
'
/@/components/Modal
'
;
import
{
priviewProps
}
from
'
./props
'
;
import
{
PreviewFileItem
}
from
'
./types
'
;
import
{
createImgPreview
}
from
'
/@/components/Preview/index
'
;
import
{
downloadByUrl
}
from
'
/@/utils/file/FileDownload
'
;
export
default
defineComponent
({
components
:
{
BasicModal
,
BasicTable
},
props
:
priviewProps
,
setup
(
props
,
{
emit
})
{
const
[
register
,
{
closeModal
}]
=
useModalInner
();
const
fileListRef
=
ref
<
PreviewFileItem
[]
>
([]);
watch
(
()
=>
props
.
value
,
(
value
)
=>
{
fileListRef
.
value
=
[];
value
.
forEach
((
item
)
=>
{
fileListRef
.
value
=
[
...
unref
(
fileListRef
),
{
url
:
item
,
type
:
item
.
split
(
'
.
'
).
pop
()
||
''
,
name
:
item
.
split
(
'
/
'
).
pop
()
||
''
,
},
];
});
},
{
immediate
:
true
}
);
// 删除
function
handleRemove
(
record
:
PreviewFileItem
)
{
const
index
=
fileListRef
.
value
.
findIndex
((
item
)
=>
item
.
url
===
record
.
url
);
if
(
index
!==
-
1
)
{
fileListRef
.
value
.
splice
(
index
,
1
);
emit
(
'
change
'
,
fileListRef
.
value
.
map
((
item
)
=>
item
.
url
)
);
}
}
// 预览
function
handlePreview
(
record
:
PreviewFileItem
)
{
const
{
url
=
''
}
=
record
;
createImgPreview
({
imageList
:
[
url
],
});
}
// 下载
function
handleDownload
(
record
:
PreviewFileItem
)
{
const
{
url
=
''
}
=
record
;
downloadByUrl
({
url
});
}
const
[
registerTable
]
=
useTable
({
columns
:
createPreviewColumns
(),
pagination
:
false
,
actionColumn
:
createPreviewActionColumn
({
handleRemove
,
handlePreview
,
handleDownload
}),
});
return
{
register
,
closeModal
,
fileListRef
,
registerTable
,
};
},
});
</
script
>
<
style
lang=
"less"
>
.upload-preview-modal {
.ant-upload-list {
display: none;
}
.ant-table-wrapper .ant-spin-nested-loading {
padding: 0;
}
}
</
style
>
src/components/Upload/src/data.tsx
0 → 100644
浏览文件 @
746d4a74
// import { BasicColumn, TableAction, ActionItem } from '@/components/table';
import
{
checkImgType
,
isImgTypeByName
}
from
'
./utils
'
;
// import ThumnUrl from './ThumbUrl.vue';
import
{
Progress
}
from
'
ant-design-vue
'
;
import
{
FileItem
,
PreviewFileItem
,
UploadResultStatus
}
from
'
./types
'
;
// import { ElecArchivesSaveResult } from '@/api/biz/file/model/fileModel';
// import { quryFile } from '@/api/biz/file/file';
import
{
BasicColumn
,
ActionItem
,
TableAction
}
from
'
/@/components/Table/index
'
;
// 文件上传列表
export
function
createTableColumns
():
BasicColumn
[]
{
return
[
{
dataIndex
:
'
thumbUrl
'
,
title
:
'
图例
'
,
width
:
100
,
customRender
:
({
record
})
=>
{
const
{
thumbUrl
,
type
}
=
(
record
as
FileItem
)
||
{};
return
<
span
>
{
thumbUrl
?
<
img
src
=
{
thumbUrl
}
style
=
{
{
width
:
'
50px
'
}
}
/>
:
type
}
</
span
>;
// return <ThumnUrl fileUrl={thumbUrl} fileType={type} fileName={type} />;
},
},
{
dataIndex
:
'
name
'
,
title
:
'
文件名
'
,
align
:
'
left
'
,
customRender
:
({
text
,
record
})
=>
{
const
{
percent
,
status
:
uploadStatus
}
=
(
record
as
FileItem
)
||
{};
let
status
=
'
normal
'
;
if
(
uploadStatus
===
UploadResultStatus
.
ERROR
)
{
status
=
'
exception
'
;
}
else
if
(
uploadStatus
===
UploadResultStatus
.
UPLOADING
)
{
status
=
'
active
'
;
}
else
if
(
uploadStatus
===
UploadResultStatus
.
SUCCESS
)
{
status
=
'
success
'
;
}
return
(
<
span
>
<
p
class
=
"ellipsis mb-1"
title
=
{
text
}
>
{
text
}
</
p
>
<
Progress
percent
=
{
percent
}
size
=
"small"
status
=
{
status
}
/>
</
span
>
);
},
},
{
dataIndex
:
'
size
'
,
title
:
'
文件大小
'
,
width
:
100
,
customRender
:
({
text
=
0
})
=>
{
return
text
&&
(
text
/
1024
).
toFixed
(
2
)
+
'
KB
'
;
},
},
// {
// dataIndex: 'type',
// title: '文件类型',
// width: 100,
// },
{
dataIndex
:
'
status
'
,
title
:
'
状态
'
,
width
:
100
,
customRender
:
({
text
})
=>
{
if
(
text
===
UploadResultStatus
.
SUCCESS
)
{
return
'
上传成功
'
;
}
else
if
(
text
===
UploadResultStatus
.
ERROR
)
{
return
'
上传失败
'
;
}
else
if
(
text
===
UploadResultStatus
.
UPLOADING
)
{
return
'
上传中
'
;
}
return
text
;
},
},
];
}
export
function
createActionColumn
(
handleRemove
:
Function
,
handlePreview
:
Function
):
BasicColumn
{
return
{
width
:
120
,
title
:
'
操作
'
,
dataIndex
:
'
action
'
,
fixed
:
false
,
customRender
:
({
record
})
=>
{
const
actions
:
ActionItem
[]
=
[
{
label
:
'
删除
'
,
onClick
:
handleRemove
.
bind
(
null
,
record
),
},
];
if
(
checkImgType
(
record
))
{
actions
.
unshift
({
label
:
'
预览
'
,
onClick
:
handlePreview
.
bind
(
null
,
record
),
});
}
return
<
TableAction
actions
=
{
actions
}
/>;
},
};
}
// 文件预览列表
export
function
createPreviewColumns
():
BasicColumn
[]
{
return
[
{
dataIndex
:
'
url
'
,
title
:
'
图例
'
,
width
:
100
,
customRender
:
({
record
})
=>
{
const
{
url
,
type
}
=
(
record
as
PreviewFileItem
)
||
{};
return
(
<
span
>
{
isImgTypeByName
(
url
)
?
<
img
src
=
{
url
}
style
=
{
{
width
:
'
50px
'
}
}
/>
:
type
}
</
span
>
);
},
},
{
dataIndex
:
'
name
'
,
title
:
'
文件名
'
,
align
:
'
left
'
,
},
];
}
export
function
createPreviewActionColumn
({
handleRemove
,
handlePreview
,
handleDownload
,
}:
{
handleRemove
:
Function
;
handlePreview
:
Function
;
handleDownload
:
Function
;
}):
BasicColumn
{
return
{
width
:
160
,
title
:
'
操作
'
,
dataIndex
:
'
action
'
,
fixed
:
false
,
customRender
:
({
record
})
=>
{
const
{
url
}
=
(
record
as
PreviewFileItem
)
||
{};
const
actions
:
ActionItem
[]
=
[
{
label
:
'
删除
'
,
onClick
:
handleRemove
.
bind
(
null
,
record
),
},
{
label
:
'
下载
'
,
onClick
:
handleDownload
.
bind
(
null
,
record
),
},
];
if
(
isImgTypeByName
(
url
))
{
actions
.
unshift
({
label
:
'
预览
'
,
onClick
:
handlePreview
.
bind
(
null
,
record
),
});
}
return
<
TableAction
actions
=
{
actions
}
/>;
},
};
}
src/components/Upload/src/props.ts
0 → 100644
浏览文件 @
746d4a74
import
type
{
PropType
}
from
'
vue
'
;
export
const
basicProps
=
{
helpText
:
{
type
:
String
as
PropType
<
string
>
,
default
:
''
,
},
// 文件最大多少MB
maxSize
:
{
type
:
Number
as
PropType
<
number
>
,
default
:
2
,
},
// 最大数量的文件,0不限制
maxNumber
:
{
type
:
Number
as
PropType
<
number
>
,
default
:
0
,
},
// 根据后缀,或者其他
accept
:
{
type
:
Array
as
PropType
<
string
[]
>
,
default
:
()
=>
[],
},
multiple
:
{
type
:
Boolean
,
default
:
true
,
},
};
export
const
uploadContainerProps
=
{
value
:
{
type
:
Array
as
PropType
<
string
[]
>
,
default
:
()
=>
[],
},
...
basicProps
,
};
export
const
priviewProps
=
{
value
:
{
type
:
Array
as
PropType
<
string
[]
>
,
default
:
()
=>
[],
},
};
src/components/Upload/src/types.ts
0 → 100644
浏览文件 @
746d4a74
import
{
UploadApiResult
}
from
'
/@/api/demo/model/uploadModel
'
;
export
enum
UploadResultStatus
{
SUCCESS
=
'
success
'
,
ERROR
=
'
error
'
,
UPLOADING
=
'
uploading
'
,
}
export
interface
FileItem
{
thumbUrl
?:
string
;
name
:
string
;
size
:
string
|
number
;
type
?:
string
;
percent
:
number
;
file
:
File
;
status
?:
UploadResultStatus
;
responseData
?:
UploadApiResult
;
uuid
:
string
;
}
export
interface
PreviewFileItem
{
url
:
string
;
name
:
string
;
type
:
string
;
}
src/components/Upload/src/useUpload.ts
0 → 100644
浏览文件 @
746d4a74
import
{
Ref
,
unref
,
computed
}
from
'
vue
'
;
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
;
}
return
[];
});
const
getStringAccept
=
computed
(()
=>
{
return
unref
(
getAccept
)
.
map
((
item
)
=>
`.
${
item
}
`
)
.
join
(
'
,
'
);
});
// 支持jpg、jpeg、png格式,不超过2M,最多可选择10张图片,。
const
getHelpText
=
computed
(()
=>
{
const
helpText
=
unref
(
helpTextRef
);
if
(
helpText
)
{
return
helpText
;
}
const
helpTexts
:
string
[]
=
[];
const
accept
=
unref
(
acceptRef
);
if
(
accept
.
length
>
0
)
{
helpTexts
.
push
(
`支持
${
accept
.
join
(
'
,
'
)}
格式`
);
}
const
maxSize
=
unref
(
maxSizeRef
);
if
(
maxSize
)
{
helpTexts
.
push
(
`不超过
${
maxSize
}
MB`
);
}
const
maxNumber
=
unref
(
maxNumberRef
);
if
(
maxNumber
)
{
helpTexts
.
push
(
`最多可选择
${
maxNumber
}
个文件`
);
}
return
helpTexts
.
join
(
'
,
'
);
});
return
{
getAccept
,
getStringAccept
,
getHelpText
};
}
src/components/Upload/src/utils.ts
0 → 100644
浏览文件 @
746d4a74
export
function
checkFileType
(
file
:
File
,
accepts
:
string
[])
{
const
newTypes
=
accepts
.
join
(
'
|
'
);
// const reg = /\.(jpg|jpeg|png|gif|txt|doc|docx|xls|xlsx|xml)$/i;
const
reg
=
new
RegExp
(
'
\\
.(
'
+
newTypes
+
'
)$
'
,
'
i
'
);
if
(
!
reg
.
test
(
file
.
name
))
{
return
false
;
}
else
{
return
true
;
}
}
export
function
checkImgType
(
file
:
File
)
{
return
/
\.(
jpg|jpeg|png|gif
)
$/i
.
test
(
file
.
name
);
}
export
function
isImgTypeByName
(
name
:
string
)
{
return
/
\.(
jpg|jpeg|png|gif
)
$/i
.
test
(
name
);
}
export
function
getBase64WithFile
(
file
:
File
)
{
return
new
Promise
<
{
result
:
string
;
file
:
File
;
}
>
((
resolve
,
reject
)
=>
{
const
reader
=
new
FileReader
();
reader
.
readAsDataURL
(
file
);
reader
.
onload
=
()
=>
resolve
({
result
:
reader
.
result
as
string
,
file
});
reader
.
onerror
=
(
error
)
=>
reject
(
error
);
});
}
src/router/menus/modules/demo/comp.ts
浏览文件 @
746d4a74
...
...
@@ -38,6 +38,10 @@ const menu: MenuModule = {
path
:
'
strength-meter
'
,
name
:
'
密码强度组件
'
,
},
{
path
:
'
upload
'
,
name
:
'
上传组件
'
,
},
{
path
:
'
scroll
'
,
name
:
'
滚动组件
'
,
...
...
src/router/routes/modules/demo/comp.ts
浏览文件 @
746d4a74
...
...
@@ -170,5 +170,13 @@ export default {
title
:
'
密码强度组件
'
,
},
},
{
path
:
'
/upload
'
,
name
:
'
UploadDemo
'
,
component
:
()
=>
import
(
'
/@/views/demo/comp/upload/index.vue
'
),
meta
:
{
title
:
'
上传组件
'
,
},
},
],
}
as
AppRouteModule
;
src/utils/http/axios/Axios.ts
浏览文件 @
746d4a74
...
...
@@ -5,9 +5,10 @@ import { AxiosCanceler } from './axiosCancel';
import
{
isFunction
}
from
'
/@/utils/is
'
;
import
{
cloneDeep
}
from
'
lodash-es
'
;
import
type
{
RequestOptions
,
CreateAxiosOptions
,
Result
}
from
'
./types
'
;
import
type
{
RequestOptions
,
CreateAxiosOptions
,
Result
,
UploadFileParams
}
from
'
./types
'
;
// import { ContentTypeEnum } from '/@/enums/httpEnum';
import
{
errorResult
}
from
'
./const
'
;
import
{
ContentTypeEnum
}
from
'
/@/enums/httpEnum
'
;
export
*
from
'
./axiosTransform
'
;
...
...
@@ -107,25 +108,42 @@ export class VAxios {
this
.
axiosInstance
.
interceptors
.
response
.
use
(
undefined
,
responseInterceptorsCatch
);
}
// /**
// * @description: 文件上传
// */
// uploadFiles(config: AxiosRequestConfig, params: File[]) {
// const formData = new FormData();
// Object.keys(params).forEach((key) => {
// formData.append(key, params[key as any]);
// });
// return this.request({
// ...config,
// method: 'POST',
// data: formData,
// headers: {
// 'Content-type': ContentTypeEnum.FORM_DATA,
// },
// });
// }
/**
* @description: 文件上传
*/
uploadFile
<
T
=
any
>
(
config
:
AxiosRequestConfig
,
params
:
UploadFileParams
)
{
const
formData
=
new
window
.
FormData
();
if
(
params
.
data
)
{
Object
.
keys
(
params
.
data
).
forEach
((
key
)
=>
{
if
(
!
params
.
data
)
return
;
const
value
=
params
.
data
[
key
];
// support key-value array data
if
(
Array
.
isArray
(
value
))
{
value
.
forEach
((
item
)
=>
{
// { list: [ 11, 22 ] }
// formData.append('list[]', 11);
formData
.
append
(
`
${
key
}
[]`
,
item
);
});
return
;
}
formData
.
append
(
key
,
params
.
data
[
key
]);
});
}
formData
.
append
(
params
.
name
||
'
file
'
,
params
.
file
,
params
.
filename
);
return
this
.
axiosInstance
.
request
<
T
>
({
...
config
,
method
:
'
POST
'
,
data
:
formData
,
headers
:
{
'
Content-type
'
:
ContentTypeEnum
.
FORM_DATA
,
ignoreCancelToken
:
true
,
},
});
}
/**
* @description: 请求方法
...
...
src/utils/http/axios/types.ts
浏览文件 @
746d4a74
...
...
@@ -28,3 +28,14 @@ export interface Result<T = any> {
message
:
string
;
result
:
T
;
}
// multipart/form-data:上传文件
export
interface
UploadFileParams
{
// 其他参数
data
?:
{
[
key
:
string
]:
any
};
// 文件参数的接口字段名
name
?:
string
;
// 文件
file
:
File
|
Blob
;
// 文件名
filename
?:
string
;
}
src/views/demo/comp/upload/index.vue
0 → 100644
浏览文件 @
746d4a74
<
template
>
<div
class=
"p-4"
>
<UploadContainer
:maxSize=
"5"
/>
</div>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
}
from
'
vue
'
;
import
{
UploadContainer
}
from
'
/@/components/Upload/index
'
;
// import { Alert } from 'ant-design-vue';
export
default
defineComponent
({
components
:
{
UploadContainer
},
setup
()
{
return
{};
},
});
</
script
>
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录