github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/static_source/admin/src/views/Images/components/Browser.vue (about) 1 <script setup lang="ts"> 2 import {ElBadge, ElButton, ElCol, ElMessage, ElRow, ElUpload, UploadProps} from 'element-plus' 3 import {useI18n} from '@/hooks/web/useI18n' 4 import {defineEmits, reactive, unref} from "vue"; 5 import {ApiImage, GetImageFilterListResultfilter} from "@/api/stub"; 6 import api from "@/api/api"; 7 import {createImageViewer} from "@/components/ImageViewer"; 8 import {propTypes} from "@/utils/propTypes"; 9 import {useCache} from "@/hooks/web/useCache"; 10 import {GetFullUrl, prepareUrl} from "@/utils/serverId"; 11 12 const {wsCache} = useCache() 13 const {t} = useI18n() 14 const emit = defineEmits(['imageSelected']) 15 16 interface ViewerObject { 17 loading: boolean 18 filterList?: GetImageFilterListResultfilter[] 19 currentFilter?: GetImageFilterListResultfilter 20 imageList?: ApiImage[] 21 selected?: ApiImage 22 } 23 24 const props = defineProps({ 25 id: propTypes.string.def(''), 26 selectMode: propTypes.bool.def(false), 27 }) 28 29 const viewerObject = reactive<ViewerObject>( 30 { 31 loading: false, 32 } 33 ) 34 35 const fetch = async () => { 36 await getFilterList() 37 if (viewerObject.filterList && viewerObject.filterList.length > 0) { 38 getList(viewerObject.filterList[viewerObject.filterList.length - 1]) 39 } 40 } 41 42 const getList = async (filter?: GetImageFilterListResultfilter) => { 43 if (!filter) { 44 return 45 } 46 viewerObject.currentFilter = filter; 47 viewerObject.loading = true 48 const res = await api.v1.imageServiceGetImageListByDate({filter: filter.date}) 49 .catch(() => { 50 }) 51 .finally(() => { 52 viewerObject.loading = false 53 }) 54 55 let {items} = unref(res.data); 56 for (const key in items) { 57 items[key].url = GetFullUrl(items[key].url) 58 } 59 viewerObject.imageList = items 60 } 61 62 const getFilterList = async () => { 63 viewerObject.loading = true 64 65 const res = await api.v1.imageServiceGetImageFilterList() 66 .catch(() => { 67 }) 68 .finally(() => { 69 viewerObject.loading = false 70 }) 71 if (res) { 72 const {items} = res.data; 73 viewerObject.filterList = items; 74 } 75 } 76 77 const select = (image: ApiImage) => { 78 if (image) { 79 if (viewerObject.selected && viewerObject.selected.id === image.id) { 80 viewerObject.selected = undefined 81 } 82 viewerObject.selected = image 83 } else { 84 viewerObject.selected = undefined 85 } 86 const output = Object.assign({}, unref(viewerObject)?.selected) as ApiImage 87 output.url = output.url.replace(import.meta.env.VITE_API_BASEPATH, ''); 88 const serverId = wsCache.get('serverId') 89 output.url = output.url.replace('?serverId=' + serverId, ''); 90 emit('imageSelected', {id: props.id, image: output}) 91 //todo: fix 92 ElMessage({ 93 message: t('message.selectedImage') + ` ${output.id}`, 94 type: 'success', 95 duration: 2000 96 }) 97 } 98 99 const removeFromServer = async (image: ApiImage) => { 100 await api.v1.imageServiceDeleteImageById(image.id) 101 // await getList(viewerObject.currentFilter) 102 await getFilterList() 103 } 104 105 const onSuccess: UploadProps['onSuccess'] = (image: ApiImage, uploadFile) => { 106 getFilterList() 107 getList(viewerObject.currentFilter) 108 ElMessage({ 109 message: t('message.uploadSuccessfully'), 110 type: 'success', 111 duration: 2000 112 }) 113 } 114 115 const getUploadURL = () => { 116 const uri = import.meta.env.VITE_API_BASEPATH as string || window.location.origin; 117 const accessToken = wsCache.get("accessToken") 118 return prepareUrl(uri + '/v1/image/upload?access_token=' + accessToken); 119 } 120 121 const handleRemove: UploadProps['onRemove'] = (image: ApiImage, uploadFiles) => { 122 removeFromServer(image) 123 } 124 125 const handlePictureCardPreview: UploadProps['onPreview'] = (image) => { 126 if (props.selectMode) { 127 select(image) 128 return 129 } 130 createImageViewer({ 131 urlList: [ 132 prepareUrl(image.url)! 133 ] 134 }) 135 } 136 137 fetch() 138 139 </script> 140 141 <template> 142 <ElRow class="file-manager-body"> 143 <ElCol :span="6" :xs="24" class="mb-20px"> 144 <ul class="list-unstyled filters"> 145 <li v-for="item in viewerObject.filterList?.slice().reverse()" :key="item.date"> 146 <ElBadge :value="item.count" class="item" type="info"> 147 <ElButton :link="true" @click.prevent.stop="getList(item)"> 148 {{ item.date }} 149 </ElButton> 150 </ElBadge> 151 </li> 152 </ul> 153 </ElCol> 154 <ElCol :span="18" :xs="24"> 155 156 <ElUpload 157 v-model:file-list="viewerObject.imageList" 158 list-type="picture-card" 159 :multiple="true" 160 ref="upload" 161 :action="getUploadURL()" 162 :on-success="onSuccess" 163 :on-preview="handlePictureCardPreview" 164 :on-remove="handleRemove" 165 :auto-upload="true"> 166 <Icon icon="ic:baseline-plus"/> 167 </ElUpload> 168 169 </ElCol> 170 </ElRow> 171 172 </template> 173 174 <style lang="less"> 175 176 .list-unstyled { 177 list-style: none; 178 } 179 180 .file-manager-body { 181 padding: 20px; 182 position: relative; 183 184 .el-image { 185 display: block; 186 } 187 188 .drop-box { 189 background: #F8F8F8; 190 border: 1px dashed #DDD; 191 text-align: center; 192 padding-top: 25px; 193 cursor: pointer; 194 195 .title { 196 font-size: 10px; 197 } 198 199 } 200 201 ul.filters { 202 203 li { 204 position: relative; 205 206 &.selected { 207 font-weight: 600; 208 } 209 210 } 211 } 212 213 ul.file-manager-items { 214 margin: 0; 215 padding: 0; 216 list-style: none; 217 218 .fa-cloud-upload { 219 font-size: 3rem; 220 } 221 222 li.file-manager-item { 223 width: 150px; 224 height: 100px; 225 float: left; 226 margin: 5px; 227 overflow: hidden; 228 position: relative; 229 230 img { 231 background-repeat: no-repeat; 232 background-size: 100% auto; 233 width: 100%; 234 } 235 236 .file-manager-item-title { 237 position: absolute; 238 bottom: 0; 239 background: black; 240 opacity: 0.5; 241 color: #ffffff; 242 font-size: 10px; 243 left: 0; 244 right: 0; 245 padding: 2px 8px; 246 } 247 248 .cross.close-button { 249 opacity: 0; 250 background-color: #FFFFFF; 251 position: absolute; 252 top: 0; 253 right: 0; 254 cursor: pointer; 255 256 } 257 258 .is_selected { 259 position: absolute; 260 top: 0; 261 left: 0; 262 bottom: 0; 263 right: 0; 264 background: rgba(0, 0, 0, 0.5); 265 text-align: center; 266 font-size: 35px; 267 color: #FFF; 268 padding-top: 31px; 269 } 270 271 &:hover { 272 273 .cross.close-button { 274 opacity: 0.7; 275 -webkit-transition: opacity 0.6s ease-in-out; 276 -moz-transition: opacity 0.6s ease-in-out; 277 -ms-transition: opacity 0.6s ease-in-out; 278 -o-transition: opacity 0.6s ease-in-out; 279 transition: opacity 0.6s ease-in-out; 280 } 281 282 } 283 } 284 } 285 } 286 287 </style>