crm客户关系管理系统(vue+maven多模块+SSM)
一、技术介绍1.1 maven多模块这里写了maven多模块的介绍和为什么要使用maven多模块,后面还有maven多模块项目搭建实战。https://blog.csdn.net/qq_36892672/article/details/1038366141.2 前后端分离vue基础:https://blog.csdn.net/qq_36892672/article/details/10...
一、技术介绍
1.1 maven多模块
这里写了maven多模块的介绍和为什么要使用maven多模块,后面还有maven多模块项目搭建实战。
https://blog.csdn.net/qq_36892672/article/details/103836614
1.2 前后端分离
- vue基础:
https://blog.csdn.net/qq_36892672/article/details/103772412
- vue进阶:
https://blog.csdn.net/qq_36892672/article/details/103787320
- element ui :
https://blog.csdn.net/qq_36892672/article/details/103809746
- 项目使用vue-admin-master,这个在网上有很多的教程,这里就不做详解了,这是一个基于vue的前端后台管理的demo,我们只需要在其中加上我们自己的模块就好了。
//download.csdn.net/download/qq_36892672/12106039
1.3 SSM框架
SSM集成:
https://blog.csdn.net/qq_36892672/article/details/103752919
1.4 第三方登录
1.5 Lucene搜索引擎
1.6 Saas模式
SAAS:软件即服务
本系统是基于saas服务的。统一开放,维护,租户(注册付费的公司)需要在本系统中进行注册,并付费,然后根据付费情况使用系统功能。
多租户(Multi Tenancy/Tenant)是一种软件架构,其定义是:在一台服务器上运行单个应用实例,它为多个租户提供服务。
我们项目是基于saas的,提供给其他公司进行付费使用,租户需要先在平台完成注册和付费。
我们项目采用的是:
共享数据库,共享scheme,共享数据库表,通过租户id进行区别:
所有租户的数据都存放在一个数据库的同一套表中, 在表中增加tenant_id标志字段,表明该记录是属于哪个租户的。
优点:数据源和数据库的管理都比较简单。和原来的应用没有差别。
缺点:数据权限比较复杂,增加程序的复杂性。如果应用比较复杂,很多数据表都需要加入客户标志字段,很多查询都需要包括该字段,会比较麻烦。如果有遗漏,、特别是查询条件中遗漏该字段,就会造成一个客户看到另一个客户的数据。
1.7 shiro权限管理
shiro权限管理:
https://blog.csdn.net/qq_36892672/article/details/103541985
二、项目需求分析
2.1 需求文档
略
2.2 系统模块图
2.3 数据库设计
数据库sql语句见附件。
//download.csdn.net/download/qq_36892672/12106112
2.4 模块详解
2.4.1 订单管理:(t_order)
- 业务描述:用户缴纳定金后需要将定金合同录入系统,
增加、删除(批量删除、根据id删除)、修改、查询(条件:单号、签订时间范围、营销人员、客户、状态)、生成合同
sn:yyyyMMdd-XXXX,自动生成
-定金客户:从客户池中选取
签订时间:手动录入yyyy-MM-dd
营销人员:从当前登录的用户中获取 - 模型:
- 使用人员:营销人员
2.4.2 合同管理:(t_ontract)
- 业务描述:客户确认购买公司时由订单管理生成合同,对合同进行修改保存,保存的时候将将对应订单的状态改为已签订合同,同时生成保修单。
搜索:(客户、合同单号、订单单号、签订时间)
新增:选择未签订合同订单。
模型:
- 合同付款明细(t_ontract_detail)
- 使用人员:营销人员
2.4.3 保修管理:(t_repair)
- 业务描述:保修单由合同生成是自动生成,只做修改,即增加保修明细。
- 模型:
- 保修单明细(t_repair_detail)
- 使用人员:客服人员
2.4.4 业务流程
销售人员在线下签订订单录入,录入后可以录入信息进行修改删除和生成合同,一个订单只能生成一个合同,生成后禁用生成合同,若将该合格删除,那么生成合同恢复,生成的合同字段不完整,一些信息需要手动录入和修改,合同签订可以生成保单,一个合同可能对应多个保单,所以生成保单后可以继续生成,不禁用生成保单。保单和合同的详情采用可编辑表格手动录入。
三、(负责模块)开发
3.1 订单管理
3.1.1 vue
<template>
<div>
<!--查询的form表单-->
<el-form style="margin-top: 20px" :inline="true" :model="searchForm" class="demo-form-inline">
<el-form-item label="状态">
<el-select v-model="searchForm.status" placeholder="请选择状态">
<el-option label="已签合同" value="1"></el-option>
<el-option label="未签合同" value="0"></el-option>
<el-option label="定金失效" value="-1"></el-option>
</el-select>
</el-form-item>
<el-form-item label="签订时间">
<el-col :span="11">
<el-date-picker
v-model="searchForm.minSignTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择日期">
</el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-date-picker
v-model="searchForm.maxSignTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择日期">
</el-date-picker>
</el-col>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="searchSubmit">查询</el-button>
</el-form-item>
</el-form>
<!--批量删除-->
<el-button type="danger" style="float: left;margin-bottom:20px;margin-left: 20px" @click="batchRemove"
:disabled="this.selectRows.length===0">批量删除
</el-button>
<!--添加-->
<el-button type="primary" style="float: left;margin-bottom:20px;" @click="add">新增</el-button>
<!--
:data 根据数据展示列表
@selection-change: 获取选中列表触发事件(返回的是选中的对象列表)
v-loading="loading" 值为true代表是加载效果
-->
<el-table
:data="tableData"
v-loading="loading"
style="width: 100%"
@selection-change="selectionChange"
>
<el-table-column fixed type="selection" width="55">
</el-table-column>
<el-table-column type="index" fixed label="序号" width="70px" sortable="true">
</el-table-column>
<el-table-column width="140px" fixed prop="sn" label="单号" sortable="true"></el-table-column>
<el-table-column width="100px" prop="customer.name" label="订单客户"></el-table-column>
<el-table-column width="130px" prop="signTime" label="签订时间" sortable="true"></el-table-column>
<el-table-column width="130px" prop="dueToTime" label="到期时间"></el-table-column>
<el-table-column width="100px" prop="seller.realName" label="营销人员"></el-table-column>
<el-table-column width="100px" prop="sum" label="金额" sortable="true"></el-table-column>
<el-table-column width="100px" prop="status" label="状态">
<template slot-scope="scope">
<el-tag
:type="scope.row.status == 1 ? 'success' :scope.row.status == 0 ? 'info' : 'danger'"
disable-transitions>{{scope.row.status == 1 ? '已签合同' : scope.row.status == 0 ? '未签合同' :
'失效'}}
</el-tag>
</template>
</el-table-column>
<el-table-column width="200px" prop="intro" label="摘要"></el-table-column>
<!--操作-->
<el-table-column label="操作" width="250px" fixed="right">
<template slot-scope="scope">
<el-button
l-tabl size="small"
@click="handleEdit(scope.$index, scope.row)">编辑
</el-button>
<el-button type="warning"
@click="createContract(scope.$index, scope.row)"
size="small"
:disabled="scope.row.status!=0">生成合同
</el-button>
<el-button
size="small"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<!--分页-->
<el-pagination style="margin-top: 10px;float: right"
@size-change="sizeChange"
@current-change="currentChange"
:current-page="currentPage"
:page-sizes="pageSizes"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
<!--修改、添加弹出框-->
<el-dialog :title="title" :visible.sync="visible" :close-on-click-modal="false">
<el-form :model="form" label-width="80px" :rules="formRules" ref="form">
<el-form-item label="单号">
<el-input v-model="form.sn" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="订单客户">
<!--@change="optionChange"-->
<el-select v-model="form.customerId" placeholder="请选择客户">
<el-option
v-for="item in customers"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="签订时间">
<el-date-picker
v-model="form.signTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择日期">
</el-date-picker>
</el-form-item>
<el-form-item label="到期时间">
<el-date-picker
v-model="form.dueToTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择日期">
</el-date-picker>
</el-form-item>
<el-form-item label="金额">
<el-input v-model="form.sum" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="摘要">
<el-input
type="textarea"
autosize
placeholder="请输入内容"
v-model="form.intro">
</el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click.native="visible = false">取消</el-button>
<el-button type="primary" @click.native="submit" :loading="editLoading">提交</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'Order',
data() {
return {
currentPermissions:[],
loading: true,
tableData: [],
selectRows: [],
customers: [],
//分页相关
//当前页
currentPage: 1,
//每页条数集合
pageSizes: [5, 10, 15, 20],
//每页条数
pageSize: 10,
//总数
total: 0,
//修改、增加相关
//是否可见
visible: false,
//标题
title: "",
//搜索条件form model
searchForm: {
status: '',
minSignTime: '',
maxSignTime: ''
},
//修改、新增form model
form: {
customerId: '',
id: "",
sn: "",
customer: null,
signTime: '',
dueToTime: '',
sum: '',
intro: ''
},
formRules: {
name: [
{required: true, message: '请输入部门', trigger: 'blur'}
]
},
editLoading: false
};
},
methods: {
//加载列表
loadOrderList() {
//查询传递参数
let params = {
"currentPage": this.currentPage,
"pageSize": this.pageSize,
status: this.searchForm.status,
minSignTime: this.searchForm.minSignTime,
maxSignTime: this.searchForm.maxSignTime
};
this.$http.patch("/allUserPermissions").then(res => {
this.currentPermissions=res.data;
});
this.loading = true;
this.$http.patch("/order/selectPageByQuery", params).then(res => {
this.tableData = res.data.list;
this.total = res.data.total;
this.loading = false;
});
},
//多选
selectionChange(v) {
this.selectRows = v;
},
/*optionChange(v){
console.log(v);
this.form.customer.id = v;
},*/
//每页条数改变
sizeChange(v) {
this.currentPage = 1;
this.pageSize = v;
this.loadOrderList();
//加载框
this.loading = true;
},
//当前页改变
currentChange(v) {
this.currentPage = v;
this.loadOrderList();
//加载框
this.loading = true
},
//删除一条数据
handleDelete(i, r) {
if(this.currentPermissions.indexOf("/order/delete")===-1){
this.$message({type: 'info',message:"没有权限!"});return;
}
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http.delete("/order/delete/" + r.id).then(res => {
if (res.data.success) {
this.$message({
type: 'success',
message: r.sn + "删除成功"
});
} else {
this.$message({
type: 'error',
message: res.data.msg
});
}
this.loadOrderList();
})
}).catch(() => {
});
},
//批量删除
batchRemove() {
if(this.currentPermissions.indexOf("/order/batchDelete")===-1){
this.$message({type: 'info',message:"没有权限!"});return;
}
if (!this.selectRows.length) {
this.$message.error('亲!请选中数据进行删除哦!!');
return;
}
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http.patch("/order/batchDelete", this.selectRows).then(res => {
if (res.data.success) {
if (res.data.success) {
this.$message({
type: 'success',
message: "共删除" + this.selectRows.length + "条数据"
});
} else {
this.$message({
type: 'error',
message: res.data.msg
});
}
this.loadOrderList();
}
})
}).catch(() => {
});
},
//新增
add() {
if(this.currentPermissions.indexOf("/order/save")===-1){
this.$message({type: 'info',message:"没有权限!"});return;
}
this.$http.patch("/customer/list").then(res => {
this.customers = res.data;
});
for (let k in this.form) {
this.form[k] = '';
}
this.visible = true;
this.title = "添加订单";
},
//修改
handleEdit(i, r) {
if(this.currentPermissions.indexOf("/order/update")===-1){
this.$message({type: 'info',message:"没有权限!"});return;
}
this.$http.patch("/customer/list").then(res => {
this.customers = res.data;
});
for (let k in r) {
this.form[k] = r[k];
}
this.form.customerId = r.customer.id;
console.log(this.form);
this.visible = true;
this.title = "更新订单";
},
//提交修改或增加
submit() {
this.$refs.form.validate((valid) => {
if (valid) {
this.editLoading = true;
//NProgress.start();
let para = Object.assign({}, this.form);
let customer = {
id: ''
};
customer.id = para.customerId;
para.customer = customer;
if (this.form.id) {
this.$http.post("/order/update", para).then((res) => {
this.editLoading = false;
//NProgress.done();
if (res.data.success) {
this.$message({
message: '提交成功',
type: 'success'
});
} else {
this.$message({
message: res.data.msg,
type: 'error'
});
}
this.$refs['form'].resetFields();
this.visible = false;
this.loadOrderList();
});
}
else {
this.editLoading = false;
this.$http.put("/order/save", para).then((res) => {
this.editLoading = false;
//NProgress.done();
if (res.data.success) {
this.$message({
message: '提交成功',
type: 'success'
});
} else {
this.$message({
message: res.data.msg,
type: 'error'
});
}
this.$refs['form'].resetFields();
this.visible = false;
this.loadOrderList();
});
}
}
});
},
//生成合同
createContract(i,r) {
if(this.currentPermissions.indexOf("/order/createContract")===-1){
this.$message({type: 'info',message:"没有权限!"});return;
}
this.$http.post("/order/createContract", r).then((res) => {
if (res.data.success) {
this.$message({
message: '生成合同成功!'+res.data.msg,
type: 'success'
});
} else {
this.$message({
message: res.data.msg,
type: 'error'
});
}
this.loadOrderList();
});
},
//搜索框
searchSubmit() {
this.loadOrderList();
}
},
mounted() {
//当页面加载完毕的时候发送ajax请求
this.loadOrderList();
}
}
</script>
<style scoped>
</style>
routes.js
//增加
import Order from './views/system/Order.vue'
import Contract from './views/system/Contract.vue'
import Repair from './views/system/Repair.vue'
.....
let routes = [
.....
{
path: '/',
component: Home,
name: '订单合同管理',
iconCls: 'fa fa-id-card-o',
children: [
{ path: '/order', component: Order, name: '定金订单管理' },
{ path: '/contract', component: Contract, name: '合同管理' }
]
},
{
path: '/',
component: Home,
name: '售后管理',
iconCls: 'fa fa-address-card',
leaf: true,//只有一个节点
children: [
{ path: '/repair', component: Repair, name: '售后管理' }
]
}
];
3.1.2 controller
package com.cl.crm.web.controller;
import com.cl.base.util.AjaxResult;
import com.cl.crm.domain.Order;
import com.cl.crm.query.OrderQuery;
import com.cl.crm.service.IOrderService;
import com.cl.crm.shiro.util.UserContext;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Controller
@RequestMapping("/order")
@CrossOrigin
public class OrderController {
@Autowired
private IOrderService orderService;
/**
* resetful: 它是一个架构风格,它是基于Http协议的扩展
* 它给你提供了多种请求方式来定位资源
* GET 一般是用来做查询的,查询单个对象
* POST 一般用来做修改的
* DELETE 一般用来做删除
* PUT 一般用来做新增
* PATCH 一般用来操作批量数据的
* @return
*/
@RequestMapping(value = "/list",method = RequestMethod.PATCH)
@ResponseBody
public List<Order> list(){
return orderService.selectAll();
}
/**
* 条件查询
* @param query
* @return
*/
@RequestMapping(value = "/selectByQuery",method = RequestMethod.PATCH)
@ResponseBody
public List<Order> selectByQuery(@RequestBody OrderQuery query){
query.setTenantId(UserContext.getEmployee().getTenantId());
return orderService.selectByQuery(query);
}
/**
* 条件分页查询
* @param query
* @return
*/
@RequestMapping(value = "/selectPageByQuery",method = RequestMethod.PATCH)
@ResponseBody
public PageInfo<Order> selectPageByQuery(@RequestBody OrderQuery query){
query.setTenantId(UserContext.getEmployee().getTenantId());
return orderService.selectPageByQuery(query);
}
/**
* 添加订单
* @param order
* @return
*
* @RequestBody:前端传递json对象,它会自动转为Order对象
*
*/
@RequestMapping(value = "/save",method = RequestMethod.PUT)
@ResponseBody
public AjaxResult save(@RequestBody Order order){
try {
order.setSeller(UserContext.getEmployee());
order.setTenantId(UserContext.getEmployee().getTenantId());
orderService.insert(order);
return new AjaxResult();
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult(false, "添加失败!"+e.getMessage());
}
}
/**
* 修改订单
* @param order
* @return
*/
@RequestMapping(value = "/update",method = RequestMethod.POST)
@ResponseBody
public AjaxResult update(@RequestBody Order order){
try {
orderService.update(order);
return new AjaxResult();
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult(false, "修改失败!"+e.getMessage());
}
}
/**
* 生成合同,修改订单状态。
* @param order
* @return
*/
@RequestMapping(value = "/createContract",method = RequestMethod.POST)
@ResponseBody
public AjaxResult createContract(@RequestBody Order order){
try {
Long contractSn = orderService.updateStatus(order);
return new AjaxResult(true,"合同编号"+contractSn);
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult(false, "修改失败!"+e.getMessage());
}
}
/**
* 删除
* @param id
* @return
*/
@RequestMapping(value = "/delete/{id}",method = RequestMethod.DELETE)
@ResponseBody
public AjaxResult delete(@PathVariable("id") Long id){
try {
orderService.delete(id);
return new AjaxResult();
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult(false, "删除失败!"+e.getMessage());
}
}
/**
* 批量删除
* @param orders
* @return
*/
@RequestMapping(value = "/batchDelete",method = RequestMethod.PATCH)
@ResponseBody
public AjaxResult batchDelete(@RequestBody List<Order> orders){
try {
orderService.batchDelete(orders);
return new AjaxResult();
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult(false, "删除失败!"+e.getMessage());
}
}
/**
* 查询单个对象
* @param id
* @return
*/
@RequestMapping(value = "/get/{id}",method = RequestMethod.GET)
@ResponseBody
public Order get(@PathVariable("id") Long id){
return orderService.selectById(id);
}
}
3.1.3 service接口
public interface IOrderService extends IBaseService<Order,Long> {
Long updateStatus(Order order);
}
3.1.3.1 serviceImpl
@Service
public class OrderServiceImpl extends BaseServiceImpl<Order,Long> implements IOrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private ContractMapper contractMapper;
@Override
public BaseMapper<Order, Long> baseMapper() {
return orderMapper;
}
@Override
public Long updateStatus(Order order) {
//生成合同对象
Contract contract = new Contract();
contract.setCustomer(order.getCustomer());
contract.setOrder(order);
contract.setSn(order.getSn());
contract.setSeller(order.getSeller());
contract.setTenantId(order.getTenantId());
//将订单状态改为已签合同
order.setStatus(1);
orderMapper.update(order);
contractMapper.insert(contract);
return contract.getSn();
}
}
3.1.4 mapper接口
public interface OrderMapper extends BaseMapper<Order,Long> {
}
3.1.5 mapper.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.cl.crm.mapper.OrderMapper">
<resultMap id="sqlMap" type="Order">
<id column="id" property="id"/>
<result column="sn" property="sn"/>
<result column="signTime" property="signTime"/>
<result column="dueToTime" property="dueToTime"/>
<result column="sum" property="sum"/>
<result column="intro" property="intro"/>
<result column="status" property="status"/>
<result column="tenantId" property="tenantId"/>
<association property="customer" javaType="Customer">
<id column="cuid" property="id"/>
<result column="cuname" property="name"/>
</association>
<association property="seller" javaType="Employee">
<id column="eid" property="id"/>
<result column="erealName" property="realName"/>
</association>
</resultMap>
<sql id="column">
o.id,
o.sn,
o.signTime,
o.dueToTime,
o.sum,
o.intro,
o.status,
o.tenant_id AS tenantId,
cu.id AS cuid,
cu.name AS cuname,
e.id AS eid,
e.realName AS erealName
</sql>
<insert id="insert" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
INSERT INTO
t_order(sn,customer_id,signTime,dueToTime,seller_id,sum,intro,status,mark,tenant_id)
VALUES (#{sn}, #{customer.id},#{signTime},#{dueToTime},#{seller.id},
#{sum},#{intro},#{status},#{mark},#{tenantId})
</insert>
<delete id="delete">
UPDATE t_order set mark =FALSE WHERE id=#{id}
</delete>
<delete id="batchDelete">
UPDATE t_order set mark =FALSE WHERE id IN
<foreach collection="list" open="(" close=")" item="item" separator=",">
#{item.id}
</foreach>
</delete>
<update id="update">
update t_order
<set>
<if test="sn!=null">
sn = #{sn},
</if>
<if test="customer!=null and customer.id!=null">
customer_id = #{customer.id},
</if>
<if test="signTime!=null">
signTime = #{signTime},
</if>
<if test="dueToTime!=null">
dueToTime = #{dueToTime},
</if>
<if test="seller!=null and seller.id!=null">
seller_id = #{seller.id},
</if>
<if test="sum!=null">
sum = #{sum},
</if>
<if test="intro!=null and intro!=''">
intro = #{intro},
</if>
<if test="status!=null">
status = #{status},
</if>
</set>
WHERE id = #{id}
</update>
<select id="selectById" resultMap="sqlMap">
SELECT
<include refid="column"/>
FROM t_order o
LEFT JOIN t_customer cu
ON o.customer_id = cu.id
LEFT JOIN t_employee e
ON o.seller_id = e.id
WHERE o.id=#{id} AND o.mark=b'1'
</select>
<select id="selectAll" resultMap="sqlMap">
SELECT <include refid="column"/> FROM t_order o
LEFT JOIN t_customer cu
ON o.customer_id = cu.id
LEFT JOIN t_employee e
ON o.seller_id = e.id
WHERE o.mark=b'1'
</select>
<select id="selectByQuery" resultMap="sqlMap">
SELECT
<include refid="column"/>
FROM t_order o
LEFT JOIN t_customer cu
ON o.customer_id = cu.id
LEFT JOIN t_employee e
ON o.seller_id = e.id
WHERE o.mark=b'1'
<if test="minSignTime!=null">
AND o.signTime >= #{minSignTime}
</if>
<if test="tenantId!=null">
AND o.tenant_id = #{tenantId}
</if>
<if test="maxSignTime!=null">
AND o.signTime <![CDATA[<]]> #{maxSignTime}
</if>
<if test="status!=null">
AND o.status = #{status}
</if>
</select>
</mapper>
ContractDetailMapper.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.cl.crm.mapper.ContractDetailMapper">
<resultMap id="sqlMap" type="ContractDetail">
<id column="id" property="id"/>
<result column="payTime" property="payTime"/>
<result column="mony" property="mony"/>
<result column="scale" property="scale"/>
<result column="payment" property="payment"/>
</resultMap>
<sql id="column">
id,payTime,mony,scale,payment
</sql>
<insert id="insert" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
INSERT INTO t_contract_detail(
payTime,mony,scale,payment)
VALUES (#{payTime},#{mony},#{scale},#{payment})
</insert>
<delete id="delete">
DELETE FROM t_contract_detail WHERE id=#{id}
</delete>
<delete id="deleteByContractId">
DELETE FROM t_contract_detail WHERE contract_id=#{contractId}
</delete>
<insert id="batchInsert">
INSERT INTO t_contract_detail(payTime,mony,scale,payment,contract_id) VALUES
<foreach collection="contractDetails" item="item" separator=",">
(#{item.payTime},#{item.mony},#{item.scale},#{item.payment},#{contractId})
</foreach>
</insert>
<delete id="batchDelete">
DELETE FROM t_contract_detail WHERE id IN
<foreach collection="list" open="(" close=")" item="item" separator=",">
#{item.id}
</foreach>
</delete>
<update id="update">
update t_contract_detail
<set>
<if test="payTime!=null">
payTime = #{payTime},
</if>
<if test="mony!=null">
mony = #{mony},
</if>
<if test="scale!=null">
scale = #{scale},
</if>
<if test="payment!=null">
payment = #{payment},
</if>
</set>
where id = #{id}
</update>
<select id="selectById" resultMap="sqlMap">
SELECT
<include refid="column"/>
FROM t_contract_detail WHERE id=#{id}
</select>
<select id="selectByContractId" resultMap="sqlMap">
SELECT <include refid="column"/> FROM t_contract_detail WHERE contract_id=#{contractId}
</select>
<select id="selectAll" resultMap="sqlMap">
SELECT
<include refid="column"/>
FROM t_contract_detail
</select>
<select id="selectByQuery" resultMap="sqlMap">
SELECT
<include refid="column"/>
FROM t_contract_detail
<where>
<if test="contract!=null and contract.id!=null">
AND contract_id = #{contract.id}
</if>
<if test="minPayTime!=null">
AND payTime >= #{minPayTime}
</if>
<if test="maxPayTime!=null">
AND payTime <![CDATA[<]]> #{maxPayTime}
</if>
</where>
</select>
</mapper>
3.2 合同管理
3.1.1 vue
<template xmlns:v-slot="http://www.w3.org/1999/XSL/Transform">
<div>
<!--查询的form表单-->
<el-form style="margin-top: 20px" :inline="true" :model="searchForm" class="demo-form-inline">
<el-form-item label="最小未付金额">
<el-input type="number" v-model="searchForm.unpaid" placeholder="最小未付金额"/>
</el-form-item>
<el-form-item label="签订时间">
<el-col :span="11">
<el-date-picker
v-model="searchForm.minSignTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择日期">
</el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-date-picker
v-model="searchForm.maxSignTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择日期">
</el-date-picker>
</el-col>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="searchSubmit">查询</el-button>
</el-form-item>
</el-form>
<!--批量删除-->
<el-button type="danger" style="float: left;margin-bottom:20px;margin-left: 20px" @click="batchRemove"
:disabled="this.selectRows.length===0">批量删除
</el-button>
<!--
:data 根据数据展示列表
@selection-change: 获取选中列表触发事件(返回的是选中的对象列表)
v-loading="loading" 值为true代表是加载效果
-->
<el-table
:data="tableData"
v-loading="loading"
style="width: 100%"
@selection-change="selectionChange"
>
<el-table-column fixed type="selection" width="55">
</el-table-column>
<el-table-column type="index" fixed label="序号" width="70px" sortable="true">
</el-table-column>
<el-table-column width="140px" fixed prop="sn" label="合同编号号" sortable="true"></el-table-column>
<el-table-column width="100px" prop="customer.name" label="合同客户"></el-table-column>
<el-table-column width="140px" prop="order.sn" label="订单编号"></el-table-column>
<el-table-column width="130px" prop="signTime" label="签订时间" sortable="true"></el-table-column>
<el-table-column width="100px" prop="seller.realName" label="营销人员"></el-table-column>
<el-table-column width="100px" prop="sum" label="金额" sortable="true"></el-table-column>
<el-table-column width="120px" prop="paid" label="已付金额" sortable="true"></el-table-column>
<el-table-column width="120px" prop="unpaid" label="未付金额" sortable="true"></el-table-column>
<el-table-column width="200px" prop="intro" label="摘要"></el-table-column>
<!--操作-->
<el-table-column label="操作" width="250px" fixed="right">
<template slot-scope="scope">
<el-button
size="small"
@click="handleEdit(scope.$index, scope.row)">编辑
</el-button>
<el-button type="warning"
@click="createContract(scope.$index, scope.row)"
size="small">生成保单
</el-button>
<el-button
size="small"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<!--分页-->
<el-pagination style="margin-top: 10px;float: right"
@size-change="sizeChange"
@current-change="currentChange"
:current-page="currentPage"
:page-sizes="pageSizes"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
<!--修改弹出框-->
<el-dialog :title="title" :visible.sync="visible" :close-on-click-modal="false">
<el-form :model="form" label-width="80px" :rules="formRules" ref="form">
<el-form-item label="签订时间">
<el-date-picker
v-model="form.signTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择日期">
</el-date-picker>
</el-form-item>
<el-form-item label="摘要">
<el-input
type="textarea"
autosize
placeholder="请输入内容"
v-model="form.intro">
</el-input>
</el-form-item>
<h6 style="display: inline-block">合同付款详情</h6>
<!--可编辑表格-->
<vxe-button @click="insertEvent">插入</vxe-button>
<vxe-table
border
show-overflow
:data="form.contractDetails"
:edit-config="{trigger: 'click', mode: 'cell'}">
<vxe-table-column type="seq" width="60"></vxe-table-column>
<vxe-table-column width="150" field="payTime" title="付款时间" :edit-render="{name: 'input'}">
<template v-slot:edit="{ row }">
<input type="date" v-model="row.payTime" class="custom-input">
</template>
</vxe-table-column>
<vxe-table-column field="mony" title="付款金额" :edit-render="{name: 'input'}">
<template v-slot:edit="{ row }">
<el-input
@change="monyChange"
type="number"
autosize
placeholder="请输入内容"
v-model="row.mony">
</el-input>
</template>
</vxe-table-column>
<vxe-table-column field="scale" title="所占比例">
</vxe-table-column>
<vxe-table-column field="payment" title="是否付款" :edit-render="{name: 'radio'}">
<template v-slot:edit="{ row }">
<el-radio v-model="row.payment" label="true">true</el-radio>
<el-radio v-model="row.payment" label="false">false</el-radio>
</template>
</vxe-table-column>
<vxe-table-column title="操作">
<!--<template v-slot="{ row }">
<el-button @click="removeEvent(row)">移除</el-button>
</template>-->
<template slot-scope="scope">
<el-button
@click.native.prevent="deleteRow(scope.$index, form.contractDetails)"
type="text"
size="small">
移除
</el-button>
</template>
</vxe-table-column>
</vxe-table>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click.native="visible = false">取消</el-button>
<el-button type="primary" @click.native="submit" :loading="editLoading">提交</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'Contract',
data() {
return {
currentPermissions: [],
loading: true,
tableData: [],
selectRows: [],
//分页相关
//当前页
currentPage: 1,
//每页条数集合
pageSizes: [5, 10, 15, 20],
//每页条数
pageSize: 10,
//总数
total: 0,
//修改、增加相关
//是否可见
visible: false,
//标题
title: "",
//搜索条件form model
searchForm: {
unpaid: "",
minSignTime: '',
maxSignTime: ''
},
//修改、新增form model
form: {
signTime: "",
intro: "",
contractDetails: [],
},
formRules: {
sn: [
{required: true, message: '请输入合同编号', trigger: 'blur'}
]
},
editLoading: false,
};
},
methods: {
//加载列表
loadContractList() {
//查询传递参数
this.$http.patch("/allUserPermissions").then(res => {
this.currentPermissions = res.data;
});
let params = {
"currentPage": this.currentPage,
"pageSize": this.pageSize,
unpaid: this.searchForm.unpaid,
minSignTime: this.searchForm.minSignTime,
maxSignTime: this.searchForm.maxSignTime
};
this.loading = true;
this.$http.patch("/contract/selectPageByQuery", params).then(res => {
this.tableData = res.data.list;
this.total = res.data.total;
this.loading = false;
});
},
//多选
selectionChange(v) {
this.selectRows = v;
},
//每页条数改变
sizeChange(v) {
this.currentPage = 1;
this.pageSize = v;
this.loadContractList();
//加载框
this.loading = true;
},
//当前页改变
currentChange(v) {
this.currentPage = v;
this.loadContractList();
//加载框
this.loading = true
},
//删除一条数据
handleDelete(i, r) {
if (this.currentPermissions.indexOf("/contract/delete") === -1) {
this.$message({type: 'info', message: "没有权限!"});
return;
}
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http.delete("/contract/delete/" + r.id).then(res => {
if (res.data.success) {
this.$message({
type: 'success',
message: r.sn + "删除成功"
});
} else {
this.$message({
type: 'error',
message: res.data.msg
});
}
this.loadContractList();
})
}).catch(() => {
});
},
//批量删除
batchRemove() {
if (this.currentPermissions.indexOf("/contract/batchDelete") === -1) {
this.$message({type: 'info', message: "没有权限!"});
return;
}
if (!this.selectRows.length) {
this.$message.error('亲!请选中数据进行删除哦!!');
return;
}
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http.patch("/contract/batchDelete", this.selectRows).then(res => {
if (res.data.success) {
if (res.data.success) {
this.$message({
type: 'success',
message: "共删除" + this.selectRows.length + "条数据"
});
} else {
this.$message({
type: 'error',
message: res.data.msg
});
}
this.loadContractList();
}
})
}).catch(() => {
});
},
//修改合同
handleEdit(i, r) {
if (this.currentPermissions.indexOf("/contract/update") === -1) {
this.$message({type: 'info', message: "没有权限!"});
return;
}
for (let k in r) {
this.form[k] = r[k];
}
this.visible = true;
this.title = "更新合同";
},
//修改表单提交
submit() {
this.$refs.form.validate((valid) => {
if (valid) {
this.editLoading = true;
//NProgress.start();
let para = Object.assign({}, this.form);
if (this.form.id) {
this.$http.post("/contract/update", para).then((res) => {
this.editLoading = false;
//NProgress.done();
if (res.data.success) {
this.$message({
message: '提交成功',
type: 'success'
});
} else {
this.$message({
message: res.data.msg,
type: 'error'
});
}
this.$refs['form'].resetFields();
this.visible = false;
this.loadContractList();
});
}
else {
this.$http.put("/contract/save", para).then((res) => {
this.editLoading = false;
//NProgress.done();
if (res.data.success) {
this.$message({
message: '提交成功',
type: 'success'
});
} else {
this.$message({
message: res.data.msg,
type: 'error'
});
}
this.$refs['form'].resetFields();
this.visible = false;
this.loadContractList();
});
}
}
});
},
//生成保单
createContract(i, r) {
if (this.currentPermissions.indexOf("/contract/createRepair") === -1) {
this.$message({type: 'info', message: "没有权限!"});
return;
}
this.$http.post("/contract/createRepair", r).then((res) => {
if (res.data.success) {
this.$message({
message: '生成保单成功!' + res.data.msg,
type: 'success'
});
} else {
this.$message({
message: res.data.msg,
type: 'error'
});
}
this.loadOrderList();
});
},
//搜索框
searchSubmit() {
this.loadContractList();
},
//详情增加按钮
insertEvent(row) {
let contractDetail = {
id: null,
mony: "",
scale: "",
payTime: "",
payment: true
};
this.form.contractDetails.push(contractDetail);
},
//详情金额改变事件
monyChange() {
let contractDetails = this.form.contractDetails;
var mony = 0.00;
for (let i = 0; i < contractDetails.length; i++) {
mony += parseFloat(contractDetails[i].mony);
}
for (let i = 0; i < this.form.contractDetails.length; i++) {
this.form.contractDetails[i].scale = parseFloat(contractDetails[i].mony) / mony * 100;
}
},
//详情删除按钮
deleteRow(index, rows) {
rows.splice(index, 1);
}
},
mounted() {
//当页面加载完毕的时候发送ajax请求
this.loadContractList();
}
}
</script>
<style scoped>
</style>
3.1.2 controller
package com.cl.crm.web.controller;
import com.cl.base.util.AjaxResult;
import com.cl.crm.domain.Contract;
import com.cl.crm.query.ContractQuery;
import com.cl.crm.service.IContractService;
import com.cl.crm.shiro.util.UserContext;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Controller
@RequestMapping("/contract")
@CrossOrigin
public class ContractController {
@Autowired
private IContractService contractService;
/**
* resetful: 它是一个架构风格,它是基于Http协议的扩展
* 它给你提供了多种请求方式来定位资源
* GET 一般是用来做查询的,查询单个对象
* POST 一般用来做修改的
* DELETE 一般用来做删除
* PUT 一般用来做新增
* PATCH 一般用来操作批量数据的
* @return
*/
@RequestMapping(value = "/list",method = RequestMethod.PATCH)
@ResponseBody
public List<Contract> list(){
return contractService.selectAll();
}
/**
* 条件查询
* @param query
* @return
*/
@RequestMapping(value = "/selectByQuery",method = RequestMethod.PATCH)
@ResponseBody
public List<Contract> selectByQuery(@RequestBody ContractQuery query){
query.setTenantId(UserContext.getEmployee().getTenantId());
return contractService.selectByQuery(query);
}
/**
* 条件分页查询
* @param query
* @return
*/
@RequestMapping(value = "/selectPageByQuery",method = RequestMethod.PATCH)
@ResponseBody
public PageInfo<Contract> selectPageByQuery(@RequestBody ContractQuery query){
query.setTenantId(UserContext.getEmployee().getTenantId());
return contractService.selectPageByQuery(query);
}
/**
* 添加部门
* @param contract
* @return
*
* @RequestBody:前端传递json对象,它会自动转为Contract对象
*
*/
@RequestMapping(value = "/save",method = RequestMethod.PUT)
@ResponseBody
public AjaxResult save(@RequestBody Contract contract){
try {
contractService.insert(contract);
return new AjaxResult();
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult(false, "添加失败!"+e.getMessage());
}
}
/**
* 合同修改
* @param contract
* @return
*/
@RequestMapping(value = "/update",method = RequestMethod.POST)
@ResponseBody
public AjaxResult update(@RequestBody Contract contract){
try {
contractService.update(contract);
return new AjaxResult();
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult(false, "修改失败!"+e.getMessage());
}
}
/**
* 合同生成保单
* @param contract
* @return
*/
@RequestMapping(value = "/createRepair",method = RequestMethod.POST)
@ResponseBody
public AjaxResult createRepair(@RequestBody Contract contract){
try {
Long repairSn = contractService.createRepair(contract);
return new AjaxResult(true,"合同编号"+repairSn);
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult(false, "修改失败!"+e.getMessage());
}
}
/**
* 删除
* @param id
* @return
*/
@RequestMapping(value = "/delete/{id}",method = RequestMethod.DELETE)
@ResponseBody
public AjaxResult delete(@PathVariable("id") Long id){
try {
contractService.delete(id);
return new AjaxResult();
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult(false, "删除失败!"+e.getMessage());
}
}
/**
* 批量删除
* @param contracts
* @return
*/
@RequestMapping(value = "/batchDelete",method = RequestMethod.PATCH)
@ResponseBody
public AjaxResult batchDelete(@RequestBody List<Contract> contracts){
try {
contractService.batchDelete(contracts);
return new AjaxResult();
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult(false, "删除失败!"+e.getMessage());
}
}
/**
* 查询单个对象
* @param id
* @return
*/
@RequestMapping(value = "/get/{id}",method = RequestMethod.GET)
@ResponseBody
public Contract get(@PathVariable("id") Long id){
return contractService.selectById(id);
}
}
3.1.3 service接口
public interface IContractService extends IBaseService<Contract,Long> {
Long createRepair(Contract contract);
}
3.1.3.1 serviceImpl
@Service
public class ContractServiceImpl extends BaseServiceImpl<Contract,Long> implements IContractService {
//注入合同mapper
@Autowired
private ContractMapper contractMapper;
//注入合同详情mapper
@Autowired
private ContractDetailMapper contractDetailMapper;
//注入订单mapper
@Autowired
private OrderMapper orderMapper;
//注入保单mapper
@Autowired
private RepairMapper repairMapper;
@Override
public BaseMapper<Contract, Long> baseMapper() {
return contractMapper;
}
@Override
public void update(Contract contract) {
//删除合同详情
contractDetailMapper.deleteByContractId(contract.getId());
//获取详情列表
List<ContractDetail> contractDetails = contract.getContractDetails();
//判断详情是否为空
if (contractDetails.size()>0) {
//不为空则计算总金额
BigDecimal sumMony = new BigDecimal(0.00);
//不为空则计算总付款金额
BigDecimal paid = new BigDecimal(0.00);
//不为空则计算总未付款金额
BigDecimal unpaid = new BigDecimal(0.00);
for (ContractDetail c:contractDetails) {
sumMony = sumMony.add(c.getMony());
if (c.getPayment()){
paid = paid.add(c.getMony());
} else {
unpaid = unpaid.add(c.getMony());
}
}
//设置总金额
contract.setSum(sumMony);
//设置付款金额
contract.setPaid(paid);
//设置未付款金额
contract.setUnpaid(unpaid);
//插入合同详情
contractDetailMapper.batchInsert(contract.getId(), contract.getContractDetails());
}
//修改合同
super.update(contract);
}
@Override
public void delete(Long id) {
//根据id获取合同
Contract contract = contractMapper.selectById(id);
//根据合同获取订单
Order order = orderMapper.selectById(contract.getOrder().getId());
//将订单设置为未付款
order.setStatus(0);
//将变更保存到数据库
orderMapper.update(order);
//删除合同详情
contractDetailMapper.deleteByContractId(id);
super.delete(id);
}
@Override
public void batchDelete(List<Contract> contracts) {
contracts.forEach(c->{
//根据合同获取订单
Order order = orderMapper.selectById(c.getOrder().getId());
//将订单设置为未付款
order.setStatus(0);
//将变更保存到数据库
orderMapper.update(order);
//删除合同详情
contractDetailMapper.deleteByContractId(c.getId());
});
super.batchDelete(contracts);
}
@Override
public Long createRepair(Contract contract) {
//new保单对象
Repair repair = new Repair();
//设置保单客户
repair.setCustomer(contract.getCustomer());
//设置保单sn
repair.setSn(contract.getSn());
//设置合同
repair.setContract(contract);
//设置租户
repair.setTenantId(contract.getTenantId());
//保存保单
repairMapper.insert(repair);
return repair.getSn();
}
}
3.1.4 mapper接口
ContractMapper
public interface ContractMapper extends BaseMapper<Contract,Long> {
}
ContractDetailMapper
public interface ContractDetailMapper extends BaseMapper<ContractDetail,Long> {
List<ContractDetail> selectByContractId(Long contractId);
void deleteByContractId(Long contractId);
void batchInsert(@Param("contractId") Long contractId, @Param("contractDetails")List<ContractDetail> contractDetails);
}
3.1.5 mapper.xml
ContractMapper.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.cl.crm.mapper.ContractMapper">
<resultMap id="sqlMap" type="Contract">
<id column="id" property="id"/>
<result column="sn" property="sn"/>
<result column="signTime" property="signTime"/>
<result column="sum" property="sum"/>
<result column="paid" property="paid"/>
<result column="unpaid" property="unpaid"/>
<result column="intro" property="intro"/>
<result column="tenantId" property="tenantId"/>
<association property="customer" javaType="Customer">
<id column="cuid" property="id"/>
<result column="cuname" property="name"/>
</association>
<association property="seller" javaType="Employee">
<id column="eid" property="id"/>
<result column="erealName" property="realName"/>
</association>
<association property="order" javaType="Order">
<id column="oid" property="id"/>
<result column="osn" property="sn"/>
</association>
<collection property="contractDetails" ofType="ContractDetail"
column="id" select="com.cl.crm.mapper.ContractDetailMapper.selectByContractId"/>
</resultMap>
<sql id="column">
c.id,
c.sn,
c.customer_id,
c.order_id,
c.signTime,
c.seller_id,
c.sum,
c.paid,
c.unpaid,
c.intro,
c.tenant_id AS tenantId,
cu.id AS cuid,
cu.name AS cuname,
o.id AS oid,
o.sn AS osn,
e.id AS eid,
e.realName AS erealName
</sql>
<insert id="insert" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
INSERT INTO t_contract(
sn,customer_id,order_id,signTime,seller_id,sum,paid,unpaid,intro,tenant_id
) VALUES (
#{sn},
#{customer.id},
#{order.id},
#{signTime},
#{seller.id},
#{sum},
#{paid},
#{unpaid},
#{intro},
#{tenantId}
)
</insert>
<delete id="delete">
UPDATE t_contract set mark =FALSE WHERE id=#{id}
</delete>
<delete id="batchDelete">
UPDATE t_contract set mark =FALSE WHERE id IN
<foreach collection="list" open="(" close=")" item="item" separator=",">
#{item.id}
</foreach>
</delete>
<update id="update">
update t_contract
<set>
<if test="sn!=null">
sn = #{sn},
</if>
<if test="customer!=null and customer.id!=null">
customer_id = #{customer.id},
</if>
<if test="order!=null and order.id!=null">
order_id = #{order.id},
</if>
<if test="signTime!=null">
signTime = #{signTime},
</if>
<if test="seller!=null and seller.id!=null">
seller_id = #{seller.id},
</if>
<if test="sum!=null">
sum = #{sum},
</if>
<if test="paid!=null">
paid = #{paid},
</if>
<if test="unpaid!=null">
unpaid = #{unpaid},
</if>
<if test="intro!=null and intro!=''">
intro = #{intro},
</if>
</set>
where id = #{id}
</update>
<select id="selectById" resultMap="sqlMap">
SELECT
<include refid="column"/>
FROM t_contract c
LEFT JOIN t_customer cu ON c.customer_id = cu.id
LEFT JOIN t_employee e ON c.seller_id = e.id
LEFT JOIN t_order o ON c.order_id = o.id
WHERE c.id=#{id} AND c.mark=b'1'
</select>
<select id="selectAll" resultMap="sqlMap">
SELECT
<include refid="column"/>
FROM t_contract c
LEFT JOIN t_customer cu ON c.customer_id = cu.id
LEFT JOIN t_employee e ON c.seller_id = e.id
LEFT JOIN t_order o ON c.order_id = o.id
WHERE c.mark=b'1'
</select>
<select id="selectByQuery" resultMap="sqlMap">
SELECT
<include refid="column"/>
FROM t_contract c
LEFT JOIN t_customer cu ON c.customer_id = cu.id
LEFT JOIN t_employee e ON c.seller_id = e.id
LEFT JOIN t_order o ON c.order_id = o.id
WHERE c.mark=b'1'
<if test="minSignTime!=null">
AND c.signTime >= #{minSignTime}
</if>
<if test="tenantId!=null">
AND c.tenant_id = #{tenantId}
</if>
<if test="maxSignTime!=null">
AND c.signTime <![CDATA[<]]> #{maxSignTime}
</if>
<if test="unpaid!=null">
AND c.unpaid >= #{unpaid}
</if>
</select>
</mapper>
3.3 保单管理
3.1.1 vue
<template xmlns:v-slot="http://www.w3.org/1999/XSL/Transform">
<div>
<!--查询的form表单-->
<el-form style="margin-top: 20px" :inline="true" :model="searchForm" class="demo-form-inline">
<el-form-item label="合同编号">
<el-input type="number" v-model="searchForm.contractSn" placeholder="合同编号"/>
</el-form-item>
<el-form-item label="到期时间">
<el-col :span="11">
<el-date-picker
v-model="searchForm.minDueToTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择日期">
</el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-date-picker
v-model="searchForm.maxDueToTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择日期">
</el-date-picker>
</el-col>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="searchSubmit">查询</el-button>
</el-form-item>
</el-form>
<!--批量删除-->
<el-button type="danger" style="float: left;margin-bottom:20px;margin-left: 20px" @click="batchRemove" :disabled="this.selectRows.length===0">批量删除</el-button>
<!--添加-->
<!--<el-button type="primary" style="float: left;margin-bottom:20px;" @click="add">新增</el-button>-->
<!--
:data 根据数据展示列表
@selection-change: 获取选中列表触发事件(返回的是选中的对象列表)
v-loading="loading" 值为true代表是加载效果
-->
<el-table
:data="tableData"
v-loading="loading"
style="width: 100%"
@selection-change="selectionChange"
>
<el-table-column type="selection" width="55">
</el-table-column>
<el-table-column type="index" label="序号" width="70px" sortable="true">
</el-table-column>
<el-table-column prop="sn" label="保单单号" sortable="true" ></el-table-column>
<el-table-column prop="contract.sn" label="合同单号" sortable="true" ></el-table-column>
<el-table-column prop="customer.name" label="保单客户" ></el-table-column>
<el-table-column prop="dueToTime" label="到期时间" ></el-table-column>
<!--操作-->
<el-table-column label="操作">
<template slot-scope="scope">
<el-button
size="small"
@click="handleEdit(scope.$index, scope.row)">编辑
</el-button>
<el-button
size="small"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<!--分页-->
<el-pagination style="margin-top: 10px;float: right"
@size-change="sizeChange"
@current-change="currentChange"
:current-page="currentPage"
:page-sizes="pageSizes"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
<!--修改、添加弹出框-->
<el-dialog :title="title" :visible.sync="visible" :close-on-click-modal="false">
<el-form :model="form" label-width="80px" :rules="formRules" ref="form">
<el-form-item label="保单号">
<el-input v-model="form.sn" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="到期时间">
<el-date-picker
v-model="form.dueToTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择日期">
</el-date-picker>
</el-form-item>
<!--可编辑表格-->
<h6 style="display: inline-block">保单详情</h6>
<vxe-button @click="insertEvent">插入</vxe-button>
<vxe-table
border
show-overflow
:data="form.repairDetails"
:edit-config="{trigger: 'click', mode: 'cell'}">
<vxe-table-column type="seq" width="60"></vxe-table-column>
<vxe-table-column field="repairDate" title="保修时间" :edit-render="{name: 'input'}">
<template v-slot:edit="{ row }">
<input type="date" v-model="row.repairDate" class="custom-input">
</template>
</vxe-table-column>
<vxe-table-column field="repairContent" title="保修内容" :edit-render="{name: 'input'}">
<template v-slot:edit="{ row }">
<el-input
type="textarea"
autosize
placeholder="请输入内容"
v-model="row.repairContent">
</el-input>
</template>
</vxe-table-column>
<vxe-table-column field="solve" title="是否解决" :edit-render="{name: 'radio'}">
<template v-slot:edit="{ row }">
<el-radio v-model="row.solve" label="true">true</el-radio>
<el-radio v-model="row.solve" label="false">false</el-radio>
</template>
</vxe-table-column>
<vxe-table-column title="操作">
<!--<template v-slot="{ row }">
<el-button @click="removeEvent(row)">移除</el-button>
</template>-->
<template slot-scope="scope">
<el-button
@click.native.prevent="deleteRow(scope.$index, form.repairDetails)"
type="text"
size="small">
移除
</el-button>
</template>
</vxe-table-column>
</vxe-table>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click.native="visible = false">取消</el-button>
<el-button type="primary" @click.native="submit" :loading="editLoading">提交</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'Repair',
data() {
return {
currentPermissions:[],
loading: true,
tableData: [],
selectRows: [],
customers:[],
//分页相关
//当前页
currentPage: 1,
//每页条数集合
pageSizes: [5, 10, 15, 20],
//每页条数
pageSize: 10,
//总数
total: 0,
//修改、增加相关
//是否可见
visible: false,
//标题
title: "",
//搜索条件form model
searchForm: {
contractSn:'',
minDueToTime:'',
maxDueToTime:''
},
//修改、新增form model
form: {
id: "",
sn: "",
customer:null,
dueToTime:'',
repairDetails:[]
},
formRules: {
name: [
{required: true, message: '请输入部门', trigger: 'blur'}
]
},
editLoading: false
};
},
methods: {
//详情增加按钮
insertEvent (row) {
let repairDetail ={
id: null,
repairContent: "",
repairDate: "",
solve: true
};
this.form.repairDetails.push(repairDetail);
},
//详情删除按钮
deleteRow(index, rows) {
rows.splice(index, 1);
},
//加载列表
loadRepairList() {
this.$http.patch("/allUserPermissions").then(res => {
this.currentPermissions=res.data;
});
//查询传递参数
let params = {
"currentPage": this.currentPage,
"pageSize": this.pageSize,
contractSn:this.searchForm.contractSn,
minDueToTime:this.searchForm.minDueToTime,
maxDueToTime:this.searchForm.maxDueToTime
};
this.loading = true;
this.$http.patch("/repair/selectPageByQuery", params).then(res => {
this.tableData = res.data.list;
this.total = res.data.total;
this.loading = false;
});
},
//多选
selectionChange(v) {
this.selectRows = v;
},
//每页条数改变
sizeChange(v) {
this.currentPage = 1;
this.pageSize = v;
this.loadRepairList();
//加载框
this.loading = true;
},
//当前页改变
currentChange(v) {
this.currentPage = v;
this.loadRepairList();
//加载框
this.loading = true
},
//删除一条数据
handleDelete(i, r) {
if(this.currentPermissions.indexOf("/repair/delete")===-1){
this.$message({type: 'info',message:"没有权限!"});return;
}
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http.delete("/repair/delete/" + r.id).then(res => {
if (res.data.success) {
this.$message({
type: 'success',
message: r.sn+"删除成功"
});
} else {
this.$message({
type: 'error',
message: res.data.msg
});
}
this.loadRepairList();
})
}).catch(() => {
});
},
//批量删除
batchRemove() {
if(this.currentPermissions.indexOf("/repair/batchDelete")===-1){
this.$message({type: 'info',message:"没有权限!"});return;
}
if (!this.selectRows.length) {
this.$message.error('亲!请选中数据进行删除哦!!');
return;
}
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http.patch("/repair/batchDelete", this.selectRows).then(res => {
if (res.data.success) {
if (res.data.success) {
this.$message({
type: 'success',
message: "共删除" + this.selectRows.length + "条数据"
});
} else {
this.$message({
type: 'error',
message: res.data.msg
});
}
this.loadRepairList();
}
})
}).catch(() => {
});
},
//新增
/*add() {
for (let k in this.form) {
this.form[k] = '';
}
this.visible = true;
this.title = "添加部门";
},*/
handleEdit(i, r) {
if(this.currentPermissions.indexOf("/repair/update")===-1){
this.$message({type: 'info',message:"没有权限!"});return;
}
for (let k in r) {
this.form[k] = r[k];
}
this.visible = true;
this.title = "更新部门";
},
submit() {
this.$refs.form.validate((valid) => {
if (valid) {
this.editLoading = true;
//NProgress.start();
let para = Object.assign({}, this.form);
if (this.form.id) {
console.log(para);
this.editLoading = false;
this.$http.post("/repair/update", para).then((res) => {
this.editLoading = false;
//NProgress.done();
if (res.data.success) {
this.$message({
message: '提交成功',
type: 'success'
});
} else {
this.$message({
message: res.data.msg,
type: 'error'
});
}
this.$refs['form'].resetFields();
this.visible = false;
this.loadRepairList();
});
}
/*else {
console.log(para);
this.$http.put("/repair/save", para).then((res) => {
this.editLoading = false;
//NProgress.done();
if (res.data.success) {
this.$message({
message: '提交成功',
type: 'success'
});
} else {
this.$message({
message: res.data.msg,
type: 'error'
});
}
this.$refs['form'].resetFields();
this.visible = false;
this.loadRepairList();
});
}*/
}
});
},
//搜索框
searchSubmit() {
this.loadRepairList();
}
},
mounted() {
//当页面加载完毕的时候发送ajax请求
this.loadRepairList();
}
}
</script>
<style scoped>
</style>
3.1.2 controller
package com.cl.crm.web.controller;
import com.cl.base.util.AjaxResult;
import com.cl.crm.domain.Repair;
import com.cl.crm.query.RepairQuery;
import com.cl.crm.service.IRepairService;
import com.cl.crm.shiro.util.UserContext;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Controller
@RequestMapping("/repair")
@CrossOrigin
public class RepairController {
@Autowired
private IRepairService repairService;
/**
* resetful: 它是一个架构风格,它是基于Http协议的扩展
* 它给你提供了多种请求方式来定位资源
* GET 一般是用来做查询的,查询单个对象
* POST 一般用来做修改的
* DELETE 一般用来做删除
* PUT 一般用来做新增
* PATCH 一般用来操作批量数据的
* @return
*/
@RequestMapping(value = "/list",method = RequestMethod.PATCH)
@ResponseBody
public List<Repair> list(){
return repairService.selectAll();
}
/**
* 条件查询
* @param query
* @return
*/
@RequestMapping(value = "/selectByQuery",method = RequestMethod.PATCH)
@ResponseBody
public List<Repair> selectByQuery(@RequestBody RepairQuery query){
query.setTenantId(UserContext.getEmployee().getTenantId());
return repairService.selectByQuery(query);
}
/**
* 条件分页查询
* @param query
* @return
*/
@RequestMapping(value = "/selectPageByQuery",method = RequestMethod.PATCH)
@ResponseBody
public PageInfo<Repair> selectPageByQuery(@RequestBody RepairQuery query){
System.out.println(UserContext.getEmployee());
query.setTenantId(UserContext.getEmployee().getTenantId());
return repairService.selectPageByQuery(query);
}
/**
* 添加部门
* @param repair
* @return
*
* @RequestBody:前端传递json对象,它会自动转为Repair对象
*
*/
@RequestMapping(value = "/save",method = RequestMethod.PUT)
@ResponseBody
public AjaxResult save(@RequestBody Repair repair){
try {
repairService.insert(repair);
return new AjaxResult();
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult(false, "添加失败!"+e.getMessage());
}
}
@RequestMapping(value = "/update",method = RequestMethod.POST)
@ResponseBody
public AjaxResult update(@RequestBody Repair repair){
try {
repairService.update(repair);
return new AjaxResult();
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult(false, "修改失败!"+e.getMessage());
}
}
/**
* 删除
* @param id
* @return
*/
@RequestMapping(value = "/delete/{id}",method = RequestMethod.DELETE)
@ResponseBody
public AjaxResult delete(@PathVariable("id") Long id){
try {
repairService.delete(id);
return new AjaxResult();
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult(false, "删除失败!"+e.getMessage());
}
}
/**
* 批量删除
* @param repairs
* @return
*/
@RequestMapping(value = "/batchDelete",method = RequestMethod.PATCH)
@ResponseBody
public AjaxResult batchDelete(@RequestBody List<Repair> repairs){
try {
repairService.batchDelete(repairs);
return new AjaxResult();
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult(false, "删除失败!"+e.getMessage());
}
}
/**
* 查询单个对象
* @param id
* @return
*/
@RequestMapping(value = "/get/{id}",method = RequestMethod.GET)
@ResponseBody
public Repair get(@PathVariable("id") Long id){
return repairService.selectById(id);
}
}
3.1.3 service接口
public interface IRepairService extends IBaseService<Repair,Long> {
}
3.1.3.1 serviceImpl
@Service
public class RepairServiceImpl extends BaseServiceImpl<Repair,Long> implements IRepairService {
@Autowired
private RepairMapper repairMapper;
@Autowired
private RepairDetailMapper repairDetailMapper;
@Override
public BaseMapper<Repair, Long> baseMapper() {
return repairMapper;
}
@Override
public void update(Repair repair) {
//删除订单详情
repairDetailMapper.deleteByRepairId(repair.getId());
super.update(repair);
//获取订单详情
System.out.println(repair.getRepairDetails());
if (repair.getRepairDetails().size()>0) {
//保存订单详情
repairDetailMapper.batchInsert(repair.getId(), repair.getRepairDetails());
}
}
@Override
public void delete(Long id) {
//删除订单详情
repairDetailMapper.deleteByRepairId(id);
super.delete(id);
}
@Override
public void batchDelete(List<Repair> repairs) {
repairs.forEach(r->{
repairDetailMapper.deleteByRepairId(r.getId());
});
super.batchDelete(repairs);
}
}
3.1.4 mapper接口
repairMapper
public interface RepairMapper extends BaseMapper<Repair,Long> {
}
repairDetailMapper
public interface RepairDetailMapper extends BaseMapper<RepairDetail,Long> {
List<RepairDetail> selectByRepairId(Long repairId);
void deleteByRepairId(Long id);
void batchInsert(@Param("repairId") Long repairId,@Param("repairDetails") List<RepairDetail> repairDetails);
}
3.1.5 mapper.xml
repairMapper.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.cl.crm.mapper.RepairMapper">
<resultMap id="sqlMap" type="Repair">
<id column="id" property="id"/>
<result column="sn" property="sn"/>
<result column="dueToTime" property="dueToTime"/>
<result column="tenantId" property="tenantId"/>
<association property="customer" javaType="Customer">
<id column="cuid" property="id"/>
<result column="cuname" property="name"/>
</association>
<association property="contract" javaType="Contract">
<id column="cid" property="id"/>
<result column="csn" property="sn"/>
</association>
<collection property="repairDetails" ofType="RepairDetail"
column="id" select="com.cl.crm.mapper.RepairDetailMapper.selectByRepairId"/>
</resultMap>
<sql id="column">
r.id,
r.sn,
r.dueToTime,
r.tenant_id AS tenantId,
c.id AS cid,
c.sn AS csn,
cu.id AS cuid,
cu.name AS cuname
</sql>
<insert id="insert" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
INSERT INTO t_repair(sn,dueToTime,customer_id,tenant_id,contract_id)
VALUES (#{sn},#{dueToTime},#{customer.id},#{tenantId},#{contract.id})
</insert>
<delete id="delete">
UPDATE t_repair SET mark = FALSE WHERE id=#{id}
</delete>
<delete id="batchDelete">
UPDATE t_repair SET mark = FALSE WHERE id IN
<foreach collection="list" open="(" close=")" item="item" separator=",">
#{item.id}
</foreach>
</delete>
<update id="update">
update t_repair
<set>
<if test="sn!=null">
sn = #{sn},
</if>
<if test="dueToTime!=null">
dueToTime = #{dueToTime},
</if>
</set>
where id = #{id}
</update>
<select id="selectById" resultMap="sqlMap">
SELECT
<include refid="column"/>
FROM t_repair r
LEFT JOIN t_customer cu ON r.customer_id = cu.id
LEFT JOIN t_contract c ON r.contract_id = c.id
WHERE r.id=#{id} AND r.mark=b'1'
</select>
<select id="selectAll" resultMap="sqlMap">
SELECT
<include refid="column"/>
FROM t_repair r
LEFT JOIN t_customer cu ON r.customer_id = cu.id
LEFT JOIN t_contract c ON r.contract_id = c.id
WHERE r.mark=b'1'
</select>
<select id="selectByQuery" resultMap="sqlMap">
SELECT
<include refid="column"/>
FROM t_repair r
LEFT JOIN t_customer cu ON r.customer_id = cu.id
LEFT JOIN t_contract c ON r.contract_id = c.id
WHERE r.mark=b'1'
<if test="minDueToTime!=null">
AND r.dueToTime >= #{minDueToTime}
</if>
<if test="tenantId!=null">
AND r.tenant_id = #{tenantId}
</if>
<if test="maxDueToTime!=null">
AND r.dueToTime <![CDATA[<]]> #{maxDueToTime}
</if>
<if test="contractSn!=null and contractSn!=''">
AND c.sn LIKE CONCAT("%",#{contractSn},"%")
</if>
</select>
</mapper>
repairDetailMapper.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.cl.crm.mapper.RepairDetailMapper">
<resultMap id="sqlMap" type="RepairDetail">
<id column="id" property="id"/>
<result column="repairDate" property="repairDate"/>
<result column="repairContent" property="repairContent"/>
<result column="solve" property="solve"/>
</resultMap>
<sql id="column">
id,repairDate,repairContent,solve
</sql>
<insert id="insert" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
INSERT INTO t_repair_detail(repairDate,repairContent,solve)
VALUES (#{repairDate},#{repairContent},#{solve})
</insert>
<delete id="delete">
DELETE FROM t_repair_detail WHERE id=#{id}
</delete>
<delete id="deleteByRepairId">
DELETE FROM t_repair_detail WHERE repair_id=#{repairId}
</delete>
<delete id="batchDelete">
DELETE FROM t_repair_detail WHERE id IN
<foreach collection="list" open="(" close=")" item="item" separator=",">
#{item.id}
</foreach>
</delete>
<insert id="batchInsert">
INSERT INTO t_repair_detail(repairDate,repairContent,solve,repair_id) VALUES
<foreach collection="repairDetails" item="item" separator=",">
(#{item.repairDate},#{item.repairContent},#{item.solve},#{repairId})
</foreach>
</insert>
<update id="update">
update t_repair_detail
<set>
<if test="repairDate!=null">
repairDate = #{repairDate},
</if>
<if test="repairContent!=null and repairContent!=''">
repairContent = #{repairContent},
</if>
<if test="solve!=null">
solve = #{solve},
</if>
</set>
where id = #{id}
</update>
<select id="selectById" resultMap="sqlMap">
SELECT
<include refid="column"/>
FROM t_repair_detail WHERE id=#{id}
</select>
<select id="selectByRepairId" resultMap="sqlMap">
SELECT
<include refid="column"/>
FROM t_repair_detail WHERE repair_id=#{repairId}
</select>
<select id="selectAll" resultMap="sqlMap">
SELECT
<include refid="column"/>
FROM t_repair_detail
</select>
<select id="selectByQuery" resultMap="sqlMap">
SELECT
<include refid="column"/>
FROM t_repair_detail
<where>
<if test="solve!=null">
AND solve = #{solve}
</if>
<if test="minRepairDate!=null">
AND repairDate >= #{minRepairDate}
</if>
<if test="maxRepairDate!=null">
AND repairDate <![CDATA[<]]> #{maxRepairDate}
</if>
</where>
</select>
</mapper>
3.4 报表
3.4.1 vue
<template>
<div>
<!--<button @click="changeType">切换图表类型</button>-->
<el-form style="margin-top: 20px" :inline="true" :model="searchForm" class="demo-form-inline" >
<el-form-item label="年份">
<el-input type="number" maxlength="4" minlength="4" v-model="searchForm.year" placeholder="请输入有效的年份"/>
</el-form-item>
<el-form-item label="月份">
<el-select v-model="searchForm.month" placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="success" @click="searchSubmit">生成图表</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="changeType">切换图表类型</el-button>
</el-form-item>
</el-form>
<ve-chart :data="chartData" :settings="chartSettings"></ve-chart>
</div>
</template>
<script>
export default {
data () {
this.typeArr = ['line', 'histogram', 'pie']
this.index = 0
return {
chartData: {
columns: [],
rows: []
},
chartSettings: { type: this.typeArr[this.index] },
options: [{
value: '',
label: ''
},{
value: '0',
label: '一月'
}, {
value: '1',
label: '二月'
}, {
value: '2',
label: '三月'
}, {
value: '3',
label: '四月'
}, {
value: '4',
label: '五月'
}, {
value: '5',
label: '六月'
}, {
value: '6',
label: '七月'
}, {
value: '7',
label: '八月'
}, {
value: '8',
label: '九月'
}, {
value: '9',
label: '十月'
}, {
value: '10',
label: '十一月'
}, {
value: '11',
label: '十二月'
}],
searchForm:{
year:'',
month:''
}
}
},
methods: {
//加载列表
loadContractList() {
let year = this.searchForm.year;
let month = this.searchForm.month;
let date='1';
if (year!=null && year!=''){
date = year;
}
if (month!=null && month!=''){
date = year+"-"+month;
}
this.$http.patch("/echarts/contract/"+date).then(res => {
this.chartData.columns =['时间', '金额'];
let contracts = res.data;
for (let i = 0; i<contracts.length;i++){
let row = {
'时间':'',
'金额':''
};
if ((year!=null && year!=='' )&&( month==null || month==='')){
row.时间 = (parseInt(contracts[i].signTime)+1)+"月";
row.金额 = contracts[i].paid;
} else if (month!=null && month!==''){
row.时间 = contracts[i].signTime;
row.金额 = contracts[i].paid;
}else {
row.时间 = contracts[i].signTime+"年";
row.金额 = contracts[i].paid;
}
this.chartData.rows.push(row)
}
});
},
changeType: function () {
this.index++
if (this.index >= this.typeArr.length) { this.index = 0 }
this.chartSettings = { type: this.typeArr[this.index] }
},
searchSubmit:function () {
this.chartData = {
columns: [],
rows: []
}
this.loadContractList();
}
},
mounted() {
//当页面加载完毕的时候发送ajax请求
this.loadContractList();
}
}
</script>
<style scoped>
</style>
3.4.2 controller
package com.cl.crm.web.controller;
import com.cl.crm.domain.Contract;
import com.cl.crm.query.ContractQuery;
import com.cl.crm.service.IContractService;
import com.cl.crm.shiro.util.UserContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.*;
@Controller
@RequestMapping("/echarts")
@CrossOrigin
public class EChartsController {
@Autowired
private IContractService contractService;
@RequestMapping(value = "/contract/{date}", method = RequestMethod.PATCH)
@ResponseBody
public List<Map<String, String>> contract(@PathVariable("date") String date) {
Calendar calendar = Calendar.getInstance();
Calendar calendar2 = Calendar.getInstance();
//String year = String.valueOf(date.get(Calendar.YEAR));
//新建查询对象
ContractQuery query = new ContractQuery();
//设置租户对象
query.setTenantId(UserContext.getEmployee().getTenantId());
//获取查询结果
List<Contract> list = contractService.selectByQuery(query);
List<Map<String, String>> list2 = new ArrayList<>();
if (date.length() == 1) {
C:
for (Contract contract : list) {
calendar.setTime(contract.getSignTime());
String year = String.valueOf(calendar.get(Calendar.YEAR));
C2:
for (Map<String, String> map : list2) {
if (map.get("signTime").equals(year)) {
float paid = Float.parseFloat(map.get("paid")) + contract.getPaid().intValue();
map.put("paid", paid + "");
continue C;
}
}
Map<String, String> map = new HashMap<>();
map.put("signTime", year);
map.put("paid", contract.getPaid() + "");
list2.add(map);
}
} else if (date.length() == 4) {
C:
for (Contract contract : list) {
calendar.setTime(contract.getSignTime());
String year = String.valueOf(calendar.get(Calendar.YEAR));
String month = String.valueOf(calendar.get(Calendar.MONTH));
if (date.equals(year)) {
C2: for (Map<String, String> map : list2) {
if (map.get("signTime").equals(month)) {
float paid = Float.parseFloat(map.get("paid")) + contract.getPaid().intValue();
map.put("paid", paid + "");
continue C;
}
}
Map<String, String> map = new HashMap<>();
map.put("signTime", month);
map.put("paid", contract.getPaid() + "");
list2.add(map);
}
}
} else {
C:
for (Contract contract : list) {
calendar.setTime(contract.getSignTime());
String day = String.valueOf(calendar.get(Calendar.DATE));
String year = String.valueOf(calendar.get(Calendar.YEAR));
String month = String.valueOf(calendar.get(Calendar.MONTH));
String date2 = year + "-" + month;
if (date.equals(date2)) {
C2: for (Map<String, String> map : list2) {
if (map.get("signTime").equals(day)) {
float paid = Float.parseFloat(map.get("paid")) + contract.getPaid().intValue();
map.put("paid", paid + "");
continue C;
}
}
Map<String, String> map = new HashMap<>();
map.put("signTime", day);
map.put("paid", contract.getPaid() + "");
list2.add(map);
}
}
}
Collections.sort(list2, new Comparator<Map<String, String>>() {
@Override
public int compare(Map<String, String> o1, Map<String, String> o2) {
// 根据日期进行排序
int paid1 = Integer.parseInt(o1.get("signTime"));
int paid2 = Integer.parseInt(o2.get("signTime"));
return paid1-paid2;
}
});
return list2;
}
}
3.5 动态菜单
3.5.1 home.vue
...
<!--导航菜单-->
<el-menu :default-active="$route.path" class="el-menu-vertical-demo" @open="handleopen" @close="handleclose" @select="handleselect"
unique-opened router v-show="!collapsed">
<template v-for="(item,index) in $router.options.routes" v-if="!item.hidden">
<div v-for="menu in menuData">
<div v-if="item.name === menu.name">
<el-submenu :index="index+''" v-if="!item.leaf">
<template slot="title"><i :class="item.iconCls"></i>{{item.name}}</template>
<div v-for="child in item.children">
<div v-for="menu in menuData">
<div v-if="child.name === menu.name">
<el-menu-item :index="child.path"
:key="child.path"
v-if="!child.hidden">
{{child.name}}
</el-menu-item>
</div>
</div>
</div>
</el-submenu>
</div>
</div>
<div v-for="menu in menuData">
<div v-if="item.children[0].name === menu.name">
<el-menu-item v-if="item.leaf&&item.children.length>0"
:index="item.children[0].path"><i
:class="item.iconCls"></i>{{item.children[0].name}}
</el-menu-item>
</div>
</div>
</template>
</el-menu>
...
<script>
...
return{
menuData:[],
}
method:{
getMenus(){
this.$http.patch("/menu/selectByEmployeeId").then(res => {
this.menuData = res.data;
});
},
}
...
</script>
3.5.2 后台代码
MenuController.java
@RequestMapping(value = "/selectByEmployeeId",method = RequestMethod.PATCH)
@ResponseBody
public List<Menu> selectByEmployeeId(){
Long employeeId = UserContext.getEmployee().getId();
return iMenuService.selectByEmployeeId(employeeId);
}
......
MenuMapper.xml
<select id="selectByEmployeeId" resultType="Menu">
SELECT DISTINCT m.* FROM t_employee e
JOIN t_emp_role er ON er.emp_id= e.id
JOIN t_role r ON r.id = er.role_id
JOIN t_permission_role pr ON pr.role_id = r.id
JOIN t_permission p ON p.id=pr.permission_id
JOIN t_menu m ON m.id = p.menu_id
WHERE e.id = #{employeeId}
</select>
四、难点和错误总结
- 业务逻辑需要理清楚才能开始;
- 第三方登录集成失败;
- 动态菜单逻辑判断;
- 报表数据组装;
更多推荐
所有评论(0)