300rmb掏了个java+vue2的小系统,学习代码,调整下申请流程。
原有的入库流程是,库管(admin)提出采购申请给采购员(caigou),采购员采购入库时点击入库完成采购入库流程。
想弄清后端代码怎样流转申请?需要一点点找。
从vue的采购申请页面找到请求的后端api地址:
采购申请页面vue路由是:
/admin/rurchase
对应的组件是:
admin/rurchase/Rurchase
对应的vue代码地址是:
src\views\admin\rurchase\RurchaseAdd.vue
<template>
<a-drawer
title="新增采购申请"
:maskClosable="false"
placement="right"
:closable="false"
:visible="show"
:width="1200"
@close="onClose"
style="height: calc(100% - 55px);overflow: auto;padding-bottom: 53px;"
>
<a-form :form="form" layout="vertical">
<a-row :gutter="20">
<a-col :span="12">
<a-form-item label='申请人' v-bind="formItemLayout">
<a-input v-decorator="[
'applicant',
{ rules: [{ required: true, message: '请输入申请人!' }] }
]"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label='备注消息' v-bind="formItemLayout">
<a-textarea :rows="4" v-decorator="[
'content',
{ rules: [{ required: true, message: '请输入备注消息!' }] }
]"/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-table :columns="columns" :data-source="dataList">
<template slot="nameShow" slot-scope="text, record">
<a-input v-model="record.name"></a-input>
</template>
<template slot="typeShow" slot-scope="text, record">
<a-input v-model="record.type"></a-input>
</template>
<template slot="typeIdShow" slot-scope="text, record">
<a-select v-model="record.typeId" style="width: 100%">
<a-select-option v-for="(item, index) in consumableType" :value="item.id" :key="index">{{ item.name }}</a-select-option>
</a-select>
</template>
<template slot="unitShow" slot-scope="text, record">
<a-input v-model="record.unit"></a-input>
</template>
<template slot="amountShow" slot-scope="text, record">
<a-input-number v-model="record.amount" :min="1" :step="1"/>
</template>
<template slot="priceShow" slot-scope="text, record">
<a-input-number v-model="record.price" :min="1"/>
</template>
</a-table>
<a-button @click="dataAdd" type="primary" ghost size="large" style="margin-top: 10px;width: 100%">
新增物品
</a-button>
</a-col>
</a-row>
</a-form>
<div class="drawer-bootom-button">
<a-popconfirm title="确定放弃编辑?" @confirm="onClose" okText="确定" cancelText="取消">
<a-button style="margin-right: .8rem">取消</a-button>
</a-popconfirm>
<a-button @click="handleSubmit" type="primary" :loading="loading">提交</a-button>
</div>
</a-drawer>
</template>
<script>
import {mapState} from 'vuex'
const formItemLayout = {
labelCol: { span: 24 },
wrapperCol: { span: 24 }
}
export default {
name: 'RurchaseAdd',
props: {
rurchaseAddVisiable: {
default: false
}
},
computed: {
...mapState({
currentUser: state => state.account.user
}),
show: {
get: function () {
return this.rurchaseAddVisiable
},
set: function () {
}
},
columns () {
return [{
title: '物品名称',
dataIndex: 'name',
scopedSlots: {customRender: 'nameShow'}
}, {
title: '型号',
dataIndex: 'type',
scopedSlots: {customRender: 'typeShow'}
}, {
title: '数量',
dataIndex: 'amount',
scopedSlots: {customRender: 'amountShow'}
}, {
title: '所属类型',
dataIndex: 'typeId',
width: 200,
scopedSlots: {customRender: 'typeIdShow'}
}, {
title: '单位',
dataIndex: 'unit',
scopedSlots: {customRender: 'unitShow'}
}, {
title: '单价',
dataIndex: 'price',
scopedSlots: {customRender: 'priceShow'}
}]
}
},
data () {
return {
formItemLayout,
form: this.$form.createForm(this),
loading: false,
dataList: [],
consumableType: []
}
},
mounted () {
this.getConsumableType()
},
methods: {
getConsumableType () {
this.$get('/cos/consumable-type/list').then((r) => {
this.consumableType = r.data.data
})
},
dataAdd () {
this.dataList.push({name: '', type: '', typeId: '', unit: '', amount: '', price: ''})
},
reset () {
this.loading = false
this.form.resetFields()
},
onClose () {
this.reset()
this.$emit('close')
},
handleSubmit () {
if (this.dataList.length !== 0) {
let price = 0
this.dataList.forEach(item => {
price += item.price * item.amount
})
this.form.validateFields((err, values) => {
if (!err) {
values.price = price
values.goods = JSON.stringify(this.dataList)
this.loading = true
this.$post('/cos/rurchase-request', {
...values
}).then((r) => {
this.reset()
this.$emit('success')
}).catch(() => {
this.loading = false
})
}
})
} else {
this.$message.warning('请添加记录!')
}
}
}
}
</script>
<style scoped>
</style>
在前端代码中找到提交申请的后台api接口地址是:
/cos/rurchase-request
根据后台接口地址找到对应的java controller类和方法:
cc.mrbird.febs.cos.controller.RurchaseRequestController#save
这里用到了RESTfultool插件
package cc.mrbird.febs.cos.controller;
import cc.mrbird.febs.common.utils.R;
import cc.mrbird.febs.cos.entity.RurchaseRequest;
import cc.mrbird.febs.cos.service.IRurchaseRequestService;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
/**
* @author FanK
*/
@RestController
@RequestMapping("/cos/rurchase-request")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class RurchaseRequestController {
private final IRurchaseRequestService rurchaseRequestService;
/**
* 采购申请入库
* @param rurchaseRequest
* @return
*/
@PostMapping("/rurchasePut")
public R rurchasePut(RurchaseRequest rurchaseRequest) {
return R.ok(rurchaseRequestService.rurchasePut(rurchaseRequest));
}
/**
* 分页获取采购申请
* @param page
* @param rurchaseRequest
* @return
*/
@GetMapping("/page")
public R page(Page page, RurchaseRequest rurchaseRequest) {
return R.ok(rurchaseRequestService.rurchaseRequestByPage(page, rurchaseRequest));
}
/**
* 添加采购申请
* @param rurchaseRequest
* @return
*/
@PostMapping
public R save(RurchaseRequest rurchaseRequest) {
rurchaseRequest.setCreateDate(DateUtil.formatDateTime(new Date()));
return R.ok(rurchaseRequestService.rurchaseRequestAdd(rurchaseRequest));
}
/**
* 修改采购申请
* @param rurchaseRequest
* @return
*/
@PutMapping
public R edit(RurchaseRequest rurchaseRequest) {
return R.ok(rurchaseRequestService.updateById(rurchaseRequest));
}
/**
* 删除采购申请
* @param ids
* @return
*/
@DeleteMapping("/{ids}")
public R deleteByIds(@PathVariable("ids") List<Integer> ids) {
return R.ok(rurchaseRequestService.removeByIds(ids));
}
}
通过其调用的函数:
rurchaseRequestService.rurchaseRequestAdd(rurchaseRequest)
mybatis的mapper
cc.mrbird.febs.cos.service.IRurchaseRequestService
package cc.mrbird.febs.cos.service;
import cc.mrbird.febs.cos.entity.RurchaseRequest;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import org.apache.ibatis.annotations.Param;
import java.util.LinkedHashMap;
/**
* @author FanK
*/
public interface IRurchaseRequestService extends IService<RurchaseRequest> {
// 分页获取采购申请
IPage<LinkedHashMap<String, Object>> rurchaseRequestByPage(Page page, RurchaseRequest rurchaseRequest);
// 添加采购申请
Boolean rurchaseRequestAdd(RurchaseRequest rurchaseRequest);
// 采购申请入库
Boolean rurchasePut(RurchaseRequest rurchaseRequest);
}
IRurchaseRequestService的实现类:
cc.mrbird.febs.cos.service.impl.RurchaseRequestServiceImpl
package cc.mrbird.febs.cos.service.impl;
import cc.mrbird.febs.cos.entity.GoodsBelong;
import cc.mrbird.febs.cos.entity.RurchaseRequest;
import cc.mrbird.febs.cos.dao.RurchaseRequestMapper;
import cc.mrbird.febs.cos.entity.StockInfo;
import cc.mrbird.febs.cos.entity.StockPut;
import cc.mrbird.febs.cos.service.IGoodsBelongService;
import cc.mrbird.febs.cos.service.IRurchaseRequestService;
import cc.mrbird.febs.cos.service.IStockInfoService;
import cc.mrbird.febs.cos.service.IStockPutService;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
/**
* @author FanK
*/
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class RurchaseRequestServiceImpl extends ServiceImpl<RurchaseRequestMapper, RurchaseRequest> implements IRurchaseRequestService {
private final IGoodsBelongService goodsBelongService;
private final IStockPutService stockPutService;
private final IStockInfoService stockInfoService;
@Override
public IPage<LinkedHashMap<String, Object>> rurchaseRequestByPage(Page page, RurchaseRequest rurchaseRequest) {
return baseMapper.rurchaseRequestByPage(page, rurchaseRequest);
}
@Override
public Boolean rurchaseRequestAdd(RurchaseRequest rurchaseRequest) {
rurchaseRequest.setNum("RUR-"+new Date().getTime());
JSONArray array = JSONUtil.parseArray(rurchaseRequest.getGoods());
List<GoodsBelong> goodsBelongList = JSONUtil.toList(array, GoodsBelong.class);
rurchaseRequest.setStep(0);
this.save(rurchaseRequest);
goodsBelongList.forEach(item -> {
item.setCreateDate(DateUtil.formatDateTime(new Date()));
item.setNum(rurchaseRequest.getNum());
});
return goodsBelongService.saveBatch(goodsBelongList);
}
@Override
public Boolean rurchasePut(RurchaseRequest rurchaseRequest) {
JSONArray array = JSONUtil.parseArray(rurchaseRequest.getGoods());
List<GoodsBelong> goodsBelongList = JSONUtil.toList(array, GoodsBelong.class);
// 添加入库单
StockPut stockPut = new StockPut();
stockPut.setContent(rurchaseRequest.getRurchaseContent());
stockPut.setCreateDate(DateUtil.formatDateTime(new Date()));
stockPut.setCustodian(rurchaseRequest.getCustodian());
stockPut.setPutUser(rurchaseRequest.getPutUser());
stockPut.setPrice(rurchaseRequest.getPrice());
stockPut.setNum("PUT-"+new Date().getTime());
stockPutService.save(stockPut);
goodsBelongList.forEach(item -> {
item.setCreateDate(DateUtil.formatDateTime(new Date()));
item.setNum(stockPut.getNum());
// 判断库房物品是否存在
StockInfo stockInfo = stockInfoService.getOne(Wrappers.<StockInfo>lambdaQuery().eq(StockInfo::getName, item.getName()).eq(StockInfo::getTypeId, item.getTypeId()).eq(StockInfo::getIsIn, 0));
if (stockInfo != null) {
// 更改库房数据
stockInfoService.update(Wrappers.<StockInfo>lambdaUpdate().set(StockInfo::getAmount, stockInfo.getAmount()+item.getAmount())
.set(StockInfo::getPrice, stockInfo.getPrice())
.eq(StockInfo::getName, stockInfo.getName()));
} else {
// 重新添加库房数据
StockInfo stock = new StockInfo();
stock.setName(item.getName());
stock.setAmount(item.getAmount());
stock.setCreateDate(DateUtil.formatDateTime(new Date()));
stock.setType(item.getType());
stock.setTypeId(item.getTypeId());
stock.setUnit(item.getUnit());
stock.setPrice(item.getPrice());
stock.setIsIn(0);
stockInfo = stock;
stockInfoService.save(stock);
}
// 添加入库记录
StockInfo stockInfoPut = new StockInfo();
stockInfoPut.setParentId(stockInfo.getId());
stockInfoPut.setName(item.getName());
stockInfoPut.setAmount(item.getAmount());
stockInfoPut.setCreateDate(DateUtil.formatDateTime(new Date()));
stockInfoPut.setType(item.getType());
stockInfoPut.setTypeId(item.getTypeId());
stockInfoPut.setUnit(item.getUnit());
stockInfoPut.setPrice(item.getPrice());
stockInfoPut.setIsIn(1);
stockInfoService.save(stockInfoPut);
// 添加所属信息
GoodsBelong goodsBelong = new GoodsBelong();
goodsBelong.setNum(stockPut.getNum());
goodsBelong.setCreateDate(DateUtil.formatDateTime(new Date()));
goodsBelong.setAmount(item.getAmount());
goodsBelong.setName(item.getName());
goodsBelong.setPrice(item.getPrice());
goodsBelong.setType(item.getType());
goodsBelong.setTypeId(item.getTypeId());
goodsBelong.setUnit(item.getUnit());
goodsBelongService.save(goodsBelong);
});
// 修改状态
this.update(Wrappers.<RurchaseRequest>lambdaUpdate().set(RurchaseRequest::getStep, 1).eq(RurchaseRequest::getId, rurchaseRequest.getId()));
return true;
}
}
从RurchaseRequestServiceImpl#rurchaseRequestAdd方法中找到两个操作数据库的关键函数:
this.save(rurchaseRequest);
goodsBelongService.saveBatch(goodsBelongList);
这两个方法都是继承自mybatisplus的操作数据库的公共方法,可以在类的定义中找到对应的java实体类:
public class RurchaseRequestServiceImpl extends ServiceImpl<RurchaseRequestMapper, RurchaseRequest> implements IRurchaseRequestService
public interface IGoodsBelongService extends IService<GoodsBelong>
关于mybatisplus的使用方法参考:
Mybatis-plus之IService的使用_iservice mybatisplus-CSDN博客
https://www.cnblogs.com/kaibindirver/p/16086336.html
(不明白为什么extends ServiceImpl<RurchaseRequestMapper, RurchaseRequest>后,还要implements IRurchaseRequestService,需要看源码)
找到java实体类:
cc.mrbird.febs.cos.entity.GoodsBelong
cc.mrbird.febs.cos.entity.RurchaseRequest
package cc.mrbird.febs.cos.entity;
import java.io.Serializable;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 物品所属
*
* @author FanK
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class GoodsBelong implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "ID", type = IdType.AUTO)
private Integer id;
/**
* 物品名称
*/
private String name;
/**
* 型号
*/
private String type;
/**
* 单位
*/
private String unit;
/**
* 数量
*/
private Integer amount;
/**
* 耗材类型
*/
private Integer typeId;
/**
* 申请/入库单号
*/
private String num;
/**
* 单价
*/
private BigDecimal price;
/**
* 日期
*/
private String createDate;
}
package cc.mrbird.febs.cos.entity;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 采购申请
*
* @author FanK
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class RurchaseRequest implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "ID", type = IdType.AUTO)
private Integer id;
/**
* 采购申请单号
*/
private String num;
/**
* 采购说明
*/
private String content;
/**
* 预计金额
*/
private BigDecimal price;
/**
* 采购流程 0是正在采购 1是入库完成
*/
private Integer process;
/**
* 当前流程
*/
private Integer step;
/**
* 申请人
*/
private String applicant;
/**
* 创建时间
*/
private String createDate;
@TableField(exist = false)
private String goods;
@TableField(exist = false)
private String custodian;
@TableField(exist = false)
private String putUser;
@TableField(exist = false)
private String rurchaseContent;
}
从mybatisplus的表名对应关系,可以找到数据库的两张表:
goods_belong
名 | 类型 | 长度 | 小数点 | 注释 |
id | int | 主键 | ||
name | varchar | 200 | 物品名称 | |
type | varchar | 200 | 型号 | |
unit | varchar | 30 | 单位 | |
amount | int | 数量 | ||
type_id | int | 耗材类型 | ||
num | varchar | 200 | 申请/入库单号 | |
price | decimal | 10 | 2 | 单价 |
create_date | datetime | 日期 |
rurchase_request
名 | 类型 | 长度 | 小数点 | 注释 |
id | int | 主键 | ||
num | varchar | 200 | 采购申请单号 | |
content | varchar | 300 | 采购说明 | |
price | decimal | 10 | 2 | 预计金额 |
process | tinyint | 采购流程 0是正在采购 1是入库完成 | ||
step | tinyint | 当前流程 | ||
applicant | varchar | 200 | 申请人 | |
create_date | datetime | 创建时间 |
库管admin新增一个采购申请,会在rurchase_request增加一条数据对应这个申请,同时会在goods_belong中新增若干条数据,对应申请表中的若干项物资
申请记录:
ps:其中step字段的值表示当前流程,0表示等待采购,1表示入库完成
申请的物品清单:
在采购员账号caigou中可以办理采购入库:
当入库后,库存就会增加,对应的库存表会变化,涉及到多张表
stock_info
stock_put
goods_belong
rurchase_request
cc.mrbird.febs.cos.service.impl.RurchaseRequestServiceImpl#rurchasePut
@Override
public Boolean rurchasePut(RurchaseRequest rurchaseRequest) {
JSONArray array = JSONUtil.parseArray(rurchaseRequest.getGoods());
List<GoodsBelong> goodsBelongList = JSONUtil.toList(array, GoodsBelong.class);
// 添加入库单
StockPut stockPut = new StockPut();
stockPut.setContent(rurchaseRequest.getRurchaseContent());
stockPut.setCreateDate(DateUtil.formatDateTime(new Date()));
stockPut.setCustodian(rurchaseRequest.getCustodian());
stockPut.setPutUser(rurchaseRequest.getPutUser());
stockPut.setPrice(rurchaseRequest.getPrice());
stockPut.setNum("PUT-"+new Date().getTime());
stockPutService.save(stockPut);
goodsBelongList.forEach(item -> {
item.setCreateDate(DateUtil.formatDateTime(new Date()));
item.setNum(stockPut.getNum());
// 判断库房物品是否存在
StockInfo stockInfo = stockInfoService.getOne(Wrappers.<StockInfo>lambdaQuery().eq(StockInfo::getName, item.getName()).eq(StockInfo::getTypeId, item.getTypeId()).eq(StockInfo::getIsIn, 0));
if (stockInfo != null) {
// 更改库房数据
stockInfoService.update(Wrappers.<StockInfo>lambdaUpdate().set(StockInfo::getAmount, stockInfo.getAmount()+item.getAmount())
.set(StockInfo::getPrice, stockInfo.getPrice())
.eq(StockInfo::getName, stockInfo.getName()));
} else {
// 重新添加库房数据
StockInfo stock = new StockInfo();
stock.setName(item.getName());
stock.setAmount(item.getAmount());
stock.setCreateDate(DateUtil.formatDateTime(new Date()));
stock.setType(item.getType());
stock.setTypeId(item.getTypeId());
stock.setUnit(item.getUnit());
stock.setPrice(item.getPrice());
stock.setIsIn(0);
stockInfo = stock;
stockInfoService.save(stock);
}
// 添加入库记录
StockInfo stockInfoPut = new StockInfo();
stockInfoPut.setParentId(stockInfo.getId());
stockInfoPut.setName(item.getName());
stockInfoPut.setAmount(item.getAmount());
stockInfoPut.setCreateDate(DateUtil.formatDateTime(new Date()));
stockInfoPut.setType(item.getType());
stockInfoPut.setTypeId(item.getTypeId());
stockInfoPut.setUnit(item.getUnit());
stockInfoPut.setPrice(item.getPrice());
stockInfoPut.setIsIn(1);
stockInfoService.save(stockInfoPut);
// 添加所属信息
GoodsBelong goodsBelong = new GoodsBelong();
goodsBelong.setNum(stockPut.getNum());
goodsBelong.setCreateDate(DateUtil.formatDateTime(new Date()));
goodsBelong.setAmount(item.getAmount());
goodsBelong.setName(item.getName());
goodsBelong.setPrice(item.getPrice());
goodsBelong.setType(item.getType());
goodsBelong.setTypeId(item.getTypeId());
goodsBelong.setUnit(item.getUnit());
goodsBelongService.save(goodsBelong);
});
// 修改状态
this.update(Wrappers.<RurchaseRequest>lambdaUpdate().set(RurchaseRequest::getStep, 1).eq(RurchaseRequest::getId, rurchaseRequest.getId()));
return true;
}
入库后goods_belong会增加三条入库操作记录