<template>
  <div class="dispatch-layout">

    <!-- ══════════════ 左栏：项目列表 ══════════════ -->
    <div class="panel-left">
      <div class="left-header">
        <span class="left-title">项目列表</span>
        <span class="left-count">{{ projectList.length }} 个</span>
      </div>
      <div class="left-search">
        <el-input v-model="searchText" placeholder="编号 / 代号 / 名称" prefix-icon="el-icon-search" size="small" clearable @input="filterProjects" />
      </div>
      <div class="left-list" v-loading="projectLoading">
        <div
          v-for="p in filteredList"
          :key="p.projectId"
          class="project-item"
          :class="{ 'is-active': activeProject && activeProject.projectId === p.projectId }"
          @click="selectProject(p)"
        >
          <div class="pi-top">
            <span class="pi-name" :title="p.projectName">{{ p.projectName }}</span>
            <span class="pi-status" :class="statusClass(p.projectStatus)">{{ statusLabel(p.projectStatus) }}</span>
          </div>
          <div class="pi-row">
            <span class="pi-tag" v-if="p.projectNum">{{ p.projectNum }}</span>
            <span class="pi-tag accent" v-if="p.projectCode">{{ p.projectCode }}</span>
          </div>
          <div class="pi-row">
            <i class="el-icon-user" style="color:#c0c4cc;font-size:11px;margin-right:3px" />
            <span class="pi-sub">{{ p.functionary || '—' }}</span>
            <span class="pi-sub" style="margin-left:auto" v-if="p.beginTime">{{ parseTime(p.beginTime, '{y}-{m}-{d}') }}</span>
          </div>
        </div>
        <div v-if="!projectLoading && filteredList.length === 0" class="left-empty">暂无项目</div>
      </div>
    </div>

    <!-- ══════════════ 中栏：模块 Tab ══════════════ -->
    <div class="panel-mid" v-if="activeProject">
      <div
        v-for="m in MODULES"
        :key="m.key"
        class="mod-tab"
        :class="{ 'mod-active': activeTab === m.key }"
        @click="switchTab(m.key)"
      >
        <i :class="m.icon" class="mod-icon" />
        <span class="mod-label">{{ m.label }}</span>
        <span v-if="badgeCounts[m.key] > 0" class="mod-badge">{{ badgeCounts[m.key] }}</span>
        <span v-else-if="badgeCounts[m.key] === 0" class="mod-badge mod-badge-zero">0</span>
      </div>
    </div>

    <!-- ══════════════ 右栏：内容区 ══════════════ -->
    <div class="panel-right" v-if="activeProject" v-loading="moduleLoading[activeTab]">

      <!-- ── 当前项目固定头 ── -->
      <div class="project-header-bar">
        <i class="el-icon-office-building project-header-icon" />
        <span class="project-header-name">{{ activeProject.projectName }}</span>
        <span v-if="activeProject.projectNum" class="project-header-tag">{{ activeProject.projectNum }}</span>
        <span v-if="activeProject.projectCode" class="project-header-tag accent">{{ activeProject.projectCode }}</span>
        <span class="project-header-status" :class="statusClass(activeProject.projectStatus)">{{ statusLabel(activeProject.projectStatus) }}</span>
        <span v-if="activeProject.functionary" class="project-header-sub"><i class="el-icon-user" /> {{ activeProject.functionary }}</span>
      </div>

      <!-- ── 内容滚动区 ── -->
      <div class="panel-right-body">

      <!-- ── 基本信息 ── -->
      <template v-if="activeTab === 'info'">
        <div class="section-title">基本信息</div>
        <el-descriptions :column="3" border size="small">
          <el-descriptions-item label="项目名称" :span="2">{{ activeProject.projectName }}</el-descriptions-item>
          <el-descriptions-item label="项目状态">
            <span :class="'status-dot ' + statusClass(activeProject.projectStatus)">{{ statusLabel(activeProject.projectStatus) }}</span>
          </el-descriptions-item>
          <el-descriptions-item label="项目编号">{{ activeProject.projectNum || '—' }}</el-descriptions-item>
          <el-descriptions-item label="项目代号">{{ activeProject.projectCode || '—' }}</el-descriptions-item>
          <el-descriptions-item label="项目类型">{{ activeProject.projectType || '—' }}</el-descriptions-item>
          <el-descriptions-item label="负责人">{{ activeProject.functionary || '—' }}</el-descriptions-item>
          <el-descriptions-item label="开始时间">{{ parseTime(activeProject.beginTime, '{y}-{m}-{d}') || '—' }}</el-descriptions-item>
          <el-descriptions-item label="计划完成">{{ parseTime(activeProject.finishTime, '{y}-{m}-{d}') || '—' }}</el-descriptions-item>
          <el-descriptions-item label="项目地址" :span="2">{{ activeProject.address || '—' }}</el-descriptions-item>
          <el-descriptions-item label="项目资金">{{ activeProject.funds ? activeProject.funds + ' 元' : '—' }}</el-descriptions-item>
          <el-descriptions-item label="交付说明" :span="3">{{ activeProject.delivery || '—' }}</el-descriptions-item>
          <el-descriptions-item label="项目简介" :span="3">{{ activeProject.introduction || '—' }}</el-descriptions-item>
        </el-descriptions>
        <!-- 快速统计 -->
        <div class="section-title" style="margin-top:20px">关联统计</div>
        <el-row :gutter="12">
          <el-col v-for="m in MODULES.filter(x => x.key !== 'info')" :key="m.key" :span="4">
            <div class="stat-mini" @click="switchTab(m.key)">
              <i :class="m.icon" class="stat-mini-icon" />
              <div class="stat-mini-num">{{ badgeCounts[m.key] !== undefined ? badgeCounts[m.key] : '—' }}</div>
              <div class="stat-mini-label">{{ m.label }}</div>
            </div>
          </el-col>
        </el-row>
      </template>

      <!-- ── 合同 ── -->
      <template v-else-if="activeTab === 'contract'">
        <div class="section-title">合同记录</div>
        <el-table :data="moduleData.contract" size="small" border stripe>
          <el-table-column label="合同编号" prop="contractNum" width="140" />
          <el-table-column label="合同名称" prop="contractName" min-width="160" show-overflow-tooltip />
          <el-table-column label="合同金额(元)" prop="contractPrice" width="120" align="right">
            <template slot-scope="{ row }"><span class="money">{{ row.contractPrice }}</span></template>
          </el-table-column>
          <el-table-column label="签订时间" prop="signTime" width="110">
            <template slot-scope="{ row }">{{ parseTime(row.signTime, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="有效期" prop="validity" width="110" />
          <el-table-column label="合同类型" prop="contractType" width="90" align="center" />
          <el-table-column label="状态" prop="contractStatus" width="80" align="center" />
          <el-table-column label="甲方单位" prop="firstName" width="120" show-overflow-tooltip />
          <el-table-column label="甲方负责人" prop="firstPerson" width="90" align="center" />
          <el-table-column label="甲方电话" prop="firstPhone" width="120" />
          <el-table-column label="乙方单位" prop="secondName" width="120" show-overflow-tooltip />
          <el-table-column label="乙方负责人" prop="secondPerson" width="90" align="center" />
          <el-table-column label="乙方电话" prop="secondPhone" width="120" />
          <el-table-column label="创建人" prop="createBy" width="80" align="center" />
          <el-table-column label="创建时间" prop="createTime" width="110">
            <template slot-scope="{ row }">{{ parseTime(row.createTime, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="附件" width="80" align="center" fixed="right">
            <template slot-scope="{ row }">
              <el-button v-if="row.accessory" type="text" size="mini" icon="el-icon-download" @click="$download.oss(row.accessory)">下载</el-button>
              <span v-else style="color:#c0c4cc">无</span>
            </template>
          </el-table-column>
        </el-table>
      </template>

      <!-- ── 收付款记录 ── -->
      <template v-else-if="activeTab === 'finance'">
        <div class="section-title">收付款记录</div>
        <el-table :data="moduleData.finance" size="small" border stripe>
          <el-table-column label="账务名称" prop="financeTitle" min-width="150" show-overflow-tooltip />
          <el-table-column label="收/付款类型" width="90" align="center">
            <template slot-scope="{ row }">
              <span :style="{ color: String(row.financeType) === '0' ? '#67C23A' : '#F56C6C' }">
                {{ String(row.financeType) === '0' ? '收款' : String(row.financeType) === '1' ? '付款' : row.financeType || '—' }}
              </span>
            </template>
          </el-table-column>
          <el-table-column label="付款方式" width="100" align="center">
            <template slot-scope="{ row }">{{ payTypeLabel(row.payType) }}</template>
          </el-table-column>
          <el-table-column label="付款金额(元)" width="120" align="right">
            <template slot-scope="{ row }"><span class="money">{{ sumDetailPrice(row) }}</span></template>
          </el-table-column>
          <el-table-column label="开票比例" prop="makeRatio" width="90" align="center" />
          <el-table-column label="交易时间" prop="financeTime" width="110">
            <template slot-scope="{ row }">{{ parseTime(row.financeTime, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="经手人/付款方" prop="financeParties" width="120" show-overflow-tooltip />
          <el-table-column label="收款账户" prop="receiveAccountName" width="120" show-overflow-tooltip />
          <el-table-column label="签约公司" prop="signingCompany" width="120" show-overflow-tooltip />
          <el-table-column label="状态" width="80" align="center">
            <template slot-scope="{ row }">
              <span :style="{ color: row.status === 1 ? '#67C23A' : '#E6A23C' }">{{ row.status === 1 ? '已完成' : '待处理' }}</span>
            </template>
          </el-table-column>
          <el-table-column label="备注" prop="remark" min-width="120" show-overflow-tooltip />
        </el-table>
      </template>

      <!-- ── 回款计划 ── -->
      <template v-else-if="activeTab === 'payment'">
        <div class="section-title">回款计划</div>
        <el-table :data="moduleData.payment" size="small" border stripe>
          <el-table-column label="计划开始" prop="startTime" width="110">
            <template slot-scope="{ row }">{{ parseTime(row.startTime, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="计划结束" prop="endTime" width="110">
            <template slot-scope="{ row }">{{ parseTime(row.endTime, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="最早结束时间" prop="earliestEndTime" width="120">
            <template slot-scope="{ row }">{{ parseTime(row.earliestEndTime, '{y}-{m}-{d}') || '—' }}</template>
          </el-table-column>
          <el-table-column label="金额(元)" prop="amount" width="120" align="right">
            <template slot-scope="{ row }"><span class="money">{{ row.amount }}</span></template>
          </el-table-column>
          <el-table-column label="完成状态" width="90" align="center">
            <template slot-scope="{ row }">
              <span :style="{ color: row.complete === 1 ? '#67C23A' : '#E6A23C' }">{{ row.complete === 1 ? '已完成' : '待回款' }}</span>
            </template>
          </el-table-column>
          <el-table-column label="完成资格" width="90" align="center">
            <template slot-scope="{ row }">
              <span :style="{ color: row.qualified === 1 ? '#67C23A' : '#909399' }">{{ row.qualified === 1 ? '已具备' : '未具备' }}</span>
            </template>
          </el-table-column>
          <el-table-column label="是否作废" width="80" align="center">
            <template slot-scope="{ row }">
              <span :style="{ color: row.isVoid === 1 ? '#F56C6C' : '#67C23A' }">{{ row.isVoid === 1 ? '已作废' : '有效' }}</span>
            </template>
          </el-table-column>
          <el-table-column label="备注" prop="remark" min-width="160" show-overflow-tooltip />
        </el-table>
      </template>

      <!-- ── 成本 ── -->
      <template v-else-if="activeTab === 'cost'">
        <div class="section-title">成本明细</div>
        <el-table :data="moduleData.cost" size="small" border stripe>
          <el-table-column label="成本类型" width="100" align="center">
            <template slot-scope="{ row }">{{ costTypeLabel(row.costType) }}</template>
          </el-table-column>
          <el-table-column label="金额(元)" prop="cost" width="130" align="right">
            <template slot-scope="{ row }"><span class="money">{{ row.cost }}</span></template>
          </el-table-column>
          <el-table-column label="备注" prop="remark" min-width="200" show-overflow-tooltip />
        </el-table>
      </template>

      <!-- ── 报销 ── -->
      <template v-else-if="activeTab === 'claim'">
        <div class="section-title">报销记录</div>
        <el-table :data="moduleData.claim" size="small" border stripe>
          <el-table-column label="出发时间" prop="startTime" width="110">
            <template slot-scope="{ row }">{{ parseTime(row.startTime, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="返回时间" prop="endTime" width="110">
            <template slot-scope="{ row }">{{ parseTime(row.endTime, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="天数" prop="tripDays" width="60" align="center" />
          <el-table-column label="报销金额(元)" prop="cost" width="120" align="right">
            <template slot-scope="{ row }"><span class="money">{{ row.cost }}</span></template>
          </el-table-column>
          <el-table-column label="目的地" prop="address" min-width="120" show-overflow-tooltip />
          <el-table-column label="票据数" prop="detailNumber" width="70" align="center" />
          <el-table-column label="审批状态" width="90" align="center">
            <template slot-scope="{ row }">
              <span :style="{ color: row.status === 1 ? '#67C23A' : row.status === 2 ? '#F56C6C' : '#E6A23C' }">
                {{ row.status === 1 ? '已通过' : row.status === 2 ? '已驳回' : '审批中' }}
              </span>
            </template>
          </el-table-column>
          <el-table-column label="完成时间" prop="completedTime" width="110">
            <template slot-scope="{ row }">{{ parseTime(row.completedTime, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="备注" prop="remark" min-width="120" show-overflow-tooltip />
        </el-table>
      </template>

      <!-- ── 奖金分配 ── -->
      <template v-else-if="activeTab === 'bonus'">
        <div class="section-title">奖金池分配</div>
        <el-table :data="moduleData.bonus" size="small" border stripe>
          <el-table-column label="奖金池ID" prop="poolId" width="100" align="center" />
          <el-table-column label="分配金额" prop="allocatedAmount" width="130" align="right">
            <template slot-scope="{ row }"><span class="money">{{ row.allocatedAmount }}</span></template>
          </el-table-column>
          <el-table-column label="备注" prop="remark" min-width="200" show-overflow-tooltip />
          <el-table-column label="创建时间" prop="createTime" width="150">
            <template slot-scope="{ row }">{{ parseTime(row.createTime, '{y}-{m}-{d}') }}</template>
          </el-table-column>
        </el-table>
      </template>

      <!-- ── 项目进度 ── -->
      <template v-else-if="activeTab === 'progress'">
        <div class="section-title">项目进度</div>
        <div class="progress-tree">
          <div v-if="!moduleData.progress || moduleData.progress.length === 0" class="empty-tip">暂无进度数据</div>
          <template v-for="top in progressTree">
            <div :key="'t-' + top.progressId" class="pt-group">
              <div class="pt-top">
                <i class="el-icon-folder" style="color:#409EFF;margin-right:6px" />
                <span class="pt-top-name">{{ top.progressName }}</span>
                <span class="pt-status" :class="'ps-' + top.status">{{ progressStatusLabel(top.status) }}</span>
              </div>
              <div v-for="sub in top.children" :key="'s-' + sub.progressId" class="pt-sub">
                <i class="el-icon-caret-right" style="color:#909399;margin-right:4px;font-size:11px" />
                <span class="pt-sub-name">{{ sub.progressName }}</span>
                <span class="pt-status" :class="'ps-' + sub.status">{{ progressStatusLabel(sub.status) }}</span>
                <span v-if="sub.amount" class="pt-amount">¥{{ sub.amount }}</span>
                <span v-if="sub.timeRemark" class="pt-time-remark">{{ sub.timeRemark }}</span>
                <!-- leaf tasks -->
                <div v-for="leaf in sub.children" :key="'l-' + leaf.progressId" class="pt-leaf">
                  <i class="el-icon-document" style="color:#c0c4cc;margin-right:4px;font-size:11px" />
                  <span>{{ leaf.progressName }}</span>
                  <span class="pt-status" :class="'ps-' + leaf.status">{{ progressStatusLabel(leaf.status) }}</span>
                  <span v-if="leaf.amount" class="pt-amount">¥{{ leaf.amount }}</span>
                </div>
              </div>
            </div>
          </template>
        </div>
      </template>

      <!-- ── 任务 ── -->
      <template v-else-if="activeTab === 'task'">
        <div class="section-title">任务列表</div>
        <el-table :data="moduleData.task" size="small" border stripe>
          <el-table-column label="任务标题" prop="taskTitle" min-width="160" show-overflow-tooltip />
          <el-table-column label="工作类型" width="100" align="center">
            <template slot-scope="{ row }">{{ workTypeLabel(row.taskType) }}</template>
          </el-table-column>
          <el-table-column label="优先级" width="70" align="center">
            <template slot-scope="{ row }">
              <span :style="{ color: String(row.taskGrade) === '2' ? '#F56C6C' : String(row.taskGrade) === '1' ? '#E6A23C' : '#909399' }">
                {{ String(row.taskGrade) === '2' ? '紧急' : String(row.taskGrade) === '1' ? '中等' : '一般' }}
              </span>
            </template>
          </el-table-column>
          <el-table-column label="状态" width="80" align="center">
            <template slot-scope="{ row }">
              <span :style="{ color: Number(row.state) === 2 ? '#67C23A' : Number(row.state) === 1 ? '#E6A23C' : '#409EFF' }">
                {{ Number(row.state) === 2 ? '已完成' : Number(row.state) === 1 ? '待验收' : '进行中' }}
              </span>
            </template>
          </el-table-column>
          <el-table-column label="执行人" prop="workerNickName" width="80" align="center" />
          <el-table-column label="协作人员" prop="collaborator" width="100" show-overflow-tooltip />
          <el-table-column label="部门" prop="deptName" width="100" show-overflow-tooltip />
          <el-table-column label="开始" prop="beginTime" width="100">
            <template slot-scope="{ row }">{{ parseTime(row.beginTime, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="截止" prop="finishTime" width="100">
            <template slot-scope="{ row }">{{ parseTime(row.finishTime, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="完成时间" prop="completedTime" width="100">
            <template slot-scope="{ row }">{{ parseTime(row.completedTime, '{y}-{m}-{d}') || '—' }}</template>
          </el-table-column>
          <el-table-column label="逾期天数" prop="overDays" width="80" align="center">
            <template slot-scope="{ row }">
              <span v-if="row.overDays > 0" style="color:#F56C6C">{{ row.overDays }}天</span>
              <span v-else style="color:#67C23A">—</span>
            </template>
          </el-table-column>
          <el-table-column label="延期次数" prop="postponements" width="80" align="center" />
          <el-table-column label="发起人" prop="createUserNickName" width="80" align="center" />
        </el-table>
      </template>

      <!-- ── 采购需求 ── -->
      <template v-else-if="activeTab === 'require'">
        <div class="section-title">采购需求</div>
        <el-table :data="moduleData.require" size="small" border stripe>
          <el-table-column label="标题" prop="title" min-width="160" show-overflow-tooltip />
          <el-table-column label="需求描述" prop="description" min-width="160" show-overflow-tooltip />
          <el-table-column label="需求方" prop="requesterNickName" width="90" align="center" />
          <el-table-column label="负责人" prop="ownerNickName" width="90" align="center" />
          <el-table-column label="状态" width="90" align="center">
            <template slot-scope="{ row }">
              <span :style="{ color: row.status === 2 ? '#67C23A' : row.status === 1 ? '#409EFF' : '#E6A23C' }">
                {{ row.status === 2 ? '已完成' : row.status === 1 ? '进行中' : '待处理' }}
              </span>
            </template>
          </el-table-column>
          <el-table-column label="截止日期" prop="deadline" width="110">
            <template slot-scope="{ row }">{{ parseTime(row.deadline, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="所属项目" prop="projectName" min-width="140" show-overflow-tooltip />
          <el-table-column label="创建人" prop="createBy" width="90" align="center" />
          <el-table-column label="创建时间" prop="createTime" width="110">
            <template slot-scope="{ row }">{{ parseTime(row.createTime, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="最后更新人" prop="updateBy" width="90" align="center" />
          <el-table-column label="更新时间" prop="updateTime" width="110">
            <template slot-scope="{ row }">{{ parseTime(row.updateTime, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="备注" prop="remark" min-width="120" show-overflow-tooltip />
        </el-table>
      </template>

      <!-- ── 发货单 ── -->
      <template v-else-if="activeTab === 'delivery'">
        <div class="section-title">发货单</div>
        <el-table :data="moduleData.delivery" size="small" border stripe>
          <el-table-column label="发货单号" prop="deliveryOrderNo" width="200" show-overflow-tooltip />
          <el-table-column label="状态" width="80" align="center">
            <template slot-scope="{ row }">
              <span :style="{ color: row.status === 1 ? '#67C23A' : '#E6A23C' }">{{ row.status === 1 ? '已完成' : '进行中' }}</span>
            </template>
          </el-table-column>
          <el-table-column label="合同号" prop="contractNo" width="110" show-overflow-tooltip />
          <el-table-column label="用户合同号" prop="userContractNo" width="120" show-overflow-tooltip />
          <el-table-column label="采购合同号" prop="procurementNo" width="120" show-overflow-tooltip />
          <el-table-column label="送达目的地" prop="deliveryDestination" min-width="120" show-overflow-tooltip />
          <el-table-column label="送货地址" prop="deliveryAddress" min-width="120" show-overflow-tooltip />
          <el-table-column label="收货单位" prop="receivingCompany" min-width="120" show-overflow-tooltip />
          <el-table-column label="收货人" prop="receiver" width="90" align="center" />
          <el-table-column label="实际收货人" prop="actualReceiver" width="90" align="center" />
          <el-table-column label="收货电话" prop="receiverPhone" width="120" />
          <el-table-column label="供应商" prop="supplierFullname" min-width="120" show-overflow-tooltip />
          <el-table-column label="供应商联系人" prop="supplierContact" width="100" align="center" />
          <el-table-column label="供应商电话" prop="supplierPhone" width="120" />
          <el-table-column label="施工单位" prop="constructionCompany" min-width="120" show-overflow-tooltip />
          <el-table-column label="送货备注" prop="deliveryRemark" min-width="120" show-overflow-tooltip />
          <el-table-column label="备注" prop="remark" min-width="120" show-overflow-tooltip />
          <el-table-column label="附件" width="80" align="center" fixed="right">
            <template slot-scope="{ row }">
              <el-button v-if="row.accessory" type="text" size="mini" icon="el-icon-download" @click="$download.oss(row.accessory)">下载</el-button>
              <span v-else style="color:#c0c4cc">无</span>
            </template>
          </el-table-column>
        </el-table>
      </template>

      <!-- ── 快递 ── -->
      <template v-else-if="activeTab === 'express'">
        <div class="section-title">快递记录</div>
        <el-table :data="moduleData.express" size="small" border stripe>
          <el-table-column label="快递单号" prop="expressCode" width="160" />
          <el-table-column label="快递类型" prop="expressType" width="90" align="center" />
          <el-table-column label="状态" width="90" align="center">
            <template slot-scope="{ row }">
              <span :style="{ color: row.status === 2 ? '#67C23A' : row.status === 1 ? '#409EFF' : '#909399' }">{{ expressStatusLabel(row.status) }}</span>
            </template>
          </el-table-column>
          <el-table-column label="供应商" prop="supplyName" width="120" show-overflow-tooltip />
          <el-table-column label="供应商电话" prop="supplyPhone" width="120" />
          <el-table-column label="负责人" prop="ownerName" width="90" align="center" />
          <el-table-column label="负责人电话" prop="ownerPhone" width="120" />
          <el-table-column label="计划到货" prop="planDate" width="110">
            <template slot-scope="{ row }">{{ parseTime(row.planDate, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="接收时间" prop="acceptTime" width="110">
            <template slot-scope="{ row }">{{ parseTime(row.acceptTime, '{y}-{m}-{d}') || '—' }}</template>
          </el-table-column>
          <el-table-column label="物流状态" prop="firstStatusName" width="100" show-overflow-tooltip />
          <el-table-column label="当前节点" prop="lastStatus" min-width="140" show-overflow-tooltip />
          <el-table-column label="关联发货记录" prop="detailName" min-width="120" show-overflow-tooltip />
          <el-table-column label="备注" prop="remark" min-width="120" show-overflow-tooltip />
        </el-table>
      </template>

      <!-- ── 流程卡 ── -->
      <template v-else-if="activeTab === 'processCard'">
        <div class="section-title">制造流程卡</div>
        <el-table :data="moduleData.processCard" size="small" border stripe>
          <el-table-column label="设备名称" prop="equipmentName" min-width="160" show-overflow-tooltip />
          <el-table-column label="数量" prop="equipmentQuantity" width="70" align="center" />
          <el-table-column label="制造负责人" prop="manufacturingLeader" width="110" align="center" />
          <el-table-column label="运营负责人" prop="operationLeader" width="110" align="center" />
          <el-table-column label="计划交货日期" prop="plannedDeliveryDate" width="120">
            <template slot-scope="{ row }">{{ parseTime(row.plannedDeliveryDate, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="备注" prop="remark" min-width="160" show-overflow-tooltip />
        </el-table>
      </template>

      <!-- ── 工作报告 ── -->
      <template v-else-if="activeTab === 'report'">
        <div class="section-title">工作报告</div>
        <el-table :data="moduleData.report" size="small" border stripe>
          <el-table-column label="报工人" prop="nickName" width="90" align="center" />
          <el-table-column label="部门" prop="deptName" width="100" show-overflow-tooltip />
          <el-table-column label="工作地点" prop="workPlace" width="120" show-overflow-tooltip />
          <el-table-column label="国内/国外" width="90" align="center">
            <template slot-scope="{ row }">{{ row.workTypeName || (row.workType === 0 ? '国内' : row.workType === 1 ? '国外' : '—') }}</template>
          </el-table-column>
          <el-table-column label="是否出差" width="80" align="center">
            <template slot-scope="{ row }">
              <span :style="{ color: row.isTrip === 1 ? '#E6A23C' : '#909399' }">{{ row.isTrip === 1 ? '出差' : '未出差' }}</span>
            </template>
          </el-table-column>
          <el-table-column label="国内工时" prop="inWorkNum" width="80" align="center" />
          <el-table-column label="国外工时" prop="outWorkNum" width="80" align="center" />
          <el-table-column label="报工内容" prop="content" min-width="200" show-overflow-tooltip>
            <template slot-scope="{ row }"><span v-html="row.content" class="html-preview" /></template>
          </el-table-column>
          <el-table-column label="报工时间" prop="createTime" width="150">
            <template slot-scope="{ row }">{{ parseTime(row.createTime, '{y}-{m}-{d} {h}:{i}') }}</template>
          </el-table-column>
        </el-table>
      </template>

      <!-- ── 汇报摘要 ── -->
      <template v-else-if="activeTab === 'summary'">
        <div class="section-title">汇报摘要</div>
        <el-table :data="moduleData.summary" size="small" border stripe>
          <el-table-column label="汇报标题" prop="reportTitle" min-width="160" show-overflow-tooltip />
          <el-table-column label="汇报日期" prop="reportDate" width="110">
            <template slot-scope="{ row }">{{ parseTime(row.reportDate, '{y}-{m}-{d}') }}</template>
          </el-table-column>
          <el-table-column label="汇报人" prop="reporter" width="90" align="center" />
          <el-table-column label="状态" width="80" align="center">
            <template slot-scope="{ row }">
              <span :style="{ color: row.status === 1 ? '#67C23A' : '#409EFF' }">{{ row.status === 1 ? '已完成' : '进行中' }}</span>
            </template>
          </el-table-column>
          <el-table-column label="最近更新" prop="lastUpdateTime" width="150">
            <template slot-scope="{ row }">{{ parseTime(row.lastUpdateTime, '{y}-{m}-{d} {h}:{i}') || '—' }}</template>
          </el-table-column>
          <el-table-column label="备注" prop="remark" min-width="160" show-overflow-tooltip />
        </el-table>
      </template>

      <!-- ── 文件操作记录 ── -->
      <template v-else-if="activeTab === 'files'">
        <div class="section-title">文件操作记录</div>
        <el-table :data="moduleData.files" size="small" border stripe>
          <el-table-column label="文件名" prop="fileName" min-width="180" show-overflow-tooltip />
          <el-table-column label="一级节点" prop="firstLevelNode" width="110" show-overflow-tooltip />
          <el-table-column label="二级节点" prop="secondLevelNode" width="110" show-overflow-tooltip />
          <el-table-column label="操作类型" width="80" align="center">
            <template slot-scope="{ row }">
              <span :style="{ color: row.type === 1 ? '#409EFF' : '#F56C6C' }">{{ row.type === 1 ? '上传' : '删除' }}</span>
            </template>
          </el-table-column>
          <el-table-column label="操作人" prop="operatorName" width="90" align="center" />
          <el-table-column label="操作时间" prop="createTime" width="150">
            <template slot-scope="{ row }">{{ parseTime(row.createTime, '{y}-{m}-{d} {h}:{i}') }}</template>
          </el-table-column>
          <el-table-column label="备注" prop="remark" min-width="120" show-overflow-tooltip />
          <el-table-column label="下载" width="80" align="center" fixed="right">
            <template slot-scope="{ row }">
              <el-button v-if="row.fileId" type="text" size="mini" icon="el-icon-download" @click="$download.oss(row.fileId)">下载</el-button>
              <span v-else style="color:#c0c4cc">—</span>
            </template>
          </el-table-column>
        </el-table>
      </template>

      <!-- ── 问题反馈 ── -->
      <template v-else-if="activeTab === 'feedback'">
        <div class="section-title">问题反馈</div>
        <el-table :data="moduleData.feedback" size="small" border stripe>
          <el-table-column label="标题" prop="title" min-width="160" show-overflow-tooltip />
          <el-table-column label="类型" prop="type" width="90" align="center">
            <template slot-scope="{ row }">{{ row.type || '—' }}</template>
          </el-table-column>
          <el-table-column label="状态" width="90" align="center">
            <template slot-scope="{ row }">
              <span :style="{ color: row.status === 1 ? '#67C23A' : '#E6A23C' }">{{ row.status === 1 ? '已解决' : '待处理' }}</span>
            </template>
          </el-table-column>
          <el-table-column label="反馈内容" prop="content" min-width="200" show-overflow-tooltip />
          <el-table-column label="提交人" prop="createBy" width="90" align="center" />
          <el-table-column label="备注" prop="remark" min-width="120" show-overflow-tooltip />
          <el-table-column label="创建时间" prop="createTime" width="150">
            <template slot-scope="{ row }">{{ parseTime(row.createTime, '{y}-{m}-{d} {h}:{i}') }}</template>
          </el-table-column>
        </el-table>
      </template>

      <!-- ── 操作历史 ── -->
      <template v-else-if="activeTab === 'oplog'">
        <div class="section-title">操作历史</div>
        <el-table :data="moduleData.oplog" size="small" border stripe>
          <el-table-column label="操作时间" prop="operateTime" width="150">
            <template slot-scope="{ row }">{{ parseTime(row.operateTime, '{y}-{m}-{d} {h}:{i}') }}</template>
          </el-table-column>
          <el-table-column label="操作对象" width="90" align="center">
            <template slot-scope="{ row }">
              <span class="badge-tag" :style="{ color: targetTypeColor(row.targetType), borderColor: targetTypeColor(row.targetType) }">{{ targetTypeLabel(row.targetType) }}</span>
            </template>
          </el-table-column>
          <el-table-column label="对象名称" prop="targetName" width="130" show-overflow-tooltip />
          <el-table-column label="操作类型" width="90" align="center">
            <template slot-scope="{ row }">
              <span class="badge-tag" :style="{ color: opTypeColor(row.operationType), borderColor: opTypeColor(row.operationType) }">{{ opTypeLabel(row.operationType) }}</span>
            </template>
          </el-table-column>
          <el-table-column label="操作描述" prop="operationDesc" min-width="200" show-overflow-tooltip />
          <el-table-column label="操作人" prop="operator" width="90" align="center" />
        </el-table>
      </template>

      <!-- 分页 -->
      <div class="right-pagination" v-if="activeTab !== 'info' && activeTab !== 'progress'">
        <pagination
          v-show="modulePaging[activeTab] && modulePaging[activeTab].total > 0"
          :total="modulePaging[activeTab] ? modulePaging[activeTab].total : 0"
          :page.sync="modulePaging[activeTab].pageNum"
          :limit.sync="modulePaging[activeTab].pageSize"
          layout="total, prev, pager, next"
          @pagination="reloadCurrentTab"
        />
      </div>

      </div><!-- /panel-right-body -->
    </div>

    <!-- 未选中项目时的占位 -->
    <div class="panel-right panel-empty" v-else>
      <i class="el-icon-office-building" style="font-size:48px;color:#dcdfe6" />
      <p>请从左侧选择一个项目</p>
    </div>

  </div>
</template>

<script>
import { listProject, getProject } from '@/api/oa/project'
import { listOaContract } from '@/api/oa/oaContract'
import { listFinancePro } from '@/api/oa/finance'
import request from '@/utils/request'
// /oa/cost/list1 支持 projectId 过滤（list 是全项目汇总，不能用）
function listCostByProject (params) {
  return request({ url: '/oa/cost/list1', method: 'get', params })
}
import { getPaymentProgress } from '@/api/oa/finance/progress'
import { listOaClaim } from '@/api/oa/claim'
import { listBonusProjectRel } from '@/api/oa/bonusProjectRel'
import { listProgress } from '@/api/oa/progress'
import { listTask } from '@/api/oa/task'
import { listRequirements } from '@/api/oa/requirement'
import { listDeliveryOrder } from '@/api/oa/workshop/deliveryOrder'
import { listExpress } from '@/api/oa/express'
import { listProcessCard } from '@/api/oa/workshop/processCard'
import { listProjectReport } from '@/api/oa/projectReport'
import { listReportSummary } from '@/api/oa/reportSummary'
import { listFileOperationRecord } from '@/api/oa/fileOperationRecord'
import { listFeedback } from '@/api/oa/feedback'
import { listOperationLog } from '@/api/oa/projectOperationLog'

const MODULES = [
  { key: 'info',        label: '基本信息',   icon: 'el-icon-office-building' },
  { key: 'contract',    label: '合同',        icon: 'el-icon-document'         },
  { key: 'finance',     label: '收付款记录',  icon: 'el-icon-bank-card'        },
  { key: 'payment',     label: '回款计划',    icon: 'el-icon-money'            },
  { key: 'cost',        label: '成本',        icon: 'el-icon-coin'             },
  { key: 'claim',       label: '报销',        icon: 'el-icon-tickets'          },
  { key: 'bonus',       label: '奖金分配',    icon: 'el-icon-present'          },
  { key: 'progress',    label: '项目进度',    icon: 'el-icon-data-line'        },
  { key: 'task',        label: '任务',        icon: 'el-icon-s-check'          },
  { key: 'require',     label: '采购需求',    icon: 'el-icon-shopping-cart-2'  },
  { key: 'delivery',    label: '发货单',      icon: 'el-icon-truck'            },
  { key: 'express',     label: '快递',        icon: 'el-icon-box'              },
  { key: 'processCard', label: '生产',         icon: 'el-icon-printer'          },
  { key: 'report',      label: '工作报告',    icon: 'el-icon-edit-outline'     },
  { key: 'summary',     label: '汇报摘要',    icon: 'el-icon-collection'       },
  { key: 'files',       label: '文件记录',    icon: 'el-icon-folder'           },
  { key: 'feedback',    label: '问题反馈',    icon: 'el-icon-warning-outline'  },
  { key: 'oplog',       label: '操作历史',    icon: 'el-icon-s-order'          }
]

const TARGET_TYPES = [
  { value: 1, label: '项目进度', color: '#409EFF' },
  { value: 2, label: '进度步骤', color: '#67C23A' },
  { value: 3, label: '任务',     color: '#E6A23C' },
  { value: 4, label: '延期申请', color: '#F56C6C' }
]
const OP_TYPES = [
  { value: 1, label: '新增',     color: '#67C23A' },
  { value: 2, label: '修改',     color: '#409EFF' },
  { value: 3, label: '删除',     color: '#F56C6C' },
  { value: 4, label: '状态变更', color: '#E6A23C' },
  { value: 5, label: '完成',     color: '#67C23A' },
  { value: 6, label: '申请延期', color: '#E6A23C' },
  { value: 7, label: '审批通过', color: '#67C23A' },
  { value: 8, label: '审批驳回', color: '#F56C6C' }
]

// 每个 tab 的数据加载函数工厂
function makePaging () { return { pageNum: 1, pageSize: 20, total: 0 } }

export default {
  name: 'ProjectDispatch',
  data () {
    return {
      MODULES,
      projectLoading: false,
      projectList: [],
      filteredList: [],
      searchText: '',
      activeProject: null,
      activeTab: 'info',
      moduleData: {},
      moduleLoading: {},
      badgeCounts: {},
      modulePaging: Object.fromEntries(MODULES.map(m => [m.key, makePaging()]))
    }
  },
  computed: {
    progressTree () {
      const rows = this.moduleData.progress || []
      const map = {}
      rows.forEach(r => { map[r.progressId] = { ...r, children: [] } })
      const roots = []
      rows.forEach(r => {
        if (r.parentId && map[r.parentId]) {
          map[r.parentId].children.push(map[r.progressId])
        } else {
          roots.push(map[r.progressId])
        }
      })
      return roots
    }
  },
  created () {
    this.loadProjects()
  },
  methods: {
    // ── 项目列表 ──
    loadProjects () {
      this.projectLoading = true
      listProject({ pageNum: 1, pageSize: 999 }).then(res => {
        this.projectList = res.rows || []
        this.filteredList = this.projectList
      }).finally(() => { this.projectLoading = false })
    },
    filterProjects () {
      const q = (this.searchText || '').trim().toLowerCase()
      if (!q) { this.filteredList = this.projectList; return }
      this.filteredList = this.projectList.filter(p =>
        (p.projectName || '').toLowerCase().includes(q) ||
        (p.projectNum  || '').toLowerCase().includes(q) ||
        (p.projectCode || '').toLowerCase().includes(q)
      )
    },
    selectProject (p) {
      if (this.activeProject && this.activeProject.projectId === p.projectId) return
      this.activeProject = p
      this.activeTab = 'info'
      this.moduleData = {}
      this.modulePaging = Object.fromEntries(MODULES.map(m => [m.key, makePaging()]))
      this.badgeCounts = {}
      this.loadAllBadges()
    },

    // ── Tab 切换 ──
    switchTab (key) {
      this.activeTab = key
      if (key === 'info') return
      if (this.moduleData[key] === undefined) {
        this.fetchModule(key)
      }
    },
    reloadCurrentTab () {
      this.fetchModule(this.activeTab)
    },

    // ── 数据加载 ──
    fetchModule (key) {
      const pid = this.activeProject.projectId
      const pg  = this.modulePaging[key]
      this.$set(this.moduleLoading, key, true)

      const done = (rows, total) => {
        this.$set(this.moduleData, key, rows || [])
        if (pg) pg.total = total || (rows || []).length
        this.$set(this.moduleLoading, key, false)
        this.$set(this.badgeCounts, key, total || (rows || []).length)
      }
      const fail = () => { this.$set(this.moduleLoading, key, false) }
      const params = { projectId: pid, pageNum: pg.pageNum, pageSize: pg.pageSize }

      const loaders = {
        contract:    () => listOaContract(params).then(r => done(r.rows, r.total)).catch(fail),
        finance:     () => listFinancePro(params).then(r => done(r.rows, r.total)).catch(fail),
        payment:     () => getPaymentProgress(params).then(r => done(r.rows, r.total)).catch(fail),
        cost:        () => listCostByProject(params).then(r => done(r.rows, r.total)).catch(fail),
        claim:       () => listOaClaim(params).then(r => done(r.rows, r.total)).catch(fail),
        bonus:       () => listBonusProjectRel(params).then(r => done(r.rows, r.total)).catch(fail),
        progress:    () => listProgress(pid).then(r => { const rows = Array.isArray(r) ? r : (r.rows || r.data || []); done(rows, rows.length) }).catch(fail),
        task:        () => listTask(params).then(r => done(r.rows, r.total)).catch(fail),
        require:     () => listRequirements(params).then(r => done(r.rows, r.total)).catch(fail),
        delivery:    () => listDeliveryOrder(params).then(r => done(r.rows, r.total)).catch(fail),
        express:     () => listExpress(params).then(r => done(r.rows, r.total)).catch(fail),
        processCard: () => listProcessCard(params).then(r => done(r.rows, r.total)).catch(fail),
        report:      () => listProjectReport(params).then(r => done(r.rows, r.total)).catch(fail),
        summary:     () => listReportSummary(params).then(r => done(r.rows, r.total)).catch(fail),
        files:       () => listFileOperationRecord(params).then(r => done(r.rows, r.total)).catch(fail),
        feedback:    () => listFeedback(params).then(r => done(r.rows, r.total)).catch(fail),
        oplog:       () => listOperationLog(params).then(r => done(r.rows, r.total)).catch(fail)
      }
      if (loaders[key]) loaders[key]()
    },

    // 并发加载所有 badge count（pageSize=1 只取 total）
    loadAllBadges () {
      const pid = this.activeProject.projectId
      MODULES.filter(m => m.key !== 'info').forEach(m => {
        this.$set(this.badgeCounts, m.key, undefined)
      })
      // use small pageSize for count
      const cp = { projectId: pid, pageNum: 1, pageSize: 1 }
      const setCount = (key, res) => {
        this.$set(this.badgeCounts, key, res.total !== undefined ? res.total : (res.rows || []).length)
      }
      listOaContract(cp).then(r => setCount('contract', r)).catch(() => {})
      listFinancePro(cp).then(r => setCount('finance', r)).catch(() => {})
      getPaymentProgress(cp).then(r => setCount('payment', r)).catch(() => {})
      listCostByProject(cp).then(r => setCount('cost', r)).catch(() => {})
      listOaClaim(cp).then(r => setCount('claim', r)).catch(() => {})
      listBonusProjectRel(cp).then(r => setCount('bonus', r)).catch(() => {})
      listProgress(pid).then(r => { const rows = Array.isArray(r) ? r : (r.rows || r.data || []); this.$set(this.badgeCounts, 'progress', rows.length) }).catch(() => {})
      listTask(cp).then(r => setCount('task', r)).catch(() => {})
      listRequirements(cp).then(r => setCount('require', r)).catch(() => {})
      listDeliveryOrder(cp).then(r => setCount('delivery', r)).catch(() => {})
      listExpress(cp).then(r => setCount('express', r)).catch(() => {})
      listProcessCard(cp).then(r => setCount('processCard', r)).catch(() => {})
      listProjectReport(cp).then(r => setCount('report', r)).catch(() => {})
      listReportSummary(cp).then(r => setCount('summary', r)).catch(() => {})
      listFileOperationRecord(cp).then(r => setCount('files', r)).catch(() => {})
      listFeedback(cp).then(r => setCount('feedback', r)).catch(() => {})
      listOperationLog(cp).then(r => setCount('oplog', r)).catch(() => {})
    },

    // ── 辅助 ──
    // sys_project_status 字典: '0'=进行中(primary), '1'=进度完成(success)
    statusLabel (s) {
      if (s === '0' || s === 0) return '进行中'
      if (s === '1' || s === 1) return '进度完成'
      return s || '—'
    },
    statusClass (s) {
      if (s === '0' || s === 0) return 'st-active'
      if (s === '1' || s === 1) return 'st-done'
      return 'st-cancel'
    },
    costTypeLabel (t) {
      return t === 1 ? '材料' : t === 2 ? '人工' : t === 3 ? '设备' : t === 4 ? '其他' : '—'
    },
    progressStatusLabel (s) {
      return s === 1 ? '进行中' : s === 2 ? '已完成' : s === 0 ? '未开始' : '—'
    },
    expressStatusLabel (s) {
      return s === 0 ? '待发货' : s === 1 ? '运输中' : s === 2 ? '已签收' : '—'
    },
    targetTypeLabel (v) { return (TARGET_TYPES.find(t => t.value === v) || {}).label || v },
    targetTypeColor (v) { return (TARGET_TYPES.find(t => t.value === v) || {}).color || '#909399' },
    opTypeLabel (v)   { return (OP_TYPES.find(t => t.value === v) || {}).label || v },
    opTypeColor (v)   { return (OP_TYPES.find(t => t.value === v) || {}).color || '#909399' },
    // sys_work_type 字典
    workTypeLabel (v) {
      const map = { 1: '需求沟通', 2: '方案策划', 3: '采购备货', 4: '收货验参', 5: '施工安装', 6: '质量管控', 7: '项目初验', 8: '项目终验', 9: '项目结算', 101: '客户接待' }
      return map[Number(v)] || (v != null ? String(v) : '—')
    },
    // sys_pay_type 字典: 1=对公转账, 2=现金交易, 3=现金转账, 4=银行承兑
    payTypeLabel (v) {
      const map = { '1': '对公转账', '2': '现金交易', '3': '现金转账', '4': '银行承兑' }
      return map[String(v)] || (v != null ? String(v) : '—')
    },
    // 计算 detailList 中所有 price 的加和
    sumDetailPrice (row) {
      const list = row.detailList
      if (!Array.isArray(list) || list.length === 0) return row.makePrice || '—'
      const total = list.reduce((acc, item) => acc + (parseFloat(item.price) || 0), 0)
      return total.toFixed(2)
    }
  }
}
</script>

<style scoped>
/* ══ 整体布局 ══ */
.dispatch-layout {
  display: flex;
  height: calc(100vh - 84px);
  background: #f0f2f5;
  overflow: hidden;
  gap: 0;
}

/* ══ 左栏 ══ */
.panel-left {
  width: 240px;
  flex-shrink: 0;
  background: #fff;
  border-right: 1px solid #dcdfe6;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.left-header {
  padding: 14px 14px 8px;
  display: flex;
  align-items: baseline;
  gap: 6px;
  flex-shrink: 0;
  border-bottom: 1px solid #f0f0f0;
}
.left-title { font-size: 14px; font-weight: 700; color: #303133; }
.left-count  { font-size: 12px; color: #909399; }
.left-search { padding: 10px 10px 6px; flex-shrink: 0; }
.left-list   { flex: 1; overflow-y: auto; }
.left-empty  { text-align: center; color: #c0c4cc; padding: 40px 0; font-size: 13px; }

.project-item {
  padding: 10px 12px;
  cursor: pointer;
  border-bottom: 1px solid #f5f5f5;
  transition: background .15s;
}
.project-item:hover   { background: #f5f7fa; }
.project-item.is-active { background: #ecf5ff; border-right: 3px solid #409EFF; }

.pi-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}
.pi-name {
  font-size: 13px;
  font-weight: 600;
  color: #303133;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
  margin-right: 6px;
}
.pi-status {
  font-size: 11px;
  padding: 1px 5px;
  border-radius: 2px;
  flex-shrink: 0;
  border: 1px solid;
}
.st-active  { color: #409EFF; border-color: #b3d8ff; background: #ecf5ff; }
.st-done    { color: #67C23A; border-color: #c2e7b0; background: #f0f9eb; }
.st-pause   { color: #E6A23C; border-color: #faecd8; background: #fdf6ec; }
.st-cancel  { color: #909399; border-color: #e4e7ed; background: #f4f4f5; }

.pi-row {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-top: 3px;
}
.pi-tag {
  font-size: 11px;
  color: #606266;
  background: #f4f4f5;
  border-radius: 2px;
  padding: 1px 5px;
}
.pi-tag.accent { color: #409EFF; background: #ecf5ff; }
.pi-sub { font-size: 11px; color: #909399; }

/* ══ 中栏（模块 Tab） ══ */
.panel-mid {
  width: 120px;
  flex-shrink: 0;
  background: #fff;
  border-right: 1px solid #dcdfe6;
  overflow-y: auto;
  padding: 8px 0;
}
.mod-tab {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 9px 12px;
  cursor: pointer;
  font-size: 12px;
  color: #606266;
  position: relative;
  transition: background .15s;
}
.mod-tab:hover   { background: #f5f7fa; color: #303133; }
.mod-active      { background: #ecf5ff; color: #409EFF; font-weight: 600; border-left: 3px solid #409EFF; }
.mod-icon        { font-size: 13px; flex-shrink: 0; }
.mod-label       { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mod-badge {
  font-size: 10px;
  background: #F56C6C;
  color: #fff;
  border-radius: 8px;
  padding: 0 4px;
  min-width: 16px;
  text-align: center;
  line-height: 16px;
  flex-shrink: 0;
}
.mod-badge-zero {
  background: #e4e7ed;
  color: #909399;
}

/* ══ 右栏（内容区） ══ */
.panel-right {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #f0f2f5;
}

/* 当前项目固定头 */
.project-header-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 18px;
  background: #fff;
  border-bottom: 1px solid #dcdfe6;
  flex-shrink: 0;
  flex-wrap: wrap;
}
.project-header-icon { font-size: 15px; color: #409EFF; flex-shrink: 0; }
.project-header-name { font-size: 14px; font-weight: 700; color: #303133; margin-right: 4px; }
.project-header-tag  { font-size: 11px; color: #606266; background: #f4f4f5; border-radius: 2px; padding: 1px 6px; flex-shrink: 0; }
.project-header-tag.accent { color: #409EFF; background: #ecf5ff; }
.project-header-status { font-size: 11px; padding: 1px 6px; border-radius: 2px; border: 1px solid; flex-shrink: 0; }
.project-header-sub  { font-size: 12px; color: #909399; margin-left: 4px; }

/* 内容滚动区 */
.panel-right-body {
  flex: 1;
  overflow-y: auto;
  padding: 16px 18px;
}
.panel-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #c0c4cc;
  font-size: 14px;
  gap: 12px;
}

.section-title {
  font-size: 14px;
  font-weight: 700;
  color: #303133;
  margin-bottom: 12px;
  padding-left: 8px;
  border-left: 3px solid #409EFF;
}

/* ══ 统计卡片（基本信息页底部） ══ */
.stat-mini {
  background: #fff;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  padding: 12px 10px;
  text-align: center;
  cursor: pointer;
  margin-bottom: 10px;
  transition: border-color .2s;
}
.stat-mini:hover { border-color: #409EFF; }
.stat-mini-icon  { font-size: 18px; color: #909399; }
.stat-mini-num   { font-size: 18px; font-weight: 700; color: #303133; margin: 4px 0; }
.stat-mini-label { font-size: 11px; color: #909399; }

/* ══ 进度树 ══ */
.progress-tree { background: #fff; border: 1px solid #dcdfe6; border-radius: 4px; padding: 12px 16px; }
.empty-tip     { text-align: center; color: #c0c4cc; padding: 30px 0; font-size: 13px; }

.pt-group  { margin-bottom: 12px; border-bottom: 1px solid #f0f0f0; padding-bottom: 10px; }
.pt-top    { display: flex; align-items: center; padding: 6px 0; font-size: 13px; font-weight: 600; color: #303133; }
.pt-top-name { flex: 1; }

.pt-sub    { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; padding: 4px 0 4px 20px; font-size: 12px; color: #606266; }
.pt-sub-name { font-weight: 500; color: #303133; }

.pt-leaf   { display: flex; align-items: center; gap: 6px; padding: 3px 0 3px 40px; font-size: 12px; color: #909399; width: 100%; }

.pt-status { font-size: 11px; padding: 1px 5px; border-radius: 2px; flex-shrink: 0; }
.ps-0 { color: #909399; background: #f4f4f5; }
.ps-1 { color: #409EFF; background: #ecf5ff; }
.ps-2 { color: #67C23A; background: #f0f9eb; }

.pt-amount      { font-size: 11px; color: #E6A23C; background: #fdf6ec; padding: 1px 5px; border-radius: 2px; }
.pt-time-remark { font-size: 11px; color: #909399; }

/* ══ 通用 ══ */
.money { color: #303133; font-weight: 600; }
.html-preview { font-size: 12px; line-height: 1.4; }
.right-pagination { margin-top: 12px; display: flex; justify-content: flex-end; }

.badge-tag {
  display: inline-block;
  padding: 0 5px;
  height: 18px;
  line-height: 16px;
  border-radius: 2px;
  border: 1px solid;
  font-size: 11px;
  white-space: nowrap;
}

/* el-table 放在灰色背景上，加白色外壳 */
.el-table { background: #fff; }
</style>
