提交 396ac942 authored 作者: zhoushaopan's avatar zhoushaopan

提交代码

上级 e29793d7
...@@ -15,8 +15,11 @@ import com.tykj.dev.device.library.subject.Dto.DeviceLogDto; ...@@ -15,8 +15,11 @@ import com.tykj.dev.device.library.subject.Dto.DeviceLogDto;
import com.tykj.dev.device.library.subject.domin.DeviceLibrary; import com.tykj.dev.device.library.subject.domin.DeviceLibrary;
import com.tykj.dev.device.library.subject.vo.FileVo; import com.tykj.dev.device.library.subject.vo.FileVo;
import com.tykj.dev.device.library.subject.vo.ScriptSaveVo; import com.tykj.dev.device.library.subject.vo.ScriptSaveVo;
import com.tykj.dev.device.packing.controller.PackingController;
import com.tykj.dev.device.packing.repository.PackingLibraryDao;
import com.tykj.dev.device.packing.service.PackingLibraryService; import com.tykj.dev.device.packing.service.PackingLibraryService;
import com.tykj.dev.device.packing.subject.domin.PackingLibrary; import com.tykj.dev.device.packing.subject.domin.PackingLibrary;
import com.tykj.dev.device.packing.subject.vo.SelectPack;
import com.tykj.dev.device.task.repository.TaskDao; import com.tykj.dev.device.task.repository.TaskDao;
import com.tykj.dev.device.task.service.TaskLogService; import com.tykj.dev.device.task.service.TaskLogService;
import com.tykj.dev.device.task.service.TaskService; import com.tykj.dev.device.task.service.TaskService;
...@@ -29,6 +32,7 @@ import com.tykj.dev.device.user.subject.service.AreaService; ...@@ -29,6 +32,7 @@ import com.tykj.dev.device.user.subject.service.AreaService;
import com.tykj.dev.device.user.subject.service.UnitsService; import com.tykj.dev.device.user.subject.service.UnitsService;
import com.tykj.dev.device.user.subject.service.UserPublicService; import com.tykj.dev.device.user.subject.service.UserPublicService;
import com.tykj.dev.device.user.util.UserUtils; import com.tykj.dev.device.user.util.UserUtils;
import com.tykj.dev.misc.base.BeanHelper;
import com.tykj.dev.misc.base.ResultObj; import com.tykj.dev.misc.base.ResultObj;
import com.tykj.dev.misc.base.StatusEnum; import com.tykj.dev.misc.base.StatusEnum;
import com.tykj.dev.misc.exception.ApiException; import com.tykj.dev.misc.exception.ApiException;
...@@ -38,6 +42,8 @@ import com.tykj.dev.socket.MyWebSocket; ...@@ -38,6 +42,8 @@ import com.tykj.dev.socket.MyWebSocket;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
...@@ -114,6 +120,9 @@ public class AllotBillController { ...@@ -114,6 +120,9 @@ public class AllotBillController {
@Autowired @Autowired
private TaskDao taskDao; private TaskDao taskDao;
@Autowired
private PackingLibraryDao packingLibraryDao;
@Autowired @Autowired
private PackingLibraryService packingLibraryService; private PackingLibraryService packingLibraryService;
...@@ -144,7 +153,7 @@ public class AllotBillController { ...@@ -144,7 +153,7 @@ public class AllotBillController {
@ApiOperation(value = "发起配发业务", notes = "可以通过这个接口发起配发任务") @ApiOperation(value = "发起配发业务", notes = "可以通过这个接口发起配发任务")
@PostMapping(value = "/addAllotBill") @PostMapping(value = "/addAllotBill")
@Transactional(rollbackFor = Exception.class) // @Transactional(rollbackFor = Exception.class)
public ResponseEntity addAllotBill(@RequestBody @Validated AllotBillSaveVo allotBillSaveVo) { public ResponseEntity addAllotBill(@RequestBody @Validated AllotBillSaveVo allotBillSaveVo) {
//判断发起配发的装备的生命状态 //判断发起配发的装备的生命状态
if (allotBillSaveVo.getAllotCheckDetail()!=null&&allotBillSaveVo.getAllotCheckDetail().length()>0) { if (allotBillSaveVo.getAllotCheckDetail()!=null&&allotBillSaveVo.getAllotCheckDetail().length()>0) {
...@@ -250,6 +259,8 @@ public class AllotBillController { ...@@ -250,6 +259,8 @@ public class AllotBillController {
List<Integer> ids = new ArrayList<>(); List<Integer> ids = new ArrayList<>();
//横纵向列装转换map(key:转换前列装id,value:转换后列装id),减少数据库查询 //横纵向列装转换map(key:转换前列装id,value:转换后列装id),减少数据库查询
Map<Integer,Integer> changeMap = new HashMap<>(); Map<Integer,Integer> changeMap = new HashMap<>();
get(strings,allotBillSaveVo);
for (String s : strings) { for (String s : strings) {
//最后一位原来为装备扫码结果,已弃用 //最后一位原来为装备扫码结果,已弃用
if (s.length() >= 2) { if (s.length() >= 2) {
...@@ -259,7 +270,8 @@ public class AllotBillController { ...@@ -259,7 +270,8 @@ public class AllotBillController {
//改变装备状态 //改变装备状态
DeviceLibrary deviceLibraryEntity = deviceLibraryService.getOne(id); DeviceLibrary deviceLibraryEntity = deviceLibraryService.getOne(id);
//纵向配发 //纵向配发
if (allotBillSaveVo.getAllotType() == 1){ // if (allotBillSaveVo.getAllotType() == 1){
if (allotBillSaveVo.getMatchingRange() == 1){
//如果当前装备的配用范围不是省以下纵向 //如果当前装备的配用范围不是省以下纵向
if (deviceLibraryEntity.getMatchingRange()!=1){ if (deviceLibraryEntity.getMatchingRange()!=1){
//判断changeMap是否存在该列装的转换信息 //判断changeMap是否存在该列装的转换信息
...@@ -291,9 +303,41 @@ public class AllotBillController { ...@@ -291,9 +303,41 @@ public class AllotBillController {
deviceLibraryEntity.setLifeStatus(3); deviceLibraryEntity.setLifeStatus(3);
//改变装备管理状态为不在本单位 //改变装备管理状态为不在本单位
deviceLibraryEntity.setManageStatus(0); deviceLibraryEntity.setManageStatus(0);
}else if(allotBillSaveVo.getMatchingRange() == 2){
//如果当前装备的配用范围不是省以下纵向
if (deviceLibraryEntity.getMatchingRange()!=2){
//判断changeMap是否存在该列装的转换信息
if (changeMap.get(deviceLibraryEntity.getPackingId())!=null){
//改变装备所属列装以及配用范围
deviceLibraryEntity.setPackingId(changeMap.get(deviceLibraryEntity.getPackingId()));
deviceLibraryEntity.setMatchingRange(2);
}
else {
//判断是否存在省以下纵向的相同列装装备
PackingLibrary packingLibrary = packingLibraryService.getOne(deviceLibraryEntity.getPackingId());
PackingLibrary packingLibrary1 = packingLibraryService.findSamePacking(packingLibrary.getPartParentId(), 2, packingLibrary.getType(), packingLibrary.getStyle(), packingLibrary.getName(), packingLibrary.getSecretLevel(), packingLibrary.getInvisibleRange());
//不存在直接抛出异常
if (packingLibrary1 == null) {
throw new ApiException(ResponseEntity.status(20000).body(new ResultObj("序列号为" + deviceLibraryEntity.getSeqNumber() + "的装备所属列装不存在配用范围为省对下纵向的相同列装装备")));
}
//存在的话改变装备所属列装以及配用范围
else {
changeMap.put(deviceLibraryEntity.getPackingId(),packingLibrary1.getId());
deviceLibraryEntity.setPackingId(packingLibrary1.getId());
deviceLibraryEntity.setMatchingRange(1);
}
}
//存装备日志
DeviceLogDto deviceLogDto = new DeviceLogDto(id, "纵向配发将所属列装由" + deviceLibraryEntity.getMatchingRangeName() + "的列装改为"+configCache.getMatchingRangeMap().get(1)+"的列装", fileVoList,saveEntity.getId(),null);
deviceLogService.addLog(deviceLogDto);
}
//改变装备生命状态为配发
deviceLibraryEntity.setLifeStatus(3);
//改变装备管理状态为不在本单位
deviceLibraryEntity.setManageStatus(0);
} }
//横向配发 //横向配发
else { else if (allotBillSaveVo.getMatchingRange() == 3){
//如果当前装备的配用范围不是省以下横向 //如果当前装备的配用范围不是省以下横向
if (deviceLibraryEntity.getMatchingRange()!=3) { if (deviceLibraryEntity.getMatchingRange()!=3) {
//判断changeMap是否存在该列装的转换信息 //判断changeMap是否存在该列装的转换信息
...@@ -307,8 +351,11 @@ public class AllotBillController { ...@@ -307,8 +351,11 @@ public class AllotBillController {
PackingLibrary packingLibrary = packingLibraryService.getOne(deviceLibraryEntity.getPackingId()); PackingLibrary packingLibrary = packingLibraryService.getOne(deviceLibraryEntity.getPackingId());
PackingLibrary packingLibrary1 = packingLibraryService.findSamePacking(packingLibrary.getPartParentId(), 3, packingLibrary.getType(), packingLibrary.getStyle(), packingLibrary.getName(), packingLibrary.getSecretLevel(), packingLibrary.getInvisibleRange()); PackingLibrary packingLibrary1 = packingLibraryService.findSamePacking(packingLibrary.getPartParentId(), 3, packingLibrary.getType(), packingLibrary.getStyle(), packingLibrary.getName(), packingLibrary.getSecretLevel(), packingLibrary.getInvisibleRange());
//不存在直接抛出异常 //不存在直接抛出异常
if (packingLibrary1 == null) { // if (packingLibrary1 == null) {
throw new ApiException(ResponseEntity.status(20000).body(new ResultObj("序列号为" + deviceLibraryEntity.getSeqNumber() + "的装备所属列装不存在配用范围为省对下横向的相同列装装备"))); // throw new ApiException(ResponseEntity.status(20000).body(new ResultObj("序列号为" + deviceLibraryEntity.getSeqNumber() + "的装备所属列装不存在配用范围为省对下横向的相同列装装备")));
// }
if (packingLibrary1 == null){
createPackingLibrary(packingLibrary,null,id);
} }
//存在的话改变装备所属列装以及配用范围 //存在的话改变装备所属列装以及配用范围
else { else {
...@@ -834,4 +881,226 @@ public class AllotBillController { ...@@ -834,4 +881,226 @@ public class AllotBillController {
return ResponseEntity.ok(title + "的任务撤回成功"); return ResponseEntity.ok(title + "的任务撤回成功");
} }
// @ApiOperation(value = "创建列装装备")
//// @PostMapping("/createPackingLibrary")
// public Map<Integer,Integer> createPackingLibrary(PackingLibrary packingLibrary,Integer matchingRange,Integer devId){
// Map<Integer,Integer> map = new HashMap<>();
// //是否是配件
// Integer isPart = packingLibrary.getIsPart();
//
//// List<DeviceLibrary> deviceLibraries = deviceLibraryService.getAllDevByDevIds(ids);
//// //遍历所有装备的id
//// for (Integer id : ids) {
//// //先判断配发装备之间有没有父子结构
//// if (ids.contains(packingLibrary.getPartParentId())){
//// ids.remove()
//// }
//// }
// //如果是配件 需要找到父类
// if (isPart == 1){
// PackingLibrary packingLibrary1 = new PackingLibrary();
// BeanUtils.copyProperties(packingLibrary,packingLibrary1);
// packingLibrary1.setMatchingRange(matchingRange);
// //更新
// PackingLibrary packingLibrary2 = packingLibraryService.update(packingLibrary);
// //同时修改装备的状态
// DeviceLibrary deviceLibraryEntity = deviceLibraryService.getOne(devId);
// deviceLibraryEntity.setMatchingRange(matchingRange);
// map.put(packingLibrary.getId(),packingLibrary2.getId());
// }else {
// //是装备
// //查询出父子结构
// SelectPack selectPack = new SelectPack();
// selectPack.setModel(packingLibrary.getModel());
// selectPack.setName(packingLibrary.getName());
// selectPack.setStatus(packingLibrary.getStatus());
// selectPack.setSecretLevel(packingLibrary.getSecretLevel());
// List<PackingLibrary> insertList = packingLibraryService.getInsertList(selectPack);
// //拿到装备
// for (PackingLibrary library : insertList) {
// if (library.getIsPart() == 0){
// PackingLibrary newPackingLibrary = new PackingLibrary();
// BeanUtils.copyProperties(library,newPackingLibrary);
// newPackingLibrary.setId(null);
// newPackingLibrary.setMatchingRange(matchingRange);
// //更新 新的装备
// PackingLibrary packingLibrary1 = packingLibraryService.addEntity(newPackingLibrary);
// //同时修改装备的状态
// DeviceLibrary deviceLibraryEntity = deviceLibraryService.getOne(devId);
// deviceLibraryEntity.setPackingId(packingLibrary1.getId());
// deviceLibraryEntity.setMatchingRange(matchingRange);
// map.put(library.getId(),packingLibrary1.getId());
// }else {
// if (library.getMatchingRange() != matchingRange){
// PackingLibrary newPackingLibrary = new PackingLibrary();
// BeanUtils.copyProperties(library,newPackingLibrary);
// newPackingLibrary.setMatchingRange(matchingRange);
// //更新
// PackingLibrary packingLibrary2 = packingLibraryService.update(packingLibrary);
// //同时修改装备的状态
// DeviceLibrary deviceLibraryEntity = deviceLibraryService.getOne(devId);
// deviceLibraryEntity.setMatchingRange(matchingRange);
// map.put(packingLibrary.getId(),packingLibrary2.getId());
// }
// }
// }
// }
// return map;
//
// }
public Map<Integer,Integer> createPackingLibrary(PackingLibrary packingLibrary,Integer matchingRange,Integer devId){
Map<Integer,Integer> map = new HashMap<>();
//是否是配件
Integer isPart = packingLibrary.getIsPart();
//如果是配件 需要找到父类
// if (isPart == 1){
// PackingLibrary packingLibrary1 = new PackingLibrary();
// BeanUtils.copyProperties(packingLibrary,packingLibrary1);
// packingLibrary1.setMatchingRange(matchingRange);
// //更新
// PackingLibrary packingLibrary2 = packingLibraryService.update(packingLibrary);
// //同时修改装备的状态
// DeviceLibrary deviceLibraryEntity = deviceLibraryService.getOne(devId);
// deviceLibraryEntity.setMatchingRange(matchingRange);
// map.put(packingLibrary.getId(),packingLibrary2.getId());
// }else {
// //是装备
// //查询出父子结构
// SelectPack selectPack = new SelectPack();
// selectPack.setModel(packingLibrary.getModel());
// selectPack.setName(packingLibrary.getName());
// selectPack.setStatus(packingLibrary.getStatus());
// selectPack.setSecretLevel(packingLibrary.getSecretLevel());
// List<PackingLibrary> insertList = packingLibraryService.getInsertList(selectPack);
// //拿到装备
// for (PackingLibrary library : insertList) {
// if (library.getIsPart() == 0){
// PackingLibrary newPackingLibrary = new PackingLibrary();
// BeanUtils.copyProperties(library,newPackingLibrary);
// newPackingLibrary.setId(null);
// newPackingLibrary.setMatchingRange(matchingRange);
// //更新 新的装备
// PackingLibrary packingLibrary1 = packingLibraryService.addEntity(newPackingLibrary);
// //同时修改装备的状态
// DeviceLibrary deviceLibraryEntity = deviceLibraryService.getOne(devId);
// deviceLibraryEntity.setPackingId(packingLibrary1.getId());
// deviceLibraryEntity.setMatchingRange(matchingRange);
// map.put(library.getId(),packingLibrary1.getId());
// }else {
// if (library.getMatchingRange() != matchingRange){
// PackingLibrary newPackingLibrary = new PackingLibrary();
// BeanUtils.copyProperties(library,newPackingLibrary);
// newPackingLibrary.setMatchingRange(matchingRange);
// //更新
// PackingLibrary packingLibrary2 = packingLibraryService.update(packingLibrary);
// //同时修改装备的状态
// DeviceLibrary deviceLibraryEntity = deviceLibraryService.getOne(devId);
// deviceLibraryEntity.setMatchingRange(matchingRange);
// map.put(packingLibrary.getId(),packingLibrary2.getId());
// }
// }
// }
// }
return map;
}
public PackingLibrary getPackingLibrary(PackingLibrary packingLibrary){
Integer partParentId = packingLibrary.getPartParentId();
PackingLibrary one = packingLibraryService.getOne(partParentId);
if (one.getIsRoot() == 0){
PackingLibrary parentPackingLibrary = packingLibraryService.getOne(partParentId);
return getPackingLibrary(parentPackingLibrary);
}else {
return packingLibrary;
}
}
public void getPackingLibrary2(PackingLibrary packingLibrary,Integer newId,Integer matchingRange){
ModelMapper mapper = BeanHelper.getUserMapper();
// PackingLibrary newPackingLibrary = mapper.map(packingLibrary,PackingLibrary.class);
PackingLibrary newPackingLibrary = new PackingLibrary();
BeanUtils.copyProperties(packingLibrary,newPackingLibrary);
newPackingLibrary.setId(null);
newPackingLibrary.setPartParentId(newId);
newPackingLibrary.setMatchingRange(matchingRange);
// packingLibraryService.addEntity(newPackingLibrary);
PackingLibrary pl = packingLibraryDao.save(newPackingLibrary);
log.info("pl:{}",pl);
List<PackingLibrary> packingLibraryList = packingLibraryService.getAllByPartPackingId(packingLibrary.getId());
if (packingLibraryList!=null||packingLibraryList.size()!=0){
packingLibraryList.forEach(packingLibrary1 -> {
getPackingLibrary2(packingLibrary1,newPackingLibrary.getId(),matchingRange);
});
}
}
public void get(String[] strings,AllotBillSaveVo allotBillSaveVo){
for (String s : strings) {
//最后一位原来为装备扫码结果,已弃用
if (s.length() >= 2) {
//去掉最后一位得到装备id
Integer id = Integer.parseInt(s.substring(0, s.length() - 1));
// ids.add(id);
//改变装备状态
DeviceLibrary deviceLibraryEntity = deviceLibraryService.getOne(id);
//纵向配发
if (allotBillSaveVo.getMatchingRange() == 1){
//如果当前装备的配用范围不是省以下纵向
if (deviceLibraryEntity.getMatchingRange()!=1){
//判断是否存在省以下纵向的相同列装装备
PackingLibrary packingLibrary = packingLibraryService.getOne(deviceLibraryEntity.getPackingId());
PackingLibrary packingLibrary1 = packingLibraryService.findSamePacking(packingLibrary.getPartParentId(), 1, packingLibrary.getType(), packingLibrary.getStyle(), packingLibrary.getName(), packingLibrary.getSecretLevel(), packingLibrary.getInvisibleRange());
//不存在直接抛出异常
if (packingLibrary1 == null) {
PackingLibrary library = getPackingLibrary(packingLibrary);
getPackingLibrary2(library,library.getPartParentId(),1);
}
}
}
//横向配发
else if (allotBillSaveVo.getMatchingRange() == 2){
//如果当前装备的配用范围不是省以下纵向
if (deviceLibraryEntity.getMatchingRange()!=2){
//判断是否存在省以下纵向的相同列装装备
PackingLibrary packingLibrary = packingLibraryService.getOne(deviceLibraryEntity.getPackingId());
PackingLibrary packingLibrary1 = packingLibraryService.findSamePacking(packingLibrary.getPartParentId(), 2, packingLibrary.getType(), packingLibrary.getStyle(), packingLibrary.getName(), packingLibrary.getSecretLevel(), packingLibrary.getInvisibleRange());
//不存在直接抛出异常
if (packingLibrary1 == null) {
PackingLibrary library = getPackingLibrary(packingLibrary);
getPackingLibrary2(library,library.getPartParentId(),2);
}
}
}
else if (allotBillSaveVo.getMatchingRange() == 3){
//如果当前装备的配用范围不是省以下横向
if (deviceLibraryEntity.getMatchingRange()!=3) {
PackingLibrary packingLibrary = packingLibraryService.getOne(deviceLibraryEntity.getPackingId());
PackingLibrary packingLibrary1 = packingLibraryService.findSamePacking(packingLibrary.getPartParentId(), 3, packingLibrary.getType(), packingLibrary.getStyle(), packingLibrary.getName(), packingLibrary.getSecretLevel(), packingLibrary.getInvisibleRange());
if (packingLibrary1 == null){
PackingLibrary library = getPackingLibrary(packingLibrary);
getPackingLibrary2(library,library.getPartParentId(),3);
}
}
}
}
}
}
} }
...@@ -105,6 +105,9 @@ public class AllotBillSaveVo { ...@@ -105,6 +105,9 @@ public class AllotBillSaveVo {
@ApiModelProperty(value = "单据保存vo") @ApiModelProperty(value = "单据保存vo")
private List<ScriptSaveVo> scriptSaveVos; private List<ScriptSaveVo> scriptSaveVos;
@ApiModelProperty(value = "")
private Integer matchingRange;
/** /**
* 转为配发单实体 * 转为配发单实体
*/ */
......
...@@ -176,4 +176,9 @@ public interface DeviceLibraryService { ...@@ -176,4 +176,9 @@ public interface DeviceLibraryService {
*/ */
void judgeSeqNumbersInNotEqualLifeStatus(List<String> seqNumbers,Integer leftStatus); void judgeSeqNumbersInNotEqualLifeStatus(List<String> seqNumbers,Integer leftStatus);
/**
* 根据装备id集合查询出所有的装备
*/
List<DeviceLibrary> getAllDevByDevIds(List<Integer> ids);
} }
...@@ -564,6 +564,12 @@ public class DeviceLibraryServiceImpl implements DeviceLibraryService { ...@@ -564,6 +564,12 @@ public class DeviceLibraryServiceImpl implements DeviceLibraryService {
} }
} }
@Override
public List<DeviceLibrary> getAllDevByDevIds(List<Integer> ids) {
List<DeviceLibrary> allByIdIn = deviceLibraryDao.findAllByIdIn(ids);
return allByIdIn;
}
@Override @Override
public void isNotLoss(List<Integer> ids) { public void isNotLoss(List<Integer> ids) {
ids.forEach(integer -> { ids.forEach(integer -> {
......
...@@ -171,4 +171,5 @@ public interface PackingLibraryService { ...@@ -171,4 +171,5 @@ public interface PackingLibraryService {
*/ */
Boolean hasSamePack(Integer parentId,Integer type,Integer style,String name,Integer secretLevel,Integer invisibleRange); Boolean hasSamePack(Integer parentId,Integer type,Integer style,String name,Integer secretLevel,Integer invisibleRange);
List<PackingLibrary> getAllByPartPackingId(Integer partPackingId);
} }
...@@ -642,6 +642,14 @@ public class PackingLibraryServiceImpl implements PackingLibraryService { ...@@ -642,6 +642,14 @@ public class PackingLibraryServiceImpl implements PackingLibraryService {
return packingLibraryDao.findAll(predicateBuilder.build()).size()>0; return packingLibraryDao.findAll(predicateBuilder.build()).size()>0;
} }
@Override
public List<PackingLibrary> getAllByPartPackingId(Integer partPackingId) {
// PredicateBuilder<PackingLibrary> and = Specifications.and();
// and.eq("partParentId",partPackingId);
// return packingLibraryDao.findAll(and.build());
return packingLibraryDao.findAllByPartParentId(partPackingId);
}
private Specification<PackingLibrary> getSelectSpecification(PackingLibrarySelectVo packingLibrarySelectVo) { private Specification<PackingLibrary> getSelectSpecification(PackingLibrarySelectVo packingLibrarySelectVo) {
PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and(); PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
Integer level = userUtils.getCurrentUnitLevel(); Integer level = userUtils.getCurrentUnitLevel();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论