From 2ba24b9d1265d02f2f3d1f828f0e0bfb8fa9125e Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期三, 24 九月 2025 16:13:20 +0800
Subject: [PATCH] 自动生成项目总结报

---
 src/views/collaborativeApproval/reportGeneration/index.vue |  596 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 596 insertions(+), 0 deletions(-)

diff --git a/src/views/collaborativeApproval/reportGeneration/index.vue b/src/views/collaborativeApproval/reportGeneration/index.vue
new file mode 100644
index 0000000..c160ad7
--- /dev/null
+++ b/src/views/collaborativeApproval/reportGeneration/index.vue
@@ -0,0 +1,596 @@
+<template>
+  <div class="report-generation">
+    <!-- 椤甸潰澶撮儴 -->
+    <div class="page-header">
+      <h2>椤圭洰鎬荤粨鎶ュ憡鐢熸垚</h2>
+      <div class="header-actions">
+        <el-button v-if="!reportGenerated" type="primary" @click="generateReport" :loading="generating">
+          <el-icon><Document /></el-icon>
+          鐢熸垚鎶ュ憡
+        </el-button>
+        <el-button v-if="reportGenerated" type="primary" @click="resetConfig">
+          <el-icon><Refresh /></el-icon>
+          鐢熸垚鏂版姤鍛�
+        </el-button>
+        <el-button @click="exportReport" :disabled="!reportGenerated">
+          <el-icon><Download /></el-icon>
+          瀵煎嚭鎶ュ憡
+        </el-button>
+      </div>
+    </div>
+
+    <!-- 鎶ュ憡閰嶇疆鍖哄煙 -->
+    <el-card class="config-card" v-if="!reportGenerated">
+      <template #header>
+        <span>鎶ュ憡閰嶇疆</span>
+      </template>
+      <el-form :model="reportConfig" label-width="120px">
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="椤圭洰鍚嶇О">
+              <el-select v-model="reportConfig.projectId" placeholder="璇烽�夋嫨椤圭洰">
+                <el-option
+                  v-for="project in projectList"
+                  :key="project.id"
+                  :label="project.name"
+                  :value="project.id"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鎶ュ憡鍛ㄦ湡">
+              <el-date-picker
+                v-model="reportConfig.dateRange"
+                type="daterange"
+                range-separator="鑷�"
+                start-placeholder="寮�濮嬫棩鏈�"
+                end-placeholder="缁撴潫鏃ユ湡"
+                format="YYYY-MM-DD"
+                value-format="YYYY-MM-DD"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </el-card>
+
+    <!-- 鎶ュ憡鍐呭灞曠ず鍖哄煙 -->
+    <div v-if="reportGenerated" class="report-content">
+      <!-- 椤圭洰鍩烘湰淇℃伅 -->
+      <el-card class="report-section">
+        <template #header>
+          <span>椤圭洰鍩烘湰淇℃伅</span>
+        </template>
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="椤圭洰鍚嶇О">{{ reportData.projectInfo.name }}</el-descriptions-item>
+          <el-descriptions-item label="椤圭洰缁忕悊">{{ reportData.projectInfo.manager }}</el-descriptions-item>
+          <el-descriptions-item label="寮�濮嬫椂闂�">{{ reportData.projectInfo.startDate }}</el-descriptions-item>
+          <el-descriptions-item label="缁撴潫鏃堕棿">{{ reportData.projectInfo.endDate }}</el-descriptions-item>
+          <el-descriptions-item label="椤圭洰鐘舵��">
+            <el-tag :type="getStatusType(reportData.projectInfo.status)">
+              {{ reportData.projectInfo.status }}
+            </el-tag>
+          </el-descriptions-item>
+          <el-descriptions-item label="鎬婚绠�">{{ reportData.projectInfo.budget }}</el-descriptions-item>
+        </el-descriptions>
+      </el-card>
+
+      <!-- 浠诲姟瀹屾垚鐜囩粺璁� -->
+      <el-card class="report-section">
+        <template #header>
+          <span>浠诲姟瀹屾垚鐜囩粺璁�</span>
+        </template>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <div class="completion-stats">
+              <div class="stat-item">
+                <div class="stat-label">鎬讳换鍔℃暟</div>
+                <div class="stat-value">{{ reportData.taskStats.total }}</div>
+              </div>
+              <div class="stat-item">
+                <div class="stat-label">宸插畬鎴�</div>
+                <div class="stat-value completed">{{ reportData.taskStats.completed }}</div>
+              </div>
+              <div class="stat-item">
+                <div class="stat-label">杩涜涓�</div>
+                <div class="stat-value in-progress">{{ reportData.taskStats.inProgress }}</div>
+              </div>
+              <div class="stat-item">
+                <div class="stat-label">鏈紑濮�</div>
+                <div class="stat-value pending">{{ reportData.taskStats.pending }}</div>
+              </div>
+            </div>
+          </el-col>
+          <el-col :span="12">
+            <div class="completion-rate">
+              <el-progress
+                type="circle"
+                :percentage="reportData.taskStats.completionRate"
+                :width="150"
+                :stroke-width="8"
+              >
+                <template #default="{ percentage }">
+                  <span class="percentage-value">{{ percentage }}%</span>
+                  <div class="percentage-label">瀹屾垚鐜�</div>
+                </template>
+              </el-progress>
+            </div>
+          </el-col>
+        </el-row>
+      </el-card>
+
+      <!-- 闂璁板綍缁熻 -->
+      <el-card class="report-section">
+        <template #header>
+          <span>闂璁板綍缁熻</span>
+        </template>
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <div class="issue-summary">
+              <div class="summary-item">
+                <div class="summary-label">鎬婚棶棰樻暟</div>
+                <div class="summary-value">{{ reportData.issueStats.total }}</div>
+              </div>
+              <div class="summary-item">
+                <div class="summary-label">宸茶В鍐�</div>
+                <div class="summary-value resolved">{{ reportData.issueStats.resolved }}</div>
+              </div>
+              <div class="summary-item">
+                <div class="summary-label">寰呰В鍐�</div>
+                <div class="summary-value pending">{{ reportData.issueStats.pending }}</div>
+              </div>
+            </div>
+          </el-col>
+          <el-col :span="16">
+            <el-table :data="reportData.issueStats.topIssues" size="small">
+              <el-table-column prop="title" label="涓昏闂" />
+              <el-table-column prop="severity" label="涓ラ噸绋嬪害" width="100">
+                <template #default="{ row }">
+                  <el-tag :type="getSeverityType(row.severity)" size="small">
+                    {{ row.severity }}
+                  </el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column prop="status" label="鐘舵��" width="80">
+                <template #default="{ row }">
+                  <el-tag :type="row.status === '宸茶В鍐�' ? 'success' : 'warning'" size="small">
+                    {{ row.status }}
+                  </el-tag>
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-col>
+        </el-row>
+      </el-card>
+
+      <!-- 寤惰鍒嗘瀽 -->
+      <el-card class="report-section">
+        <template #header>
+          <span>寤惰鍒嗘瀽</span>
+        </template>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <div class="delay-stats">
+              <div class="delay-item">
+                <div class="delay-label">寤惰浠诲姟鏁�</div>
+                <div class="delay-value">{{ reportData.delayAnalysis.delayedTasks }}</div>
+              </div>
+              <div class="delay-item">
+                <div class="delay-label">骞冲潎寤惰澶╂暟</div>
+                <div class="delay-value">{{ reportData.delayAnalysis.avgDelayDays }}</div>
+              </div>
+              <div class="delay-item">
+                <div class="delay-label">鏈�澶у欢璇ぉ鏁�</div>
+                <div class="delay-value">{{ reportData.delayAnalysis.maxDelayDays }}</div>
+              </div>
+            </div>
+          </el-col>
+          <el-col :span="12">
+            <div class="delay-reasons">
+              <h4>涓昏寤惰鍘熷洜</h4>
+              <ul>
+                <li v-for="reason in reportData.delayAnalysis.reasons" :key="reason.reason">
+                  {{ reason.reason }} ({{ reason.count }}娆�)
+                </li>
+              </ul>
+            </div>
+          </el-col>
+        </el-row>
+      </el-card>
+
+      <!-- 鍥㈤槦缁╂晥 -->
+      <el-card class="report-section">
+        <template #header>
+          <span>鍥㈤槦缁╂晥</span>
+        </template>
+        <el-table :data="reportData.teamPerformance" size="small">
+          <el-table-column prop="name" label="鎴愬憳濮撳悕" />
+          <el-table-column prop="completedTasks" label="瀹屾垚浠诲姟鏁�" />
+          <el-table-column prop="completionRate" label="瀹屾垚鐜�" width="100">
+            <template #default="{ row }">
+              <el-progress :percentage="row.completionRate" :show-text="false" />
+              <span style="margin-left: 10px;">{{ row.completionRate }}%</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="performance" label="缁╂晥璇勭骇" width="100">
+            <template #default="{ row }">
+              <el-tag :type="getPerformanceType(row.performance)">
+                {{ row.performance }}
+              </el-tag>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-card>
+
+      <!-- 鎬荤粨涓庡缓璁� -->
+      <el-card class="report-section">
+        <template #header>
+          <span>鎬荤粨涓庡缓璁�</span>
+        </template>
+        <div class="summary-content">
+          <h4>椤圭洰鎬荤粨</h4>
+          <p>{{ reportData.summary.conclusion }}</p>
+          
+          <h4>鏀硅繘寤鸿</h4>
+          <ul>
+            <li v-for="suggestion in reportData.summary.suggestions" :key="suggestion">
+              {{ suggestion }}
+            </li>
+          </ul>
+        </div>
+      </el-card>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted } from 'vue'
+import { Document, Download, Refresh } from '@element-plus/icons-vue'
+import { ElMessage } from 'element-plus'
+
+// 鍝嶅簲寮忔暟鎹�
+const generating = ref(false)
+const reportGenerated = ref(false)
+
+// 鎶ュ憡閰嶇疆
+const reportConfig = reactive({
+  projectId: '',
+  dateRange: []
+})
+
+// 椤圭洰鍒楄〃
+const projectList = ref([
+  { id: 1, name: '浜у搧搴撳瓨绠$悊绯荤粺' },
+  { id: 2, name: '瀹㈡埛鍏崇郴绠$悊骞冲彴' },
+  { id: 3, name: '璐㈠姟绠$悊绯荤粺鍗囩骇' },
+  { id: 4, name: '绉诲姩绔簲鐢ㄥ紑鍙�' }
+])
+
+// 鎶ュ憡鏁版嵁
+const reportData = ref({})
+
+// 妯℃嫙鎶ュ憡鏁版嵁
+const mockReportData = {
+  projectInfo: {
+    name: '浜у搧搴撳瓨绠$悊绯荤粺',
+    manager: '寮犱笁',
+    startDate: '2024-01-01',
+    endDate: '2024-03-31',
+    status: '宸插畬鎴�',
+    budget: '楼500,000'
+  },
+  taskStats: {
+    total: 45,
+    completed: 38,
+    inProgress: 5,
+    pending: 2,
+    completionRate: 84
+  },
+  issueStats: {
+    total: 12,
+    resolved: 9,
+    pending: 3,
+    topIssues: [
+      { title: '鏁版嵁搴撹繛鎺ヨ秴鏃�', severity: '楂�', status: '宸茶В鍐�' },
+      { title: '鍓嶇椤甸潰鍝嶅簲鎱�', severity: '涓�', status: '宸茶В鍐�' },
+      { title: '鏉冮檺楠岃瘉寮傚父', severity: '楂�', status: '寰呰В鍐�' },
+      { title: '鎶ヨ〃瀵煎嚭鍔熻兘缂哄け', severity: '涓�', status: '寰呰В鍐�' }
+    ]
+  },
+  delayAnalysis: {
+    delayedTasks: 8,
+    avgDelayDays: 3.5,
+    maxDelayDays: 12,
+    reasons: [
+      { reason: '闇�姹傚彉鏇�', count: 3 },
+      { reason: '鎶�鏈毦棰�', count: 2 },
+      { reason: '璧勬簮涓嶈冻', count: 2 },
+      { reason: '澶栭儴渚濊禆', count: 1 }
+    ]
+  },
+  teamPerformance: [
+    { name: '鏉庡洓', completedTasks: 12, completionRate: 92, performance: '浼樼' },
+    { name: '鐜嬩簲', completedTasks: 10, completionRate: 85, performance: '鑹ソ' },
+    { name: '璧靛叚', completedTasks: 8, completionRate: 78, performance: '鑹ソ' },
+    { name: '閽变竷', completedTasks: 8, completionRate: 72, performance: '涓�鑸�' }
+  ],
+  summary: {
+    conclusion: '鏈」鐩暣浣撴墽琛屾儏鍐佃壇濂斤紝浠诲姟瀹屾垚鐜囪揪鍒�84%锛屽洟闃熷崗浣滄晥鐜囪緝楂樸�備富瑕侀棶棰橀泦涓湪鎶�鏈疄鐜板拰闇�姹傚彉鏇存柟闈紝閫氳繃鍙婃椂娌熼�氬拰鎶�鏈敾鍏筹紝澶ч儴鍒嗛棶棰樺凡寰楀埌瑙e喅銆�',
+    suggestions: [
+      '鍔犲己闇�姹傚垎鏋愰樁娈电殑宸ヤ綔锛屽噺灏戝悗鏈熼渶姹傚彉鏇�',
+      '寤虹珛鎶�鏈毦棰橀璀︽満鍒讹紝鎻愬墠璇嗗埆鍜岃В鍐虫妧鏈闄�',
+      '浼樺寲鍥㈤槦璧勬簮閰嶇疆锛屾彁楂樻暣浣撳伐浣滄晥鐜�',
+      '瀹屽杽椤圭洰绠$悊娴佺▼锛屽姞寮鸿繃绋嬬洃鎺�'
+    ]
+  }
+}
+
+// 鐢熸垚鎶ュ憡
+const generateReport = async () => {
+  if (!reportConfig.projectId) {
+    ElMessage.warning('璇烽�夋嫨椤圭洰')
+    return
+  }
+  
+  generating.value = true
+  
+  // 妯℃嫙鐢熸垚鎶ュ憡鐨勮繃绋�
+  setTimeout(() => {
+    reportData.value = mockReportData
+    reportGenerated.value = true
+    generating.value = false
+    ElMessage.success('鎶ュ憡鐢熸垚鎴愬姛')
+  }, 2000)
+}
+
+// 瀵煎嚭鎶ュ憡
+const exportReport = () => {
+  ElMessage.success('鎶ュ憡瀵煎嚭鍔熻兘寮�鍙戜腑...')
+}
+
+// 閲嶇疆閰嶇疆锛岀敓鎴愭柊鎶ュ憡
+const resetConfig = () => {
+  reportGenerated.value = false
+  reportData.value = {}
+  // 閲嶇疆閰嶇疆涓洪粯璁ゅ��
+  reportConfig.projectId = 1
+  const endDate = new Date()
+  const startDate = new Date()
+  startDate.setDate(startDate.getDate() - 30)
+  reportConfig.dateRange = [
+    startDate.toISOString().split('T')[0],
+    endDate.toISOString().split('T')[0]
+  ]
+  ElMessage.success('宸查噸缃厤缃紝鍙互鐢熸垚鏂版姤鍛�')
+}
+
+// 鑾峰彇鐘舵�佺被鍨�
+const getStatusType = (status) => {
+  const statusMap = {
+    '宸插畬鎴�': 'success',
+    '杩涜涓�': 'warning',
+    '鏈紑濮�': 'info',
+    '宸叉殏鍋�': 'danger'
+  }
+  return statusMap[status] || 'info'
+}
+
+// 鑾峰彇涓ラ噸绋嬪害绫诲瀷
+const getSeverityType = (severity) => {
+  const severityMap = {
+    '楂�': 'danger',
+    '涓�': 'warning',
+    '浣�': 'success'
+  }
+  return severityMap[severity] || 'info'
+}
+
+// 鑾峰彇缁╂晥绫诲瀷
+const getPerformanceType = (performance) => {
+  const performanceMap = {
+    '浼樼': 'success',
+    '鑹ソ': 'primary',
+    '涓�鑸�': 'warning',
+    '寰呮敼杩�': 'danger'
+  }
+  return performanceMap[performance] || 'info'
+}
+
+// 缁勪欢鎸傝浇鏃跺垵濮嬪寲
+onMounted(() => {
+  // 璁剧疆榛樿椤圭洰
+  reportConfig.projectId = 1
+  // 璁剧疆榛樿鏃ユ湡鑼冨洿锛堟渶杩�30澶╋級
+  const endDate = new Date()
+  const startDate = new Date()
+  startDate.setDate(startDate.getDate() - 30)
+  reportConfig.dateRange = [
+    startDate.toISOString().split('T')[0],
+    endDate.toISOString().split('T')[0]
+  ]
+})
+</script>
+
+<style scoped>
+.report-generation {
+  padding: 20px;
+}
+
+.page-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+}
+
+.page-header h2 {
+  margin: 0;
+  color: #303133;
+}
+
+.header-actions {
+  display: flex;
+  gap: 10px;
+}
+
+.config-card {
+  margin-bottom: 20px;
+}
+
+.report-content {
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+}
+
+.report-section {
+  margin-bottom: 20px;
+}
+
+.completion-stats {
+  display: flex;
+  justify-content: space-around;
+  padding: 20px 0;
+}
+
+.stat-item {
+  text-align: center;
+}
+
+.stat-label {
+  font-size: 14px;
+  color: #909399;
+  margin-bottom: 8px;
+}
+
+.stat-value {
+  font-size: 24px;
+  font-weight: bold;
+  color: #303133;
+}
+
+.stat-value.completed {
+  color: #67c23a;
+}
+
+.stat-value.in-progress {
+  color: #e6a23c;
+}
+
+.stat-value.pending {
+  color: #909399;
+}
+
+.completion-rate {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 200px;
+}
+
+.percentage-value {
+  font-size: 20px;
+  font-weight: bold;
+  color: #409eff;
+}
+
+.percentage-label {
+  font-size: 12px;
+  color: #909399;
+  margin-top: 4px;
+}
+
+.issue-summary {
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+  padding: 20px 0;
+}
+
+.summary-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.summary-label {
+  font-size: 14px;
+  color: #606266;
+}
+
+.summary-value {
+  font-size: 18px;
+  font-weight: bold;
+  color: #303133;
+}
+
+.summary-value.resolved {
+  color: #67c23a;
+}
+
+.summary-value.pending {
+  color: #e6a23c;
+}
+
+.delay-stats {
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+  padding: 20px 0;
+}
+
+.delay-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.delay-label {
+  font-size: 14px;
+  color: #606266;
+}
+
+.delay-value {
+  font-size: 18px;
+  font-weight: bold;
+  color: #e6a23c;
+}
+
+.delay-reasons h4 {
+  margin: 0 0 15px 0;
+  color: #303133;
+}
+
+.delay-reasons ul {
+  margin: 0;
+  padding-left: 20px;
+}
+
+.delay-reasons li {
+  margin-bottom: 8px;
+  color: #606266;
+}
+
+.summary-content h4 {
+  margin: 0 0 10px 0;
+  color: #303133;
+}
+
+.summary-content p {
+  line-height: 1.6;
+  color: #606266;
+  margin-bottom: 20px;
+}
+
+.summary-content ul {
+  margin: 0;
+  padding-left: 20px;
+}
+
+.summary-content li {
+  margin-bottom: 8px;
+  color: #606266;
+  line-height: 1.5;
+}
+</style>
\ No newline at end of file

--
Gitblit v1.9.3