<template>
  <div class="frame-body adaption-frame-body task-page">
    <div class="frame-card">
      <div class="frame-card-header border-radius">
        <div class="frame-search search-toolbar">
          <el-form :inline="true" :model="search" class="demo-form-inline">
            <div class="search-line">
              <div class="item2">
                <el-form-item v-if="showSearchType">
                  <el-select v-model="search.searchType" placeholder="全部状态" clearable @change="triggerSearch">
                    <el-option v-for="item in searchTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
                  </el-select>
                </el-form-item>
                <el-form-item v-if="showCompanyFilter">
                  <el-select v-model="search.subCompanyId" placeholder="请选择公司" clearable filterable @change="handleCompanyChange">
                    <el-option v-for="item in companyOptions" :key="item.value" :label="item.label" :value="item.value" />
                  </el-select>
                </el-form-item>
                <el-form-item v-if="showDeptFilter">
                  <el-select v-model="search.deptId" placeholder="请选择部门" clearable filterable @change="handleDeptChange">
                    <el-option v-for="item in deptOptions" :key="item.value" :label="item.label" :value="item.value" />
                  </el-select>
                </el-form-item>
                <el-form-item v-if="showUserFilter">
                  <el-select v-model="search.userId" placeholder="请选择成员" clearable filterable @change="triggerSearch">
                    <el-option v-for="item in userOptions" :key="item.value" :label="item.label" :value="item.value" />
                  </el-select>
                </el-form-item>
                <el-form-item>
                  <el-select
                    v-model="search.status"
                    multiple
                    collapse-tags
                    collapse-tags-tooltip
                    placeholder="全部状态"
                    style="width: 160px"
                    @change="triggerSearch"
                  >
                    <el-option label="未开始" value="1" />
                    <el-option label="进行中" value="2" />
                    <el-option label="已完成" value="3" />
                    <el-option label="已逾期" value="5" />
                  </el-select>
                </el-form-item>
                <el-form-item>
                  <el-date-picker
                    v-model="dt2"
                    type="daterange"
                    value-format="YYYY-MM-DD"
                    start-placeholder="开始时间"
                    end-placeholder="结束时间"
                    :clearable="true"
                    @change="handleChangeTime"
                  />
                </el-form-item>
                <el-form-item>
                  <el-input
                    v-model="kws"
                    placeholder="请输入关键字"
                    clearable
                    @keyup.enter="keydownSearch"
                    @blur="keydownSearch"
                  />
                </el-form-item>
                <el-form-item>
                  <el-button type="primary" @click="reset">重置</el-button>
                </el-form-item>
              </div>
              <div class="item3">
                <el-form-item>
                  <span class="search-right">
                    <el-button v-if="switchRoute" circle @click="goSwitchRoute">
                      <el-icon><OfficeBuilding /></el-icon>
                    </el-button>
                    <el-button v-if="allowBatchDelete" type="primary" @click="delTasks">批量删除</el-button>
                    <el-button v-if="allowCreate" type="primary" @click="openDialogForm">新建任务</el-button>
                  </span>
                </el-form-item>
              </div>
            </div>
          </el-form>
        </div>
      </div>

      <div class="frame-card-content table-area">
        <div class="calendar-day h-100">
          <div class="target_list h-100">
            <div class="list-header">
              <div class="name-col">
                <el-checkbox
                  v-model="checkouts"
                  :disabled="allDisabled"
                  style="padding: 0 10px"
                  :indeterminate="allIndeterminate"
                  @change="checkAllIn"
                />
                任务名称
              </div>
              <div class="person-col">执行人</div>
              <div class="progress-col">进度</div>
              <div class="person-col">状态</div>
              <div class="time-col">任务时间</div>
              <div class="person-col">来源</div>
              <div class="handle-col">操作</div>
            </div>

            <div class="card-content" v-loading="loading">
              <div v-for="item in pageData" :key="item.taskDateId || item.id" class="card-box">
                <div class="card-row-main">
                  <div class="icon-col">
                    <el-icon
                      v-if="item.sonTasks && item.sonTasks.length"
                      class="expand-icon"
                      :class="{ 'is-close': !item.show }"
                      @click="item.show = !item.show"
                    >
                      <ArrowDown />
                    </el-icon>
                  </div>
                  <div class="box-target-col text-overflow">
                    <el-checkbox
                      v-model="item.checks"
                      :disabled="!item.isEditable"
                      :indeterminate="item.indeterminate"
                      style="padding-right: 10px"
                      @change="checkChange(item)"
                    />
                    <p class="title" v-html="item.title || item.name" @click="goDetail(item)"></p>
                    <span v-if="formatTaskLabel(item.taskLabel)" class="task-label">{{ formatTaskLabel(item.taskLabel) }}</span>
                    <span v-for="(tag, idx) in normalizeTags(item.taskTagls)" :key="idx" class="task-tag">{{ tag }}</span>
                  </div>
                  <div class="person-col person-col-flex">
                    <el-avatar :size="28">{{ getAvatarText(item.executeName || item.ownerName) }}</el-avatar>
                    <span class="person-name">{{ item.executeName || item.ownerName || item.memberName || '-' }}</span>
                  </div>
                  <div class="progress-col">
                    <div class="progress-click" @click="openDialogTaskProgress(item.taskDateId || item.id)">
                      <el-progress :percentage="toNumber(item.percent)" :stroke-width="12" color="#2d8cf0" />
                    </div>
                  </div>
                  <div class="person-col">
                    <div>{{ formatStatus(item.status, item.statusLabel) }}</div>
                    <div v-if="Number(item.status) === 5 && item.overdueDays" class="overdue-text">{{ `(已逾期${item.overdueDays})` }}</div>
                  </div>
                  <div class="time-col">
                    <span v-if="item.dateType && Number(item.dateType) < 5">{{ item.dateStartDate }}</span>
                    <span v-if="item.dateType && Number(item.dateType) < 5">（</span>
                    {{ item.dateName || item.deadline || item.createdAt || '-' }}
                    <span v-if="item.dateType && Number(item.dateType) < 5">）</span>
                  </div>
                  <div class="person-col">{{ item.createName || item.fromName || '-' }}</div>
                  <div class="handle-col handle-col-btn">
                    <button v-if="allowCreate" type="button" class="img-btn" title="添加子任务" @click="openDialogForm(item.id)">+</button>
                    <button type="button" class="img-btn look-btn" title="查看详情" @click="goDetail(item)">看</button>
                    <button type="button" class="img-btn del-btn" title="删除任务" @click="del(item.id)">删</button>
                  </div>
                </div>

                <div v-show="item.show" class="box-content">
                  <div v-for="task in item.sonTasks || []" :key="task.taskDateId || task.id" class="card-row-sub">
                    <div class="icon-col icon-col-placeholder"></div>
                    <div class="content-target-col text-overflow">
                      <el-checkbox
                        v-model="task.checks"
                        :disabled="!task.isEditable"
                        style="padding-right: 10px"
                        @change="checkChangeSon(item, task)"
                      />
                      <p class="title" v-html="task.title || task.name" @click="goDetail(task)"></p>
                      <span v-if="formatTaskLabel(task.taskLabel)" class="task-label">{{ formatTaskLabel(task.taskLabel) }}</span>
                      <span v-for="(tag, idx) in normalizeTags(task.taskTagls)" :key="idx" class="task-tag">{{ tag }}</span>
                    </div>
                    <div class="person-col person-col-flex">
                      <el-avatar :size="28">{{ getAvatarText(task.executeName || task.ownerName) }}</el-avatar>
                      <span class="person-name">{{ task.executeName || task.ownerName || '-' }}</span>
                    </div>
                    <div class="progress-col">
                      <div class="progress-click" @click="openDialogTaskProgress(task.taskDateId || task.id)">
                        <el-progress :percentage="toNumber(task.percent)" :stroke-width="12" color="#2d8cf0" />
                      </div>
                    </div>
                    <div class="person-col">
                      <div>{{ formatStatus(task.status, task.statusLabel) }}</div>
                      <div v-if="Number(task.status) === 5 && task.overdueDays" class="overdue-text">{{ `(已逾期${task.overdueDays})` }}</div>
                    </div>
                    <div class="time-col">
                      <span v-if="task.dateType && Number(task.dateType) < 5">{{ task.dateStartDate }}</span>
                      <span v-if="task.dateType && Number(task.dateType) < 5">（</span>
                      {{ task.dateName || task.deadline || '-' }}
                      <span v-if="task.dateType && Number(task.dateType) < 5">）</span>
                    </div>
                    <div class="person-col">{{ task.createName || task.fromName || '-' }}</div>
                    <div class="handle-col handle-col-btn">
                      <button type="button" class="img-btn look-btn" title="查看详情" @click="goDetail(task)">看</button>
                      <button type="button" class="img-btn del-btn" title="删除任务" @click="del(task.id)">删</button>
                    </div>
                  </div>
                </div>
              </div>

              <el-empty v-if="!pageData.length && !loading" description="暂无任务" />
            </div>

            <div class="pager-wrap">
              <el-pagination
                v-model:current-page="pagination.pageNo"
                v-model:page-size="pagination.pageSize"
                background
                :page-sizes="pagination.psizes"
                :total="pagination.total"
                layout="total, sizes, prev, pager, next"
                @size-change="loadData"
                @current-change="loadData"
              />
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { onActivated, onMounted, reactive, ref } from 'vue'
import moment from 'moment'
import { ArrowDown, OfficeBuilding } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useRouter } from 'vue-router'
import { getCompanyList, getDepartmentList, getPersonList } from '@/api/public'
import { taskListAtMine, taskListByTable, taskListSubordinateGantt } from '@/api/otr/task/core'

type TaskRow = Record<string, any>
type OptionItem = { label: string; value: string }
type Scene = 'table' | 'member' | 'at-list'

const props = withDefaults(
  defineProps<{
    scene: Scene
    showSearchType?: boolean
    showCompanyFilter?: boolean
    showDeptFilter?: boolean
    showUserFilter?: boolean
    allowCreate?: boolean
    allowBatchDelete?: boolean
    switchRoute?: string
    defaultRange?: 'month' | 'empty'
    searchTypeOptions?: OptionItem[]
  }>(),
  {
    showSearchType: false,
    showCompanyFilter: false,
    showDeptFilter: false,
    showUserFilter: false,
    allowCreate: false,
    allowBatchDelete: false,
    switchRoute: '',
    defaultRange: 'month',
    searchTypeOptions: () => [],
  },
)

const router = useRouter()
const loading = ref(false)
const kws = ref('')
const pageData = ref<TaskRow[]>([])
const companyOptions = ref<OptionItem[]>([])
const deptOptions = ref<OptionItem[]>([])
const userOptions = ref<OptionItem[]>([])
const checkouts = ref(false)
const allIndeterminate = ref(false)
const allDisabled = ref(false)
const userInfo = ref<Record<string, any>>(readUserInfo())
const defaultMonthRange = [moment().format('YYYY-MM-DD'), moment().endOf('month').format('YYYY-MM-DD')]
const dt2 = ref<[string, string] | string[]>(props.defaultRange === 'month' ? defaultMonthRange : [])

const pagination = reactive({
  total: 0,
  psizes: [10, 20, 50, 100],
  pageNo: 1,
  pageSize: 10,
})

const search = reactive({
  orderBy: '',
  sort: '',
  deptId: '',
  subCompanyId: '',
  searchType: '',
  keyWord: '',
  endDate: props.defaultRange === 'month' ? defaultMonthRange[1] : '',
  startDate: props.defaultRange === 'month' ? defaultMonthRange[0] : '',
  sta: [] as string[],
  status: [] as string[],
  userId: '',
  pageNo: 1,
  pageSize: 10,
})

function readUserInfo() {
  try {
    return JSON.parse(localStorage.getItem('userInfo') || '{}')
  } catch {
    return {}
  }
}

function goSwitchRoute() {
  if (props.switchRoute) {
    router.push(props.switchRoute)
  }
}

function keydownSearch() {
  search.keyWord = kws.value
  resetPageAndLoad()
}

function triggerSearch() {
  search.sta = [...(search.status || [])]
  resetPageAndLoad()
}

function handleChangeTime(value: string[] | null) {
  const range = Array.isArray(value) ? value : []
  search.startDate = range[0] || ''
  search.endDate = range[1] || ''
  resetPageAndLoad()
}

async function handleCompanyChange(value: string) {
  search.subCompanyId = value || ''
  search.deptId = ''
  search.userId = ''
  deptOptions.value = []
  userOptions.value = []
  if (search.subCompanyId) {
    await loadDeptOptions(search.subCompanyId)
  }
  resetPageAndLoad()
}

async function handleDeptChange(value: string) {
  search.deptId = value || ''
  search.userId = ''
  userOptions.value = []
  if (search.deptId) {
    await loadUserOptions(search.deptId)
  }
  resetPageAndLoad()
}

function reset() {
  const currentUser = readUserInfo()
  kws.value = ''
  search.keyWord = ''
  search.searchType = ''
  search.status = []
  search.sta = []
  search.userId = ''
  if (props.showCompanyFilter) {
    search.subCompanyId = String(currentUser.subCompanyId || '')
  } else {
    search.subCompanyId = ''
  }
  if (props.showDeptFilter) {
    search.deptId = String(currentUser.deptId || '')
  } else {
    search.deptId = ''
  }
  if (props.defaultRange === 'month') {
    dt2.value = [...defaultMonthRange]
    search.startDate = defaultMonthRange[0]
    search.endDate = defaultMonthRange[1]
  } else {
    dt2.value = []
    search.startDate = ''
    search.endDate = ''
  }
  loadDefaultFilters()
  resetPageAndLoad()
}

function openDialogForm(parentTaskId?: string | number) {
  if (parentTaskId) {
    router.push({ path: '/otr/task/form', query: { ptaskId: String(parentTaskId) } })
    return
  }
  router.push('/otr/task/form')
}

function goDetail(row: TaskRow) {
  router.push({ path: '/otr/task/detail', query: { id: String(row.taskDateId || row.id || '') } })
}

function openDialogTaskProgress(taskId?: string | number) {
  if (!taskId) return
  router.push({ path: '/otr/task/detail', query: { id: String(taskId) } })
}

function normalizeTaskRows(records: TaskRow[]) {
  return (records || []).map((item) => ({
    ...item,
    title: item.title || item.name || '-',
    executeName: item.executeName || item.ownerName || item.memberName || '-',
    createName: item.createName || item.fromName || '-',
    percent: toNumber(item.percent || item.progress || 0),
    status: item.status ?? inferStatus(item.statusLabel),
    dateName: item.dateName || item.deadline || item.createdAt || '-',
    dateStartDate: item.dateStartDate || item.startDate || item.deadline || item.createdAt || '',
    show: item.show ?? true,
    isEditable: item.isEditable ?? true,
    sonTasks: normalizeTaskRows(item.sonTasks || []),
    checks: false,
    indeterminate: false,
  }))
}

async function loadData() {
  loading.value = true
  try {
    const payload = {
      ...search,
      pageNo: pagination.pageNo,
      pageSize: pagination.pageSize,
      page: pagination.pageNo,
      psize: pagination.pageSize,
      sta: search.status,
      status: search.status,
      keyWord: search.keyWord,
      kws: search.keyWord,
      startDate: search.startDate,
      endDate: search.endDate,
      start: search.startDate,
      end: search.endDate,
    }

    let res: any
    if (props.scene === 'member') {
      res = await taskListSubordinateGantt(payload)
    } else if (props.scene === 'at-list') {
      res = await taskListAtMine(payload)
    } else {
      res = await taskListByTable(payload)
    }

    const result = res?.result || {}
    const records = result.records || result.list || []
    pageData.value = normalizeTaskRows(records)
    pagination.total = Number(result.total || pageData.value.length)
    syncCheckState()
  } finally {
    loading.value = false
  }
}

function resetPageAndLoad() {
  pagination.pageNo = 1
  loadData()
}

function checkAllIn() {
  allIndeterminate.value = false
  pageData.value.forEach((item) => {
    if (item.isEditable) {
      item.checks = checkouts.value
      item.indeterminate = false
    }
    ;(item.sonTasks || []).forEach((child: TaskRow) => {
      if (child.isEditable) child.checks = checkouts.value
    })
  })
  syncCheckState()
}

function checkChange(row: TaskRow) {
  row.indeterminate = false
  ;(row.sonTasks || []).forEach((child: TaskRow) => {
    if (child.isEditable) child.checks = !!row.checks
  })
  syncCheckState()
}

function checkChangeSon(parent: TaskRow, task: TaskRow) {
  const editableChildren = (parent.sonTasks || []).filter((child: TaskRow) => child.isEditable)
  const checkedCount = editableChildren.filter((child: TaskRow) => child.checks).length
  parent.checks = checkedCount > 0 && checkedCount === editableChildren.length
  parent.indeterminate = checkedCount > 0 && checkedCount < editableChildren.length
  task.checks = !!task.checks
  syncCheckState()
}

function getChooseIds() {
  const ids: Array<string | number> = []
  pageData.value.forEach((item) => {
    if (item.checks) ids.push(item.id)
    ;(item.sonTasks || []).forEach((child: TaskRow) => {
      if (child.checks) ids.push(child.id)
    })
  })
  return ids.filter(Boolean)
}

function syncCheckState() {
  const editableRows = pageData.value.flatMap((item) => {
    const rows = item.isEditable ? [item] : []
    const children = (item.sonTasks || []).filter((child: TaskRow) => child.isEditable)
    return rows.concat(children)
  })
  const checkedRows = editableRows.filter((row) => row.checks)
  allDisabled.value = editableRows.length === 0
  checkouts.value = editableRows.length > 0 && checkedRows.length === editableRows.length
  allIndeterminate.value = checkedRows.length > 0 && checkedRows.length < editableRows.length
}

function delTasks() {
  const ids = getChooseIds()
  if (!ids.length) {
    ElMessage.warning('请先选择任务')
    return
  }
  ElMessageBox.confirm('确认批量删除已选择任务吗？', '系统提示', {
    confirmButtonText: '提交',
    cancelButtonText: '取消',
    type: 'warning',
  })
    .then(() => {
      pageData.value = pageData.value.filter((item) => !ids.includes(item.id))
      pageData.value.forEach((item) => {
        item.sonTasks = (item.sonTasks || []).filter((child: TaskRow) => !ids.includes(child.id))
      })
      pagination.total = Math.max(0, pagination.total - ids.length)
      syncCheckState()
      ElMessage.success('删除成功')
    })
    .catch(() => undefined)
}

function del(id?: string | number) {
  if (!id) return
  ElMessageBox.confirm('确认删除该任务吗？', '系统提示', {
    confirmButtonText: '提交',
    cancelButtonText: '取消',
    type: 'warning',
  })
    .then(() => {
      pageData.value = pageData.value.filter((item) => item.id !== id)
      pageData.value.forEach((item) => {
        item.sonTasks = (item.sonTasks || []).filter((child: TaskRow) => child.id !== id)
      })
      pagination.total = Math.max(0, pagination.total - 1)
      syncCheckState()
      ElMessage.success('删除成功')
    })
    .catch(() => undefined)
}

function toNumber(value: any) {
  const raw = String(value ?? '0').replace('%', '')
  const num = Number(raw)
  return Number.isNaN(num) ? 0 : Math.max(0, Math.min(100, num))
}

function inferStatus(label?: string) {
  if (!label) return 1
  if (label.includes('未开始') || label.includes('未读')) return 1
  if (label.includes('进行中') || label.includes('待处理') || label.includes('待确认')) return 2
  if (label.includes('已完成') || label.includes('已发布')) return 3
  if (label.includes('已逾期')) return 5
  return 1
}

function formatStatus(status: any, statusLabel?: string) {
  if (statusLabel) return statusLabel
  switch (Number(status)) {
    case 1:
      return '未开始'
    case 2:
      return '进行中'
    case 3:
    case 4:
      return '已完成'
    case 5:
      return '已逾期'
    default:
      return '-'
  }
}

function formatTaskLabel(label: any) {
  const value = Number(label)
  if (!value || value === 1) return ''
  if (value === 2) return '主任务'
  if (value === 3) return '子任务'
  return '任务'
}

function normalizeTags(tags: any) {
  if (!Array.isArray(tags)) return []
  return tags.map((item) => item?.name || item?.label || item?.title || String(item)).filter(Boolean)
}

function getAvatarText(name?: string) {
  return name ? name.slice(-1) : '人'
}

function normalizeOptionList(list: any[], valueKeys: string[], labelKeys: string[]) {
  return (list || []).map((item) => ({
    value: String(valueKeys.map((key) => item?.[key]).find(Boolean) ?? ''),
    label: String(labelKeys.map((key) => item?.[key]).find(Boolean) ?? '-'),
  })).filter((item) => item.value)
}

async function loadCompanyOptions() {
  try {
    const res: any = await getCompanyList()
    companyOptions.value = normalizeOptionList(res?.result || res?.rows || res?.data || [], ['id', 'value'], ['name', 'label'])
  } catch {
    companyOptions.value = []
  }
}

async function loadDeptOptions(companyId: string) {
  if (!companyId) {
    deptOptions.value = []
    return
  }
  try {
    const res: any = await getDepartmentList(companyId)
    deptOptions.value = normalizeOptionList(res?.result || res?.rows || res?.data || [], ['id', 'value'], ['name', 'title', 'label'])
  } catch {
    deptOptions.value = []
  }
}

async function loadUserOptions(deptId: string) {
  if (!deptId) {
    userOptions.value = []
    return
  }
  try {
    const res: any = await getPersonList(deptId)
    userOptions.value = normalizeOptionList(res?.result || res?.rows || res?.data || [], ['id', 'userId', 'value'], ['realName', 'staffName', 'name', 'label'])
  } catch {
    userOptions.value = []
  }
}

function loadDefaultFilters() {
  if (!props.showCompanyFilter && !props.showDeptFilter) return
  const localUser = userInfo.value || {}
  if (props.showCompanyFilter && localUser.subCompanyId) {
    search.subCompanyId = String(localUser.subCompanyId)
    loadDeptOptions(search.subCompanyId)
  }
  if (props.showDeptFilter && localUser.deptId) {
    search.deptId = String(localUser.deptId)
    loadUserOptions(search.deptId)
  }
}

onMounted(async () => {
  if (props.showCompanyFilter) {
    await loadCompanyOptions()
  }
  loadDefaultFilters()
  loadData()
})

onActivated(() => {
  loadData()
})
</script>

<style scoped lang="scss">
.task-page {
  .frame-card {
    background: #fff;
    border-radius: 8px;
  }

  .frame-card-header {
    padding: 16px 20px 10px;
    border-bottom: 1px solid #f0f2f5;
  }

  .frame-card-content {
    padding: 0;
  }

  .frame-search {
    width: 100%;
  }

  .search-toolbar {
    display: flex;
    justify-content: space-between;
  }

  .search-line {
    display: flex;
    align-items: center;
    justify-content: space-between;

    :deep(.el-form-item) {
      margin-bottom: 0;
      margin-right: 12px;
    }

    :deep(.el-select) {
      width: 140px;
    }

    :deep(.el-date-editor) {
      width: 240px;
    }
  }

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

  .item3 {
    display: flex;
    justify-content: flex-end;
    margin-left: 16px;
  }

  .search-right {
    display: inline-flex;
    align-items: center;
    gap: 12px;
  }

  .table-area {
    background: #f8fafc;
    margin: 0;
    overflow: hidden;
  }

  .target_list {
    padding: 0 20px 20px;
  }

  .list-header,
  .card-row-main,
  .card-row-sub {
    display: grid;
    grid-template-columns: 32px minmax(320px, 2.4fr) 140px 180px 100px 180px 80px 120px;
    align-items: center;
    column-gap: 20px;
  }

  .list-header {
    height: 56px;
    color: #606266;
    font-weight: 600;
  }

  .name-col,
  .box-target-col,
  .content-target-col {
    display: flex;
    align-items: center;
    min-width: 0;
  }

  .name-col {
    grid-column: 1 / 3;
  }

  .icon-col {
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .icon-col-placeholder {
    visibility: hidden;
  }

  .card-content {
    min-height: 320px;
  }

  .card-box {
    margin-bottom: 12px;
    background: #fff;
    border: 1px solid #ebeef5;
    border-radius: 8px;
    overflow: hidden;
  }

  .card-row-main,
  .card-row-sub {
    min-height: 68px;
    padding: 0 16px;
  }

  .card-row-sub {
    border-top: 1px solid #f3f4f6;
    background: #fbfcfe;
  }

  .title {
    margin: 0;
    color: #303133;
    cursor: pointer;
    line-height: 20px;
    font-size: 14px;
  }

  .text-overflow .title {
    flex: 1;
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .task-label {
    display: inline-flex;
    align-items: center;
    height: 22px;
    margin-left: 8px;
    padding: 0 8px;
    font-size: 12px;
    color: #409eff;
    background: #ecf5ff;
    border-radius: 11px;
  }

  .task-tag {
    display: inline-flex;
    align-items: center;
    height: 22px;
    margin-left: 8px;
    padding: 0 8px;
    font-size: 12px;
    color: #606266;
    background: #f4f4f5;
    border-radius: 11px;
  }

  .person-col,
  .progress-col,
  .handle-col,
  .time-col {
    min-width: 0;
    color: #606266;
    font-size: 13px;
  }

  .person-col-flex {
    display: flex;
    align-items: center;
  }

  .person-name {
    margin-left: 8px;
    color: #606266;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .progress-click {
    cursor: pointer;
    display: flex;
    align-items: center;
  }

  :deep(.progress-col .el-progress) {
    width: 100%;
  }

  .time-col {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .overdue-text {
    color: #e71e19;
    font-size: 12px;
    margin-top: 2px;
  }

  .expand-icon {
    cursor: pointer;
    color: #909399;
    transition: transform 0.2s;
  }

  .expand-icon.is-close {
    transform: rotate(-90deg);
  }

  .handle-col-btn {
    display: flex;
    align-items: center;
    gap: 8px;
    justify-content: flex-start;
  }

  .img-btn {
    width: 28px;
    height: 28px;
    border: 0;
    border-radius: 50%;
    color: #fff;
    background: #409eff;
    cursor: pointer;
    font-size: 12px;
  }

  .look-btn {
    background: #67c23a;
  }

  .del-btn {
    background: #f56c6c;
  }

  .pager-wrap {
    display: flex;
    justify-content: flex-end;
    margin-top: 16px;
  }

  @media (max-width: 1280px) {
    .search-line {
      align-items: flex-start;
      flex-direction: column;
      gap: 12px;
    }

    .item3 {
      margin-left: 0;
      width: 100%;
      justify-content: flex-start;
    }

    .list-header,
    .card-row-main,
    .card-row-sub {
      grid-template-columns: 28px minmax(240px, 2fr) 120px 150px 88px 160px 72px 108px;
      column-gap: 12px;
    }
  }
}
</style>
