Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop

This commit is contained in:
shilixia 2021-12-03 15:18:55 +08:00
commit 58d1ccc9bf
17 changed files with 1303 additions and 426 deletions

View File

@ -44,5 +44,7 @@ export default {
top: 15px; top: 15px;
right: 18px; right: 18px;
} }
.bigDialog .el-dialog{
width: 70%!important;
}
</style> </style>

View File

@ -0,0 +1,594 @@
<template>
<div>
<el-form
ref="checkForm"
label-width="100px"
:model="checkForm"
>
<el-row>
<el-col
v-for="(item, $index) in formData"
v-show="filterBlock(item.parent,item.display_expression)"
:key="$index"
:span="12"
>
<el-form-item
v-if="item.field_type === 'string'"
:label="item.field_name"
>
<el-input
v-model="checkForm[item.field_key]"
placeholder="请输入"
@input="keyChange(item.field_key)"
/>
</el-form-item>
<el-form-item
v-else-if="item.field_type === 'int'"
:label="item.field_name"
>
<el-input
v-model="checkForm[item.field_key]"
type="number"
placeholder="请输入"
@input="keyChange(item.field_key)"
/>
</el-form-item>
<el-form-item
v-else-if="item.field_type === 'float'"
:label="item.field_name"
>
<el-input
v-model="checkForm[item.field_key]"
type="number"
placeholder="请输入"
@input="keyChange(item.field_key)"
/>
</el-form-item>
<el-form-item
v-else-if="item.field_type === 'date'"
:label="item.field_name"
>
<el-date-picker
v-model="checkForm[item.field_key]"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
@change="keyChange(item.field_key)"
/>
<!--</el-date-picker>-->
</el-form-item>
<el-form-item
v-else-if="item.field_type === 'datetime'"
:label="item.field_name"
>
<el-date-picker
v-model="checkForm[item.field_key]"
type="datetime"
placeholder="选择日期"
value-format="yyyy-MM-dd HH:mm:ss"
style="width: 100%"
@change="keyChange(item.field_key)"
/>
<!--</el-date-picker>-->
</el-form-item>
<el-form-item
v-else-if="item.field_type === 'select'"
:label="item.field_name"
>
<el-select
v-model="checkForm[item.field_key]"
style="width: 100%"
placeholder="请选择"
@change="keyChange(item.field_key)"
>
<el-option
v-for="item1 in item.field_choice"
:key="item1"
:label="item1"
:value="item1"
/>
<!--</el-option>-->
</el-select>
</el-form-item>
<el-form-item
v-else-if="item.field_type === 'selects'"
:label="item.field_name"
>
<el-select
v-model="checkForm[item.field_key]"
style="width: 100%"
multiple
placeholder="请选择"
>
<el-option
v-for="item1 in item.field_choice"
:key="item1"
:label="item1"
:value="item1"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row v-show="hasPicture">
<el-form-item label="图表">
<div>
<img id="canvasImg" src="./../../assets/glass.png" style="width:500px;height: 300px;display: none">
<div style="position: relative;display: flex;flex-direction: column;
border: 1px solid #DCDFE6;">
<canvas id="canvas" width="500" height="300">
您的浏览器不支持绘图请升级或更换浏览器
</canvas>
<input type="text" value="" class="hide" id="txt" placeholder="请输入文字">
<textarea class="hide" id="word" cols="15" rows="5" placeholder="请输入文字" autofocus></textarea>
<input id="inputV" type="hidden" value="1">
<div class="canvasBtnWrap">
<div class="canvasBtn" @click="error1">标记</div>
<div class="canvasBtn" @click="word1()">文字</div>
<div class="canvasBtn" @click="back()">回退</div>
<div class="canvasBtn" @click="saveTu()">保存</div>
</div>
<div id="res"></div>
</div>
</div>
</el-form-item>
</el-row>
<div style="text-align: right">
<el-button type="primary" @click="judgeForm">
合格验证
</el-button>
</div>
</el-form>
</div>
</template>
<script>
import { upFile } from "@/api/file";
let preDrawAry = [];
export default {
name: "index",
props: {
results:{
type:Array,
default: () => {
return []
}} ,
formID: {
type:Number,
default:0
},
hasPicture:{
type:Boolean,
default:false
}
},
mounted() {
let that = this;
this.form = this.formID;
// debugger;
// console.log(this.results);
this.formData=this.results;
this.formData=[...this.formData];
for(let i=0;i<this.results.length;i++){
let key = this.results[i].field_key;
that.checkForm[key]='';
that.$set(that.checkForm,key,'')
}
// debugger;
// console.log(that.checkForm);
let listJudge = this.formData.filter(item => {
return item.need_judge === true;
});
listJudge.forEach(item => {
let obj = new Object();
obj = item;
obj.judge = false;
that.judgeList.push(obj)
});
setTimeout(function(){
that.canvasInit();
},500);
},
data(){
return{
checkForm:{},
canvas:null,
ctx:null,
myCanvas_rect:null,
Txt:null,
word:null,
widths:0,
heights:0,
lineW:3,
colorF:"#e42343",
imgData:'',
canvasImg:'',
formData:[],//表单数组
judgeList:[],//判定数组
}
},
methods:{
filterBlock(parent,rule){
// debugger;
let that = this;
if(parent!==''&&parent!==null&&parent!==undefined){
if(rule!==''&&rule!==null&&rule!==undefined){
let reg = /\{(.+?)\}/g;
//let str = rule.replace(temp,'').replace('$','');//==''
//let y = that.checkForm[key];
if(rule.indexOf('||')>-1||rule.indexOf('&&')>-1){
let tam = '', arr = [];
if(rule.indexOf('||')>-1){
arr = rule.split('||');
}else{
arr = rule.split('&&');
}
for (let i = 0;i<arr.length;i++){
//获取判断依据
let a = '';
a = arr[i].replace(/`/g,'');
a = '`'+ a+'`';
let tem =a.match(reg)[0];
let ky = tem.replace(/\{|\}/g, '');//qipao
if(that.checkForm[ky]){
//替换变量
a = a.replace(ky, 'yyy');
let yyy = "'"+that.checkForm[ky]+"'";
if(eval(eval( a))){
tam += 'true';
}else{
tam += 'false';
}
}else{
tam += 'false';
}
}
let rea = true;
if(rule.indexOf('||')>-1){
if( tam.indexOf('true')>-1){
rea = true;
}else{
rea = false;
}
}else{
if( tam.indexOf('false')>-1){
rea = false;
}else{
rea = true;
}
}
return rea;
}else{
let temp =rule.match(reg)[0];
let key = temp.replace(/\{|\}/g, '');//qipao
let a = rule.replace(key, 'yy');
a = a.replace(key, 'yy');
let yy = "'"+that.checkForm[key]+"'";
return eval(eval(a));
// return eval("'"+y+"'"+str);
}
}else{
return false;
}
}else{
return true;
}
},
keyChange(key){
key;
this.$forceUpdate();
/* debugger;
let y = this.checkForm[key];
this.$set(this.checkForm,key,y);*/
// this.filterBlock();
},
/* base64ToFile */
canvasInit(){
let that = this;
preDrawAry = [];
that.canvas = document.getElementById('canvas');
that.ctx = that.canvas.getContext('2d');
that.myCanvas_rect = that.canvas.getBoundingClientRect();
that.Txt = document.getElementById('txt');
that.word = document.getElementById('word');
that.widths = that.myCanvas_rect.width;
that.heights = that.myCanvas_rect.height;
setTimeout(function(){
that.draw();
},500);
},
draw(){
let canvasImg = document.getElementById("canvasImg");
canvasImg.style.width = '500px';
canvasImg.style.height = '300px';
this.ctx.drawImage(canvasImg,0,0,500,300);
},
// 叉号
error1(){
let canvas1 = document.getElementById('canvas');
let ctx1 = canvas1.getContext('2d');
this.Txt.style.display="none";
document.getElementById('word').style.display="none";
ctx1.closePath();
canvas1.onmousedown=function () {
this.imgData= ctx1.getImageData(0,0,canvas1.width,canvas1.height);
preDrawAry.push(this.imgData);
ctx1.beginPath();
ctx1.strokeStyle = "#e42343";
ctx1.lineWidth = "3";
ctx1.lineJoin="round";
};
//鼠标按下的位置
canvas1.onmouseup=function (ev) {
let oldX = ev.offsetX;
let oldY = ev.offsetY;
ctx1.moveTo(oldX,oldY);
ctx1.lineTo(ev.offsetX+10,ev.offsetY+10);
ctx1.moveTo(ev.offsetX+10,ev.offsetY);
ctx1.lineTo(ev.offsetX,ev.offsetY+10);
ctx1.stroke();
};
this.ctx.closePath();
},
// 文字先写字
text(){
let canvas2 = document.getElementById('canvas');
let ctx2 = canvas2.getContext('2d');
let Txt2 = document.getElementById('txt');
Txt2.style.display="block";
document.getElementById('word').style.display="none";
ctx2.font="16px Microsoft Yahei";
canvas2.onmousedown=function (ev) {
this.imgData=ctx2.getImageData(0,0,canvas2.width,canvas2.height);
preDrawAry.push(this.imgData);
var v = Txt2.value;
// console.log(v);
if (v != '') {
var oldX = ev.offsetX;
var oldY = ev.offsetY;
// console.log(oldX,oldY);
ctx2.moveTo(oldX,oldY);
canvas2.onmouseup=function () {
ctx2.fillStyle=this.colorF;
ctx2.fillText(v,oldX,oldY);
canvas2.TextAutoLine(v,canvas2,oldX,oldY,20);
// Txt.value = "";
Txt2.style.display="none";
}
}
}
},
// 文字
word1(){
let canvas3 = document.getElementById('canvas');
let ctx3 = canvas3.getContext('2d');
let Txt3 = document.getElementById('txt');
let word3 = document.getElementById('word');
Txt3.style.display="none";
ctx3.font="16px Microsoft Yahei";
canvas3.onmousedown=function () {
ctx3.closePath();
}
canvas3.onmouseup=function (ev) {
var inputV= document.getElementById('inputV').value;
if(inputV == 1){
document.getElementById('word').focus();
// console.log(ev.offsetX,ev.offsetY);
var oldX = ev.offsetX;
var oldY = ev.offsetY;
word3.style.display="block";
word3.style.left=oldX+'px';
word3.style.top =oldY+'px';
word3.onblur=function () {
let v = word3.value;
if(v != '' && v != ' '){
this.imgData=ctx3.getImageData(0,0,canvas3.width,canvas3.height);
let img = ctx3.getImageData(0,0,canvas3.width,canvas3.height);
// debugger;
preDrawAry.push(img);
ctx3.moveTo(oldX,oldY);
ctx3.fillStyle="#e42343";
let lineWidth = 0;
let canvasWidth = canvas3.width;
let lastSubStrIndex= 0;
for(let i=0;i<v.length;i++){
lineWidth+=ctx3.measureText(v[i]).width;
if(lineWidth>canvasWidth-oldX){
ctx3.fillText(v.substring(lastSubStrIndex,i),oldX,(oldY+10));
oldY+=20;
lineWidth=0;
lastSubStrIndex=i;
}
if(i==v.length-1){
ctx3.fillText(v.substring(lastSubStrIndex,i+1),oldX,(oldY+10));
}
}
inputV ="2";
word3.value = "";
}
}
}
}
},
// 文字过长超出换行toDataURL()
canvasTextAutoLine(str,canvas,initX,initY,lineHeight){
let ctx = canvas.getContext("2d");
let lineWidth = 0;
let canvasWidth = canvas.width;
let lastSubStrIndex= 0;
for(let i=0;i<str.length;i++){
lineWidth+=ctx.measureText(str[i]).width;
if(lineWidth>canvasWidth-initX){
ctx.fillText(str.substring(lastSubStrIndex,i),initX,initY);
initY+=lineHeight;
lineWidth=0;
lastSubStrIndex=i;
}
if(i==str.length-1){
ctx.fillText(str.substring(lastSubStrIndex,i+1),initX,initY);
}
}
},
// 撤销
back(){
this.word.style.display="none";
this.Txt.style.display="none";
if(preDrawAry.length>0) {
var popData = preDrawAry.pop();
this.ctx.putImageData(popData, 0, 0);
}
},
// 回退一次
put(){
this.ctx.putImageData(this.imgData,0,0);
},
//保存
saveTu(){
this.word.style.display="none";
this.Txt.style.display="none";
let canvas = document.getElementById('canvas');
let image = new Image();
image = canvas.toDataURL('image/png');
this.canvasImg = image;
let file = this.base64ToFile(image);
let formData = new FormData();
formData.append('file', file);
upFile(formData).then((res) => {
res;
// console.log(res);
})
},
base64ToFile(baseUrl) {
let arr = baseUrl.split(',');
// let type = arr[0].match(/:(.*?);/)[1]; // 解锁图片类型
let bytes = atob(arr[1]); // 解码base64
let n = bytes .length;
let bufferArray = new Uint8Array(n);
while (n--) {
bufferArray[n] = bytes.charCodeAt(n);
}
// let fileOfBlob = new File([bufferArray], new Date()+'.jpg');
return new File([bufferArray ],'draw.jpg');
},
/* base64ToFile */
judgeForm(){
let that = this ,
reg = /\{(.+?)\}/g,
judgeList = this.judgeList;
for(let i=0;i<judgeList.length;i++){
let arr = [],str = '';
let item = judgeList[i].rule_expression.replace(/`/g,'');
if(item.indexOf('||')>-1){
arr = item.split('||');
}else if(item.indexOf('&&')>-1){
arr = item.split('&&');
}else{
arr.push(item);
}
//对每个条件进行判定如果符合
for (let i = 0;i<arr.length;i++){
//获取判断依据
let a = '`'+ arr[i]+'`';
let tem =a.match(reg)[0];
let ky = tem.replace(/\{|\}/g, '');//qipao
//有值时进行判断
if(that.checkForm[ky]!==''&&that.checkForm[ky]!==null&&that.checkForm[ky]!==undefined){
//替换变量
a = a.replace(ky, 'yyy');
let yyy = "'"+that.checkForm[ky]+"'";
// debugger;
if(eval(eval( a))){
str += 'true';
}else{
str += 'false';
}
}
}
if(str.indexOf('true')>-1){
that.judgeList[i].judge = true;
}else{
that.judgeList[i].judge = false;
}
}
let real = that.judgeList.filter(item=>{
return item.judge==true;
});
if(real.length>0){
alert("检验不合格!")
}else{
alert("检验合格!")
}
},
}
}
</script>
<style scoped>
canvas {
width:500px!important;
/*border: 1px solid #000000;*/
cursor: crosshair;
margin: auto;
}
.canvasBtnWrap {
display: flex;
/*flex-direction: column;*/
/*width: 80px;*/
/*padding-left: 20px;*/
justify-content: flex-end;
}
.canvasBtn {
width: 70px;
height: 35px;
line-height: 35px;
border: 1px solid #aaaaaa;
text-align: center;
border-radius: 15px;
margin-right: 10px;
margin-bottom: 10px;
}
.hide {
display: none;
}
#txt {
position: absolute;
top: 1%;
left: 1%;
width: 150px;
height: 30px;
border: 1px solid #e42343;
}
#word {
position: absolute;
width: 200px;
height: 70px;
padding: 0 2px;
background: none;
color: #e42343;
border: 1px dashed #b9b9b9;
}
#word::-webkit-input-placeholder {
color: #e42343;
}
#word::-moz-placeholder {
color: #e42343;
}
#word::placeholder {
color: #e42343;
}
#res {
display: inline-block;
}
</style>

View File

@ -85,113 +85,125 @@
</el-dialog> </el-dialog>
<!--表格展示--> <!--表格展示-->
<el-dialog <el-dialog
class="bigDialog"
:visible.sync="dialogVisibleForm" :visible.sync="dialogVisibleForm"
:close-on-click-modal="false" :close-on-click-modal="false"
:title="tableForm.name" :title="tableForm.name"
> >
<el-form ref="Forms" label-width="80px" :model="checkForm"> <customForm
<el-row :results="fieldList.results"
v-for="(item, $index) in fieldList.results" :hasPicture="hasPicture"
v-show="filterBlock(item.parent,item.rule_expression,item.need_judge)" :formID="formID"
:key="$index" @formFunc="formFunc"
> />
<!--<div v-if="item.field_type === 'img'">--> <!--<el-form ref="Forms" label-width="100px" :model="checkForm">
<el-form-item v-if="item.field_type === 'string'" :label="item.field_name"> <el-row>
<el-input <el-col
v-model="checkForm[item.field_key]" :span="12"
placeholder="请输入" v-for="(item, $index) in fieldList.results"
@input="keyChange(item.field_key)" v-show="filterBlock(item.parent,item.display_expression)"
/> :key="$index"
</el-form-item>
<el-form-item
v-else-if="item.field_type === 'int'"
:label="item.field_name"
> >
<el-input &lt;!&ndash;<div v-if="item.field_type === 'img'">&ndash;&gt;
v-model="checkForm[item.field_key]" <el-form-item v-if="item.field_type === 'string'" :label="item.field_name">
type="number" <el-input
placeholder="请输入" v-model="checkForm[item.field_key]"
@input="keyChange(item.field_key)" placeholder="请输入"
/> @input="keyChange(item.field_key)"
</el-form-item> />
<el-form-item </el-form-item>
v-else-if="item.field_type === 'float'" <el-form-item
:label="item.field_name" v-else-if="item.field_type === 'int'"
> :label="item.field_name"
<el-input
v-model="checkForm[item.field_key]"
type="number"
placeholder="请输入"
@input="keyChange(item.field_key)"
/>
</el-form-item>
<el-form-item
v-else-if="item.field_type === 'date'"
:label="item.field_name"
>
<el-date-picker
v-model="checkForm[item.field_key]"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
@change="keyChange(item.field_key)"
> >
</el-date-picker> <el-input
</el-form-item> v-model="checkForm[item.field_key]"
<el-form-item type="number"
v-else-if="item.field_type === 'datetime'" placeholder="请输入"
:label="item.field_name" @input="keyChange(item.field_key)"
> />
<el-date-picker </el-form-item>
v-model="checkForm[item.field_key]" <el-form-item
type="datetime" v-else-if="item.field_type === 'float'"
placeholder="选择日期" :label="item.field_name"
value-format="yyyy-MM-dd HH:mm:ss"
style="width: 100%"
@change="keyChange(item.field_key)"
> >
</el-date-picker> <el-input
</el-form-item> v-model="checkForm[item.field_key]"
<el-form-item type="number"
v-else-if="item.field_type === 'select'" placeholder="请输入"
:label="item.field_name" @input="keyChange(item.field_key)"
> />
<el-select </el-form-item>
v-model="checkForm[item.field_key]" <el-form-item
style="width: 100%" v-else-if="item.field_type === 'date'"
placeholder="请选择" :label="item.field_name"
@change="keyChange(item.field_key)"
> >
<el-option <el-date-picker
v-for="item1 in item.field_choice" v-model="checkForm[item.field_key]"
:key="item1" type="date"
:label="item1" placeholder="选择日期"
:value="item1" value-format="yyyy-MM-dd"
style="width: 100%"
@change="keyChange(item.field_key)"
> >
</el-option> </el-date-picker>
</el-select> </el-form-item>
</el-form-item> <el-form-item
<el-form-item v-else-if="item.field_type === 'datetime'"
v-else-if="item.field_type === 'selects'" :label="item.field_name"
:label="item.field_name"
>
<el-select
v-model="checkForm[item.field_key]"
style="width: 100%"
multiple
placeholder="请选择"
> >
<el-option <el-date-picker
v-for="item1 in item.field_choice" v-model="checkForm[item.field_key]"
:key="item1" type="datetime"
:label="item1" placeholder="选择日期"
:value="item1" value-format="yyyy-MM-dd HH:mm:ss"
style="width: 100%"
@change="keyChange(item.field_key)"
> >
</el-option> </el-date-picker>
</el-select> </el-form-item>
</el-form-item> <el-form-item
<el-form-item label="图表" v-else-if="item.field_type === 'draw'"> v-else-if="item.field_type === 'select'"
:label="item.field_name"
>
<el-select
v-model="checkForm[item.field_key]"
style="width: 100%"
placeholder="请选择"
@change="keyChange(item.field_key)"
>
<el-option
v-for="item1 in item.field_choice"
:key="item1"
:label="item1"
:value="item1"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item
v-else-if="item.field_type === 'selects'"
:label="item.field_name"
>
<el-select
v-model="checkForm[item.field_key]"
style="width: 100%"
multiple
placeholder="请选择"
>
<el-option
v-for="item1 in item.field_choice"
:key="item1"
:label="item1"
:value="item1"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row v-show="hasPicture">
<el-form-item label="图表">
<div> <div>
<img id="canvasImg" src="./../../assets/glass.png" style="width:300px;height: 200px;display: none"> <img id="canvasImg" src="./../../assets/glass.png" style="width:300px;height: 200px;display: none">
<div style="position: relative;display: flex"> <div style="position: relative;display: flex">
@ -204,7 +216,7 @@
<div class="canvasBtnWrap"> <div class="canvasBtnWrap">
<div class="canvasBtn" @click="error1">标记</div> <div class="canvasBtn" @click="error1">标记</div>
<div class="canvasBtn" @click="word1()">文字</div> <div class="canvasBtn" @click="word1()">文字</div>
<!--<button @click="restuya()">清除批注</button>--> &lt;!&ndash;<button @click="restuya()">清除批注</button>&ndash;&gt;
<div class="canvasBtn" @click="back()">回退</div> <div class="canvasBtn" @click="back()">回退</div>
<div class="canvasBtn" @click="saveTu()">保存</div> <div class="canvasBtn" @click="saveTu()">保存</div>
</div> </div>
@ -213,7 +225,12 @@
</div> </div>
</el-form-item> </el-form-item>
</el-row> </el-row>
</el-form> </el-form>-->
<!--<div style="text-align: right">-->
<!--<el-button type="primary" @click="judgeForm">-->
<!--合格验证-->
<!--</el-button>-->
<!--</div>-->
</el-dialog> </el-dialog>
</el-card> </el-card>
</el-col> </el-col>
@ -454,10 +471,13 @@
</el-form-item> </el-form-item>
!--> !-->
<el-form-item label="表达" v-if="field.need_judge === true"> <el-form-item label="判定" v-if="field.need_judge === true">
<el-input v-model="field.rule_expression" type="textarea"/> <el-input v-model="field.rule_expression" type="textarea"/>
</el-form-item> </el-form-item>
<el-form-item label="模板图片" v-if="field.field_type === 'img'"> <el-form-item label="展示表达式">
<el-input v-model="field.display_expression" type="textarea"/>
</el-form-item>
<el-form-item label="模板图片" v-if="field.field_type === 'draw'">
<el-upload <el-upload
class="avatar-uploader" class="avatar-uploader"
:action="upUrl" :action="upUrl"
@ -467,8 +487,8 @@
:before-upload="beforeAvatarUpload" :before-upload="beforeAvatarUpload"
:headers="upHeaders" :headers="upHeaders"
> >
<img v-if="field.draw_template" :src="field.draw_template" class="avatar" /> <img v-if="field.draw_template" :src="field.draw_template" class="avatar"/>
<i v-else class="el-icon-plus avatar-uploader-icon" /> <i v-else class="el-icon-plus avatar-uploader-icon"/>
</el-upload> </el-upload>
</el-form-item> </el-form-item>
<el-form-item label="排序" prop="sort"> <el-form-item label="排序" prop="sort">
@ -498,6 +518,7 @@
</template> </template>
<script> <script>
import customForm from '@/components/customForm/index'
import checkPermission from "@/utils/permission"; import checkPermission from "@/utils/permission";
import {getEquipmentAll} from "@/api/equipment"; import {getEquipmentAll} from "@/api/equipment";
import vueJsonEditor from "vue-json-editor"; import vueJsonEditor from "vue-json-editor";
@ -512,7 +533,7 @@
updaterffield, updaterffield,
deleterffield, deleterffield,
} from "@/api/mtm"; } from "@/api/mtm";
import { upFile } from "@/api/file"; import {upFile} from "@/api/file";
import {genTree} from "@/utils"; import {genTree} from "@/utils";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
import Treeselect from '@riophae/vue-treeselect' import Treeselect from '@riophae/vue-treeselect'
@ -527,7 +548,7 @@
const defaultfield = {}; const defaultfield = {};
let preDrawAry = []; let preDrawAry = [];
export default { export default {
components: {Pagination, vueJsonEditor, Treeselect}, components: {Pagination, vueJsonEditor, Treeselect, customForm},
data() { data() {
return { return {
step: defaultstep, step: defaultstep,
@ -535,6 +556,7 @@
upHeaders: upHeaders(), upHeaders: upHeaders(),
upUrl: upUrl(), upUrl: upUrl(),
fileList: [], fileList: [],
hasPicture: true,
listLoading: true, listLoading: true,
need_judge: false, need_judge: false,
dialogVisibles: false, dialogVisibles: false,
@ -562,8 +584,8 @@
dialogType1: "new", dialogType1: "new",
dialogVisible1: false, dialogVisible1: false,
tableForm: defaultrecordform, tableForm: defaultrecordform,
checkForm:{ checkForm: {
hhh:'', hhh: '',
}, },
listQueryrecordform: { listQueryrecordform: {
page: 1, page: 1,
@ -650,17 +672,19 @@
label: "生产记录", label: "生产记录",
}, },
], ],
canvas:null, canvas: null,
ctx:null, ctx: null,
myCanvas_rect:null, myCanvas_rect: null,
Txt:null, Txt: null,
word:null, word: null,
widths:0, formID: 0,
heights:0, widths: 0,
lineW:3, heights: 0,
colorF:"#e42343", lineW: 3,
imgData:'', colorF: "#e42343",
canvasImg:'', imgData: '',
canvasImg: '',
judgeList: [],
}; };
}, },
computed: {}, computed: {},
@ -670,6 +694,9 @@
this.recordformLists(); this.recordformLists();
}, },
methods: { methods: {
formFunc(value) {
this.dialogVisibleForm = value;
},
handleAvatarSuccess(res, file) { handleAvatarSuccess(res, file) {
this.field.draw_template = res.data.path; this.field.draw_template = res.data.path;
}, },
@ -680,81 +707,77 @@
} }
return isLt2M; return isLt2M;
}, },
keyChange(key){ keyChange(key) {
let y = this.checkForm[key]; let y = this.checkForm[key];
this.$set(this.checkForm,key,y); this.$set(this.checkForm, key, y);
this.fieldList.results=[...this.fieldList.results]; this.fieldList.results = [...this.fieldList.results];
this.filterBlock(); this.filterBlock();
}, },
filterBlock(parent,rule,judge){ filterBlock(parent, rule) {
let that = this; let that = this;
if(parent!==''&&parent!==null&&parent!==undefined){ if (parent !== '' && parent !== null && parent !== undefined) {
if(judge){ if (rule !== '' && rule !== null && rule !== undefined) {
if(rule!==''&&rule!==null&&rule!==undefined){ let reg = /\{(.+?)\}/g;
let reg = /\{(.+?)\}/g; //let str = rule.replace(temp,'').replace('$','');//==''
//let str = rule.replace(temp,'').replace('$','');//=='' //let y = that.checkForm[key];
//let y = that.checkForm[key]; if (rule.indexOf('||') > -1 || rule.indexOf('&&') > -1) {
if(rule.indexOf('||')>-1||rule.indexOf('&&')>-1){ let tam = '', arr = [];
let tam = '', arr = []; if (rule.indexOf('||') > -1) {
if(rule.indexOf('||')>-1){ arr = rule.split('||');
arr = rule.split('||'); } else {
}else{ arr = rule.split('&&');
arr = rule.split('&&'); }
} for (let i = 0; i < arr.length; i++) {
for (let i = 0;i<arr.length;i++){ //获取判断依据
//获取判断依据 let a = '';
let a = ''; a = arr[i].replace(/`/g, '');
a = arr[i].replace(/`/g,''); a = '`' + a + '`';
a = '`'+ a+'`'; let tem = a.match(reg)[0];
let tem =a.match(reg)[0]; let ky = tem.replace(/\{|\}/g, '');//qipao
let ky = tem.replace(/\{|\}/g, '');//qipao if (that.checkForm[ky]) {
if(that.checkForm[ky]){ //替换变量
//替换变量 a = a.replace(ky, 'yyy');
a = a.replace(ky, 'yyy'); let yyy = "'" + that.checkForm[ky] + "'";
let yyy = "'"+that.checkForm[ky]+"'"; if (eval(eval(a))) {
if(eval(eval( a))){ tam += 'true';
tam += 'true'; } else {
}else{ tam += 'false';
tam += 'false'; }
} } else {
}else{ tam += 'false';
tam += 'false';
}
}
let rea = true;
if(rule.indexOf('||')>-1){
if( tam.indexOf('true')>-1){
rea = true;
}else{
rea = false;
}
}else{
if( tam.indexOf('false')>-1){
rea = false;
}else{
rea = true;
}
}
return rea;
}else{
let temp =rule.match(reg)[0];
let key = temp.replace(/\{|\}/g, '');//qipao
let a = rule.replace(key, 'yy');
a = a.replace(key, 'yy');
let yy = "'"+that.checkForm[key]+"'";
return eval(eval(a));
// return eval("'"+y+"'"+str);
}
debugger;
}else{
return false;
}
}else{
return true;
} }
}else{ }
return true; let rea = true;
if (rule.indexOf('||') > -1) {
if (tam.indexOf('true') > -1) {
rea = true;
} else {
rea = false;
}
} else {
if (tam.indexOf('false') > -1) {
rea = false;
} else {
rea = true;
}
}
return rea;
} else {
let temp = rule.match(reg)[0];
let key = temp.replace(/\{|\}/g, '');//qipao
let a = rule.replace(key, 'yy');
a = a.replace(key, 'yy');
let yy = "'" + that.checkForm[key] + "'";
return eval(eval(a));
// return eval("'"+y+"'"+str);
}
debugger;
} else {
return false;
} }
} else {
return true;
}
}, },
checkValue() { checkValue() {
this.field.field_key = this.field.field_key.replace(/[^a-zA-Z]/g, ''); this.field.field_key = this.field.field_key.replace(/[^a-zA-Z]/g, '');
@ -774,23 +797,39 @@
that.listQueryfield.form = that.formID; that.listQueryfield.form = that.formID;
getrffieldList(that.listQueryfield).then((response) => { getrffieldList(that.listQueryfield).then((response) => {
if (response.data) { if (response.data) {
debugger; this.hasPicture = false;
that.fieldList = response.data; that.fieldList = response.data;
let list = response.data.results; let list = response.data.results;
for(let i=0;i<list.length;i++){ let arr = list.filter(item => {
return item.field_type === 'draw'
});
that.judgeList = [];
let listJudge = list.filter(item => {
return item.need_judge === true;
});
listJudge.forEach(item => {
let obj = new Object();
obj = item;
obj.judge = false;
that.judgeList.push(obj)
});
if (arr.length > 0) {
this.hasPicture = true;
}
for (let i = 0; i < list.length; i++) {
let key = list[i].field_key; let key = list[i].field_key;
that.checkForm[key]=''; that.checkForm[key] = '';
that.$set(that.checkForm,key,'') that.$set(that.checkForm, key, '')
} }
that.dialogVisibleForm = true; that.dialogVisibleForm = true;
setTimeout(function(){ /* setTimeout(function () {
that.canvasInit(); that.canvasInit();
},500); }, 500);*/
} }
}); });
that.fieldLists(); that.fieldLists();
}, },
canvasInit(){ /*canvasInit() {
let that = this; let that = this;
preDrawAry = []; preDrawAry = [];
that.canvas = document.getElementById('canvas'); that.canvas = document.getElementById('canvas');
@ -800,10 +839,10 @@
that.word = document.getElementById('word'); that.word = document.getElementById('word');
that.widths = that.myCanvas_rect.width; that.widths = that.myCanvas_rect.width;
that.heights = that.myCanvas_rect.height; that.heights = that.myCanvas_rect.height;
setTimeout(function(){ setTimeout(function () {
that.draw(); that.draw();
},500); }, 500);
}, },*/
checkPermission, checkPermission,
handleCurrentChange(row) { handleCurrentChange(row) {
@ -826,7 +865,7 @@
getrffieldList(that.listQueryfield).then((response) => { getrffieldList(that.listQueryfield).then((response) => {
if (response.data) { if (response.data) {
that.fieldList = response.data; that.fieldList = response.data;
that.fieldList.results=[...that.fieldList.results] that.fieldList.results = [...that.fieldList.results]
} }
}); });
}, },
@ -845,50 +884,50 @@
} }
}); });
}, },
draw(){ /*draw() {
let canvasImg = document.getElementById("canvasImg"); let canvasImg = document.getElementById("canvasImg");
canvasImg.style.width = '300px'; canvasImg.style.width = '300px';
canvasImg.style.height = '200px'; canvasImg.style.height = '200px';
this.ctx.drawImage(canvasImg,0,0,300,200); this.ctx.drawImage(canvasImg, 0, 0, 300, 200);
}, },
// 叉号 // 叉号
error1(){ error1() {
let canvas1 = document.getElementById('canvas'); let canvas1 = document.getElementById('canvas');
let ctx1 = canvas1.getContext('2d'); let ctx1 = canvas1.getContext('2d');
this.Txt.style.display="none"; this.Txt.style.display = "none";
document.getElementById('word').style.display="none"; document.getElementById('word').style.display = "none";
ctx1.closePath(); ctx1.closePath();
canvas1.onmousedown=function () { canvas1.onmousedown = function () {
this.imgData= ctx1.getImageData(0,0,canvas1.width,canvas1.height); this.imgData = ctx1.getImageData(0, 0, canvas1.width, canvas1.height);
preDrawAry.push(this.imgData); preDrawAry.push(this.imgData);
ctx1.beginPath(); ctx1.beginPath();
ctx1.strokeStyle = "#e42343"; ctx1.strokeStyle = "#e42343";
ctx1.lineWidth = "3"; ctx1.lineWidth = "3";
ctx1.lineJoin="round"; ctx1.lineJoin = "round";
}; };
//鼠标按下的位置 //鼠标按下的位置
canvas1.onmouseup=function (ev) { canvas1.onmouseup = function (ev) {
let oldX = ev.offsetX; let oldX = ev.offsetX;
let oldY = ev.offsetY; let oldY = ev.offsetY;
ctx1.moveTo(oldX,oldY); ctx1.moveTo(oldX, oldY);
ctx1.lineTo(ev.offsetX+10,ev.offsetY+10); ctx1.lineTo(ev.offsetX + 10, ev.offsetY + 10);
ctx1.moveTo(ev.offsetX+10,ev.offsetY); ctx1.moveTo(ev.offsetX + 10, ev.offsetY);
ctx1.lineTo(ev.offsetX,ev.offsetY+10); ctx1.lineTo(ev.offsetX, ev.offsetY + 10);
ctx1.stroke(); ctx1.stroke();
}; };
this.ctx.closePath(); this.ctx.closePath();
}, },
// 文字先写字 // 文字先写字
text(){ text() {
let canvas2 = document.getElementById('canvas'); let canvas2 = document.getElementById('canvas');
let ctx2 = canvas2.getContext('2d'); let ctx2 = canvas2.getContext('2d');
let Txt2 = document.getElementById('txt'); let Txt2 = document.getElementById('txt');
Txt2.style.display="block"; Txt2.style.display = "block";
document.getElementById('word').style.display="none"; document.getElementById('word').style.display = "none";
ctx2.font="16px Microsoft Yahei"; ctx2.font = "16px Microsoft Yahei";
canvas2.onmousedown=function (ev) { canvas2.onmousedown = function (ev) {
this.imgData=ctx2.getImageData(0,0,canvas2.width,canvas2.height); this.imgData = ctx2.getImageData(0, 0, canvas2.width, canvas2.height);
preDrawAry.push(this.imgData); preDrawAry.push(this.imgData);
var v = Txt2.value; var v = Txt2.value;
// console.log(v); // console.log(v);
@ -896,65 +935,65 @@
var oldX = ev.offsetX; var oldX = ev.offsetX;
var oldY = ev.offsetY; var oldY = ev.offsetY;
// console.log(oldX,oldY); // console.log(oldX,oldY);
ctx2.moveTo(oldX,oldY); ctx2.moveTo(oldX, oldY);
canvas2.onmouseup=function () { canvas2.onmouseup = function () {
ctx2.fillStyle=this.colorF; ctx2.fillStyle = this.colorF;
ctx2.fillText(v,oldX,oldY); ctx2.fillText(v, oldX, oldY);
canvas2.TextAutoLine(v,canvas2,oldX,oldY,20); canvas2.TextAutoLine(v, canvas2, oldX, oldY, 20);
// Txt.value = ""; // Txt.value = "";
Txt2.style.display="none"; Txt2.style.display = "none";
} }
} }
} }
}, },
// 文字 // 文字
word1(){ word1() {
let canvas3 = document.getElementById('canvas'); let canvas3 = document.getElementById('canvas');
let ctx3 = canvas3.getContext('2d'); let ctx3 = canvas3.getContext('2d');
let Txt3 = document.getElementById('txt'); let Txt3 = document.getElementById('txt');
let word3 = document.getElementById('word'); let word3 = document.getElementById('word');
Txt3.style.display="none"; Txt3.style.display = "none";
ctx3.font="16px Microsoft Yahei"; ctx3.font = "16px Microsoft Yahei";
canvas3.onmousedown=function () { canvas3.onmousedown = function () {
ctx3.closePath(); ctx3.closePath();
} }
canvas3.onmouseup=function (ev) { canvas3.onmouseup = function (ev) {
var inputV= document.getElementById('inputV').value; var inputV = document.getElementById('inputV').value;
if(inputV == 1){ if (inputV == 1) {
document.getElementById('word').focus(); document.getElementById('word').focus();
// console.log(ev.offsetX,ev.offsetY); // console.log(ev.offsetX,ev.offsetY);
var oldX = ev.offsetX; var oldX = ev.offsetX;
var oldY = ev.offsetY; var oldY = ev.offsetY;
word3.style.display="block"; word3.style.display = "block";
word3.style.left=oldX+'px'; word3.style.left = oldX + 'px';
word3.style.top =oldY+'px'; word3.style.top = oldY + 'px';
word3.onblur=function () { word3.onblur = function () {
let v = word3.value; let v = word3.value;
if(v != '' && v != ' '){ if (v != '' && v != ' ') {
this.imgData=ctx3.getImageData(0,0,canvas3.width,canvas3.height); this.imgData = ctx3.getImageData(0, 0, canvas3.width, canvas3.height);
let img = ctx3.getImageData(0,0,canvas3.width,canvas3.height); let img = ctx3.getImageData(0, 0, canvas3.width, canvas3.height);
debugger; debugger;
preDrawAry.push(img); preDrawAry.push(img);
ctx3.moveTo(oldX,oldY); ctx3.moveTo(oldX, oldY);
ctx3.fillStyle="#e42343"; ctx3.fillStyle = "#e42343";
let lineWidth = 0; let lineWidth = 0;
let canvasWidth = canvas3.width; let canvasWidth = canvas3.width;
let lastSubStrIndex= 0; let lastSubStrIndex = 0;
for(let i=0;i<v.length;i++){ for (let i = 0; i < v.length; i++) {
lineWidth+=ctx3.measureText(v[i]).width; lineWidth += ctx3.measureText(v[i]).width;
if(lineWidth>canvasWidth-oldX){ if (lineWidth > canvasWidth - oldX) {
ctx3.fillText(v.substring(lastSubStrIndex,i),oldX,(oldY+10)); ctx3.fillText(v.substring(lastSubStrIndex, i), oldX, (oldY + 10));
oldY+=20; oldY += 20;
lineWidth=0; lineWidth = 0;
lastSubStrIndex=i; lastSubStrIndex = i;
} }
if(i==v.length-1){ if (i == v.length - 1) {
ctx3.fillText(v.substring(lastSubStrIndex,i+1),oldX,(oldY+10)); ctx3.fillText(v.substring(lastSubStrIndex, i + 1), oldX, (oldY + 10));
} }
} }
inputV ="2"; inputV = "2";
word3.value = ""; word3.value = "";
} }
} }
@ -963,50 +1002,50 @@
}, },
// 文字过长超出换行toDataURL() // 文字过长超出换行toDataURL()
canvasTextAutoLine(str,canvas,initX,initY,lineHeight){ canvasTextAutoLine(str, canvas, initX, initY, lineHeight) {
let ctx = canvas.getContext("2d"); let ctx = canvas.getContext("2d");
let lineWidth = 0; let lineWidth = 0;
let canvasWidth = canvas.width; let canvasWidth = canvas.width;
let lastSubStrIndex= 0; let lastSubStrIndex = 0;
for(let i=0;i<str.length;i++){ for (let i = 0; i < str.length; i++) {
lineWidth+=ctx.measureText(str[i]).width; lineWidth += ctx.measureText(str[i]).width;
if(lineWidth>canvasWidth-initX){ if (lineWidth > canvasWidth - initX) {
ctx.fillText(str.substring(lastSubStrIndex,i),initX,initY); ctx.fillText(str.substring(lastSubStrIndex, i), initX, initY);
initY+=lineHeight; initY += lineHeight;
lineWidth=0; lineWidth = 0;
lastSubStrIndex=i; lastSubStrIndex = i;
} }
if(i==str.length-1){ if (i == str.length - 1) {
ctx.fillText(str.substring(lastSubStrIndex,i+1),initX,initY); ctx.fillText(str.substring(lastSubStrIndex, i + 1), initX, initY);
} }
} }
}, },
/* // 删除批注 /!* // 删除批注
restuya(){ restuya(){
this.word.style.display="none"; this.word.style.display="none";
this.Txt.style.display="none"; this.Txt.style.display="none";
this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height); this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);
window.location.reload(); window.location.reload();
},*/ },*!/
// 撤销 // 撤销
back(){ back() {
this.word.style.display="none"; this.word.style.display = "none";
this.Txt.style.display="none"; this.Txt.style.display = "none";
if(preDrawAry.length>0) { if (preDrawAry.length > 0) {
var popData = preDrawAry.pop(); var popData = preDrawAry.pop();
this.ctx.putImageData(popData, 0, 0); this.ctx.putImageData(popData, 0, 0);
} }
}, },
// 回退一次 // 回退一次
put(){ put() {
this.ctx.putImageData(this.imgData,0,0); this.ctx.putImageData(this.imgData, 0, 0);
}, },
//保存 //保存
saveTu(){ saveTu() {
let canvas = document.getElementById('canvas'); let canvas = document.getElementById('canvas');
let image = new Image(); let image = new Image();
image = canvas.toDataURL('image/png'); image = canvas.toDataURL('image/png');
@ -1024,15 +1063,73 @@
let arr = baseUrl.split(','); let arr = baseUrl.split(',');
// let type = arr[0].match(/:(.*?);/)[1]; // 解锁图片类型 // let type = arr[0].match(/:(.*?);/)[1]; // 解锁图片类型
let bytes = atob(arr[1]); // 解码base64 let bytes = atob(arr[1]); // 解码base64
let n = bytes .length; let n = bytes.length;
let bufferArray = new Uint8Array(n); let bufferArray = new Uint8Array(n);
while (n--) { while (n--) {
bufferArray[n] = bytes.charCodeAt(n); bufferArray[n] = bytes.charCodeAt(n);
} }
// let fileOfBlob = new File([bufferArray], new Date()+'.jpg'); // let fileOfBlob = new File([bufferArray], new Date()+'.jpg');
return new File([bufferArray ],'draw.jpg'); return new File([bufferArray], 'draw.jpg');
}, },
judgeForm() {
let that = this,
reg = /\{(.+?)\}/g,
judgeList = this.judgeList;
debugger;
console.log(judgeList);
for (let i = 0; i < judgeList.length; i++) {
let arr = [], str = '';
let item = judgeList[i].rule_expression.replace(/`/g, '');
if (item.indexOf('||') > -1) {
arr = item.split('||');
} else if (item.indexOf('&&') > -1) {
arr = item.split('&&');
} else {
arr.push(item);
}
debugger;
console.log(arr);
//对每个条件进行判定如果符合
for (let i = 0; i < arr.length; i++) {
//获取判断依据
let a = '`' + arr[i] + '`';
let tem = a.match(reg)[0];
let ky = tem.replace(/\{|\}/g, '');//qipao
debugger;
console.log(that.checkForm[ky]);
//有值时进行判断
if (that.checkForm[ky] !== '' && that.checkForm[ky] !== null && that.checkForm[ky] !== undefined) {
//替换变量
a = a.replace(ky, 'yyy');
let yyy = "'" + that.checkForm[ky] + "'";
debugger;
if (eval(eval(a))) {
str += 'true';
} else {
str += 'false';
}
}
}
debugger;
console.log(str);
if (str.indexOf('true') > -1) {
that.judgeList[i].judge = true;
} else {
that.judgeList[i].judge = false;
}
}
let real = that.judgeList.filter(item => {
return item.judge == true;
});
debugger;
console.log(that.judgeList);
console.log(real);
if (real.length > 0) {
alert("检验不合格!")
} else {
alert("检验合格!")
}
},*/
//新增记录表 //新增记录表
handleCreate() { handleCreate() {
this.recordform = Object.assign({}, defaultrecordform); this.recordform = Object.assign({}, defaultrecordform);
@ -1177,55 +1274,5 @@
.my-content { .my-content {
background: #fde2e2; background: #fde2e2;
} }
canvas{
border:1px solid #000000;
cursor: crosshair;
}
.canvasBtnWrap{
display: flex;
flex-direction: column;
width: 80px;
padding-left: 20px;
justify-content: space-between;
}
.canvasBtn{
width: 70px;
height: 35px;
line-height: 35px;
border: 1px solid #aaaaaa;
text-align: center;
border-radius: 15px;
}
.hide{
display: none;
}
#txt{
position: absolute;
top: 1%;
left: 1%;
width: 150px;
height: 30px;
border:1px solid #e42343;
}
#word{
position: absolute;
width: 150px;
height: 70px;
padding: 0 2px;
background:none;
color:#e42343;
border: 1px dashed #b9b9b9;
}
#word::-webkit-input-placeholder{
color:#e42343;
}
#word::-moz-placeholder{
color:#e42343;
}
#word::placeholder{
color:#e42343;
}
#res{
display: inline-block;
}
</style> </style>

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2021-12-03 01:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mtm', '0040_material_piece_count'),
]
operations = [
migrations.AlterField(
model_name='material',
name='type',
field=models.PositiveSmallIntegerField(choices=[(1, '成品'), (2, '半成品'), (3, '主要原料'), (4, '辅助材料'), (5, '加工工具'), (6, '辅助工装')], default=1, verbose_name='物料类型'),
),
]

View File

@ -36,7 +36,7 @@ class Material(CommonAModel):
name = models.CharField('物料名称', max_length=100) name = models.CharField('物料名称', max_length=100)
number = models.CharField('编号', max_length=100, unique=True) number = models.CharField('编号', max_length=100, unique=True)
specification = models.CharField('型号', max_length=100, null=True, blank=True) specification = models.CharField('型号', max_length=100, null=True, blank=True)
type = models.CharField('物料类型', choices= type_choices, max_length=20, default=1) type = models.PositiveSmallIntegerField('物料类型', choices= type_choices, default=1)
sort_str = models.CharField('排序字符', max_length=100, null=True, blank=True) sort_str = models.CharField('排序字符', max_length=100, null=True, blank=True)
unit = models.CharField('基准计量单位', choices=unit_choices, default='', max_length=10) unit = models.CharField('基准计量单位', choices=unit_choices, default='', max_length=10)
count = models.IntegerField('物料总数', default=0) count = models.IntegerField('物料总数', default=0)

View File

@ -42,7 +42,7 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
queryset = ProductionPlan.objects.select_related('order', 'order__contract', 'product') queryset = ProductionPlan.objects.select_related('order', 'order__contract', 'product')
serializer_class = ProductionPlanSerializer serializer_class = ProductionPlanSerializer
search_fields = ['number'] search_fields = ['number']
filterset_fields = [] filterset_fields = ['product', 'order']
ordering_fields = ['id'] ordering_fields = ['id']
ordering = ['-id'] ordering = ['-id']

View File

@ -0,0 +1,30 @@
# Generated by Django 3.2.9 on 2021-12-02 08:20
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0040_material_piece_count'),
('qm', '0012_alter_testrecorditem_field_type'),
]
operations = [
migrations.AddField(
model_name='testrecord',
name='step',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.step', verbose_name='关联的工序步骤'),
),
migrations.AddField(
model_name='testrecord',
name='test_record',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='qm.testrecord', verbose_name='关联检验记录'),
),
migrations.AddField(
model_name='testrecord',
name='type',
field=models.PositiveSmallIntegerField(choices=[(10, '子工序检验'), (20, '工序检验'), (30, '工序复检'), (40, '成品检验')], default=20),
),
]

View File

@ -47,14 +47,27 @@ class TestRecord(CommonAModel):
""" """
检验记录 检验记录
""" """
TEST_STEP = 10
TEST_PROCESS = 20
TEST_PROCESS_RE = 30
TEST_FINAL = 40
type_choice = (
(TEST_STEP, '子工序检验'),
(TEST_PROCESS, '工序检验'),
(TEST_PROCESS_RE, '工序复检'),
(TEST_FINAL, '成品检验')
)
form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE) form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE)
type = models.PositiveSmallIntegerField(choices=type_choice, default=TEST_PROCESS)
is_testok = models.BooleanField('是否合格', default=True) is_testok = models.BooleanField('是否合格', default=True)
is_testok_robot = models.BooleanField('自动判定的是否合格', default=True) is_testok_robot = models.BooleanField('自动判定的是否合格', default=True)
number = models.CharField('产品编号', null=True, blank=True, max_length=50) number = models.CharField('产品编号', null=True, blank=True, max_length=50)
wproduct = models.ForeignKey('wpm.wproduct', verbose_name='关联的动态产品', on_delete=models.CASCADE, null=True, blank=True) wproduct = models.ForeignKey('wpm.wproduct', verbose_name='关联的动态产品', on_delete=models.CASCADE, null=True, blank=True)
material = models.ForeignKey('mtm.material', verbose_name='关联的物料状态', on_delete=models.CASCADE, null=True, blank=True) material = models.ForeignKey('mtm.material', verbose_name='关联的物料状态', on_delete=models.CASCADE, null=True, blank=True)
step = models.ForeignKey('mtm.step', verbose_name='关联的工序步骤', on_delete=models.CASCADE, null=True, blank=True)
subproduction_plan = models.ForeignKey('pm.subproductionplan', verbose_name='关联的生产子计划', on_delete=models.CASCADE, null=True, blank=True) subproduction_plan = models.ForeignKey('pm.subproductionplan', verbose_name='关联的生产子计划', on_delete=models.CASCADE, null=True, blank=True)
fifo_item = models.ForeignKey('inm.fifoitem', verbose_name='关联的出入库批次', on_delete=models.CASCADE, null=True, blank=True) fifo_item = models.ForeignKey('inm.fifoitem', verbose_name='关联的出入库批次', on_delete=models.CASCADE, null=True, blank=True)
test_record = models.ForeignKey('self', verbose_name='关联检验记录', on_delete=models.CASCADE, null=True, blank=True)
remark = models.TextField('备注', default='') remark = models.TextField('备注', default='')

View File

@ -50,7 +50,7 @@ class OrderViewSet(CreateUpdateCustomMixin, ModelViewSet):
queryset = Order.objects.select_related('contract', 'customer').all() queryset = Order.objects.select_related('contract', 'customer').all()
serializer_class = OrderSerializer serializer_class = OrderSerializer
search_fields = ['number', 'product'] search_fields = ['number', 'product']
filterset_fields = [] filterset_fields = ['product', 'contract', 'customer']
ordering_fields = ['create_time'] ordering_fields = ['create_time']
ordering = ['-create_time'] ordering = ['-create_time']

View File

@ -210,6 +210,18 @@ class Ticket(CommonBModel):
act_state = models.IntegerField('进行状态', default=1, help_text='当前工单的进行状态', choices=act_state_choices) act_state = models.IntegerField('进行状态', default=1, help_text='当前工单的进行状态', choices=act_state_choices)
multi_all_person = models.JSONField('全部处理的结果', default=dict, blank=True, help_text='需要当前状态处理人全部处理时实际的处理结果json格式') multi_all_person = models.JSONField('全部处理的结果', default=dict, blank=True, help_text='需要当前状态处理人全部处理时实际的处理结果json格式')
class TicketData():
"""
工单数据,自定义字段值
"""
form_field = models.ForeignKey(CustomField, verbose_name='关联字段', on_delete=models.SET_NULL, db_constraint=False, null=True, blank=True)
field_name = models.CharField('字段名', max_length=50)
field_key = models.CharField('字段标识', max_length=50)
field_type = models.CharField('字段类型', choices=CustomField.field_type_choices, max_length=50)
field_value = models.JSONField('录入值', default=dict, blank=True)
sort = models.IntegerField('排序号', default=1)
class TicketFlow(BaseModel): class TicketFlow(BaseModel):
""" """
工单流转日志 工单流转日志

View File

@ -52,7 +52,7 @@ class TicketCreateSerializer(serializers.ModelSerializer):
transition = serializers.IntegerField(label='流转ID') transition = serializers.IntegerField(label='流转ID')
class Meta: class Meta:
model=Ticket model=Ticket
fields=['title','workflow','ticket_data', 'transition'] fields=['title','workflow', 'ticket_data', 'transition']
def create(self, validated_data): def create(self, validated_data):
validated_data.pop('transition') validated_data.pop('transition')

View File

@ -0,0 +1,54 @@
# Generated by Django 3.2.9 on 2021-12-02 01:54
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('inm', '0019_auto_20211201_1011'),
('pm', '0015_auto_20211122_1556'),
('mtm', '0040_material_piece_count'),
('wpm', '0026_auto_20211201_1608'),
]
operations = [
migrations.CreateModel(
name='Pick',
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='删除标记')),
('type', models.PositiveSmallIntegerField(choices=[(10, '仓库领取'), (20, '半成品领取')], default=10)),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='pick_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('fifo', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='inm.fifo', verbose_name='关联的出入库记录')),
('subproduction_plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='关联子生产计划')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='pick_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='PickWproduct',
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='删除标记')),
('number', models.CharField(blank=True, max_length=50, null=True, verbose_name='物品编号')),
('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='领取时的物料状态')),
('pick', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.pick', verbose_name='关联领料')),
('subproduction_plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='领取时所属子生产计划')),
('wproduct', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='pw_wproduct', to='wpm.wproduct', verbose_name='关联半成品')),
],
options={
'abstract': False,
},
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.9 on 2021-12-02 08:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wpm', '0027_pick_pickwproduct'),
]
operations = [
migrations.AlterField(
model_name='wproduct',
name='act_state',
field=models.IntegerField(choices=[(6, '待复检'), (8, '操作准备中'), (10, '操作进行中'), (20, '待检验'), (30, '已合格'), (40, '库存中'), (50, '不合格'), (60, '待成品检验')], default=0, verbose_name='进行状态'),
),
migrations.AlterField(
model_name='wproduct',
name='is_executed',
field=models.BooleanField(default=False, verbose_name='是否执行'),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.9 on 2021-12-02 08:30
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wpm', '0028_auto_20211202_1620'),
]
operations = [
migrations.RemoveField(
model_name='wproduct',
name='is_executed',
),
migrations.AlterField(
model_name='wproduct',
name='operation',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wp_operation', to='wpm.operation', verbose_name='关联操作'),
),
]

View File

@ -3,7 +3,7 @@ from django.db import models
from django.db.models.base import Model from django.db.models.base import Model
import django.utils.timezone as timezone import django.utils.timezone as timezone
from django.db.models.query import QuerySet from django.db.models.query import QuerySet
from apps.inm.models import WareHouse from apps.inm.models import FIFO, WareHouse
from apps.pm.models import ProductionPlan, SubProductionPlan, SubProductionProgress from apps.pm.models import ProductionPlan, SubProductionPlan, SubProductionProgress
from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File
from utils.model import SoftModel, BaseModel from utils.model import SoftModel, BaseModel
@ -20,12 +20,12 @@ class WMaterial(BaseModel):
batch = models.CharField('批次号', max_length=100, null=True, blank=True) batch = models.CharField('批次号', max_length=100, null=True, blank=True)
count = models.PositiveIntegerField('当前数量', default=0) count = models.PositiveIntegerField('当前数量', default=0)
class WProduct(CommonAModel): class WProduct(CommonAModel):
""" """
动态半成品/成品表 动态半成品/成品表
""" """
WPR_ACT_STATE_TORETEST = 6 WPR_ACT_STATE_TORETEST = 6
WPR_ACT_STATE_DOWAIT = 8
WPR_ACT_STATE_DOING = 10 WPR_ACT_STATE_DOING = 10
WPR_ACT_STATE_TOTEST = 20 WPR_ACT_STATE_TOTEST = 20
WPR_ACT_STATE_OK = 30 WPR_ACT_STATE_OK = 30
@ -34,7 +34,8 @@ class WProduct(CommonAModel):
WPR_ACT_STATE_TOFINALTEST = 60 WPR_ACT_STATE_TOFINALTEST = 60
act_state_choices=( act_state_choices=(
(WPR_ACT_STATE_TORETEST, '待复检'), (WPR_ACT_STATE_TORETEST, '待复检'),
(WPR_ACT_STATE_DOING, '生产中'), (WPR_ACT_STATE_DOWAIT, '操作准备中'),
(WPR_ACT_STATE_DOING, '操作进行中'),
(WPR_ACT_STATE_TOTEST, '待检验'), (WPR_ACT_STATE_TOTEST, '待检验'),
(WPR_ACT_STATE_OK, '已合格'), (WPR_ACT_STATE_OK, '已合格'),
(WPR_ACT_STATE_INM, '库存中'), (WPR_ACT_STATE_INM, '库存中'),
@ -46,14 +47,38 @@ class WProduct(CommonAModel):
pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True, on_delete=models.CASCADE, related_name='w_pre_step') pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True, on_delete=models.CASCADE, related_name='w_pre_step')
step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True, related_name='w_step') step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True, related_name='w_step')
act_state = models.IntegerField('进行状态', default=0, choices=act_state_choices) act_state = models.IntegerField('进行状态', default=0, choices=act_state_choices)
is_executed = models.BooleanField('子工序是否已执行', default=False)
is_hidden = models.BooleanField('是否隐藏', default=False) is_hidden = models.BooleanField('是否隐藏', default=False)
child = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE) child = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE)
remark = models.CharField('备注', max_length=200, null=True, blank=True) remark = models.CharField('备注', max_length=200, null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, related_name='wproduct_subplan') subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, related_name='wproduct_subplan')
warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True) warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
operation = models.ForeignKey('wpm.operation', verbose_name='关联操作', operation = models.ForeignKey('wpm.operation', verbose_name='关联操作',
on_delete=models.SET_NULL, null=True, blank=True, related_name='current_operation') on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation')
class Pick(CommonADModel):
"""
领料记录
"""
PICK_FROM_WAREHOUSE = 10
PICK_FROM_WPRODUCT = 20
type_choice = (
(PICK_FROM_WAREHOUSE, '仓库领取'),
(PICK_FROM_WPRODUCT, '半成品领取'),
)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE)
type = models.PositiveSmallIntegerField(choices=type_choice, default=PICK_FROM_WAREHOUSE)
fifo = models.ForeignKey(FIFO, verbose_name='关联的出入库记录', on_delete=models.CASCADE, null=True, blank=True)
class PickWproduct(BaseModel):
"""
领取半成品时详情
"""
pick = models.ForeignKey(Pick, verbose_name='关联领料', on_delete=models.CASCADE)
wproduct = models.ForeignKey(WProduct, verbose_name='关联半成品', on_delete=models.CASCADE, related_name='pw_wproduct')
number = models.CharField('物品编号', null=True, blank=True, max_length=50)
material = models.ForeignKey(Material, verbose_name='领取时的物料状态', on_delete=models.CASCADE)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='领取时所属子生产计划', on_delete=models.CASCADE)
class Operation(CommonADModel): class Operation(CommonADModel):
""" """

View File

@ -13,26 +13,26 @@ from django.utils.translation import gettext_lazy as _
from apps.pm.serializers import SubproductionPlanSimpleSerializer from apps.pm.serializers import SubproductionPlanSimpleSerializer
from apps.qm.models import TestRecord, TestRecordItem from apps.qm.models import TestRecord, TestRecordItem
from apps.system.serializers import UserSimpleSerializer from apps.system.serializers import UserSimpleSerializer
from apps.wpm.models import Operation, OperationEquip, OperationMaterial, OperationWproduct, WMaterial, WProduct, OperationRecord, OperationRecordItem from apps.wpm.models import Operation, OperationEquip, OperationMaterial, OperationWproduct, Pick, WMaterial, WProduct, OperationRecord, OperationRecordItem
from django.db import transaction from django.db import transaction
class PickHalfSerializer(serializers.Serializer): class PickHalfSerializer(serializers.Serializer):
id = serializers.PrimaryKeyRelatedField(queryset=SubProductionProgress.objects.all(), label='子计划进度ID') id = serializers.PrimaryKeyRelatedField(queryset=SubProductionProgress.objects.all(), label='子计划进度ID')
wproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label='半成品ID'), wproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all())
required=False) # 从半成品表里直接修改状态 , label='半成品ID', required=False) # 从半成品表里直接修改状态
class PickHalfsSerializer(serializers.ListSerializer):
child = PickHalfSerializer()
class PickDetailSerializer(serializers.Serializer): class PickDetailSerializer(serializers.Serializer):
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID") material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID")
batch = serializers.CharField(label='物料批次', allow_blank=True) batch = serializers.CharField(label='物料批次', allow_blank=True)
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID") warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
pick_count = serializers.IntegerField(label="领料数量", required=False) pick_count = serializers.IntegerField(label="领料数量", required=False)
iproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all(), label='库存半成品ID'), iproducts = serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all(), label='库存半成品ID',required=False, many=True)
required=False)
class PickSerializer(serializers.Serializer): class PickSerializer(serializers.Serializer):
subproduction_plan=serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID") subproduction_plan=serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
picks = PickDetailSerializer(many=True) # 从库存里拿 picks = PickDetailSerializer(many=True) # 从库存里拿
def create(self, validated_data): def create(self, validated_data):
picks = validated_data.pop('picks') picks = validated_data.pop('picks')
@ -101,13 +101,20 @@ class PickSerializer(serializers.Serializer):
wids = IProduct.objects.filter(pk__in=[x.id for x in iproducts]).values_list('wproduct', flat=True) wids = IProduct.objects.filter(pk__in=[x.id for x in iproducts]).values_list('wproduct', flat=True)
wproducts = WProduct.objects.filter(pk__in=wids) wproducts = WProduct.objects.filter(pk__in=wids)
first_step = Step.objects.get(pk=sp.steps[0]['id']) first_step = Step.objects.get(pk=sp.steps[0]['id'])
wproducts.update(step=first_step, is_executed=False, wproducts.update(step=first_step,
act_state=WProduct.WPR_ACT_STATE_TORETEST, is_hidden=False, warehouse=None, act_state=WProduct.WPR_ACT_STATE_TORETEST, is_hidden=False, warehouse=None,
subproduction_plan=sp) subproduction_plan=sp)
sp.is_picked=True sp.is_picked=True
sp.state = SubProductionPlan.SUBPLAN_STATE_WORKING #生产中 sp.state = SubProductionPlan.SUBPLAN_STATE_WORKING #生产中
sp.state_date_real = timezone.now() #实际开工日期 sp.state_date_real = timezone.now() #实际开工日期
sp.save() sp.save()
# 创建领料记录
pick = Pick()
pick.subproduction_plan = sp
pick.type = Pick.PICK_FROM_WAREHOUSE
pick.fifo = fifo
pick.create_by = self.context['request'].user
pick.save()
# 更新库存 # 更新库存
fifo.is_audited = True fifo.is_audited = True
fifo.save() fifo.save()
@ -166,8 +173,7 @@ class OperationCreateSerializer(serializers.Serializer):
""" """
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID") step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
# subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False) # subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
wproducts = serializers.ListField(child= wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label="半成品ID列表", required=False, many=True)
serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
def validate(self, data): def validate(self, data):
# subproduction_plan = data['subproduction_plan'] # subproduction_plan = data['subproduction_plan']
@ -181,10 +187,10 @@ class OperationCreateSerializer(serializers.Serializer):
if step.type == Step.STEP_TYPE_DIV: if step.type == Step.STEP_TYPE_DIV:
raise exceptions.APIException(_('不可进行此操作')) raise exceptions.APIException(_('不可进行此操作'))
for i in data['wproducts']: for i in data['wproducts']:
if i.act_state != WProduct.WPR_ACT_STATE_DOING: if i.act_state != WProduct.WPR_ACT_STATE_DOWAIT:
raise exceptions.APIException('半成品不在生产状态') raise exceptions.APIException('半成品不在待操作状态')
if i.is_executed: # if i.is_executed:
raise exceptions.APIException('不可进行操作') # raise exceptions.APIException('不可进行操作')
# if i.subproduction_plan != subproduction_plan: # if i.subproduction_plan != subproduction_plan:
# raise exceptions.APIException('半成品所属子计划不一致') # raise exceptions.APIException('半成品所属子计划不一致')
if i.step != step: if i.step != step:
@ -203,8 +209,7 @@ class OperationUpdateSerializer(serializers.ModelSerializer):
class OperationInitSerializer(serializers.Serializer): class OperationInitSerializer(serializers.Serializer):
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID") step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False) subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
wproducts = serializers.ListField(child= wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label="半成品ID列表", required=False, many=True)
serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
def validate(self, data): def validate(self, data):
# subproduction_plan = data['subproduction_plan'] # subproduction_plan = data['subproduction_plan']
@ -218,8 +223,8 @@ class OperationInitSerializer(serializers.Serializer):
if step.type == Step.STEP_TYPE_DIV: if step.type == Step.STEP_TYPE_DIV:
raise exceptions.APIException(_('不可进行此操作')) raise exceptions.APIException(_('不可进行此操作'))
for i in data['wproducts']: for i in data['wproducts']:
if i.is_executed: if i.act_state != WProduct.WPR_ACT_STATE_DOWAIT:
raise exceptions.APIException('不可进行操作') raise exceptions.APIException('半成品不在待操作状态')
# if i.subproduction_plan != subproduction_plan: # if i.subproduction_plan != subproduction_plan:
# raise exceptions.APIException('半成品所属子计划不一致') # raise exceptions.APIException('半成品所属子计划不一致')
if i.step != step: if i.step != step:
@ -267,8 +272,7 @@ class OperationWproductListSerializer(serializers.ModelSerializer):
class OperationSubmitSerializer(serializers.Serializer): class OperationSubmitSerializer(serializers.Serializer):
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID") step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False) subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
wproducts = serializers.ListField(child= wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label="半成品ID列表", required=False, many=True)
serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
input = DoInputSerializer(many=True, required=False) input = DoInputSerializer(many=True, required=False)
output = DoOutputSerializer(many=True, required=False) output = DoOutputSerializer(many=True, required=False)
forms = OperationRecordSerializer(many=True, required=False) forms = OperationRecordSerializer(many=True, required=False)
@ -288,11 +292,6 @@ class WpmTestRecordCreateSerializer(serializers.ModelSerializer):
model = TestRecord model = TestRecord
fields = ['form', 'record_data', 'is_testok', 'wproduct'] fields = ['form', 'record_data', 'is_testok', 'wproduct']
class WproductPutInSerializer(serializers.Serializer):
"""
半成品入库序列化
"""
class WplanPutInSerializer(serializers.Serializer): class WplanPutInSerializer(serializers.Serializer):
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID") warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
remark = serializers.CharField(label="入库备注", required =False) remark = serializers.CharField(label="入库备注", required =False)
@ -301,6 +300,12 @@ class WproductPutInSerializer(serializers.Serializer):
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID") warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
remark = serializers.CharField(label="入库备注", required =False) remark = serializers.CharField(label="入库备注", required =False)
class WproductPutInsSerializer(serializers.Serializer):
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label='半成品ID', many=True)
remark = serializers.CharField(label="入库备注", required =False)
class OperationEquipListSerializer(serializers.Serializer): class OperationEquipListSerializer(serializers.Serializer):
equip_ = EquipmentSimpleSerializer(source='equip', read_only=True) equip_ = EquipmentSimpleSerializer(source='equip', read_only=True)
class Meta: class Meta:

View File

@ -11,14 +11,14 @@ from apps.mtm.models import Material, RecordForm, RecordFormField, Step, Subprod
from apps.mtm.serializers import RecordFormDetailSerializer, SubprodctionMaterialListSerializer, TechDocListSerializer from apps.mtm.serializers import RecordFormDetailSerializer, SubprodctionMaterialListSerializer, TechDocListSerializer
from apps.pm.models import SubProductionPlan, SubProductionProgress from apps.pm.models import SubProductionPlan, SubProductionProgress
from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from apps.qm.models import TestRecordItem from apps.qm.models import TestRecord, TestRecordItem
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from rest_framework.decorators import action from rest_framework.decorators import action
from apps.wpm.filters import WMaterialFilterSet from apps.wpm.filters import WMaterialFilterSet
from apps.wpm.models import OperationEquip, OperationWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem from apps.wpm.models import OperationEquip, OperationWproduct, Pick, PickWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem
from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickHalfsSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer, WproductPutInsSerializer
from rest_framework.response import Response from rest_framework.response import Response
from django.db import transaction from django.db import transaction
from rest_framework import exceptions, serializers from rest_framework import exceptions, serializers
@ -27,6 +27,7 @@ from apps.wpm.services import WpmServies
from django.utils import timezone from django.utils import timezone
from utils.tools import ranstr from utils.tools import ranstr
from rest_framework import status from rest_framework import status
from django.db.models import Count
# Create your views here. # Create your views here.
class WPlanViewSet(ListModelMixin, GenericViewSet): class WPlanViewSet(ListModelMixin, GenericViewSet):
""" """
@ -40,7 +41,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
ordering_fields = [] ordering_fields = []
ordering = ['-update_time'] ordering = ['-update_time']
@action(methods=['post', 'get'], detail=True, perms_map={'post':'*', 'get':'*'}, serializer_class=PickHalfSerializer) @action(methods=['post', 'get'], detail=True, perms_map={'post':'*', 'get':'*'}, serializer_class=PickHalfsSerializer)
@transaction.atomic @transaction.atomic
def pick_half(self, request, pk=None): def pick_half(self, request, pk=None):
""" """
@ -55,10 +56,16 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
material__type=Material.MA_TYPE_HALFGOOD, subproduction_plan=sp).select_related('material') material__type=Material.MA_TYPE_HALFGOOD, subproduction_plan=sp).select_related('material')
return Response(SubProductionProgressSerializer(instance=spps, many=True).data) return Response(SubProductionProgressSerializer(instance=spps, many=True).data)
elif request.method=='POST': elif request.method=='POST':
serializer= PickHalfSerializer(data=request.data, many=True) serializer= PickHalfsSerializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
vdata = serializer.data vdata = serializer.data
first_step = Step.objects.get(pk=sp.steps[0]['id']) first_step = Step.objects.get(pk=sp.steps[0]['id'])
# 创建领料记录
pick = Pick()
pick.subproduction_plan = sp
pick.type = Pick.PICK_FROM_WPRODUCT
pick.create_by = request.user
pick.save()
for i in vdata: for i in vdata:
if 'wproducts' in i and len(i['wproducts'])>0: if 'wproducts' in i and len(i['wproducts'])>0:
spp = SubProductionProgress.objects.get(pk=i['id']) spp = SubProductionProgress.objects.get(pk=i['id'])
@ -66,12 +73,21 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
# if spp.count_pick > spp.count: # if spp.count_pick > spp.count:
# raise exceptions.APIException('超过计划数') # raise exceptions.APIException('超过计划数')
spp.save() spp.save()
wps = WProduct.objects.filter(pk__in=[x for x in i['wproducts']]) wps = WProduct.objects.filter(pk__in=[x for x in i['wproducts']], act_state=WProduct.WPR_ACT_STATE_OK)
wps.update(step=first_step, is_executed=False, wps.update(step=first_step,
act_state=WProduct.WPR_ACT_STATE_TORETEST, is_hidden=False, warehouse=None, act_state=WProduct.WPR_ACT_STATE_TORETEST, is_hidden=False, warehouse=None,
subproduction_plan=sp, update_by=request.user, update_time=timezone.now()) subproduction_plan=sp, update_by=request.user, update_time=timezone.now())
for i in wps:
pw = PickWproduct()
pw.pick =pick
pw.wproduct = i
pw.number = i.number
pw.material = i.material
pw.subproduction_plan = i.suproduction_plan
pw.save()
sp.is_picked = True sp.is_picked = True
sp.save() sp.save()
return Response() return Response()
@ -160,9 +176,9 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
半成品 半成品
""" """
perms_map={'*':'*'} perms_map={'*':'*'}
queryset = WProduct.objects.select_related('step', 'material').filter(is_hidden=False, operation=None) queryset = WProduct.objects.select_related('step', 'material').filter(is_hidden=False)
serializer_class = WProductListSerializer serializer_class = WProductListSerializer
filterset_fields = ['step', 'subproduction_plan', 'material', 'step__process', 'act_state'] filterset_fields = ['step', 'subproduction_plan', 'material', 'step__process', 'act_state', 'material__type']
search_fields = ['number'] search_fields = ['number']
ordering_fields = ['id'] ordering_fields = ['id']
ordering = ['id'] ordering = ['id']
@ -178,13 +194,19 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
vdata = serializer.validated_data vdata = serializer.validated_data
record_data = vdata.pop('record_data') record_data = vdata.pop('record_data')
wproduct = vdata['wproduct'] wproduct = vdata['wproduct']
if wproduct.act_state not in [WProduct.WPR_ACT_STATE_TOTEST, WProduct.WPR_ACT_STATE_TORETEST]: if wproduct.act_state not in [WProduct.WPR_ACT_STATE_TOTEST,
WProduct.WPR_ACT_STATE_TORETEST, WProduct.WPR_ACT_STATE_TOFINALTEST]:
raise exceptions.APIException('该产品当前状态不可检验') raise exceptions.APIException('该产品当前状态不可检验')
if 'is_testok' not in vdata: if 'is_testok' not in vdata:
raise exceptions.APIException('未填写检测结论') raise exceptions.APIException('未填写检测结论')
obj = serializer.save(create_by = self.request.user, savedict = dict(create_by = self.request.user,
material=wproduct.material, number=wproduct.number, subproduction_plan=wproduct.subproduction_plan) material=wproduct.material, number=wproduct.number, subproduction_plan=wproduct.subproduction_plan, step=wproduct.step)
if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST:
savedict['type'] = TestRecord.TEST_PROCESS_RE
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOFINALTEST:
savedict['type'] = TestRecord.TEST_FINAL
obj = serializer.save(**savedict)
tris = [] tris = []
for m in record_data: # 保存记录详情 for m in record_data: # 保存记录详情
form_field = m['form_field'] form_field = m['form_field']
@ -202,7 +224,12 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
# 如果检测合格, 变更动态产品进行状态 # 如果检测合格, 变更动态产品进行状态
if obj.is_testok: if obj.is_testok:
wproduct.act_state = WProduct.WPR_ACT_STATE_OK if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST:
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT # 复检
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and wproduct.material.type == Material.MA_TYPE_GOOD:
wproduct.act_state = WProduct.WPR_ACT_STATE_TOFINALTEST # 成品检验
else:
wproduct.act_state = WProduct.WPR_ACT_STATE_OK
if wproduct.number is None: # 产生半成品编号 if wproduct.number is None: # 产生半成品编号
wproduct.number = 'WP'+ranstr(7) wproduct.number = 'WP'+ranstr(7)
wproduct.save() wproduct.save()
@ -217,49 +244,57 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
wproduct.save() wproduct.save()
return Response() return Response()
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestRecordCreateSerializer) @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WproductPutInsSerializer)
@transaction.atomic @transaction.atomic
def retest(self, request, pk=None): def putins(self, request, pk=None):
""" """
复检 半成品批量入库
""" """
serializer = WpmTestRecordCreateSerializer(data=request.data) serializer= WproductPutInsSerializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data vdata = serializer.data
record_data = vdata.pop('record_data') wproducts = WProduct.objects.filter(pk__in=[x for x in vdata['wproducts']])
wproduct = vdata['wproduct'] warehouse = WareHouse.objects.get(id=vdata['warehouse'])
if wproduct.act_state != WProduct.WPR_ACT_STATE_TORETEST: for i in wproducts:
raise exceptions.APIException('该产品当前状态不可检验') if i.act_state is not WProduct.WPR_ACT_STATE_OK:
if 'is_testok' not in vdata: raise exceptions.APIException('存在不可入库半成品')
raise exceptions.APIException('未填写检测结论') # 聚合一下
wproducts_a = wproducts.values('subproduction_plan', 'material', 'subproduction_plan__number').annotate(total=Count('id'))
obj = serializer.save(create_by = self.request.user, # 创建入库记录
material=wproduct.material, number=wproduct.number, subproduction_plan=wproduct.subproduction_plan) remark = vdata.get('remark', '')
tris = [] fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN,
for m in record_data: # 保存记录详情 is_audited=True, auditor=request.user, inout_date=timezone.now(), create_by=request.user, remark=remark)
form_field = m['form_field'] # 创建入库明细
m['field_name'] = form_field.field_name for i in wproducts_a:
m['field_key'] = form_field.field_key spi = SubProductionPlan.objects.get(pk=i['subproduction_plan'])
m['field_type'] = form_field.field_type fifoitem = FIFOItem()
m['field_value'] = m['field_value'] fifoitem.is_tested = True
m['sort'] = form_field.sort fifoitem.is_testok = True
m['need_judge'] = form_field.need_judge fifoitem.warehouse = warehouse
m['is_testok'] = m['is_testok'] if 'is_testok' in m else None fifoitem.material = Material.objects.get(pk=i['material'])
m['test_record'] = obj fifoitem.count = i['total']
tris.append(TestRecordItem(**m)) fifoitem.batch = spi.number
TestRecordItem.objects.bulk_create(tris) fifoitem.fifo = fifo
fifoitem.subproduction_plan = spi
fifoitem.save()
# 如果检测合格, 变更动态产品进行状态 wproducts_items = wproducts.filter(subproduction_plan=i['subproduction_plan'], material=i['material'])
ips = []
if obj.is_testok: for i in wproducts_items:
wproduct.act_state = WProduct.WPR_ACT_STATE_DOING # 创建入库明细半成品
wproduct.save() ip = {}
else:# 如果不合格 ip['fifoitem'] = fifoitem
wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK ip['wproduct'] = i
wproduct.save() ip['number'] = i.number
ip['material'] = i.material
ips.append(FIFOItemProduct(**ip))
FIFOItemProduct.objects.bulk_create(ips)
# 更新库存并修改半成品进行状态
update_inm(fifo)
wproducts.update(act_state=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse, update_by=request.user)
return Response() return Response()
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductPutInSerializer) @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductPutInSerializer)
@transaction.atomic @transaction.atomic
def putin(self, request, pk=None): def putin(self, request, pk=None):
@ -340,6 +375,8 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
instance = self.get_object() instance = self.get_object()
if instance.is_submited: if instance.is_submited:
raise exceptions.APIException('该操作已提交') raise exceptions.APIException('该操作已提交')
# 恢复半成品可操作
instance.wp_operation.all().update(act_state=WProduct.WPR_ACT_STATE_DOWAIT)
self.perform_destroy(instance) self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=status.HTTP_204_NO_CONTENT)
@ -359,7 +396,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
# 创建操作所用半成品关联记录 # 创建操作所用半成品关联记录
if 'wproducts' in vdata: if 'wproducts' in vdata:
owps = [] owps = []
WProduct.objects.filter(pk__in=[x.id for x in vdata['wproducts']]).update(operation=op) WProduct.objects.filter(pk__in=[x.id for x in vdata['wproducts']]).update(operation=op, act_state=WProduct.WPR_ACT_STATE_DOING)
splans = WpmServies.get_subplans_queryset_from_wproducts(vdata['wproducts']) splans = WpmServies.get_subplans_queryset_from_wproducts(vdata['wproducts'])
for wpd in vdata['wproducts']: for wpd in vdata['wproducts']:
owp = {} owp = {}
@ -439,9 +476,8 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
wp.step = newstep wp.step = newstep
wp.pre_step = step wp.pre_step = step
if hasNext: if hasNext:
wp.is_executed= False wp.act_state= WProduct.WPR_ACT_STATE_DOWAIT
else: else:
wp.is_executed = True
wp.act_state = WProduct.WPR_ACT_STATE_TOTEST wp.act_state = WProduct.WPR_ACT_STATE_TOTEST
wp.material = wsp.main_product wp.material = wsp.main_product
# 更新子计划进度 # 更新子计划进度
@ -457,7 +493,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
if i.subproduction_progress.is_main: if i.subproduction_progress.is_main:
newstep, _ = WpmServies.get_next_step(i.subproduction_plan, step) newstep, _ = WpmServies.get_next_step(i.subproduction_plan, step)
wpr = dict(material=i.material, step=newstep, wpr = dict(material=i.material, step=newstep,
act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='', act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='',
subproduction_plan=i.subproduction_plan) subproduction_plan=i.subproduction_plan)
for x in range(i.count): for x in range(i.count):
WProduct.objects.create(**wpr) WProduct.objects.create(**wpr)
@ -469,11 +505,9 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
wproduct.step = newstep wproduct.step = newstep
wproduct.subproduction_plan = i.subproduction_plan wproduct.subproduction_plan = i.subproduction_plan
if hasNext: if hasNext:
wproduct.act_state = WProduct.WPR_ACT_STATE_DOING wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
wproduct.is_executed = False
else: else:
wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
wproduct.is_executed = True
# 更新子计划进度 # 更新子计划进度
instance = SubProductionProgress.objects.get(subproduction_plan=i.subproduction_plan, instance = SubProductionProgress.objects.get(subproduction_plan=i.subproduction_plan,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
@ -782,7 +816,7 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
if vdata['step'].type == Step.STEP_TYPE_DIV: if vdata['step'].type == Step.STEP_TYPE_DIV:
newstep, _ = WpmServies.get_next_step(i['subproduction_plan'], vdata['step']) newstep, _ = WpmServies.get_next_step(i['subproduction_plan'], vdata['step'])
wpr = dict(material=ma, step=newstep, wpr = dict(material=ma, step=newstep,
act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='', act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='',
subproduction_plan=i['subproduction_plan']) subproduction_plan=i['subproduction_plan'])
for x in range(i['count_output']): for x in range(i['count_output']):
WProduct.objects.create(**wpr) WProduct.objects.create(**wpr)
@ -814,11 +848,9 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
wproduct.subproduction_plan=vdata['subproduction_plan'] wproduct.subproduction_plan=vdata['subproduction_plan']
wproduct.parent = data['wproducts'] wproduct.parent = data['wproducts']
if hasNext: if hasNext:
wproduct.act_state=WProduct.WPR_ACT_STATE_DOING wproduct.act_state=WProduct.WPR_ACT_STATE_DOWAIT
wproduct.is_executed=False
else: else:
wproduct.act_state=WProduct.WPR_ACT_STATE_TOTEST wproduct.act_state=WProduct.WPR_ACT_STATE_TOTEST
wproduct.is_executed=True
wproduct.save() wproduct.save()
else: else:
raise exceptions.APIException('请指定子计划') raise exceptions.APIException('请指定子计划')
@ -829,9 +861,8 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
wproduct.step = newstep wproduct.step = newstep
wproduct.pre_step=vdata['step'] wproduct.pre_step=vdata['step']
if hasNext: if hasNext:
wproduct.is_executed= False wproduct.act_state=WProduct.WPR_ACT_STATE_DOWAIT
else: else:
wproduct.is_executed= True
wproduct.act_state=WProduct.WPR_ACT_STATE_TOTEST wproduct.act_state=WProduct.WPR_ACT_STATE_TOTEST
wproduct.material=wproduct.subproduction_plan.main_product wproduct.material=wproduct.subproduction_plan.main_product
wproduct.save() wproduct.save()