f581a093创建于 2023年7月28日历史提交
<script setup lang="ts">
import { ref, reactive, onMounted, watch, CSSProperties, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { debounce } from 'lodash-es';

import ISSUE_CONFIG from '@/data/quick-issue/quick-issue';
import { getPrSelectOption, getRepoPull } from '@/api/api-quick-issue';
import { OptionList } from '@/shared/@types/type-quick-issue';
import { isValidKey } from '@/shared/utils';
import { useLabelColor } from '@/stores/index';

import IconTraingleUp from '~icons/app/icon-arrow-traingle-up.svg';
import IconTraingleDown from '~icons/app/icon-arrow-traingle-down.svg';
import IconFilter from '~icons/app/icon-filter.svg';
import IconTag from '~icons/app/icon-tag';
import IconRefresh from '~icons/app/icon-refresh';
import IconSetting from '~icons/app/icon-setting';

import ODropdown from 'opendesign/dropdown/ODropdown.vue';
import OIcon from 'opendesign/icon/OIcon.vue';

const props = defineProps({
  issueType: {
    type: String,
    default: '',
  },
  userName: {
    type: String,
    default: '',
  },
});
const { t } = useI18n();

const typeTitel: any = {
  submitted: t('quickIssue.MY_SUBMISSIONS'),
  pending: t('quickIssue.MY_ASSIGNMENTS'),
  all: t('quickIssue.ALL'),
};

const labelColor = useLabelColor();
const isShowLabel = ref(false);
const inputValue = ref('');
const optionValue = ref('');
const openDropDown = ref('');
const isOpen = ref(false);
const issueData = ref([]);
const total = ref(0);
const currentPage = ref(1);
const totalPage = ref(0);
const layout = ref('sizes, prev, pager, next, slot, jumper');

const keyArr = [
  'authorsList',
  'assigneesList',
  'labelsList',
  'exLabelsList',
  'refsList',
  'reposList',
  'sigsList',
];

const filterList = ref(new Map());
// 构造筛选条件数组
for (let i = 0; i < keyArr.length; i++) {
  filterList.value.set(keyArr[i], { page: 1, total: 0, keyword: '', data: [] });
}

const queryData = reactive({
  page: 1,
  per_page:
    props.issueType === 'submitted' || props.issueType === 'pending' ? 5 : 10,
  search: '',
  sig: '',
  state: props.issueType === 'pending' ? ['open'] : [],
  direction: 'desc',
  create: '',
  author: props.issueType === 'submitted' ? props.userName : '',
  sort: 'created_at',
  assignee: props.issueType === 'pending' ? props.userName : '',
  label: [],
  exclusion: [],
  ref: '',
  repo: '',
});

const activeSig = computed(() => {
  return queryData.sig;
});

const optionQuery = reactive({
  page: 1,
  per_page: 40,
  keyword: '',
  sig: activeSig,
});
const titleList = ref(
  new Map([
    [
      'sig',
      {
        value: 'SIG',
      },
    ],
    [
      'repo',
      {
        value: t('quickIssue.REPO_NAME'),
      },
    ],
    [
      'title',
      {
        value: t('quickIssue.TITLE'),
      },
    ],
    [
      'branch',
      {
        value: t('quickIssue.BRANCH'),
      },
    ],
    [
      'state',
      {
        value: t('quickIssue.STATE'),
      },
    ],
    [
      'author',
      {
        value: t('quickIssue.SUBMITTER'),
      },
    ],
    [
      'assignee',
      {
        value: t('quickIssue.ASSIGNER'),
      },
    ],
    [
      'label',
      {
        value: t('quickIssue.LABEL'),
      },
    ],
    [
      'created_at',
      {
        value: t('quickIssue.CREATED_AT'),
      },
    ],
    [
      'updated_at',
      {
        value: t('quickIssue.UPDATE_AT'),
      },
    ],
  ])
);
// 控制表格列
const checkedTitle = ref([
  'repo',
  'title',
  'state',
  'branch',
  'author',
  'label',
  'created_at',
]);
const handleSizeChange = (val: number) => {
  queryData.per_page = val;
  totalPage.value = Math.ceil(total.value / val);
};

const handleCurrentChange = (val: number) => {
  queryData.page = val;
  currentPage.value = val;
};

function searchValchange() {
  queryData.search = inputValue.value;
}

const valueChangeDebounced = debounce(
  (val) => {
    if (val !== optionQuery.keyword) {
      filterList.value.get(`${openDropDown.value}List`).data = [];
      filterList.value.get(`${openDropDown.value}List`).page = 1;
      optionQuery.keyword = val;
      optionQuery.page = 1;
    }
  },
  500,
  {
    trailing: true,
  }
);
function getRepoIssueData() {
  getRepoPull(queryData).then((res) => {
    if (res.data) {
      total.value = res.total;
      issueData.value = res.data;
      totalPage.value = Math.ceil(total.value / queryData.per_page);
    } else {
      total.value = 0;
      issueData.value = [];
    }
  });
}
function handleCommand(command: string | Array<string>, key: string) {
  if (isValidKey(key, queryData)) {
    (queryData as any)[key] = command;
  }
}
function getLabelColor(label: string) {
  const result: CSSProperties = {};
  result.color = `#${
    labelColor?.labelColor?.find((item) => {
      return item.name === label;
    })?.color
  }`;
  return result;
}
function getNextPage() {
  // page * per_page 大于 totle 不再请求
  filterList.value.get(`${openDropDown.value}List`).total >
  filterList.value.get(`${openDropDown.value}List`).page * optionQuery.per_page
    ? (optionQuery.page = ++filterList.value.get(`${openDropDown.value}List`)
        .page)
    : '';
}

function visibleChange(stash: boolean, type: string) {
  isOpen.value = stash;
  if (!stash) {
    optionQuery.page = 1;
    optionQuery.keyword = '';
    optionValue.value = '';
    openDropDown.value = '';
  } else {
    openDropDown.value = type;
    filterList.value.get(`${openDropDown.value}List`).page;
    if (filterList.value.get(`${openDropDown.value}List`).keyword) {
      filterList.value.get(`${openDropDown.value}List`).data = [];
      optionQuery.keyword = filterList.value.get(
        `${openDropDown.value}List`
      ).keyword;
    }
    // SIG 与仓库级联
    if (type === 'repos' && queryData.sig && !queryData.repo) {
      filterList.value.get('reposList').data = [];
      // 手动触发
      if (optionQuery.sig === queryData.sig) {
        optionQuery.page = 1;
        filterList.value.get(`${openDropDown.value}List`).page = 1;
        getOption(openDropDown.value);
      } else {
        optionQuery.sig = queryData.sig;
      }
    }
  }
}
function stateChange(state: string) {
  return ISSUE_CONFIG.PR_STATE.find((item) => {
    return item.VALUE === state;
  })?.TEXT;
}

function sortClick(sort: string) {
  if (queryData.sort === sort) {
    queryData.direction === 'desc'
      ? (queryData.direction = 'asc')
      : (queryData.direction = 'desc');
  }
  queryData.sort = sort;
}
const handleTitleClick = (title: string) => {
  if (checkedTitle.value.includes(title)) {
    const index = checkedTitle.value.indexOf(title);
    checkedTitle.value.splice(index, 1);
  } else {
    checkedTitle.value.push(title);
  }
};
function labelClick() {
  getOption('exLabels');
  isShowLabel.value = true;
}
function getOption(type: string) {
  getPrSelectOption(type, optionQuery)
    .then((res: OptionList) => {
      filterList.value.get(`${type}List`).data = [
        ...filterList.value.get(`${type}List`).data,
        ...res.data,
      ];
      filterList.value.get(`${type}List`).total = res.total;
    })
    .catch((err: any) => {
      throw new Error(err);
    });
}

onMounted(() => {
  if (window.localStorage?.getItem('pr-title')) {
    checkedTitle.value = JSON.parse(
      window.localStorage.getItem('pr-title') as any
    );
  }
  getRepoIssueData();
  getOption('authors');
  getOption('assignees');
  getOption('labels');
  getOption('refs');
  getOption('repos');
  getOption('sigs');
});
watch(
  () => checkedTitle,
  () => {
    window.localStorage.setItem('pr-title', JSON.stringify(checkedTitle.value));
  },
  {
    deep: true,
  }
);
watch(
  () => queryData,
  () => {
    getRepoIssueData();
  },
  {
    deep: true,
  }
);
watch(
  () => optionQuery,
  () => {
    if (isOpen.value) {
      getOption(openDropDown.value);
    }
  },
  {
    deep: true,
  }
);
</script>

<template>
  <div class="table-content" :class="props.userName ? 'login-style' : ''">
    <div class="input-container">
      <h2
        v-show="props.userName"
        :id="typeTitel[props.issueType]"
        class="table-title"
      >
        {{ typeTitel[props.issueType] }}
      </h2>
      <div class="data-amount">({{ total }})</div>
      <OSearch
        v-model="inputValue"
        :placeholder="t('quickIssue.PLACEHOLDER_PR')"
        @change="searchValchange"
      ></OSearch>
    </div>
    <OTable class="quick-issue-table" :data="issueData" style="width: 100%">
      <el-table-column
        v-if="checkedTitle.includes('sig')"
        key="sig"
        min-width="150"
      >
        <template #header>
          <span :class="queryData.sig ? 'active' : ''">{{
            queryData.sig || 'SIG'
          }}</span>

          <ODropdown
            :max-height="250"
            :listener-scorll="true"
            @scorll-bottom="getNextPage"
            @command="(val:string) => handleCommand(val, 'sig')"
            @visible-change="(val:boolean) => visibleChange(val, 'sigs')"
          >
            <OIcon class="filter-icon" :class="queryData.sig ? 'active' : ''">
              <IconFilter></IconFilter>
            </OIcon>

            <template #dropdown>
              <div class="search-box">
                <ODropdownItem v-if="queryData.sig" :command="''">{{
                  t('quickIssue.CANCEL')
                }}</ODropdownItem>
                <OSearch
                  v-model="filterList.get('sigsList').keyword"
                  :placeholder="t('quickIssue.SEARCH_PLACEHOLDER')"
                  @input="valueChangeDebounced"
                ></OSearch>
              </div>
              <ul v-if="filterList.get('sigsList').data.length">
                <ODropdownItem
                  v-for="item in filterList.get('sigsList').data"
                  :key="item"
                  :command="item"
                  :class="queryData.sig === item ? 'is-active' : ''"
                  >{{ item }}</ODropdownItem
                >
              </ul>
              <ODropdownItem v-else disabled class="empty-option"
                >No Data</ODropdownItem
              >
            </template>
          </ODropdown>
        </template>
        <template #default="scope">
          <span class="detail-page">
            {{ scope.row.sig }}
          </span>
        </template>
      </el-table-column>
      <el-table-column
        v-if="checkedTitle.includes('repo')"
        key="repo"
        min-width="150"
      >
        <template #header>
          <span :class="queryData.repo ? 'active' : ''">{{
            queryData.repo || t('quickIssue.REPO_NAME')
          }}</span>
          <ODropdown
            :max-height="250"
            :listener-scorll="true"
            @scorll-bottom="getNextPage"
            @command="(val:string) => handleCommand(val, 'repo')"
            @visible-change="(val:boolean) => visibleChange(val, 'repos')"
          >
            <OIcon class="filter-icon" :class="queryData.repo ? 'active' : ''">
              <IconFilter></IconFilter>
            </OIcon>

            <template #dropdown>
              <div class="search-box">
                <ODropdownItem v-if="queryData.repo" :command="''">{{
                  t('quickIssue.CANCEL')
                }}</ODropdownItem>
                <OSearch
                  v-model="filterList.get('reposList').keyword"
                  :placeholder="t('quickIssue.SEARCH_PLACEHOLDER')"
                  @input="valueChangeDebounced"
                ></OSearch>
              </div>
              <ul v-if="filterList.get('reposList').data.length">
                <ODropdownItem
                  v-for="item in filterList.get('reposList').data"
                  :key="item"
                  :command="item"
                  :class="queryData.repo === item ? 'is-active' : ''"
                  >{{ item }}</ODropdownItem
                >
              </ul>
              <ODropdownItem v-else disabled class="empty-option"
                >No Data</ODropdownItem
              >
            </template>
          </ODropdown>
        </template>
        <template #default="scope">
          <span class="detail-page">
            {{ scope.row.repo }}
          </span>
        </template>
      </el-table-column>
      <el-table-column
        v-if="checkedTitle.includes('title')"
        key="title"
        min-width="350"
      >
        <template #header>
          <span>{{ t('quickIssue.TITLE') }}</span>
        </template>
        <template #default="scope">
          <span class="detail-page">
            <a :href="scope.row.link" target="_blank">{{ scope.row.title }}</a>
          </span>
        </template>
      </el-table-column>
      <el-table-column
        v-if="checkedTitle.includes('branch')"
        key="branch"
        min-width="100"
      >
        <template #header>
          <span :class="queryData.ref ? 'active' : ''">{{
            queryData.ref || t('quickIssue.BRANCH')
          }}</span>

          <ODropdown
            :max-height="250"
            :listener-scorll="true"
            @scorll-bottom="getNextPage"
            @command="(val:string) => handleCommand(val, 'ref')"
            @visible-change="(val:boolean) => visibleChange(val, 'refs')"
          >
            <OIcon class="filter-icon" :class="queryData.ref ? 'active' : ''">
              <IconFilter></IconFilter>
            </OIcon>
            <template #dropdown>
              <div class="search-box">
                <ODropdownItem v-if="queryData.ref" :command="''">{{
                  t('quickIssue.CANCEL')
                }}</ODropdownItem>
                <OSearch
                  v-model="filterList.get('refsList').keyword"
                  :placeholder="t('quickIssue.SEARCH_PLACEHOLDER')"
                  @input="valueChangeDebounced"
                ></OSearch>
              </div>
              <ul v-if="filterList.get('refsList').data.length">
                <ODropdownItem
                  v-for="item in filterList.get('refsList').data"
                  :key="item"
                  :command="item"
                  :class="queryData.ref === item ? 'is-active' : ''"
                  >{{ item }}</ODropdownItem
                >
              </ul>
              <ODropdownItem v-else disabled class="empty-option"
                >No Data</ODropdownItem
              >
            </template>
          </ODropdown>
        </template>
        <template #default="scope">
          <span class="detail-page">
            {{ scope.row.ref }}
          </span>
        </template>
      </el-table-column>
      <el-table-column
        v-if="checkedTitle.includes('state')"
        key="state"
        min-width="100"
      >
        <template #header>
          <span :class="queryData.state.length ? 'active' : ''">
            <template v-if="queryData.state.length">
              <span v-for="item in queryData.state" :key="item">
                {{ stateChange(item)
                }}<i v-show="queryData.state.length > 1">, </i>
              </span>
            </template>
            <template v-else>
              {{ t('quickIssue.STATE') }}
            </template>
          </span>
          <ODropdown
            :max-height="250"
            @command="(val:string) => handleCommand(val, 'state')"
          >
            <OIcon
              class="filter-icon"
              :class="queryData.state.length ? 'active' : ''"
            >
              <IconFilter></IconFilter>
            </OIcon>
            <template #dropdown>
              <el-dropdown-menu>
                <OCheckboxGroup v-model="queryData.state">
                  <OCheckbox
                    v-for="item in ISSUE_CONFIG.PR_STATE"
                    :key="item.VALUE"
                    :value="item.VALUE"
                  >
                    {{ item.TEXT }}
                  </OCheckbox>
                </OCheckboxGroup>
              </el-dropdown-menu>
            </template>
          </ODropdown>
        </template>
        <template #default="scope">
          <span class="detail-page">
            {{ stateChange(scope.row.state) }}
          </span>
        </template>
      </el-table-column>
      <el-table-column
        v-if="
          checkedTitle.includes('author') && props.issueType !== 'submitted'
        "
        key="author"
        min-width="130"
      >
        <template #header>
          <span :class="queryData.author ? 'active' : ''">{{
            queryData.author || t('quickIssue.SUBMITTER')
          }}</span>

          <ODropdown
            :max-height="250"
            :listener-scorll="true"
            @scorll-bottom="getNextPage"
            @command="(val:string) => handleCommand(val, 'author')"
            @visible-change="(val:boolean) => visibleChange(val, 'authors')"
          >
            <OIcon
              class="filter-icon"
              :class="queryData.author ? 'active' : ''"
            >
              <IconFilter></IconFilter>
            </OIcon>

            <template #dropdown>
              <div class="search-box">
                <ODropdownItem v-if="queryData.author" :command="''">{{
                  t('quickIssue.CANCEL')
                }}</ODropdownItem>
                <OSearch
                  v-model="filterList.get('authorsList').keyword"
                  :placeholder="t('quickIssue.SEARCH_PLACEHOLDER')"
                  @input="valueChangeDebounced"
                ></OSearch>
              </div>
              <ul v-if="filterList.get('authorsList').data.length">
                <ODropdownItem
                  v-for="item in filterList.get('authorsList').data"
                  :key="item"
                  :command="item"
                  :class="queryData.author === item ? 'is-active' : ''"
                  >{{ item }}</ODropdownItem
                >
              </ul>
              <ODropdownItem v-else disabled class="empty-option"
                >No Data</ODropdownItem
              >
            </template>
          </ODropdown>
        </template>
        <template #default="scope">
          <span class="detail-page">
            <a
              :key="scope.row.author"
              :href="`https://gitee.com/${scope.row.author}`"
              :title="scope.row.author"
              target="_blank"
            >
              {{ scope.row.author }}
            </a>
          </span>
        </template>
      </el-table-column>
      <el-table-column
        v-if="
          checkedTitle.includes('assignee') && props.issueType !== 'pending'
        "
        key="assignee"
        min-width="130"
      >
        <template #header>
          <span :class="queryData.assignee ? 'active' : ''">{{
            queryData.assignee || t('quickIssue.ASSIGNER')
          }}</span>

          <ODropdown
            :max-height="250"
            :listener-scorll="true"
            @scorll-bottom="getNextPage"
            @command="(val:string) => handleCommand(val, 'assignee')"
            @visible-change="(val:boolean) => visibleChange(val, 'assignees')"
          >
            <OIcon
              class="filter-icon"
              :class="queryData.assignee ? 'active' : ''"
            >
              <IconFilter></IconFilter>
            </OIcon>
            <template #dropdown>
              <div class="search-box">
                <ODropdownItem v-if="queryData.assignee" :command="''">{{
                  t('quickIssue.CANCEL')
                }}</ODropdownItem>
                <OSearch
                  v-model="filterList.get('assigneesList').keyword"
                  :placeholder="t('quickIssue.SEARCH_PLACEHOLDER')"
                  @input="valueChangeDebounced"
                ></OSearch>
              </div>
              <ul v-if="filterList.get('assigneesList').data.length">
                <ODropdownItem
                  v-for="item in filterList.get('assigneesList').data"
                  :key="item"
                  :command="item"
                  :class="queryData.assignee === item ? 'is-active' : ''"
                  >{{ item }}</ODropdownItem
                >
              </ul>
              <ODropdownItem v-else disabled class="empty-option"
                >No Data</ODropdownItem
              >
            </template>
          </ODropdown>
        </template>
        <template #default="scope">
          <span class="detail-page">
            <a
              v-for="item in scope.row.assignees?.split(',')"
              :key="item"
              :href="`https://gitee.com/${item}`"
              :class="item === queryData.assignee ? 'active' : ''"
              :title="item"
              class="link"
              target="_blank"
            >
              {{ item }}
            </a>
          </span>
        </template>
      </el-table-column>
      <el-table-column
        v-if="checkedTitle.includes('label')"
        key="label"
        min-width="200"
      >
        <template #header>
          <div
            class="filter-box"
            :class="
              queryData.label.length || queryData.exclusion.length
                ? 'active'
                : ''
            "
          >
            <p v-if="queryData.label.length || queryData.exclusion.length">
              <span class="label-title" :title="queryData.label.join(',')">{{
                queryData.label.join(',')
              }}</span>
              <span
                class="label-title label-exclusion"
                :title="queryData.exclusion.join(',')"
                >{{ queryData.exclusion.join(',') }}</span
              >
            </p>
            <span v-else>{{ t('quickIssue.LABEL') }}</span>
          </div>
          <OIcon
            class="filter-icon"
            :class="queryData.label.length ? 'active' : ''"
            @click="labelClick()"
          >
            <IconFilter></IconFilter>
          </OIcon>
        </template>
        <template #default="scope">
          <span class="detail-page">
            <p
              v-for="item in scope.row.labels?.split(',')"
              :key="item"
              :title="item"
              :style="getLabelColor(item)"
            >
              <OIcon v-if="item">
                <IconTag></IconTag>
              </OIcon>
              {{ item }}
            </p>
          </span>
        </template>
      </el-table-column>
      <el-table-column
        v-if="checkedTitle.includes('created_at')"
        key="created_at"
        min-width="120"
      >
        <template #header>
          <span>{{ t('quickIssue.CREATED_AT') }}</span>
          <div class="sort-time" @click="sortClick('created_at')">
            <OIcon
              class="icon-up"
              :class="
                queryData.direction === 'asc' && queryData.sort === 'created_at'
                  ? 'slot-active'
                  : ''
              "
            >
              <IconTraingleUp></IconTraingleUp>
            </OIcon>
            <OIcon
              class="icon-down"
              :class="
                queryData.direction === 'desc' &&
                queryData.sort === 'created_at'
                  ? 'slot-active'
                  : ''
              "
            >
              <IconTraingleDown></IconTraingleDown>
            </OIcon>
          </div>
        </template>
        <template #default="scope">
          <span class="detail-page">
            <p>{{ scope.row.created_at?.split(' ')[0] }}</p>
            <p>{{ scope.row.created_at?.split(' ')[1] }}</p>
          </span>
        </template>
      </el-table-column>
      <el-table-column
        v-if="checkedTitle.includes('updated_at')"
        key="updated_at"
        min-width="120"
      >
        <template #header>
          <span>{{ t('quickIssue.UPDATE_AT') }}</span>
          <div class="sort-time" @click="sortClick('updated_at')">
            <OIcon
              class="icon-up"
              :class="
                queryData.direction === 'asc' && queryData.sort === 'updated_at'
                  ? 'slot-active'
                  : ''
              "
            >
              <IconTraingleUp></IconTraingleUp>
            </OIcon>
            <OIcon
              class="icon-down"
              :class="
                queryData.direction === 'desc' &&
                queryData.sort === 'updated_at'
                  ? 'slot-active'
                  : ''
              "
            >
              <IconTraingleDown></IconTraingleDown>
            </OIcon>
          </div>
        </template>
        <template #default="scope">
          <span class="detail-page">
            <p>{{ scope.row.updated_at?.split(' ')[0] }}</p>
            <p>{{ scope.row.updated_at?.split(' ')[1] }}</p>
          </span>
        </template>
      </el-table-column>
      <el-table-column
        key="setting"
        width="50"
        fixed="right"
        class-name="setting-title"
      >
        <template #header>
          <el-popover width="286" trigger="click">
            <template #reference>
              <OIcon :class="queryData.assignee ? 'active' : ''">
                <IconSetting></IconSetting>
              </OIcon>
            </template>
            <div class="filter-title">
              <OTag
                v-for="(item, index) in titleList"
                v-show="
                  !(item[0] === 'author' && props.issueType === 'submitted') &&
                  !(item[0] === 'assignee' && props.issueType === 'pending')
                "
                :key="index"
                checkable
                checked
                :type="checkedTitle.includes(item[0]) ? 'primary' : 'text'"
                @click="handleTitleClick(item[0])"
              >
                {{ item[1].value }}
              </OTag>
            </div>
          </el-popover>
        </template>
      </el-table-column>
    </OTable>
    <OPagination
      v-model:page-size="queryData.per_page"
      v-model:currentPage="queryData.page"
      class="pagination"
      :page-sizes="[5, 10, 20, 40, 80]"
      :layout="layout"
      :total="total"
      :background="true"
      :hide-on-single-page="true"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    >
      <span class="slot-content">{{ currentPage }}/{{ totalPage }}</span>
    </OPagination>
  </div>
  <ODialog v-model="isShowLabel" :show-close="true" :lock-scroll="true">
    <h1 class="title">{{ t('quickIssue.LABEL') }}</h1>
    <div class="label-select">
      <span class="label">{{ t('quickIssue.SELECT_LABEL') }}</span>
      <OSelect
        v-model="queryData.label"
        multiple
        :placeholder="t('quickIssue.SELECT')"
        popper-class="remove-scrollbar"
        :listener-scorll="true"
        @scorll-bottom="getNextPage"
        @visible-change="(val:boolean) => visibleChange(val, 'labels')"
      >
        <OSearch
          v-model="filterList.get('labelsList').keyword"
          :placeholder="t('quickIssue.SEARCH_PLACEHOLDER')"
          style="padding: 0 8px"
          @input="valueChangeDebounced"
        ></OSearch>
        <el-scrollbar class="Escrollbar">
          <ElOption
            v-if="!filterList.get('labelsList').data.length"
            :key="''"
            :label="'no date'"
            :value="''"
            :disabled="true"
            style="text-align: center"
          />
          <ElOption
            v-for="item in filterList.get('labelsList').data"
            :key="item"
            :label="item"
            :value="item"
          />
        </el-scrollbar>
      </OSelect>
      <OIcon class="icon-refresh" @click="queryData.label = []">
        <IconRefresh> </IconRefresh>
      </OIcon>
    </div>
    <p class="label-tip">{{ t('quickIssue.LABER_TIP') }}</p>
    <div class="label-select">
      <span class="label">{{ t('quickIssue.EXCLUDE') }}</span>
      <OSelect
        v-model="queryData.exclusion"
        multiple
        :placeholder="t('quickIssue.SELECT')"
        popper-class="remove-scrollbar"
        :listener-scorll="true"
        @scorll-bottom="getNextPage"
        @visible-change="(val:boolean) => visibleChange(val, 'exLabels')"
      >
        <OSearch
          v-model="filterList.get('exLabelsList').keyword"
          :placeholder="t('quickIssue.SEARCH_PLACEHOLDER')"
          style="padding: 0 8px"
          @input="valueChangeDebounced"
        ></OSearch>
        <ElOption
          v-if="!filterList.get('exLabelsList').data.length"
          :key="''"
          :label="'no date'"
          :value="''"
          :disabled="true"
          style="text-align: center"
        />
        <ElOption
          v-for="item in filterList.get('exLabelsList').data"
          :key="item"
          :label="item"
          :value="item"
        />
      </OSelect>
      <OIcon class="icon-refresh" @click="queryData.exclusion = []">
        <IconRefresh> </IconRefresh>
      </OIcon>
    </div>
    <p class="label-tip">{{ t('quickIssue.LABER_TIP1') }}</p>
  </ODialog>
</template>

<style lang="scss" scoped>
.app-content {
  position: relative;
}
.table-content {
  .table-title {
    flex-shrink: 0;
    font-weight: 300;
    font-size: var(--o-font-size-h4);
    &::before {
      content: '';
      display: block;
      height: 40px;
      margin-top: -40px;
      visibility: hidden;
    }
  }
  .data-amount {
    margin: 0 24px 0 0;
    display: none;
  }
}
.login-style {
  margin-bottom: 40px;
  padding: 40px;
  background-color: var(--o-color-bg2);
  .input-container {
    align-items: center;
    :deep(.o-search) {
      height: 40px;
    }
    .data-amount {
      display: flex;
      align-items: center;
      font-weight: 300;
      font-size: var(--o-font-size-h4);
    }
  }
  .quick-issue-table {
    margin-top: var(--o-spacing-h4);
  }
  .o-pagination {
    margin-top: 40px;
    margin-bottom: 0;
  }
}
.filter-title {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  width: 260px;
  background-color: #fff;
}
.el-popper.el-select__popper {
  --el-popper-border-radius: 0;
  .el-input {
    position: relative;
    padding: 0px 8px;
    position: sticky;
    top: 8px;
    background-color: var(--o-color-bg2);
    z-index: 1;
    &::before {
      position: absolute;
      content: '';
      height: 10px;
      width: 100%;
      top: -10px;
      left: 0;
      background-color: var(--o-color-bg2);
    }
  }
  .el-input__wrapper {
    padding: 0 32px 0 20px;
    box-shadow: 0 0 0 1px var(--o-color-border1) inset;
    &:hover {
      box-shadow: 0 0 0 1px var(--o-color-border1) inset;
    }
  }
}
.issue-btn {
  border-color: var(--o-color-white);
  color: var(--o-color-white);
  @media (max-width: 767px) {
    padding: 3px 16px;
    font-size: var(--o-font-size-text);
    line-height: var(--o-line-height-text);
  }
}
.active {
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  word-spacing: 100vw;
  color: var(--o-color-brand1);
  .label-title {
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 1;
  }
  .label-exclusion {
    text-decoration: line-through;
  }
}
:deep(.quick-issue-table) {
  margin-top: var(--o-spacing-h3);
  box-shadow: none;
  .el-table__body-wrapper {
    transform: scaleY(-1);

    .el-scrollbar__view {
      transform: scaleY(-1);
    }
  }
  tr {
    .cell {
      display: flex;
      align-items: center;
      .detail-page {
        p,
        .link {
          overflow: hidden;
          text-overflow: ellipsis;
          display: -webkit-box;
          -webkit-box-orient: vertical;
          -webkit-line-clamp: 1;
          .o-icon {
            display: inline-block;
          }
        }
        .active {
          color: var(--o-color-warning1);
        }
      }
      .filter-icon {
        cursor: pointer;
        flex-shrink: 0;
        margin-left: 5px;
        color: var(--o-color-text1);
      }
      .select-icon {
        font-size: 24px;
      }
      .sort-time {
        cursor: pointer;
        display: flex;
        flex-direction: column;
        color: #999;
        .icon-up {
          margin-bottom: -4px;
        }
        .icon-down {
          margin-top: -4px;
        }
        .slot-active {
          color: var(--o-color-text1);
        }
      }
    }
  }
  .setting-title {
    .cell {
      justify-content: center;
      padding: 0;
    }

    .o-icon {
      cursor: pointer;
      font-size: 20px;
    }
  }
}

.input-container {
  display: flex;
  .table-title {
    flex-shrink: 0;
  }
  @media screen and (max-width: 768px) {
    margin-bottom: var(--o-spacing-h5);
  }
  :deep(.o-search) {
    height: 48px;
    @media screen and (max-width: 768px) {
      height: 36px;
    }
  }
}
:deep(.pagination) {
  margin-top: var(--o-spacing-h2);
  .el-pager {
    .is-active {
      background-color: var(--o-color-brand2) !important;
    }
    .number:hover,
    .more:hover {
      background-color: var(--o-color-brand2);
    }
  }
  .slot-content {
    color: var(--o-color-white);
  }
}

.el-dropdown__popper {
  .o-dropdown-item:empty {
    display: none;
  }
  .o-checkbox-group {
    flex-direction: column;
    justify-content: flex-start;
    align-items: flex-start;
  }
  .o-checkbox {
    display: flex;
    align-items: center;
    margin: 5px 16px;
  }
  .el-checkbox {
    display: flex;
    align-items: center;
    margin: 5px 16px;
    height: 22px;

    :deep(.el-checkbox__label) {
      color: var(--o-color-text1);
    }
  }
}
</style>
<style lang="scss">
.o-dialog {
  max-width: 500px;
  width: 100%;
  border-radius: 0;
  .el-dialog__header {
    padding: 0;
    .el-dialog__headerbtn {
      top: var(--o-spacing-h4);
      right: var(--o-spacing-h4);
      font-size: var(--o-font-size-h5);
      width: fit-content;
      height: fit-content;
      z-index: 10;
      .el-dialog__close {
        color: var(--o-color-text1);
      }
    }
  }
  .el-dialog__body {
    padding: var(--o-spacing-h4);
    .title {
      font-weight: 500;
      line-height: var(--o-line-height-h8);
      font-size: var(--o-font-size-h8);
    }
    .label-select {
      display: flex;
      align-items: center;
      justify-content: flex-start;
      .label {
        margin-right: var(--o-spacing-h6);
        word-break: break-word;
        min-width: 58px;
      }
      .icon-refresh {
        cursor: pointer;
        margin-left: var(--o-spacing-h8);
        font-size: var(--o-font-size-h7);
        color: var(--o-color-text1);
      }
    }
    .label-tip {
      margin: 12px 0 0 68px;
      color: var(--o-color-brand1);
    }
    .label-select:nth-of-type(1) {
      margin-top: var(--o-spacing-h4);
    }
    .label-tip:nth-of-type(1) {
      margin-bottom: 24px;
    }
    .o-select {
      .el-input__wrapper {
        min-width: 350px;
        box-shadow: 0 0 0 1px var(--o-color-border1) inset;
        &:hover {
          box-shadow: 0 0 0 1px var(--o-color-border1) inset;
        }
        .o-icon {
          font-size: var(--o-font-size-h7);
        }
      }
    }
  }
}
</style>