<template>
  <div class="container">
    <div class="left">
      <div class="body">
        <div class="req-label ">
          <div class="req-label-item" :class="{ 'is-active header-indicator': item.name === activeName }"
            v-for="(item, i) in requestList" :key="item.name" @click="handleChangeReq(item)">
            <div class="req-label-item_content" :title="item.name">
              <i class="el-icon-loading" v-if="item.loading"></i>
              <div class="method-indicator method" :class="item.method">{{ item.method }}</div>
              <div class="req-label-item_content_val">{{ item.name }}</div>
            </div>
            <div>
              <el-button style="color: #ff4949;" type="text" icon="el-icon-delete" :disabled="item.loading"
                @click.stop="handleDelete(i)"></el-button>
            </div>
          </div>
          <div class="req-label-toolbar">
            <el-button style="width: 120px" plain icon="el-icon-upload2" @click="handleImport">导入</el-button>
            <el-button type="info" style="width: 120px" icon="el-icon-delete" :disabled="!requestList.length"
              @click="handleClear">清空</el-button>
          </div>
        </div>
        <div class="req-content">
          <div class="req-content-header">
            <el-input placeholder="请输入内容" v-model="currentUrl" size="large" :disabled="reqDisabled">
              <el-select v-model="activeReq.method" slot="prepend" placeholder="请选择" class="input-select method"
                :class="activeReq.method">
                <el-option v-for="item in methodOptions" :key="item.value" :disabled="reqDisabled" :label="item"
                  :value="item" class="method" :class="item">
                </el-option>
              </el-select>
            </el-input>
            <el-button type="primary" icon="el-icon-search" size="large" :disabled="reqDisabled" :loading="reqLoading"
              @click="handleSend">发送</el-button>
          </div>
          <el-tabs class="req-params-wrap" type="border-card" v-model="activeType" @tab-click="handleTabChange">
            <el-tab-pane name="Params" label="Params">
              <div slot="label" style="padding: 0 6px;">
                <el-badge :value="paramsNum" :hidden="paramsNum === 0" class="badge-item" type="primary">
                  Params
                </el-badge>
              </div>
              <RequestForm :key="activeReq.name + 'ParamsForm'" ref="ParamsForm" :disabled="reqDisabled"
                :loading="activeReq.loading" :name="activeReq.name + 'Params'" :params="activeParams"
                v-model="activeReq.paramsForm" @append="onAppend" @delete="onDelete" />
            </el-tab-pane>
            <el-tab-pane name="Headers" label="Headers">
              <div slot="label" style="padding: 0 6px;">
                <el-badge :value="headerNum" :hidden="headerNum === 0" class="badge-item" type="success">
                  Headers
                </el-badge>
              </div>
              <RequestForm :key="activeReq.name + 'HeadersForm'" ref="HeadersForm" :disabled="reqDisabled"
                :name="activeReq.name + 'Headers'" :params="activeHeader" v-model="activeReq.headerForm"
                @append="onAppend" @delete="onDelete" />
            </el-tab-pane>
            <el-tab-pane name="Body" label="Body">
              <div slot="label" style="padding: 0 6px;">
                <el-badge :value="bodyNum" :hidden="bodyNum === 0" class="badge-item" type="warning">
                  Body
                </el-badge>
              </div>
              <RequestForm :key="activeReq.name + 'BodyForm'" ref="BodyForm" :name="activeReq.name + 'Body'"
                :params="activeBody" :disabled="activeReq.method === 'GET' || reqDisabled" v-model="activeReq.bodyForm"
                @append="onAppend" @delete="onDelete" />
            </el-tab-pane>
          </el-tabs>
          <div class="req-result">
            <div class="req-result-header header-indicator">
              <div class="req-result-header-title ">请求结果</div>
              <div class="progress-wrap">
                <el-progress style="width: 100px;margin-right: 20px;" :percentage="50" :show-text="false"></el-progress>
                <el-button type="text" icon="el-icon-delete" @click="handleClearResult">清空</el-button>
              </div>

            </div>
            <div class="req-result-body"></div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import RequestForm from './RequestForm.vue';
import { localReq } from './req.js'
import axios from 'axios';
export default {
  components: {
    RequestForm,
  },
  data() {
    return {
      baseUrl: '',
      activeName: '',
      activeType: 'Params',
      requestList: [],
      methodOptions: [
        'GET',
        'POST',
        'PUT',
        'DELETE',
      ],
    };
  },
  computed: {
    currentUrl: {
      get: function () {
        return this.activeReq?.url ?? '';
      },
      set: function (val) {
        this.activeReq.url = val;
      }
    },
    activeReq() {
      return this.requestList.find(item => item.name === this.activeName) || {};
    },
    activeParams() {
      return this.activeReq?.params ?? [];
    },
    paramsNum() {
      return this.activeParams.filter(item => item.key && item.disabled !== true).length;
    },
    activeHeader() {
      return this.activeReq?.header ?? [];
    },
    headerNum() {
      return this.activeHeader.filter(item => item.key && item.disabled !== true).length;
    },
    activeBody() {
      return this.activeReq?.body ?? [];
    },
    bodyNum() {
      return this.activeBody.filter(item => item.key && item.disabled !== true).length;
    },
    reqDisabled() {
      return !this.activeReq?.method || this.reqLoading;
    },
    reqLoading() {
      return this.activeReq.loading;
    },
  },
  created() {
    this.init();
  },
  methods: {
    init() {
      this.resolvePostmanData({
        item: localReq
      });
      this.activeName = this.requestList?.[0].name ?? '';
      console.log(this.activeType)
    },
    handleTabChange(e) {
      this.$nextTick(() => {
        this.$refs[e.name + 'Form'].doLayout();
      });
    },
    handleImport() {
      // 导入postman导出的json文件
      const input = document.createElement('input');
      input.type = 'file';
      input.accept = '.json';
      input.onchange = e => {
        const file = e.target.files[0];
        const reader = new FileReader();
        reader.onload = e => {
          this.resolvePostmanData(e.target.result);
        };
        reader.readAsText(file);
      };
      input.click();
    },
    handleClear() {
      this.requestList = [];
      this.activeName = '';
    },
    handleChangeReq(req) {
      this.activeName = req.name;
    },
    handleDelete(index) {
      this.requestList.splice(index, 1);
      this.activeName = this.requestList?.[0].name ?? '';
    },
    handleSend() {
      const { paramsForm, url, method, headerForm, bodyForm } = this.activeReq;
      let newUrl = this.baseUrl ? this.baseUrl : url;
      // 如果没有http或者https开头，则根据当前页面的protocol拼接
      if (!newUrl.startsWith('http')) {
        newUrl = `${location.protocol}//${newUrl}`;
      }
      const params = {
        url: newUrl,
        method: method.toLowerCase(),
        headers: headerForm,
        params: paramsForm,
        data: bodyForm,
      };
      console.log(params)
      // this.activeReq.loading = true;
      const req = this.requestList.find(item => item.name === this.activeName);
      req.loading = true;
      setTimeout(() => {
        // req.loading = false;
      }, 5000)
      // axios.request(params).then(res => {
      //   console.log(res)
      // });
    },
    resolvePostmanData(txt) {
      const addUUID = (list) => {
        if (!list) {
          return [];
        }
        if (typeof list === 'string') {
          list = JSON.parse(list);
        }
        if (Array.isArray(list)) {
          list = list.map(item => {
            // console.log(item.value)
            return {
              ...item,
              uuid: this.uuid(),
            };
          });
        } else {
          list = Object.keys(list).map(key => {
            return {
              key,
              value: list[key],
              uuid: this.uuid(),
              type: typeof list[key] === 'object' ? 'json' : 'text'
            };
          });
        }
        return list;
      }
      try {
        let data = txt;
        if (typeof txt === 'string') {
          data = JSON.parse(txt);
        }
        const { item } = data;
        for (const req of item) {
          const { name, request } = req;
          const { url, method, header, body } = request;
          if (!url) {
            continue;
          }
          const { host, port, path, query } = url;
          const newUrl = `${host.join('.')}${port ? (':' + port) : ''}/${path.join('/')}`;

          let bodyParams = [];
          if (body) {
            switch (body.mode) {
              case 'formdata':
                bodyParams = addUUID(body.formdata);
                break;
              case 'urlencoded':
                bodyParams = addUUID(body.urlencoded);
                break;
              case 'raw':
                bodyParams = addUUID(body.raw);
                break;
            }
          }
          const newReq = {
            name,
            url: newUrl,
            method,
            header: addUUID(header),
            body: bodyParams,
            params: addUUID(query),
            loading: false
          };
          // push之前先判断name是否重复
          if (!this.requestList.find(item => item.name === name)) {
            this.requestList.push(newReq);
          }
        }
        // 如果没有选中的，自动选中第一个
        if (!this.activeName) {
          this.activeName = this.requestList?.[0].name ?? '';
        }
        console.log(this.requestList)
      } catch (error) {
        console.log(error)
      }
    },
    onAppend(params) {
      //追加一个空白参数
      params.push({
        uuid: this.uuid(),
        key: '',
        value: '',
        elType: 'input'
      });
    },
    onDelete(params, index) {
      //删除一个参数
      params.splice(index, 1);
    },
    handleClearResult() {

    },
    uuid() {
      // 生成uuid
      return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = (Math.random() * 16) | 0,
          v = c == 'x' ? r : (r & 0x3) | 0x8;
        return v.toString(16);
      });
    }
  }
};
</script>
<style lang="scss" scoped>
.container {
  display: flex;
  padding: 14px;
  height: 100%;

  .left,
  .right {
    display: flex;
    flex-direction: column;
  }

  .left {
    flex-grow: 1;
  }

  .divider {
    height: 100%;
    width: 1px;
    background-color: #DCDFE6;
  }

  .right {
    flex-shrink: 0;
    width: 300px;
    margin-left: 10px;
  }


  .body {
    padding: 0 10px 0 10px;
    flex-grow: 1;
    min-height: 1px;
    // overflow: auto;
    display: flex;
  }

  .toolbar {
    margin-top: 20px;
    text-align: end;
  }
}
</style>
<style lang="scss">
.el-tabs {
  width: 100%;
}


.req-label {
  width: 380px;
  border: 1px solid #dfe4ed;
  max-height: 100%;
  overflow-y: auto;
}

.req-label-item {
  padding: 0 20px;
  height: 40px;
  line-height: 40px;
  font-size: 14px;
  font-weight: 500;
  color: #303133;
  position: relative;
  display: flex;
  align-items: center;
  cursor: pointer;

  &:hover {
    color: #409eff;
  }

  &+.req-label-item {
    border-top: 1px solid #dfe4ed;
  }
}

.req-label-item.is-active {
  color: #409eff;
  background-color: #f5f7fa;
  position: sticky;
  top: 0;
  z-index: 1;
}

.req-label-item_content {
  flex: 1;
  min-width: 1px;
  display: flex;
  align-items: center;
  margin-right: 10px;

  &_val {
    flex: 1;
    min-width: 1px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }


}

.method-indicator {
  margin-right: 15px;
  margin-left: 10px;
}

.method {

  font-weight: 600;
}

.method .el-input__inner {
  font-weight: 600;
}

.GET {
  color: #5fdd9a !important;
}

.POST {
  color: #ceb75f !important;
}

.PUT {
  color: #71a9ee !important;
}

.DELETE {
  color: #f79a8e !important;
}

.req-label-toolbar {
  text-align: center;
  padding: 10px 0;
  position: sticky;
  bottom: 0;
  background-color: white;
  border-top: 1px solid #dfe4ed;
  z-index: 2;
}

.req-content {
  flex: 1;
  width: 1px;
  margin-left: 10px;
  display: flex;
  flex-direction: column;
}

.req-content-header {
  margin-bottom: 10px;
  display: flex;
  align-items: center;
  column-gap: 10px;
}

.input-select {
  width: 120px;
  background-color: #ffffff;
}

.req-params-wrap {
  flex: 1;
  min-height: 1px;
  display: flex;
  flex-direction: column;

  .el-tabs__content {
    flex: 1;
    min-height: 1px;
    padding: 15px 15px 0 15px;

    .el-tab-pane {
      height: 100%;
    }
  }
}

.req-result {
  margin-top: 10px;
  height: 400px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.header-indicator {
  position: relative;

  &::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 0;
    width: 4px;
    height: 80%;
    background-color: #409EFF;
    border-top-right-radius: 4px;
    border-bottom-right-radius: 4px;
    transform: translateY(-50%);
  }
}

.req-result-header {
  width: 100%;
  display: flex;
  align-items: center;
  box-sizing: border-box;
  overflow: hidden;
  justify-content: space-between;
  padding: 0 15px;
  background-color: #f5f7fa;
  border-bottom: 1px solid #DCDFE6;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-shrink: 0;

  &-title {
    font-size: 14px;
    height: 42px;
    line-height: 42px;
  }
}

.progress-wrap {
  display: flex;
  align-items: center;
}

.req-result-body {
  flex: 1;
  min-height: 1px;
  padding: 10px;
  border: 1px solid #dfe4ed;
  border-top: none;
}

.badge-item {
  .el-badge__content {
    top: 10px;
    right: 0px;
  }
}
</style>
