<template>
  <div v-loading="pageLoading" class="app-container dashboard">
    <!-- A. 欢迎区 -->
    <section class="welcome-banner">
      <div class="welcome-banner__main">
        <div class="welcome-banner__greet">
          <span class="welcome-banner__time">{{ greetingText }}，</span>
          <span class="welcome-banner__name">{{ displayName }}</span>
        </div>
        <p class="welcome-banner__meta">
          <span v-if="displayDept"><svg-icon icon-class="tree" class="meta-icon" />{{ displayDept }}</span>
          <span class="welcome-banner__date"><svg-icon icon-class="date" class="meta-icon" />{{ todayText }}</span>
        </p>
        <p class="welcome-banner__tip">{{ welcomeTip }}</p>
      </div>
      <div class="welcome-banner__actions">
        <el-button type="primary" plain icon="Refresh" @click="handleRefresh">刷新</el-button>
        <el-badge :value="unreadMessageCount" :hidden="unreadMessageCount === 0" :max="99">
          <el-button plain icon="Bell" @click="focusMessages">消息</el-button>
        </el-badge>
      </div>
    </section>

    <!-- B. 个人概览卡片 -->
    <section class="summary-row">
      <div
        v-for="card in summaryCards"
        :key="card.key"
        class="summary-card"
        :class="`summary-card--${card.theme}`"
        @click="onSummaryClick(card)"
      >
        <div class="summary-card__icon">
          <el-icon :size="22"><component :is="card.icon" /></el-icon>
        </div>
        <div class="summary-card__body">
          <div class="summary-card__value">{{ card.displayValue }}</div>
          <div class="summary-card__label">{{ card.label }}</div>
        </div>
      </div>
    </section>

    <el-row :gutter="16" class="dashboard-main">
      <!-- 左侧主栏 -->
      <el-col :xs="24" :lg="16">
        <!-- C. 我的待办 -->
        <el-card shadow="hover" class="block-card">
          <template #header>
            <div class="block-card__header">
              <span class="block-card__title">
                <el-icon><Tickets /></el-icon>
                我的待办
              </span>
              <el-link type="primary" :underline="false" @click="openMenu('workflow/task/taskWaiting')">查看全部</el-link>
            </div>
          </template>
          <div v-if="taskWaitList.length" class="task-list">
            <div
              v-for="item in taskWaitList"
              :key="item.id"
              class="task-list__item"
              @click="onTaskClick(item)"
            >
              <div class="task-list__title">{{ item.businessTitle }}</div>
              <div class="task-list__meta">
                <el-tag size="small" effect="plain">{{ item.flowName }}</el-tag>
                <span class="task-list__node">{{ item.nodeName }}</span>
                <span v-if="taskCreateByName(item)" class="task-list__user">发起人：{{ taskCreateByName(item) }}</span>
              </div>
              <div class="task-list__time">{{ item.createTime }}</div>
            </div>
          </div>
          <el-empty v-else description="暂无待办，辛苦了" :image-size="72" />
        </el-card>

        <!-- E. 我发起的流程 -->
        <el-card shadow="hover" class="block-card block-card--last">
          <template #header>
            <div class="block-card__header">
              <span class="block-card__title">
                <el-icon><Document /></el-icon>
                我发起的（进行中）
              </span>
              <el-link type="primary" :underline="false" @click="openMenu('workflow/task/myDocument')">查看全部</el-link>
            </div>
          </template>
          <el-table v-loading="processLoading" :data="myProcessList" stripe size="small" class="compact-table" @row-click="onProcessRowClick">
            <el-table-column prop="businessTitle" label="业务标题" min-width="160" show-overflow-tooltip />
            <el-table-column prop="flowName" label="流程" width="120" show-overflow-tooltip />
            <el-table-column prop="nodeName" label="当前节点" width="110" show-overflow-tooltip />
            <el-table-column prop="flowStatus" label="状态" width="90" align="center">
              <template #default="{ row }">
                <el-tag :type="row.statusType" size="small">{{ row.flowStatusLabel }}</el-tag>
              </template>
            </el-table-column>
            <el-table-column prop="createTime" label="发起时间" width="150" align="center" />
          </el-table>
        </el-card>
      </el-col>

      <!-- 右侧辅栏 -->
      <el-col :xs="24" :lg="8">
        <!-- D. 公告与消息 -->
        <el-card shadow="hover" class="block-card">
          <template #header>
            <div class="block-card__header">
              <span class="block-card__title">
                <el-icon><Message /></el-icon>
                公告与消息
              </span>
            </div>
          </template>
          <el-tabs v-model="noticeTab" class="notice-tabs" :class="{ 'notice-tabs--calendar': noticeTab === 'calendar' }">
            <el-tab-pane label="系统公告" name="notice">
              <ul v-if="noticeList.length" class="notice-feed">
                <li
                  v-for="n in noticeList"
                  :key="n.noticeId"
                  class="notice-feed__item"
                  @click="onNoticeClick(n)"
                >
                  <el-tag size="small" :type="n.tagType">{{ n.noticeTypeLabel }}</el-tag>
                  <span class="notice-feed__title">{{ n.noticeTitle }}</span>
                  <span class="notice-feed__time">{{ n.createTime }}</span>
                </li>
              </ul>
              <el-empty v-else description="暂无公告" :image-size="64" />
            </el-tab-pane>
            <el-tab-pane name="message">
              <template #label>
                <span>站内消息</span>
                <el-badge v-if="unreadMessageCount" :value="unreadMessageCount" class="tab-badge" />
              </template>
              <ul v-if="messageList.length" class="notice-feed">
                <li
                  v-for="(m, k) in messageList"
                  :key="k"
                  class="notice-feed__item"
                  :class="{ 'is-unread': !m.read }"
                  @click="onMessageClick(k)"
                >
                  <span v-if="!m.read" class="notice-feed__dot" />
                  <span class="notice-feed__title">{{ m.message }}</span>
                  <span class="notice-feed__time">{{ m.time }}</span>
                </li>
              </ul>
              <el-empty v-else description="暂无消息" :image-size="64" />
            </el-tab-pane>
            <el-tab-pane label="工作日历" name="calendar">
              <WorkCalendar
                ref="workCalendarRef"
                :active="noticeTab === 'calendar'"
                :pending-tasks="calendarPendingTasks"
                @task-click="onCalendarTaskClick"
              />
            </el-tab-pane>
          </el-tabs>
        </el-card>

        <!-- F. 快捷入口 -->
        <el-card shadow="hover" class="block-card block-card--last">
          <template #header>
            <div class="block-card__header">
              <span class="block-card__title">
                <el-icon><Grid /></el-icon>
                快捷入口
              </span>
            </div>
          </template>
          <div class="shortcut-grid">
            <div
              v-for="s in visibleShortcuts"
              :key="s.key"
              class="shortcut-grid__item"
              @click="onShortcutClick(s)"
            >
              <div class="shortcut-grid__icon" :style="{ background: s.bg }">
                <el-icon :size="20"><component :is="s.icon" /></el-icon>
              </div>
              <span class="shortcut-grid__label">{{ s.label }}</span>
            </div>
          </div>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>

<script setup name="Index" lang="ts">
import {
  Briefcase,
  Calendar,
  Document,
  EditPen,
  Grid,
  Message,
  Notebook,
  Reading,
  Tickets,
  Timer,
  User
} from '@element-plus/icons-vue';
import { pageByTaskWait, pageByTaskCopy } from '@/api/workflow/task';
import { FlowTaskVO } from '@/api/workflow/task/types';
import { pageByCurrent } from '@/api/workflow/instance';
import { FlowInstanceVO } from '@/api/workflow/instance/types';
import workflowCommon from '@/api/workflow/workflowCommon';
import { RouterJumpVo } from '@/api/workflow/workflowCommon/types';
import { listNotice } from '@/api/system/notice';
import { NoticeVO } from '@/api/system/notice/types';
import { getUserProfile } from '@/api/system/user';
import { listContractInfo } from '@/api/oa/erp/contractInfo';
import { listTimesheetInfo } from '@/api/oa/erp/timesheetInfo';
import { TimesheetInfoVO } from '@/api/oa/erp/timesheetInfo/types';
import { useUserStore } from '@/store/modules/user';
import { useNoticeStore } from '@/store/modules/notice';
import { resolveMenuPath } from '@/utils/resolveMenuPath';
import WorkCalendar from '@/components/WorkCalendar/index.vue';
import type { CalendarPendingTask } from '@/components/WorkCalendar/workCalendar.types';
import dayjs from 'dayjs';

const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const userStore = useUserStore();
const noticeStore = useNoticeStore();

const { wf_business_status, sys_notice_type, timesheet_status } = toRefs<any>(
  proxy?.useDict('wf_business_status', 'sys_notice_type', 'timesheet_status')
);

const RUNNING_FLOW_STATUS = ['waiting', 'back', 'draft'];

const pageLoading = ref(false);
const processLoading = ref(false);

const profileDept = ref('');

const summary = reactive({
  taskWaitCount: 0,
  taskCopyCount: 0,
  myProcessRunningCount: 0,
  timesheetWeekStatus: 'NOT_FILLED',
  timesheetWeekLabel: '未填报',
  contractCount: 0
});

const taskWaitList = ref<FlowTaskVO[]>([]);
const myProcessList = ref<
  {
    id: string | number;
    businessId: string;
    businessTitle: string;
    flowName: string;
    nodeName: string;
    flowStatus: string;
    flowStatusLabel: string;
    statusType: 'success' | 'warning' | 'info' | 'danger' | 'primary';
    createTime: string;
    formCustom: string;
    formPath: string;
  }[]
>([]);

const noticeList = ref<
  {
    noticeId: number;
    noticeTitle: string;
    noticeTypeLabel: string;
    tagType: 'success' | 'warning' | 'info' | 'danger' | 'primary';
    createTime: string;
  }[]
>([]);

const messageList = computed(() => noticeStore.state.notices);

const shortcutDefs = [
  { key: 'taskWait', label: '我的待办', icon: Tickets, bg: 'linear-gradient(135deg, #409eff 0%, #66b1ff 100%)', menuComponent: 'workflow/task/taskWaiting' },
  { key: 'myDoc', label: '我发起的', icon: Document, bg: 'linear-gradient(135deg, #67c23a 0%, #85ce61 100%)', menuComponent: 'workflow/task/myDocument' },
  { key: 'profile', label: '个人中心', icon: User, bg: 'linear-gradient(135deg, #909399 0%, #b1b3b8 100%)', menuComponent: 'user/profile' },
  { key: 'timesheet', label: '工时填报', icon: Timer, bg: 'linear-gradient(135deg, #e6a23c 0%, #ebb563 100%)', menuComponent: 'oa/erp/timesheetInfo/index' },
  { key: 'report', label: '项目周报', icon: EditPen, bg: 'linear-gradient(135deg, #f56c6c 0%, #f78989 100%)', menuComponent: 'oa/erp/projectReport/index' },
  { key: 'project', label: '项目信息', icon: Briefcase, bg: 'linear-gradient(135deg, #409eff 0%, #53a8ff 100%)', menuComponent: 'oa/erp/projectInfo/index' },
  { key: 'notice', label: '系统公告', icon: Reading, bg: 'linear-gradient(135deg, #00bcd4 0%, #26c6da 100%)', menuComponent: 'system/notice/index' }
];

const visibleShortcuts = computed(() =>
  shortcutDefs.filter((s) => resolveMenuPath(s.menuComponent) != null)
);

const noticeTab = ref('notice');
const workCalendarRef = ref<InstanceType<typeof WorkCalendar>>();

const calendarPendingTasks = computed<CalendarPendingTask[]>(() =>
  taskWaitList.value.map((t) => ({
    id: t.id,
    businessId: t.businessId,
    businessTitle: t.businessTitle || '—',
    createTime: t.createTime ? String(t.createTime) : undefined,
    flowName: t.flowName,
    formCustom: t.formCustom,
    formPath: t.formPath
  }))
);

const displayName = computed(() => userStore.nickname || '用户');
const displayDept = computed(() => {
  const user = profileDept.value;
  return user || '';
});

const weekDays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
const todayText = computed(() => {
  const d = dayjs();
  return `${d.format('YYYY年MM月DD日')} ${weekDays[d.day()]}`;
});

const greetingText = computed(() => {
  const h = dayjs().hour();
  if (h < 12) return '上午好';
  if (h < 18) return '下午好';
  return '晚上好';
});

const welcomeTip = computed(() => {
  const n = summary.taskWaitCount;
  if (n > 0) return `您有 ${n} 条待办待处理，建议优先处理今日到达的审批任务。`;
  return '今日暂无待办。';
});

const unreadMessageCount = computed(() => messageList.value.filter((m) => !m.read).length);

const summaryCards = computed(() => [
  {
    key: 'taskWait',
    label: '待我审批',
    displayValue: summary.taskWaitCount,
    theme: 'primary',
    icon: Tickets,
    menuComponent: 'workflow/task/taskWaiting'
  },
  {
    key: 'taskCopy',
    label: '抄送我的',
    displayValue: summary.taskCopyCount,
    theme: 'purple',
    icon: Message,
    menuComponent: 'workflow/task/taskCopyList'
  },
  {
    key: 'myProcess',
    label: '发起进行中',
    displayValue: summary.myProcessRunningCount,
    theme: 'success',
    icon: Document,
    menuComponent: 'workflow/task/myDocument'
  },
  {
    key: 'timesheet',
    label: '本周工时',
    displayValue: summary.timesheetWeekLabel,
    theme: summary.timesheetWeekStatus === 'NOT_FILLED' ? 'warning' : 'info',
    icon: Calendar,
    menuComponent: 'oa/erp/timesheetInfo/index'
  },
  {
    key: 'contract',
    label: '合同信息',
    displayValue: summary.contractCount,
    theme: 'cyan',
    icon: Notebook,
    menuComponent: 'oa/erp/contractInfo/index'
  }
]);

/** 自然周周一至周日 */
const getCurrentWeekRange = () => {
  const d = dayjs();
  const day = d.day();
  const mondayOffset = day === 0 ? -6 : 1 - day;
  const monday = d.add(mondayOffset, 'day');
  return {
    start: monday.format('YYYY-MM-DD'),
    end: monday.add(6, 'day').format('YYYY-MM-DD')
  };
};

const flowStatusLabel = (status: string) => {
  return proxy?.selectDictLabel(wf_business_status.value, status) || status || '—';
};

const flowStatusTagType = (status: string): 'success' | 'warning' | 'info' | 'danger' | 'primary' => {
  if (status === 'finish') return 'success';
  if (status === 'waiting') return 'warning';
  if (status === 'back' || status === 'cancel') return 'danger';
  if (status === 'draft') return 'info';
  return 'primary';
};

const openMenu = (menuComponent: string, query?: Record<string, unknown>) => {
  const path = resolveMenuPath(menuComponent);
  if (!path) {
    proxy?.$modal.msgWarning('未找到对应菜单路由，请确认已分配菜单权限');
    return;
  }
  proxy?.$tab.openPage(path, undefined, query);
};

const loadProfile = async () => {
  try {
    const res = await getUserProfile();
    const user = res.data?.user;
    if (user?.deptName) {
      profileDept.value = user.deptName;
    }
  } catch {
    /* 忽略 */
  }
};

const loadTaskWait = async () => {
  const res = await pageByTaskWait({ pageNum: 1, pageSize: 5 });
  taskWaitList.value = res.rows || [];
  summary.taskWaitCount = res.total ?? taskWaitList.value.length;
};

const loadTaskCopy = async () => {
  const res = await pageByTaskCopy({ pageNum: 1, pageSize: 1 });
  summary.taskCopyCount = res.total ?? 0;
};

const loadMyProcess = async () => {
  processLoading.value = true;
  try {
    const res = await pageByCurrent({ pageNum: 1, pageSize: 20 });
    const rows = (res.rows || []) as FlowInstanceVO[];
    const running = rows.filter((r) => RUNNING_FLOW_STATUS.includes(r.flowStatus));
    summary.myProcessRunningCount = running.length;
    myProcessList.value = running.slice(0, 5).map((row) => {
      const nodeName = row.flowTaskList?.[0]?.nodeName || row.flowStatusName || '—';
      return {
        id: row.id,
        businessId: row.businessId,
        businessTitle: row.businessTitle || '—',
        flowName: row.flowName || '—',
        nodeName,
        flowStatus: row.flowStatus,
        flowStatusLabel: flowStatusLabel(row.flowStatus),
        statusType: flowStatusTagType(row.flowStatus),
        createTime: row.createTime ? proxy.parseTime(row.createTime) : '—',
        formCustom: row.flowTaskList?.[0]?.formCustom ?? '',
        formPath: row.flowTaskList?.[0]?.formPath ?? ''
      };
    });
  } finally {
    processLoading.value = false;
  }
};

const resolveTimesheetWeek = async () => {
  const week = getCurrentWeekRange();
  const res = await listTimesheetInfo({
    pageNum: 1,
    pageSize: 1,
    userId: userStore.userId,
    startTime: week.start,
    endTime: week.end
  });
  const row = (res.rows?.[0] || null) as TimesheetInfoVO | null;
  if (!row) {
    summary.timesheetWeekStatus = 'NOT_FILLED';
    summary.timesheetWeekLabel = '未填报';
    return;
  }
  const status = row.timesheetStatus || '';
  summary.timesheetWeekStatus = status === '1' ? 'DRAFT' : status === '3' ? 'APPROVED' : status === '2' ? 'SUBMITTED' : status;
  summary.timesheetWeekLabel =
    proxy?.selectDictLabel(timesheet_status.value, status) ||
    (status === '1' ? '暂存' : status === '2' ? '审批中' : status === '3' ? '已审批' : '已填报');
};

const loadContractCount = async () => {
  try {
    const res = await listContractInfo({ pageNum: 1, pageSize: 1 });
    summary.contractCount = res.total ?? 0;
  } catch {
    summary.contractCount = 0;
  }
};

const loadNotices = async () => {
  const res = await listNotice({
    pageNum: 1,
    pageSize: 5,
    noticeTitle: '',
    createByName: '',
    status: '0',
    noticeType: ''
  });
  const rows = (res.rows || []) as NoticeVO[];
  noticeList.value = rows.map((n) => ({
    noticeId: n.noticeId,
    noticeTitle: n.noticeTitle,
    noticeTypeLabel: proxy?.selectDictLabel(sys_notice_type.value, n.noticeType) || '公告',
    tagType: (n.noticeType === '1' ? 'success' : 'info') as 'success' | 'info',
    createTime: n.createTime ? proxy.parseTime(n.createTime, '{y}-{m}-{d}') : ''
  }));
};

const loadDashboard = async () => {
  pageLoading.value = true;
  try {
    await Promise.allSettled([
      loadProfile(),
      loadTaskWait(),
      loadTaskCopy(),
      loadMyProcess(),
      resolveTimesheetWeek(),
      loadContractCount(),
      loadNotices()
    ]);
  } finally {
    pageLoading.value = false;
  }
};

const handleRefresh = () => {
  loadDashboard();
  if (noticeTab.value === 'calendar') {
    workCalendarRef.value?.reload();
  }
};

const focusMessages = () => {
  noticeTab.value = 'message';
};

const onMessageClick = (index: number) => {
  const notices = noticeStore.state.notices;
  if (notices[index] && !notices[index].read) {
    notices[index].read = true;
  }
};

const onSummaryClick = (card: { menuComponent?: string }) => {
  if (card.menuComponent) {
    openMenu(card.menuComponent);
  }
};

const taskCreateByName = (row: FlowTaskVO) => (row as FlowTaskVO & { createByName?: string }).createByName;

const onTaskClick = (row: FlowTaskVO) => {
  const routerJumpVo = reactive<RouterJumpVo>({
    businessId: row.businessId,
    taskId: row.id,
    type: 'approval',
    formCustom: row.formCustom,
    formPath: row.formPath
  });
  workflowCommon.routerJump(routerJumpVo, proxy);
};

const onProcessRowClick = (row: (typeof myProcessList.value)[0]) => {
  const routerJumpVo = reactive<RouterJumpVo>({
    businessId: row.businessId,
    taskId: row.id,
    type: 'view',
    formCustom: row.formCustom,
    formPath: row.formPath
  });
  workflowCommon.routerJump(routerJumpVo, proxy);
};

const onNoticeClick = (_n?: { noticeTitle?: string }) => {
  openMenu('system/notice/index');
};

const onShortcutClick = (s: { menuComponent: string }) => {
  openMenu(s.menuComponent);
};

const onCalendarTaskClick = (task: CalendarPendingTask) => {
  const routerJumpVo = reactive<RouterJumpVo>({
    businessId: task.businessId,
    taskId: task.id,
    type: 'approval',
    formCustom: task.formCustom,
    formPath: task.formPath
  });
  workflowCommon.routerJump(routerJumpVo, proxy);
};

onMounted(() => {
  loadDashboard();
});
</script>

<style lang="scss" scoped>
.dashboard {
  padding-bottom: 16px;
  background: var(--el-bg-color-page, #f0f2f5);
  min-height: calc(100vh - 84px);
}

/* A. 欢迎区 */
.welcome-banner {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 20px 24px;
  margin-bottom: 16px;
  border-radius: 8px;
  background: linear-gradient(to right, #0047ab 0%, #1e90ff 100%);
  color: #fff;
  box-shadow:
    0 4px 20px rgba(0, 71, 171, 0.22),
    0 1px 4px rgba(30, 144, 255, 0.12);

  &__main,
  &__actions {
    position: relative;
    z-index: 1;
  }

  &__greet {
    font-size: 22px;
    font-weight: 600;
    line-height: 1.4;
  }

  &__name {
    margin-left: 4px;
  }

  &__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    margin: 8px 0 0;
    font-size: 13px;
    opacity: 0.92;

    .meta-icon {
      margin-right: 4px;
    }
  }

  &__date {
    display: inline-flex;
    align-items: center;
  }

  &__tip {
    margin: 10px 0 0;
    font-size: 13px;
    opacity: 0.88;
    max-width: 560px;
  }

  &__actions {
    display: flex;
    align-items: center;
    gap: 10px;

    :deep(.el-button) {
      --el-button-bg-color: rgba(255, 255, 255, 0.15);
      --el-button-border-color: rgba(255, 255, 255, 0.5);
      --el-button-hover-bg-color: rgba(255, 255, 255, 0.28);
      --el-button-text-color: #fff;
    }
  }
}

/* B. 概览卡片 */
.summary-row {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 12px;
  margin-bottom: 16px;

  @media (max-width: 1200px) {
    grid-template-columns: repeat(3, 1fr);
  }

  @media (max-width: 768px) {
    grid-template-columns: repeat(2, 1fr);
  }
}

.summary-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  background: var(--el-bg-color);
  border-radius: 8px;
  border: 1px solid var(--el-border-color-lighter);
  cursor: pointer;
  transition: transform 0.2s, box-shadow 0.2s;

  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.06);
  }

  &__icon {
    width: 44px;
    height: 44px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
  }

  &__value {
    font-size: 22px;
    font-weight: 700;
    line-height: 1.2;
    color: var(--el-text-color-primary);
  }

  &__label {
    font-size: 12px;
    color: var(--el-text-color-secondary);
    margin-top: 2px;
  }

  &--primary .summary-card__icon {
    background: linear-gradient(135deg, #409eff, #66b1ff);
  }
  &--purple .summary-card__icon {
    background: linear-gradient(135deg, #9b59b6, #b07cc6);
  }
  &--success .summary-card__icon {
    background: linear-gradient(135deg, #67c23a, #85ce61);
  }
  &--warning .summary-card__icon {
    background: linear-gradient(135deg, #e6a23c, #ebb563);
  }
  &--info .summary-card__icon {
    background: linear-gradient(135deg, #909399, #b1b3b8);
  }
  &--cyan .summary-card__icon {
    background: linear-gradient(135deg, #00bcd4, #26c6da);
  }
}

.dashboard-main {
  align-items: flex-start;
}

.block-card {
  margin-bottom: 16px;

  &--last {
    margin-bottom: 0;
  }

  &__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
  }

  &__title {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-weight: 600;
    font-size: 15px;
  }
}

/* C. 待办列表 */
.task-list {
  &__item {
    padding: 12px 0;
    border-bottom: 1px dashed var(--el-border-color-lighter);
    cursor: pointer;
    transition: background 0.15s;

    &:last-child {
      border-bottom: none;
      padding-bottom: 0;
    }

    &:first-child {
      padding-top: 0;
    }

    &:hover {
      background: var(--el-fill-color-light);
      margin: 0 -12px;
      padding-left: 12px;
      padding-right: 12px;
      border-radius: 6px;
    }
  }

  &__title {
    font-size: 14px;
    font-weight: 500;
    color: var(--el-text-color-primary);
    margin-bottom: 6px;
  }

  &__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    color: var(--el-text-color-secondary);
  }

  &__node::before {
    content: '·';
    margin-right: 4px;
    color: var(--el-text-color-placeholder);
  }

  &__time {
    font-size: 12px;
    color: var(--el-text-color-placeholder);
    margin-top: 6px;
  }
}

.compact-table {
  :deep(.el-table__row) {
    cursor: pointer;
  }
}

/* D. 公告 */
.notice-tabs {
  :deep(.el-tabs__header) {
    margin-bottom: 8px;
  }

  :deep(.el-tabs__item) {
    font-size: 13px;
    padding: 0 14px;
  }

  :deep(.el-tab-pane) {
    min-height: 0;
  }
}

.notice-tabs--calendar {
  :deep(.el-tabs__content) {
    overflow: visible;
  }

  :deep(.el-card__body) {
    padding-bottom: 12px;
  }
}

.tab-badge {
  margin-left: 6px;
  vertical-align: middle;
}

.notice-feed {
  list-style: none;
  margin: 0;
  padding: 0;

  &__item {
    position: relative;
    padding: 10px 0 10px 0;
    border-bottom: 1px solid var(--el-border-color-extra-light);
    cursor: pointer;

    &:last-child {
      border-bottom: none;
    }

    &:hover .notice-feed__title {
      color: var(--el-color-primary);
    }

    &.is-unread {
      padding-left: 12px;
    }
  }

  &__dot {
    position: absolute;
    left: 0;
    top: 14px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--el-color-danger);
  }

  &__title {
    display: block;
    font-size: 13px;
    line-height: 1.5;
    color: var(--el-text-color-primary);
    margin-top: 4px;
    transition: color 0.15s;
  }

  &__time {
    display: block;
    font-size: 12px;
    color: var(--el-text-color-placeholder);
    margin-top: 4px;
  }
}

/* F. 快捷入口 */
.shortcut-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 16px 12px;

  @media (max-width: 1200px) {
    grid-template-columns: repeat(3, 1fr);
  }

  &__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    transition: transform 0.15s;

    &:hover {
      transform: scale(1.05);

      .shortcut-grid__label {
        color: var(--el-color-primary);
      }
    }
  }

  &__icon {
    width: 48px;
    height: 48px;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.12);
  }

  &__label {
    font-size: 12px;
    color: var(--el-text-color-regular);
    text-align: center;
    line-height: 1.3;
  }
}
</style>
