云服务管理云平台

01项目开发流程

1.根据需求文档分析整个项目,进行相关表的设计

通过需求文档分析各个模块需要的表以及表与表之间的关系
‘‘表的设计没有对错之分,只有合理不合理’’

2.前端项目搭建

项目开发使用阿里开源的前端框架ant design,此框架是使用vue来完成具体功能的,采用前后端分离的方式进行开发,也比较符合在公司中的开发场景,前端工程师负责实现前端的功能,后端工程师就完成后端逻辑的编写。采用webstorm,下载好前端模板
操作步骤
1.下载前端项目并进行解压
2.在webstorm的命令行中,输入指令npm install 安装npm
3.安装完成后,使用 npm run serve 运行项目

3.后端项目搭建

使用springboot 搭建,打开idea创建一个新项目,选择spring initializing
接着考虑自己需要添加的组件,比如web的项目肯定要springmvc的数据库肯定要有,还有像需要日志功能,就要添加mybatis组件
选择devtools(热部署),spring web , mysql driver, mybatis framework

添加依赖:

   <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--mybatis代码快速生成-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>

完成项目的搭建之后,通过mybatis-plus 反向生成实体类,通过事先准备好的逻辑代码,生成对应的mapper、service、controller和bean

知识点:mybatis-plus 是通过导入依赖 然后创建一个测试类,通过new generator 的方式
也就是创建一个自动生成器 通过全局配置、策略配置、数据源配置,包名配置 去自动生成与数据库表相对应的实体类

public class TestGenerator {  //Generator  生成器

    @Test
    public void testGenerator() {
        AutoGenerator autoGenerator = new AutoGenerator();

        //全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setAuthor("liu")
                .setOutputDir("D:\\workspace\\family_service_platform\\src\\main\\java")//设置输出路径
                .setFileOverride(true)//设置文件覆盖
                .setIdType(IdType.AUTO)//设置主键生成策略
                .setServiceName("%sService")//service接口的名称
                .setBaseResultMap(true)//基本结果集合
                .setBaseColumnList(true)//设置基本的列
                .setControllerName("%sController");

        //配置数据源
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver").setUrl("jdbc:mysql://localhost:3306/family_service_platform?serverTimezone=UTC")
                .setUsername("root").setPassword("root");

        //策略配置
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setCapitalMode(true)//设置全局大写命名
                .setNaming(NamingStrategy.underline_to_camel)//数据库表映射到实体的命名策略
                //.setTablePrefix("tbl_")//设置表名前缀
                .setInclude();

        //包名配置
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setParent("com.mashibing").setMapper("mapper")
                .setService("service").setController("controller")
                .setEntity("bean").setXml("mapper");

        autoGenerator.setGlobalConfig(globalConfig).setDataSource(dataSourceConfig)
                .setStrategy(strategyConfig).setPackageInfo(packageConfig);

        autoGenerator.execute();
    }
}

生成完对应的实体类之后,进行配置文件的配置,作为一个网络服务,先配置端口号,数据源,mybatis,sql提示

#项目服务启动端口
server:
  port: 8080
# 数据源配置   数据库连接池使用springboot 自带的hikari
spring:

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/family_service_platform?serverTimeZone=UTC&useSSL=false
    username: root
    password: root
#  profiles:  配置不同的环境切换  比如:线上环境、生产环境、测试环境
#    active:

# mybatis配置
mybatis:
  mapper-locations:  classpath:com/mashibing/mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true
# sql 语句日志打印   主要是提示功能
logging:
  level:
    com:
      mashibing:
        mapper: debug

尝试运行项目:报错啦
Error creating bean with name ‘fcBuildingServiceImpl’: fcBuildingServiceImpl创建不了
No qualifying bean of type ‘com.mashibing.mapper.FcBuildingMapper’ available 当前的mapper并不存在
原因就是:创建mapper文件之后 并没有加注解 导致mapper文件识别不到 对于157张表,每一个映射文件都加过于繁琐 这是可以在启动类上加一个 @mapperscan

2022-02-24 12:57:10.749 ERROR 28800 --- [  restartedMain] o.s.boot.SpringApplication               : Application run failed


> Error creating bean with name 'fcBuildingServiceImpl':  Unsatisfied
> dependency expressed through field 'baseMapper'; nested exception is
> org.springframework.beans.factory.NoSuchBeanDefinitionException: No
> qualifying bean of type 'com.mashibing.mapper.FcBuildingMapper'
> available: expected at least 1 bean which qualifies as autowire
> candidate. Dependency annotations:
> {@org.springframework.beans.factory.annotation.Autowired(required=true)}
> 	at
> org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:659)
> ~[spring-beans-5.3.15.jar:5.3.15] 	at
> org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:639)
> ~[spring-beans-5.3.15.jar:5.3.15] 	at
> org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)
> ~[spring-beans-5.3.15.jar:5.3.15]

测试web请求是否有效:在controller中新建一个test类,然后控制台打印数据,看请求发送后,控制台能否打印数据

//@Controller
@RestController //== controller + responsebody
public class TestController {
    @RequestMapping("/test")
    public String test(){
        System.out.println("test");//控制台打印test
        return "";
    }
}

测试有效之后就开始写代码逻辑,环境准备工作就已经完成了

知识点:
跨域问题:比如说在8000端口中请求8080的数据 这在前后端分离的架构中是比较麻烦的
解决:

第一步:先让从8000端口的访问跳转到8080
首先关闭前端模拟的真实数据,也就是mock
preview 预览
1.在env.development 文件中 设置preview= false
2.URL改成我们需要的地址 比如 http://localhost:8080/
3.在main.js中 关闭导入mock包
之后就可以实现在8000端口中,访问8080端口,在network中可以看到
注意一点的就是:即使你在后端代码中,加入了对应的网址映射,但是此时并不能访问,这就涉及到跨域问题的核心

这里有两种方式:
第一种是写一个配置类
第二种是使用注解
不同的是,配置类属于全局配置,注解可能需要每个controller都需要加

配置类方式:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        //  你需要跨域的地址  注意这里的 127.0.0.1 != localhost
        // * 表示对所有的地址都可以访问
        corsConfiguration.addAllowedOriginPattern("*");
        //  跨域的请求头
        corsConfiguration.addAllowedHeader("*"); // 2
        //  跨域的请求方法
        corsConfiguration.addAllowedMethod("*"); // 3
        //加上了这一句,大致意思是可以携带 cookie
        //最终的结果是可以 在跨域请求的时候获取同一个 session
        corsConfiguration.setAllowCredentials(true);
        return corsConfiguration;
    }
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        //配置 可以访问的地址
        source.registerCorsConfiguration("/**", buildConfig()); // 4
        return new CorsFilter(source);
    }
}

注解方式:直接在对应的controller类中加入注解

@CrossOrigin(originPatterns = "*",allowCredentials = "true",allowedHeaders = "*",methods = {})

知识点:
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出Http请求,从而克服了AJAX只能同源使用的限制。
origin:起源
Credentials:资格
Pattern:模型

跨域配置报错:
SpringBoot升级2.4.0所出现的问题
跨域配置报错,将.allowedOrigins替换成.allowedOriginPatterns即可。
注解方式:
也需要将origin参数换成originpatterns

02登录功能实现

​ 在上一节中我们把基本的环境都准备好了,下面开始进行登录模块的编写。

1、登录请求

​ 打开登录页面之后,用户可以输入用户名和密码,然后点击登录,需要去数据库验证用户名和密码是否正确。在 输入用户名和密码之后,需要在springboot中接受参数,而前后端分离的项目参数的接受比较有意思,不能直接接受,需要进行转换。

​ 下面介绍两种方式,大家按照自己喜欢的方式编写即可:

​ (1)使用@RequestBody接受参数

 @RequestMapping("/auth/login")
    public String login(@RequestBody Map<String,Object> map){
        System.out.println("login");
        System.out.println(map);
        return "success";
    }

​ (2)在前端传递参数的时候,进行数据的转换,转换成后端能直接接受的方式

​ 在前端项目的根目录下运行 npm install qs,安装对应的组件,并且在登录的方法调用前添加如下代码:

 const QS = require('qs')
 const data = QS.stringify(loginParams)

​ 在接受参数的方法上controller方法上编写如下代码:

    @RequestMapping("/auth/login")
    public String login(String username,String password){
        System.out.println("login");
        System.out.println(username+"------"+password);
        return "success";
    }

2、编写登录后续逻辑

1、编写mapper类及对应的配置文件

TblUserRecordMapper.java

public interface TblUserRecordMapper extends BaseMapper<TblUserRecord> {
    public TblUserRecord login(@Param("username") String username,@Param("password") String password);
}

TblUserRecordMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjmsb.mapper.TblUserRecordMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.bjmsb.bean.TblUserRecord">
        <id column="id" property="id" />
        <result column="user_name" property="userName" />
        <result column="user_password" property="userPassword" />
        <result column="user_type" property="userType" />
        <result column="user_role" property="userRole" />
        <result column="user_gender" property="userGender" />
        <result column="user_dept" property="userDept" />
        <result column="user_job" property="userJob" />
        <result column="user_status" property="userStatus" />
        <result column="office_phone" property="officePhone" />
        <result column="inner_phone" property="innerPhone" />
        <result column="move_phone" property="movePhone" />
        <result column="email" property="email" />
        <result column="is_send_msg" property="isSendMsg" />
        <result column="start_date" property="startDate" />
        <result column="stop_date" property="stopDate" />
        <result column="birthday" property="birthday" />
        <result column="ip_rule" property="ipRule" />
        <result column="user_hiredate" property="userHiredate" />
        <result column="is_send_wchat" property="isSendWchat" />
        <result column="remark" property="remark" />
        <result column="company" property="company" />
        <result column="is_dept_admin" property="isDeptAdmin" />
        <result column="last_login_date" property="lastLoginDate" />
        <result column="create_person" property="createPerson" />
        <result column="create_date" property="createDate" />
    </resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, user_name, user_password, user_type, user_role, user_gender, user_dept, user_job, user_status, office_phone, inner_phone, move_phone, email, is_send_msg, start_date, stop_date, birthday, ip_rule, user_hiredate, is_send_wchat, remark, company, is_dept_admin, last_login_date, create_person, create_date
    </sql>
    <select id="login" resultMap="loginResultMap">
        select a.*,
            b.dept_privileges,
            b.dept_manage_privileges,
            c.role_privileges,
            d.company_simple_name
        from tbl_user_record a
        left outer join tbl_dept b on a.user_dept = b.id
        left outer join tbl_role c on a.user_role = c.id
        left outer join tbl_company d on a.company= d.id
        where a.user_name = #{username} and a.user_password=#{userPassword}
    </select>
    <resultMap id="loginResultMap" type="com.bjmsb.bean.TblUserRecord">
        <result column="user_name" property="userName" />
        <result column="user_password" property="userPassword" />
        <result column="user_type" property="userType" />
        <result column="user_gender" property="userGender" />
        <result column="user_job" property="userJob" />
        <result column="user_status" property="userStatus" />
        <result column="office_phone" property="officePhone" />
        <result column="inner_phone" property="innerPhone" />
        <result column="move_phone" property="movePhone" />
        <result column="email" property="email" />
        <result column="is_send_msg" property="isSendMsg" />
        <result column="start_date" property="startDate" />
        <result column="stop_date" property="stopDate" />
        <result column="birthday" property="birthday" />
        <result column="ip_rule" property="ipRule" />
        <result column="user_hiredate" property="userHiredate" />
        <result column="is_send_wchat" property="isSendWchat" />
        <result column="remark" property="remark" />
        <result column="is_dept_admin" property="isDeptAdmin" />
        <result column="last_login_date" property="lastLoginDate" />
        <result column="create_person" property="createPerson" />
        <result column="create_date" property="createDate" />
        <association property="tblRole" javaType="com.bjmsb.bean.TblRole">
            <result property="rolePrivileges" column="role_privileges"></result>
        </association>
        <association property="tblDept" javaType="com.bjmsb.bean.TblDept">
            <result property="deptPrivileges" column="dept_privileges"></result>
            <result property="deptManagePrivileges" column="dept_manage_privileges"></result>
        </association>
        <association property="tblCompany" javaType="com.bjmsb.bean.TblCompany">
            <result property="companySimpleName" column="company_simple_name"></result>
        </association>
    </resultMap>
</mapper>

LoginService.java

package com.bjmsb.service;

import com.bjmsb.bean.TblUserRecord;
import com.bjmsb.mapper.TblUserRecordMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class LoginService {
    @Autowired
    private TblUserRecordMapper tblUserRecordMapper;

    public TblUserRecord login(String username, String password){
        return tblUserRecordMapper.login(username,password);
    }
}

LoginController.java

@RequestMapping("/auth/login")
    public TblUserRecord login(String username,String password){
        System.out.println("login");
        TblUserRecord tblUserRecord = loginService.login(username, password);
        System.out.println(tblUserRecord);
        return tblUserRecord;
    }

按道理来说,我们现在运行应该是可以成功的,但是事与愿违,发现运行不成功,下面开始来排查问题。

1、类型不匹配

​ 因为是关联查询,需要在对应的实体类上添加对应的实体类,而不是属性值

package com.bjmsb.bean;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime;
import java.io.Serializable;

/**
 * <p>
 * 用户档案
 * </p>
 *
 * @author lian
 * @since 2020-04-15
 */
public class TblUserRecord implements Serializable {

    private static final long serialVersionUID=1L;

    /**
     * 用户编号
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 用户姓名
     */
    private String userName;

    /**
     * 用户密码
     */
    private String userPassword;

    /**
     * 用户类型
     */
    private String userType;

    /**
     * 岗位角色
     */
    private TblRole tblRole;

    /**
     * 用户性别
     */
    private String userGender;

    /**
     * 所属部门
     */
    private TblDept tblDept;

    /**
     * 职位
     */
    private Integer userJob;

    /**
     * 用户状态
     */
    private String userStatus;

    /**
     * 办公电话
     */
    private String officePhone;

    /**
     * 内线电话
     */
    private String innerPhone;

    /**
     * 移动电话
     */
    private String movePhone;

    /**
     * 电子邮箱
     */
    private String email;

    /**
     * 允许发送手机短信
     */
    private String isSendMsg;

    /**
     * 有效开始日期
     */
    private LocalDateTime startDate;

    /**
     * 有效结束日期
     */
    private LocalDateTime stopDate;

    /**
     * 出生日期
     */
    private LocalDateTime birthday;

    /**
     * 登陆ip规则
     */
    private String ipRule;

    /**
     * 入职日期
     */
    private LocalDateTime userHiredate;

    /**
     * 允许发送微信
     */
    private String isSendWchat;

    /**
     * 备注
     */
    private String remark;

    /**
     * 所属公司
     */
    private TblCompany tblCompany;

    /**
     * 是否部门管理者
     */
    private String isDeptAdmin;

    /**
     * 最后登陆时间
     */
    private LocalDateTime lastLoginDate;

    /**
     * 创建人
     */
    private String createPerson;

    /**
     * 创建时间
     */
    private LocalDateTime createDate;

    private String token;

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserPassword() {
        return userPassword;
    }

    public void setUserPassword(String userPassword) {
        this.userPassword = userPassword;
    }

    public String getUserType() {
        return userType;
    }

    public void setUserType(String userType) {
        this.userType = userType;
    }

    public TblRole getTblRole() {
        return tblRole;
    }

    public void setTblRole(TblRole tblRole) {
        this.tblRole = tblRole;
    }

    public String getUserGender() {
        return userGender;
    }

    public void setUserGender(String userGender) {
        this.userGender = userGender;
    }

    public TblDept getTblDept() {
        return tblDept;
    }

    public void setTblDept(TblDept tblDept) {
        this.tblDept = tblDept;
    }

    public Integer getUserJob() {
        return userJob;
    }

    public void setUserJob(Integer userJob) {
        this.userJob = userJob;
    }

    public String getUserStatus() {
        return userStatus;
    }

    public void setUserStatus(String userStatus) {
        this.userStatus = userStatus;
    }

    public String getOfficePhone() {
        return officePhone;
    }

    public void setOfficePhone(String officePhone) {
        this.officePhone = officePhone;
    }

    public String getInnerPhone() {
        return innerPhone;
    }

    public void setInnerPhone(String innerPhone) {
        this.innerPhone = innerPhone;
    }

    public String getMovePhone() {
        return movePhone;
    }

    public void setMovePhone(String movePhone) {
        this.movePhone = movePhone;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getIsSendMsg() {
        return isSendMsg;
    }

    public void setIsSendMsg(String isSendMsg) {
        this.isSendMsg = isSendMsg;
    }

    public LocalDateTime getStartDate() {
        return startDate;
    }

    public void setStartDate(LocalDateTime startDate) {
        this.startDate = startDate;
    }

    public LocalDateTime getStopDate() {
        return stopDate;
    }

    public void setStopDate(LocalDateTime stopDate) {
        this.stopDate = stopDate;
    }

    public LocalDateTime getBirthday() {
        return birthday;
    }

    public void setBirthday(LocalDateTime birthday) {
        this.birthday = birthday;
    }

    public String getIpRule() {
        return ipRule;
    }

    public void setIpRule(String ipRule) {
        this.ipRule = ipRule;
    }

    public LocalDateTime getUserHiredate() {
        return userHiredate;
    }

    public void setUserHiredate(LocalDateTime userHiredate) {
        this.userHiredate = userHiredate;
    }

    public String getIsSendWchat() {
        return isSendWchat;
    }

    public void setIsSendWchat(String isSendWchat) {
        this.isSendWchat = isSendWchat;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public TblCompany getTblCompany() {
        return tblCompany;
    }

    public void setTblCompany(TblCompany tblCompany) {
        this.tblCompany = tblCompany;
    }

    public String getIsDeptAdmin() {
        return isDeptAdmin;
    }

    public void setIsDeptAdmin(String isDeptAdmin) {
        this.isDeptAdmin = isDeptAdmin;
    }

    public LocalDateTime getLastLoginDate() {
        return lastLoginDate;
    }

    public void setLastLoginDate(LocalDateTime lastLoginDate) {
        this.lastLoginDate = lastLoginDate;
    }

    public String getCreatePerson() {
        return createPerson;
    }

    public void setCreatePerson(String createPerson) {
        this.createPerson = createPerson;
    }

    public LocalDateTime getCreateDate() {
        return createDate;
    }

    public void setCreateDate(LocalDateTime createDate) {
        this.createDate = createDate;
    }

    @Override
    public String toString() {
        return "TblUserRecord{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", userPassword='" + userPassword + '\'' +
                ", userType='" + userType + '\'' +
                ", tblRole=" + tblRole +
                ", userGender='" + userGender + '\'' +
                ", tblDept=" + tblDept +
                ", userJob=" + userJob +
                ", userStatus='" + userStatus + '\'' +
                ", officePhone='" + officePhone + '\'' +
                ", innerPhone='" + innerPhone + '\'' +
                ", movePhone='" + movePhone + '\'' +
                ", email='" + email + '\'' +
                ", isSendMsg='" + isSendMsg + '\'' +
                ", startDate=" + startDate +
                ", stopDate=" + stopDate +
                ", birthday=" + birthday +
                ", ipRule='" + ipRule + '\'' +
                ", userHiredate=" + userHiredate +
                ", isSendWchat='" + isSendWchat + '\'' +
                ", remark='" + remark + '\'' +
                ", tblCompany=" + tblCompany +
                ", isDeptAdmin='" + isDeptAdmin + '\'' +
                ", lastLoginDate=" + lastLoginDate +
                ", createPerson='" + createPerson + '\'' +
                ", createDate=" + createDate +
                '}';
    }
}
2、页面无法实现跳转,报错信息还是请求出现错误,请稍后再试

​ 前端在进行数据回显的时候,会发生写错误,这个错误很难去做判断,但是可以一步步观察,注意细节和过程。

​ 用户在验证完用户名和密码之后,会回显数据,我们看到请求确实是200,但是依然有问题,会执行requestFailed方法,此时意味着一定出现了问题

requestFailed(err) {
            this.isLoginError = true
            this.$notification['error']({
                message: '错误',
                description: ((err.response || {}).data || {}).message || '请求出现错误,请稍后再试',
                duration: 4
            })
        }

问题出现在哪里呢?其实很简单,我们在进行数据回显的时候,要求是json格式,而我们回显的直接是一个对象,所以此时肯定是有问题的,因此需要把具体的对象转换成json格式进行返回。

    @RequestMapping("/auth/login")
    public JSONObject login(String username,String password){
        System.out.println("login");
        TblUserRecord tblUserRecord = loginService.login(username, password);
        System.out.println(tblUserRecord);
        return JSONObject.parseObject(JSONObject.toJSONString(tblUserRecord));
    }
3、此时发现还是没有办法跳转,这是为什么呢?可以通过观察他的mock数据集在查看,在auth.js文件中
return builder(
        {
            id: Mock.mock('@guid'),
            name: Mock.mock('@name'),
            username: 'admin',
            password: 'admin',
            avatar: 'https://gw.alipayobjects.com/zos/rmsportal/jZUIxmJycoymBprLOUbT.png',
            status: 1,
            telephone: '',
            lastLoginIp: '27.154.74.117',
            lastLoginTime: 1534837621348,
            creatorId: 'admin',
            createTime: 1497160610259,
            deleted: 0,
            roleId: 'admin',
            lang: 'zh-CN',
            token: '4291d7da9005377ec9aec4a71ea837f'
        },
        '',
        200,
        { 'Custom-Header': Mock.mock('@guid') }
    )

这是预先给出的数据格式,我们在不搭建后端服务的时候,大家发现返回的是这样的数据,也就是说我们需要返回类似于这样的数据,但是观察后发现其实需要的是几个字段,message,code,result,而在执行成功之后需要拉取的数据是result中的token,其实result就是我们要回显的数据,因此我们要组织类似的数据格式。

1、在TblUserRecord类中添加token的关键字段

2、设置返回的数据类型,添加json包,并且创建common类

package com.bjmsb.json;

public class Common {
    private String message = "";
    private Integer code = 200;
    private Object result;

    public Common() {
    }

    public Common(Object result) {
        this.result = result;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }

    @Override
    public String toString() {
        return "Common{" +
                "message='" + message + '\'' +
                ", code=" + code +
                ", result=" + result +
                '}';
    }
}

3、拼接返回对象

@RequestMapping("/auth/login")
public JSONObject login(String username,String password){
    System.out.println("login");
    TblUserRecord tblUserRecord = loginService.login(username, password);
    System.out.println(tblUserRecord);
    tblUserRecord.setToken(tblUserRecord.getUserName());
    Common common = new Common(tblUserRecord);
    return JSONObject.parseObject(JSONObject.toJSONString(common));
}

​ 此时大家发现在页面弹出的窗口有两个,一个是成功,一个是失败,成功表明用户名和密码的验证已经成功了,但是依然还有一个错误提示,这又是为什么呢?下面来开始解决这个问题

3、实现登录成功正常跳转

​ 在此前端框架中,有非常严格的权限管理,因此我们在进行数据回显的时候也需要权限的验证,大家可以看permission.js文件

router.beforeEach((to, from, next) => {
  NProgress.start() // start progress bar
  to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${to.meta.title} - ${domTitle}`))
  if (Vue.ls.get(ACCESS_TOKEN)) {
    /* has token */
    if (to.path === '/user/login') {
      next({ path: defaultRoutePath })
      NProgress.done()
    } else {
      if (store.getters.roles.length === 0) {
        store
          .dispatch('GetInfo')
          .then(res => {
            const roles = res.result && res.result.role
            console.dir(roles)
            store.dispatch('GenerateRoutes', { roles }).then(() => {
              // 根据roles权限生成可访问的路由表
              // 动态添加可访问路由表
              router.addRoutes(store.getters.addRouters)
              console.log(store.getters.addRouters)
              // 请求带有 redirect 重定向时,登录自动重定向到该地址
              const redirect = decodeURIComponent(from.query.redirect || to.path)
              if (to.path === redirect) {
                // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
                next({ ...to, replace: true })
              } else {
                // 跳转到目的路由
                next({ path: redirect })
              }
            })
          })
          .catch(() => {
            notification.error({
              message: '错误',
              description: '请求用户信息失败,请重试'
            })
            store.dispatch('Logout').then(() => {
              next({ path: '/user/login', query: { redirect: to.fullPath } })
            })
          })
      } else {
        next()
      }
    }
  } else {
    if (whiteList.includes(to.name)) {
      // 在免登录白名单,直接进入
      next()
    } else {
      next({ path: '/user/login', query: { redirect: to.fullPath } })
      NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
    }
  }
})

​ 此时的话,可以看到紧接着会发送一个/auth/info的请求,相当于发送请求,获取权限,来判断可以显示哪些模块功能。此处的话可以参考官方文档:

https://pro.loacg.com/docs/authority-management

这个权限管理包含了非常细致的权限管理,我们其实不需要这么多,此框架提供的粒度太细致了,包含了按钮的具体操作,因此我们需要简化开发,只需要返回类似于这样的数据格式即可:

{
  message: "ok",
  result: {
    name: "admin",
    avatar: "/avatar2.jpg",
    role: {
      permissions: [
        {
          permissionId: "901"
        },
        {
          permissionId: "221"
        },
        {
          permissionId: "223",
        },
        {
          permissionId: "226",
        },
      ],
    },
  },
  code: 200,
}

下面开始组织这样的样式:

定义对应的实体类,在json包下:

Permission.java

package com.bjmsb.json;

public class Permission {
    private String permissionId;

    public Permission() {
    }

    public Permission(String permissionId) {
        this.permissionId = permissionId;
    }

    public String getPermissionId() {
        return permissionId;
    }

    public void setPermissionId(String permissionId) {
        this.permissionId = permissionId;
    }

    @Override
    public String toString() {
        return "Permission{" +
                "permissionId='" + permissionId + '\'' +
                '}';
    }
}

Permissions.java

package com.bjmsb.json;

import java.util.List;

public class Permissions {
    private List<Permission> permissions;

    public List<Permission> getPermissions() {
        return permissions;
    }

    public void setPermissions(List<Permission> permissions) {
        this.permissions = permissions;
    }

    @Override
    public String toString() {
        return "Permissions{" +
                "permissions=" + permissions +
                '}';
    }
}

UserInfo.java

package com.bjmsb.json;

public class UserInfo {

    private String name;
    private String avatar = "/avatar2.jpg";
    private Permissions role;

    public UserInfo() {
    }

    public UserInfo(String name, Permissions role) {
        this.name = name;
        this.role = role;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAvatar() {
        return avatar;
    }

    public void setAvatar(String avatar) {
        this.avatar = avatar;
    }

    public Permissions getRole() {
        return role;
    }

    public void setRole(Permissions role) {
        this.role = role;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
                "name='" + name + '\'' +
                ", avatar='" + avatar + '\'' +
                ", role=" + role +
                '}';
    }
}

编写对应的controller中的方法,在编写此逻辑的时候我们发现需要获取用户的数据,此处如果重新发送请求的话会比较麻烦,因此我们需要从login中设置session,然后在另外的一个方法中获取session中的值,因此需要修改我们的代码如下:

@RequestMapping("/auth/login")
    public JSONObject login(String username, String password, HttpSession session){
        TblUserRecord tblUserRecord = loginService.login(username, password);
        tblUserRecord.setToken(tblUserRecord.getUserName());
        session.setAttribute("userRecord",tblUserRecord);
        Common common = new Common();
        common.setResult(tblUserRecord);
        return JSONObject.parseObject(JSONObject.toJSONString(common));
    }

    @RequestMapping("/user/info")
    public JSONObject userInfo(HttpSession session){
        //获取用户数据
        TblUserRecord userRecord = (TblUserRecord) session.getAttribute("userRecord");
        //获取对应用户需要账务的功能模块
        String[] rolePrivileges = userRecord.getTblRole().getRolePrivileges().split("-");
        // 拼接需要返回的数据对象的格式
        Permissions permissions = new Permissions();
        List<Permission> permissionList = new ArrayList<>();
        for (String rolePrivilege : rolePrivileges) {
            permissionList.add(new Permission(rolePrivilege));
        }
        permissions.setPermissions(permissionList);
        UserInfo userInfo = new UserInfo(userRecord.getUserName(),permissions);
        Common common = new Common(userInfo);
        return JSONObject.parseObject(JSONObject.toJSONString(common));
    }

​ 当你这样写完之后,发现并没有成功,报了空指针异常,其实就是从session中并没有获取到对应的数据,为什么呢?为什么不是同一个session对象呢?

​ 其实最根本的原因就在于跨域的问题,导致开启了不同的会话,因此需要在前端添加额外的设置。

​ 需要在request.js中添加如下配置:

axios.defaults.withCredentials = true

当完成这步操作之后,大家发现我们终于进入到页面中了,怎么样是不是很嗨皮!!!开发项目的时候会遇到各种各样的问题,但是遇到项目不要慌,(先拿出手机拍个抖音),开玩笑而已,遇到问题解决问题即可,不要觉得麻烦,也不要觉得累,出现的错误越多,那么你成长的就越快,所以,干就完了!!!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zJ4AK6qs-1646046255640)(image\崩溃.jpg)]

4、登录退出

​ 找到退出登录的页面,在src\components\tools\UserMenu.vue目录下,并且在controller中添加退出登录的方法:

    @RequestMapping("/auth/logout")
    public JSONObject loginOut(HttpSession session){
        System.out.println("退出登录");
        session.invalidate();
        return JSONObject.parseObject(JSONObject.toJSONString(new Common(null)));
    }

03 楼盘管理

1、新增住宅向导-Step1

​ 本模块来完成新增住宅向导的功能

​ 1、当点击新增住宅向导之后,需要添加查询相关的公司数据作为下拉列表的展示,添加前端请求

创建新的请求文件

estate.js

import { axios } from '@/utils/request'

export function selectCompany() {
    return axios({
        url: '/estate/selectCompany',
        method: 'get'
    })
}

export function insertEstate(params) {
    return axios({
        url: '/estate/insertEstate',
        method: 'post',
        data: params
    })
}

<script>
    import { insertEstate, selectCompany } from '@/api/estate'
    const QS = require('qs')
    export default {
        name: 'Step1',
        data() {
            return {
                select: [],
                labelCol: { lg: { span: 6 }, sm: { span: 4 } },
                wrapperCol: { lg: { span: 16 }, sm: { span: 20 } },
                form: {
                    company: [],
                    estateCode: '',
                    estateName: '',
                    coverArea: '',
                    buildArea: '',
                    greenArea: '',
                    roadArea: '',
                    buildingNumber: '',
                    buildingLeader: '',
                    estateAddr: '',
                    companyName: '',
                    companyBehalf: '',
                    contact: '',
                    contactPhone: '',
                    remark: ''
                },
                rules: {
                    estateCode: [
                        { required: true, message: '住宅编码必须填写', trigger: 'blur' }
                        // { min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' }
                    ],
                    company: [{ required: true, message: '所属公司必须填写', trigger: 'change' }],
                    estateName: [{ required: true, message: '住宅名称必须填写', trigger: 'blur' }],
                    buildingNumber: [
                        {
                            required: true,
                            message: '楼宇数量必须填写',
                            trigger: 'change'
                        },
                        { min: 1, max: 20, type: 'number', message: 'Length should be 1 to 20', trigger: 'change' }
                    ]
                }
            }
        },
        created() {
            selectCompany().then(res => {
                    this.select = res.result
                }).catch(err => {
                this.$notification['error']({
                    message: '错误',
                    description: ((err.response || {}).data || {}).message || '获取公司信息失败',
                    duration: 4
                })
            })
        },
        methods: {
            nextStep() {
                this.$refs.ruleForm.validate(valid => {
                    if (valid) {
                        const data = QS.stringify(this.form)
                        insertEstate(data).then(res => {
                            if (res.message === '1') {
                                setTimeout(() => {
                                    this.$notification.success({
                                        message: '恭喜你',
                                        description: res.result
                                    })
                                }, 1000)
                                this.$store.commit('SET_TITLE', {
                                    buildingNumber: this.form.buildingNumber,
                                    estateCode: this.form.estateCode
                                })
                                this.$emit('nextStep')
                            } else {
                                setTimeout(() => {
                                    this.$notification.error({
                                        message: '抱歉',
                                        description: res.result
                                    })
                                }, 1000)
                            }
                        }
                        ).catch(err => {
                            this.$notification.error({
                                message: err.result,
                                description: ((err.response || {}).data || {}).message || '插入房产信息失败',
                                duration: 1
                            })
                        })
                    } else {
                        console.log('error submit!!')
                        return false
                    }
                })
            },
            resetForm() {
                this.$refs.ruleForm.resetFields()
                console.log(this.$refs.ruleForm.resetFields)
            }
        }
    }
</script>

​ 2、编写后端逻辑

EstateController.java

package com.bjmsb.controller;

import com.alibaba.fastjson.JSONObject;
import com.bjmsb.bean.FcEstate;
import com.bjmsb.json.Common;
import com.bjmsb.service.EstateService;
import com.bjmsb.service.common.FcEstateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
//@CrossOrigin(origins = "*",allowCredentials="true",allowedHeaders = "*",methods = {})
public class EstateController {

    @Autowired
    private EstateService estateService;

    @RequestMapping("/estate/selectCompany")
    public JSONObject selectCompany(){
        System.out.println("/estate/selectCompany");
        List<String> tblCompanyNames = estateService.selectCompany();
        return JSONObject.parseObject(JSONObject.toJSONString(new Common(tblCompanyNames)));
    }

    @RequestMapping("/estate/insertEstate")
    public JSONObject insertEstate(FcEstate fcEstate){
        System.out.println("insert estate");
        Integer result = estateService.insertEstate(fcEstate);
        if (result==0){
            return JSONObject.parseObject(JSONObject.toJSONString(new Common("房产编码已存在","0")));
        }else{
            return JSONObject.parseObject(JSONObject.toJSONString(new Common("插入房产成功","1")));
        }
    }
}

EstateService.java

package com.bjmsb.service;

import com.bjmsb.bean.FcEstate;
import com.bjmsb.bean.TblCompany;
import com.bjmsb.mapper.FcEstateMapper;
import com.bjmsb.mapper.TblCompanyMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class EstateService {

    @Autowired
    private TblCompanyMapper tblCompanyMapper;

    @Autowired
    private FcEstateMapper fcEstateMapper;

    public List<String> selectCompany(){
        List<String> tblCompanies = tblCompanyMapper.selectCompany();
        return tblCompanies;
    }

    /**
     * 在此逻辑中需要先做判断,判断数据库中是否已经存在编码,如果存在,那么对用户发出提示
     * @param fcEstate
     * @return
     */
    public Integer insertEstate(FcEstate fcEstate){
        int result = 0;
        QueryWrapper<FcEstate> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("estate_code", fcEstate.getEstateCode());
        FcEstate fe = fcEstateMapper.selectOne(queryWrapper);
        if (fe==null){
            result = fcEstateMapper.insert(fcEstate);
        }
        return result;
    }
}

TblCompanyMapper.java

@Component
public interface TblCompanyMapper extends BaseMapper<TblCompany> {

    public List<String> selectCompany();
}

TblCompanyMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjmsb.mapper.TblCompanyMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.bjmsb.bean.TblCompany">
        <id column="id" property="id" />
        <result column="company_full_name" property="companyFullName" />
        <result column="company_simple_name" property="companySimpleName" />
        <result column="company_english_name" property="companyEnglishName" />
        <result column="company_brand" property="companyBrand" />
        <result column="company_type" property="companyType" />
        <result column="company_trade" property="companyTrade" />
        <result column="company_addr" property="companyAddr" />
        <result column="post_code" property="postCode" />
        <result column="company_phone" property="companyPhone" />
        <result column="company_fax" property="companyFax" />
        <result column="company_website" property="companyWebsite" />
        <result column="company_email" property="companyEmail" />
        <result column="company_national" property="companyNational" />
        <result column="company_land" property="companyLand" />
        <result column="open_bank" property="openBank" />
        <result column="bank_account" property="bankAccount" />
        <result column="company_leader" property="companyLeader" />
        <result column="register_date" property="registerDate" />
        <result column="register_money" property="registerMoney" />
        <result column="employee_number" property="employeeNumber" />
        <result column="company_intro" property="companyIntro" />
        <result column="remark" property="remark" />
    </resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, company_full_name, company_simple_name, company_english_name, company_brand, company_type, company_trade, company_addr, post_code, company_phone, company_fax, company_website, company_email, company_national, company_land, open_bank, bank_account, company_leader, register_date, register_money, employee_number, company_intro, remark
    </sql>

    <!--查询所有的公司名称-->
    <select id="selectCompany" resultType="String">
        select company_full_name from tbl_company
    </select>
</mapper>

FcEstateMapper.java

@Component
public interface FcEstateMapper extends BaseMapper<FcEstate> {

}

FcEstateMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjmsb.mapper.FcEstateMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.bjmsb.bean.FcEstate">
        <id column="id" property="id" />
        <result column="estate_code" property="estateCode" />
        <result column="estate_name" property="estateName" />
        <result column="estate_addr" property="estateAddr" />
        <result column="cover_area" property="coverArea" />
        <result column="build_area" property="buildArea" />
        <result column="green_area" property="greenArea" />
        <result column="road_area" property="roadArea" />
        <result column="building_number" property="buildingNumber" />
        <result column="building_leader" property="buildingLeader" />
        <result column="company_name" property="companyName" />
        <result column="company_behalf" property="companyBehalf" />
        <result column="contact" property="contact" />
        <result column="contact_phone" property="contactPhone" />
        <result column="contact_addr" property="contactAddr" />
        <result column="car_space_delay_rate" property="carSpaceDelayRate" />
        <result column="car_space_over_day" property="carSpaceOverDay" />
        <result column="estate_type" property="estateType" />
        <result column="street_lamp_number" property="streetLampNumber" />
        <result column="hfcNum" property="hfcNum" />
        <result column="remark" property="remark" />
        <result column="company" property="company" />
    </resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, estate_code, estate_name, estate_addr, cover_area, build_area, green_area, road_area, building_number, building_leader, company_name, company_behalf, contact, contact_phone, contact_addr, car_space_delay_rate, car_space_over_day, estate_type, street_lamp_number, hfcNum, remark, company
    </sql>
</mapper>

2、Step1-Step2数据传递问题

​ 当完成第二个页面的跳转之后,大家发现了一个问题,在页面的最上面会引入一个楼宇的数量,我们很明显的知道楼宇的数据来源于step1中设置的值,那么问题就来了,如何把第一个页面设置的值传递到第二个页面呢?这里我们使用vuex这样一个组件来完成具体的功能。

1、在step1中实现页面跳转之前,我们需要实现如下的定义:

 this.$store.commit('SET_TITLE',{
                        buildingNumber: this.form.buildingNumber
                    })
                    this.$emit('nextStep')

2、在store目录下创建一个新的文件叫做oneStep.js的文件,定义如下内容

const oneStep = {
    state: {
        buildingNumber: ''
    },
    mutations: {
        // 这里只能是同步的
        SET_TITLE(state, payload) {
            console.log(payload)
            state.buildingNumber = payload.buildingNumber
        }
    },
    actions: {

    },
    getters: {

    }
}
export default oneStep

3、在下面的index.js文件中将定义好的oneStep定义成一个模块

import Vue from 'vue'
import Vuex from 'vuex'

import app from './modules/app'
import user from './modules/user'
// default router permission control
import permission from './modules/permission'
import oneStep from './modules/oneStep'
// dynamic router permission control (Experimental)
// import permission from './modules/async-router'
import getters from './getters'

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    app,
    user,
    permission,
    oneStep
  },
  state: {

  },
  mutations: {

  },
  actions: {

  },
  getters
})

4、在step2.vue中添加如下代码进行引入

  <span style="color: blue;font-weight: 700;">{{ this.$store.state.oneStep.buildingNumber }}</span>

3、新增住宅向导-Step2

​ 下面开始来完成Step2的功能,其实这部分看起来是比较简单的,但是你需要注意了正儿八经开始做的时候,你就要疯了,原因也很简单,我们在Step1的时候设置过楼宇的数量,那么就意味着数据库中就应该由与之对应的数据库表记录,此时你发现数据库是空的,因此这种时候,我们需要先完成插入的功能,然后再完成数据更新的过程。

1、修改页面Step2.vue文件,添加如下代码

<template>
    <div>
        <a-row class="header">
            楼宇数量:
            <span style="color: blue;font-weight: 700;">{{ this.$store.state.oneStep.buildingNumber }}</span>
                        单元数量:
            <a-select v-model="form2.region" @change="change()">
                <a-select-option value="1">1</a-select-option>
                <a-select-option value="2">2</a-select-option>
                <a-select-option value="3">3</a-select-option>
                <a-select-option value="4">4</a-select-option>
                <a-select-option value="5">5</a-select-option>
            </a-select>
        </a-row>
        <a-row>
            <a-table :columns="columns" :dataSource="data" align="center" bordered>
                <template
                    :slot="col"
                    slot-scope="text, record"
                    v-for="col in [
            'buildingCode',
            'buildingName',
            'unitCount',
            'overRoofDate',
            'finishDate',
            'salePermissionId',
            'buildPermissionId',
            'buildArea',
            'usedArea',
            'remark'
          ]"
                >
                    <div :key="col">
                        <a-input
                            :value="text"
                            @change="e => handleChange(e.target.value, record.key, col)"
                            style="margin: -5px 0"
                            v-if="record.editable"
                        />
                        <template v-else>{{ text }}</template>
                    </div>
                </template>
                <template slot="operation" slot-scope="text, record">
                    <div class="editable-row-operations">
            <span v-if="record.editable">
              <a @click="() => save(record.key)">保存</a>
              <a-popconfirm @confirm="() => cancel(record.key)" title="确认取消吗?">
                <a>取消</a>
              </a-popconfirm>
            </span>
                        <span v-else>
              <a :disabled="editingKey !== ''" @click="() => edit(record.key)">编辑</a>
            </span>
                    </div>
                </template>
            </a-table>
            <a-row>
                <a-button @click="nextStep()" type="primary">下一步</a-button>
            </a-row>
        </a-row>
    </div>
</template>

<script>
    import { selectBuilding, updateBuilding } from '@/api/estate'
    // import moment from 'moment'
    const QS = require('qs')
    const columns = [
        {
            align: 'center',
            title: '楼宇编码',
            dataIndex: 'buildingCode',
            width: '6%',
            scopedSlots: { customRender: 'buildingCode' }
        },
        {
            align: 'center',
            title: '楼宇名称',
            dataIndex: 'buildingName',
            width: '15%',
            scopedSlots: { customRender: 'buildingName' }
        },
        {
            align: 'center',
            title: '单元数量',
            dataIndex: 'unitCount',
            width: '6%',
            scopedSlots: { customRender: 'unitCount' }
        },
        {
            align: 'center',
            title: '封顶日期',
            dataIndex: 'overRoofDate',
            width: '7%',
            scopedSlots: { customRender: 'overRoofDate' }
        },
        {
            align: 'center',
            title: '竣工日期',
            dataIndex: 'finishDate',
            width: '7%',
            scopedSlots: { customRender: 'finishDate' }
        },
        {
            align: 'center',
            title: '预售许可证',
            dataIndex: 'salePermissionId',
            width: '7%',
            scopedSlots: { customRender: 'salePermissionId' }
        },
        {
            align: 'center',
            title: '建筑许可证',
            dataIndex: 'buildPermissionId',
            width: '7%',
            scopedSlots: { customRender: 'buildPermissionId' }
        },
        {
            align: 'center',
            title: '建筑面积',
            dataIndex: 'buildArea',
            width: '6%',
            scopedSlots: { customRender: 'buildArea' }
        },
        {
            align: 'center',
            title: '使用面积',
            dataIndex: 'usedArea',
            width: '6%',
            scopedSlots: { customRender: 'usedArea' }
        },
        {
            align: 'center',
            title: '备注',
            dataIndex: 'remark',
            width: '10%',
            scopedSlots: { customRender: 'remark' }
        },
        {
            align: 'center',
            title: '编辑',
            width: '4%',
            dataIndex: 'operation',
            scopedSlots: { customRender: 'operation' }
        }
    ]

    const data = []
    export default {
        name: 'Step2',
        data() {
            return {
                labelCol: { span: 2 },
                wrapperCol: { span: 1 },
                form2: {
                    name: '',
                    region: undefined,
                    date1: undefined,
                    delivery: false,
                    type: [],
                    resource: '',
                    desc: ''
                },
                data,
                columns,
                editingKey: ''
                // labelCol: { lg: { span: 5 }, sm: { span: 5 } },
                // wrapperCol: { lg: { span: 19 }, sm: { span: 19 } },
                // form: this.$form.createForm(this),
                // loading: false,
                // timer: 0
            }
        },
        created() {
            const allData = {
                buildingNumber: this.$store.state.oneStep.buildingNumber,
                estateCode: this.$store.state.oneStep.estateCode
            }
            const params = QS.stringify(allData)
            selectBuilding(params).then(res => {
                const result = res.result
                for (let i = 0; i < result.length; i++) {
                    const building = result[i]
                    data.push({
                        key: building.id.toString(),
                        buildingCode: building.buildingCode,
                        buildingName: building.buildingName,
                        unitCount: building.unitCount,
                        overRoofDate: building.overRoofDate,
                        finishDate: building.finishDate,
                        salePermissionId: building.salePermissionId,
                        buildPermissionId: building.buildPermissionId,
                        buildArea: building.buildArea,
                        usedArea: building.usedArea,
                        remark: building.remark
                    })
                }
                this.cacheData = data.map(item => ({ ...item }))
            }).catch(err => {
                this.$notification['error']({
                    message: '错误',
                    description: ((err.response || {}).data || {}).message || '获取楼宇信息失败',
                    duration: 4
                })
            })
        },
        methods: {
            change() {
                const unitNumber = this.form2.region
                for (let i = 0; i< this.data.length; i++) {
                    this.data[i].unitCount = unitNumber
                }
            },
            nextStep() {
                const dataArray = this.data
                var param = '['
                for (let i = 0; i < dataArray.length; i++) {
                    if (i !== dataArray.length - 1) {
                        param += '{ "buildingCode": "' + dataArray[i].buildingCode + '", "unitCount": ' + dataArray[i].unitCount + '},'
                    } else {
                        param += '{ "buildingCode": "' + dataArray[i].buildingCode + '", "unitCount": ' + dataArray[i].unitCount + '}]'
                    }
                }

                this.$store.commit('SET_TITLE', {
                    unitMessage: param
                })
                this.$emit('nextStep')
            },
            prevStep() {
                // this.$emit('prevStep')
            },
            handleChange(value, key, column) {
                const newData = [...this.data]
                const target = newData.filter(item => key === item.key)[0]
                if (target) {
                    target[column] = value
                    this.data = newData
                }
            },
            edit(key) {
                const newData = [...this.data]
                const target = newData.filter(item => key === item.key)[0]
                this.editingKey = key
                if (target) {
                    target.editable = true
                    this.data = newData
                    this.editingKey = ''
                }
            },
            save(key) {
                const newData = [...this.data]
                const newCacheData = [...this.cacheData]
                const target = newData.filter(item => key === item.key)[0]
                const targetCache = newCacheData.filter(item => key === item.key)[0]
                if (target && targetCache) {
                    delete target.editable
                    this.data = newData
                    Object.assign(targetCache, target)
                    this.cacheData = newCacheData
                }
                target.id = key
                target.estateCode = this.$store.state.oneStep.estateCode
                const param = QS.stringify(target)
                updateBuilding(param).then(res => {
                    setTimeout(() => {
                        this.$notification.success({
                            message: '恭喜你',
                            description: res.result
                        })
                    }, 1000)
                }).catch(err => {
                    this.$notification.error({
                        message: 'error',
                        description: ((err.response || {}).data || {}).message || '添加楼宇信息失败',
                        duration: 1
                    })
                })
            },
            cancel(key) {
                const newData = [...this.data]
                const target = newData.filter(item => key === item.key)[0]
                this.editingKey = ''
                if (target) {
                    Object.assign(target, this.cacheData.filter(item => key === item.key)[0])
                    delete target.editable
                    this.data = newData
                }
            }
        },
        beforeDestroy() {
            //  clearTimeout(this.timer)
        }
    }
</script>

<style lang="less" scoped>
    .stepFormText {
        margin-bottom: 24px;

        .ant-form-item-label,
        .ant-form-item-control {
            line-height: 22px;
        }
    }
</style>

2、编写后端服务

EstateController.java

package com.bjmsb.controller;

import com.alibaba.fastjson.JSONObject;
import com.bjmsb.bean.FcBuilding;
import com.bjmsb.bean.FcEstate;
import com.bjmsb.json.Common;
import com.bjmsb.service.EstateService;
import com.bjmsb.service.common.FcEstateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
//@CrossOrigin(origins = "*",allowCredentials="true",allowedHeaders = "*",methods = {})
public class EstateController {

    @Autowired
    private EstateService estateService;

    @RequestMapping("/estate/selectCompany")
    public JSONObject selectCompany(){
        System.out.println("/estate/selectCompany");
        List<String> tblCompanyNames = estateService.selectCompany();
        return JSONObject.parseObject(JSONObject.toJSONString(new Common(tblCompanyNames)));
    }

    @RequestMapping("/estate/insertEstate")
    public JSONObject insertEstate(FcEstate fcEstate){
        System.out.println("insert estate");
        Integer integer = estateService.insertEstate(fcEstate);
        return JSONObject.parseObject(JSONObject.toJSONString(new Common("插入房产成功")));
    }

    @RequestMapping("/estate/selectBuilding")
    public JSONObject selectBuilding(Integer buildingNumber,String estateCode){
        List<FcBuilding> fcBuildings = estateService.selectBuilding(buildingNumber, estateCode);
        for (FcBuilding fcBuilding : fcBuildings) {
            System.out.println(fcBuilding.getId());
        }
        return JSONObject.parseObject(JSONObject.toJSONString(new Common(fcBuildings)));
    }
}

EstateService.java

package com.bjmsb.service;

import com.bjmsb.bean.FcBuilding;
import com.bjmsb.bean.FcEstate;
import com.bjmsb.bean.TblCompany;
import com.bjmsb.mapper.FcBuildingMapper;
import com.bjmsb.mapper.FcEstateMapper;
import com.bjmsb.mapper.TblCompanyMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class EstateService {

    @Autowired
    private TblCompanyMapper tblCompanyMapper;

    @Autowired
    private FcEstateMapper fcEstateMapper;
    @Autowired
    private FcBuildingMapper fcBuildingMapper;

    public List<String> selectCompany(){
        List<String> tblCompanies = tblCompanyMapper.selectCompany();
        return tblCompanies;
    }

    public Integer insertEstate(FcEstate fcEstate){
        int insert = fcEstateMapper.insert(fcEstate);
        return insert;
    }

    /**
     * 在进行查询之前,因为数据库中没有原始数据,因此需要用户先插入数据然后再将数据回显更新
     * @param buildingNumber
     * @param estaeCode
     * @return
     */
    public List<FcBuilding> selectBuilding(Integer buildingNumber,String estaeCode ){
        //定义返回的数据集合
        List<FcBuilding> fcBuildings = new ArrayList<>();
        //创建插入的对象
        //插入数据,完成数据插入之后,id会直接回显,因此直接显式即可
        for(int i = 0;i<buildingNumber;i++){
            FcBuilding fcBuilding = new FcBuilding();
            fcBuilding.setEstateCode(estaeCode);
            fcBuildingMapper.insert(fcBuilding);
            fcBuildings.add(fcBuilding);
        }
        return fcBuildings;
    }
}

当每行数据修改完成之后点击保存,将数据更新到数据库,下面开始写前端逻辑

<template>
    <div>
        <a-row class="header">
            楼宇数量:
            <span style="color: blue;font-weight: 700;">{{ this.$store.state.oneStep.buildingNumber }}</span>
            <!--            单元数量:-->
            <!--            <a-select v-model="form2.region">-->
            <!--                <a-select-option value="1">1</a-select-option>-->
            <!--                <a-select-option value="2">2</a-select-option>-->
            <!--                <a-select-option value="3">3</a-select-option>-->
            <!--                <a-select-option value="4">4</a-select-option>-->
            <!--                <a-select-option value="5">5</a-select-option>-->
            <!--            </a-select>-->
            <!-- </a-form-model-item> -->
        </a-row>
        <a-row>
            <a-table :columns="columns" :dataSource="data" bordered align="center">
                <template
                    v-for="col in [
            'buildingCode',
            'buildingName',
            'unitCount',
            'overRoofDate',
            'finishDate',
            'salePermissionId',
            'buildPermissionId',
            'buildArea',
            'usedArea',
            'remark'
          ]"
                    :slot="col"
                    slot-scope="text, record"
                >
                    <div :key="col">
                        <a-input
                            v-if="record.editable"
                            style="margin: -5px 0"
                            :value="text"
                            @change="e => handleChange(e.target.value, record.key, col)"
                        />
                        <template v-else>{{ text }}</template>
                    </div>
                </template>
                <template slot="operation" slot-scope="text, record">
                    <div class="editable-row-operations">
            <span v-if="record.editable">
              <a @click="() => save(record.key)">保存</a>
              <a-popconfirm title="确认取消吗?" @confirm="() => cancel(record.key)">
                <a>取消</a>
              </a-popconfirm>
            </span>
                        <span v-else>
              <a :disabled="editingKey !== ''" @click="() => edit(record.key)">编辑</a>
            </span>
                    </div>
                </template>
            </a-table>
            <a-row>
                <a-button type="primary" @click="nextStep()">下一步</a-button>
            </a-row>
        </a-row>
    </div>
</template>

<script>
    import { selectBuilding, updateBuilding } from '@/api/estate'
    // import moment from 'moment'
    const QS = require('qs')
    const columns = [
        {
            align: 'center',
            title: '楼宇编码',
            dataIndex: 'buildingCode',
            width: '6%',
            scopedSlots: { customRender: 'buildingCode' }
        },
        {
            align: 'center',
            title: '楼宇名称',
            dataIndex: 'buildingName',
            width: '15%',
            scopedSlots: { customRender: 'buildingName' }
        },
        {
            align: 'center',
            title: '单元数量',
            dataIndex: 'unitCount',
            width: '6%',
            scopedSlots: { customRender: 'unitCount' }
        },
        {
            align: 'center',
            title: '封顶日期',
            dataIndex: 'overRoofDate',
            width: '7%',
            scopedSlots: { customRender: 'overRoofDate' }
        },
        {
            align: 'center',
            title: '竣工日期',
            dataIndex: 'finishDate',
            width: '7%',
            scopedSlots: { customRender: 'finishDate' }
        },
        {
            align: 'center',
            title: '预售许可证',
            dataIndex: 'salePermissionId',
            width: '7%',
            scopedSlots: { customRender: 'salePermissionId' }
        },
        {
            align: 'center',
            title: '建筑许可证',
            dataIndex: 'buildPermissionId',
            width: '7%',
            scopedSlots: { customRender: 'buildPermissionId' }
        },
        {
            align: 'center',
            title: '建筑面积',
            dataIndex: 'buildArea',
            width: '6%',
            scopedSlots: { customRender: 'buildArea' }
        },
        {
            align: 'center',
            title: '使用面积',
            dataIndex: 'usedArea',
            width: '6%',
            scopedSlots: { customRender: 'usedArea' }
        },
        {
            align: 'center',
            title: '备注',
            dataIndex: 'remark',
            width: '10%',
            scopedSlots: { customRender: 'remark' }
        },
        {
            align: 'center',
            title: '编辑',
            width: '4%',
            dataIndex: 'operation',
            scopedSlots: { customRender: 'operation' }
        }
    ]

    const data = []
    export default {
        name: 'Step2',
        data() {
            return {
                labelCol: { span: 2 },
                wrapperCol: { span: 1 },
                form2: {
                    name: '',
                    region: undefined,
                    date1: undefined,
                    delivery: false,
                    type: [],
                    resource: '',
                    desc: ''
                },
                data,
                columns,
                editingKey: ''
                // labelCol: { lg: { span: 5 }, sm: { span: 5 } },
                // wrapperCol: { lg: { span: 19 }, sm: { span: 19 } },
                // form: this.$form.createForm(this),
                // loading: false,
                // timer: 0
            }
        },
        created() {
            const allData = {
                buildingNumber: this.$store.state.oneStep.buildingNumber,
                estateCode: this.$store.state.oneStep.estateCode
            }
            const params = QS.stringify(allData)
            selectBuilding(params).then(res => {
                const result = res.result
                for (let i = 0; i < result.length; i++) {
                    const building = result[i]
                    data.push({
                        key: building.id.toString(),
                        buildingCode: building.buildingCode,
                        buildingName: building.buildingName,
                        unitCount: building.unitCount,
                        overRoofDate: building.overRoofDate,
                        finishDate: building.finishDate,
                        salePermissionId: building.salePermissionId,
                        buildPermissionId: building.buildPermissionId,
                        buildArea: building.buildArea,
                        usedArea: building.usedArea,
                        remark: building.remark
                    })
                }
                this.cacheData = data.map(item => ({ ...item }))
            }).catch(err => {
                this.$notification['error']({
                    message: '错误',
                    description: ((err.response || {}).data || {}).message || '获取楼宇信息失败',
                    duration: 4
                })
            })
        },
        methods: {
            nextStep() {
                this.$emit('nextStep')
            },
            prevStep() {
                // this.$emit('prevStep')
            },
            handleChange(value, key, column) {
                const newData = [...this.data]
                const target = newData.filter(item => key === item.key)[0]
                if (target) {
                    target[column] = value
                    this.data = newData
                }
            },
            edit(key) {
                const newData = [...this.data]
                const target = newData.filter(item => key === item.key)[0]
                this.editingKey = key
                if (target) {
                    target.editable = true
                    this.data = newData
                    this.editingKey = ''
                }
            },
            save(key) {
                const newData = [...this.data]
                const newCacheData = [...this.cacheData]
                const target = newData.filter(item => key === item.key)[0]
                const targetCache = newCacheData.filter(item => key === item.key)[0]
                if (target && targetCache) {
                    delete target.editable
                    this.data = newData
                    Object.assign(targetCache, target)
                    this.cacheData = newCacheData
                }
                target.id = key
                target.estateCode = this.$store.state.oneStep.estateCode
                const param = QS.stringify(target)
                updateBuilding(param).then(res => {
                    setTimeout(() => {
                        this.$notification.success({
                            message: '恭喜你',
                            description: res.result
                        })
                    }, 1000)
                }).catch(err => {
                    this.$notification.error({
                        message: 'error',
                        description: ((err.response || {}).data || {}).message || '添加楼宇信息失败',
                        duration: 1
                    })
                })
            },
            cancel(key) {
                const newData = [...this.data]
                const target = newData.filter(item => key === item.key)[0]
                this.editingKey = ''
                if (target) {
                    Object.assign(target, this.cacheData.filter(item => key === item.key)[0])
                    delete target.editable
                    this.data = newData
                }
            }
        },
        beforeDestroy() {
            //  clearTimeout(this.timer)
        }
    }
</script>

<style lang="less" scoped>
    .stepFormText {
        margin-bottom: 24px;

        .ant-form-item-label,
        .ant-form-item-control {
            line-height: 22px;
        }
    }
</style>

编写后端逻辑

EstateController.java

package com.bjmsb.controller;

import com.alibaba.fastjson.JSONObject;
import com.bjmsb.bean.FcBuilding;
import com.bjmsb.bean.FcEstate;
import com.bjmsb.json.Common;
import com.bjmsb.service.EstateService;
import com.bjmsb.service.common.FcEstateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
//@CrossOrigin(origins = "*",allowCredentials="true",allowedHeaders = "*",methods = {})
public class EstateController {

    @Autowired
    private EstateService estateService;

    @RequestMapping("/estate/selectCompany")
    public JSONObject selectCompany(){
        System.out.println("/estate/selectCompany");
        List<String> tblCompanyNames = estateService.selectCompany();
        return JSONObject.parseObject(JSONObject.toJSONString(new Common(tblCompanyNames)));
    }

    @RequestMapping("/estate/insertEstate")
    public JSONObject insertEstate(FcEstate fcEstate){
        System.out.println("insert estate");
        Integer integer = estateService.insertEstate(fcEstate);
        return JSONObject.parseObject(JSONObject.toJSONString(new Common("插入房产成功")));
    }

    @RequestMapping("/estate/selectBuilding")
    public JSONObject selectBuilding(Integer buildingNumber,String estateCode){
        List<FcBuilding> fcBuildings = estateService.selectBuilding(buildingNumber, estateCode);
        for (FcBuilding fcBuilding : fcBuildings) {
            System.out.println(fcBuilding.getId());
        }
        return JSONObject.parseObject(JSONObject.toJSONString(new Common(fcBuildings)));
    }

    @RequestMapping("/estate/updateBuilding")
    public JSONObject updateBuilding(FcBuilding fcBuilding){
        System.out.println("update building");
        System.out.println(fcBuilding);
        Integer update = estateService.updateBuilding(fcBuilding);
        System.out.println(update);
        return JSONObject.parseObject(JSONObject.toJSONString(new Common("插入楼宇成功")));
    }
}

EstateService.java

package com.bjmsb.service;

import com.bjmsb.bean.FcBuilding;
import com.bjmsb.bean.FcEstate;
import com.bjmsb.bean.TblCompany;
import com.bjmsb.mapper.FcBuildingMapper;
import com.bjmsb.mapper.FcEstateMapper;
import com.bjmsb.mapper.TblCompanyMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class EstateService {

    @Autowired
    private TblCompanyMapper tblCompanyMapper;
    @Autowired
    private FcEstateMapper fcEstateMapper;
    @Autowired
    private FcBuildingMapper fcBuildingMapper;

    public List<String> selectCompany(){
        List<String> tblCompanies = tblCompanyMapper.selectCompany();
        return tblCompanies;
    }

    public Integer insertEstate(FcEstate fcEstate){
        int insert = fcEstateMapper.insert(fcEstate);
        return insert;
    }

    /**
     * 在进行查询之前,因为数据库中没有原始数据,因此需要用户先插入数据然后再将数据回显更新
     * @param buildingNumber
     * @param estaeCode
     * @return
     */
    public List<FcBuilding> selectBuilding(Integer buildingNumber,String estaeCode ){
        //定义返回的数据集合
        List<FcBuilding> fcBuildings = new ArrayList<>();
        //创建插入的对象
        //插入数据,完成数据插入之后,id会直接回显,因此直接显式即可
        for(int i = 0;i<buildingNumber;i++){
            FcBuilding fcBuilding = new FcBuilding();
            fcBuilding.setEstateCode(estaeCode);
            fcBuildingMapper.insert(fcBuilding);
            fcBuilding.setBuildingCode("B"+fcBuilding.getId());
            fcBuilding.setBuildingName("第"+(i+1)+"号楼");
            fcBuildings.add(fcBuilding);
        }
        return fcBuildings;
    }

    public Integer updateBuilding(FcBuilding fcBuilding){
        int update = fcBuildingMapper.updateById(fcBuilding);
        return update;
    }
}

4、Step2-Step3数据传递问题:

​ 跟之前的数据传递一样,此时我们也需要进行数据的传递,那么怎么来完成呢?看代码实操

1、在Step2跳转之前添加如下 代码

nextStep() {
                const dataArray = this.data
                var param = '['
                for (let i = 0; i < dataArray.length; i++) {
                    if (i !== dataArray.length - 1) {
                        param += '{ buildingCode: ' + dataArray[i].buildingCode + ', unitCount: ' + dataArray[i].unitCount + '},'
                    } else {
                        param += '{ buildingCode: ' + dataArray[i].buildingCode + ', unitCount: ' + dataArray[i].unitCount + '}]'
                    }
                }
                this.$store.commit('SET_TITLE', {
                    unitMessage: param
                })
                this.$emit('nextStep')
            },

2、添加twoStep.js文件在src\store\modules目录下

const twoStep = {
    state: {
        unitMessage: []
    },
    mutations: {
        // 这里只能是同步的
        SET_TITLE(state, payload) {
            console.log(payload)
            state.unitMessage = payload.unitMessage
        }
    },
    actions: {

    },
    getters: {

    }
}
export default twoStep

3、在同样目录的index.js文件中添加如下代码:

import Vue from 'vue'
import Vuex from 'vuex'

import app from './modules/app'
import user from './modules/user'
// default router permission control
import permission from './modules/permission'
import oneStep from './modules/oneStep'
import twoStep from './modules/twoStep'
// dynamic router permission control (Experimental)
// import permission from './modules/async-router'
import getters from './getters'

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    app,
    user,
    permission,
    oneStep,
    twoStep
  },
  state: {

  },
  mutations: {

  },
  actions: {

  },
  getters
})

4、在Step3.vue中使用之前传递过来的参数:

{{ this.$store.state.twoStep.unitMessage }}

5、新增住宅向导-Step3

​ 下面开始完成Step3的功能,其实跟之前的操作差不多,干他!!!

1、编写前端页面

<template>
  <div>
    <!-- <a-form-model ref="ruleForm" :model="form2" :label-col="labelCol" :wrapper-col="wrapperCol"> -->
    <a-row class="header">
      楼层数量:
      <a-input style="width: 30px;padding: 0;text-align: center;" @blur="changeFloor()" v-model="form2.floorNumber"></a-input>开始房号:
      <!-- <a-form-model-item label="单元数量:" prop="region" class="units" :labelCol="labelCol" :wrapperCol="wrapperCol"> -->
      <a-select v-model="form2.startCell" @change="changeStartCell()">
        <a-select-option value="1">1</a-select-option>
        <a-select-option value="2">2</a-select-option>
        <a-select-option value="3">3</a-select-option>
        <a-select-option value="4">4</a-select-option>
        <a-select-option value="5">5</a-select-option>
        <a-select-option value="6">6</a-select-option>
        <a-select-option value="7">7</a-select-option>
        <a-select-option value="8">8</a-select-option>
      </a-select>结束房号:
      <!-- <a-form-model-item label="单元数量:" prop="region" class="units" :labelCol="labelCol" :wrapperCol="wrapperCol"> -->
      <a-select v-model="form2.stopCell" @change="changeStopCell()">
        <a-select-option value="1">1</a-select-option>
        <a-select-option value="2">2</a-select-option>
        <a-select-option value="3">3</a-select-option>
        <a-select-option value="4">4</a-select-option>
        <a-select-option value="5">5</a-select-option>
        <a-select-option value="6">6</a-select-option>
        <a-select-option value="7">7</a-select-option>
        <a-select-option value="8">8</a-select-option>

      </a-select>
      <!-- </a-form-model-item> -->
    </a-row>
    <a-row>
      <a-table :columns="columns" :dataSource="data" bordered align="center">
        <template
          v-for="col in [
            'buildingCode',
            'unitCode',
            'unitName',
            'startFloor',
            'stopFloor',
            'startCellId',
            'stopCellId',
            'remark'
          ]"
          :slot="col"
          slot-scope="text, record"
        >
          <div :key="col">
            <a-input
              v-if="record.editable"
              style="margin: -5px 0"
              :value="text"
              @change="e => handleChange(e.target.value, record.key, col)"
            />
            <template v-else>{{ text }}</template>
          </div>
        </template>
        <template slot="operation" slot-scope="text, record">
          <div class="editable-row-operations">
            <span v-if="record.editable">
              <a @click="() => save(record.key)">保存</a>&nbsp;
              <a-popconfirm title="确认取消吗?" @confirm="() => cancel(record.key)">
                <a>取消</a>
              </a-popconfirm>
            </span>
            <span v-else>
              <a :disabled="editingKey !== ''" @click="() => edit(record.key)">编辑</a>
            </span>
          </div>
        </template>
      </a-table>
      <a-row>
        <a-button type="primary" @click="nextStep()">下一步</a-button>
      </a-row>
    </a-row>
  </div>
</template>

<script>
    import { selectUnit, updateUnit } from '@/api/estate'
const QS = require('qs')
const columns = [
    {
        // 楼宇编码	单元编码	单元名称	开始楼层	结束楼层	开始房号	结束房号
        align: 'center',
        title: '楼宇编码',
        dataIndex: 'buildingCode',
        width: '6%',
        scopedSlots: { customRender: 'buildingCode' }
    },
    {
        align: 'center',
        title: '单元编码',
        dataIndex: 'unitCode',
        width: '6%',
        scopedSlots: { customRender: 'unitCode' }
    },
    {
        align: 'center',
        title: '单元名称',
        dataIndex: 'unitName',
        width: '6%',
        scopedSlots: { customRender: 'unitName' }
    },
    {
        align: 'center',
        title: '开始楼层',
        dataIndex: 'startFloor',
        width: '7%',
        scopedSlots: { customRender: 'startFloor' }
    },
    {
        align: 'center',
        title: '结束楼层',
        dataIndex: 'stopFloor',
        width: '7%',
        scopedSlots: { customRender: 'stopFloor' }
    },
    {
        align: 'center',
        title: '开始房号',
        dataIndex: 'startCellId',
        width: '7%',
        scopedSlots: { customRender: 'startCellId' }
    },
    {
        align: 'center',
        title: '结束房号',
        dataIndex: 'stopCellId',
        width: '7%',
        scopedSlots: { customRender: 'stopCellId' }
    },
    {
        align: 'center',
        title: '备注',
        dataIndex: 'remark',
        width: '18%',
        scopedSlots: { customRender: 'remark' }
    },
    {
        align: 'center',
        title: '编辑',
        width: '7%',
        dataIndex: 'operation',
        scopedSlots: { customRender: 'operation' }
    }
]

const data = []
export default {
    name: 'Step3',
    data() {
        return {
            labelCol: { span: 2 },
            wrapperCol: { span: 1 },
            form2: {
                name: '',
                startCell: '',
                stopCell: '',
                date1: undefined,
                delivery: false,
                type: [],
                resource: '',
                floorNumber: '',
                desc: ''
            },
            data,
            columns,
            editingKey: ''
        }
    },created() {
        selectUnit( this.$store.state.twoStep.unitMessage ).then(res => {
            const result = res.result
            for (let i = 0; i < result.length; i++) {
                const unit = result[i]
                data.push({
                    key: unit.id.toString(),
                    buildingCode: unit.buildingCode,
                    unitCode: unit.unitCode,
                    unitName: unit.unitName,
                    startFloor: unit.startFloor,
                    stopFloor: unit.stopFloor,
                    startCellId: unit.startCellId,
                    stopCellId: unit.stopCellId,
                    remark: unit.remark
                })
            }
            this.cacheData = data.map(item => ({ ...item }))
        }).catch(err => {
            this.$notification['error']({
                message: '错误',
                description: ((err.response || {}).data || {}).message || '获取单元数据',
                duration: 4
            })
        })
    },
    methods: {
        changeFloor(){
            const floorNumber = this.form2.floorNumber
            for (let i = 0; i < this.data.length; i++) {
                this.data[i].startFloor = 1
                this.data[i].stopFloor = floorNumber
            }
        },
        changeStartCell(){
            const startCell = this.form2.startCell
            for (let i = 0; i < this.data.length; i++) {
                this.data[i].startCellId = startCell
            }
        },
        changeStopCell(){
            const stopCell = this.form2.stopCell
            for (let i = 0; i < this.data.length; i++) {
                this.data[i].stopCellId = stopCell
            }
        },
        nextStep() {
            this.$emit('nextStep')
        },
        prevStep() {
            // this.$emit('prevStep')
        },
        handleChange(value, key, column) {
            const newData = [...this.data]
            const target = newData.filter(item => key === item.key)[0]
            if (target) {
                target[column] = value
                this.data = newData
            }
        },
        edit(key) {
            const newData = [...this.data]
            const target = newData.filter(item => key === item.key)[0]
            this.editingKey = key
            if (target) {
                target.editable = true
                this.data = newData
            }
        },
        save(key) {
            console.log(key)
            const newData = [...this.data]
            const newCacheData = [...this.cacheData]
            const target = newData.filter(item => key === item.key)[0]
            const targetCache = newCacheData.filter(item => key === item.key)[0]
            if (target && targetCache) {
                delete target.editable
                this.data = newData
                Object.assign(targetCache, target)
                this.cacheData = newCacheData
                this.editingKey = ''
            }
            target.id = key
            const param = QS.stringify(target)
            updateUnit(param).then(res => {
                setTimeout(() => {
                    this.$notification.success({
                        message: '恭喜你',
                        description: res.result
                    })
                }, 1000)
            }).catch(err => {
                this.$notification.error({
                    message: 'error',
                    description: ((err.response || {}).data || {}).message || '添加单元信息失败',
                    duration: 1
                })
            })
        },
        cancel(key) {
            const newData = [...this.data]
            const target = newData.filter(item => key === item.key)[0]
            this.editingKey = ''
            if (target) {
                Object.assign(target, this.cacheData.filter(item => key === item.key)[0])
                delete target.editable
                this.data = newData
            }
        }
    },
    beforeDestroy() {
        //  clearTimeout(this.timer)
    }
}
</script>

<style lang="less" scoped>
.stepFormText {
    margin-bottom: 24px;

    .ant-form-item-label,
    .ant-form-item-control {
        line-height: 22px;
    }
}
</style>

2、编写后端逻辑

UnitMessage.java

package com.bjmsb.vo;

public class UnitMessage {

    private String buildingCode;
    private Integer unitCount;

    public UnitMessage() {
    }

    public UnitMessage(String buildingCode, Integer unitCount) {
        this.buildingCode = buildingCode;
        this.unitCount = unitCount;
    }

    public String getBuildingCode() {
        return buildingCode;
    }

    public void setBuildingCode(String buildingCode) {
        this.buildingCode = buildingCode;
    }

    public Integer getUnitCount() {
        return unitCount;
    }

    public void setUnitCount(Integer unitCount) {
        this.unitCount = unitCount;
    }

    @Override
    public String toString() {
        return "UnitMessage{" +
                "buildingCode='" + buildingCode + '\'' +
                ", unitCount=" + unitCount +
                '}';
    }
}

EstateController.java

 @RequestMapping("/estate/selectUnit")
    public JSONObject selectUnit(@RequestBody UnitMessage[] unitMessages){
        System.out.println("selectUnit");
        System.out.println(unitMessages[0]);
        List<FcUnit> allUnit = new ArrayList<>();
        for (UnitMessage unitMessage : unitMessages) {
            allUnit.addAll(estateService.selectUnit(unitMessage));
        }
        System.out.println(allUnit.size());
        return JSONObject.parseObject(JSONObject.toJSONString(new Common(allUnit)));
    }
@RequestMapping("/estate/updateUnit")
    public JSONObject updateUnit(FcUnit fcUnit){
        System.out.println("update unit");
        System.out.println(fcUnit);
        Integer update = estateService.updateUnit(fcUnit);
        System.out.println(update);
        return JSONObject.parseObject(JSONObject.toJSONString(new Common("更新单元成功")));
    }

EstateService.java

 /**
     * 此处的逻辑跟上述的逻辑相同,只需要插入对应的数据即可
     * @return
     */
    public List<FcUnit> selectUnit(UnitMessage unitMessage){
        //定义返回的集合
        List<FcUnit> fcUnits = new ArrayList<>();
        //操作插入数据
        for (int i = 0;i<unitMessage.getUnitCount();i++){
            FcUnit fcUnit = new FcUnit();
            fcUnit.setBuildingCode(unitMessage.getBuildingCode());
            fcUnit.setUnitCode("U"+(i+1));
            fcUnit.setUnitName("第"+(i+1)+"单元");
            fcUnitMapper.insert(fcUnit);
            fcUnits.add(fcUnit);
        }
        return fcUnits;
    }
 public Integer updateUnit(FcUnit fcUnit){
        int update = fcUnitMapper.updateById(fcUnit);
        return update;
    }

6、Step3-Step4数据传递问题

跟之前的数据传递一样,此时我们也需要进行数据的传递,那么怎么来完成呢?看代码实操

1、在Step2跳转之前添加如下 代码

nextStep() {
            const dataArray = this.data
            console.log(dataArray)
            let param = '['
            for (let i = 0; i < dataArray.length; i++) {
                if (i !== dataArray.length - 1) {
                    param += '{ "unitCode": "' + dataArray[i].unitCode + '", "startFloor": ' + dataArray[i].startFloor + '", "stopFloor": ' + dataArray[i].stopFloor + '", "startCellId": ' + dataArray[i].startCellId + '", "stopCellId": ' + dataArray[i].stopCellId + '},'
                } else {
                    param += '{ "unitCode": "' + dataArray[i].unitCode + '", "startFloor": ' + dataArray[i].startFloor + '", "stopFloor": ' + dataArray[i].stopFloor + '", "startCellId": ' + dataArray[i].startCellId + '", "stopCellId": ' + dataArray[i].stopCellId + '}'
                }
            }
            console.log('param:' + param)
            this.$store.commit('SET_TITLE', {
                cellMessage: param
            })
            this.$emit('nextStep')
        },

2、添加threeStep.js文件在src\store\modules目录下

const threeStep = {
    state: {
        cellMessage: []
    },
    mutations: {
        // 这里只能是同步的
        SET_TITLE(state, payload) {
            console.log(payload)
            state.cellMessage = payload.cellMessage
        }
    },
    actions: {

    },
    getters: {

    }
}
export default threeStep

3、在同样目录的index.js文件中添加如下代码:

import Vue from 'vue'
import Vuex from 'vuex'

import app from './modules/app'
import user from './modules/user'
// default router permission control
import permission from './modules/permission'
import oneStep from './modules/oneStep'
import twoStep from './modules/twoStep'
import threeStep from '@/store/modules/threeStep3'
// dynamic router permission control (Experimental)
// import permission from './modules/async-router'
import getters from './getters'

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    app,
    user,
    permission,
    oneStep,
    twoStep,
    threeStep
  },
  state: {

  },
  mutations: {

  },
  actions: {

  },
  getters
})

4、在Step4.vue中使用之前传递过来的参数:

{{ this.$store.state.threeStep.cellMessage }}

7、新增住宅向导-Step4

1、前端编写

<template>
  <div>
    <!-- <a-form-model ref="ruleForm" :model="form2" :label-col="labelCol" :wrapper-col="wrapperCol"> -->
    <a-row class="header">
      选择楼宇:
        <a-select v-model="form2.building" @change="changeBuilding()">
            <a-select-option
                :key="index"
                :value="item.buildingCode"
                v-for="(item, index) in buildingSelect"
            >
                {{ item.buildingName }}
            </a-select-option>
        </a-select>选择单元:
        <a-select v-model="form2.unit" @change="changeUnit()">
            <a-select-option
                :key="index"
                :value="item.unitCode"
                v-for="(item, index) in unitSelect"
            >
                {{ item.unitName }}
            </a-select-option>
        </a-select>
      建筑面积:
      <a-input style="width: 40px;padding: 0;text-align: center;"></a-input>
      使用面积:
      <a-input style="width: 40px;padding: 0;text-align: center;"></a-input>
    </a-row>
    <a-row>
      <a-table :columns="columns" :dataSource="data" bordered align="center">
        <template
          v-for="col in [
            'floorNumber',
            'cellCode',
            'cellName',
            'cellBuildArea',
            'cellUsedArea',
            'remark'
          ]"
          :slot="col"
          slot-scope="text, record"
        >
          <div :key="col">
            <a-input
              v-if="record.editable"
              style="margin: -5px 0"
              :value="text"
              @change="e => handleChange(e.target.value, record.key, col)"
            />
            <template v-else>{{ text }}</template>
          </div>
        </template>
        <template slot="operation" slot-scope="text, record">
          <div class="editable-row-operations">
            <span v-if="record.editable">
              <a @click="() => save(record.key)">保存</a>&nbsp;
              <a-popconfirm title="确认取消吗?" @confirm="() => cancel(record.key)">
                <a>取消</a>
              </a-popconfirm>
            </span>
            <span v-else>
              <a :disabled="editingKey !== ''" @click="() => edit(record.key)">编辑</a>
            </span>
          </div>
        </template>
      </a-table>
      <a-row>
        <a-button type="primary" @click="prevStep()">上一步</a-button>
        <a-button type="primary" @click="nextStep()">下一步</a-button>
      </a-row>
    </a-row>
  </div>
</template>

<script>
    import { insertCell, selectBuildingName, selectUnitName, selectCell, updateCell } from '@/api/estate'
const QS = require('qs')
const columns = [
    {
        align: 'center',
        title: '楼层数',
        dataIndex: 'floorNumber',
        width: '6%',
        scopedSlots: { customRender: 'floorNumber' }
    },
    {
        align: 'center',
        title: '单元编码',
        dataIndex: 'unitCode',
        width: '6%',
        scopedSlots: { customRender: 'unitCode' }
    },
    {
        align: 'center',
        title: '房间编码',
        dataIndex: 'cellCode',
        width: '6%',
        scopedSlots: { customRender: 'cellCode' }
    },
    {
        align: 'center',
        title: '房间姓名',
        dataIndex: 'cellName',
        width: '6%',
        scopedSlots: { customRender: 'cellName' }
    },
    {
        align: 'center',
        title: '建筑面积',
        dataIndex: 'cellBuildArea',
        width: '6%',
        scopedSlots: { customRender: 'cellBuildArea' }
    },
    {
        align: 'center',
        title: '使用面积',
        dataIndex: 'cellUsedArea',
        width: '7%',
        scopedSlots: { customRender: 'cellUsedArea' }
    },
    {
        align: 'center',
        title: '备注',
        dataIndex: 'remark',
        width: '38%',
        scopedSlots: { customRender: 'remark' }
    },
    {
        align: 'center',
        title: '编辑',
        width: '7%',
        dataIndex: 'operation',
        scopedSlots: { customRender: 'operation' }
    }
]

const data = []
export default {
    name: 'Step4',
    data() {
        return {
            buildingSelect: [],
            unitSelect: [],
            labelCol: { span: 2 },
            wrapperCol: { span: 1 },
            form2: {
                name: '',
                building: [],
                unit: [],
                date1: undefined,
                delivery: false,
                type: [],
                resource: '',
                desc: ''
            },
            data,
            columns,
            editingKey: ''
        }
    },
    created() {
        // 插入并回显房间信息
        insertCell(this.$store.state.threeStep.cellMessage).then(res => {
            const result = res.result
            for (let i = 0; i < result.length; i++) {
                const cell = result[i]
                data.push({
                    key: cell.id,
                    floorNumber: cell.floorNumber,
                    unitCode: cell.unitCode,
                    cellCode: cell.cellCode,
                    cellName: cell.cellName,
                    cellBuildArea: cell.cellBuildArea,
                    cellUsedArea: cell.cellUsedArea,
                    remark: cell.remark
                })
            }
            this.cacheData = data.map(item => ({ ...item }))
        }).catch(err => {
            this.$notification.error({
                message: '错误',
                description: '插入房间失败' + err.result,
                duration: 4
            })
        })
        // 查询存在的楼宇
        selectBuildingName(QS.stringify({ estateCode: this.$store.state.threeStep.estateCode })).then(res => {
            this.buildingSelect = res.result
        }).catch(err => {
            this.$notification['error']({
                message: '错误',
                description: ((err.response || {}).data || {}).message || '获取楼宇信息失败',
                duration: 4
            })
        })
    },
    methods: {
        changeUnit() {
            selectCell(QS.stringify({ unitCode: this.form2.unit })).then(res => {
                const result = res.result
                console.log('size:' + result.length)
                const myData = []
                for (let i = 0; i < result.length; i++) {
                    const cell = result[i]
                    console.log('i:' + i)
                    myData.push({
                        key: cell.id,
                        floorNumber: cell.floorNumber,
                        unitCode: cell.unitCode,
                        cellCode: cell.cellCode,
                        cellName: cell.cellName,
                        cellBuildArea: cell.cellBuildArea,
                        cellUsedArea: cell.cellUsedArea,
                        remark: cell.remark
                    })
                }
                this.data = myData
                this.cacheData = data.map(item => ({ ...item }))
            }).catch(err => {
                this.$notification.error({
                    message: '错误',
                    description: '插入房间失败' + err.result,
                    duration: 4
                })
            })
        },
        changeBuilding() {
            selectUnitName(QS.stringify({ buildingCode: this.form2.building })).then(res => {
                this.unitSelect = res.result
            }).catch(err => {
                this.$notification['error']({
                    message: '错误',
                    description: ((err.response || {}).data || {}).message || '获取单元信息失败',
                    duration: 4
                })
            })
        },
        nextStep() {
            this.$emit('nextStep')
        },
        prevStep() {
            this.$emit('prevStep')
        },
        handleChange(value, key, column) {
            const newData = [...this.data]
            const target = newData.filter(item => key === item.key)[0]
            if (target) {
                target[column] = value
                this.data = newData
            }
        },
        edit(key) {
            const newData = [...this.data]
            const target = newData.filter(item => key === item.key)[0]
            this.editingKey = key
            if (target) {
                target.editable = true
                this.data = newData
            }
        },
        save(key) {
            const newData = [...this.data]
            const newCacheData = [...this.cacheData]
            const target = newData.filter(item => key === item.key)[0]
            const targetCache = newCacheData.filter(item => key === item.key)[0]
            if (target && targetCache) {
                delete target.editable
                this.data = newData
                Object.assign(targetCache, target)
                this.cacheData = newCacheData
                this.editingKey = ''
            }
            target.id = key
            const param = QS.stringify(target)
            updateCell(param).then(res => {
                setTimeout(() => {
                    this.$notification.success({
                        message: '恭喜你',
                        description: res.result
                    })
                }, 1000)
            }).catch(err => {
                this.$notification.error({
                    message: 'error',
                    description: ((err.response || {}).data || {}).message || '更新房间信息失败',
                    duration: 1
                })
            })
        },
        cancel(key) {
            const newData = [...this.data]
            const target = newData.filter(item => key === item.key)[0]
            this.editingKey = ''
            if (target) {
                Object.assign(target, this.cacheData.filter(item => key === item.key)[0])
                delete target.editable
                this.data = newData
            }
        }
    },
    beforeDestroy() {
        //  clearTimeout(this.timer)
    }
}
</script>

<style lang="less" scoped>
.stepFormText {
    margin-bottom: 24px;

    .ant-form-item-label,
    .ant-form-item-control {
        line-height: 22px;
    }
}
</style>

2、后端逻辑编写

 @RequestMapping("/estate/insertCell")
    public String insertCell(@RequestBody List<CellMessage> cellMessage){
        System.out.println("estate insertCell");
        List<FcCell> fcCells = estateService.insertCell(cellMessage);
        return JSONObject.toJSONString(new Common(fcCells));
    }

    @RequestMapping("/estate/selectBuildingName")
    public String selectBuildingName(String estateCode){
        System.out.println("estate selectBuildingName");
        List<FcBuilding> fcBuildings = estateService.selectBuildingName(estateCode);
        System.out.println(fcBuildings);
        return JSONObject.toJSONString(new Common(fcBuildings));
    }

    @RequestMapping("/estate/selectUnitName")
    public String selectUnitName(String buildingCode){
        System.out.println("select unitName");
        List<FcUnit> fcUnits = estateService.selectUnitName(buildingCode);
        System.out.println(fcUnits);
        return JSONObject.toJSONString(new Common(fcUnits));
    }

    @RequestMapping("/estate/selectCell")
    public String selectCell(String unitCode){
        System.out.println("select cell");
        System.out.println(unitCode);
        List<FcCell> fcCells = estateService.selectCell(unitCode);
        System.out.println(fcCells);
        return JSONObject.toJSONString(new Common(fcCells));
    }

    @RequestMapping("/estate/updateCell")
    public String updateCell(FcCell fcCell){
        System.out.println("update cell");
        System.out.println(fcCell);
        Integer update = estateService.updateCell(fcCell);
        System.out.println(update);
        return JSONObject.toJSONString(new Common("更新房间成功"));
    }
public List<FcCell> insertCell(List<CellMessage> cellMessages){
        List<FcCell> fcCells = new ArrayList<>();
        for (CellMessage cellMessage : cellMessages) {
            for(int i = 1;i<=cellMessage.getStopFloor();i++){
                for(int j = 1;j<=Integer.valueOf(cellMessage.getStopCellId());j++){
                    FcCell cell = new FcCell();
                    cell.setUnitCode(cellMessage.getUnitCode());
                    cell.setCellName(i+"0"+j);
                    cell.setCellCode(cellMessage.getUnitCode()+"C"+i+"0"+j);
                    cell.setFloorNumber(i);
                    fcCellMapper.insert(cell);
                    fcCells.add(cell);
                }
            }
        }
        return fcCells;
    }

    /**
     * 查询楼宇的名称
     * @param estateCode
     * @return
     */
    public List<FcBuilding> selectBuildingName(String estateCode){
        QueryWrapper<FcBuilding> queryWrapper = new QueryWrapper<FcBuilding>();
        queryWrapper.eq("estate_code",estateCode);
        queryWrapper.select("building_code","building_name");
        List<FcBuilding> fcBuildings = fcBuildingMapper.selectList(queryWrapper);
        return fcBuildings;
    }

    public List<FcUnit> selectUnitName(String buildingCode){
        QueryWrapper<FcUnit> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("building_code",buildingCode);
        queryWrapper.select("unit_code","unit_name");
        List<FcUnit> fcUnits = fcUnitMapper.selectList(queryWrapper);
        return fcUnits;
    }

    public List<FcCell> selectCell(String unitCode){
        QueryWrapper<FcCell> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("unit_code",unitCode);
        List<FcCell> fcCells = fcCellMapper.selectList(queryWrapper);
        return fcCells;
    }

    public Integer updateCell(FcCell fcCell){
        int update = fcCellMapper.updateById(fcCell);
        return update;
    }

到此时为止,我们的新增住宅向导就编写完毕

8、批量增加楼宇

Step1.vue

<template>
  <div>
    <a-form :form="form" style="margin: 20px auto 0;">
      <a-row>
        <a-col :span="12">
          <a-form-item label="所属公司" :labelCol="labelCol" :wrapperCol="wrapperCol">
            <a-select
              @change="company"
              v-decorator="[
                'company',
                { rules: [{ required: true, message: '所属公司必须填写', trigger: 'change' }] },
              ]"
            >
               <a-select-option
                  :key="index"
                  :value="item.id+''"
                  v-for="(item, index) in selectCompany"
               >
                   {{ item.companyFullName }}
               </a-select-option>
            </a-select>
          </a-form-item>
        </a-col>
      </a-row>
      <a-row>
        <a-col :span="12">
          <a-form-item label="选择住宅" :labelCol="labelCol" :wrapperCol="wrapperCol">
            <a-select
              v-decorator="[
                'estate',
                { rules: [{ required: true, message: '选择住宅必须填写', trigger: 'change' }] },
              ]"
            >
                <a-select-option
                    :key="index"
                    :value="item.estateCode"
                    v-for="(item, index) in selectEstate"
                >
                    {{ item.estateName }}
                </a-select-option>
            </a-select>
          </a-form-item>
        </a-col>
        <a-col :span="12">
          <a-form-item label="新增楼宇数量" :labelCol="labelCol" :wrapperCol="wrapperCol">
            <a-input
              v-decorator="[
                'buildingNumber',
                { rules: [{ required: true, message: '新增楼宇数量必须填写', trigger: 'blur' }] },
              ]"
            />
          </a-form-item>
        </a-col>
      </a-row>
      <a-form-item :wrapperCol="{span: 19, offset: 5}">
        <a-button type="primary" @click="nextStep">下一步</a-button>
        <a-button style="margin-left: 10px;">Reset</a-button>
      </a-form-item>
    </a-form>
  </div>
</template>

<script>
import { selectCompany, selectEstate } from '@/api/estate'
const QS = require('qs')
export default {
    name: 'Step1',
    data() {
        return {
            selectCompany: [],
            selectEstate:[],
            labelCol: { lg: { span: 6 }, sm: { span: 4 } },
            wrapperCol: { lg: { span: 16 }, sm: { span: 20 } },
            form: this.$form.createForm(this)
        }
    },
    created() {
        selectCompany().then(res => {
            this.selectCompany = res.result
        }).catch(err => {
            this.$notification['error']({
                message: '错误',
                description: ((err.response || {}).data || {}).message || '获取公司信息失败',
                duration: 4
            })
        })
    },
    methods: {
        company(value) {
            selectEstate(QS.stringify({company: value})).then(res => {
                this.selectEstate = res.result
            }).catch(err => {
                this.$notification['error']({
                    message: '错误',
                    description: ((err.response || {}).data || {}).message || '获取公司信息失败',
                    duration: 4
                })
            })
        },
        nextStep(e) {
            e.preventDefault()
            this.form.validateFieldsAndScroll((err, values) => {
                if (!err) {
                    this.$store.commit('SET_TITLE', {
                        buildingNumber: values.buildingNumber,
                        estateCode: values.estate
                    })
                    this.$emit('nextStep')
                    console.log('Received values of form: ', values)
                }
            })
        }
    }
}
</script>

<style lang="less" scoped>
.step-form-style-desc {
    padding: 0 56px;
    color: rgba(0, 0, 0, 0.45);

    h3 {
        margin: 0 0 12px;
        color: rgba(0, 0, 0, 0.45);
        font-size: 16px;
        line-height: 32px;
    }

    h4 {
        margin: 0 0 4px;
        color: rgba(0, 0, 0, 0.45);
        font-size: 14px;
        line-height: 22px;
    }

    p {
        margin-top: 0;
        margin-bottom: 12px;
        line-height: 22px;
    }
}
.ant-form-item {
    margin-bottom: 8px;
}
</style>

Step2.vue

<template>
    <div>
        <a-row class="header">
            楼宇数量:
            <span style="color: blue;font-weight: 700;">{{ this.returnBuildingNumber }}</span>
            单元数量:
            <a-select v-model="form2.region" @change="change()">
                <a-select-option value="1">1</a-select-option>
                <a-select-option value="2">2</a-select-option>
                <a-select-option value="3">3</a-select-option>
                <a-select-option value="4">4</a-select-option>
                <a-select-option value="5">5</a-select-option>
            </a-select>
        </a-row>
        <a-row>
            <a-table :columns="columns" :dataSource="data" align="center" bordered>
                <template
                    :slot="col"
                    slot-scope="text, record"
                    v-for="col in [
            'buildingCode',
            'buildingName',
            'unitCount',
            'overRoofDate',
            'finishDate',
            'salePermissionId',
            'buildPermissionId',
            'buildArea',
            'usedArea',
            'remark'
          ]"
                >
                    <div :key="col">
                        <a-input
                            :value="text"
                            @change="e => handleChange(e.target.value, record.key, col)"
                            style="margin: -5px 0"
                            v-if="record.editable"
                        />
                        <template v-else>{{ text }}</template>
                    </div>
                </template>
                <template slot="operation" slot-scope="text, record">
                    <div class="editable-row-operations">
            <span v-if="record.editable">
              <a @click="() => save(record.key)">保存</a>
              <a-popconfirm @confirm="() => cancel(record.key)" title="确认取消吗?">
                <a>取消</a>
              </a-popconfirm>
            </span>
                        <span v-else>
              <a :disabled="editingKey !== ''" @click="() => edit(record.key)">编辑</a>
            </span>
                    </div>
                </template>
            </a-table>
            <a-row>
                <a-button @click="nextStep()" type="primary">下一步</a-button>
            </a-row>
        </a-row>
    </div>
</template>

<script>
    import { selectBuilding, updateBuilding, selectCountBuilding } from '@/api/estate'
    // import moment from 'moment'
    const QS = require('qs')
    const columns = [
        {
            align: 'center',
            title: '楼宇编码',
            dataIndex: 'buildingCode',
            width: '6%',
            scopedSlots: { customRender: 'buildingCode' }
        },
        {
            align: 'center',
            title: '楼宇名称',
            dataIndex: 'buildingName',
            width: '15%',
            scopedSlots: { customRender: 'buildingName' }
        },
        {
            align: 'center',
            title: '单元数量',
            dataIndex: 'unitCount',
            width: '6%',
            scopedSlots: { customRender: 'unitCount' }
        },
        {
            align: 'center',
            title: '封顶日期',
            dataIndex: 'overRoofDate',
            width: '7%',
            scopedSlots: { customRender: 'overRoofDate' }
        },
        {
            align: 'center',
            title: '竣工日期',
            dataIndex: 'finishDate',
            width: '7%',
            scopedSlots: { customRender: 'finishDate' }
        },
        {
            align: 'center',
            title: '预售许可证',
            dataIndex: 'salePermissionId',
            width: '7%',
            scopedSlots: { customRender: 'salePermissionId' }
        },
        {
            align: 'center',
            title: '建筑许可证',
            dataIndex: 'buildPermissionId',
            width: '7%',
            scopedSlots: { customRender: 'buildPermissionId' }
        },
        {
            align: 'center',
            title: '建筑面积',
            dataIndex: 'buildArea',
            width: '6%',
            scopedSlots: { customRender: 'buildArea' }
        },
        {
            align: 'center',
            title: '使用面积',
            dataIndex: 'usedArea',
            width: '6%',
            scopedSlots: { customRender: 'usedArea' }
        },
        {
            align: 'center',
            title: '备注',
            dataIndex: 'remark',
            width: '10%',
            scopedSlots: { customRender: 'remark' }
        },
        {
            align: 'center',
            title: '编辑',
            width: '4%',
            dataIndex: 'operation',
            scopedSlots: { customRender: 'operation' }
        }
    ]

    const data = []
    export default {
        name: 'Step2',
        data() {
            return {
                labelCol: { span: 2 },
                wrapperCol: { span: 1 },
                returnBuildingNumber: '',
                form2: {
                    name: '',
                    region: undefined,
                    date1: undefined,
                    delivery: false,
                    type: [],
                    resource: '',
                    desc: ''
                },
                data,
                columns,
                editingKey: ''
                // labelCol: { lg: { span: 5 }, sm: { span: 5 } },
                // wrapperCol: { lg: { span: 19 }, sm: { span: 19 } },
                // form: this.$form.createForm(this),
                // loading: false,
                // timer: 0
            }
        },
        created() {
            const allData = {
                buildingNumber: this.$store.state.oneStep.buildingNumber,
                estateCode: this.$store.state.oneStep.estateCode
            }
            const params = QS.stringify(allData)
            selectBuilding(params).then(res => {
                const result = res.result
                for (let i = 0; i < result.length; i++) {
                    const building = result[i]
                    data.push({
                        key: building.id.toString(),
                        buildingCode: building.buildingCode,
                        buildingName: building.buildingName,
                        unitCount: building.unitCount,
                        overRoofDate: building.overRoofDate,
                        finishDate: building.finishDate,
                        salePermissionId: building.salePermissionId,
                        buildPermissionId: building.buildPermissionId,
                        buildArea: building.buildArea,
                        usedArea: building.usedArea,
                        remark: building.remark
                    })
                }
                this.cacheData = data.map(item => ({ ...item }))
                selectCountBuilding(QS.stringify({ estateCode: this.$store.state.oneStep.estateCode })).then(res => {
                    this.returnBuildingNumber = res.result
                })
            }).catch(err => {
                this.$notification['error']({
                    message: '错误',
                    description: ((err.response || {}).data || {}).message || '获取楼宇信息失败',
                    duration: 4
                })
            })
        },
        methods: {
            change() {
                const unitNumber = this.form2.region
                for (let i = 0; i < this.data.length; i++) {
                    this.data[i].unitCount = unitNumber
                }
            },
            nextStep() {
                const dataArray = this.data
                var param = '['
                for (let i = 0; i < dataArray.length; i++) {
                    if (i !== dataArray.length - 1) {
                        param += '{ "buildingCode": "' + dataArray[i].buildingCode + '", "unitCount": ' + dataArray[i].unitCount + '},'
                    } else {
                        param += '{ "buildingCode": "' + dataArray[i].buildingCode + '", "unitCount": ' + dataArray[i].unitCount + '}]'
                    }
                }

                this.$store.commit('SET_TITLE', {
                    unitMessage: param,
                    estateCode: this.$store.state.oneStep.estateCode
                })
                this.$emit('nextStep')
            },
            prevStep() {
                // this.$emit('prevStep')
            },
            handleChange(value, key, column) {
                const newData = [...this.data]
                const target = newData.filter(item => key === item.key)[0]
                if (target) {
                    target[column] = value
                    this.data = newData
                }
            },
            edit(key) {
                const newData = [...this.data]
                const target = newData.filter(item => key === item.key)[0]
                this.editingKey = key
                if (target) {
                    target.editable = true
                    this.data = newData
                    this.editingKey = ''
                }
            },
            save(key) {
                const newData = [...this.data]
                const newCacheData = [...this.cacheData]
                const target = newData.filter(item => key === item.key)[0]
                const targetCache = newCacheData.filter(item => key === item.key)[0]
                if (target && targetCache) {
                    delete target.editable
                    this.data = newData
                    Object.assign(targetCache, target)
                    this.cacheData = newCacheData
                }
                target.id = key
                target.estateCode = this.$store.state.oneStep.estateCode
                const param = QS.stringify(target)
                updateBuilding(param).then(res => {
                    setTimeout(() => {
                        this.$notification.success({
                            message: '恭喜你',
                            description: res.result
                        })
                    }, 1000)
                }).catch(err => {
                    this.$notification.error({
                        message: 'error',
                        description: ((err.response || {}).data || {}).message || '添加楼宇信息失败',
                        duration: 1
                    })
                })
            },
            cancel(key) {
                const newData = [...this.data]
                const target = newData.filter(item => key === item.key)[0]
                this.editingKey = ''
                if (target) {
                    Object.assign(target, this.cacheData.filter(item => key === item.key)[0])
                    delete target.editable
                    this.data = newData
                }
            }
        },
        beforeDestroy() {
            //  clearTimeout(this.timer)
        }
    }
</script>

<style lang="less" scoped>
    .stepFormText {
        margin-bottom: 24px;

        .ant-form-item-label,
        .ant-form-item-control {
            line-height: 22px;
        }
    }
</style>

后台逻辑:

    @RequestMapping("/estate/selectCompany")
    public JSONObject selectCompany(){
        System.out.println("/estate/selectCompany");
        List<TblCompany> tblCompanyNames = estateService.selectCompany();
        return JSONObject.parseObject(JSONObject.toJSONString(new Common(tblCompanyNames)));
    }
 @RequestMapping("/estate/selectEstate")
    public String selectEstate(String company){
        List<FcEstate> fcEstates = estateService.selectEstate(company);
        return JSONObject.toJSONString(new Common(fcEstates));
    }
@RequestMapping("/estate/selectCountBuilding")
    public String selectCountBuilding(String estateCode){
        Integer integer = estateService.selectCountBuilding(estateCode);
        System.out.println("-------------------"+integer);
        return JSONObject.toJSONString(new Common(integer));
    }
 public List<FcBuilding> selectBuilding(Integer buildingNumber,String estateCode ){
        FcBuilding lastRecord = fcBuildingMapper.selectLastRecord();
        int count = 0;
        if (lastRecord == null){
            count = 1;
        }else{
            count = Integer.parseInt(lastRecord.getBuildingName().replace("第","").replace("号楼",""))+1;
        }
        //创建插入的对象
        //插入数据,完成数据插入之后,id会直接回显,因此直接显式即可
        for(int i = 0;i<buildingNumber;i++){
            FcBuilding fcBuilding = new FcBuilding();
            fcBuilding.setEstateCode(estateCode);
            fcBuilding.setBuildingCode(estateCode+"B"+count);
            fcBuilding.setBuildingName("第"+count+"号楼");
            fcBuildingMapper.insert(fcBuilding);
            count++;
        }
        //定义返回的数据集合
        List<FcBuilding> fcBuildings = fcBuildingMapper.selectList(null);
        return fcBuildings;
    }
public List<FcEstate> selectEstate(String company){
        QueryWrapper<FcEstate> queryWrapper = new QueryWrapper<FcEstate>();
        queryWrapper.eq("company",company);
        queryWrapper.select("estate_code","estate_name");
        List<FcEstate> list = fcEstateMapper.selectList(queryWrapper);
        return list;
    }

    public Integer selectCountBuilding(String estateCode){
        QueryWrapper<FcBuilding> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("estate_code",estateCode);
        Integer integer = fcBuildingMapper.selectCount(queryWrapper);
        System.out.println("integer:"+integer);
        return integer;
    }

9、住宅维护

<template>
  <div>
    <a-table :rowSelection="rowSelection" :columns="columns" :dataSource="data">
      <a slot="estateCode" slot-scope="text, record" @click="edit(record)">{{ text }}</a>
      <template slot="operation" slot-scope="text, record">
        <a href="javascript:;" @click="seemqintain(text, record)">查看楼宇</a>
      </template>
    </a-table>
    <house-edit :editObj="editObj"></house-edit>
  </div>
</template>

<script>
import houseEdit from '../maintain-dialog/house.edit'
import { selectAllEstate } from '@/api/estate'

const columns = [
    {
        title: '所属公司',
        dataIndex: 'company',
    },
    {
        title: '住宅编码',
        dataIndex: 'estateCode',
        scopedSlots: { customRender: 'estateCode' }
    },
    {
        title: '住宅名称',
        dataIndex: 'estateName'
    },
    {
        title: '地址',
        dataIndex: 'estateAddr'
    },
    {
        align: 'center',
        title: '编辑',
        dataIndex: 'operation',
        scopedSlots: { customRender: 'operation' }
    }
]
const data = []
export default {
    name: 'Houseinformation',
    props: {
        activeKey: {
            type: Object,
            default: () => {
                return {
                    defaultKey: '1'
                }
            }
        }
    },
    data() {
        return {
            data,
            columns,
            editObj: {
                editvisible: false,
                company: ''
            }
        }
    },
    created() {
        selectAllEstate().then(res => {
            const result = res.result
            for(let i = 0; i<result.length; i++){
                const estate = result[i]
                data.push({
                    key: estate.id,
                    company: estate.company,
                    estateCode: estate.estateCode,
                    estateName: estate.estateName,
                    estateAddr: estate.estateAddr,
                    coverArea: estate.coverArea,
                    buildArea: estate.buildArea,
                    greenArea: estate.greenArea,
                    roadArea: estate.roadArea,
                    buildingNumber: estate.buildingNumber,
                    buildingLeader: estate.buildingLeader,
                    companyName: estate.companyName,
                    companyBehalf: estate.companyBehalf,
                    contact: estate.contact,
                    contactPhone: estate.contactPhone,
                    contactAddr: estate.contactAddr,
                    carSpaceDelayRate: estate.carSpaceDelayRate,
                    carSpaceOverDay: estate.carSpaceOverDay,
                    estateType: estate.estateType,
                    streetLampNumber: estate.streetLampNumber,
                    hfcNum: estate.hfcNum,
                    remark: estate.remark
                })
            }
        })
    },
    computed: {
        rowSelection() {
            // eslint-disable-next-line no-unused-vars
            const { selectedRowKeys } = this
            return {
                onChange: (selectedRowKeys, selectedRows) => {
                    console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows)
                }
            }
        }
    },
    methods: {
        edit(record) {
            this.editObj = record
            this.editObj.editvisible = true
        },
        seemqintain(text, record) {
            this.activeKey.defaultKey = '2'
            console.log(text, record)
            this.$emit('set-houseinformation', record.estateName)
        }
    },
    components: {
        houseEdit
    }
}
</script>

house.edit.vue

<template>
  <div>
    <a-modal :title="`编辑${editObj.company}信息`" width="70%" v-model="editObj.editvisible">
      <a-form :label-col="labelCol" :form="form" :wrapper-col="wrapperCol">
        <a-row>
          <a-col :span="12">
            <a-form-item label="房产编码">
              <a-input
                v-decorator="[
                  'estate_code',
                  { rules: [{ required: true, message: '必须填写房产编码!',trigger: 'blur' }],
                   initialValue: editObj.estateCode}
                ]"
                placeholder="填写房产编码"
              ></a-input>
            </a-form-item>
          </a-col>
          <a-col :span="12">
            <a-form-item label="房产名称">
              <a-input
                v-decorator="[
                  'estateName',
                  { rules: [{ required: true, message: '必须填写房产名称!',trigger: 'blur' }],
                   initialValue: editObj.estateName },
                ]"
                placeholder="填写房产名称"
              ></a-input>
            </a-form-item>
          </a-col>
        </a-row>
        <a-row>
          <a-col :span="24">
            <a-form-item label="房产地址" :labelCol="{span: 3}" :wrapperCol="{span: 21}">
              <a-input v-decorator="['estateAddr',{initialValue: editObj.estateAddr}]"></a-input>
            </a-form-item>
          </a-col>
        </a-row>
        <a-row>
          <a-col :span="12">
            <a-form-item label="占地面积">
              <a-input v-decorator="['coverArea',{initialValue: editObj.coverArea}]"></a-input>
            </a-form-item>
          </a-col>
          <a-col :span="12">
            <a-form-item label="建筑面积">
              <a-input v-decorator="['buildArea',{initialValue: editObj.buildArea}]"></a-input>
            </a-form-item>
          </a-col>
        </a-row>
        <a-row>
          <a-col :span="12">
            <a-form-item label="绿地面积">
              <a-input v-decorator="['greenArea',{initialValue: editObj.greenArea}]"></a-input>
            </a-form-item>
          </a-col>
          <a-col :span="12">
            <a-form-item label="道路面积">
              <a-input v-decorator="['roadArea',{initialValue: editObj.roadArea}]"></a-input>
            </a-form-item>
          </a-col>
        </a-row>
        <a-row>
          <a-col :span="12">
            <a-form-item label="楼宇数量">
              <a-input v-decorator="['buildingNumber',{initialValue: editObj.buildingNumber}]"></a-input>
            </a-form-item>
          </a-col>
          <a-col :span="12">
            <a-form-item label="负责人">
              <a-input v-decorator="['buildingLeader',{initialValue: editObj.buildingLeader}]"></a-input>
            </a-form-item>
          </a-col>
        </a-row>
        <a-row>
          <a-col :span="12">
            <a-form-item label="公司名称">
              <a-input v-decorator="['companyName',{initialValue: editObj.companyName}]"></a-input>
            </a-form-item>
          </a-col>
          <a-col :span="12">
            <a-form-item label="法人代表">
              <a-input v-decorator="['companyBehalf',{initialValue: editObj.companyBehalf}]"></a-input>
            </a-form-item>
          </a-col>
        </a-row>
        <a-row>
          <a-col :span="12">
            <a-form-item label="联系人">
              <a-input v-decorator="['contact',{initialValue: editObj.contact}]"></a-input>
            </a-form-item>
          </a-col>
          <a-col :span="12">
            <a-form-item label="联系电话">
              <a-input v-decorator="['contactPhone',{initialValue: editObj.contactPhone}]"></a-input>
            </a-form-item>
          </a-col>
        </a-row>
        <a-row>
          <a-col :span="12">
            <a-form-item label="联系地址">
              <a-input v-decorator="['contactAddr',{initialValue: editObj.contactAddr}]"></a-input>
            </a-form-item>
          </a-col>
          <a-col :span="12">
            <a-form-item label="车位滞纳金比率">
              <a-input v-decorator="['carSpaceDelayRate',{initialValue: editObj.carSpaceDelayRate}]"></a-input>
            </a-form-item>
          </a-col>
        </a-row>
        <a-row>
          <a-col :span="12">
            <a-form-item label="车位超期天数">
              <a-input v-decorator="['carSpaceOverDay',{initialValue: editObj.carSpaceOverDay}]"></a-input>
            </a-form-item>
          </a-col>
          <a-col :span="12">
            <a-form-item label="路灯数量">
              <a-input v-decorator="['streetLampNumber',{initialValue: editObj.streetLampNumber}]"></a-input>
            </a-form-item>
          </a-col>
        </a-row>
        <a-row>
          <!--  :labelCol="{span: 3}" :wrapperCol="{span: 21}" -->
          <a-col :span="12">
            <a-form-item label="化粪池数量">
              <a-input v-decorator="['hfcNum',{initialValue: editObj.hfcNum}]"></a-input>
            </a-form-item>
          </a-col>
          <a-col :span="12">
            <a-form-item label="备注">
              <a-input v-decorator="['remark',{initialValue: editObj.remark}]"></a-input>
            </a-form-item>
          </a-col>
        </a-row>
        <a-row>
          <a-col :span="12">
            <a-form-item label="所属公司">
              <a-input v-decorator="['company',{initialValue: editObj.company}]"></a-input>
            </a-form-item>
          </a-col>
            <a-col :span="12">
                <a-form-item label="房产编号" type="hidden">
                    <a-input v-decorator="['id',{initialValue: editObj.key}]"></a-input>
                </a-form-item>
            </a-col>
        </a-row>
      </a-form>
      <template slot="footer">
        <a-button type="primary" icon="save" @click="saveAndClose">保存并关闭</a-button>&nbsp;
        <a-button type="primary" icon="close-square" @click="handleCancel">关闭</a-button>
      </template>
    </a-modal>
  </div>
</template>

<script>
import { updateEstate } from '@/api/estate'
const QS = require('qs')
export default {
    data() {
        return {
            labelCol: { lg: { span: 6 }, sm: { span: 6 } },
            wrapperCol: { lg: { span: 18 }, sm: { span: 18 } },
            form: this.$form.createForm(this)
        }
    },
    props: {
        editObj: {
            type: Object,
            default: () => {
                return {
                    editvisible: false
                }
            }
        }
    },
    methods: {
        saveAndClose(e) {
            e.preventDefault()
            this.form.validateFieldsAndScroll((err, values) => {
                updateEstate(QS.stringify(values)).then(res => {
                    this.$notification.success({
                        message: '提示',
                        duration: 3,
                        description: res.result
                    })
                }).catch(err => {
                    this.$notification.error({
                        message: '提示',
                        duration: 3,
                        description: err.result
                    })
                })
            })
            this.editObj.editvisible = false
        },
        handleCancel(e) {
            this.editObj.editvisible = false
        }
    }
}
</script>

<style lang='less' scoped>
.edit {
    width: 600px;
    height: 500px;
}
.ant-form-item {
    margin-top: 5px;
    margin-bottom: 0px;
}
</style>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值