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>