Bläddra i källkod

feat: #14 月度产值填报页面

部门管理员核心操作页面,双Tab架构+批量填报+截止倒计时

- 截止倒计时横幅: 实时计算距离12日天数,绿/橙/红三色预警,逾期提示
- 双Tab: 待填报项目(自动筛选未完工) + 填报历史(三维搜索+审核状态)
- 批量填报: 统一月份/进度/说明 + 逐项目独立产值输入
- 单个填报: 集成OutputForm组件,自动计算剩余产值上限
- 校验: 进度≤100%、产值≥0、≤剩余产值、逾期二次确认
- 协作标记: 协作部门黄色标签+协作产值字段
- 双重提交: 保存草稿/保存并提交

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
shenzx 1 månad sedan
förälder
incheckning
d9e4cac823
1 ändrade filer med 519 tillägg och 170 borttagningar
  1. 519 170
      src/views/performance/output/index.vue

+ 519 - 170
src/views/performance/output/index.vue

@@ -1,244 +1,593 @@
 <template>
   <div class="app-container">
-    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="80px">
-      <el-form-item label="项目名称" prop="projectName">
-        <el-input v-model="queryParams.projectName" placeholder="请输入项目名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
-      </el-form-item>
-      <el-form-item label="填报月份" prop="month">
-        <el-date-picker v-model="queryParams.month" type="month" value-format="YYYY-MM" placeholder="请选择月份" clearable style="width: 200px" />
-      </el-form-item>
-      <el-form-item label="审核状态" prop="reviewStatus">
-        <el-select v-model="queryParams.reviewStatus" placeholder="审核状态" clearable style="width: 200px">
-          <el-option label="待提交" value="DRAFT" />
-          <el-option label="已提交待审核" value="SUBMITTED" />
-          <el-option label="审核通过" value="APPROVED" />
-          <el-option label="审核不通过" value="REJECTED" />
-        </el-select>
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
-
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button type="primary" plain icon="Edit" @click="handleAdd" v-hasPermi="['performance:output:add']">填报产值</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button type="success" plain icon="Upload" :disabled="multiple" @click="handleBatchSubmit" v-hasPermi="['performance:output:submit']">批量提交</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['performance:output:export']">导出</el-button>
-      </el-col>
-      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
-
-    <el-table v-loading="loading" :data="outputList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="50" align="center" />
-      <el-table-column label="项目名称" align="center" prop="projectName" :show-overflow-tooltip="true" />
-      <el-table-column label="填报月份" align="center" prop="month" />
-      <el-table-column label="当月进度(%)" align="center" prop="currentProgress" />
-      <el-table-column label="当月产值(万元)" align="center" prop="currentOutput" />
-      <el-table-column label="协作产值(万元)" align="center" prop="coopOutput" />
-      <el-table-column label="审核状态" align="center" prop="reviewStatus">
-        <template #default="scope">
-          <dict-tag :options="reviewStatusOptions" :value="scope.row.reviewStatus" />
-        </template>
-      </el-table-column>
-      <el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
-        <template #default="scope">
-          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-if="scope.row.reviewStatus === 'DRAFT'" v-hasPermi="['performance:output:edit']">修改</el-button>
-          <el-button link type="primary" icon="Upload" @click="handleSubmit(scope.row)" v-if="scope.row.reviewStatus === 'DRAFT'" v-hasPermi="['performance:output:submit']">提交</el-button>
-          <el-button link type="primary" icon="View" @click="handleDetail(scope.row)">详情</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-
-    <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
-
-    <!-- 产值填报对话框 -->
-    <el-dialog :title="title" v-model="open" width="650px" append-to-body>
-      <el-form :model="form" :rules="rules" ref="outputRef" label-width="140px">
-        <el-form-item label="项目" prop="projectId">
-          <el-select v-model="form.projectId" placeholder="请选择项目" :disabled="form.outputId !== undefined" style="width: 100%">
-            <el-option v-for="item in projectOptions" :key="item.projectId" :label="item.projectName" :value="item.projectId" />
-          </el-select>
-        </el-form-item>
+    <!-- 填报截止倒计时 -->
+    <el-alert :title="deadlineMessage" :type="deadlineType" :closable="false" show-icon class="mb16">
+      <template v-if="isOverdue">
+        <span style="font-weight: bold">当前月份已超过填报截止日期(12日),系统将视为本月该部门无产值。</span>
+      </template>
+    </el-alert>
+
+    <!-- 双Tab切换 -->
+    <el-tabs v-model="activeTab" @tab-change="handleTabChange">
+      <!-- Tab 1: 待填报项目 -->
+      <el-tab-pane label="待填报项目" name="pending">
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Edit" @click="handleBatchAdd" :disabled="selectCount === 0" v-hasPermi="['performance:output:add']">
+              批量填报 ({{ selectCount }})
+            </el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Upload" @click="handleBatchSubmit" :disabled="draftCount === 0" v-hasPermi="['performance:output:submit']">
+              批量提交草稿 ({{ draftCount }})
+            </el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button text @click="toggleAllSelect">
+              {{ allSelected ? '取消全选' : '全选未填项目' }}
+            </el-button>
+          </el-col>
+        </el-row>
+
+        <el-table v-loading="loading" :data="pendingProjects" @selection-change="handlePendingSelection" ref="pendingTableRef">
+          <el-table-column type="selection" width="50" align="center" />
+          <el-table-column label="项目名称" align="center" prop="projectName" :show-overflow-tooltip="true" />
+          <el-table-column label="项目类型" align="center" prop="projectType" width="100">
+            <template #default="scope">{{ typeMap[scope.row.projectType] || scope.row.projectType }}</template>
+          </el-table-column>
+          <el-table-column label="项目状态" align="center" width="120">
+            <template #default="scope">
+              <ReviewStatusTag :status="scope.row.status" :options="projectStatusOptions" />
+            </template>
+          </el-table-column>
+          <el-table-column label="总产值得(万元)" align="center" prop="totalOutput" width="120" />
+          <el-table-column label="已填报产值(万元)" align="center" prop="filledOutput" width="120" />
+          <el-table-column label="剩余产值(万元)" align="center" width="120">
+            <template #default="scope">
+              <span :style="{ color: (scope.row.totalOutput - scope.row.filledOutput) > 0 ? '#67C23A' : '#F56C6C' }">
+                {{ ((scope.row.totalOutput || 0) - (scope.row.filledOutput || 0)).toFixed(4) }}
+              </span>
+            </template>
+          </el-table-column>
+          <el-table-column label="协作部门" align="center" width="140">
+            <template #default="scope">
+              <el-tag v-if="scope.row.coopDeptName" type="warning" effect="plain" size="small">
+                {{ scope.row.coopDeptName }}
+              </el-tag>
+              <span v-else>无</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="草稿" align="center" width="60">
+            <template #default="scope">
+              <el-tag v-if="scope.row.draftId" type="info" size="small">有</el-tag>
+              <span v-else style="color: #C0C4CC">--</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
+            <template #default="scope">
+              <el-button link type="primary" icon="Edit" @click="handleSingleAdd(scope.row)">
+                {{ scope.row.draftId ? '修改草稿' : '填报' }}
+              </el-button>
+              <el-button link type="success" icon="Upload" @click="handleSubmitSingle(scope.row)" v-if="scope.row.draftId">
+                提交
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-tab-pane>
+
+      <!-- Tab 2: 填报历史 -->
+      <el-tab-pane label="填报历史" name="history">
+        <el-form :model="historyParams" ref="historyRef" :inline="true" v-show="showSearch" label-width="80px">
+          <el-form-item label="项目名称" prop="projectName">
+            <el-input v-model="historyParams.projectName" placeholder="请输入项目名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item label="填报月份" prop="month">
+            <el-date-picker v-model="historyParams.month" type="month" value-format="YYYY-MM" placeholder="请选择月份" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item label="审核状态" prop="reviewStatus">
+            <el-select v-model="historyParams.reviewStatus" placeholder="审核状态" clearable style="width: 200px">
+              <el-option v-for="dict in reviewStatusOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+            <el-button icon="Refresh" @click="resetHistoryQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['performance:output:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getHistoryList"></right-toolbar>
+        </el-row>
+
+        <el-table v-loading="historyLoading" :data="historyList">
+          <el-table-column label="项目名称" align="center" prop="projectName" :show-overflow-tooltip="true" />
+          <el-table-column label="填报月份" align="center" prop="month" width="120" />
+          <el-table-column label="当月进度(%)" align="center" prop="currentProgress" width="110" />
+          <el-table-column label="当月产值(万元)" align="center" prop="currentOutput" width="130" />
+          <el-table-column label="协作产值(万元)" align="center" prop="coopOutput" width="130" />
+          <el-table-column label="审核状态" align="center" prop="reviewStatus" width="120">
+            <template #default="scope">
+              <ReviewStatusTag :status="scope.row.reviewStatus" :options="reviewStatusTagOptions" />
+            </template>
+          </el-table-column>
+          <el-table-column label="审核意见" align="center" prop="reviewComment" :show-overflow-tooltip="true" width="150" />
+          <el-table-column label="填报时间" align="center" prop="createTime" width="160">
+            <template #default="scope">{{ parseTime(scope.row.createTime) }}</template>
+          </el-table-column>
+          <el-table-column label="操作" align="center" width="120">
+            <template #default="scope">
+              <el-button link type="primary" icon="View" @click="handleViewDetail(scope.row)">详情</el-button>
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-if="scope.row.reviewStatus === 'DRAFT'" v-hasPermi="['performance:output:edit']">修改</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <pagination v-show="historyTotal > 0" :total="historyTotal" v-model:page="historyParams.pageNum" v-model:limit="historyParams.pageSize" @pagination="getHistoryList" />
+      </el-tab-pane>
+    </el-tabs>
+
+    <!-- 批量填报对话框 -->
+    <el-dialog title="批量产值填报" v-model="batchOpen" width="700px" append-to-body @close="cancelBatch">
+      <el-alert title="提示" type="info" :closable="false" show-icon style="margin-bottom: 16px">
+        已选择 {{ selectedProjects.length }} 个项目进行批量填报。以下字段将应用于所有选中的项目。
+      </el-alert>
+      <el-form :model="batchForm" ref="batchRef" label-width="140px">
         <el-form-item label="填报月份" prop="month">
-          <el-date-picker v-model="form.month" type="month" value-format="YYYY-MM" placeholder="请选择月份" :disabled="form.outputId !== undefined" style="width: 100%" />
-        </el-form-item>
-        <el-form-item label="当月实际进度(%)" prop="currentProgress">
-          <el-input-number v-model="form.currentProgress" :precision="1" :min="0" :max="100" placeholder="请输入当月实际进度" style="width: 100%" />
+          <el-date-picker v-model="batchForm.month" type="month" value-format="YYYY-MM" placeholder="请选择填报月份" style="width: 100%" />
         </el-form-item>
-        <el-form-item label="当月实际产值(万元)" prop="currentOutput">
-          <el-input-number v-model="form.currentOutput" :precision="4" :min="0" placeholder="请输入当月实际产值" style="width: 100%" />
+        <el-form-item label="统一进度(%)" prop="currentProgress">
+          <el-slider v-model="batchForm.currentProgress" :min="0" :max="100" :step="0.5" show-input style="width: 100%" />
         </el-form-item>
         <el-form-item label="进度说明" prop="description">
-          <el-input v-model="form.description" type="textarea" placeholder="请输入进度说明" maxlength="500" />
+          <el-input v-model="batchForm.description" type="textarea" :rows="3" placeholder="统一进度说明(可选)" maxlength="500" />
         </el-form-item>
       </el-form>
+      <el-divider content-position="left">各项目产值明细</el-divider>
+      <el-table :data="selectedProjects" border max-height="300">
+        <el-table-column label="项目名称" prop="projectName" :show-overflow-tooltip="true" width="180" />
+        <el-table-column label="剩余产值(万元)" prop="remainingOutput" width="130">
+          <template #default="scope">
+            <span>{{ ((scope.row.totalOutput || 0) - (scope.row.filledOutput || 0)).toFixed(4) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="当月产值(万元)" width="150">
+          <template #default="scope">
+            <el-input-number v-model="batchOutputs[scope.row.projectId]" :precision="4" :min="0" :max="Math.max(0, (scope.row.totalOutput || 0) - (scope.row.filledOutput || 0))" size="small" style="width: 130px" />
+          </template>
+        </el-table-column>
+      </el-table>
       <template #footer>
         <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">保 存</el-button>
-          <el-button @click="cancel">取 消</el-button>
+          <el-button type="primary" @click="submitBatchSave">保存草稿</el-button>
+          <el-button type="success" @click="submitBatchAndSubmit">保存并提交</el-button>
+          <el-button @click="batchOpen = false">取 消</el-button>
         </div>
       </template>
     </el-dialog>
+
+    <!-- 单个填报对话框 -->
+    <el-dialog :title="singleTitle" v-model="singleOpen" width="650px" append-to-body @close="cancelSingle">
+      <OutputForm
+        ref="outputFormRef"
+        v-model="singleForm"
+        :projectOptions="availableProjects"
+        :disabled="!!singleForm.outputId"
+        :showCooperation="currentProjectHasCooperation"
+        :projectTotalOutput="projectTotalOutputLimit"
+      />
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitSingleSave">保存草稿</el-button>
+          <el-button type="success" @click="submitSingleAndSubmit" :disabled="isOverdue">提交审核</el-button>
+          <el-button @click="singleOpen = false">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!-- 填报详情对话框 -->
+    <el-dialog title="填报详情" v-model="detailOpen" width="550px" append-to-body>
+      <el-descriptions :column="1" border>
+        <el-descriptions-item label="项目名称">{{ detailData.projectName }}</el-descriptions-item>
+        <el-descriptions-item label="填报月份">{{ detailData.month }}</el-descriptions-item>
+        <el-descriptions-item label="当月进度(%)">{{ detailData.currentProgress }}%</el-descriptions-item>
+        <el-descriptions-item label="当月产值(万元)">{{ detailData.currentOutput }}</el-descriptions-item>
+        <el-descriptions-item label="协作产值(万元)">{{ detailData.coopOutput || '--' }}</el-descriptions-item>
+        <el-descriptions-item label="审核状态">
+          <ReviewStatusTag :status="detailData.reviewStatus" :options="reviewStatusTagOptions" />
+        </el-descriptions-item>
+        <el-descriptions-item label="审核意见">{{ detailData.reviewComment || '--' }}</el-descriptions-item>
+        <el-descriptions-item label="进度说明">{{ detailData.description || '--' }}</el-descriptions-item>
+        <el-descriptions-item label="填报时间">{{ parseTime(detailData.createTime) }}</el-descriptions-item>
+      </el-descriptions>
+    </el-dialog>
   </div>
 </template>
 
 <script setup name="PerformanceOutput">
-import { listOutput, getOutput, addOutput, updateOutput, submitOutput } from '@/api/performance/output'
+import { listOutput, getOutput, addOutput, updateOutput, submitOutput, batchOutput, listCooperation } from '@/api/performance/output'
+import { listProject } from '@/api/performance/project'
+import { OutputForm, ReviewStatusTag } from '@/components/performance'
 
 const { proxy } = getCurrentInstance()
 
-const reviewStatusOptions = ref([
+// 截止日期计算
+const now = new Date()
+const currentDay = now.getDate()
+const currentMonth = now.getMonth() + 1
+const currentYear = now.getFullYear()
+const isOverdue = currentDay > 12
+
+const deadlineMessage = computed(() => {
+  if (isOverdue) {
+    return `本月填报已截止(12日),当前日期 ${currentMonth}月${currentDay}日。逾期未填报视为本月该部门无产值。`
+  }
+  const remainDays = 12 - currentDay
+  return `月度填报进行中,距离截止日期(${currentMonth}月12日)还有 ${remainDays} 天。请在截止前完成填报并提交审核!`
+})
+
+const deadlineType = computed(() => isOverdue ? 'error' : currentDay >= 8 ? 'warning' : 'success')
+
+// 选项数据
+const projectStatusOptions = [
+  { label: '已完成招投标在建', value: 'BIDDING_IN_PROGRESS', tagType: 'warning' },
+  { label: '前期策划但未开工', value: 'PLANNING_NOT_STARTED', tagType: 'info' },
+  { label: '前期策划并且同步开工', value: 'PLANNING_IN_PROGRESS', tagType: '' }
+]
+
+const reviewStatusOptions = [
   { label: '待提交', value: 'DRAFT' },
   { label: '已提交待审核', value: 'SUBMITTED' },
   { label: '审核通过', value: 'APPROVED' },
   { label: '审核不通过', value: 'REJECTED' }
-])
+]
+
+const reviewStatusTagOptions = [
+  { label: '待提交', value: 'DRAFT', tagType: 'info' },
+  { label: '已提交待审核', value: 'SUBMITTED', tagType: 'warning' },
+  { label: '审核通过', value: 'APPROVED', tagType: 'success' },
+  { label: '审核不通过', value: 'REJECTED', tagType: 'danger' }
+]
 
-const outputList = ref([])
-const open = ref(false)
-const loading = ref(true)
+const typeMap = {
+  'ENGINEERING': '工程项目',
+  'TECHNICAL_SERVICE': '技术服务',
+  'CONSULTING': '咨询服务',
+  'OTHER': '其他'
+}
+
+// 状态变量
+const activeTab = ref('pending')
+const loading = ref(false)
+const historyLoading = ref(false)
 const showSearch = ref(true)
-const ids = ref([])
-const single = ref(true)
-const multiple = ref(true)
-const total = ref(0)
-const title = ref('')
-const projectOptions = ref([])
-
-const data = reactive({
-  form: {},
-  queryParams: {
-    pageNum: 1,
-    pageSize: 10,
-    projectName: undefined,
-    month: undefined,
-    reviewStatus: undefined
-  },
-  rules: {
-    projectId: [{ required: true, message: '项目不能为空', trigger: 'change' }],
-    month: [{ required: true, message: '填报月份不能为空', trigger: 'change' }],
-    currentProgress: [{ required: true, message: '当月实际进度不能为空', trigger: 'blur' }],
-    currentOutput: [{ required: true, message: '当月实际产值不能为空', trigger: 'blur' }]
-  }
+const selectCount = ref(0)
+const draftCount = ref(0)
+const allSelected = ref(false)
+const historyTotal = ref(0)
+
+const pendingProjects = ref([])
+const selectedProjects = ref([])
+const historyList = ref([])
+const availableProjects = ref([])
+
+const batchOpen = ref(false)
+const singleOpen = ref(false)
+const detailOpen = ref(false)
+
+const singleTitle = ref('')
+
+const batchOutputs = reactive({})
+
+const detailData = reactive({})
+
+const batchForm = reactive({
+  month: undefined,
+  currentProgress: undefined,
+  description: undefined
 })
 
-const { queryParams, form, rules } = toRefs(data)
+const singleForm = reactive({
+  outputId: undefined,
+  projectId: undefined,
+  month: undefined,
+  currentProgress: undefined,
+  currentOutput: undefined,
+  coopOutput: undefined,
+  description: undefined
+})
+
+const historyParams = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  projectName: undefined,
+  month: undefined,
+  reviewStatus: undefined
+})
 
-function getList() {
+const outputFormRef = ref(null)
+
+const currentProject = computed(() => {
+  if (!singleForm.projectId) return {}
+  return pendingProjects.value.find(p => p.projectId === singleForm.projectId) || {}
+})
+
+const currentProjectHasCooperation = computed(() => !!currentProject.value.coopDeptName)
+
+const projectTotalOutputLimit = computed(() => {
+  const p = currentProject.value
+  return Math.max(0, (p.totalOutput || 0) - (p.filledOutput || 0))
+})
+
+// 加载待填报项目
+function getPendingProjects() {
   loading.value = true
-  listOutput(queryParams.value).then(res => {
-    outputList.value = res.rows
-    total.value = res.total
+  listProject({
+    pageNum: 1,
+    pageSize: 999,
+    status: 'BIDDING_IN_PROGRESS,PLANNING_IN_PROGRESS,PLANNING_NOT_STARTED',
+    myDept: true
+  }).then(res => {
+    pendingProjects.value = (res.rows || []).map(p => {
+      const remaining = Math.max(0, (p.totalOutput || 0) - (p.filledOutput || 0))
+      return {
+        ...p,
+        remainingOutput: remaining,
+        hasCooperation: !!p.coopDeptName
+      }
+    })
     loading.value = false
+    availableProjects.value = pendingProjects.value.map(p => ({
+      projectId: p.projectId,
+      projectName: p.projectName,
+      deptName: p.deptName,
+      totalOutput: p.totalOutput
+    }))
+  })
+}
+
+// 加载填报历史
+function getHistoryList() {
+  historyLoading.value = true
+  listOutput(historyParams).then(res => {
+    historyList.value = res.rows
+    historyTotal.value = res.total
+    historyLoading.value = false
   })
 }
 
 function handleQuery() {
-  queryParams.value.pageNum = 1
-  getList()
+  historyParams.pageNum = 1
+  getHistoryList()
 }
 
-function resetQuery() {
-  proxy.resetForm('queryRef')
+function resetHistoryQuery() {
+  proxy.resetForm('historyRef')
   handleQuery()
 }
 
-function handleSelectionChange(selection) {
-  ids.value = selection.map(item => item.outputId)
-  single.value = selection.length !== 1
-  multiple.value = !selection.length
+function handleTabChange(tab) {
+  if (tab === 'history') {
+    getHistoryList()
+  } else {
+    getPendingProjects()
+  }
 }
 
-function reset() {
-  form.value = {
-    outputId: undefined,
-    projectId: undefined,
-    month: undefined,
-    currentProgress: undefined,
-    currentOutput: undefined,
-    description: undefined
+// 选择操作
+function handlePendingSelection(selection) {
+  selectedProjects.value = selection
+  selectCount.value = selection.length
+  draftCount.value = selection.filter(item => item.draftId).length
+
+  // 初始化批量产值
+  selection.forEach(p => {
+    if (!(p.projectId in batchOutputs)) {
+      batchOutputs[p.projectId] = undefined
+    }
+  })
+}
+
+function toggleAllSelect() {
+  allSelected.value = !allSelected.value
+  const tableRef = proxy.$refs.pendingTableRef
+  if (allSelected.value) {
+    const unfilled = pendingProjects.value.filter(p => {
+      const remaining = (p.totalOutput || 0) - (p.filledOutput || 0)
+      return remaining > 0
+    })
+    unfilled.forEach(row => tableRef.toggleRowSelection(row, true))
+  } else {
+    tableRef.clearSelection()
   }
-  proxy.resetForm('outputRef')
 }
 
-function cancel() {
-  open.value = false
-  reset()
+// 批量填报
+function handleBatchAdd() {
+  if (selectedProjects.value.length === 0) {
+    proxy.$modal.msgWarning('请至少选择一个项目')
+    return
+  }
+  // 验证选中的项目都有剩余产值
+  const invalid = selectedProjects.value.filter(p => {
+    const remaining = (p.totalOutput || 0) - (p.filledOutput || 0)
+    return remaining <= 0
+  })
+  if (invalid.length > 0) {
+    proxy.$modal.msgWarning(`以下项目已无剩余产值: ${invalid.map(p => p.projectName).join('、')}`)
+    return
+  }
+  batchForm.month = `${currentYear}-${String(currentMonth).padStart(2, '0')}`
+  batchForm.currentProgress = undefined
+  batchForm.description = undefined
+  batchOpen.value = true
 }
 
-function handleAdd() {
-  reset()
-  open.value = true
-  title.value = '产值填报'
+function cancelBatch() {
+  batchOpen.value = false
 }
 
-function handleUpdate(row) {
-  reset()
-  getOutput(row.outputId).then(res => {
-    form.value = res.data
-    open.value = true
-    title.value = '修改产值填报'
+function buildBatchOutputData(submitNow) {
+  return selectedProjects.value.map(p => ({
+    projectId: p.projectId,
+    month: batchForm.month,
+    currentProgress: batchForm.currentProgress,
+    currentOutput: batchOutputs[p.projectId],
+    description: batchForm.description,
+    submitNow
+  }))
+}
+
+function submitBatchSave() {
+  if (!batchForm.month) {
+    proxy.$modal.msgWarning('请选择填报月份')
+    return
+  }
+  const batchData = buildBatchOutputData(false)
+  const invalid = batchData.filter(d => d.currentOutput == null || d.currentOutput < 0)
+  if (invalid.length > 0) {
+    proxy.$modal.msgWarning('请为所有项目填写当月产值')
+    return
+  }
+  batchOutput({ records: batchData }).then(() => {
+    proxy.$modal.msgSuccess('批量保存草稿成功')
+    batchOpen.value = false
+    getPendingProjects()
   })
 }
 
-function handleDetail(row) {
-  // TODO: 查看填报详情
+function submitBatchAndSubmit() {
+  if (!batchForm.month) {
+    proxy.$modal.msgWarning('请选择填报月份')
+    return
+  }
+  const batchData = buildBatchOutputData(true)
+  const invalid = batchData.filter(d => d.currentOutput == null || d.currentOutput < 0)
+  if (invalid.length > 0) {
+    proxy.$modal.msgWarning('请为所有项目填写当月产值')
+    return
+  }
+  if (isOverdue) {
+    proxy.$modal.confirm('当前已超过填报截止日期,确认仍要提交?提交后将进入审核流程。').then(() => {
+      return batchOutput({ records: batchData })
+    }).then(() => {
+      proxy.$modal.msgSuccess('批量提交成功')
+      batchOpen.value = false
+      getPendingProjects()
+    }).catch(() => {})
+    return
+  }
+  batchOutput({ records: batchData }).then(() => {
+    proxy.$modal.msgSuccess('批量提交成功')
+    batchOpen.value = false
+    getPendingProjects()
+  })
+}
+
+// 单个填报
+function handleSingleAdd(row) {
+  singleForm.outputId = row.draftId || undefined
+  singleForm.projectId = row.projectId
+  singleForm.month = row.draftMonth || `${currentYear}-${String(currentMonth).padStart(2, '0')}`
+  singleForm.currentProgress = row.draftProgress || undefined
+  singleForm.currentOutput = row.draftOutput || undefined
+  singleForm.coopOutput = row.draftCoopOutput || undefined
+  singleForm.description = row.draftDescription || undefined
+  singleTitle.value = row.draftId ? '修改产值草稿' : '产值填报'
+  singleOpen.value = true
+}
+
+function cancelSingle() {
+  singleOpen.value = false
+}
+
+function submitSingleSave() {
+  outputFormRef.value?.validate().then(valid => {
+    if (!valid) return
+    const data = { ...singleForm }
+    if (singleForm.outputId) {
+      updateOutput(data).then(() => {
+        proxy.$modal.msgSuccess('草稿已保存')
+        singleOpen.value = false
+        getPendingProjects()
+      })
+    } else {
+      addOutput(data).then(() => {
+        proxy.$modal.msgSuccess('草稿已保存')
+        singleOpen.value = false
+        getPendingProjects()
+      })
+    }
+  })
+}
+
+function submitSingleAndSubmit() {
+  outputFormRef.value?.validate().then(valid => {
+    if (!valid) return
+    const data = { ...singleForm }
+    const api = singleForm.outputId ? updateOutput : addOutput
+    api(data).then(() => {
+      return submitOutput(singleForm.outputId || data.outputId)
+    }).then(() => {
+      proxy.$modal.msgSuccess('已提交审核')
+      singleOpen.value = false
+      getPendingProjects()
+    })
+  })
 }
 
-function handleSubmit(row) {
-  proxy.$modal.confirm('确认提交该条产值填报?提交后将无法修改。').then(() => {
-    return submitOutput(row.outputId)
+function handleSubmitSingle(row) {
+  if (!row.draftId) return
+  proxy.$modal.confirm('确认提交该草稿?提交后将进入审核流程。').then(() => {
+    return submitOutput(row.draftId)
   }).then(() => {
     proxy.$modal.msgSuccess('提交成功')
-    getList()
+    getPendingProjects()
   }).catch(() => {})
 }
 
 function handleBatchSubmit() {
-  if (ids.value.length === 0) {
-    proxy.$modal.msgWarning('请选择要提交的填报记录')
+  if (draftCount.value === 0) {
+    proxy.$modal.msgWarning('没有可提交的草稿')
     return
   }
-  proxy.$modal.confirm('确认批量提交选中的产值填报?').then(() => {
-    const tasks = ids.value.map(id => submitOutput(id))
+  proxy.$modal.confirm(`确认批量提交 ${draftCount.value} 条草稿?`).then(() => {
+    const tasks = selectedProjects.value.filter(p => p.draftId).map(p => submitOutput(p.draftId))
     return Promise.all(tasks)
   }).then(() => {
     proxy.$modal.msgSuccess('批量提交成功')
-    getList()
+    getPendingProjects()
   }).catch(() => {})
 }
 
-function handleExport() {
-  proxy.download('/performance/output/export', { ...queryParams.value }, `output_${new Date().getTime()}.xlsx`)
-}
-
-function submitForm() {
-  proxy.$refs.outputRef.validate(valid => {
-    if (valid) {
-      if (form.value.outputId) {
-        updateOutput(form.value).then(() => {
-          proxy.$modal.msgSuccess('修改成功')
-          open.value = false
-          getList()
-        })
-      } else {
-        addOutput(form.value).then(() => {
-          proxy.$modal.msgSuccess('填报成功')
-          open.value = false
-          getList()
-        })
-      }
-    }
+// 历史操作
+function handleUpdate(row) {
+  getOutput(row.outputId).then(res => {
+    Object.assign(singleForm, res.data)
+    singleTitle.value = '修改产值填报'
+    singleOpen.value = true
   })
 }
 
+function handleViewDetail(row) {
+  Object.assign(detailData, row)
+  detailOpen.value = true
+}
+
+function handleExport() {
+  proxy.download('/performance/output/export', { ...historyParams }, `output_${new Date().getTime()}.xlsx`)
+}
+
 onMounted(() => {
-  getList()
+  getPendingProjects()
 })
 </script>
+
+<style lang="scss" scoped>
+.mb16 {
+  margin-bottom: 16px;
+}
+</style>