<template>
  <wrapper
    fill
    margin
    padding
    background
  >
    <c-table
      :curr="options"
      @row-click="onClick"
      @pagination="getList"
    >
      <template #header>
        <div class="l-flex__auto c-option-grid">
          <el-date-picker
            v-model="options.params.beginTime"
            class="c-option-grid__item"
            type="datetime"
            placeholder="开始时间"
            default-time="00:00:00"
            format="yyyy-MM-dd HH:mm"
            value-format="yyyy-MM-dd HH:mm:ss"
            :editable="false"
            @focus="onDateTimeFocus('beginTime')"
            @change="onDateTimeChange('beginTime')"
          />
          <el-date-picker
            v-model="options.params.endTime"
            class="c-option-grid__item"
            type="datetime"
            placeholder="结束时间"
            default-time="23:59:59"
            format="yyyy-MM-dd HH:mm"
            value-format="yyyy-MM-dd HH:mm:ss"
            :editable="false"
            @focus="onDateTimeFocus('endTime')"
            @change="onDateTimeChange('endTime')"
          />
          <search-input
            v-model.trim="options.params.userName"
            placeholder="操作者"
            @search="search"
          />
          <el-select
            v-model="options.params.business"
            placeholder="请选择模块"
            :loading="fetching"
            @visible-change="getBusiness"
            @change="search"
          >
            <el-option
              v-for="item in businessOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
          <search-input
            v-model.trim="options.params.description"
            placeholder="操作描述"
            @search="search"
          />
          <el-select
            v-model="options.params.status"
            placeholder="请选择状态"
            @change="search"
          >
            <el-option
              v-for="(item, index) in statusOptions"
              :key="index"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
          <div>
            <button
              class="c-sibling-item o-button"
              @click="search"
            >
              搜索
            </button>
            <button
              class="c-sibling-item o-button"
              @click="reset"
            >
              重置
            </button>
          </div>
        </div>
      </template>
      <el-table-column
        prop="userName"
        label="操作者"
        align="center"
        show-overflow-tooltip
      />
      <el-table-column
        prop="business"
        label="业务模块"
        align="center"
        show-overflow-tooltip
      />
      <el-table-column
        prop="description"
        label="操作描述"
        align="center"
        show-overflow-tooltip
      />
      <el-table-column
        label="执行状态"
        align="center"
        width="100"
      >
        <template v-slot="scope">
          <el-tag
            v-if="scope.row.status === 0"
            class="o-tag u-readonly"
            type="danger"
            size="medium"
          >
            失败
          </el-tag>
          <el-tag
            v-if="scope.row.status === 1"
            class="o-tag u-readonly"
            type="success"
            size="medium"
          >
            成功
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column
        prop="operTime"
        label="操作时间"
        align="center"
        show-overflow-tooltip
      />
    </c-table>
    <el-dialog
      title="操作日志详情"
      :visible.sync="showDetail"
      custom-class="c-dialog"
    >
      <div class="c-detail-grid">
        <div class="box title">操作者</div>
        <div class="box value">{{ log.userName }}</div>
        <div class="box title">操作时间</div>
        <div class="box value">{{ log.operTime }}</div>
        <div class="box title">操作模块</div>
        <div class="box value">{{ log.business }}</div>
        <div class="box title">执行状态</div>
        <div class="box value">{{ log.status }}</div>
        <div class="box title">请求IP</div>
        <div class="box value">{{ log.ip }}</div>
        <div class="box title">耗时</div>
        <div class="box value">{{ log.costTime }}ms</div>
        <div class="box title">操作描述</div>
        <div class="box value fill">{{ log.description }}</div>
        <div class="box title">调用方法</div>
        <div class="box value fill">{{ log.method }}</div>
        <div class="box title">参数</div>
        <div class="box value fill">{{ log.params }}</div>
        <div class="box title">http请求方式</div>
        <div class="box value fill">{{ log.requestMethod }}</div>
        <div class="box title">错误原因</div>
        <div class="box value fill">{{ log.errorMsg }}</div>
      </div>
    </el-dialog>
  </wrapper>
</template>

<script>
import {
  getLogs,
  getLog,
  getBusiness
} from '@/api/logger'
import { createListOptions } from '@/utils'

export default {
  name: 'Logger',
  data () {
    return {
      statusOptions: [
        { value: void 0, label: '全部状态' },
        { value: 0, label: '失败' },
        { value: 1, label: '成功' }
      ],
      options: createListOptions({
        beginTime: '',
        endTime: '',
        userName: '',
        business: void 0,
        description: '',
        status: void 0
      }),
      businessOptions: [
        { value: void 0, label: '全部模块' }
      ],
      loaded: false,
      fetching: false,
      showDetail: false,
      log: {}
    }
  },
  created () {
    this.getList()
  },
  methods: {
    getBusiness () {
      if (!this.fetching && !this.loaded) {
        this.fetching = true
        getBusiness().then(({ data }) => {
          this.businessOptions = this.businessOptions.concat(data.map(({ business, name }) => {
            return { value: business, label: name }
          }))
          this.fetching = false
          this.loaded = true
        }, () => {
          this.fetching = false
        })
      }
    },
    search () {
      const options = this.options
      options.list = []
      options.totalCount = 0
      options.params.pageNum = 1
      this.getList()
    },
    reset () {
      Object.assign(this.options.params, {
        beginTime: '',
        endTime: '',
        userName: '',
        description: '',
        status: void 0
      })
      this.search()
    },
    getList () {
      const options = this.options
      options.error = false
      options.loading = true
      getLogs(options.params).then(({ data, totalCount }) => {
        options.list = data
        options.totalCount = totalCount
      }, () => {
        options.error = true
        options.list = []
      }).finally(() => {
        options.loading = false
      })
    },
    onClick ({ id }) {
      getLog(id).then(({ data }) => {
        data.status = data.status ? '成功' : '失败'
        data.requestMethod = ['GET', 'POST', 'PUT', 'DELETE'][data.requestMethod]
        this.log = data
        this.showDetail = true
      })
    },
    checkDateTime (type) {
      const beginTime = this.options.params.beginTime
      const endTime = this.options.params.endTime
      if (beginTime && endTime && new Date(endTime) < new Date(beginTime)) {
        this.$message({
          type: 'warning',
          message: type === 'beginTime' ? '开始时间不能大于结束时间' : '结束时间不能小于开始时间'
        })
        return false
      }
      return true
    },
    onDateTimeFocus (type) {
      this[`$${type}`] = this.options.params[type]
      if (type === 'endTime' && !this.options.params.endTime && this.options.params.beginTime) {
        this.$nextTick(() => {
          this.options.params.endTime = this.options.params.beginTime.split(' ')[0] + ' 23:59:59'
        })
      }
    },
    onDateTimeChange (type) {
      const time = this.options.params[type]
      if (time) {
        if (!this.checkDateTime(type)) {
          this.options.params[type] = this[`$${type}`]
          return
        }
      } else {
        this.options.params[type] = ''
      }
      this.search()
    }
  }
}
</script>

<style lang="scss" scoped>
.c-option-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, 200px);
  grid-gap: 10px;

  &__item {
    width: 200px;
  }
}

.o-option {
  width: 200px;
}
.o-status-select {
  width: 138px;
}

.c-detail-grid {
  display: grid;
  grid-template-columns: 120px 1fr 120px 1fr;
  color: $black;
  font-size: 14px;
  border-right: 1px solid $gray;
  border-bottom: 1px solid $gray;

  .box {
    padding: 8px 10px;
    border-top: 1px solid $gray;
    border-left: 1px solid $gray;
  }

  .fill {
    grid-column-start: span 3;
  }

  .title {
    display: inline-flex;
    align-items: center;
    text-align: left;
  }

  .value {
    text-align: center;
  }
}
</style>
