Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop
This commit is contained in:
commit
0e2cc60409
|
@ -105,6 +105,23 @@ export function createConvert(data) {
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
//首件检查表初始化
|
||||||
|
export function firstTestInit(id,data) {
|
||||||
|
return request({
|
||||||
|
url: `/pm/subproduction_plan/${id}/first_test_init/`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//首件检查责任人审核
|
||||||
|
export function firstAudit(id,data) {
|
||||||
|
return request({
|
||||||
|
url: `/pm/subproduction_plan/${id}/first_audit/`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
//任务终止
|
//任务终止
|
||||||
export function planstop(id) {
|
export function planstop(id) {
|
||||||
return request({
|
return request({
|
||||||
|
@ -120,4 +137,4 @@ export function plantoggle(id) {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 813 KiB |
Binary file not shown.
After Width: | Height: | Size: 458 KiB |
|
@ -239,13 +239,15 @@
|
||||||
let imag= this.formData.filter(item => {
|
let imag= this.formData.filter(item => {
|
||||||
return item.field_type === 'draw';
|
return item.field_type === 'draw';
|
||||||
});
|
});
|
||||||
that.img = new Image();
|
if(imag.length>0){
|
||||||
that.img.crossOrigin = 'anonymous';
|
that.img = new Image();
|
||||||
let value = imag[0].field_value?imag[0].field_value:imag[0].draw_template;
|
that.img.crossOrigin = 'anonymous';
|
||||||
that.img = 'http://47.95.0.242:2222'+value;
|
let value = imag[0].field_value?imag[0].field_value:imag[0].draw_template;
|
||||||
setTimeout(function(){
|
that.img = 'http://47.95.0.242:2222'+value;
|
||||||
that.canvasInit();
|
setTimeout(function(){
|
||||||
},500);
|
that.canvasInit();
|
||||||
|
},500);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
return{
|
return{
|
||||||
|
@ -695,7 +697,7 @@
|
||||||
that.field = []; //检查项目
|
that.field = []; //检查项目
|
||||||
let submit = isSubmit=='1'?false:true;
|
let submit = isSubmit=='1'?false:true;
|
||||||
that.formData.forEach((item) => {
|
that.formData.forEach((item) => {
|
||||||
let field_value = null;
|
let field_value;
|
||||||
if(item.field_type==='int'){
|
if(item.field_type==='int'){
|
||||||
field_value = parseInt(that.checkForm[item.field_key])
|
field_value = parseInt(that.checkForm[item.field_key])
|
||||||
}else if(item.field_type==='float'){
|
}else if(item.field_type==='float'){
|
||||||
|
|
|
@ -0,0 +1,190 @@
|
||||||
|
<template>
|
||||||
|
<div class="faceLoginWrap">
|
||||||
|
<div style="height: 500px;">
|
||||||
|
<div class="video-box">
|
||||||
|
<video id="video" width="500" height="500" preload autoplay loop muted></video>
|
||||||
|
<canvas id="canvas" width="500" height="500"></canvas>
|
||||||
|
</div>
|
||||||
|
<canvas id="screenshotCanvas" width="500" height="500"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import tracking from '@/assets/tracking/build/tracking-min.js';
|
||||||
|
import {faceLogin} from "@/api/testModel";
|
||||||
|
import '@/assets/tracking/build/data/face-min.js';
|
||||||
|
import {createrecordform,updaterecordform} from "@/api/mtm";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
dialogType: {
|
||||||
|
type:String,
|
||||||
|
default:"new"
|
||||||
|
},
|
||||||
|
recordform: {
|
||||||
|
type:Object,
|
||||||
|
default:null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
video: null,
|
||||||
|
screenshotCanvas: null,
|
||||||
|
uploadLock: false // 上传锁
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.openTheCamera();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openTheCamera () {
|
||||||
|
this.$nextTick(function () {
|
||||||
|
let _this = this;
|
||||||
|
this.video = document.getElementById('video');
|
||||||
|
// 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
|
||||||
|
if (navigator.mediaDevices === undefined) {
|
||||||
|
navigator.mediaDevices = {}
|
||||||
|
}
|
||||||
|
// 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
|
||||||
|
// 使用getUserMedia,因为它会覆盖现有的属性。
|
||||||
|
// 这里,如果缺少getUserMedia属性,就添加它。
|
||||||
|
if (navigator.mediaDevices.getUserMedia === undefined) {
|
||||||
|
navigator.mediaDevices.getUserMedia = function (constraints) {
|
||||||
|
// 首先获取现存的getUserMedia(如果存在)
|
||||||
|
let getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia;
|
||||||
|
// 有些浏览器不支持,会返回错误信息
|
||||||
|
// 保持接口一致
|
||||||
|
if (!getUserMedia) {
|
||||||
|
return Promise.reject(new Error('getUserMedia is not implemented in this browser'))
|
||||||
|
}
|
||||||
|
// 否则,使用Promise将调用包装到旧的navigator.getUserMedia
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
getUserMedia.call(navigator, constraints, resolve, reject)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let constraints = { audio: false, video: { width: this.videoWidth, height: this.videoHeight, transform: 'scaleX(-1)' } };
|
||||||
|
navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
|
||||||
|
// 旧的浏览器可能没有srcObject
|
||||||
|
if ('srcObject' in _this.video) {
|
||||||
|
_this.video.srcObject = stream
|
||||||
|
} else {
|
||||||
|
// 避免在新的浏览器中使用它,因为它正在被弃用。
|
||||||
|
_this.video.src = window.URL.createObjectURL(stream)
|
||||||
|
}
|
||||||
|
_this.video.onloadedmetadata = function (e) {
|
||||||
|
_this.video.play();
|
||||||
|
};
|
||||||
|
_this.init();
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 初始化设置
|
||||||
|
init() {
|
||||||
|
// this.video = document.getElementById('video');
|
||||||
|
this.screenshotCanvas = document.getElementById('screenshotCanvas');
|
||||||
|
let canvas = document.getElementById('canvas');
|
||||||
|
let context = canvas.getContext('2d');
|
||||||
|
|
||||||
|
// 实例化tracker对象
|
||||||
|
let tracker = new window.tracking.ObjectTracker('face');
|
||||||
|
tracker.setInitialScale(4);
|
||||||
|
tracker.setStepSize(2);
|
||||||
|
tracker.setEdgesDensity(0.1);
|
||||||
|
//tracker对象和标签关联
|
||||||
|
window.tracking.track('#video', tracker, {
|
||||||
|
camera: true
|
||||||
|
});
|
||||||
|
let _this = this;
|
||||||
|
//添加事件
|
||||||
|
tracker.on('track', function (event) {
|
||||||
|
|
||||||
|
// 检测出人脸 绘画人脸位置
|
||||||
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
// 给每个人脸绘制对应的框
|
||||||
|
event.data.forEach(function (rect) {
|
||||||
|
context.strokeStyle = '#0764B7';
|
||||||
|
context.strokeRect(rect.x, rect.y, rect.width, rect.height);
|
||||||
|
// 避免重复发送请求
|
||||||
|
if(!_this.uploadLock){
|
||||||
|
_this.uploadLock = true;
|
||||||
|
// 上传图片
|
||||||
|
_this.screenshotAndUpload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 上传图片
|
||||||
|
screenshotAndUpload() {
|
||||||
|
let that = this;
|
||||||
|
// 绘制当前帧图片转换为base64格式
|
||||||
|
let canvas = this.screenshotCanvas;
|
||||||
|
let video = this.video;
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||||
|
let base64Img = canvas.toDataURL('image/jpeg');
|
||||||
|
let img = base64Img.split(',')[1];
|
||||||
|
let imgData = {base64:img};
|
||||||
|
faceLogin(imgData).then((res) => {
|
||||||
|
if (res.code >= 200) {
|
||||||
|
let item= {name:res.data.username,token:res.data.access};
|
||||||
|
that.$emit('func',item);
|
||||||
|
that.$message.success("身份认证成功!");
|
||||||
|
}else{
|
||||||
|
// 打开锁
|
||||||
|
that.uploadLock = false;
|
||||||
|
this.$message.error(res.msg);
|
||||||
|
}
|
||||||
|
}).catch(()=>{
|
||||||
|
// 打开锁
|
||||||
|
that.uploadLock = false;
|
||||||
|
// this.$message.error('面部识别失败请重新验证');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
closeCamera () {
|
||||||
|
this.video.srcObject.getTracks()[0].stop();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.faceLoginWrap{
|
||||||
|
padding: 50px;
|
||||||
|
width: 600px;
|
||||||
|
height: 600px;
|
||||||
|
background: #000000;
|
||||||
|
margin:50px auto 0 auto;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
#screenshotCanvas {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-box {
|
||||||
|
margin: auto;
|
||||||
|
position: relative;
|
||||||
|
width: 500px;
|
||||||
|
height: 500px;
|
||||||
|
background: #000000;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#video {
|
||||||
|
object-fit: fill;
|
||||||
|
-webkit-border-radius: 250px;
|
||||||
|
-moz-border-radius: 250px;
|
||||||
|
border-radius: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
video, canvas {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<div style="width: 100%;height: 620px;">
|
<div class="faceLoginWrap">
|
||||||
<div>
|
<div style="height: 500px;">
|
||||||
<div class="video-box">
|
<div class="video-box">
|
||||||
<video id="video" width="749" height="620" preload autoplay loop muted></video>
|
<video id="video" width="500" height="500" preload autoplay loop muted></video>
|
||||||
<canvas id="canvas" width="749" height="620"></canvas>
|
<canvas id="canvas" width="500" height="500"></canvas>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="screenshotCanvas" width="749" height="620"></canvas>
|
<canvas id="screenshotCanvas" width="500" height="500"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { clockRecord } from '@/api/hrm'
|
import {clockRecord} from '@/api/hrm'
|
||||||
import tracking from '@/assets/tracking/build/tracking-min.js';
|
import tracking from '@/assets/tracking/build/tracking-min.js';
|
||||||
import '@/assets/tracking/build/data/face-min.js';
|
import '@/assets/tracking/build/data/face-min.js';
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
this.openTheCamera();
|
this.openTheCamera();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openTheCamera () {
|
openTheCamera() {
|
||||||
this.$nextTick(function () {
|
this.$nextTick(function () {
|
||||||
let _this = this;
|
let _this = this;
|
||||||
this.video = document.getElementById('video');
|
this.video = document.getElementById('video');
|
||||||
|
@ -52,7 +52,10 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let constraints = { audio: false, video: { width: this.videoWidth, height: this.videoHeight, transform: 'scaleX(-1)' } };
|
let constraints = {
|
||||||
|
audio: false,
|
||||||
|
video: {width: this.videoWidth, height: this.videoHeight, transform: 'scaleX(-1)'}
|
||||||
|
};
|
||||||
navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
|
navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
|
||||||
// 旧的浏览器可能没有srcObject
|
// 旧的浏览器可能没有srcObject
|
||||||
if ('srcObject' in _this.video) {
|
if ('srcObject' in _this.video) {
|
||||||
|
@ -96,7 +99,7 @@
|
||||||
context.strokeRect(rect.x, rect.y, rect.width, rect.height);
|
context.strokeRect(rect.x, rect.y, rect.width, rect.height);
|
||||||
// window.plot(rect.x, rect.y, rect.width, rect.height+20);
|
// window.plot(rect.x, rect.y, rect.width, rect.height+20);
|
||||||
// 避免重复发送请求
|
// 避免重复发送请求
|
||||||
if(!_this.uploadLock){
|
if (!_this.uploadLock) {
|
||||||
_this.uploadLock = true;
|
_this.uploadLock = true;
|
||||||
// 上传图片
|
// 上传图片
|
||||||
_this.screenshotAndUpload();
|
_this.screenshotAndUpload();
|
||||||
|
@ -115,31 +118,40 @@
|
||||||
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||||
let base64Img = canvas.toDataURL('image/jpeg');
|
let base64Img = canvas.toDataURL('image/jpeg');
|
||||||
let img = base64Img.split(',')[1];
|
let img = base64Img.split(',')[1];
|
||||||
let imgData = {base64:img};
|
let imgData = {base64: img};
|
||||||
clockRecord(imgData).then((res) => {
|
clockRecord(imgData).then((res) => {
|
||||||
if (res.code === 200&&res.data.id) {
|
if (res.code === 200 && res.data.id) {
|
||||||
this.$message.success(res.data.name+'签到成功!');
|
this.$message.success(res.data.name + '签到成功!');
|
||||||
setTimeout(()=>{
|
setTimeout(() => {
|
||||||
that.uploadLock = false;
|
that.uploadLock = false;
|
||||||
},3000)
|
}, 3000)
|
||||||
}else{
|
} else {
|
||||||
// 打开锁
|
// 打开锁
|
||||||
that.uploadLock = false;
|
that.uploadLock = false;
|
||||||
this.$message.error(res.msg);
|
this.$message.error(res.msg);
|
||||||
}
|
}
|
||||||
}).catch(()=>{
|
}).catch(() => {
|
||||||
// 打开锁
|
// 打开锁
|
||||||
that.uploadLock = false;
|
that.uploadLock = false;
|
||||||
// this.$message.error('面部识别失败请重新验证');
|
// this.$message.error('面部识别失败请重新验证');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
closeCamera () {
|
closeCamera() {
|
||||||
this.video.srcObject.getTracks()[0].stop();
|
this.video.srcObject.getTracks()[0].stop();
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.faceLoginWrap{
|
||||||
|
padding: 50px;
|
||||||
|
width: 600px;
|
||||||
|
height: 600px;
|
||||||
|
background: #000000;
|
||||||
|
margin:50px auto 0 auto;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
#screenshotCanvas {
|
#screenshotCanvas {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -147,8 +159,13 @@
|
||||||
.video-box {
|
.video-box {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
/*width: 90%;
|
}
|
||||||
height: 90%;*/
|
|
||||||
|
#video {
|
||||||
|
object-fit: fill;
|
||||||
|
-webkit-border-radius: 250px;
|
||||||
|
-moz-border-radius: 250px;
|
||||||
|
border-radius: 250px;
|
||||||
}
|
}
|
||||||
|
|
||||||
video, canvas {
|
video, canvas {
|
||||||
|
|
|
@ -226,8 +226,7 @@ export const asyncRoutes = [
|
||||||
name: 'operation',
|
name: 'operation',
|
||||||
component: () => import('@/views/wpm/operation'),
|
component: () => import('@/views/wpm/operation'),
|
||||||
meta: { title: '车间操作', icon: 'workshopOperation', perms: ['index_manage'] }
|
meta: { title: '车间操作', icon: 'workshopOperation', perms: ['index_manage'] }
|
||||||
}
|
},
|
||||||
,
|
|
||||||
{
|
{
|
||||||
path: 'operationdo/:id',
|
path: 'operationdo/:id',
|
||||||
name: 'operationdo',
|
name: 'operationdo',
|
||||||
|
@ -240,13 +239,18 @@ export const asyncRoutes = [
|
||||||
name: 'need',
|
name: 'need',
|
||||||
component: () => import('@/views/wpm/need'),
|
component: () => import('@/views/wpm/need'),
|
||||||
meta: { title: '过程检验', icon: 'processTest', perms: ['index_manage'] }
|
meta: { title: '过程检验', icon: 'processTest', perms: ['index_manage'] }
|
||||||
}
|
},
|
||||||
,
|
|
||||||
{
|
{
|
||||||
path: 'productjy',
|
path: 'productjy',
|
||||||
name: 'productjy',
|
name: 'productjy',
|
||||||
component: () => import('@/views/wpm/productjy'),
|
component: () => import('@/views/wpm/productjy'),
|
||||||
meta: { title: '成品检验', icon: 'finishedCheck', perms: ['index_manage'] }
|
meta: { title: '成品检验', icon: 'finishedCheck', perms: ['index_manage'] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'firstCheck',
|
||||||
|
name: 'firstCheck',
|
||||||
|
component: () => import('@/views/wpm/firstCheck'),
|
||||||
|
meta: { title: '首件确认', icon: 'finishedCheck', perms: ['index_manage'] }
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -20,7 +20,7 @@ service.interceptors.request.use(
|
||||||
// please modify it according to the actual situation
|
// please modify it according to the actual situation
|
||||||
config.headers['Authorization'] = 'Bearer ' + getToken()
|
config.headers['Authorization'] = 'Bearer ' + getToken()
|
||||||
}
|
}
|
||||||
let data = config.params;
|
let data = config.data;
|
||||||
/*debugger;
|
/*debugger;
|
||||||
console.log(data)*/
|
console.log(data)*/
|
||||||
if(data){
|
if(data){
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="login">
|
<div class="login">
|
||||||
<div class="login-form" style="display: flex;justify-content: space-between">
|
<div class="login-form">
|
||||||
<div style="width: 250px;border-right: 1px dashed #409EFF;">
|
<div class="faceLoginBtnWrap">
|
||||||
<img src="./../../assets/face.png" style="margin-top: 65px;" @click="takePhoto()">
|
<img class="faceLoginBtn" src="./../../assets/face.png" @click="takePhoto()">
|
||||||
</div>
|
</div>
|
||||||
<div style="width: 360px;">
|
<div style="width: 360px;">
|
||||||
<h3 class="title">航玻生产管理系统</h3>
|
<h3 class="title">航玻生产管理系统</h3>
|
||||||
|
@ -245,7 +245,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-image: url("../../assets/beijing.jpg");
|
background-image: url("../../assets/bg-login.png");
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
}
|
}
|
||||||
.title {
|
.title {
|
||||||
|
@ -263,6 +263,10 @@
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
width: 700px;
|
width: 700px;
|
||||||
padding: 25px;
|
padding: 25px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
box-shadow: 0 0 10px 5px #eeeeee;
|
||||||
|
|
||||||
.el-input {
|
.el-input {
|
||||||
height: 45px;
|
height: 45px;
|
||||||
input {
|
input {
|
||||||
|
@ -275,6 +279,15 @@
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.faceLoginBtnWrap{
|
||||||
|
width: 250px;
|
||||||
|
border-right: 1px dashed #409EFF;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.faceLoginBtn{
|
||||||
|
width: 150px;
|
||||||
|
margin-top: 90px;
|
||||||
|
}
|
||||||
#passwordInput{
|
#passwordInput{
|
||||||
padding-right: 35px;
|
padding-right: 35px;
|
||||||
}
|
}
|
||||||
|
@ -309,6 +322,6 @@
|
||||||
}
|
}
|
||||||
.testTracking{
|
.testTracking{
|
||||||
width:100%;
|
width:100%;
|
||||||
height: 620px;
|
height: 500px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,565 @@
|
||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<el-card>
|
||||||
|
<div class="tabButtonWrap">
|
||||||
|
<div
|
||||||
|
v-for="(item,$index) in processOption"
|
||||||
|
:key="item.id"
|
||||||
|
class="tabButton"
|
||||||
|
:class="{activeTab:activeIndex===$index}"
|
||||||
|
@click="changeIndex(item,$index)"
|
||||||
|
>
|
||||||
|
{{item.name}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-table
|
||||||
|
:data="subPlanList"
|
||||||
|
fit
|
||||||
|
style="width: 100%"
|
||||||
|
height="100"
|
||||||
|
stripe
|
||||||
|
border
|
||||||
|
v-el-height-adaptive-table="{bottomOffset: 50}"
|
||||||
|
>
|
||||||
|
<el-table-column type="index" width="50"/>
|
||||||
|
<el-table-column label="子计划编号" min-width="70px" show-overflow-tooltip>
|
||||||
|
<template slot-scope="scope">{{scope.row.number}}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="产品名称" min-width="120px" show-overflow-tooltip>
|
||||||
|
<template slot-scope="scope">{{ scope.row.product_.name }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="产品型号">
|
||||||
|
<template slot-scope="scope">{{ scope.row.product_.specification }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="子工序" min-width="120px" show-overflow-tooltip>
|
||||||
|
<template slot-scope="scope" v-if="scope.row.steps">
|
||||||
|
<el-tag v-for="item in scope.row.steps"
|
||||||
|
:key="item.number"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.number">{{item.name}}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="生产车间">
|
||||||
|
<template slot-scope="scope">{{ scope.row.workshop_.name }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="生产数量" prop="count">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="开工时间" prop="start_date">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="完工时间" prop="end_date">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="检验状态">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span v-if="scope.row.leader_1!==null&&scope.row.leader_2!==null&&scope.row.leader_3!==null">已完成</span>
|
||||||
|
<span v-else>未完成</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
align="center"
|
||||||
|
label="操作"
|
||||||
|
width="120px"
|
||||||
|
fixed="right"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-link
|
||||||
|
v-if="scope.row.first_test===null"
|
||||||
|
type="primary"
|
||||||
|
@click="handleTest(scope)"
|
||||||
|
>
|
||||||
|
首件检验
|
||||||
|
</el-link>
|
||||||
|
<el-link
|
||||||
|
v-else-if="scope.row.first_test!==null&&!scope.row.first_test_.is_submited"
|
||||||
|
type="primary"
|
||||||
|
@click="handleTestContinue(scope)"
|
||||||
|
>
|
||||||
|
检验
|
||||||
|
</el-link>
|
||||||
|
<el-link
|
||||||
|
v-else-if="scope.row.first_test_.is_submited&&(scope.row.leader_1===null||scope.row.leader_2===null||scope.row.leader_3===null)"
|
||||||
|
type="primary"
|
||||||
|
@click="handleSelectclick(scope,'0')"
|
||||||
|
>
|
||||||
|
首件审批
|
||||||
|
</el-link>
|
||||||
|
<el-link
|
||||||
|
v-else-if="scope.row.leader_1!==null&&scope.row.leader_2!==null&&scope.row.leader_3!==null"
|
||||||
|
type="primary"
|
||||||
|
@click="handleSelectclick(scope,'1')"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<pagination
|
||||||
|
:total="count"
|
||||||
|
:page.sync="listQuery.page"
|
||||||
|
:limit.sync="listQuery.page_size"
|
||||||
|
@pagination="getsList"
|
||||||
|
/>
|
||||||
|
</el-card>
|
||||||
|
<!--物料检查表&&-->
|
||||||
|
<el-dialog title="首件确认检查表" :close-on-click-modal="false" :visible.sync="listVisible">
|
||||||
|
<el-select style="width: 100%" v-model="recordForm" placeholder="请选择" @change="recordFormChange">
|
||||||
|
<el-option
|
||||||
|
v-for="item in recordFormList"
|
||||||
|
:key="item.name"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="listVisible = false">
|
||||||
|
取 消
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" @click="selectedRecordForm()">填写检查项目</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
<!--检查表显示-->
|
||||||
|
<el-dialog
|
||||||
|
width="60%"
|
||||||
|
:title="formName"
|
||||||
|
:visible.sync="recordVisible"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@close="recordCancel"
|
||||||
|
>
|
||||||
|
<customForm
|
||||||
|
v-if="recordVisible"
|
||||||
|
:results="fieldList"
|
||||||
|
:hasPicture="hasPicture"
|
||||||
|
:formID="recordForm"
|
||||||
|
:wproduct="recordFormQuery.material"
|
||||||
|
:recordId="recordId"
|
||||||
|
:isDisabled="isDisabled"
|
||||||
|
:isMidTesting="is_midtesting"
|
||||||
|
@recordSubmit="recordSubmit"
|
||||||
|
@recordSave="recordSave"
|
||||||
|
@recordCancel="recordCancel"
|
||||||
|
/>
|
||||||
|
</el-dialog>
|
||||||
|
<!--已完成检查表查后的审核-->
|
||||||
|
<el-dialog
|
||||||
|
title="首件确认审核"
|
||||||
|
:visible.sync="reviewVisible"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<el-row>
|
||||||
|
<el-col v-for="item in fieldList" :key="item.id+item.id" :span="12">
|
||||||
|
<div class="items" v-if="item.field_type!=='draw'&&item.field_value!==null&&item.field_value!==''">
|
||||||
|
<span class="itemLabel">{{item.field_name}}:</span>
|
||||||
|
<span>{{item.field_value}}</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="achieve">
|
||||||
|
<div class="items">
|
||||||
|
<span class="itemLabel">工序负责人:</span>
|
||||||
|
<span>{{leader_1}}</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="achieve">
|
||||||
|
<div class="items">
|
||||||
|
<span class="itemLabel">技术负责人:</span>
|
||||||
|
<span>{{leader_2}}</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="achieve">
|
||||||
|
<div class="items">
|
||||||
|
<span class="itemLabel">总检:</span>
|
||||||
|
<span>{{leader_3}}</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="achieve">
|
||||||
|
<div class="items">
|
||||||
|
<span class="itemLabel">首件检查时间:</span>
|
||||||
|
<span>{{update_time}}</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="achieve">
|
||||||
|
<div class="items">
|
||||||
|
<span class="itemLabel">首件审批时间:</span>
|
||||||
|
<span>{{first_sign_time}}</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-for="item in fieldList" :key="item.id" :span="24">
|
||||||
|
<div class="items" v-if="item.field_type==='draw'" style="height: 400px">
|
||||||
|
<span class="itemLabel">{{item.field_name}}:</span>
|
||||||
|
<img style="width: 45%;vertical-align: text-top;" :src="'http://47.95.0.242:2222'+item.field_value"/>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row class="reviewWrap" v-if="!achieve">
|
||||||
|
<div class="reviewBlock">
|
||||||
|
<span>工序负责人:</span>
|
||||||
|
<div class="directorName">{{leader_1}}</div>
|
||||||
|
<span class="reviewBtn" @click="directorConfirm('leader_1')">人脸验证</span>
|
||||||
|
</div>
|
||||||
|
<div class="reviewBlock">
|
||||||
|
<span>技术负责人:</span>
|
||||||
|
<div class="directorName">{{leader_2}}</div>
|
||||||
|
<span class="reviewBtn" @click="directorConfirm('leader_2')">人脸验证</span>
|
||||||
|
</div>
|
||||||
|
<div class="reviewBlock">
|
||||||
|
<span>总检:</span>
|
||||||
|
<div class="directorName">{{leader_3}}</div>
|
||||||
|
<span class="reviewBtn" @click="directorConfirm('leader_3')">人脸验证</span>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog :visible.sync="limitedPhoto" @close="closeCamera" id="loginFaceWrap">
|
||||||
|
<div style="font-size: 28px;color: #333333;text-align: center;font-weight: bold;">审核人员确认</div>
|
||||||
|
<div class="testTracking">
|
||||||
|
<faceLogin v-if="limitedPhoto" ref="faceTracking" name="faceLogin" @func="getMsgFormSon"></faceLogin>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import checkPermission from "@/utils/permission";
|
||||||
|
import Pagination from "@/components/Pagination";
|
||||||
|
import customForm from '@/components/customForm/index';
|
||||||
|
import faceLogin from '@/components/faceLogin/review.vue';
|
||||||
|
import {getProcessList,getrecordformList} from "@/api/mtm";
|
||||||
|
import {getsubproductionplanList,firstTestInit,firstAudit} from "@/api/pm";
|
||||||
|
import {getTestRecordItem,putTestRecordItem,subTestRecordItem} from "@/api/qm";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "firstCheck",
|
||||||
|
components: {Pagination,faceLogin,customForm},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
count: 0,
|
||||||
|
activeIndex: 0,
|
||||||
|
fieldList: [],
|
||||||
|
subPlanList: [],
|
||||||
|
processOption: [],
|
||||||
|
recordFormList: [],
|
||||||
|
listQuery:{
|
||||||
|
page:1,
|
||||||
|
page_size:20,
|
||||||
|
process: null,
|
||||||
|
},
|
||||||
|
recordFormQuery:{
|
||||||
|
type:50,
|
||||||
|
enabled:true,
|
||||||
|
material:null
|
||||||
|
},
|
||||||
|
planId:null,
|
||||||
|
leader:null,
|
||||||
|
recordId: null,
|
||||||
|
leader_1: null,
|
||||||
|
leader_2: null,
|
||||||
|
leader_3: null,
|
||||||
|
recordForm:null,
|
||||||
|
achieve:false,
|
||||||
|
hasPicture:false,
|
||||||
|
isDisabled: false,
|
||||||
|
listLoading:false,
|
||||||
|
listVisible:false,
|
||||||
|
limitedPhoto:false,
|
||||||
|
reviewVisible:false,
|
||||||
|
recordVisible:false,
|
||||||
|
is_midtesting:false,
|
||||||
|
formName:'首件确认检查表',
|
||||||
|
update_time:'',
|
||||||
|
first_sign_time:'',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
checkPermission,
|
||||||
|
//工序渲染
|
||||||
|
getProcessList() {
|
||||||
|
let that = this;
|
||||||
|
getProcessList({page: 0}).then((response) => {
|
||||||
|
if (response.data) {
|
||||||
|
that.processOption = response.data;
|
||||||
|
that.listQuery.process = response.data[0].id;
|
||||||
|
that.getTableData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//工序转换
|
||||||
|
changeIndex(item,index) {
|
||||||
|
this.activeIndex = index;
|
||||||
|
this.listQuery.process = item.id;
|
||||||
|
this.getTableData();
|
||||||
|
},
|
||||||
|
//获取table数据
|
||||||
|
getTableData() {
|
||||||
|
this.listLoading = true;
|
||||||
|
this.listQuery.production_plan = this.id;
|
||||||
|
getsubproductionplanList(this.listQuery).then((response) => {
|
||||||
|
if (response.data) {
|
||||||
|
this.subPlanList = response.data.results;
|
||||||
|
this.count = response.data.count;
|
||||||
|
}
|
||||||
|
this.listLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//分页
|
||||||
|
getsList(){},
|
||||||
|
//第一次点击首件检验
|
||||||
|
handleTest(scope){
|
||||||
|
let that = this;
|
||||||
|
that.planId = scope.row.id;//子生产计划ID
|
||||||
|
that.recordFormQuery.material = scope.row.product;
|
||||||
|
that.recordForm = null;
|
||||||
|
getrecordformList(that.recordFormQuery).then((response) => {
|
||||||
|
if (response.data) {
|
||||||
|
that.recordformList = response.data.results;
|
||||||
|
if (that.recordformList.length === 1) {
|
||||||
|
that.recordForm = that.recordformList[0].id;
|
||||||
|
that.formName = that.recordformList[0].name;
|
||||||
|
that.selectedRecordForm();
|
||||||
|
} else {
|
||||||
|
//弹出列表选择框
|
||||||
|
that.listVisible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//首件审批
|
||||||
|
handleSelectclick(scope,index){
|
||||||
|
let that = this;
|
||||||
|
this.reviewVisible = true;
|
||||||
|
that.planId = scope.row.id;
|
||||||
|
that.leader_1 = scope.row.leader_1_?scope.row.leader_1_.name:null;
|
||||||
|
that.leader_2 = scope.row.leader_2_?scope.row.leader_2_.name:null;
|
||||||
|
that.leader_3 = scope.row.leader_3_?scope.row.leader_3_.name:null;
|
||||||
|
that.first_sign_time = scope.row.first_sign_time?scope.row.first_sign_time:'';
|
||||||
|
getTestRecordItem(scope.row.first_test).then((res) => {
|
||||||
|
that.formName = res.data.form_.name;
|
||||||
|
that.update_time = res.data.update_time;
|
||||||
|
let fieldList = res.data.record_data;
|
||||||
|
that.fieldList = [...fieldList];
|
||||||
|
let arr = fieldList.filter(item => {
|
||||||
|
return item.field_type === 'draw'
|
||||||
|
});
|
||||||
|
if (arr.length > 0) {
|
||||||
|
that.hasPicture = true;
|
||||||
|
}
|
||||||
|
that.$nextTick(() => {
|
||||||
|
if(index==='1'){
|
||||||
|
this.achieve = true;
|
||||||
|
}else{
|
||||||
|
this.achieve = false;
|
||||||
|
}
|
||||||
|
that.reviewVisible = true;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
},
|
||||||
|
//选择物料检查表
|
||||||
|
recordFormChange() {
|
||||||
|
let that = this;
|
||||||
|
let arr = this.recordFormList.filter(item => {
|
||||||
|
return item.id === that.recordForm;
|
||||||
|
});
|
||||||
|
that.formName = arr[0].name;
|
||||||
|
},
|
||||||
|
//根据选择的表,渲染检查项目
|
||||||
|
selectedRecordForm() {
|
||||||
|
let that = this;
|
||||||
|
this.listVisible = false;
|
||||||
|
that.fieldList = [];
|
||||||
|
if (that.recordForm != "") {
|
||||||
|
firstTestInit(that.planId,{ form: that.recordForm}).then((response) => {
|
||||||
|
if (response.code===200) {
|
||||||
|
that.hasPicture = false;
|
||||||
|
that.recordId = response.data.id;//记录id
|
||||||
|
that.formName = response.data.form_.name;//引用的检查表id
|
||||||
|
let fieldList = response.data.record_data;
|
||||||
|
that.fieldList = [...fieldList];
|
||||||
|
let arr = fieldList.filter(item => {
|
||||||
|
return item.field_type === 'draw'
|
||||||
|
});
|
||||||
|
if (arr.length > 0) {
|
||||||
|
that.hasPicture = true;
|
||||||
|
}
|
||||||
|
that.$nextTick(() => {
|
||||||
|
that.recordVisible = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else this.$message.error("请选择检查表!");
|
||||||
|
},
|
||||||
|
//第一次保存提交检查项目
|
||||||
|
recordCancel() {
|
||||||
|
this.recordVisible = false;
|
||||||
|
this.listVisible = false;
|
||||||
|
this.getTableData();
|
||||||
|
},
|
||||||
|
/*关闭相机*/
|
||||||
|
closeCamera () {
|
||||||
|
this.$refs.faceTracking.closeCamera();
|
||||||
|
// this.thisVideo.srcObject.getTracks()[0].stop();
|
||||||
|
},
|
||||||
|
//保存首件检查
|
||||||
|
recordSave(value) {
|
||||||
|
let that = this;
|
||||||
|
let id = value.id;
|
||||||
|
let params = {};
|
||||||
|
params.record_data = value.record_data;
|
||||||
|
params.is_testok = value.is_testok;
|
||||||
|
putTestRecordItem(id, params).then((res) => {
|
||||||
|
if (res.code >= 200) {
|
||||||
|
that.recordVisible = false;
|
||||||
|
that.getTableData();
|
||||||
|
} else {
|
||||||
|
that.$message.error(res.msg)
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
// console.error(err);
|
||||||
|
that.$message.error(err)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//提交首件检查
|
||||||
|
recordSubmit(value) {
|
||||||
|
let that = this;
|
||||||
|
let id = value.id;
|
||||||
|
let params = {};
|
||||||
|
params.record_data = value.record_data;
|
||||||
|
params.is_testok = value.is_testok;
|
||||||
|
putTestRecordItem(id, params).then((res) => {
|
||||||
|
if (res.code >= 200) {
|
||||||
|
subTestRecordItem(id, params).then((res) => {
|
||||||
|
if (res.code >= 200) {
|
||||||
|
that.recordVisible = false;
|
||||||
|
that.getTableData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
that.$message.error(res.msg)
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
that.$message.error(err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//再次点击首件检验
|
||||||
|
handleTestContinue(scope) {
|
||||||
|
let that = this;
|
||||||
|
that.fieldList = [];
|
||||||
|
that.recordVisible = false;
|
||||||
|
that.planId = scope.row.id;
|
||||||
|
that.recordId = scope.row.first_test;
|
||||||
|
that.recordForm = scope.row.first_test_.form;
|
||||||
|
getTestRecordItem(scope.row.first_test).then((res) => {
|
||||||
|
that.formName = res.data.form_.name;
|
||||||
|
let fieldList = res.data.record_data;
|
||||||
|
that.fieldList = [...fieldList];
|
||||||
|
let arr = fieldList.filter(item => {
|
||||||
|
return item.field_type === 'draw'
|
||||||
|
});
|
||||||
|
if (arr.length > 0) {
|
||||||
|
that.hasPicture = true;
|
||||||
|
}
|
||||||
|
that.$nextTick(() => {
|
||||||
|
that.recordVisible = true;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
/*getrffieldList({form: this.recordform,enabled:true, page: 1, page_size: 100}).then((response) => {
|
||||||
|
if (response.data) {
|
||||||
|
that.hasPicture = false;
|
||||||
|
let fieldList = response.data.results;
|
||||||
|
that.fieldList = [...fieldList];
|
||||||
|
let arr = fieldList.filter(item => {
|
||||||
|
return item.field_type === 'draw'
|
||||||
|
});
|
||||||
|
if (arr.length > 0) {
|
||||||
|
that.hasPicture = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});*/
|
||||||
|
},
|
||||||
|
//点击人脸验证
|
||||||
|
directorConfirm(index){
|
||||||
|
this.leader = index;
|
||||||
|
this.limitedPhoto = true;
|
||||||
|
},
|
||||||
|
//获取人脸数据
|
||||||
|
getMsgFormSon(data){
|
||||||
|
let that =this;
|
||||||
|
if(that.leader==='leader_1'){
|
||||||
|
that.leader_1=data.name;
|
||||||
|
}else if(that.leader==='leader_2'){
|
||||||
|
that.leader_2=data.name;
|
||||||
|
}else if(that.leader==='leader_3'){
|
||||||
|
that.leader_3=data.name;
|
||||||
|
}
|
||||||
|
firstAudit(that.planId,{leader:that.leader ,token : data.token}).then(res=>{
|
||||||
|
if(res.code===200){
|
||||||
|
this.limitedPhoto = false;
|
||||||
|
if(that.leader_1!==null&&that.leader_2!==null&&that.leader_3!==null){
|
||||||
|
this.reviewVisible = false;
|
||||||
|
}
|
||||||
|
that.getTableData();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.getProcessList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tabButtonWrap{
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
border-bottom: 1px solid #EBEEF5;
|
||||||
|
}
|
||||||
|
.tabButton{
|
||||||
|
height: 40px;
|
||||||
|
width: 100px;
|
||||||
|
color: #555555;
|
||||||
|
line-height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid #EBEEF5;
|
||||||
|
border-radius: 10px 10px 0 0;
|
||||||
|
}
|
||||||
|
.activeTab {
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-weight: bold;
|
||||||
|
background: #409EFF;
|
||||||
|
}
|
||||||
|
.reviewWrap{
|
||||||
|
display: flex;
|
||||||
|
font-size: 16px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
.reviewBlock{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-right: 40px
|
||||||
|
}
|
||||||
|
.directorName{
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
.reviewBtn{
|
||||||
|
width: 80px;
|
||||||
|
height: 35px;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 33px;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid #409eff;
|
||||||
|
border-radius: 5px;
|
||||||
|
/*background: #409eff;*/
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
.items {
|
||||||
|
height: 35px;
|
||||||
|
line-height: 35px;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.itemLabel {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -30,7 +30,7 @@ class HRMService:
|
||||||
update_all_user_facedata_cache()
|
update_all_user_facedata_cache()
|
||||||
try:
|
try:
|
||||||
results = face_recognition.compare_faces(face_datas,
|
results = face_recognition.compare_faces(face_datas,
|
||||||
unknown_face_encoding, tolerance=0.5)
|
unknown_face_encoding, tolerance=0.48)
|
||||||
except:
|
except:
|
||||||
return None, '人脸匹配失败'
|
return None, '人脸匹配失败'
|
||||||
for index, value in enumerate(results):
|
for index, value in enumerate(results):
|
||||||
|
|
|
@ -29,4 +29,4 @@ class IProductFilterSet(DynamicFieldsFilterMixin, filters.FilterSet):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IProduct
|
model = IProduct
|
||||||
fields = ['material', 'warehouse', 'batch', 'order', 'material__type', 'update_time_start', 'update_time_end',
|
fields = ['material', 'warehouse', 'batch', 'order', 'material__type', 'update_time_start', 'update_time_end',
|
||||||
'to_order', 'need_to_order']
|
'to_order', 'need_to_order', 'state']
|
||||||
|
|
|
@ -95,6 +95,13 @@ class FIFOItemCreateSerializer(serializers.ModelSerializer):
|
||||||
if fifo.pu_order is not None:
|
if fifo.pu_order is not None:
|
||||||
raise ValidationError('非采购订单')
|
raise ValidationError('非采购订单')
|
||||||
return super().create(validated_data)
|
return super().create(validated_data)
|
||||||
|
|
||||||
|
def validate_batch(self, value):
|
||||||
|
if value == '':
|
||||||
|
return value
|
||||||
|
elif len(value) > 6:
|
||||||
|
return value
|
||||||
|
raise ValidationError('批次号错误')
|
||||||
|
|
||||||
class FIFOItemUpdateSerializer(serializers.ModelSerializer):
|
class FIFOItemUpdateSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -122,6 +129,13 @@ class FIFODetailInPurSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = FIFOItem
|
model = FIFOItem
|
||||||
fields = ['material', 'count', 'batch', 'details', 'warehouse']
|
fields = ['material', 'count', 'batch', 'details', 'warehouse']
|
||||||
|
|
||||||
|
def validate_batch(self, value):
|
||||||
|
if value == '':
|
||||||
|
return value
|
||||||
|
elif len(value) > 6:
|
||||||
|
return value
|
||||||
|
raise ValidationError('批次号错误')
|
||||||
|
|
||||||
|
|
||||||
class MaterialBatchQuerySerializer(serializers.Serializer):
|
class MaterialBatchQuerySerializer(serializers.Serializer):
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
|
from itertools import count
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
from apps.inm.models import FIFOItemProduct, IProduct, Inventory, MaterialBatch, FIFO, FIFOItem
|
from apps.inm.models import FIFOItemProduct, IProduct, Inventory, MaterialBatch, FIFO, FIFOItem, WareHouse
|
||||||
|
from apps.mtm.models import Material
|
||||||
|
from apps.sam.models import SalePack, SaleProduct
|
||||||
|
from django.db.models import Count
|
||||||
|
from django.db.models.aggregates import Sum
|
||||||
|
|
||||||
class InmService:
|
class InmService:
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -53,18 +58,19 @@ class InmService:
|
||||||
o1 = Inventory.objects.get(material=material, warehouse=warehouse)
|
o1 = Inventory.objects.get(material=material, warehouse=warehouse)
|
||||||
temp_count = o1.count - i.count
|
temp_count = o1.count - i.count
|
||||||
if temp_count < 0:
|
if temp_count < 0:
|
||||||
raise ValidationError('库存不足,操作失败')
|
raise ValidationError('仓库库存不足,操作失败')
|
||||||
o1.count = temp_count
|
o1.count = temp_count
|
||||||
o1.save()
|
o1.save()
|
||||||
|
print(i.batch)
|
||||||
o2 = MaterialBatch.objects.get(material=material, warehouse=warehouse, batch=i.batch)
|
o2 = MaterialBatch.objects.get(material=material, warehouse=warehouse, batch=i.batch)
|
||||||
temp_count = o2.count - i.count
|
temp_count = o2.count - i.count
|
||||||
if temp_count < 0:
|
if temp_count < 0:
|
||||||
raise ValidationError('库存不足,操作失败')
|
raise ValidationError('批次库存不足,操作失败')
|
||||||
o2.count = temp_count
|
o2.count = temp_count
|
||||||
o2.save()
|
o2.save()
|
||||||
temp_count = material.count - i.count
|
temp_count = material.count - i.count
|
||||||
if temp_count < 0:
|
if temp_count < 0:
|
||||||
raise ValidationError('库存不足,操作失败')
|
raise ValidationError('物料库存不足,操作失败')
|
||||||
material.count = temp_count
|
material.count = temp_count
|
||||||
material.save()
|
material.save()
|
||||||
|
|
||||||
|
@ -72,4 +78,64 @@ class InmService:
|
||||||
if instance.type == FIFO.FIFO_TYPE_DO_OUT:
|
if instance.type == FIFO.FIFO_TYPE_DO_OUT:
|
||||||
# 生产领料的情况直接从IProduct中删除
|
# 生产领料的情况直接从IProduct中删除
|
||||||
numbers = FIFOItemProduct.objects.filter(fifoitem=i).values_list('number', flat=True)
|
numbers = FIFOItemProduct.objects.filter(fifoitem=i).values_list('number', flat=True)
|
||||||
IProduct.objects.filter(number__in=numbers).delete()
|
IProduct.objects.filter(number__in=numbers).delete()
|
||||||
|
# 销售的话已经处理了
|
||||||
|
# elif instance.type == FIFO.FIFO_TYPE_SALE_OUT:
|
||||||
|
# ips = FIFOItemProduct.objects.filter(fifoitem=i).values_list('iproduct', flat=True)
|
||||||
|
# IProduct.objects.filter(id__in=ips).update(state=IProduct.SALED)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sale_out_audit(cls, fifo:FIFO):
|
||||||
|
sale = fifo.sale
|
||||||
|
saleps = SaleProduct.objects.filter(sale=sale, packnum__isnull=True, remark__isnull=True)
|
||||||
|
if saleps.exists():
|
||||||
|
raise ValidationError('存在未装箱的产品')
|
||||||
|
# 创建出库条目
|
||||||
|
ips = IProduct.objects.filter(sale_iproduct__sale=sale,
|
||||||
|
sale_iproduct__packnum__isnull=False)
|
||||||
|
ips.update(state=IProduct.SALED)
|
||||||
|
items = ips.values('warehouse', 'material', 'batch').annotate(total=Count('id'))
|
||||||
|
for i in items:
|
||||||
|
warehouse = WareHouse.objects.get(id=i['warehouse'])
|
||||||
|
material = Material.objects.get(id=i['material'])
|
||||||
|
fifoitem = FIFOItem()
|
||||||
|
fifoitem.need_test = False
|
||||||
|
fifoitem.warehouse = warehouse
|
||||||
|
fifoitem.material = material
|
||||||
|
fifoitem.count = i['total']
|
||||||
|
fifoitem.batch = i['batch']
|
||||||
|
fifoitem.fifo = fifo
|
||||||
|
fifoitem.save()
|
||||||
|
items_p = ips.filter(warehouse=warehouse, batch=i['batch'])
|
||||||
|
ipxs = []
|
||||||
|
for i in items_p:
|
||||||
|
# 创建出库明细半成品
|
||||||
|
ip = {}
|
||||||
|
ip['fifoitem'] = fifoitem
|
||||||
|
ip['number'] = i.number
|
||||||
|
ip['material'] = i.material
|
||||||
|
ip['iproduct'] = i
|
||||||
|
ipxs.append(FIFOItemProduct(**ip))
|
||||||
|
FIFOItemProduct.objects.bulk_create(ipxs)
|
||||||
|
|
||||||
|
# 装箱附件处理
|
||||||
|
# ml = SalePack.objects.filter(sale_product__iproduct = ips
|
||||||
|
# ).values('packitem__material').annotate(count=Sum('count'))
|
||||||
|
# for i in ml:
|
||||||
|
# material = Material.objects.get(id=i['material'])
|
||||||
|
|
||||||
|
|
||||||
|
# 更新动态产品表情况
|
||||||
|
from apps.wpm.models import WProduct
|
||||||
|
WProduct.objects.filter(id__in=ips.values_list('wproduct', flat=True)).update(
|
||||||
|
act_state=WProduct.WPR_ACT_STATE_SELLED)
|
||||||
|
|
||||||
|
# 变更销售记录实际发货数
|
||||||
|
sale.count_real = ips.count()
|
||||||
|
sale.save()
|
||||||
|
# 变更订单状态
|
||||||
|
order = sale.order
|
||||||
|
if order:
|
||||||
|
order.delivered_count = IProduct.objects.filter(sale_iproduct__sale__order=order
|
||||||
|
, sale_iproduct__packnum__isnull=False).count()
|
||||||
|
order.save()
|
|
@ -184,24 +184,27 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
|
||||||
return Response()
|
return Response()
|
||||||
|
|
||||||
@action(methods=['post'], detail=True, perms_map={'post': 'fifo_audit'}, serializer_class=serializers.Serializer)
|
@action(methods=['post'], detail=True, perms_map={'post': 'fifo_audit'}, serializer_class=serializers.Serializer)
|
||||||
|
@transaction.atomic
|
||||||
def audit(self, request, pk=None):
|
def audit(self, request, pk=None):
|
||||||
"""
|
"""
|
||||||
审核通过
|
审核通过
|
||||||
"""
|
"""
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
if not FIFOItem.objects.filter(fifo=obj).exists():
|
|
||||||
raise ValidationError('出入库条目为空')
|
|
||||||
for i in FIFOItem.objects.filter(fifo=obj, need_test=True):
|
|
||||||
if not i.is_testok:
|
|
||||||
raise APIException('未检验通过, 不可审核')
|
|
||||||
if obj.is_audited:
|
if obj.is_audited:
|
||||||
raise APIException('该入库记录已审核通过')
|
raise APIException('该入库记录已审核通过')
|
||||||
with transaction.atomic():
|
if obj.type == FIFO.FIFO_TYPE_SALE_OUT: # 如果是销售提货,需额外处理
|
||||||
obj.is_audited = True
|
InmService.sale_out_audit(obj)
|
||||||
obj.auditor = request.user
|
else:
|
||||||
obj.inout_date = timezone.now() # 也是审核日期
|
if not FIFOItem.objects.filter(fifo=obj).exists():
|
||||||
obj.save()
|
raise ValidationError('出入库条目为空')
|
||||||
InmService.update_inm(obj) # 更新库存
|
for i in FIFOItem.objects.filter(fifo=obj, need_test=True):
|
||||||
|
if not i.is_testok:
|
||||||
|
raise APIException('未检验通过, 不可审核')
|
||||||
|
obj.is_audited = True
|
||||||
|
obj.auditor = request.user
|
||||||
|
obj.inout_date = timezone.now() # 也是审核日期
|
||||||
|
obj.save()
|
||||||
|
InmService.update_inm(obj) # 更新库存
|
||||||
return Response()
|
return Response()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ class MaterialDetailSerializer(serializers.ModelSerializer):
|
||||||
objs = Process.objects.filter(subproduction_process__product=obj, subproduction_process__is_deleted=False, is_deleted=False).distinct().order_by('number')
|
objs = Process.objects.filter(subproduction_process__product=obj, subproduction_process__is_deleted=False, is_deleted=False).distinct().order_by('number')
|
||||||
return ProcessSimpleSerializer(instance=objs, many=True).data
|
return ProcessSimpleSerializer(instance=objs, many=True).data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PackItemSerializer(serializers.ModelSerializer):
|
class PackItemSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PackItem
|
model = PackItem
|
||||||
|
@ -42,7 +44,13 @@ class PackItemUpdateSerializer(serializers.ModelSerializer):
|
||||||
class MaterialSimpleSerializer(serializers.ModelSerializer):
|
class MaterialSimpleSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Material
|
model = Material
|
||||||
fields = ['id', 'name', 'number', 'unit','specification', 'type']
|
fields = ['id', 'name', 'number', 'unit','specification', 'type', 'count', 'count_safe']
|
||||||
|
|
||||||
|
class PackItemDetailSerializer(serializers.ModelSerializer):
|
||||||
|
material_ = MaterialSimpleSerializer(source='material', read_only=True)
|
||||||
|
class Meta:
|
||||||
|
model = PackItem
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
class ProcessSerializer(serializers.ModelSerializer):
|
class ProcessSerializer(serializers.ModelSerializer):
|
||||||
instruction_ = FileSimpleSerializer(source='instruction', read_only=True)
|
instruction_ = FileSimpleSerializer(source='instruction', read_only=True)
|
||||||
|
|
|
@ -272,6 +272,9 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
|
||||||
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=FirstTestAuditSerializer)
|
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=FirstTestAuditSerializer)
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def first_audit(self, request, pk=None):
|
def first_audit(self, request, pk=None):
|
||||||
|
"""
|
||||||
|
首件审核
|
||||||
|
"""
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
if obj.leader_1 and obj.leader_2 and obj.leader_3:
|
if obj.leader_1 and obj.leader_2 and obj.leader_3:
|
||||||
raise ValidationError('首件确认已完成')
|
raise ValidationError('首件确认已完成')
|
||||||
|
|
|
@ -97,6 +97,8 @@ class TestRecordDetailSerializer(serializers.ModelSerializer):
|
||||||
# record_data = TestRecordItemSerializer(source='item_test_record', read_only=True, many=True)
|
# record_data = TestRecordItemSerializer(source='item_test_record', read_only=True, many=True)
|
||||||
record_data = serializers.SerializerMethodField()
|
record_data = serializers.SerializerMethodField()
|
||||||
origin_test_ = TestRecordDetailBaseSerializer(source='origin_test', read_only=True)
|
origin_test_ = TestRecordDetailBaseSerializer(source='origin_test', read_only=True)
|
||||||
|
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
|
||||||
|
update_by_ = UserSimpleSerializer(source='update_by', read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TestRecord
|
model = TestRecord
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
# Generated by Django 3.2.9 on 2022-02-22 07:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mtm', '0049_auto_20220222_0944'),
|
||||||
|
('sam', '0013_auto_20220222_0941'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='saleproduct',
|
||||||
|
name='packnum',
|
||||||
|
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='装箱单号'),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='SalePack',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||||
|
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||||
|
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||||
|
('count', models.PositiveSmallIntegerField(verbose_name='打包数量')),
|
||||||
|
('packitem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.packitem', verbose_name='打包项目')),
|
||||||
|
('sale_product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sam.saleproduct', verbose_name='关联销售产品')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -94,7 +94,6 @@ class Sale(CommonADModel):
|
||||||
receiver_address = models.CharField('收获地址', null=True, blank=True, max_length=200)
|
receiver_address = models.CharField('收获地址', null=True, blank=True, max_length=200)
|
||||||
remark = models.CharField('备注', null=True, blank=True, max_length=200)
|
remark = models.CharField('备注', null=True, blank=True, max_length=200)
|
||||||
|
|
||||||
|
|
||||||
class SaleProduct(BaseModel):
|
class SaleProduct(BaseModel):
|
||||||
"""
|
"""
|
||||||
具体产品
|
具体产品
|
||||||
|
@ -117,6 +116,7 @@ class SalePack(BaseModel):
|
||||||
on_delete=models.CASCADE)
|
on_delete=models.CASCADE)
|
||||||
packitem = models.ForeignKey(PackItem, verbose_name='打包项目',
|
packitem = models.ForeignKey(PackItem, verbose_name='打包项目',
|
||||||
on_delete=models.CASCADE)
|
on_delete=models.CASCADE)
|
||||||
|
count = models.PositiveSmallIntegerField('打包数量')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ class CustomerCreateUpdateSerializer(serializers.ModelSerializer):
|
||||||
class CustomerSimpleSerializer(serializers.ModelSerializer):
|
class CustomerSimpleSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Customer
|
model = Customer
|
||||||
fields = ['id', 'name']
|
fields = ['id', 'name', 'address', 'contact', 'contact_phone']
|
||||||
|
|
||||||
class ContractSerializer(serializers.ModelSerializer):
|
class ContractSerializer(serializers.ModelSerializer):
|
||||||
customer_ = CustomerSimpleSerializer(source='customer', read_only=True)
|
customer_ = CustomerSimpleSerializer(source='customer', read_only=True)
|
||||||
|
|
|
@ -2,8 +2,9 @@ from rest_framework import serializers
|
||||||
from rest_framework import exceptions
|
from rest_framework import exceptions
|
||||||
from apps.inm.models import IProduct
|
from apps.inm.models import IProduct
|
||||||
from apps.inm.serializers import IProductListSerializer
|
from apps.inm.serializers import IProductListSerializer
|
||||||
from apps.mtm.serializers import MaterialSimpleSerializer
|
from apps.mtm.models import Material, PackItem
|
||||||
from apps.sam.models import Sale, SaleProduct
|
from apps.mtm.serializers import MaterialSimpleSerializer, PackItemDetailSerializer
|
||||||
|
from apps.sam.models import Sale, SalePack, SaleProduct
|
||||||
from apps.sam.serializers import CustomerSimpleSerializer, OrderSimpleSerializer
|
from apps.sam.serializers import CustomerSimpleSerializer, OrderSimpleSerializer
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
|
@ -60,4 +61,39 @@ class SaleProductCreateSerializer(serializers.ModelSerializer):
|
||||||
if order:
|
if order:
|
||||||
if sale.count+order.delivered_count>order.count:
|
if sale.count+order.delivered_count>order.count:
|
||||||
raise exceptions.APIException('超过订单所需数量')
|
raise exceptions.APIException('超过订单所需数量')
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
class SPackItemSerializer(serializers.ModelSerializer):
|
||||||
|
name = serializers.CharField(source='packitem.name', read_only=True)
|
||||||
|
specification = serializers.CharField(source='packitem.specification', read_only=True)
|
||||||
|
unit = serializers.CharField(source='packitem.unit', read_only=True)
|
||||||
|
material_ = MaterialSimpleSerializer(source='packitem.material', read_only=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = SalePack
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
class SaleProductPackDetailSerializer(serializers.ModelSerializer):
|
||||||
|
detail = serializers.SerializerMethodField()
|
||||||
|
class Meta:
|
||||||
|
model = SaleProduct
|
||||||
|
fields = ['packnum', 'detail', 'remark']
|
||||||
|
|
||||||
|
def get_detail(self, obj):
|
||||||
|
return SPackItemSerializer(instance=SalePack.objects.filter(sale_product=obj)
|
||||||
|
, many=True).data
|
||||||
|
|
||||||
|
class SPackItemCreateSerializer(serializers.Serializer):
|
||||||
|
id = serializers.PrimaryKeyRelatedField(queryset=SalePack.objects.all())
|
||||||
|
count = serializers.IntegerField()
|
||||||
|
|
||||||
|
class SaleProductPackSerializer(serializers.ModelSerializer):
|
||||||
|
detail = SPackItemCreateSerializer(many=True)
|
||||||
|
packnum = serializers.CharField(min_length=6)
|
||||||
|
class Meta:
|
||||||
|
model = SaleProduct
|
||||||
|
fields = ['packnum', 'detail', 'remark']
|
||||||
|
|
||||||
|
|
||||||
|
class SRemarkItemCreateSerializer(serializers.Serializer):
|
||||||
|
remark = serializers.CharField(min_length=6)
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
|
|
||||||
from rest_framework.mixins import ListModelMixin, DestroyModelMixin, CreateModelMixin, RetrieveModelMixin
|
from rest_framework.mixins import ListModelMixin, DestroyModelMixin, CreateModelMixin, RetrieveModelMixin
|
||||||
from rest_framework.viewsets import GenericViewSet
|
from rest_framework.viewsets import GenericViewSet
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse
|
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse
|
||||||
from apps.inm.services import InmService
|
from apps.inm.services import InmService
|
||||||
from apps.mtm.models import Material
|
from apps.mtm.models import Material, PackItem
|
||||||
from apps.sam.models import Sale, SaleProduct
|
from apps.sam.models import Sale, SalePack, SaleProduct
|
||||||
from apps.sam.serializers_sale import SaleCreateSerializer, SaleListSerializer, SaleProductCreateSerializer, SaleProductListSerializer
|
from apps.sam.serializers_sale import SRemarkItemCreateSerializer, SaleCreateSerializer, SaleListSerializer, SaleProductCreateSerializer, SaleProductListSerializer, SaleProductPackDetailSerializer, SaleProductPackSerializer
|
||||||
from rest_framework import exceptions
|
from rest_framework import exceptions
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
|
@ -41,7 +42,8 @@ class SaleViewSet(CreateUpdateModelAMixin, ListModelMixin, RetrieveModelMixin, C
|
||||||
if obj.is_audited:
|
if obj.is_audited:
|
||||||
raise exceptions.APIException('该销售记录已审核,不可删除')
|
raise exceptions.APIException('该销售记录已审核,不可删除')
|
||||||
obj.delete()
|
obj.delete()
|
||||||
IProduct.objects.filter(sale_iproduct__sale=obj).update()
|
IProduct.objects.filter(sale_iproduct__sale=obj).update(state=IProduct.SALE_OK)
|
||||||
|
return Response()
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
def create(self, request, *args, **kwargs):
|
||||||
data = request.data
|
data = request.data
|
||||||
|
@ -88,46 +90,10 @@ class SaleViewSet(CreateUpdateModelAMixin, ListModelMixin, RetrieveModelMixin, C
|
||||||
fifo.create_by = request.user
|
fifo.create_by = request.user
|
||||||
fifo.number = 'CK' + ranstr(7)
|
fifo.number = 'CK' + ranstr(7)
|
||||||
fifo.save()
|
fifo.save()
|
||||||
# 创建出库条目
|
|
||||||
# ips = IProduct.objects.filter(sale_iproduct__sale=obj)
|
|
||||||
# items = ips.values('warehouse', 'material', 'batch').annotate(total=Count('id'))
|
|
||||||
# for i in items:
|
|
||||||
# warehouse = WareHouse.objects.get(id=i['warehouse'])
|
|
||||||
# material = Material.objects.get(id=i['material'])
|
|
||||||
# fifoitem = FIFOItem()
|
|
||||||
# fifoitem.need_test = False
|
|
||||||
# fifoitem.warehouse = warehouse
|
|
||||||
# fifoitem.material = material
|
|
||||||
# fifoitem.count = i['total']
|
|
||||||
# fifoitem.batch = i['batch']
|
|
||||||
# fifoitem.fifo = fifo
|
|
||||||
# fifoitem.save()
|
|
||||||
# items_p = ips.filter(warehouse=warehouse, batch=i['batch'])
|
|
||||||
# ipxs = []
|
|
||||||
# for i in items_p:
|
|
||||||
# # 创建出库明细半成品
|
|
||||||
# ip = {}
|
|
||||||
# ip['fifoitem'] = fifoitem
|
|
||||||
# ip['number'] = i.number
|
|
||||||
# ip['material'] = i.material
|
|
||||||
# ip['iproduct'] = i
|
|
||||||
# ipxs.append(FIFOItemProduct(**ip))
|
|
||||||
# FIFOItemProduct.objects.bulk_create(ipxs)
|
|
||||||
|
|
||||||
# 更新动态产品表情况
|
|
||||||
# from apps.wpm.models import WProduct
|
|
||||||
# WProduct.objects.filter(iproduct_wproduct__sale_iproduct__sale=obj).update(
|
|
||||||
# act_state=WProduct.WPR_ACT_STATE_SELLED)
|
|
||||||
# 更新库存
|
|
||||||
# InmService.update_inm(fifo)
|
|
||||||
# 变更销售提货审核状态
|
|
||||||
obj.is_audited = True
|
obj.is_audited = True
|
||||||
obj.save()
|
obj.save()
|
||||||
# 变更订单状态
|
|
||||||
# if obj.order:
|
|
||||||
# order = obj.order
|
|
||||||
# order.delivered_count = order.delivered_count + obj.count
|
|
||||||
# order.save()
|
|
||||||
return Response()
|
return Response()
|
||||||
|
|
||||||
|
|
||||||
|
@ -157,4 +123,54 @@ class SaleProductViewSet(ListModelMixin, DestroyModelMixin, CreateModelMixin, Ge
|
||||||
obj.delete()
|
obj.delete()
|
||||||
sale.count = SaleProduct.objects.filter(sale=obj.sale).count()
|
sale.count = SaleProduct.objects.filter(sale=obj.sale).count()
|
||||||
sale.save()
|
sale.save()
|
||||||
|
return Response()
|
||||||
|
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
obj = self.get_object()
|
||||||
|
sale = obj.sale
|
||||||
|
if sale.is_audited:
|
||||||
|
raise exceptions.APIException('该销售记录已审核,不可添加产品')
|
||||||
|
return super().create(request, *args, **kwargs)
|
||||||
|
|
||||||
|
@action(methods=['get', 'post'], detail=True, perms_map={'post':'sale_pack', 'get':'*'}, serializer_class=SaleProductPackSerializer)
|
||||||
|
@transaction.atomic
|
||||||
|
def pack(self, request, pk=None):
|
||||||
|
"""
|
||||||
|
打包装箱
|
||||||
|
"""
|
||||||
|
obj = self.get_object()
|
||||||
|
if request.method == 'GET':
|
||||||
|
for i in PackItem.objects.filter(product=obj.iproduct.material, is_deleted=False):
|
||||||
|
SalePack.objects.get_or_create(sale_product=obj, packitem=i,
|
||||||
|
defaults={
|
||||||
|
"sale_product":obj,
|
||||||
|
"packitem":i,
|
||||||
|
"count":i.count
|
||||||
|
})
|
||||||
|
return Response(SaleProductPackDetailSerializer(instance=obj).data)
|
||||||
|
elif request.method == 'POST':
|
||||||
|
serializer = SaleProductPackSerializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
vdata = serializer.validated_data
|
||||||
|
obj.packnum = vdata['packnum']
|
||||||
|
obj.remark = vdata.get('remark', '')
|
||||||
|
for i in vdata['detail']:
|
||||||
|
pi = i['id']
|
||||||
|
pi.count = i['count']
|
||||||
|
pi.save()
|
||||||
|
obj.save()
|
||||||
|
return Response()
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=True, perms_map={'post':'sale_pack'}, serializer_class=SRemarkItemCreateSerializer)
|
||||||
|
@transaction.atomic
|
||||||
|
def remark(self, request, pk=None):
|
||||||
|
"""
|
||||||
|
不装箱备注
|
||||||
|
"""
|
||||||
|
obj = self.get_object()
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
vdata = serializer.validated_data
|
||||||
|
obj.remark = vdata['remark']
|
||||||
|
obj.save()
|
||||||
return Response()
|
return Response()
|
Loading…
Reference in New Issue