Files
qiming/qiming-mobile/components/chat-upload-image/chat-upload-image.uvue

227 lines
5.2 KiB
Plaintext

<template>
<scroll-view
class="files-container"
direction="horizontal"
:scroll-with-animation="true"
:show-scrollbar="false"
>
<template v-for="file in files" :key="file.uid">
<!-- 如果文件是图片,则显示图片,否则显示文档默认图片 -->
<view
class="files-box relative"
:class="[
!file?.type?.includes('image/')
? 'files-box-file'
: 'files-box-image',
file.status === UploadFileStatus.error ? 'files-box-error' : '',
]"
@click="onPreview(file)"
>
<view
class="files-box-loading"
v-if="file.status === UploadFileStatus.uploading"
>
<image
class="icon-loading-image"
src="@/static/assets/image_loading.svg"
alt=""
/>
</view>
<!-- 图片 -->
<image
class="image"
v-if="file?.type?.includes('image/')"
:src="file?.url"
mode="aspectFill"
:alt="file?.name || t('Mobile.Chat.uploadImageAlt')"
/>
<!-- 文件 -->
<template v-else>
<image
class="doc-image"
:src="docImage"
mode="aspectFill"
:alt="t('Mobile.Chat.uploadFileAlt')"
/>
<view class="doc-info-container">
<view class="doc-name text-ellipsis">{{ file?.name }}</view>
<text class="doc-size text-ellipsis">{{
formatBytes(file?.size)
}}</text>
</view>
</template>
<!-- 删除按钮 -->
<view
v-if="file.status !== UploadFileStatus.uploading"
class="del-container"
@click.stop="emit('onDel', file.uid)"
>
<image
src="@/static/assets/x-circle-fill.svg"
mode="aspectFit"
style="width: 40rpx; height: 40rpx"
:alt="t('Mobile.Common.deleteIconAlt')"
/>
</view>
</view>
</template>
<!-- 添加按钮 -->
<view
class="files-box files-box-plus"
@click="emit('onAdd')"
v-if="props.showAddButton"
>
<text class="iconfont icon-Plus" />
</view>
</scroll-view>
</template>
<script lang="uts" setup>
import { UploadFileInfo } from "@/types/interfaces/common.uts";
import docImage from "@/static/assets/doc_image.png";
import { formatBytes } from "@/utils/byteConverter.uts";
import { UploadFileStatus } from "@/types/enums/common.uts";
import { useI18n } from "@/utils/i18n";
const props = defineProps<{
files: UploadFileInfo[];
showAddButton?: boolean;
}>();
const previewImages = computed(() => {
return (
props.files
?.filter((f) => f.type.includes("image/"))
?.map((file) => file.url) || []
);
});
const emit = defineEmits<{
onAdd: () => void;
onDel: (uid: string) => void;
}>();
const { t } = useI18n();
// 预览图片
const onPreview = (file: UploadFileInfo) => {
if (!file.type.includes("image/")) {
uni.showToast({
title: t("Mobile.Chat.previewTypeUnsupported"),
icon: "none",
duration: 1500,
});
return;
}
const urls = previewImages.value;
uni.previewImage({
urls,
current: file.url || "",
});
};
</script>
<style lang="scss" scoped>
.files-container {
display: flex;
flex-direction: row;
// padding: 0 32rpx;
.files-box {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
border-radius: 16rpx;
margin-right: 10rpx;
overflow: hidden;
border: 2rpx solid transparent;
&-loading {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
display: flex;
justify-content: center;
background: rgba(64, 62, 62, 0.15);
.icon-loading-image {
margin-left: 40rpx;
width: 48rpx;
height: 48rpx;
border-radius: 50%;
}
}
&-plus {
width: 128rpx;
height: 128rpx;
background: #f6f6f6;
.iconfont {
font-size: 48rpx;
color: #888;
}
}
&-image {
width: 128rpx;
height: 128rpx;
background: #f6f6f6;
}
&-error {
border-color: #f93920;
}
&-file {
width: 400rpx;
padding: 16rpx;
background: rgba(12, 20, 102, 0.04);
gap: 8rpx;
overflow: hidden;
.doc-image {
display: flex;
align-items: center;
justify-content: center;
width: 96rpx;
height: 96rpx;
}
.doc-info-container {
flex: 1;
display: flex;
flex-direction: column;
gap: 4rpx;
font-weight: 400;
.doc-name {
font-size: 28rpx;
color: #15171f;
}
.doc-size {
font-size: 24rpx;
color: #828894;
}
}
}
.image {
width: 100%;
height: 100%;
}
.del-container {
position: absolute;
top: 4rpx;
right: 4rpx;
z-index: 10;
}
}
}
</style>