<template>
  <div class="works con">
    <div class="back-top" @click="onClickBackTop" v-show="isShowBackTopBtn">
      <i class="iconfont icon-top"></i>
    </div>
    <div class="tab">
      <span>{{myWorks}} {{workTotalNum !== undefined ? `(${workTotalNum})`:''}}</span>
      <div class="tab-r">
        <div class="filter">
          <div :class="{active: isFilterFocus}" @focusin="onFilterFocus" @focusout="onFilterBlur">
            <i class="iconfont iconworks_search search"></i>
            <input type="text" :placeholder="search" v-model="searchKey">
            <i v-if="searchKey" @click="searchKey=''" class="iconfont icontoast_red del"></i>
          </div>
        </div>
      </div>
    </div>
    <div class="mask" v-show="isShowMask"></div>
    <!-- 断网时，输入关键字触发网络请求后，骨架图的隐藏会触发v-infinite-scroll，原因未知。进而导致循环触发，因此list为空时要禁用v-infinite-scroll -->
    <ul class="w-list" v-if="!(list.length === 0 && !hasMoreData)" v-infinite-scroll="requestMoreData"
      :infinite-scroll-disabled="!hasMoreData || isRequestingMoreData || (list.length === 0)" ref="w-list-ref"
      @scroll.self="onWorkListScroll">
      <li class="add-work" @click="add">
        <div class="wrapper">
          <div class="add-con">
            <div>
              <i class="iconfont icon_plus"></i>
            </div>
            <span>{{create}}</span>
          </div>
        </div>
      </li>
      <!-- 骨架图 -->
      <template v-if="isRequestingMoreData && (list.length === 0)">
        <li v-for="index in 19" :key="index">
          <div class="wrapper">
            <workCardSkeleton></workCardSkeleton>
          </div>
        </li>
      </template>
      <li v-for="(item,i) in list" :key="i" :class="{'has-more-data': hasMoreData}">
        <div class="wrapper">
          <div class="li-hover">
            <span class="lipreview" @click="handlePreview(item)">{{preview}}</span>
            <ul class="oper">
              <li class="comfirmhover" @click="edit(item)"><i class="iconfont icon-works_editor"></i>{{edittips}}</li>
              <li class="comfirmhover" @click="openShare(item)"><i class="iconfont icon-works_share"></i>{{share}}</li>
              <li class="cancelhover" @click="del(item, i)"><i class="iconfont icon-works_delete"></i>{{deltips}}</li>
            </ul>
          </div>
          <div class="img" @click="handlePreview(item)">
            <img class="real" :src="item.icon||$thumb" alt="" />
          </div>
          <div class="li-info">
            <div>
              <span class="shenglve tttttt" :title="item.name||no_title">{{item.name||no_title}}</span>
            </div>
            <div>
              <span>{{item.createTime.split(' ')[0]}}</span>
              <div :title="item.visit">
                <i class="iconfont iconworks_look"></i>{{item.visit>10000?'1w+':item.visit}}
              </div>
            </div>
          </div>
        </div>
      </li>
      <div class="work-list-loading-wrapper" v-show="isRequestingMoreData && (list.length !== 0)">
        <img class="work-list-loading" :src="require('@/assets/images/icons/work-list-loading.gif')" />
      </div>
    </ul>
    <div class="nodata" v-if="list.length == 0 && !hasMoreData && lastestUsedSearchKey">
      <img :src="$noresult" alt="" />
      <span>{{no_serch_result}}~</span>
    </div>
    <div class="nodata" v-if="list.length == 0 && !hasMoreData && !lastestUsedSearchKey">
      <img :src="config.empty" alt="" />
      <span>{{no_works}}</span>
      <button @click="add" class="upload-btn-in-table">{{create}}</button>
    </div>
    <share :show='showShare' :item="shareItem" @close="showShare=false"></share>
    <preview v-if="showItem" :name="showItem.name" :show="showPreview" :ifr="`./show.html?id=${showItem.id}`"
      :dark="false" @close="showPreview = false" />
    <div class="dialog" style="z-index: 10" v-if="isShowMaterialSelector">
      <MaterialSelector :title="select_material" @cancle="isShowMaterialSelector = false" @submit="handleSubmitFromMaterialSelector"
        :selectableType="['pano', '3D']" :isMultiSelection="true" :workId="newWorkId" initialMaterialType="pano" />
    </div>
  </div>
</template>

<script>
import share from '../popup/share'
import preview from "@/components/preview";
import workCardSkeleton from "@/components/workCardSkeleton.vue";
import config from "@/config";
import { debounce } from "@/utils/other.js"
import MaterialSelector from "@/components/materialSelectorForManageCenter.vue";
import { mapGetters } from "vuex";
import {i18n} from "@/lang"


import {
  addWorks,
  getWorksList,
  delWorks,
  getPanoInfo,
  saveWorks,
} from "@/api";

export default {
  components: {
    share,
    preview,
    workCardSkeleton,
    MaterialSelector,
  },
  computed: {
    ...mapGetters([
      'info',
    ])
  },
  data() {
    return {
      myWorks: i18n.t("material.works.my"),
      create: i18n.t("material.works.create"),
      search: i18n.t("material.works.search"),
      preview: i18n.t("material.works.preview"),
      edittips: i18n.t("material.works.edit"),
      share: i18n.t("material.works.share"),
      deltips: i18n.t("material.works.delete"),
      no_works: i18n.t("material.works.no_works"),
      no_title: i18n.t("gather.no_title"),
      no_serch_result: i18n.t("gather.no_serch_result"),
      select_material: i18n.t("gather.select_material"),


      config,
      list: [],
      workTotalNum: undefined,
      hasMoreData: true,
      isRequestingMoreData: false,

      searchKey: '',
      // 因为searchKey的变化经过debounce、异步请求的延时，才会反映到数据列表的变化上，所以是否显示、显示哪种无数据提示，也要等到数据列表变化后，根据数据列表是否为空，以及引发本次变化的那个searchKey瞬时值来决定。本变量就是用来保存那个瞬时值。
      lastestUsedSearchKey: '',
      isFilterFocus: false,

      showShare: false,
      showPreview: false,
      showItem: '',
      shareItem: '',

      isBackingTop: false,
      isShowBackTopBtn: false,

      isShowMask: false,

      isShowMaterialSelector: false,
      newWorkId: '',
    }
  },
  mounted() {
    this.requestMoreData()
  },
  watch: {
    searchKey: {
      handler: function () {
        this.refreshListDebounced()
      },
      immediate: false,
    },
  },
  methods: {
    onFilterFocus() {
      this.isFilterFocus = true
    },
    onFilterBlur() {
      this.isFilterFocus = false
    },
    refreshListDebounced: debounce(function () {
      this.list = []
      this.isRequestingMoreData = false
      this.hasMoreData = true
      this.requestMoreData()
    }, 700, false),
    openShare(data) {
      getPanoInfo(data.id, (data) => {
        if (data.scenes.length <= 0) {
          return this.$msg.warning("链接未生成，请编辑作品添加素材");
        }
        this.showShare = true
        this.shareItem = data
      })
    },

    handlePreview(item) {
      getPanoInfo(item.id, (data) => {
        if (data.scenes.length <= 0) {
          return this.$msg.warning("链接未生成，请编辑作品添加素材");
        }
        this.showItem = {
          ...item,
          ...data
        }
        this.showPreview = true
      })
    },
    add() {
      // 新建作品，弹窗让用户给作品选择素材。
      addWorks(
        {},
        (res) => {
          this.newWorkId = res.data.id
          this.isShowMaterialSelector = true
        },
      )
    },
    handleSubmitFromMaterialSelector(selected) {
      // 拿新作品的初始数据
      getPanoInfo(
        this.newWorkId,
        // 拿到了。
        (data) => {
          // 往里边添加用户选中的素材。
          this.$store.commit("SetInfo", data);
          for (const item of selected) {
            if (item.materialType === 'pano') {
              this.info.scenes.push({
                icon: item.icon,
                sceneCode: item.sceneCode,
                sceneTitle: item.name,
                category: this.info.catalogs[0].id,
                type: "pano",
                id: 's_' + this.$randomWord(true, 8, 8)
              })
            } else if (item.materialType === '3D') {
              this.info.scenes.push({
                icon: item.thumb,
                sceneCode: item.num,
                sceneTitle: item.sceneName,
                category: this.info.catalogs[0].id,
                type: "4dkk",
                id: 's_' + this.$randomWord(true, 8, 8)
              })
            }
          }

          // 保存新作品
          saveWorks(
            {
              id: this.newWorkId,
              password: '',
              someData: { ...this.info,
                 status: 1,
                icon: this.info.scenes[0].icon },
            },
            // 保存成功
            () => {
              // 隐藏素材选择弹窗
              this.isShowMaterialSelector = false

              // 刷新作品列表
              this.list = []
              this.isRequestingMoreData = false
              this.hasMoreData = true
              this.requestMoreData().then(() => {
                // 刷新成功

                // 弹出提示窗口
                this.$confirm({
                  title: '提示',
                  content: "您已成功创建作品！",
                  okText: '预览一下',
                  ok: () => {
                    this.handlePreview(this.list[0])
                    this.newWorkId = ''
                    this.$store.commit("SetInfo", {});
                  },
                  ok2Text: '继续编辑',
                  ok2: () => {
                    window.open(`./edit.html?id=${this.newWorkId}`)
                    this.newWorkId = ''
                    this.$store.commit("SetInfo", {});
                  },
                });
              }).catch(() => {
                this.$msg.message('已成功新建作品，但刷新作品列表失败，请稍后手动刷新。')
                console.error('已成功新建作品，但刷新作品列表失败。')
              })
            },
            // 保存失败，删除新建的作品。
            (error) => {
              console.error('保存失败：', error);
              delWorks(this.newWorkId)
              this.newWorkId = ''
              this.$store.commit("SetInfo", {});
            }
          );
        },
        // 没拿到，删除新建的作品。
        (error) => {
          console.error('没拿到新建的作品数据：', error);
          delWorks(this.newWorkId)
          this.newWorkId = ''
        }
      )
    },
    edit(item) {
      window.open(`./edit.html?id=${item.id}`)
    },
    del(item, index) {
      this.$confirm({
        title: '删除作品',
        content: "确定要删除作品吗？",
        ok: () => {
          delWorks(item.id, () => {
            this.$msg.success("删除成功");
            this.isRequestingMoreData = true
            const lastestUsedSearchKey = this.searchKey
            getWorksList(
              {
                pageNum: this.list.length + 1,
                pageSize: 1,
                searchKey: this.searchKey
              },
              (data) => {
                this.list.splice(index, 1)
                this.list = this.list.concat(data.data.list)
                if (this.list.length === data.data.total) {
                  this.hasMoreData = false
                }
                this.isRequestingMoreData = false
                this.lastestUsedSearchKey = lastestUsedSearchKey
                if (!lastestUsedSearchKey) {
                  this.workTotalNum = data.data.total
                }
                // TODO: 这是干啥呢？
                this.$nextTick(() => {
                  this.$bus.emit('refreshTips')
                })
              },
              () => {
                this.lastestUsedSearchKey = lastestUsedSearchKey
                this.isRequestingMoreData = false
              }
            )
          });
        },
      });
    },
    requestMoreData() {
      this.isRequestingMoreData = true
      const lastestUsedSearchKey = this.searchKey
      return new Promise((resolve, reject) => {
        getWorksList(
          {
            pageNum: Math.floor(this.list.length / config.PAGE_SIZE) + 1,
            pageSize: config.PAGE_SIZE,
            searchKey: this.searchKey,
          },
          (data) => {
            this.list = this.list.concat(data.data.list)
            if (this.list.length === data.data.total) {
              this.hasMoreData = false
            }
            this.isRequestingMoreData = false
            this.lastestUsedSearchKey = lastestUsedSearchKey
            if (!lastestUsedSearchKey) {
              this.workTotalNum = data.data.total
            }
            // TODO: 这是干啥呢？
            this.$nextTick(() => {
              this.$bus.emit('refreshTips')
            })
            resolve()
          },
          () => {
            this.isRequestingMoreData = false
            this.lastestUsedSearchKey = lastestUsedSearchKey
            reject()
          }
        );
      })
    },
    onClickBackTop() {
      if (this.isBackingTop) {
        return
      }
      this.isBackingTop = true

      const startTime = Date.now()
      const totalScroll = this.$refs['w-list-ref'].scrollTop
      const fn = () => {
        if (this.$refs['w-list-ref'].scrollTop === 0) {
          this.isBackingTop = false
          return
        }

        const nowTime = Date.now()
        const assumeScrollTop = totalScroll - (nowTime - startTime) * totalScroll / 500
        this.$refs['w-list-ref'].scrollTop = assumeScrollTop > 0 ? assumeScrollTop : 0
        requestAnimationFrame(fn)
      }
      requestAnimationFrame(fn)
    },
    onWorkListScroll(e) {
      if (e.target.scrollTop >= 30) {
        !this.isShowMask && (this.isShowMask = true)
      } else {
        this.isShowMask && (this.isShowMask = false)
      }

      if (e.target.scrollTop >= 600) {
        this.isShowBackTopBtn = true
      } else {
        this.isShowBackTopBtn = false
      }
    }
  }
}
</script>

<style lang="less" scoped>
.works {
  width: 100%;
  flex-direction: column;
  position: relative;

  .back-top {
    position: absolute;
    right: -80px;
    bottom: 30px;
    width: 60px;
    height: 60px;
    border-radius: 8px;
    background-color: #fff;
    z-index: 1;
    color: #C8C9CC;

    &:hover {
      color: #323233;
    }

    cursor: pointer;
    display: flex;
    justify-content: center;
    align-items: center;

    i {
      font-size: 20px;
    }
  }

  .tab {
    flex: 0 0 auto;
    width: 100%;
    display: flex;
    background: #fff;
    justify-content: space-between;
    align-items: center;
    padding: 20px 30px;

    >span {
      font-size: 18px;
      font-weight: bold;
    }

    .tab-r {
      align-items: center;
      display: flex;

      .ui-button {
        margin-right: 20px;
      }
    }
  }

  .mask {
    position: absolute;
    width: 100%;
    top: 210px;
    height: 30px;
    background: linear-gradient(rgb(239, 242, 244), rgba(255, 255, 255, 0));
    z-index: 1;
    pointer-events: none;
  }

  .w-list {
    flex: 1 1 auto;
    overflow: auto;
    margin-top: 30px;
    @gap: 20px;
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
    // 让宽度和视口等宽，为了保证鼠标列表显示区域以外时列表也能响应滚轮事件。
    margin-left: calc((100vw - 100%) / -2);
    padding-left: calc((100vw - 100%) / 2);
    margin-right: calc((100vw - 100%) / -2);
    padding-right: calc((100vw - 100%) / 2);

    &::-webkit-scrollbar {
      width: 0;
      height: 0;
    }

    >li {
      width: calc((100% - @gap * 4) / 5);
      height: 322px;
      margin-bottom: @gap;
      margin-right: @gap;

      &:nth-of-type(5n) {
        margin-right: 0;
      }

      // 因为有个“创建作品”card占着空间，每次拿20个数据，每行五个，又不想每次拿到数据后最后一行只有一个card，所以把最后那个card隐藏掉。
      &:last-of-type.has-more-data {
        display: none;
      }

      .wrapper {
        height: 100%;
        background: #fff;
        position: relative;
        border-radius: 6px;
        overflow: hidden;

        .li-hover {
          display: none;
          width: 100%;
          height: 240px;
          position: absolute;
          top: 0;
          left: 0;
          z-index: 99;
          background: rgba(0, 0, 0, 0.6);

          .lipreview {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: #fff;
            display: inline-block;
            line-height: 40px;
            height: 40px;
            width: 100px;
            text-align: center;
            border-radius: 22px;
            cursor: pointer;
            background-color: transparent;
            border: 1px solid #fff;

            &:hover {
              border: none;
              background: #1983F6;
            }
          }

          .oper {
            display: flex;
            justify-content: space-around;
            align-items: center;
            position: absolute;
            bottom: 10px;
            left: 0;
            width: 100%;

            >li {
              color: #fff;
              font-size: 13px;
              display: flex;
              align-items: center;
              cursor: pointer;

              >i {
                font-size: 20px;
                margin-right: 4px;
              }
            }
          }
        }

        .img {
          width: 100%;
          height: 240px;
          position: relative;
          overflow: hidden;
          cursor: pointer;

          .real {
            height: 100%;
            position: absolute;
            top: 0;
            left: 50%;
            transform: translateX(-50%);
            z-index: 0;
            transition: all ease 0.3s;
          }
        }

        .li-info {
          font-size: 14px;
          padding: 10px;

          >div {
            text-align: left;

            &:first-of-type {
              >span {
                font-weight: bold;
                margin-bottom: 10px;
                display: inline-block;
                text-overflow: ellipsis;
                overflow: hidden;
                white-space: nowrap;
                cursor: pointer;
                color: #323233;
                font-size: 16px;
              }
            }

            &:last-of-type {
              display: flex;
              justify-content: space-between;
              align-items: center;

              >span {
                font-size: 14px;
                color: #969799;
              }

              >div {
                color: #969799;

                i {
                  margin-right: 6px;
                }
              }
            }
          }
        }
      }

      &:hover {
        .wrapper {
          box-shadow: 0px 2px 12px 0px rgba(50, 50, 51, 0.12);
          transform: translateY(-6px);

          .li-hover {
            display: block;
          }

          .img {
            .real {
              height: 108%;
            }
          }
        }
      }
    }

    .add-work {
      .wrapper {
        .add-con {
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
          text-align: center;

          div {
            width: 60px;
            height: 60px;
            border-radius: 50%;
            background: linear-gradient(144deg, #00AEFB 0%, #0076F6 100%);
            position: relative;
            cursor: pointer;
            margin: 0 auto;

            >i {
              font-size: 32px;
              position: absolute;
              top: 50%;
              left: 50%;
              transform: translate(-50%, -50%);
              color: #fff
            }
          }

          span {
            color: #333333;
            display: inline-block;
            margin-top: 8px;
            font-size: 14px;
          }
        }
      }
    }

    .work-list-loading-wrapper {
      width: 100%;
      margin-top: 20px;
      margin-bottom: 22px;

      .work-list-loading {
        display: block;
        margin: 0 auto;
        width: 50px;
        height: 8px;
      }
    }
  }
}
</style>

<style lang="less" scoped>
@import '../style.less';
</style>