<template>
  <div>
    <div class="gva-search-box">
      <el-form ref="elSearchFormRef" :inline="true" :model="searchInfo" label-width="0" class="demo-form-inline"
        @keyup.enter="handleSubmitSearch">
        <el-form-item prop="createdAt" style="width:260px">
          <el-tooltip content="搜索范围是创建开始日期（包含）至创建结束日期（包含）" placement="top-start">
            <el-icon>
              <QuestionFilled />
            </el-icon>
          </el-tooltip>
          <el-date-picker v-model="searchInfo.dateRange" type="daterange" value-format="YYYY-MM-DD" :clearable="false"
            :editable="false" />
        </el-form-item>
        <el-form-item style="width:200px">
          <el-tooltip content="从标题、副标题、摘要中搜索" placement="top-start">
            <el-input v-model="searchInfo.keyword" class="keyword" placeholder="请输入关键词" clearable style="width:100%" />
          </el-tooltip>
        </el-form-item>
        <!-- <el-form-item label="所属栏目" prop="channelId" style="width:300px">
          <el-cascader v-model="searchChannelId" :options="channelOptions" style="width:100%"
            :props="{ label: 'title', value: 'ID', disabled: 'disabled', emitPath: false }" :show-all-levels="true"
            clearable placeholder="请选择" filterable />
        </el-form-item>
        <el-form-item label="文章分类" prop="categoryId" style="width:300px">
          <el-cascader v-model="searchCategoryId" :options="categoryOptions" style="width:100%"
            :props="{ label: 'title', value: 'ID', disabled: 'disabled', emitPath: false }" :show-all-levels="true"
            clearable placeholder="请选择" filterable />
        </el-form-item> -->
        <el-form-item label="" prop="status" style="width:200px">
          <el-select v-model="searchInfo.status" placeholder="请选择状态" clearable style="width:300px">
            <el-option v-for="item in statusOptions" :key="item.key" :label="item.label" :value="item.key" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="search" @click="handleSubmitSearch">查询</el-button>
          <el-button icon="refresh" @click="handleResetSearch">重置</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="gva-table-box">
      <div class="gva-btn-list">
        <el-button type="primary" icon="plus" @click="handleAdd('0')">新增文章</el-button>
        <el-button v-auth="btnAuth.delete" icon="delete" style="margin-left: 10px;"
          :disabled="!multipleSelection.length" @click="handleMultiDelete">删除</el-button>
      </div>

      <!-- 由于此处菜单跟左侧列表一一对应所以不需要分页 pageSize默认999 -->
      <el-table ref="multipleTable" :data="tableData" row-key="ID" @selection-change="handleSelectionChange">
        <el-table-column fixed type="selection" width="40" align="center" />
        <el-table-column align="left" label="ID" min-width="60" prop="ID" />
        <el-table-column align="left" label="标题/副标题" min-width="400" prop="title">
          <template #default="scope">
            <div>
              <el-link type="primary" :href="getArticlePreviewPath(scope.row.ID)" target="_blank">
                <el-text :line-clamp="2"> {{ scope.row.title }}</el-text>
              </el-link>
            </div>
            <el-text :line-clamp="2" size="small">{{ scope.row.subtitle }}</el-text>
          </template>
        </el-table-column>
        <el-table-column align="left" label="摘要" min-width="400" prop="desc" class-name="text-truncate">
          <template #default="scope">
            <el-text :line-clamp="3">{{ scope.row.desc }}</el-text>
          </template>
        </el-table-column>
        <el-table-column align="left" label="标签" min-width="150" prop="tags">
          <template #default="scope">
            <el-tag v-for="(item, index) in formatTags(scope.row.tags)" :key="index" size="small"
              style="margin-right: 5px;">
              {{ item }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column align="left" label="时间" width="280">
          <template #default="scope">
            <div><b>发布时间：</b>{{ formatDate(scope.row.publishDate) }}</div>
            <div><b>最后更新：</b>{{ formatDate(scope.row.UpdatedAt) }}</div>
          </template>
        </el-table-column>
        <el-table-column align="left" label="所属栏目" prop="categories" width="180">
          <template #default="scope">
            <el-cascader v-model="scope.row.channelIds" :options="channelOptions" style="width:100%"
              :props="{ label: 'title', value: 'ID', emitPath: false, expandTrigger: 'hover', multiple: true }"
              :collapse-tags="true" :max-collapse-tags="3" filterable
              @visible-change="(flag) => { if (!flag) handleChangeChannels(scope.row) }"
              @remove-tag="() => { handleChangeChannels(scope.row) }" />
          </template>
        </el-table-column>
        <el-table-column align=" left" label="文章分类" prop="categories" width="180">
          <template #default="scope">
            <el-cascader v-model="scope.row.categoryIds" :options="categoryOptions" style="width:100%"
              :props="{ label: 'title', value: 'ID', emitPath: false, expandTrigger: 'hover', multiple: true }"
              :collapse-tags="true" :max-collapse-tags="3" filterable
              @visible-change="(flag) => { if (!flag) handleChangeCategories(scope.row) }"
              @remove-tag="() => { handleChangeCategories(scope.row) }" />
          </template>
        </el-table-column>
        <el-table-column align="left" label="作者" min-width="80" prop="author" />
        <el-table-column align="left" label="类型" min-width="80" prop="articleType">
          <template #default="scope">{{ formatArticleType(scope.row.articleType) }}</template>
        </el-table-column>
        <el-table-column align="left" label="状态" width="80">
          <template #default="scope">{{ formatStatus(scope.row.status) }}</template>
        </el-table-column>
        <el-table-column align="left" fixed="right" label="操作" width="140" class="dispose-cell">
          <template #default="scope">
            <div class="flex md-2">
              <el-button v-if="scope.row.status === 1" v-auth="btnAuth.submit" type="success" link icon="check"
                @click="handleRowChange(scope.row, 2)">提审</el-button>
            </div>
            <div class="flex md-2">
              <el-button v-if="scope.row.status === 2" v-auth="btnAuth.review" type="primary" link icon="WindPower"
                @click="handleRowReview(scope.row)">审核</el-button>
            </div>
            <div class="flex md-2">
              <el-button v-if="scope.row.status === 3" v-auth="btnAuth.release" type="success" link icon="top"
                @click="handleRowChange(scope.row, 4)">发布</el-button>
            </div>
            <div class="flex md-2">
              <el-button v-if="scope.row.status === 4" v-auth="btnAuth.cancel" type="warning" link icon="bottom"
                @click="handleRowChange(scope.row, 5)">撤销</el-button>
            </div>
            <div class="flex md-2">
              <el-button v-auth="btnAuth.edit"
                :type="scope.row.status === 1 || scope.row.status === 5 || scope.row.status === 3 ? 'primary' : 'info'"
                link icon="edit" :disabled="scope.row.status === 4 || scope.row.status === 2"
                @click="handleRowEdit(scope.row.ID)">编辑</el-button>
            </div>
            <div class="flex md-2">
              <el-button v-auth="btnAuth.delete" type="danger" link icon="delete"
                @click="handleRowDelete(scope.row.ID)">删除</el-button>
            </div>
          </template>
        </el-table-column>
      </el-table>
      <div class="gva-pagination">
        <el-pagination layout="total, sizes, prev, pager, next, jumper" :current-page="page" :page-size="pageSize"
          :page-sizes="[10, 30, 50, 100]" :total="total" @current-change="handleCurrentChange"
          @size-change="handleSizeChange" />
      </div>
    </div>

    <ArticleEdit ref="articleEditRef" :title="articleEditTitle" @on-save="handlerSaveArticle" />
  </div>
</template>

<script setup>
import { ref, watch, nextTick } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { formatDate, getArticlePreviewPath } from '@/utils/format'
import { getCategoryTree } from '@/api/category'
import { getChannelTree } from '@/api/channel'
import { formatTimeToStr } from '@/utils/date'
import { equalArr } from '@/utils/arr'
import {
  getArticleList,
  deleteArticle,
  deleteArticleByIds,
  setArticleChannels,
  setArticleCategories,
  submitArticle,
  reviewBackArticle,
  releaseArticle,
  cancelArticle
} from '@/api/article'
import ArticleEdit from '@/view/content/components/articleEdit.vue'
import { useBtnAuth } from '@/utils/btnAuth'
import { statusOptions, formatArticleType, formatStatus } from '@/utils/options'

const btnAuth = useBtnAuth()
const articleEditTitle = ref('')
const articleEditRef = ref(false)
const page = ref(1)
const total = ref(0)
const pageSize = ref(10)
const searchInfo = ref({})
const searchCategoryId = ref('')
const searchChannelId = ref('')
const tableData = ref([])
const multipleSelection = ref([])// 多选数据
const elSearchFormRef = ref()

const formatTags = (tags) => {
  return tags && tags.split(',')
}

const initSearchInfo = () => {
  const endDate = new Date()
  const startDate = new Date(endDate.getTime() - 7 * 24 * 60 * 60 * 1000)

  searchChannelId.value = ''
  searchCategoryId.value = ''

  searchInfo.value = {
    dateRange: [
      formatTimeToStr(startDate, 'yyyy-MM-dd'),
      formatTimeToStr(endDate, 'yyyy-MM-dd'),
    ]
  }
}

initSearchInfo()

// 多选
const handleSelectionChange = (val) => {
  multipleSelection.value = val
}

const handleMultiDelete = () => {
  ElMessageBox.confirm('确定要删除所选文章吗?', '请确认', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(async valid => {
    const IDs = []
    if (multipleSelection.value.length === 0) {
      ElMessage({
        type: 'warning',
        message: '请选择要删除的数据'
      })
      return
    }
    multipleSelection.value &&
      multipleSelection.value.map(item => {
        IDs.push(item.ID)
      })
    const res = await deleteArticleByIds({ IDs })
    if (res.code === 0) {
      ElMessage({
        type: 'success',
        message: '删除成功'
      })
      if (tableData.value.length === IDs.length && page.value > 1) {
        page.value--
      }
      getTableData()
    }
  })
}

// 重置
const handleResetSearch = () => {
  initSearchInfo()
  getTableData()
}

// 搜索
const handleSubmitSearch = () => {
  elSearchFormRef.value?.validate(async valid => {
    if (!valid) return
    if (searchInfo.value.status === '') {
      searchInfo.value.status = null
    }
    if (searchChannelId.value !== '') {
      searchInfo.value.channelId = parseInt(searchChannelId.value, 10)
    }
    if (searchCategoryId.value !== '') {
      searchInfo.value.categoryId = parseInt(searchCategoryId.value, 10)
    }
    getTableData()
  })
}

// 分页
const handleSizeChange = (val) => {
  pageSize.value = val
  getTableData()
}

// 修改页面容量
const handleCurrentChange = (val) => {
  page.value = val
  getTableData()
}

// 添加
const handleAdd = () => {
  articleEditTitle.value = '添加文章'
  articleEditRef.value.openPage({ articleId: 0 })
}

// 修改
const handleRowEdit = (ID) => {
  articleEditTitle.value = '编辑文章 ID:' + ID
  articleEditRef.value.openPage({ articleId: ID })
}

// 保存文章后
const handlerSaveArticle = () => {
  getTableData()
}

// 删除
const handleRowDelete = (ID) => {
  ElMessageBox.confirm('此操作将删除文章, 是否继续?', '请确认', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(async valid => {
    const res = await deleteArticle({ ID })
    if (res.code === 0) {
      ElMessage({
        type: 'success',
        message: '删除成功!'
      })
      if (tableData.value.length === 1 && page.value > 1) {
        page.value--
      }
      getTableData()
    }
  })
}

// 提审、发布、撤销
const handleRowChange = (row, status) => {
  let msg
  if (status === 2) {
    msg = '文章提交审核'
  } else if (status === 4) {
    msg = '发布文章到网站'
  } else if (status === 5) {
    msg = '从网站撤销文章'
  }
  ElMessageBox.confirm('此操作将' + msg + ', 是否继续?', '请确认', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(async valid => {
    let res
    if (status === 2) {
      res = await submitArticle({ ID: row.ID })
    } else if (status === 4) {
      res = await releaseArticle({ ID: row.ID })
    } else if (status === 5) {
      res = await cancelArticle({ ID: row.ID, status: 2 })
    }
    if (res.code === 0) {
      ElMessage({
        type: 'success',
        message: msg + '成功！'
      })
      row.status = status
    }
  })
}

// 审核文章，弹出选择框
const handleRowReview = row => {
  ElMessageBox.confirm('请确认是否审核通过，确认请按“是”，否则请按“否”，取消请按“ESC”关闭弹窗', '请确认', {
    distinguishCancelAndClose: true,
    confirmButtonText: '是',
    cancelButtonText: '否',
    type: 'warning'
  }).then(async valid => {
    // 确认通过，发布文章
    const res = await releaseArticle({ ID: row.ID })
    if (res.code === 0) {
      ElMessage({
        type: 'success',
        message: '审核通过!'
      })
      row.status = 4
    }
  }).catch(async (action) => {
    // 确认不通过，状态为草稿
    if (action === 'cancel') {
      const res = await reviewBackArticle({ ID: row.ID })
      if (res.code === 0) {
        ElMessage({
          type: 'warning',
          message: '审核不通过!'
        })
        row.status = 1
      }
    }
  })
}

// ----- 列表更新栏目相关 -----
const handleChangeChannels = async row => {
  await nextTick()
  const ids = row.channelIds.map(i => { return parseInt(i) })
  if (ids.length === 0) {
    restoreChannels(row, '所属栏目不能为空')
    return
  }
  // 比较是否有变化
  const existArr = row.channels && row.channels.map(i => { return String(i.ID) })
  if (equalArr(existArr, ids)) {
    return
  }
  const res = await setArticleChannels({
    ID: row.ID,
    channelIds: ids
  })
  if (res.code === 0) {
    ElMessage({ type: 'success', message: '所属栏目设置成功' })
    getTableData()
  } else {
    // 恢复回去
    restoreChannels(row, res.message)
  }
}
const restoreChannels = (row, message) => {
  row.channelIds = row.channels && row.channels.map(i => { return String(i.ID) })
  ElMessage({ type: 'error', message: message })
}
// ----- 列表分类相关 -----
const handleChangeCategories = async row => {
  await nextTick()
  const ids = row.categoryIds.map(i => { return parseInt(i) })
  if (ids.length === 0) {
    restoreCategories(row, '文章分类不能为空')
    return
  }
  // 比较是否有变化
  const existArr = row.categories && row.categories.map(i => { return String(i.ID) })
  if (equalArr(existArr, ids)) {
    return
  }
  const res = await setArticleCategories({
    ID: row.ID,
    categoryIds: ids
  })
  if (res.code === 0) {
    ElMessage({ type: 'success', message: '文章分类设置成功' })
    getTableData()
  } else {
    // 恢复回去
    restoreCategories(row, res.message)
  }
}
const restoreCategories = (row, message) => {
  row.categoryIds = row.categories && row.categories.map(i => { return String(i.ID) })
  ElMessage({ type: 'error', message: message })
}

watch(() => tableData.value, () => {
  // 初始化数据
  setCategoryIds()
  setChannelIds()
})

// ----- 查询 -----
const getTableData = async valid => {
  const res = await getArticleList({ page: page.value, pageSize: pageSize.value, ...searchInfo.value })
  if (res.code === 0) {
    tableData.value = res.data.list
    total.value = res.data.total
  }
}

const setCategoryIds = () => {
  tableData.value && tableData.value.forEach((row) => {
    row.categoryIds = row.categories && row.categories.map(i => { return String(i.ID) })
  })
}

const setChannelIds = () => {
  tableData.value && tableData.value.forEach((row) => {
    row.channelIds = row.channels && row.channels.map(i => { return String(i.ID) })
  })
}

// options 相关
const initOptions = (data, optionsData, disabled) => {
  data &&
    data.forEach(item => {
      if (item.children && item.children.length) {
        const option = {
          title: item.title,
          ID: String(item.ID),
          children: []
        }
        initOptions(
          item.children,
          option.children,
        )
        optionsData.push(option)
      } else {
        const option = {
          title: item.title,
          ID: String(item.ID),
        }
        optionsData.push(option)
      }
    })
}

const channelOptions = ref([])
const categoryOptions = ref([])

const getCategoryData = async valid => {
  categoryOptions.value = []
  const res = await getCategoryTree()
  if (res.code === 0) {
    initOptions(res.data.categoryTree, categoryOptions.value, false)
  }
}
const getChannelData = async valid => {
  channelOptions.value = []
  const res = await getChannelTree()
  if (res.code === 0) {
    initOptions(res.data.channelTree, channelOptions.value, false)
  }
}

const setOptions = () => {
  getCategoryData()
  getChannelData()
}

setOptions()
getTableData()

</script>

<style type="scss">
.admin-box .el-table td .cell {
  line-height: 28px;
}

.cell button {
  line-height: 22px;
}

.text-truncate .cell {
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
}
</style>
