前后端分离 -- 深入浅出 Spring Boot + Vue 实现工程项目进度管理系统 Vue不过如此~

@TOC

引言

Hello,我是Bug终结者,一名热爱后端Java的风趣且幽默的程序员~ 终于等到幸运的你~

快来发现我的宇宙哦~

前后端分离 -- 深入浅出 Spring Boot + Vue 实现工程项目进度管理系统 Vue不过如此~

博文系列

????深入浅出前后端分离系列第一篇 :前后端分离 — 深入浅出Spring Boot + Vue实现员工管理系统 Vue如此简单~

????深入浅出前后端分离系列第二篇 :前后端分离 -- 深入浅出 Spring Boot + Vue + ElementUI 实现相册管理系统【文件上传 分页 】 文件上传也不过如此~

项目简介

在建筑项目中,进度是以金额来计算的,比如,项目合同金额为10000万元,哪一个进度完成那一部分金额,在次基础上,建立出一套工程建筑项目管理系统

功能细节

实现项目的增删改和列表

  • 项目的列表需要支持分页和按照项目名称进行多条件查询
  • 项目全称和简称均不能重复
  • 项目列表原型如下:

前后端分离 -- 深入浅出 Spring Boot + Vue 实现工程项目进度管理系统 Vue不过如此~

点击项目简称可以查看项目详情页面

前后端分离 -- 深入浅出 Spring Boot + Vue 实现工程项目进度管理系统 Vue不过如此~

点击进度进入该项目的进度列表页面

实现项目进度填报功能

  • 实现进度填报的新增、编辑、删除和列表功能
  • 列表页面效果如下

*前后端分离 -- 深入浅出 Spring Boot + Vue 实现工程项目进度管理系统 Vue不过如此~

进度年份和月份必须在项目的开始和结束时间之间,可以包括开始和结束的月份

进度的总完成金额不能超过项目的合同额度。

效果图

前后端分离 -- 深入浅出 Spring Boot + Vue 实现工程项目进度管理系统 Vue不过如此~

开发环境

后端:Spring Boot + MyBatis + Maven

前端:Vue + ElementUI

工具:前端使用VSCode,后端使用IDEA

????放松一下~

前后端分离 -- 深入浅出 Spring Boot + Vue 实现工程项目进度管理系统 Vue不过如此~

够给力的~

前后端分离 -- 深入浅出 Spring Boot + Vue 实现工程项目进度管理系统 Vue不过如此~

哇哦~????

????????????

项目风格

????请求方式统一为Post请求,目的是保证安全性

规范了接口层统一返回格式为ResultBean,详细如:

统一返回格式风格类,ResultBean

状态码,详细信息,数据

数据表结构

t_project项目表

DROP TABLE IF EXISTS t_project;
CREATE TABLE `t_project` (
  `noid` INT(11) NOT NULL AUTO_INCREMENT,
  `full_name` VARCHAR(128) NOT NULL COMMENT '项目全称名称',
  `simple_name` VARCHAR(128) NOT NULL COMMENT '项目简称',
    contract_money DECIMAL(12,2) DEFAULT 0  COMMENT '合同金额',
    province_id CHAR(8) NOT NULL COMMENT '所属省份',
    important_level TINYINT(4) DEFAULT 1 COMMENT '重要级别, 1 普通项目;2 重要项目',
    start_time DATETIME NOT NULL COMMENT '项目开始时间',
    end_time DATETIME NOT NULL COMMENT '项目结束时间',
    create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`noid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4;

t_province省份表

DROP TABLE IF EXISTS `t_province`;

CREATE TABLE `t_province` (
  `noid` char(8) NOT NULL,
  `province_name` varchar(64) DEFAULT NULL,
  `order_numb` int(11) NOT NULL DEFAULT '100' COMMENT '顺序号',
  PRIMARY KEY (`noid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

insert  into `t_province`(`noid`,`province_name`,`order_numb`) values ('1','北京市',10),('10','江苏省',100),('11','浙江省',110),('12','安徽省',120),('13','福建省',130),('14','江西省',140),('15','山东省',150),('16','河南省',160),('17','湖北省',170),('18','湖南省',180),('19','广东省',190),('2','天津市',20),('20','广西省',200),('21','海南省',210),('22','重庆市',220),('23','四川省',230),('24','贵州省',240),('25','云南省',250),('26','*',260),('27','陕西省',270),('28','甘肃省',280),('29','青海省',290),('3','河北省',30),('30','宁夏省',300),('31','*',310),('32','*省',320),('33','香港特别行政区',330),('34','澳门',340),('4','山西省',40),('5','内蒙古',50),('6','辽宁省',60),('7','吉林省',70),('8','黑龙江省',80),('9','上海市',90);

t_project_month_progress 项目月进度表

DROP TABLE IF EXISTS t_project_month_progress;

CREATE TABLE `t_project_month_progress` (
  `noid` int(11) NOT NULL AUTO_INCREMENT,
  `project_id` int(11) NOT NULL COMMENT '项目id',
  `progress_year` int(11) NOT NULL COMMENT '进度年份',
  `progress_month` int(11) NOT NULL COMMENT '进度月份',
  `progress_money` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '当月进度完成金额',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`noid`),
  UNIQUE KEY `unq_project_year_month` (`project_id`,`progress_year`,`progress_month`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

项目结构

后端结构

前后端分离 -- 深入浅出 Spring Boot + Vue 实现工程项目进度管理系统 Vue不过如此~

前端结构

前后端分离 -- 深入浅出 Spring Boot + Vue 实现工程项目进度管理系统 Vue不过如此~

项目难点

前端难点

==在选择月份的时候要求选择的月份不可大于项目开始月份也不可小于项目结束月份==

在ElementUI el-datepicker组件中可显示能被选中的月份,如下

前后端分离 -- 深入浅出 Spring Boot + Vue 实现工程项目进度管理系统 Vue不过如此~

这种效果该如何实现呢

采用组件所带的picker-options属性实现日期过滤

<el-form-item label="进度日期">
          <el-date-picker type="month" size="mini" :picker-options="pickerOptions" value-format="yyyy-MM"  v-model="projectMonthProgress.progress_time" placeholder="选择进度日期"></el-date-picker>
        </el-form-item>

js代码

//该代码写在data中,动态加载到组件中
pickerOptions:{
    //计算该日期是否可选,true,不可选,false,可选
    disabledDate: (time) => {
        let start = time.getTime() < new Date(this.project.start_time).getTime();
        let end = time.getTime() > new Date(this.project.end_time).getTime();
        return start || end;
    }
}

至此,控制日期可选完美解决

后端难点

在项目列表、项目月份进度页、项目详情页需要显示当前项目的完成额度与未完成额度,从数据库读出,在project类中添加冗余字段,并返回给前端从而进行展示数据,每次加载都去请求后端进行更新数据

核心源码

前端源码

ProjectList.vue

<template xmlns:c="http://www.w3.org/1999/html">
  <div class="box-main2 box-heigt100">
    <div class="box-search">
      <div>
        <el-input type="text" size="mini" @keydown.native.enter="clkBtnSearch" @clear="clkBtnSearch" v-model="searchInfo.searchKey" clearable placeholder="请输入标题"></el-input>
      </div>
      <div class="m1">
        <el-button type="primary" size="mini"  @click="clkBtnSearch">搜索</el-button>
      </div>
      <div class="m1">
        <el-button type="warning" size="mini" @click="clkBtnAdd">新增</el-button>
      </div>
    </div>
    <div class="box-table2">
      <el-table :data="projectPage.list" >
        <el-table-column type="index" label="序号" width="50"></el-table-column>
        <el-table-column label="项目简称" width="120">
          <template slot-scope="scope">
            <el-link type="primary" style="color: #409EFF;" @click="clkBtnGoDetail(scope.row)">{{scope.row.simple_name}}</el-link>
          </template>
        </el-table-column>
        <el-table-column prop="str_province" label="所属省份" width="80"></el-table-column>
        <el-table-column prop="contract_money" label="合同金额(万元)" width="150"></el-table-column>
        <el-table-column prop="done_money" label="已完成金额(万元)" width="150">
          <template slot-scope="scope">
            <span v-if="scope.row.done_money == null">--</span>
            <span v-if="scope.row.done_money != null">{{scope.row.done_money}}</span>
          </template>
        </el-table-column>
        <el-table-column prop="incomplete_money" label="未完成金额(万元)">
           <template slot-scope="scope">
            <span v-if="scope.row.incomplete_money == null">--</span>
            <span v-if="scope.row.incomplete_money != null">{{scope.row.incomplete_money}}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作">
          <template slot-scope="scope">
            <el-button type="primary" @click="clkBtnGotoProgress(scope.row)" size="mini">进度</el-button>
            <el-button type="warning" @click="clkBtnEdit(scope.row)" size="mini">修改</el-button>
            <el-button type="danger" @click="clkBtnDelete(scope.row)" size="mini">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <div class="box-page1">
      <el-pagination background :current-page="projectPage.pageNum" :page-size="projectPage.pageSize" :total="projectPage.total"
                     layout="total,prev,pager,next"
                     @current-change="chgPageNum">
      </el-pagination>
    </div>

    <el-dialog :visible.sync="showProjectDigLog" title="新增/编辑">
      <el-form label-width="120px">
        <el-form-item label="项目全称">
          <el-input type="text" size="mini" placeholder="请输入项目全称" v-model="project.full_name"></el-input>
        </el-form-item>
        <el-form-item label="项目简称">
          <el-input type="text" size="mini" placeholder="请输入项目简称" v-model="project.simple_name"></el-input>
        </el-form-item>
        <el-form-item label="所属省份">
           <el-select v-model="project.province_id" placeholder="请选择" size="mini">
            <el-option
              v-for="item in provinceList"
              :key="item.noid"
              :label="item.province_name"
              :value="item.noid">
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="合同金额">
          <el-input v-model="project.contract_money" size='mini'>
            <template slot="append">万元</template>
          </el-input>
        </el-form-item>
        <el-form-item label="重要级别">
          <el-radio-group v-model="project.important_level">
            <el-radio :label="1">普通项目</el-radio>
            <el-radio :label="2">重要项目</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="开始日期">
          <el-date-picker v-model="project.start_time" value-format="yyyy-MM-dd hh:mm:ss"   placeholder="开始日期"></el-date-picker>
        </el-form-item>
        <el-form-item label="结束日期">
          <el-date-picker v-model="project.end_time" value-format="yyyy-MM-dd hh:mm:ss"   placeholder="结束日期"></el-date-picker>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" size="mini" @click="clkBtnSave">确定</el-button>
        <el-button type="warning" size="mini" @click="showProjectDigLog = false">取消</el-button>
      </span>
    </el-dialog>


  </div>
</template>

<script>
  import request from '@/common/utils/request';

  export default {
    computed:{
    },
    inject: ['reload'],
    data() {
      return {
        searchInfo: {searchKey:''},
        projectPage:{pageNum: 1, pageSize: 2, list: []},
        showProjectDigLog:false,
        project:{},
        provinceList:[],
      };
    },
    watch:{
      '$route.path':{
        handler:function(newVal){
          if(newVal == '/picture-list'){
            this.initData();
          }
        }, immediate: true
      },
    },
    mounted() {
      this.initData();
    },
    methods: {
      initData() {
        this.getProvinceList();
        this.getProjectList();
      },
      getProvinceList() {
        let url = this.settings.apiUrl + "/springbootajax/province/list";
        let data = {};
        request.post(url, data).then((res) => {
          if (res.code === 0) {
            this.provinceList = res.data;
          }
        })
      },
      getProjectList() {
        let url = this.settings.apiUrl + "/springbootajax/project/page";
        let data = {};
        data.searchKey = this.searchInfo.searchKey;
        data.pageNum = this.projectPage.pageNum;
        data.pageSize = this.projectPage.pageSize;
        request.post(url, data).then((res) => {
          if (res.code === 0) {
            this.projectPage = res.data;
            console.log(this.projectPage)
          }
        })
      },
      clkBtnDelete(row) {
        this.$confirm("您确信要删除吗?", "提示").then(() => {
          let url = this.settings.apiUrl + "/springbootajax/project/delete";
          let data = {noid: row.noid};
          request.post(url, data).then((res) => {
            if (res.code === 0) {
              this.getProjectList();
              this.$message("删除成功~");
            }
          })
        }).catch(() => {
          this.$message("取消删除~");
        })
      },
      clkBtnEdit(row) {
        this.project = JSON.parse(JSON.stringify(row));
        this.showProjectDigLog = true;
      },
      clkBtnSave() {
        console.log(this.project)
        let url = this.settings.apiUrl + "/springbootajax/project/save";
        let data = this.project;
        let options = {Headers:{'Content-type':'application/json'}};
        request.post(url, data, options).then((res) => {
          if (res.code === 0) {
            this.getProjectList();
            this.showProjectDigLog = false;
            this.$message("保存成功~");
          }
        })
      },
      clkBtnAdd() {
        this.project = {important_level:1};
        this.showProjectDigLog = true;
      },
      clkBtnSearch() {
        this.getProjectList();
      },
      chgPageNum(pageNum) {
        this.projectPage.pageNum = pageNum;
        this.getProjectList();
      },
      clkBtnGoDetail(row) {
        this.$router.push({path:'/project-detail',query:{noid:row.noid}});
      },
      clkBtnGotoProgress(row) {
        this.$router.push({path:'/project-month-progress',query:{noid:row.noid}});
      }
    },
  };
</script>

<style lang="scss" scoped="scoped">

  .box-main2 {
    width: 90%;
    margin: 10px;
    box-table2{
      height: auto;
    }
    .box-search{
      display: flex;
      margin: 10px;
      .m1{
        padding-left: 10px;
      }
    }
    .box-page1{
      margin-top: 10px;
    }
  }

</style>

ProjectDetail项目详情页

<template>
  <div class="box-main2 box-heigt100">
    <div class="detail">
      <p>
        <span>
          <label>项目全称:</label><b>{{project.full_name}}</b>
        </span>
      </p>
      <p>
        <span>
          <label>项目简称:</label><b>{{project.simple_name}}</b>
        </span>
      </p>
      <p>
        <span>
          <label>所属省份:</label><b>{{project.str_province}}</b>
        </span>
      </p>
      <p>
        <span>
          <label>重要级别:</label><b>{{project.important_level|filterImportant_level}}</b>
        </span>
      </p>
      <p>
        <span>
          <label>项目起止:</label><b>{{project.start_time|filterDateFormat1}} -- {{project.end_time|filterDateFormat1}}</b>
        </span>
      </p>
      <p>
        <span>
          <label>合同金额:</label><b>{{project.contract_money}}万元</b>
        </span>
      </p>
      <p>
        <span>
          <label>完成额度:</label><b v-if="project.done_money == null">--</b><b v-if="project.done_money != null">{{project.done_money}}</b>
        </span>
      </p>
      <p>
        <span>
          <label>未完成额度:</label><b v-if="project.incomplete_money == null">--</b><b v-if="project.incomplete_money != null">{{project.incomplete_money}}</b>
        </span>
      </p>
      <div class="footer">
        <el-button type="warning" size="mini" @click="clkBtnEdit">编辑项目信息</el-button>
        <el-button type="primary" size="mini" @click="clkBtnGotoProgress">进度列表</el-button>
        <el-button type="info" size="mini" @click='clkBtnBackProject'>返回项目列表</el-button>
      </div>

<el-dialog :visible.sync="showProjectDigLog" title="新增/编辑">
      <el-form label-width="120px">
        <el-form-item label="项目全称">
          <el-input type="text" size="mini" placeholder="请输入项目全称" v-model="project.full_name"></el-input>
        </el-form-item>
        <el-form-item label="项目简称">
          <el-input type="text" size="mini" placeholder="请输入项目简称" v-model="project.simple_name"></el-input>
        </el-form-item>
        <el-form-item label="所属省份">
           <el-select v-model="project.province_id" placeholder="请选择" size="mini">
            <el-option
              v-for="item in provinceList"
              :key="item.noid"
              :label="item.province_name"
              :value="item.noid">
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="合同金额">
          <el-input v-model="project.contract_money" size='mini'>
            <template slot="append">万元</template>
          </el-input>
        </el-form-item>
        <el-form-item label="重要级别">
          <el-radio-group v-model="project.important_level">
            <el-radio :label="1">普通项目</el-radio>
            <el-radio :label="2">重要项目</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="开始日期">
          <el-date-picker v-model="project.start_time" value-format="yyyy-MM-dd hh:mm:ss"   placeholder="开始日期"></el-date-picker>
        </el-form-item>
        <el-form-item label="结束日期">
          <el-date-picker v-model="project.end_time" value-format="yyyy-MM-dd hh:mm:ss"   placeholder="结束日期"></el-date-picker>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" size="mini" @click="clkBtnSave">确定</el-button>
        <el-button type="warning" size="mini" @click="showProjectDigLog = false">取消</el-button>
      </span>
    </el-dialog>

    </div>
  </div>
</template>

<script>
  import request from '@/common/utils/request';

  export default {
    computed:{
    },
    inject: ['reload'],
    data() {
      return {
        noid:'',
        project:{},
        provinceList:[],
        showProjectDigLog:false
      };
    },
    watch:{
      // '$route.path':{
      //   handler:function(newVal){
      //     if(newVal == '/project-detail'){
      //       this.initData();
      //     }
      //   }, immediate: true
      // },
    },
    mounted() {
      this.noid = this.$route.query.noid;
      this.initData();
    },
    methods: {
      initData() {
        this.getProject();
        this.getProvinceList();
      },
       getProvinceList() {
        let url = this.settings.apiUrl + "/springbootajax/province/list";
        let data = {};
        request.post(url, data).then((res) => {
          if (res.code === 0) {
            this.provinceList = res.data;
          }
        })
      },
      getProject() {
        let url = this.settings.apiUrl + "/springbootajax/project/get";
        let data = {noid: this.noid};
        request.post(url, data).then((res) => {
          if (res.code === 0) {
            this.project = res.data;
          }
        })
      },
      clkBtnBackProject() {
        this.$router.push("project-list");
        this.reload();
      },
      clkBtnGotoProgress() {
        this.$router.push({path:'/project-month-progress',query:{noid:this.noid}});
      },
      clkBtnEdit() {
        this.project = JSON.parse(JSON.stringify(this.project));
        this.showProjectDigLog = true;
      },
      clkBtnSave() {
        console.log(this.project)
        let url = this.settings.apiUrl + "/springbootajax/project/save";
        let data = this.project;
        let options = {Headers:{'Content-type':'application/json'}};
        request.post(url, data, options).then((res) => {
          if (res.code === 0) {
            this.getProjectList();
            this.showProjectDigLog = false;
            this.$message("保存成功~");
          }
        })
      }
    },
    filters:{
      filterImportant_level(srcVal) {
        if (srcVal == 1) {
          return '普通项目';
        } else {
          return '重要项目';
        }
      },
      filterDateFormat1(srcVal){
        if(!srcVal){
          return "";
        }
        if(srcVal.length<10){
          return srcVal;
        }
        return srcVal.substr(0,10);
      },
    }
  };
</script>

<style lang="scss" scoped="scoped">

  .box-main2{
    width:1100px;
    margin:20px auto;
    background: #fff;
    .detail{
      padding: 20px;
      width:500px;
      margin:0 auto;
    }
  }



</style>

ProjectMonthProgress 项目月份进度页

<template>
  <div class="box-main2 box-heigt100">
    <div class="detail">
      <p>
        <span>
          <label>项目简称:</label><b>{{project.simple_name}}</b>
        </span>
        &emsp;
        <el-button type="warning" size="mini" @click='clkBtnGotoDetail'>项目详情</el-button>
        <el-button type="info" size="mini" @click='clkBtnBackProject'>返回项目列表</el-button>
      </p>
      <p>
        <span>
          <label>合同金额:</label> <b>{{project.contract_money}}万元</b>
        </span>
        <span>
          <label>完成额度:</label> <b v-if="project.done_money == null">--</b><b v-if="project.done_money != null">{{project.done_money}}万元</b>
        </span>
        <span>
          <label>未完成额度:</label> <b v-if="project.incomplete_money == null">--</b><b v-if="project.incomplete_money != null">{{project.incomplete_money}}万元</b>
        </span>
      </p>
    <div class="box-main3">
      <el-button type="primary" size="mini" @click="clkBtnAdd">新增进度</el-button>
      <div class="box-table">
        <el-table
          :data="projectMonthProgressPage.list"
          border
          style="width: 100%">
          <el-table-column header-align="center" align="center" type="index" label="序号" width="90"></el-table-column>
          <el-table-column  prop="progress_month" label="进度月份" >
          </el-table-column>
          <el-table-column header-align="center" align="center" prop="progress_money" label="完成额度(万元)" >
          </el-table-column>
          <el-table-column header-align="center" align="center" label="操作" >
            <template slot-scope="scope">
              <span>
                <el-button type="warning" @click="clkBtnEdit(scope.row)">编辑</el-button>
                <el-button type="danger" @click="clkBtnDelete(scope.row)">删除</el-button>
              </span>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </div>
    <el-dialog title="新增/编辑" :visible.sync="showProgressDialog">
      <el-form label-width="80px">
        <el-form-item label="进度日期">
          <el-date-picker type="month" size="mini" :picker-options="pickerOptions" value-format="yyyy-MM"  v-model="projectMonthProgress.progress_time" placeholder="选择进度日期"></el-date-picker>
        </el-form-item>
        <el-form-item label="完成额度">
          <el-input size="mini" v-model="projectMonthProgress.progress_money" placeholder="请输入完成的额度">
            <template slot="append">万元</template>
          </el-input>
        </el-form-item>
      </el-form>
      <div slot="footer">
        <el-button @click="showProgressDialog = false" size="mini">取 消</el-button>
        <el-button type="primary" @click="clkBtnSave" size="mini">确 定</el-button>
      </div>
    </el-dialog>
    <div class="box-page1">
      <el-pagination background :current-page="projectMonthProgressPage.pageNum" :page-size="projectMonthProgressPage.pageSize" :total="projectMonthProgressPage.total"
                     layout="total,prev,pager,next"
                     @current-change="chgPageNum">
      </el-pagination>
    </div>
    </div>
  </div>
</template>

<script>
  import request from '@/common/utils/request';

  export default {
    computed:{
    },
    inject: ['reload'],
    data() {
      return {
        noid:'',
        project:{},
        showProgressDialog:false,
        projectMonthProgress:{},
        projectMonthProgressPage:{pageNum:1,pageSize:3, list:[]},
        //规定可选择的日期范围,开始日期-结束日期之间
        pickerOptions:{
        
        disabledDate: (time) => {
          let start = time.getTime() < new Date(this.project.start_time).getTime();
          let end = time.getTime() > new Date(this.project.end_time).getTime();
          return start || end;
        }
      }
      };
    },
    
    watch:{
      // '$route.path':{
      //   handler:function(newVal){
      //     if(newVal == '/project-month-progress'){
      //       this.initData();
      //     }
      //   }, immediate: true
      // },
    },
    mounted() {
      this.noid = this.$route.query.noid;
      this.initData();
    },
    methods: {
      initData() {
        this.getProject();
        this.getProjectMonthProgressList();
      },
      getProject() {
        let url = this.settings.apiUrl + "/springbootajax/project/get";
        let data = {noid: this.noid};
        request.post(url, data).then((res) => {
          if (res.code === 0) {
            this.project = res.data;
          }
        })
      },
      getProjectMonthProgressList() {
        let url = this.settings.apiUrl + "/springbootajax/project_month_progress/page";
        let data = {};
        data.pageNum = this.projectMonthProgressPage.pageNum;
        data.pageSize = this.projectMonthProgressPage.pageSize;
        request.post(url, data).then((res) => {
          if (res.code === 0) {
            this.projectMonthProgressPage = res.data;
            console.log(res.data);
          }
        })
      },
      clkBtnBackProject() {
        this.$router.push("project-list");
        this.reload();
      },
      clkBtnGotoDetail() {
         this.$router.push({path:'/project-detail',query:{noid:this.noid}});
      },
      clkBtnAdd() {
        this.projectMonthProgress = {project_id:this.noid};
        this.showProgressDialog = true;
      },
      clkBtnSave() {
        let url = this.settings.apiUrl + "/springbootajax/project_month_progress/save";
        let data = this.projectMonthProgress;
        request.post(url, data).then((res) => {
          if (res.code === 0) {
            this.getProjectMonthProgressList();
            this.showProgressDialog = false;
            this.$message("保存成功~");
            this.getProject();
          }
        })
      },
      chgPageNum(pageNum) {
        this.projectMonthProgressPage.pageNum = pageNum;
        this.getProjectMonthProgressList();
      },
      clkBtnEdit(row) {
        this.projectMonthProgress = JSON.parse(JSON.stringify(row));
        this.showProgressDialog = true;
      },
      clkBtnDelete(row) {
        this.$confirm("您确信要删除吗?", "提示").then(() => {
          let url = this.settings.apiUrl + "/springbootajax/project_month_progress/delete";
          let data = {noid: row.noid};
          request.post(url, data).then((res) => {
            if (res.code === 0) {
              this.getProjectMonthProgressList();
              this.$message("删除成功~");
              this.getProject();
            }
          })
        }).catch(() => {
          this.$message("取消删除~");
        })
      }
    }

  };
</script>

<style lang="scss" scoped="scoped">

  .box-main2{
    width:1100px;
    margin:20px auto;
    background: #fff;
    .detail{
      padding: 20px;
      width:900px;
      margin:0 auto;
      span{
        padding: 10px;
      }
    }
    .box-table, .box-page1{
      margin-top:20px;
    }
  }



</style>

添加路由

index.js

import Vue from 'vue';
import Router from 'vue-router';

import Frame from '@/views/layout/Frame';


Vue.use(Router);

export default new Router({

  routes: [
    {
      path: '/',
      component: Frame,
      children: [
        {
          path: '/project-list',
          meta: {pageTitle: '项目页', leftMenuIndex: 'project-list'},
          component: () => import('@/views/ProjectList')
        },
        {
          path: '/project-detail',
          meta: {pageTitle: '项目详情页', leftMenuIndex: 'project-detail'},
          component: () => import('@/views/ProjectDetail')
        },
        {
          path: '/project-month-progress',
          meta: {pageTitle: '项目月份进度页', leftMenuIndex: 'project-month-progress'},
          component: () => import('@/views/ProjectMonthProgress')
        },

      ]
    },


  ]
});

添加左侧菜单显示

LeftMenu.vue

<el-menu-item  index="project-list" @click.native="clkItem('/project-list')">
    <i class="menuitem-icon iconfont icon-logging"></i>
    <span class="menuitem-text" slot="title">项目列表</span>
</el-menu-item>

后端源码

API

ProjectController项目访问类

package com.wanshi.controller;

import com.github.pagehelper.PageInfo;
import com.wanshi.bean.Project;
import com.wanshi.bean.ResultBean;
import com.wanshi.service.ProjectService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@CrossOrigin
@RequestMapping("/project")
public class ProjectController {

    @Autowired
    private ProjectService projectService;

    @PostMapping("/page")
    public ResultBean<PageInfo<Project>> page(@RequestBody Project param) {
        ResultBean<PageInfo<Project>> res = projectService.page(param);
        return res;
    }

    @PostMapping("/save")
    public ResultBean<Integer> save(@RequestBody Project param) {
        ResultBean<Integer> res = projectService.save(param);
        return res;
    }

    @PostMapping("/delete")
    public ResultBean<Integer> delete(@RequestBody Project param) {
        ResultBean<Integer> res = projectService.delete(param);
        return res;
    }

    @PostMapping("/get")
    public ResultBean<Project> get(@RequestBody Project param) {
        ResultBean<Project> res = projectService.get(param);
        return res;
    }
}

ProjectMonthProgressController 项目月份进度访问类

package com.wanshi.controller;

import com.github.pagehelper.PageInfo;
import com.wanshi.bean.ProjectMonthProgress;
import com.wanshi.bean.ResultBean;
import com.wanshi.service.ProjectMonthProgressService;
import org.junit.experimental.theories.DataPoints;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@CrossOrigin
@RequestMapping("/project_month_progress")
public class ProjectMonthProgressController {

    @Autowired
    private ProjectMonthProgressService projectMonthProgressService;

    @PostMapping("/page")
    public ResultBean<PageInfo<ProjectMonthProgress>> page(@RequestBody ProjectMonthProgress param) {
        ResultBean<PageInfo<ProjectMonthProgress>> res = projectMonthProgressService.page(param);
        return res;
    }

    @PostMapping("/save")
    public ResultBean<Integer> save(@RequestBody ProjectMonthProgress param) {
        ResultBean<Integer> res = projectMonthProgressService.save(param);
        return res;
    }

    @PostMapping("/delete")
    public ResultBean<Integer> delete(@RequestBody ProjectMonthProgress param) {
        ResultBean<Integer> res = projectMonthProgressService.delete(param);
        return res;
    }
}

ProvinceController省份访问类

package com.wanshi.controller;

import com.wanshi.bean.Province;
import com.wanshi.bean.ResultBean;
import com.wanshi.service.ProvinceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@CrossOrigin
@RequestMapping("/province")
public class ProvinceController {

    @Autowired
    private ProvinceService provinceService;

    @PostMapping("/list")
    public ResultBean<List<Province>> list() {
        ResultBean<List<Province>> res = provinceService.list();
        return res;
    }
}

Service

ProjectService类

package com.wanshi.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.wanshi.bean.Project;
import com.wanshi.bean.ProjectMonthProgress;
import com.wanshi.bean.Province;
import com.wanshi.bean.ResultBean;
import com.wanshi.mapper.ProjectMapper;
import com.wanshi.mapper.ProjectMonthProgressMapper;
import com.wanshi.mapper.ProvinceMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

@Service
public class ProjectService {

    @Autowired
    private ProjectMapper projectMapper;
    @Autowired
    private ProvinceMapper provinceMapper;
    @Autowired
    private ProjectMonthProgressMapper projectMonthProgressMapper;

    public ResultBean<PageInfo<Project>> page(Project param) {
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<Project> projectList = projectMapper.list(param);
        for (Project project : projectList) {
            if (project != null) {
                //回显省份名称
                Province province = new Province();
                province.setNoid(project.getProvince_id());
                Province province1 = provinceMapper.get(province);
                project.setStr_province(province1.getProvince_name());
                //获取进度记录
                ProjectMonthProgress projectMonthProgress = new ProjectMonthProgress();
                projectMonthProgress.setProject_id(project.getNoid());
                List<ProjectMonthProgress> projectMonthProgressList = projectMonthProgressMapper.list(projectMonthProgress);
                if (projectMonthProgressList != null) {

                    Double done_money = 0.0;
                    for (ProjectMonthProgress monthProgress : projectMonthProgressList) {
                        if (monthProgress != null && monthProgress.getProject_id() == project.getNoid()) {
                            done_money += monthProgress.getProgress_money();
                        }
                    }
                    project.setDone_money(done_money);
                    project.setIncomplete_money(project.getContract_money() - done_money);
                }
            }
        }
        PageInfo<Project> pageInfo = new PageInfo<>(projectList);
        return ResultBean.create(0, "success", pageInfo);
    }

    public ResultBean<Integer> save(Project param) {
        if (param.getNoid() != null) {
            projectMapper.update(param);
        } else {
            projectMapper.insert(param);
        }
        return ResultBean.create(0, "success", null);
    }

    public ResultBean<Integer> delete(Project param) {
        projectMapper.delete(param);
        return ResultBean.create(0, "success", null);
    }

    public ResultBean<Project> get(Project param) {
        Project project = projectMapper.get(param);
        //回显省份名称
        Province province = new Province();
        province.setNoid(project.getProvince_id());
        Province province1 = provinceMapper.get(province);
        project.setStr_province(province1.getProvince_name());
        //获取进度记录
        ProjectMonthProgress projectMonthProgress = new ProjectMonthProgress();
        projectMonthProgress.setProject_id(project.getNoid());
        List<ProjectMonthProgress> projectMonthProgressList = projectMonthProgressMapper.list(projectMonthProgress);
        Double done_money = 0.0;
        for (ProjectMonthProgress monthProgress : projectMonthProgressList) {
            if (monthProgress != null) {
                done_money += monthProgress.getProgress_money();
            }
        }
        project.setDone_money(done_money);
        project.setIncomplete_money(project.getContract_money() - done_money);
        return ResultBean.create(0, "success", project);
    }

}

ProjectMonthProgressService类

package com.wanshi.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.wanshi.bean.ProjectMonthProgress;
import com.wanshi.bean.ResultBean;
import com.wanshi.mapper.ProjectMonthProgressMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ProjectMonthProgressService {

    @Autowired
    private ProjectMonthProgressMapper projectMonthProgressMapper;

    public ResultBean<PageInfo<ProjectMonthProgress>> page(ProjectMonthProgress param) {
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<ProjectMonthProgress> projectMonthProgressList = projectMonthProgressMapper.list(param);
        for (ProjectMonthProgress projectMonthProgress : projectMonthProgressList) {
            if (projectMonthProgress != null) {
                String progress_time = projectMonthProgress.getProgress_year()+"-"+projectMonthProgress.getProgress_month();
                projectMonthProgress.setProgress_time(progress_time);
            }
        }
        PageInfo<ProjectMonthProgress> pageInfo = new PageInfo<>(projectMonthProgressList);
        return ResultBean.create(0, "success", pageInfo);
    }

    public ResultBean<Integer> save(ProjectMonthProgress param) {
        if (!StringUtils.isEmpty(param.getProgress_time())) {
            param.setProgress_year(Integer.valueOf(param.getProgress_time().substring(0, 4)));
            param.setProgress_month(Integer.valueOf(param.getProgress_time().substring(5)));
        }
        if (param.getNoid() != null) {
            projectMonthProgressMapper.update(param);
        } else {
            projectMonthProgressMapper.insert(param);
        }
        return ResultBean.create(0, "success", null);
    }

    public ResultBean<Integer> delete(ProjectMonthProgress param) {
        projectMonthProgressMapper.delete(param);
        return ResultBean.create(0, "success", null);
    }
}

代码过于多,就不一一展示了,文末我会提供下载源代码链接哦~

下载链接

本项目上传至GitEE码云进行项目管理,具体链接如下:

前端源码:建筑工程项目前端源码

后端源码:建筑工程项目后端源码

建议使用SSH秘钥爬取源码

前端配置教程:使用GitEE拉取前端项目并配置,保证运行成功哦~

????????????

博主寄语

该项目是一个基于SpringBoot + Vue实现的建筑项目进度管理系统,项目逻辑稍微复杂,但只要你细心,坚持的敲上几遍,相信你的编程能力会极大的提升,加油~

若在本项目中遇到技术难题,可在下方评论区留言或私信我,授人以鱼不如授人以渔

上一篇:(转载)成长,没你想象的那么迫切


下一篇:前后端分离 -- 深入浅出 Spring Boot + Vue + ElementUI 实现相册管理系统【文件上传 分页 】 文件上传也不过如此~