<template>
  <div id="app">
    <div class="bookmark" id="bookmark">
      <div class="tool-bar">
        <div class="tool-logo">
          <a href="" target="_blank"><img src="./assets/svg/logo.svg" title="感谢作者 是半夏鸭 设计的图标" class="tool-icon" />红隼书签</a>
        </div>
        <div>
          <div class="search-box">
            <img src="./assets/svg/search.svg">
            <input type="text" placeholder="请输入书签名称" v-model="searchVal" />
          </div>
          <img src="./assets/svg/add.svg" class="tool-icon" @click="add({},'add')" />
          <a title="我的博客" href="https://zhanhongzhu.top" target="_blank"><img src="./assets/svg/blog.svg" class="tool-icon" /></a>
          <a title="github" href="https://github.com" target="_blank"><img src="./assets/svg/translate.svg" class="tool-icon" /></a>
          <span class="login-s" @click="loginClick"><img src="./assets/svg/user.svg" class="tool-icon" title="已登录" /><span class="login-status" :title="userInfo.username">{{userInfo.username.slice(0, 5)}}</span></span>
        </div>
        <!-- userInfo.objectId?LoginOut:handleUserLogin -->
      </div>
      <!-- 侧边导航栏 -->
      <div class="box-m">
        <div class="left-box">
          <div class="left-box-item">
            <div class="label" :class="activeIndex===index?'active':'inactive'" v-for="(item,index) in data" :key="index" @click="selectType(item,index)">
              <img src="./assets/svg/file.svg" />
              <div class="text-elipss"> {{item.type}} </div>
            </div>
          </div>
          <!-- 导入导出 -->
          <div class="import-tool">
            <span class="import-text">导入/导出:</span>
            <i class="el-icon-upload2" title="导入浏览器书签" @click="importBookmark">
              <input type="file" ref="filElem" id="file">
            </i>
            <i class="el-icon-download" title="导出浏览器书签" @click="exportBookmark"></i>
            <i class="el-icon-setting" title="配置项" @click="configClick"></i>
            <i class="el-icon-refresh" title="重置" @click="resetClick"></i>
          </div>
        </div>
        <div class="right-box">
          <transition-group v-if="bookMark.length" name="staggered-fade" class="card-s" tag="ul" :css="false" @before-enter="beforeEnter" @enter="enter" @leave="leave">
            <div class="card-item list-complete-item" v-for="(card,idx) in bookMark" :key="idx" @click="navigate(card)">
              <div class="logo-img"><img :src="card.logo?card.logo:'/img/logo.f38dc2e8.svg'" /></div>
              <div class="logo-box">
                <span class="logo-box-tools">
                  <i class="el-icon-edit" @click.stop="add(card,'modify')"></i>
                  <i class="el-icon-delete" @click.stop="deleteClick(card)"></i>
                </span>
                <span class="title">{{card.title || 'Kestrel-bookmark'}}</span>
                <span class="subtitle">{{card.desc || "红隼书签-为中国 Web 前端开发人员提供优质网站导航"}}</span>
              </div>
            </div>
          </transition-group>
          <!-- 无数据显示 -->
          <div v-if="!bookMark.length" class="card-item-nodata">
            <div>
              <svg width="66" height="68" viewBox="0 0 66 68" class="icon empty-icon" data-v-8739e5ce="">
                <g fill="none" fill-rule="evenodd" transform="translate(4 3)" data-v-8739e5ce="">
                  <g fill="#F7F7F7" data-v-8739e5ce="">
                    <path d="M9 10h23.751v3.221H9zM9 16.494h41.083v4.026H9zM9 26.104h23.751v3.221H9zM9 42.208h23.751v3.221H9zM9 33.351h41.083v4.026H9zM9 49.455h41.083v4.026H9z" data-v-8739e5ce="">
                    </path>
                  </g>
                  <rect width="56" height="60" x="1.139" y="1.338" stroke="#EBEBEB" stroke-width="2" rx="6" data-v-8739e5ce=""></rect>
                </g>
              </svg><span class="empty-text" data-v-8739e5ce="">暂无数据</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <!-- 新增/修改弹窗 -->
  <Dialog class="my-dialog" v-model="isDetailVisible" @closeViews="closeViews" :detail="detail" :selectType="activeIndex" @fresh="search" />
  <!-- 登录弹窗 -->
  <Login v-model="isLoginVisible" @closeViews="closeLoginViews" @setUser="setUsername" />

  <!-- 配置项-背景 动画效果 -->
  <Configd v-model="isConfigVisible" @closeViews="closeConfigViews" @fresh="fresh" />

  <!-- 配置项-背景 -->
  <Bg ref="bgRef" />
</template>
<script>
import { reactive, toRefs, watch, ref, onMounted, computed } from 'vue'
import { myData } from './assets/Json/印象笔记.js'
import Dialog from './components/Dialog.vue'
import Bg from './components/Bg.vue'
import Login from './components/Login.vue'
import Configd from './components/Configd.vue'
import gsap from 'gsap'
import { ElMessage, ElMessageBox } from 'element-plus'
import { saveObject, getObject } from './Api/common.js'
import { exportBookmark, walkBookmarksTree } from './components/utils.js'
import Cookie from 'js-cookie'
import { themeConfig } from './components/theme'
import Api from './Api/user.js'
var rowData = []
export default {
  components: { Dialog, Login, Configd, Bg },
  name: 'kestrel-bookmark',
  setup() {
    // 扁平化数组
    const flatten = (arr, result = []) => {
      for (const item of arr) {
        Array.isArray(item.children)
          ? flatten(item.children, result)
          : result.push(item)
      }
      return result
    }

    const data = reactive({
      activeIndex: 0,
      data: [],
      bookMark: [],
      searchVal: '',
      allData: [],
      isDetailVisible: false,
      isLoginVisible: false,
      isConfigVisible: false,
      detail: {},
      userInfo: {
        username: '未登录'
      },
      themeStyle: {},
      theme: 'light'
    })
    /*
     **数据来源
      1.未登录 缓存无数据 取默认
      2.未登录 缓存有数据 取缓存
      3.已登录 系统无数据 取默认
      4.已登录 系统有数据 取系统数据
    */
    const getBookmarkList = (fn = () => {}) => {
      if (Cookie.get('userInfo')) {
        data.userInfo = JSON.parse(Cookie.get('userInfo'))
      }
      if (!data.userInfo.objectId) {
        if (localStorage.getItem('BOOKMARK')) {
          rowData = JSON.parse(localStorage.getItem('BOOKMARK'))
        } else {
          localStorage.setItem('BOOKMARK', JSON.stringify(myData))
          rowData = JSON.parse(JSON.stringify(myData))
        }
        data.data = rowData
        data.bookMark = rowData[0].children
        data.allData = flatten(rowData)
        fn()
      } else {
        // 已登录 系统无数据
        getObject('BOOKMARK')
          .then((res) => {
            if (res.length > 0) {
              rowData = JSON.parse(res[0].attributes.formDatas)
            } else {
              localStorage.setItem('BOOKMARK', JSON.stringify(myData))
              rowData = JSON.parse(JSON.stringify(myData))
            }
          })
          .catch(() => {
            localStorage.setItem('BOOKMARK', JSON.stringify(myData))
            rowData = JSON.parse(JSON.stringify(myData))
          })
          .finally(() => {
            fn()
            data.data = rowData
            data.bookMark = rowData[0].children
            data.allData = flatten(rowData)
          })
      }
    }

    // 设置用户
    const setUsername = () => {
      if (Cookie.get('userInfo')) {
        data.userInfo = JSON.parse(Cookie.get('userInfo'))
      } else {
        data.userInfo = { username: '未登录' }
      }
      getBookmarkList()
    }
    setUsername()
    // 全部数据筛选功能
    watch(
      () => data.searchVal,
      () => {
        data.bookMark = data.allData.filter(
          (v) =>
            v.title.toLowerCase().indexOf(data.searchVal.toLowerCase()) > -1
        )
      }
    )
    // 书签类别选择
    const selectType = (item, index) => {
      data.bookMark = item.children
      data.activeIndex = index
    }
    // 书签跳转
    const navigate = (v) => window.open(v.url, '_target')

    // 新增书签
    function add(row = {}, flag = 'add') {
      const temp = { ...row }
      if (flag === 'modify') {
        data.detail = Object.assign(temp, {
          type: rowData[data.activeIndex].type,
          flag: 'modify'
        })
      } else {
        data.detail = Object.assign(
          {},
          { type: rowData[data.activeIndex].type, flag: 'add' }
        )
      }
      data.isDetailVisible = true
    }
    // 用户登录
    const handleUserLogin = () => {
      data.isLoginVisible = true
    }

    // 配置项
    const configClick = () => {
      data.isConfigVisible = true
    }
    const closeConfigViews = (v) => (data.isConfigVisible = v)

    // 关闭弹窗事件
    const closeViews = (v) => (data.isDetailVisible = v)
    const closeLoginViews = (v) => (data.isLoginVisible = v)

    // 获取书签分类数据
    const search = async () => {
      await getBookmarkList(() => {
        data.data = rowData
        data.bookMark = rowData[data.activeIndex].children
      })
    }
    // 删除书签
    const deleteClick = (row) => {
      const myData = JSON.parse(localStorage.getItem('BOOKMARK'))
      const delDetail = Object.assign(row, {
        type: rowData[data.activeIndex].type
      })
      for (let i = 0; i < myData.length; i++) {
        if (delDetail.type === myData[i].type) {
          const cindex = myData[i].children.findIndex(
            (s) => s.title === delDetail.title
          )
          if (cindex > -1) {
            myData[i].children.splice(cindex, 1)
            localStorage.setItem('BOOKMARK', JSON.stringify(myData))
            ElMessage.success('删除成功')
            search()
          }
        }
      }
    }
    // 退出登录
    const LoginOut = () => {
      ElMessageBox.confirm('确认要退出登录?', '温馨提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        const params = { username: '', password: '' }
        Api.logout(params.username, params.password).then((res) => {
          Cookie.remove('userInfo')
          setUsername()
        })
        ElMessage({
          type: 'success',
          message: '已退出登录'
        })
      })
    }
    // 登录或退出
    const loginClick = () => {
      data.userInfo.objectId ? LoginOut() : handleUserLogin()
    }

    // 导入书签
    const importBookmark = () => {
      if (data.userInfo.objectId) {
        const file = document.getElementById('file')
        file.dispatchEvent(new MouseEvent('click'))
        const mybookmark = document.getElementById('mybookmark')
        document.getElementById('file').addEventListener('change', function () {
          var file = document.getElementById('file').files[0]
          var reader = new FileReader()
          reader.readAsText(file, 'utf-8')
          reader.onload = function () {
            mybookmark.innerHTML = reader.result
            const formDatas = JSON.stringify(walkBookmarksTree(mybookmark))
            if (formDatas) {
              const params = { formDatas: formDatas }
              saveBookmarkList(params)
            }
          }
        })
      } else {
        ElMessage.warning('请先登录')
      }
    }

    // 书签数据存储
    const saveBookmarkList = (params) => {
      saveObject('BOOKMARK', params).then((res) => {
        ElMessage.success('导入成功')
        getBookmarkList()
      })
    }
    const bgRef = ref(null)
    const fresh = () => {
      setTheme()
      bgRef.value.init()
    }

    // 设置主题
    const setTheme = () => {
      const obj1 = localStorage.getItem('granimConfig')
      if (obj1) {
        const obj = JSON.parse(obj1)
        data.theme = obj.theme
        data.themeStyle = themeConfig[`${data.theme}`]
        data.themeStyle.opacity0 =
          obj.opacity0 && obj.opacity0 > 0.5 ? obj.opacity0 : 0.5
      } else {
        data.themeStyle = themeConfig.light
        data.themeStyle.opacity0 = 0.8
      }
    }
    // 背景色
    const bgColor = computed(() => {
      return themeConfig[`${data.theme}`].bgColor
    })
    // 激活样式
    const activeColor = computed(() => {
      return themeConfig[`${data.theme}`].activeColor
    })
    // 亮度
    const opacity0 = computed(() => {
      return data.themeStyle.opacity0
    })
    // 文字颜色
    const textColor = computed(() => {
      return themeConfig[`${data.theme}`].textColor
    })
    // 边框色
    const borderColor = computed(() => {
      return themeConfig[`${data.theme}`].borderColor
    })
    // 滚动条样式
    const scrollbarColor = computed(() => {
      return themeConfig[`${data.theme}`].scrollbarColor
    })

    onMounted(() => {
      setTheme()
    })

    // 重置配置项
    const resetClick = () => {
      localStorage.removeItem('granimConfig')
      bgRef.value.init()
    }

    return {
      scrollbarColor,
      textColor,
      opacity0,
      activeColor,
      borderColor,
      bgColor,
      resetClick,
      bgRef,
      fresh,
      deleteClick,
      ...toRefs(data),
      selectType,
      navigate,
      add,
      closeViews,
      closeLoginViews,
      search,
      importBookmark,
      exportBookmark,
      loginClick,
      setUsername,
      configClick,
      closeConfigViews
    }
  },
  methods: {
    beforeEnter(el) {
      el.style.opacity = 0
      el.style.height = 0
    },
    enter(el, done) {
      gsap.to(el, {
        opacity: 1,
        height: '1.6em',
        delay: el.dataset.index * 0.15,
        onComplete: done
      })
    },
    leave(el, done) {
      gsap.to(el, {
        opacity: 0,
        height: 0,
        delay: el.dataset.index * 0.15,
        onComplete: done
      })
    }
  }
}
</script>

<style scoped lang="scss">
#app {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  width: 100vw;
  overflow: hidden;
}

.bookmark {
  position: relative;
  margin-top: 8vh;
  width: 1200px;
  height: calc(75vh);
  border: 1px solid rgba(255, 255, 255, 0.18);
  box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.2);
  border-radius: 6px;
  background: v-bind(bgColor);
  opacity: v-bind(opacity0);
  .left-box {
    width: 200px;
    height: 100%;
    border: 1px solid rgba(255, 255, 255, 0.18);
    box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.2);
    position: relative;
    // overflow-y: auto;
    padding: 8px 0;
    img {
      width: 20px;
      height: auto;
      margin-right: 5px;
      cursor: pointer;
    }
    .active {
      box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.2);
      background: v-bind(activeColor);
    }
    .inactive {
      box-shadow: none;
      background: v-bind(bgColor);
    }
    .label {
      font-size: 14px;
      display: flex;
      cursor: pointer;
      border: none;
      position: relative;
      padding: 10px 15px;
      &:hover {
        box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.2);
        background: v-bind(activeColor);
      }
      .text-elipss {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    }
  }
  .right-box {
    width: calc(100% - 200px);
    .card-s {
      width: 100%;
      padding-top: 10px;
      max-height: calc(80vh - 49px);
      // height:calc(100% - 48px);
      display: flex;
      flex-wrap: wrap;
      overflow-x: hidden;
      overflow-y: auto;
      .card-item {
        cursor: pointer;
        width: calc(33% - 40px);
        display: flex;
        justify-content: flex-start;
        align-items: center;
        border: 1px solid rgba(255, 255, 255, 0.18);
        box-shadow: 0 8px 18px 0 rgba(31, 38, 135, 0.2);
        padding: 10px;
        margin: 7px 20px 7px 20px;
        position: relative;
        border-radius: 8px;
        max-height: 200px;
        height: 72px !important;
        &:hover {
          transform: scale(1.04);
          animation-delay: 0.3ms;
          animation: 0.3ms;
          box-shadow: 0 8px 18px 0 rgba(31, 38, 135, 0.3);
          background: v-bind(activeColor);
        }
        &:hover .logo-box-tools {
          opacity: 0.85;
        }
      }
    }
  }
}
.tool-icon {
  width: 20px;
  height: 20px;
  object-fit: contain;
  display: inline-block;
  margin-right: 12px;
  cursor: pointer;
  &:hover {
    fill: '#3eaf7c';
  }
}
.tool-bar {
  height: 48px;
  border-bottom: 1px solid v-bind(borderColor);
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: v-bind(bgColor);
  .tool-logo {
    margin: 0 15px;
    a {
      color: #e03b5d;
      display: flex;
      align-items: center;
    }
  }
  .search-box {
    display: inline-block;
    position: relative;
    margin-right: 1rem;
    white-space: nowrap;
    img {
      position: absolute;
      top: 0;
      bottom: 0;
      z-index: 0;
      left: 0.6rem;
      margin: auto;
      width: 20px;
      height: auto;
    }
    input {
      text-align: initial;
      text-indent: initial;
      text-shadow: initial;
      text-transform: initial;
      word-spacing: initial;
      letter-spacing: initial;
      cursor: text;
      width: 14rem;
      height: 2rem;
      color: #4e6e8e;
      display: inline-block;
      border: 1px solid v-bind(borderColor);
      border-radius: 0.25rem;
      font-size: 0.9rem;
      line-height: 2rem;
      padding: 0 0.5rem 0 2rem;
      outline: none;
      transition: all 0.2s ease;
      background: transparent;
      background-size: auto;
      background-size: 1rem;
    }
  }
}

::-webkit-scrollbar-thumb {
  background-color: v-bind(scrollbarColor);
  background-clip: padding-box;
  min-height: 28px;
  border-radius: 10px;
}

.box-m {
  display: flex;
  height: calc(100% - 50px);
}
.logo-img {
  width: 62px;
  height: 100%;
  margin-right: 10px;
  filter: drop-shadow(0px 0px 1px #888);
  img {
    height: 100%;
    width: 100%;
    object-fit: contain;
    display: block;
    max-width: 70px;
    width: 62px;
  }
}
.logo-box {
  position: relative;
  flex: 1;
  .title {
    width: 100%;
    max-width: 145px;
    display: block;
    padding-top: 3px;
    font-size: 16px;
    font-weight: bold;
    color: v-bind(textColor);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: block;
  }
  .subtitle {
    width: 100%;
    position: relative;
    max-width: 185px;
    margin-top: 5px;
    font-size: 13px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: v-bind(textColor);
    opacity: 0.8;
    display: block;
  }
}
.list-complete-item {
  transition: all 0.8s ease;
  display: inline-block;
  margin-right: 10px;
}

.list-complete-enter-from,
.list-complete-leave-to {
  opacity: 0;
  transform: translateY(30px);
}

.list-complete-leave-active {
  position: absolute;
}
.card-item-nodata {
  height: 100%;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  span {
    display: block;
    margin-top: 20px;
    color: #999;
  }
}

.logo-box-tools {
  position: absolute;
  right: 0;
  top: 0;
  opacity: 0;
  transition: 0.4s opacity;
  i {
    padding: 4px;
    display: inline-block;
    &:hover {
      color: #e03b5d;
      background: #ff00001f;
      border-radius: 5px;
    }
  }
}

.import-tool {
  position: absolute;
  width: 100%;
  background: v-bind(bgColor);
  height: 36px;
  padding: 3px 10px;
  display: flex;
  align-items: center;
  bottom: 0;
  z-index: 99;
  border-top: 1px solid v-bind(borderColor);
  i {
    font-size: 15px;
    margin: 1px 2px;
    padding: 3px;
    cursor: pointer;
    color: #e03b5d;
    background: #ff00001f;
    border-radius: 5px;
    opacity: 0.7;
    &:hover {
      color: #e03b5d;
      background: #c804041f;
      opacity: 1;
    }
  }
}
.left-box-item {
  height: 100%;
  overflow-y: auto;
  padding-bottom: 40px;
}
.import-text {
  font-size: 12px;
  color: #999;
  margin-right: 3px;
}
.el-icon-upload2 {
  position: relative;
  input {
    width: 1.46rem;
    height: 100%;
    z-index: 1;
    opacity: 0;
    position: absolute;
    cursor: pointer;
  }
}
.login-status {
  display: inline-block;
  font-size: 12px;
  padding-right: 8px;
  color: #999;
  cursor: pointer;
}

.login-s .tool-icon {
  margin-right: 5px;
}
.login-s:hover .login-status {
  color: #e03b5d;
}
</style>
