库房bug修复
This commit is contained in:
@@ -183,6 +183,8 @@ public class SysOaWarehouseController extends BaseController {
|
|||||||
});
|
});
|
||||||
sysOaWarehouseMaster.setWarehouseList(list);
|
sysOaWarehouseMaster.setWarehouseList(list);
|
||||||
sysOaWarehouseMaster.setMasterNum(UUID.randomUUID().toString());
|
sysOaWarehouseMaster.setMasterNum(UUID.randomUUID().toString());
|
||||||
|
// 导入入口跳过"必须关联采购需求"校验,后续可在采购需求处手动关联
|
||||||
|
sysOaWarehouseMaster.setSkipRequirementCheck(true);
|
||||||
iSysOaWarehouseMasterService.insertByBo(sysOaWarehouseMaster);
|
iSysOaWarehouseMasterService.insertByBo(sysOaWarehouseMaster);
|
||||||
return R.ok(result.getAnalysis());
|
return R.ok(result.getAnalysis());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,11 @@ public class SysOaWarehouseMasterBo extends BaseEntity {
|
|||||||
|
|
||||||
private Long requirementId;
|
private Long requirementId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入场景跳过"必须关联采购需求"校验(仅 import 入口传 true)
|
||||||
|
*/
|
||||||
|
private transient Boolean skipRequirementCheck;
|
||||||
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date startTime;
|
private Date startTime;
|
||||||
|
|||||||
@@ -9,11 +9,14 @@ import com.ruoyi.system.mapper.SysUserMapper;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,6 +67,49 @@ public class ImCredentialsController extends BaseController {
|
|||||||
return R.ok(data);
|
return R.ok(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 给指定 OA 用户在 OpenIM 注册账号(如未注册)。
|
||||||
|
* 用于发消息前确保对方 imUserId 存在 —— 解决 OpenIM "RecordNotFoundError 1004"。
|
||||||
|
* <p>支持单个或批量,幂等。
|
||||||
|
*/
|
||||||
|
@PostMapping("/ensure")
|
||||||
|
public R<Map<String, Object>> ensureTargets(@RequestBody Map<String, Object> body) {
|
||||||
|
if (LoginHelper.getUserId() == null) return R.fail("未登录");
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Object> raw = (List<Object>) body.get("userIds");
|
||||||
|
if (raw == null || raw.isEmpty()) return R.fail("userIds 不能为空");
|
||||||
|
|
||||||
|
int ok = 0, fail = 0;
|
||||||
|
Map<String, String> results = new HashMap<>();
|
||||||
|
for (Object o : raw) {
|
||||||
|
Long uid;
|
||||||
|
try {
|
||||||
|
uid = Long.parseLong(o.toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ImBind exist = bindMapper.selectById(uid);
|
||||||
|
if (exist != null && exist.getImUserId() != null && !exist.getImUserId().isEmpty()) {
|
||||||
|
ok++;
|
||||||
|
results.put(uid.toString(), exist.getImUserId());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ImBind bind = ensureBind(uid);
|
||||||
|
if (bind != null) {
|
||||||
|
ok++;
|
||||||
|
results.put(uid.toString(), bind.getImUserId());
|
||||||
|
} else {
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map<String, Object> data = new HashMap<>();
|
||||||
|
data.put("ok", ok);
|
||||||
|
data.put("fail", fail);
|
||||||
|
data.put("bindings", results);
|
||||||
|
return R.ok(data);
|
||||||
|
}
|
||||||
|
|
||||||
/** 给指定 OA userId 在 OpenIM 主 API 直接注册一个账号并落 bind 表 */
|
/** 给指定 OA userId 在 OpenIM 主 API 直接注册一个账号并落 bind 表 */
|
||||||
private ImBind ensureBind(Long oaUserId) {
|
private ImBind ensureBind(Long oaUserId) {
|
||||||
SysUser u = userMapper.selectById(oaUserId);
|
SysUser u = userMapper.selectById(oaUserId);
|
||||||
|
|||||||
@@ -171,9 +171,11 @@ public class SysOaWarehouseMasterServiceImpl implements ISysOaWarehouseMasterSer
|
|||||||
add.setRemark("办公耗材自动写入");
|
add.setRemark("办公耗材自动写入");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 规则 2:入库(type=1)必须强关联采购需求(requirement_id)
|
// 规则 2:入库(type=1)默认必须强关联采购需求(requirement_id);
|
||||||
|
// 导入入口会显式传 skipRequirementCheck=true,单纯导入物料,后续在采购需求处手动关联
|
||||||
if (add.getType() != null && add.getType() == 1
|
if (add.getType() != null && add.getType() == 1
|
||||||
&& add.getRequirementId() == null) {
|
&& add.getRequirementId() == null
|
||||||
|
&& !Boolean.TRUE.equals(bo.getSkipRequirementCheck())) {
|
||||||
throw new RuntimeException("入库必须关联采购需求,请先选择需求");
|
throw new RuntimeException("入库必须关联采购需求,请先选择需求");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -168,6 +168,8 @@ public class SysOaWarehouseTaskServiceImpl implements ISysOaWarehouseTaskService
|
|||||||
sysOaWarehouseMaster.setStatus(0L);
|
sysOaWarehouseMaster.setStatus(0L);
|
||||||
sysOaWarehouseMaster.setMasterNum(UUID.randomUUID().toString());
|
sysOaWarehouseMaster.setMasterNum(UUID.randomUUID().toString());
|
||||||
sysOaWarehouseMaster.setSignUser(LoginHelper.getNickName());
|
sysOaWarehouseMaster.setSignUser(LoginHelper.getNickName());
|
||||||
|
// 操作时间必须落库,否则前端按 signTime 排序/筛选时看不到今天提报的单
|
||||||
|
sysOaWarehouseMaster.setSignTime(new java.util.Date());
|
||||||
Boolean flag = masterMapper.insert(sysOaWarehouseMaster) > 0;
|
Boolean flag = masterMapper.insert(sysOaWarehouseMaster) > 0;
|
||||||
Long masterId = sysOaWarehouseMaster.getMasterId();
|
Long masterId = sysOaWarehouseMaster.getMasterId();
|
||||||
for (SysOaWarehouseTaskBo sysOaWarehouseTaskBo : boList) {
|
for (SysOaWarehouseTaskBo sysOaWarehouseTaskBo : boList) {
|
||||||
|
|||||||
@@ -14,11 +14,18 @@
|
|||||||
<el-table-column label="规格" align="center" prop="specifications" />
|
<el-table-column label="规格" align="center" prop="specifications" />
|
||||||
<el-table-column label="出库时间" align="cenetr" width="220px" prop="signTime" />
|
<el-table-column label="出库时间" align="cenetr" width="220px" prop="signTime" />
|
||||||
<el-table-column label="品牌" align="center" prop="brand" />
|
<el-table-column label="品牌" align="center" prop="brand" />
|
||||||
|
<el-table-column label="操作" align="center" width="90">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="text" style="color:#e6a23c"
|
||||||
|
icon="el-icon-back" @click="handleReturn(scope.row)">退库</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { redoDetail } from '@/api/oa/warehouse/oaOutWarehouse'
|
||||||
export default {
|
export default {
|
||||||
name: 'OutWarehouseDetailTable',
|
name: 'OutWarehouseDetailTable',
|
||||||
props: {
|
props: {
|
||||||
@@ -53,6 +60,33 @@ export default {
|
|||||||
},
|
},
|
||||||
handlePagination (val) {
|
handlePagination (val) {
|
||||||
this.$emit('pagination', val);
|
this.$emit('pagination', val);
|
||||||
|
},
|
||||||
|
// 一键退库:默认按出库数量全额退回
|
||||||
|
handleReturn (row) {
|
||||||
|
const max = Number(row.amount || 0)
|
||||||
|
if (max <= 0) {
|
||||||
|
this.$message.warning('该明细出库数量为 0,无法退库')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$prompt(`退回数量(最大 ${max}),物料:${row.warehouseName || ''}`, '退库', {
|
||||||
|
confirmButtonText: '确定退库',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
inputValue: String(max),
|
||||||
|
inputValidator: (v) => {
|
||||||
|
const n = Number(v)
|
||||||
|
if (!n || n <= 0) return '请输入大于 0 的数量'
|
||||||
|
if (n > max) return '不能超过出库数量 ' + max
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}).then(({ value }) => {
|
||||||
|
const num = Math.floor(Number(value))
|
||||||
|
redoDetail([{ detailId: row.id, returnNum: num }]).then(() => {
|
||||||
|
this.$modal.msgSuccess(`已退库 ${num} 件`)
|
||||||
|
this.$emit('returned')
|
||||||
|
}).catch(() => {
|
||||||
|
this.$modal.msgError('退库失败')
|
||||||
|
})
|
||||||
|
}).catch(() => {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,6 +113,12 @@
|
|||||||
<el-table-column label="型号" align="center" prop="model"/>
|
<el-table-column label="型号" align="center" prop="model"/>
|
||||||
<el-table-column label="规格" align="center" prop="specifications"/>
|
<el-table-column label="规格" align="center" prop="specifications"/>
|
||||||
<el-table-column label="品牌" align="center" prop="brand"/>
|
<el-table-column label="品牌" align="center" prop="brand"/>
|
||||||
|
<el-table-column label="操作" align="center" width="90">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="text" style="color:#e6a23c"
|
||||||
|
icon="el-icon-back" @click="handleReturn(scope.row)">退库</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<div slot="footer" class="dialog-footer">
|
<div slot="footer" class="dialog-footer">
|
||||||
<el-button @click="detail = false">关闭</el-button>
|
<el-button @click="detail = false">关闭</el-button>
|
||||||
@@ -122,6 +128,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { redoDetail } from '@/api/oa/warehouse/oaOutWarehouse'
|
||||||
export default {
|
export default {
|
||||||
name: 'OutWarehouseMasterTable',
|
name: 'OutWarehouseMasterTable',
|
||||||
props: {
|
props: {
|
||||||
@@ -174,6 +181,40 @@ export default {
|
|||||||
},
|
},
|
||||||
handlePagination(val) {
|
handlePagination(val) {
|
||||||
this.$emit('pagination', val);
|
this.$emit('pagination', val);
|
||||||
|
},
|
||||||
|
// 一键退库:默认按出库数量全额退回
|
||||||
|
handleReturn (row) {
|
||||||
|
const max = Number(row.amount || 0)
|
||||||
|
if (max <= 0) {
|
||||||
|
this.$message.warning('该明细出库数量为 0,无法退库')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$prompt(`退回数量(最大 ${max}),物料:${row.warehouseName || ''}`, '退库', {
|
||||||
|
confirmButtonText: '确定退库',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
inputValue: String(max),
|
||||||
|
inputValidator: (v) => {
|
||||||
|
const n = Number(v)
|
||||||
|
if (!n || n <= 0) return '请输入大于 0 的数量'
|
||||||
|
if (n > max) return '不能超过出库数量 ' + max
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}).then(({ value }) => {
|
||||||
|
const num = Math.floor(Number(value))
|
||||||
|
redoDetail([{ detailId: row.id, returnNum: num }]).then(() => {
|
||||||
|
this.$modal.msgSuccess(`已退库 ${num} 件`)
|
||||||
|
// 通知父页面刷新数据
|
||||||
|
this.$emit('returned')
|
||||||
|
// 同步本地:扣掉已退数量
|
||||||
|
row.amount = max - num
|
||||||
|
if (row.amount <= 0) {
|
||||||
|
const idx = this.detailData.warehouseList.indexOf(row)
|
||||||
|
if (idx > -1) this.detailData.warehouseList.splice(idx, 1)
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
this.$modal.msgError('退库失败')
|
||||||
|
})
|
||||||
|
}).catch(() => {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,11 +26,13 @@
|
|||||||
<OutWarehouseMasterTable :list="outWareHouseList" :loading="loading" :total="total"
|
<OutWarehouseMasterTable :list="outWareHouseList" :loading="loading" :total="total"
|
||||||
@selection-change="handleSelectionChange" @delete="handleDelete" @query="handleQuery"
|
@selection-change="handleSelectionChange" @delete="handleDelete" @query="handleQuery"
|
||||||
@pagination="handlePagination" @status-change="handleStatusChange"
|
@pagination="handlePagination" @status-change="handleStatusChange"
|
||||||
|
@returned="handleReturned"
|
||||||
@export-detail="handleExportDetail" />
|
@export-detail="handleExportDetail" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="出库明细维度" name="detail">
|
<el-tab-pane label="出库明细维度" name="detail">
|
||||||
<OutWarehouseDetailTable :list="outWarehouseDetailList" :loading="loading" :total="total"
|
<OutWarehouseDetailTable :list="outWarehouseDetailList" :loading="loading" :total="total"
|
||||||
@pagination="handlePagination" @export-detail="handleExportDetailDetail" />
|
@pagination="handlePagination" @returned="handleReturned"
|
||||||
|
@export-detail="handleExportDetailDetail" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -218,6 +220,10 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
// 项目选择
|
// 项目选择
|
||||||
|
// 退库成功后刷新右侧明细
|
||||||
|
handleReturned () {
|
||||||
|
this.getList()
|
||||||
|
},
|
||||||
handleProjectSelect (data) {
|
handleProjectSelect (data) {
|
||||||
this.currentProject = data;
|
this.currentProject = data;
|
||||||
this.queryParams.projectId = data.projectId;
|
this.queryParams.projectId = data.projectId;
|
||||||
|
|||||||
Reference in New Issue
Block a user