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