254 lines
6.1 KiB
Vue
254 lines
6.1 KiB
Vue
<script lang="ts" setup>
|
||
import { uploadBaseUrl } from '@/common'
|
||
import { UploadFile } from '@idux/components'
|
||
import AppApi from '@/common/app/app-api.ts'
|
||
import Toast from '@/components/toast'
|
||
import TspPhotoApi from '@/pages/tsp-photo/tsp-photo-api.ts'
|
||
import { ref } from 'vue'
|
||
import times, { FMT } from '@/common/utils/times.ts'
|
||
|
||
const props = defineProps<{
|
||
tspId?: string
|
||
pointName?: string
|
||
uploadDate?: string
|
||
status: 'edit' | 'view'
|
||
}>()
|
||
|
||
const emit = defineEmits([ 'refresh' ])
|
||
|
||
|
||
const photoListTitle = computed(() => {
|
||
return props.uploadDate == null || props.pointName == null ? '图片列表'
|
||
: props.pointName + times.format(times.parse(props.uploadDate, FMT.date), FMT.date_zh) + '上传的图片'
|
||
})
|
||
|
||
const files = ref<UploadFile[]>([])
|
||
const fileUrls = ref<{ [key: string]: string }>({})
|
||
|
||
|
||
async function requestData(file: UploadFile) {
|
||
if (file.raw == null) return Promise.reject()
|
||
let res = await AppApi.obtainPresignedUrl(file.name)
|
||
const url = '/' + res.data.bucketName + '/' + res.data.objectName
|
||
file.thumbUrl = AppApi.fileUrl(url)
|
||
const key = file.key as string
|
||
fileUrls.value[key] = url
|
||
|
||
delete res.data.bucketName
|
||
delete res.data.objectName
|
||
return Promise.resolve(res.data)
|
||
}
|
||
|
||
function fileStatusChange(file: UploadFile) {
|
||
if (file.status === 'success') {
|
||
Toast.success('上传成功')
|
||
} else if (file.status === 'error') {
|
||
Toast.error('上传失败')
|
||
}
|
||
}
|
||
|
||
function delPhoto(index: number) {
|
||
const key = files.value[index].key as string
|
||
delete fileUrls.value[key]
|
||
files.value.splice(index, 1)
|
||
}
|
||
|
||
watch(
|
||
() => props.uploadDate,
|
||
(val) => {
|
||
if (val == null) {
|
||
files.value = []
|
||
return
|
||
}
|
||
TspPhotoApi.listPhoto({
|
||
tspId: props.tspId,
|
||
uploadDate: props.uploadDate,
|
||
}).then(res => {
|
||
let data = res.data?.photos ?? []
|
||
let temp: UploadFile[] = []
|
||
for (let datum of data) {
|
||
temp.push({
|
||
key: datum,
|
||
name: datum,
|
||
status: 'success',
|
||
thumbUrl: AppApi.fileUrl(datum),
|
||
})
|
||
}
|
||
files.value = temp
|
||
})
|
||
})
|
||
|
||
function submitPhoto() {
|
||
TspPhotoApi.save({
|
||
tspId: props.tspId,
|
||
uploadDate: props.uploadDate,
|
||
photos: files.value.map(it => fileUrls.value[it.key as string]).filter(it => it != null),
|
||
}).then(() => {
|
||
Toast.success('提交成功')
|
||
emit('refresh')
|
||
})
|
||
}
|
||
|
||
|
||
</script>
|
||
|
||
<template>
|
||
<div class="photo-list-container">
|
||
<div class="photo-title">
|
||
{{ photoListTitle }}
|
||
</div>
|
||
<div v-if="status === 'view'" class="photo-list">
|
||
<IxImage v-for="(it,i) in files" :key="'photo--'+i" :src="it.status==='success' ? it.thumbUrl ?? '' : ''">
|
||
<template #previewIcon>
|
||
<div class="photo-preview">
|
||
<IxIcon name="plus-circle"/>
|
||
</div>
|
||
</template>
|
||
</IxImage>
|
||
</div>
|
||
|
||
<!--<div v-else-if="status === 'edit' && uploadDate != null">
|
||
<div style="height: 100px;width: 100px;background-color: #00B42A" v-for="(it,i) in files" :key="'photo--'+i"></div>
|
||
</div>-->
|
||
|
||
<IxUpload
|
||
v-else-if="status === 'edit' && uploadDate != null"
|
||
v-model:files="files"
|
||
:action="uploadBaseUrl"
|
||
:progress="{strokeColor: {
|
||
'0%': '#108EE9',
|
||
'100%': '#87D068',
|
||
},
|
||
strokeWidth: 3,
|
||
}"
|
||
:request-data="requestData"
|
||
dragable
|
||
accept="image/*"
|
||
multiple
|
||
@file-status-change="fileStatusChange">
|
||
<div class="drag-panel">
|
||
<IxIcon class="drag-panel-icon" name="upload"/>
|
||
<p>点击或拖拽上传</p>
|
||
</div>
|
||
<template #list>
|
||
<div v-if="files.length > 0" class="photo-list">
|
||
<IxImage v-for="(it,i) in files" :key="'photo--'+i" :src="it.status==='success' ? it.thumbUrl ?? '' : ''">
|
||
<template #previewIcon>
|
||
<div class="photo-preview">
|
||
<IxIcon name="plus-circle"/>
|
||
<IxIcon name="delete" @click.stop="delPhoto(i)"/>
|
||
</div>
|
||
</template>
|
||
</IxImage>
|
||
</div>
|
||
<IxEmpty v-else/>
|
||
</template>
|
||
</IxUpload>
|
||
<IxEmpty v-else description="请选择小区和日期"/>
|
||
<div v-if="status === 'edit' && uploadDate != null" class="photo-bottom">
|
||
<IxPopconfirm placement="top" title="是否提交?" @ok="submitPhoto">
|
||
<IxButton :disabled="files.length === 0" mode="primary">提交修改</IxButton>
|
||
<template #content>
|
||
<div>小区:{{ pointName }}</div>
|
||
<div>日期:{{ uploadDate }}</div>
|
||
<div>图片数量:{{ files.length }}</div>
|
||
</template>
|
||
</IxPopconfirm>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style lang="stylus" scoped>
|
||
.photo-list-container {
|
||
width 30%
|
||
height 100%
|
||
|
||
display flex
|
||
flex-direction column
|
||
|
||
.photo-title {
|
||
font-size 2rem
|
||
font-weight bold
|
||
padding 1rem
|
||
box-sizing border-box
|
||
border-bottom 1px solid rgb(211, 215, 222);
|
||
text-wrap: auto;
|
||
word-break: break-word;
|
||
overflow-wrap: normal;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
:deep(.ix-upload) {
|
||
flex 1
|
||
display: flex
|
||
flex-direction: column;
|
||
height: 0;
|
||
|
||
.ix-upload-selector {
|
||
height 6rem
|
||
width 100%;
|
||
margin-bottom 1rem
|
||
|
||
.drag-panel {
|
||
height 100%
|
||
width 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap 1rem
|
||
|
||
&-icon {
|
||
font-size: 24px;
|
||
}
|
||
|
||
p {
|
||
font-size: 14px;
|
||
margin: 8px 0 0 0;
|
||
}
|
||
|
||
&:hover {
|
||
color: #1C6EFF;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.photo-list {
|
||
flex 1
|
||
width 100%;
|
||
padding 1rem
|
||
overflow auto
|
||
display grid
|
||
grid-template-columns repeat(2, 1fr)
|
||
grid-auto-rows: 8rem
|
||
gap 1rem
|
||
align-items stretch
|
||
|
||
& > div {
|
||
height: 8rem;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.photo-preview {
|
||
display: flex
|
||
color: white;
|
||
font-size: 2rem;
|
||
gap: 1rem;
|
||
}
|
||
}
|
||
|
||
.photo-bottom {
|
||
display flex
|
||
justify-content space-evenly
|
||
align-items center
|
||
height 10rem
|
||
gap 5%
|
||
padding 1rem
|
||
|
||
& > button {
|
||
width 10rem
|
||
}
|
||
}
|
||
}
|
||
</style>
|