6ae0fcef149ddbe614746023a58a3885b3ac4bde..1fa6ac40e2ce16e1174cec9ca538d45eeb660fdc
2025-06-05 xiangpei
工作台
1fa6ac 对比 | 目录
2025-06-05 xiangpei
首页
833d0b 对比 | 目录
2025-06-05 xiangpei
系统名称调整、登录页调整、项目新增发起依据
d328bd 对比 | 目录
11个文件已修改
3个文件已添加
1577 ■■■■■ 已修改文件
.env.development 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.production 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.staging 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/ruoyi.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/FileUpload/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Navbar.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/index-nongtou.vue 882 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login.vue 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/projectEngineering/projectLibrary/component/ProjectFrom.vue 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/projectEngineering/projectLibrary/projectDetails.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/workbench.vue 596 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vue.config.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.development
@@ -1,10 +1,10 @@
# 页面标题
VUE_APP_TITLE = 射洪智慧项目管理系统
VUE_APP_TITLE = 农投项目管理系统
# 开发环境配置
ENV = 'development'
# 射洪智慧项目管理系统/开发环境
# 农投项目管理系统/开发环境
VUE_APP_BASE_API = '/dev-api'
# 路由懒加载
.env.production
@@ -1,10 +1,10 @@
# 页面标题
VUE_APP_TITLE = 射洪智慧项目管理系统
VUE_APP_TITLE = 农投项目管理系统
# 生产环境配置
ENV = 'production'
# 射洪智慧项目管理系统/生产环境
# 农投项目管理系统/生产环境
VUE_APP_BASE_API = '/prod-api'
# 开打新的tab的url前缀
.env.staging
@@ -1,5 +1,5 @@
# 页面标题
VUE_APP_TITLE = 射洪智慧项目管理系统
VUE_APP_TITLE = 农投项目管理系统
BABEL_ENV = production
@@ -8,5 +8,5 @@
# 测试环境配置
ENV = 'staging'
# 射洪智慧项目管理系统/测试环境
# 农投项目管理系统/测试环境
VUE_APP_BASE_API = '/stage-api'
package.json
@@ -1,7 +1,7 @@
{
  "name": "ruoyi",
  "version": "3.8.8",
  "description": "射洪智慧项目管理系统",
  "description": "农投项目管理系统",
  "author": "射洪项目",
  "license": "MIT",
  "scripts": {
src/assets/styles/ruoyi.scss
@@ -197,7 +197,7 @@
}
.el-card__header {
  padding: 14px 15px 7px !important;
  padding: 7px 15px 7px !important;
  min-height: 40px;
}
src/components/FileUpload/index.vue
@@ -61,7 +61,7 @@
    // 文件类型, 例如['png', 'jpg', 'jpeg']
    fileType: {
      type: Array,
      default: () => ["doc", "xls", "ppt", "txt", "pdf"],
      default: () => ["doc", "docx", "xls", "xlsx", "ppt", "txt", "pdf", "jpg", "png"],
    },
    // 是否显示提示
    isShowTip: {
src/layout/components/Navbar.vue
@@ -2,7 +2,7 @@
    <div class="navbar">
        <div class="ruoyi-logo">
            <img src="@/assets/logo/logo.png" alt="" />
            <span>射洪智慧项目管理系统</span>
            <span>农投项目管理系统</span>
        </div>
        <div class="right-menu flex align-center">
          <div style="color: rgb(49,48,48);margin-right: 30px;font-size: 16px">
src/router/index.js
@@ -68,7 +68,7 @@
    children: [
      {
        path: 'index',
        component: () => import('@/views/index'),
        component: () => import('@/views/index-nongtou'),
        name: 'Index',
        meta: { title: '首页', icon: 'dashboard', affix: true }
      }
src/views/index-nongtou.vue
New file
@@ -0,0 +1,882 @@
<template>
  <div class="project-management-container">
    <!-- 页面标题 -->
<!--    <div class="page-header">-->
<!--      <h1>项目管理系统</h1>-->
<!--      <div class="user-info">-->
<!--        <span>欢迎,{{ userName }}</span>-->
<!--        <el-avatar :size="36" :src="userAvatar"></el-avatar>-->
<!--      </div>-->
<!--    </div>-->
    <!-- 数据概览卡片 -->
    <div class="overview-cards">
      <el-card class="overview-card" shadow="hover">
        <div class="card-content">
          <div class="card-icon" style="background-color: #409EFF20;">
            <i class="el-icon-s-data" style="color: #409EFF;"></i>
          </div>
          <div class="card-info">
            <div class="card-title">项目总数</div>
            <div class="card-value">{{ overviewData.totalProjects }}</div>
          </div>
        </div>
      </el-card>
      <el-card class="overview-card" shadow="hover">
        <div class="card-content">
          <div class="card-icon" style="background-color: #67C23A20;">
            <i class="el-icon-success" style="color: #67C23A;"></i>
          </div>
          <div class="card-info">
            <div class="card-title">进行中</div>
            <div class="card-value">{{ overviewData.inProgress }}</div>
          </div>
        </div>
      </el-card>
      <el-card class="overview-card" shadow="hover">
        <div class="card-content">
          <div class="card-icon" style="background-color: #E6A23C20;">
            <i class="el-icon-warning" style="color: #E6A23C;"></i>
          </div>
          <div class="card-info">
            <div class="card-title">有风险</div>
            <div class="card-value">{{ overviewData.atRisk }}</div>
          </div>
        </div>
      </el-card>
      <el-card class="overview-card" shadow="hover">
        <div class="card-content">
          <div class="card-icon" style="background-color: #F56C6C20;">
            <i class="el-icon-error" style="color: #F56C6C;"></i>
          </div>
          <div class="card-info">
            <div class="card-title">已延期</div>
            <div class="card-value">{{ overviewData.delayed }}</div>
          </div>
        </div>
      </el-card>
    </div>
    <!-- 主要内容区域 -->
    <div class="main-content">
      <!-- 左侧内容 -->
      <div class="left-content">
        <!-- 项目进度图表 -->
        <el-card class="chart-card" style="min-height: 400px" shadow="hover">
          <div slot="header" class="clearfix row">
            <div style="flex: 1">项目进度统计</div>
            <div style="flex: 3;display: flex;justify-content: flex-end">
              <el-select
                v-model="selectedMonth"
                placeholder="选择月份"
                style="width: 120px; margin-right: 10px;"
                @change="updateProgressChart"
              >
                <el-option
                  v-for="month in months"
                  :key="month.value"
                  :label="month.label"
                  :value="month.value"
                ></el-option>
              </el-select>
              <el-select
                v-model="selectedProjects"
                multiple
                collapse-tags
                placeholder="选择项目"
                style="width: 350px; margin-right: 10px;"
                @change="updateProgressChart"
              >
                <el-option
                  v-for="project in allProjects"
                  :key="project.id"
                  :label="project.name"
                  :value="project.id"
                ></el-option>
              </el-select>
              <el-button type="text" @click="showDetail">详情</el-button>
            </div>
          </div>
          <div class="chart-container" ref="progressChart" style="height: 400px;"></div>
        </el-card>
        <!-- 卡点任务列表 -->
        <el-card class="blocking-tasks-card" shadow="hover">
          <div slot="header" class="clearfix row">
            <div style="flex: 1">推进卡点</div>
            <div style="flex: 3; display: flex; justify-content: flex-end">
              <el-button type="text">全部</el-button>
            </div>
          </div>
          <el-table :data="blockingTasks" style="width: 100%" height="250">
            <el-table-column prop="taskName" label="任务名称" width="180"></el-table-column>
            <el-table-column prop="project" label="所属项目"></el-table-column>
            <el-table-column prop="owner" label="负责人" width="100"></el-table-column>
            <el-table-column prop="startTime" label="开始时间" width="120"></el-table-column>
            <el-table-column prop="deadline" label="截止日期" width="120"></el-table-column>
            <el-table-column prop="overTime" label="已超时" width="120"></el-table-column>
            <el-table-column prop="totalOverTimes" label="累计超时次数" width="120" align="center"></el-table-column>
            <el-table-column label="操作" width="80">
              <template slot-scope="scope">
                <el-button size="mini" @click="handleTaskDetail(scope.row)">查看</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-card>
      </div>
      <!-- 右侧内容 -->
      <div class="right-content">
        <!-- 资金使用情况 -->
        <el-card class="chart-card" style="min-height: 400px" shadow="hover">
          <div slot="header" class="clearfix">
            <span>资金使用情况</span>
            <div style="float: right;">
              <el-select
                v-model="fundSelectedProjects"
                multiple
                collapse-tags
                placeholder="选择项目"
                style="width: 350px; margin-right: 10px;"
                @change="updateFundChart"
              >
                <el-option
                  v-for="project in allProjects"
                  :key="project.id"
                  :label="project.name"
                  :value="project.id"
                ></el-option>
              </el-select>
              <el-button type="text" @click="showFundDetail">详情</el-button>
            </div>
          </div>
          <div class="chart-container" ref="fundChart" style="height: 400px;"></div>
        </el-card>
        <!-- 项目阶段统计 -->
        <el-card class="chart-card" shadow="hover">
          <div slot="header" class="clearfix row">
            <div style="flex:1">项目阶段统计</div>
            <div style="flex:3;display: flex;justify-content: flex-end">
              <el-button type="text">详情</el-button>
            </div>
          </div>
          <div class="chart-container" ref="stageChart" style="height: 250px;"></div>
        </el-card>
      </div>
    </div>
  </div>
</template>
<script>
import * as echarts from 'echarts';
export default {
  name: 'ProjectManagement',
  data() {
    return {
      userName: '张经理',
      userAvatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
      overviewData: {
        totalProjects: 42,
        inProgress: 28,
        atRisk: 7,
        delayed: 5
      },
      blockingTasks: [
        {
          taskName: '取得土地权属',
          project: '射洪市酒粮基地建设项目',
          owner: '李四',
          startTime: '2025-05-15',
          overTime: '10天06小时',
          deadline: '2025-06-05',
          totalOverTimes: 4,
          status: '紧急'
        },
        {
          taskName: '可行性研究报告申请',
          project: '射洪市酒粮基地建设项目',
          owner: '王五',
          startTime: '2025-05-21',
          overTime: '8天',
          deadline: '2025-05-30',
          totalOverTimes: '5',
          status: '高风险'
        },
        {
          taskName: '建设工程竣工验收申请',
          project: '射洪市宜居宜业和美乡村建设项目',
          owner: '赵六',
          startTime: '2025-05-24',
          overTime: '4天14小时',
          deadline: '2025-06-04',
          totalOverTimes: '4',
          status: '延期'
        },
        {
          taskName: '生产建设项目水土保持方案编制',
          project: '射洪市宜居宜业和美乡村建设项目',
          owner: '钱七',
          startTime: '2025-06-01',
          overTime: '4天',
          deadline: '2025-06-07',
          totalOverTimes: '6',
          status: '进行中'
        },
      ],
      progressChart: null,
      fundChart: null,
      stageChart: null,
      // 筛选数据
      selectedMonth: '2025-06',
      months: [
        { value: '2025-05', label: '2025年5月' },
        { value: '2025-06', label: '2025年6月' },
        { value: '2025-07', label: '2025年7月' },
        { value: '2025-08', label: '2025年8月' }
      ],
      selectedProjects: [],
      fundSelectedProjects: [],
      allProjects: [
        { id: 'p1', name: '射洪市国家储备林建设项目(一期)' },
        { id: 'p2', name: '射洪市白羽肉鸡产业建设项目' },
        { id: 'p3', name: '遂宁市射洪2024—2027年度东北片区高标准农田建设项目' },
        { id: 'p4', name: '射洪市现代种业示范基地建设项目' },
        { id: 'p5', name: '射洪市宜居宜业和美乡村建设项目' },
        { id: 'p6', name: '射洪市沱牌镇综合水利设施建设项目' }
      ],
      // 项目进度模拟数据
      progressData: {
        '2025-05': {
          'p1': { completed: 30, inProgress: 50, notStarted: 20 },
          'p2': { completed: 40, inProgress: 40, notStarted: 20 },
          'p3': { completed: 10, inProgress: 60, notStarted: 30 },
          'p4': { completed: 60, inProgress: 30, notStarted: 10 },
          'p5': { completed: 25, inProgress: 45, notStarted: 30 },
          'p6': { completed: 35, inProgress: 35, notStarted: 30 }
        },
        '2025-06': {
          'p1': { completed: 50, inProgress: 40, notStarted: 10 },
          'p2': { completed: 60, inProgress: 30, notStarted: 10 },
          'p3': { completed: 30, inProgress: 50, notStarted: 20 },
          'p4': { completed: 80, inProgress: 15, notStarted: 5 },
          'p5': { completed: 45, inProgress: 35, notStarted: 20 },
          'p6': { completed: 55, inProgress: 25, notStarted: 20 }
        },
        '2025-07': {
          'p1': { completed: 70, inProgress: 25, notStarted: 5 },
          'p2': { completed: 80, inProgress: 15, notStarted: 5 },
          'p3': { completed: 50, inProgress: 40, notStarted: 10 },
          'p4': { completed: 90, inProgress: 10, notStarted: 0 },
          'p5': { completed: 65, inProgress: 25, notStarted: 10 },
          'p6': { completed: 75, inProgress: 15, notStarted: 10 }
        },
        '2025-08': {
          'p1': { completed: 90, inProgress: 10, notStarted: 0 },
          'p2': { completed: 95, inProgress: 5, notStarted: 0 },
          'p3': { completed: 70, inProgress: 25, notStarted: 5 },
          'p4': { completed: 100, inProgress: 0, notStarted: 0 },
          'p5': { completed: 85, inProgress: 10, notStarted: 5 },
          'p6': { completed: 90, inProgress: 5, notStarted: 5 }
        }
      },
      // 资金使用模拟数据
      fundData: {
        'p1': {
          total: 5000,
          allocated: 3500,
          remaining: 1500,
          completed: 2800,
          sources: {
            projectCapital: 2000,
            countyInvestment: 1500,
            otherInvestment: 1000,
            governmentInvestment: 500
          }
        },
        'p2': {
          total: 3200,
          allocated: 2500,
          remaining: 700,
          completed: 1800,
          sources: {
            projectCapital: 1200,
            countyInvestment: 1000,
            governmentInvestment: 1000
          }
        },
        'p3': {
          total: 4200,
          allocated: 3000,
          remaining: 1200,
          completed: 2200,
          sources: {
            projectCapital: 1500,
            otherInvestment: 1200,
            governmentInvestment: 1500
          }
        },
        'p4': {
          total: 2800,
          allocated: 2000,
          remaining: 800,
          completed: 1500,
          sources: {
            projectCapital: 1000,
            countyInvestment: 800,
            otherInvestment: 500,
            governmentInvestment: 500
          }
        },
        'p5': {
          total: 3800,
          allocated: 3000,
          remaining: 800,
          completed: 2500,
          sources: {
            projectCapital: 1500,
            countyInvestment: 1000,
            governmentInvestment: 1300
          }
        },
        'p6': {
          total: 4500,
          allocated: 3500,
          remaining: 1000,
          completed: 3000,
          sources: {
            projectCapital: 2000,
            countyInvestment: 1500,
            otherInvestment: 500,
            governmentInvestment: 500
          }
        }
      }
    };
  },
  mounted() {
    this.selectedProjects = this.allProjects.map(p => p.id); // 默认全选
    this.fundSelectedProjects = this.allProjects.map(p => p.id); // 默认全选
    this.initCharts();
    window.addEventListener('resize', this.handleResize);
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.handleResize);
    if (this.progressChart) {
      this.progressChart.dispose();
    }
    if (this.fundChart) {
      this.fundChart.dispose();
    }
    if (this.stageChart) {
      this.stageChart.dispose();
    }
  },
  methods: {
    initCharts() {
      // 初始化项目进度图表
      this.progressChart = echarts.init(this.$refs.progressChart);
      this.updateProgressChart();
      // 初始化资金使用情况图表
      this.fundChart = echarts.init(this.$refs.fundChart);
      this.updateFundChart();
      // 初始化项目阶段统计图表
      this.stageChart = echarts.init(this.$refs.stageChart);
      this.stageChart.setOption({
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'shadow'
          }
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true
        },
        xAxis: {
          type: 'category',
          data: ['在库', '储备', '前期', '实施', '竣工'],
          axisLine: {
            lineStyle: {
              color: '#409EFF'
            }
          }
        },
        yAxis: {
          type: 'value',
          axisLine: {
            lineStyle: {
              color: '#409EFF'
            }
          }
        },
        series: [
          {
            data: [15, 12, 10, 8, 6, 4, 2],
            type: 'line',
            smooth: true,
            lineStyle: {
              width: 3,
              color: '#409EFF'
            },
            itemStyle: {
              color: '#409EFF'
            },
            areaStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                {
                  offset: 0,
                  color: 'rgba(64, 158, 255, 0.5)'
                },
                {
                  offset: 1,
                  color: 'rgba(64, 158, 255, 0.1)'
                }
              ])
            }
          }
        ]
      });
    },
    // 更新项目进度图表数据
    updateProgressChart() {
      if (!this.progressChart) return;
      const monthData = this.progressData[this.selectedMonth];
      const filteredProjects = this.allProjects.filter(p =>
        this.selectedProjects.includes(p.id)
      );
      const categories = filteredProjects.map(p => p.name);
      const completedData = filteredProjects.map(p => monthData[p.id].completed);
      const inProgressData = filteredProjects.map(p => monthData[p.id].inProgress);
      const notStartedData = filteredProjects.map(p => monthData[p.id].notStarted);
      this.progressChart.setOption({
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'shadow'
          },
          formatter: function(params) {
            let result = params[0].name + '<br/>';
            params.forEach(param => {
              result += `${param.seriesName}: ${param.value}%<br/>`;
            });
            result += `总计: ${params.reduce((sum, param) => sum + param.value, 0)}%`;
            return result;
          }
        },
        legend: {
          data: ['已完成事项', '进行中事项', '未开始事项']
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true
        },
        xAxis: {
          type: 'value',
          max: 100,
          axisLabel: {
            formatter: '{value}%'
          }
        },
        yAxis: {
          type: 'category',
          data: categories
        },
        series: [
          {
            name: '已完成事项',
            type: 'bar',
            stack: 'total',
            emphasis: {
              focus: 'series'
            },
            data: completedData,
            itemStyle: {
              color: '#67C23A'
            },
            label: {
              show: true,
              position: 'inside',
              formatter: '{c}%'
            }
          },
          {
            name: '进行中事项',
            type: 'bar',
            stack: 'total',
            emphasis: {
              focus: 'series'
            },
            data: inProgressData,
            itemStyle: {
              color: '#409EFF'
            },
            label: {
              show: true,
              position: 'inside',
              formatter: '{c}%'
            }
          },
          {
            name: '未开始事项',
            type: 'bar',
            stack: 'total',
            emphasis: {
              focus: 'series'
            },
            data: notStartedData,
            itemStyle: {
              color: '#E6A23C'
            },
            label: {
              show: true,
              position: 'inside',
              formatter: '{c}%'
            }
          }
        ]
      });
    },
    // 更新资金使用图表数据
    updateFundChart() {
      if (!this.fundChart) return;
      const filteredProjects = this.allProjects.filter(p =>
        this.fundSelectedProjects.includes(p.id)
      );
      const categories = filteredProjects.map(p => p.name);
      const allocatedData = filteredProjects.map(p => this.fundData[p.id].allocated);
      const remainingData = filteredProjects.map(p => this.fundData[p.id].remaining);
      // 资金来源数据
      const projectCapitalData = filteredProjects.map(p =>
        this.fundData[p.id].sources.projectCapital || 0
      );
      const countyInvestmentData = filteredProjects.map(p =>
        this.fundData[p.id].sources.countyInvestment || 0
      );
      const otherInvestmentData = filteredProjects.map(p =>
        this.fundData[p.id].sources.otherInvestment || 0
      );
      const governmentInvestmentData = filteredProjects.map(p =>
        this.fundData[p.id].sources.governmentInvestment || 0
      );
      this.fundChart.setOption({
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'shadow'
          },
          formatter: function(params) {
            let result = params[0].name + '<br/>';
            // 资金拨付和剩余
            result += `资金拨付: ${params[0].value}万元<br/>`;
            result += `剩余金额: ${params[1].value}万元<br/>`;
            result += `总金额: ${params[0].value + params[1].value}万元<br/>`;
            result += `完成投资: ${params[0].axisValueLabel}万元<br/><br/>`;
            // 资金来源
            result += '<strong>资金来源构成:</strong><br/>';
            result += `项目本金: ${params[2].value}万元<br/>`;
            result += `县(市、区)投资: ${params[3].value}万元<br/>`;
            result += `其他投资: ${params[4].value}万元<br/>`;
            result += `政府投资: ${params[5].value}万元<br/>`;
            return result;
          }
        },
        legend: {
          data: ['剩余金额', '资金拨付', '项目本金', '县(市、区)投资', '政府投资', '其他投资']
        },
        grid: {
          top: '30%',
          left: '3%',
          right: '4%',
          bottom: '5%',
          containLabel: true
        },
        xAxis: {
          type: 'category',
          data: categories,
          axisLabel: {
            interval: 0,
            rotate: 30
          }
        },
        yAxis: {
          type: 'value',
          name: '金额(万元)'
        },
        series: [
          {
            name: '资金拨付',
            type: 'bar',
            stack: 'total',
            emphasis: {
              focus: 'series'
            },
            data: allocatedData,
            itemStyle: {
              color: '#409EFF'
            },
            label: {
              show: true,
              position: 'inside',
              formatter: '{c}'
            }
          },
          {
            name: '剩余金额',
            type: 'bar',
            stack: 'total',
            emphasis: {
              focus: 'series'
            },
            data: remainingData,
            itemStyle: {
              color: '#E6A23C'
            },
            label: {
              show: true,
              position: 'inside',
              formatter: '{c}'
            }
          },
          {
            name: '项目本金',
            type: 'bar',
            stack: 'sources',
            emphasis: {
              focus: 'series'
            },
            data: projectCapitalData,
            itemStyle: {
              color: '#67C23A'
            }
          },
          {
            name: '县(市、区)投资',
            type: 'bar',
            stack: 'sources',
            emphasis: {
              focus: 'series'
            },
            data: countyInvestmentData,
            itemStyle: {
              color: '#F56C6C'
            }
          },
          {
            name: '其他投资',
            type: 'bar',
            stack: 'sources',
            emphasis: {
              focus: 'series'
            },
            data: otherInvestmentData,
            itemStyle: {
              color: '#909399'
            }
          },
          {
            name: '政府投资',
            type: 'bar',
            stack: 'sources',
            emphasis: {
              focus: 'series'
            },
            data: governmentInvestmentData,
            itemStyle: {
              color: '#8E44AD'
            }
          }
        ]
      });
    },
    // 更新所有图表
    updateCharts() {
      this.updateProgressChart();
      this.updateFundChart();
    },
    handleResize() {
      if (this.progressChart) {
        this.progressChart.resize();
      }
      if (this.fundChart) {
        this.fundChart.resize();
      }
      if (this.stageChart) {
        this.stageChart.resize();
      }
    },
    getStatusTagType(status) {
      const map = {
        '紧急': 'danger',
        '高风险': 'warning',
        '延期': 'info',
        '进行中': 'primary'
      };
      return map[status] || '';
    },
    handleTaskDetail(task) {
      this.$message.info(`查看任务详情: ${task.taskName}`);
    },
    showDetail() {
      this.$message.info(`查看${this.selectedMonth}月份的项目进度详情`);
    },
    showFundDetail() {
      this.$message.info('查看资金使用详情');
    }
  }
};
</script>
<style scoped>
.project-management-container {
  padding: 20px;
  background-color: #f5f7fa;
  min-height: 100vh;
}
.page-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding-bottom: 15px;
  border-bottom: 1px solid #ebeef5;
}
.page-header h1 {
  color: #409EFF;
  margin: 0;
}
.user-info {
  display: flex;
  align-items: center;
}
.user-info span {
  margin-right: 10px;
  color: #606266;
}
.overview-cards {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
  margin-bottom: 20px;
}
.overview-card {
  border-radius: 8px;
  border-top: 3px solid #409EFF;
}
.overview-card:nth-child(1) {
  border-top-color: #409EFF;
}
.overview-card:nth-child(2) {
  border-top-color: #67C23A;
}
.overview-card:nth-child(3) {
  border-top-color: #E6A23C;
}
.overview-card:nth-child(4) {
  border-top-color: #F56C6C;
}
.card-content {
  display: flex;
  align-items: center;
  padding: 10px 0;
}
.card-icon {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 15px;
}
.card-icon i {
  font-size: 24px;
}
.card-info {
  flex: 1;
}
.card-title {
  font-size: 14px;
  color: #909399;
  margin-bottom: 5px;
}
.card-value {
  font-size: 24px;
  font-weight: bold;
  color: #303133;
}
.main-content {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 20px;
}
.chart-card, .blocking-tasks-card {
  border-radius: 8px;
  margin-bottom: 20px;
  border: 1px solid #ebeef5;
}
.chart-card >>> .el-card__header {
  background-color: #f5f7fa;
  border-bottom: 1px solid #ebeef5;
  padding: 12px 20px;
  font-weight: bold;
  color: #409EFF;
}
.blocking-tasks-card >>> .el-card__header {
  background-color: #f5f7fa;
  border-bottom: 1px solid #ebeef5;
  padding: 12px 20px;
  font-weight: bold;
  color: #409EFF;
}
.chart-container {
  width: 100%;
}
.row {
  display: flex;
  align-items: center;
  height: 36px;
}
</style>
src/views/login.vue
@@ -2,11 +2,11 @@
    <div class="login">
        <div class="nav">
            <img alt="" src="../assets/images/bj.png" />
            <div class="ml-[10px]">射洪智慧项目管理系统</div>
            <div class="ml-[10px]">农投项目管理系统</div>
        </div>
        <div class="conter">
            <div class="left">
                <div class="title">射洪智慧项目管理系统</div>
                <div class="title">农投项目管理系统</div>
                <div>
                    运用系统的观点、方法和理论,对项目涉及的全部工作进行有效地管理
                </div>
@@ -19,14 +19,7 @@
                        class="login-corporation"
                        @click="currentClick('corporation')"
                    >
                        法人登录
                    </div>
                    <div
                        :class="{ active: currentTab === 'supervise' }"
                        class="login-supervise"
                        @click="superviseClick('supervise')"
                    >
                        监管部门登录
                        账号登录
                    </div>
                </div>
                <el-form
@@ -307,7 +300,7 @@
        .right {
            border-radius: 6px;
            background: #ffffff;
            width: 500px;
            width: 450px;
            padding: 0px 25px 5px 25px;
            .tab {
src/views/projectEngineering/projectLibrary/component/ProjectFrom.vue
New file
@@ -0,0 +1,54 @@
<template>
  <div class="basic-info">
    <el-form ref="demoFormRef" :disabled="disabled" :model="projectFromForm" class="dialog_form">
      <el-form-item label="依据说明" label-width="120px" prop="projectFromWhere" style="width: 100%">
        <el-input type="textarea" v-model="projectFromForm.projectFromWhere" style="width: 100%"
                  placeholder="请输入"/>
      </el-form-item>
      <el-form-item label="依据附件" label-width="120px" prop="projectFromFile" style="width: 100%">
        <file-upload :limit="5" :file-size="100" @input="getUploadResult" />
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
import FileUpload from "@/components/FileUpload"
export default {
  name: 'ProjectForm',
  components: {FileUpload},
  props: {
    disabled: {
      type: Boolean,
      default: false,
      required: true
    },
  },
  data() {
    return {
      projectFromForm: {
        projectFromWhere: '',
        projectFromFile: '',
      },
    }
  },
  mounted() {
  },
  beforeDestroy() {
  },
  methods: {
    getUploadResult(fileList) {
      console.log("上传结果", fileList)
    }
  }
}
</script>
<style lang="scss" scoped>
</style>
src/views/projectEngineering/projectLibrary/projectDetails.vue
@@ -77,6 +77,7 @@
import InvestInfo from "@/views/projectEngineering/projectLibrary/component/InvestInfo";
import InvestmentFunds from "@/views/projectEngineering/projectLibrary/component/investmentFunds";
import LegalPerson from "@/views/projectEngineering/projectLibrary/component/legalPerson";
import ProjectFrom from "@/views/projectEngineering/projectLibrary/component/ProjectFrom";
import PolicyInfo from "@/views/projectEngineering/projectLibrary/component/PolicyInfo";
import DocumentsInfo from "@/views/projectEngineering/projectLibrary/component/DocumentsInfo";
import { editProject } from "@/api/projectEngineering/projectInfo";
@@ -115,6 +116,11 @@
          value: "项目(法人)单位登记信息",
          componentName: LegalPerson,
        },
        {
          label: "项目发起依据",
          value: "项目发起依据",
          componentName: ProjectFrom,
        },
        // {
        //   label: "投资项目产业政策符合情况",
        //   value: "投资项目产业政策符合情况",
src/views/workbench.vue
New file
@@ -0,0 +1,596 @@
<template>
  <div class="dashboard-container">
    <!-- 顶部导航栏 -->
    <div class="top-navbar">
      <div class="welcome-message">
        <h2>早安,{{ this.$store.state.user.name }}!</h2>
        <p>今天是{{ currentDate }},祝您工作愉快!</p>
      </div>
      <div class="quick-stats">
        <div class="stat-item">
          <span class="stat-number">{{ todayTasks }}</span>
          <span class="stat-label">今日待办</span>
        </div>
        <div class="stat-item">
          <span class="stat-number">{{ todaySchedules }}</span>
          <span class="stat-label">今日日程</span>
        </div>
        <div class="stat-item">
          <span class="stat-number">{{ unreadMessages }}</span>
          <span class="stat-label">未读消息</span>
        </div>
      </div>
      <div class="user-profile">
<!--        <el-dropdown>-->
<!--          <div class="user-avatar">-->
<!--            <img :src="userInfo.avatar" alt="用户头像">-->
<!--            <span>{{ userInfo.name }}</span>-->
<!--          </div>-->
<!--          <el-dropdown-menu slot="dropdown">-->
<!--            <el-dropdown-item>个人中心</el-dropdown-item>-->
<!--            <el-dropdown-item>设置</el-dropdown-item>-->
<!--            <el-dropdown-item divided>退出登录</el-dropdown-item>-->
<!--          </el-dropdown-menu>-->
<!--        </el-dropdown>-->
      </div>
    </div>
    <!-- 主内容区 -->
    <div class="main-content">
      <!-- 左侧项目列表 -->
      <div class="left-sidebar">
        <div class="project-list">
          <h3>项目列表</h3>
          <el-menu
            :default-active="activeProject"
            class="project-menu"
            @select="handleProjectSelect">
            <el-menu-item index="all">
              <i class="el-icon-menu"></i>
              <span slot="title">全部项目</span>
            </el-menu-item>
            <el-menu-item
              v-for="project in projects"
              :key="project.id"
              :index="project.id">
              <i class="el-icon-folder"></i>
              <span slot="title" class="project-name" :title="project.name">
                {{ project.name }}
              </span>
            </el-menu-item>
          </el-menu>
          <div class="project-actions">
            <el-button type="primary" icon="el-icon-plus" size="small">新建项目</el-button>
          </div>
        </div>
      </div>
      <!-- 中间内容区 -->
      <div class="center-content">
        <!-- 待办任务 -->
        <div class="task-section">
          <div class="section-header">
            <h3>待办任务</h3>
            <el-button type="text" icon="el-icon-refresh">刷新</el-button>
          </div>
          <el-table
            :data="tasks"
            border
            style="width: 100%"
            >
            <el-table-column
              prop="name"
              label="任务名称"
              width="240">
            </el-table-column>
            <el-table-column
              prop="project"
              label="所属项目"
              show-overflow-tooltip
              width="300">
            </el-table-column>
            <el-table-column
              prop="startTime"
              label="开始时间"
              align="center"
              width="160">
            </el-table-column>
            <el-table-column
              prop="deadline"
              label="截止时间"
              align="center"
              width="160">
            </el-table-column>
            <el-table-column
              prop="status"
              label="状态"
              align="center"
              width="100">
              <template slot-scope="scope">
                <el-tag :type="scope.row.status === '待完成' ? 'success' : 'warning'" size="small">
                  {{ scope.row.status }}
                </el-tag>
              </template>
            </el-table-column>
            <el-table-column
              label="操作"
              fixed="right"
              width="120">
              <template slot-scope="scope">
                <el-button size="mini" @click="handleTaskEdit(scope.row)">办理</el-button>
              </template>
            </el-table-column>
          </el-table>
        </div>
        <!-- 项目办理日志 -->
        <div class="log-section">
          <div class="section-header">
            <h3>项目办理日志</h3>
            <el-button type="text" icon="el-icon-refresh">刷新</el-button>
          </div>
          <div class="log-list">
            <div v-for="log in logs" :key="log.id" class="log-item">
              <div class="log-time">{{ log.time }}</div>
              <div class="log-content">
                <span class="log-project">{{ log.project }}</span>
                <span class="log-action">{{ log.action }}</span>
                <span class="log-detail">{{ log.detail }}</span>
              </div>
            </div>
          </div>
        </div>
      </div>
      <!-- 右侧边栏 -->
      <div class="right-sidebar">
        <!-- 个人成就 -->
        <div class="achievement-section">
          <h3>个人成就</h3>
          <div class="achievement-stats">
            <div class="stat-item">
              <div class="stat-number">{{ achievements.completedTasks }}</div>
              <div class="stat-label">完成任务</div>
            </div>
            <div class="stat-item">
              <div class="stat-number">{{ achievements.avgDuration }}天</div>
              <div class="stat-label">平均用时</div>
            </div>
            <div class="stat-item">
              <div class="stat-number">{{ achievements.totalSchedules }}</div>
              <div class="stat-label">安排日程</div>
            </div>
            <div class="stat-item">
              <div class="stat-number">{{ achievements.completedSchedules }}</div>
              <div class="stat-label">完成日程</div>
            </div>
          </div>
        </div>
        <!-- 日历 -->
        <div class="calendar-section">
          <el-calendar v-model="calendarDate">
            <template
              slot="dateCell"
              slot-scope="{date, data}">
              <div class="calendar-day">
                {{ data.day.split('-').slice(2).join('-') }}
                <div v-if="getScheduleCount(date) > 0" class="schedule-count">
                  {{ getScheduleCount(date) }}个日程
                </div>
              </div>
            </template>
          </el-calendar>
        </div>
        <!-- 日程列表 -->
        <div class="schedule-list-section">
          <div class="section-header">
            <h3>日程列表</h3>
            <div>
              <el-button type="text" icon="el-icon-plus" @click="handleAddSchedule">新增</el-button>
              <el-button type="text" icon="el-icon-refresh">刷新</el-button>
            </div>
          </div>
          <div class="schedule-list">
            <el-table
              :data="filteredSchedules"
              style="width: 100%"
              height="250">
              <el-table-column
                prop="time"
                label="时间"
                width="100">
              </el-table-column>
              <el-table-column
                prop="title"
                label="事项"
                width="120">
              </el-table-column>
              <el-table-column
                label="操作"
                width="120">
                <template slot-scope="scope">
                  <el-button size="mini" @click="handleEditSchedule(scope.row)">编辑</el-button>
                  <el-button size="mini" type="danger" @click="handleDeleteSchedule(scope.row)">删除</el-button>
                </template>
              </el-table-column>
            </el-table>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      userInfo: {
        name: '张工程师',
        avatar: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
        department: '项目部'
      },
      currentDate: this.formatDate(new Date()),
      todayTasks: 5,
      todaySchedules: 3,
      unreadMessages: 2,
      activeProject: 'all',
      projects: [
        { id: '1', name: '射洪市沱牌镇综合水利设施建设项目' },
        { id: '2', name: '射洪市国家储备林建设项目(一期)' },
        { id: '3', name: '射洪市白羽肉鸡产业建设项目' },
        { id: '4', name: '遂宁市射洪2024—2027年度东北片区高标准农田建设项目' },
        { id: '5', name: '射洪市现代种业示范基地建设项目' },
      ],
      tasks: [
        { id: 1, name: '审核施工图纸', project: '射洪市国家储备林建设项目(一期)', startTime: '2025-05-05', deadline: '2025-06-15', status: '待完成' },
        { id: 2, name: '采购材料清单', project: '射洪市白羽肉鸡产业建设项目', startTime: '2025-05-14', deadline: '2025-06-18', status: '待完成' },
        { id: 3, name: '现场安全检查', project: '遂宁市射洪2024—2027年度东北片区高标准农田建设项目', startTime: '2025-05-10', deadline: '2025-06-12', status: '容缺中' },
        { id: 4, name: '项目进度报告', project: '射洪市现代种业示范基地建设项目', startTime: '2025-05-23', deadline: '2025-06-20', status: '待完成' },
        { id: 5, name: '供应商会议', project: '射洪市沱牌镇综合水利设施建设项目', startTime: '2025-05-14', deadline: '2025-06-14', status: '容缺中' }
      ],
      logs: [
        { id: 1, time: '09:30', project: '射洪市国家储备林建设项目(一期)', action: '提交', detail: '提交了施工图纸审核申请' },
        { id: 2, time: '10:15', project: '射洪市白羽肉鸡产业建设项目', action: '更新', detail: '更新了材料采购清单' },
        { id: 3, time: '11:00', project: '遂宁市射洪2024—2027年度东北片区高标准农田建设项目', action: '完成', detail: '完成了电力设备测试' },
        { id: 4, time: '14:30', project: '射洪市现代种业示范基地建设项目', action: '创建', detail: '创建了新的安装计划' },
        { id: 5, time: '16:45', project: '射洪市沱牌镇综合水利设施建设项目', action: '审批', detail: '审批通过了安全方案' }
      ],
      achievements: {
        completedTasks: 128,
        avgDuration: 3.5,
        totalSchedules: 89,
        completedSchedules: 76
      },
      calendarDate: new Date(),
      schedules: [
        { id: 1, date: '2025-05-10', time: '09:00', title: '项目启动会议', project: '射洪市国家储备林建设项目(一期)' },
        { id: 2, date: '2025-05-10', time: '14:00', title: '供应商洽谈', project: '射洪市白羽肉鸡产业建设项目' },
        { id: 3, date: '2025-05-11', time: '10:30', title: '现场勘察', project: '遂宁市射洪2024—2027年度东北片区高标准农田建设项目' },
        { id: 4, date: '2025-05-12', time: '09:00', title: '安全培训', project: '射洪市现代种业示范基地建设项目' },
        { id: 5, date: '2025-05-12', time: '15:00', title: '进度汇报', project: '射洪市沱牌镇综合水利设施建设项目' },
        { id: 6, date: '2025-05-15', time: '13:00', title: '设备验收', project: '射洪市白羽肉鸡产业建设项目' }
      ]
    }
  },
  computed: {
    filteredSchedules() {
      const selectedDate = this.formatCalendarDate(this.calendarDate);
      return this.schedules.filter(schedule => schedule.date === selectedDate);
    }
  },
  methods: {
    // 截断过长的项目名称
    truncateProjectName(name) {
      const maxLength = 10; // 最大显示长度
      return name.length > maxLength ? `${name.substring(0, maxLength)}...` : name;
    },
    // 判断项目名是否过长
    isProjectNameTooLong(name) {
      return name.length > 10;
    },
    formatDate(date) {
      const year = date.getFullYear();
      const month = date.getMonth() + 1;
      const day = date.getDate();
      return `${year}年${month}月${day}日`;
    },
    formatCalendarDate(date) {
      const year = date.getFullYear();
      const month = (date.getMonth() + 1).toString().padStart(2, '0');
      const day = date.getDate().toString().padStart(2, '0');
      return `${year}-${month}-${day}`;
    },
    handleProjectSelect(index) {
      this.activeProject = index;
      // 这里可以添加项目筛选逻辑
    },
    getPriorityType(priority) {
      switch (priority) {
        case '高': return 'danger';
        case '中': return 'warning';
        case '低': return 'success';
        default: return 'info';
      }
    },
    handleTaskEdit(task) {
      console.log('编辑任务:', task);
      this.$message.info(`开始处理任务: ${task.name}`);
    },
    getScheduleCount(date) {
      const dateStr = this.formatCalendarDate(date);
      return this.schedules.filter(s => s.date === dateStr).length;
    },
    handleAddSchedule() {
      this.$message.info('新增日程');
    },
    handleEditSchedule(schedule) {
      this.$message.info(`编辑日程: ${schedule.title}`);
    },
    handleDeleteSchedule(schedule) {
      this.$confirm('确定删除该日程吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.$message.success('删除成功');
      }).catch(() => {
        this.$message.info('已取消删除');
      });
    }
  }
}
</script>
<style scoped>
.dashboard-container {
  font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: #f5f7fa;
}
/* 顶部导航栏样式 */
.top-navbar {
  background-color: #1e88e5;
  color: white;
  padding: 15px 20px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.welcome-message h2 {
  margin: 0;
  font-size: 20px;
}
.welcome-message p {
  margin: 5px 0 0;
  font-size: 14px;
  opacity: 0.9;
}
.quick-stats {
  display: flex;
  gap: 30px;
}
.stat-item {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.stat-number {
  font-size: 24px;
  font-weight: bold;
}
.stat-label {
  font-size: 14px;
  opacity: 0.9;
}
.user-profile {
  display: flex;
  align-items: center;
}
.user-avatar {
  display: flex;
  align-items: center;
  cursor: pointer;
}
.user-avatar img {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  margin-right: 10px;
}
/* 主内容区样式 */
.main-content {
  display: flex;
  flex: 1;
  overflow: hidden;
}
.left-sidebar {
  width: 220px;
  background-color: white;
  border-right: 1px solid #e6e6e6;
  padding: 15px;
  margin-top: 10px;
  overflow-y: auto;
}
.project-name {
  display: inline-block;
  max-width: 150px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.project-list h3 {
  margin-top: 0;
  color: #333;
  padding-bottom: 10px;
  border-bottom: 1px solid #eee;
}
.project-menu {
  border-right: none;
}
.project-actions {
  margin-top: 15px;
  text-align: center;
}
.center-content {
  flex: 1;
  padding: 15px;
  overflow-y: auto;
  background-color: white;
  margin: 10px 10px 0px;
  border-radius: 4px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15px;
}
.section-header h3 {
  margin: 0;
  color: #333;
}
.task-section {
  margin-bottom: 20px;
  height: 350px;
}
.log-list {
  border: 1px solid #ebeef5;
  border-radius: 4px;
  padding: 10px;
}
.log-item {
  display: flex;
  padding: 8px 0;
  border-bottom: 1px dashed #eee;
}
.log-item:last-child {
  border-bottom: none;
}
.log-time {
  width: 60px;
  color: #666;
  font-size: 14px;
}
.log-content {
  flex: 1;
}
.log-project {
  color: #1e88e5;
  margin-right: 10px;
  font-weight: bold;
}
.log-action {
  color: #ff9800;
  margin-right: 10px;
}
.right-sidebar {
  width: 320px;
  background-color: white;
  border-left: 1px solid #e6e6e6;
  padding: 15px;
  margin-top: 10px;
  overflow-y: auto;
}
.achievement-section h3 {
  margin-top: 0;
  color: #333;
  padding-bottom: 10px;
  border-bottom: 1px solid #eee;
}
.achievement-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 15px;
  margin-bottom: 20px;
}
.achievement-stats .stat-item {
  background-color: #f5f7fa;
  padding: 15px;
  border-radius: 4px;
  text-align: center;
}
.achievement-stats .stat-number {
  font-size: 24px;
  color: #1e88e5;
  font-weight: bold;
  margin-bottom: 5px;
}
.achievement-stats .stat-label {
  font-size: 14px;
  color: #666;
}
.calendar-section {
  margin-bottom: 20px;
}
.calendar-day {
  height: 45px;
  padding: 5px;
  box-sizing: border-box;
}
.schedule-count {
  font-size: 12px;
  color: #1e88e5;
  margin-top: 2px;
}
.schedule-list-section h3 {
  margin-top: 0;
  color: #333;
  padding-bottom: 10px;
  border-bottom: 1px solid #eee;
}
.calendar-section >>> .el-calendar-table .el-calendar-day {
  height: 40px !important; /* 设置每日单元格高度 */
  padding: 0 !important;
}
.calendar-section >>> .el-calendar__header {
  padding: 0 !important;
  border: none !important;
}
.calendar-section >>> .el-calendar__body {
  padding: 0 !important;
  border: none !important;
}
</style>
vue.config.js
@@ -7,7 +7,7 @@
const CompressionPlugin = require('compression-webpack-plugin')
const name = process.env.VUE_APP_TITLE || '射洪智慧项目管理系统' // 网页标题
const name = process.env.VUE_APP_TITLE || '农投项目管理系统' // 网页标题
const port = process.env.port || process.env.npm_config_port || 80 // 端口