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>
<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>
<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>
<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>