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

This commit is contained in:
shilixia 2021-12-13 14:29:13 +08:00
commit d85ac1c7e0
35 changed files with 3937 additions and 347 deletions

View File

@ -47,4 +47,17 @@ export default {
.bigDialog .el-dialog{
width: 70%!important;
}
.fail input.el-input__inner{
border: 1px solid #ff0000!important;
}
.adopt input.el-input__inner{
border: 1px solid #46ce7a!important;
}
.fail .originBlock input.el-input__inner,
.adopt .originBlock input.el-input__inner{
border: none!important;
}
#customerForm .el-form-item{
margin-bottom: 30px!important;
}
</style>

View File

@ -288,5 +288,14 @@ export function recordInit(id) {
})
}
//半产品复检
export function wproductReview(data) {
return request({
url: '/wpm/wproduct/test_init/',
method: 'post',
data
})
}

View File

@ -1,8 +1,9 @@
<template>
<div>
<el-form
<el-form
id="customerForm"
ref="checkForm"
label-width="100px"
label-width="100px"
:model="checkForm"
>
<el-row>
@ -11,6 +12,8 @@
v-show="filterBlock(item.parent,item.display_expression)"
:key="$index"
:span="12"
style="position: relative"
:class="item.need_judge&&item.is_testok===true?'adopt':item.need_judge&&item.is_testok===false?'fail':''"
>
<el-form-item
v-if="item.field_type === 'string'"
@ -112,12 +115,15 @@
</el-option>
</el-select>
</el-form-item>
<span v-show="item.help_text" class="helpText">说明{{item.help_text}}</span>
<span v-if="item.need_judge&&item.is_testok===true" class="adoptTip">合格</span>
<span v-if="item.need_judge&&item.is_testok===false" class="failTip">不合格</span>
</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">
<img id="canvasImg" :src="img" 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">
@ -130,7 +136,7 @@
<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 class="canvasBtn" @click="saveTu()">保存</div>-->
</div>
<div id="res"></div>
</div>
@ -189,7 +195,7 @@
formData.forEach(item => {
let obj = new Object();
obj = item;
obj.is_testok = true;//是否合格
obj.is_testok = null;//是否合格
that.formData.push(obj)
});
that.formData=[...that.formData];
@ -208,6 +214,12 @@
obj = item;
that.judgeList.push(obj)
});
let imag= this.formData.filter(item => {
return item.field_type === 'draw';
});
that.img = new Image();
that.img.crossOrigin = '';
that.img = 'http://47.95.0.242:2222'+imag[0].draw_template;
setTimeout(function(){
that.canvasInit();
},500);
@ -228,10 +240,12 @@
myCanvas_rect:null,
Txt:null,
word:null,
img:null,
widths:0,
heights:0,
lineW:3,
colorF:"#e42343",
imgUrl:'',
imgData:'',
canvasImg:'',
formData:[],//表单数组
@ -344,19 +358,23 @@
if(item.indexOf('&&')>-1){
if(str.indexOf('false')>-1){
that.formData[index].is_testok = true;
that.$set(that.formData[index],'is_testok',true)
}else{
that.formData[index].is_testok = false;
that.$set(that.formData[index],'is_testok',false)
}
}else{
if(str.indexOf('true')>-1){
that.formData[index].is_testok = false;
that.$set(that.formData[index],'is_testok',false)
}else{
that.formData[index].is_testok = true;
that.$set(that.formData[index],'is_testok',true)
}
}
}else{
that.formData[index].is_testok = true;
that.$forceUpdate();
}
that.$forceUpdate();
that.judgeList = that.formData.filter(item => {
return item.need_judge === true;
});
@ -382,6 +400,7 @@
//画布添加背景模板图
draw(){
let canvasImg = document.getElementById("canvasImg");
canvasImg.setAttribute("crossOrigin",'anonymous');
canvasImg.style.width = '500px';
canvasImg.style.height = '300px';
this.ctx.drawImage(canvasImg,0,0,500,300);
@ -528,6 +547,7 @@
},
//保存
saveTu(){
let that = this;
this.word.style.display="none";
this.Txt.style.display="none";
let canvas = document.getElementById('canvas');
@ -538,7 +558,9 @@
let formData = new FormData();
formData.append('file', file);
upFile(formData).then((res) => {
res;
debugger;
console.log(res);
that.imgUrl=res.data.field;
// console.log(res);
})
},
@ -609,31 +631,50 @@
});
if(real.length>0){
that.is_testok = false;
alert("检验不合格!")
// alert("检验不合格!")
}else{
that.is_testok = true;
alert("检验合格!")
// alert("检验合格!")
}
},
//提交检查项目
submitfield() {
let that = this;
debugger;
console.log(that.checkForm);
debugger;
let drawArr = that.formData.filter(item=>{
return item.field_type==='draw';
});
if(drawArr.length>0){
that.word.style.display="none";
that.Txt.style.display="none";
let canvas = document.getElementById('canvas');
let image = new Image();
image = canvas.toDataURL('image/png');
that.canvasImg = image;
let file = that.base64ToFile(image);
let formData = new FormData();
formData.append('file', file);
upFile(formData).then((res) => {
if(res){
let key = drawArr[0].field_key;
that.imgUrl=res.data.file;
that.checkForm[key] = that.imgUrl;
that.fieldData();
}
});
}else{
that.fieldData();
}
},
fieldData(){
let that = this;
that.field = []; //检查项目
that.formData.forEach((item) => {
debugger;
console.log(that.checkForm[item.field_key]);
debugger;
that.field.push({
form_field: item.id,
field_value: that.checkForm[item.field_key],
is_testok: item.is_testok//单项检查结果
});
});
console.log(that.field);
debugger;
that.testrecord.form = that.formID;//检查表
that.testrecord.record_data = that.field;//检查项列表
that.testrecord.is_testok = that.is_testok;//检查表检查结果
@ -708,4 +749,23 @@
#res {
display: inline-block;
}
.helpText{
position: absolute;
top: 40px;
left: 100px;
}
.adoptTip{
position: absolute;
top: 38px;
right: 0;
font-size: 12px;
color: #46ce7a;
}
.failTip{
position: absolute;
top: 38px;
right: 0;
font-size: 12px;
color: #ff0000;
}
</style>

View File

@ -0,0 +1,878 @@
<template>
<div>
<el-form
id="customerForm"
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"
style="position: relative"
:class="item.need_judge&&item.is_testok===true?'adopt':item.need_judge&&item.is_testok===false?'fail':''"
>
<el-form-item
v-if="item.field_type === 'string'"
:label="item.field_name"
>
<el-input
disabled
class="halfWidth originBlock"
v-model="originForm[item.field_key]"
placeholder="请输入"
@input="keyChange($index,item.field_key)"
/>
<el-input
class="halfWidth"
v-model="checkForm[item.field_key]"
placeholder="请输入"
@input="keyChange($index,item.field_key)"
/>
</el-form-item>
<el-form-item
v-else-if="item.field_type === 'int'"
:label="item.field_name"
>
<el-input
disabled
class="halfWidth originBlock"
v-model="originForm[item.field_key]"
type="number"
placeholder="请输入"
@input="keyChange($index,item.field_key)"
/>
<el-input
class="halfWidth"
v-model="checkForm[item.field_key]"
type="number"
placeholder="请输入"
@input="keyChange($index,item.field_key)"
/>
</el-form-item>
<el-form-item
v-else-if="item.field_type === 'float'"
:label="item.field_name"
>
<el-input
disabled
class="halfWidth originBlock"
v-model="originForm[item.field_key]"
type="number"
placeholder="请输入"
@input="keyChange($index,item.field_key)"
/>
<el-input
class="halfWidth"
v-model="checkForm[item.field_key]"
type="number"
placeholder="请输入"
@input="keyChange($index,item.field_key)"
/>
</el-form-item>
<el-form-item
v-else-if="item.field_type === 'date'"
:label="item.field_name"
>
<el-date-picker
disabled
v-model="originForm[item.field_key]"
class="halfWidth originBlock"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
@change="keyChange($index,item.field_key)"
/>
<el-date-picker
v-model="checkForm[item.field_key]"
class="halfWidth"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
@change="keyChange($index,item.field_key)"
/>
</el-form-item>
<el-form-item
v-else-if="item.field_type === 'datetime'"
:label="item.field_name"
>
<el-date-picker
disabled
v-model="originForm[item.field_key]"
class="halfWidth originBlock"
type="datetime"
placeholder="选择日期"
value-format="yyyy-MM-dd HH:mm:ss"
@change="keyChange($index,item.field_key)"
/>
<el-date-picker
v-model="checkForm[item.field_key]"
class="halfWidth"
type="datetime"
placeholder="选择日期"
value-format="yyyy-MM-dd HH:mm:ss"
@change="keyChange($index,item.field_key)"
/>
</el-form-item>
<el-form-item
v-else-if="item.field_type === 'select'"
:label="item.field_name"
>
<el-select
disabled
v-model="originForm[item.field_key]"
class="halfWidth originBlock"
placeholder="请选择"
@change="keyChange($index,item.field_key)"
>
<el-option
v-for="item1 in item.field_choice"
:key="item1"
:label="item1"
:value="item1"
/>
</el-select>
<el-select
v-model="checkForm[item.field_key]"
class="halfWidth"
placeholder="请选择"
@change="keyChange($index,item.field_key)"
>
<el-option
v-for="item1 in item.field_choice"
:key="item1"
:label="item1"
:value="item1"
/>
</el-select>
</el-form-item>
<el-form-item
v-else-if="item.field_type === 'selects'"
:label="item.field_name"
>
<el-select
disabled
v-model="originForm[item.field_key]"
class="halfWidth originBlock"
multiple
placeholder="请选择"
@change="keyChange($index,item.field_key)"
>
<el-option
v-for="item1 in item.field_choice"
:key="item1"
:label="item1"
:value="item1"
@change="keyChange($index,item.field_key)"
>
</el-option>
</el-select>
<el-select
v-model="checkForm[item.field_key]"
class="halfWidth"
multiple
placeholder="请选择"
@change="keyChange($index,item.field_key)"
>
<el-option
v-for="item1 in item.field_choice"
:key="item1"
:label="item1"
:value="item1"
@change="keyChange($index,item.field_key)"
>
</el-option>
</el-select>
</el-form-item>
<span v-show="item.help_text" class="helpText">说明{{item.help_text}}</span>
<span v-if="item.need_judge&&item.is_testok===true" class="adoptTip">合格</span>
<span v-if="item.need_judge&&item.is_testok===false" class="failTip">不合格</span>
</el-col>
</el-row>
<el-row v-show="hasPicture">
<el-form-item label="图表">
<div class="halfWidth">
<img :src="originImg">
</div>
<div class="halfWidth">
<img id="canvasImg" :src="img" 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>
<div id="res"></div>
</div>
</div>
</el-form-item>
</el-row>
<el-row>
<el-form-item label="是否合格">
<el-radio v-model="is_testok" :label="testokTrue">检查合格</el-radio>
<el-radio v-model="is_testok" :label="testokFalse">检查不合格</el-radio>
</el-form-item>
<div class="dialog-footer" style="text-align: right">
<el-button @click="innerVisible = false"> </el-button>
<el-button type="primary" @click="submitfield">提交检查项目</el-button>
</div>
</el-row>
</el-form>
</div>
</template>
<script>
import { upFile } from "@/api/file";
let preDrawAry = [];
export default {
name: "review",
props: {
results:{
type:Array,
default: () => {
return []
}} ,
originList:{
type:Array,
default: () => {
return []
}} ,
formID: {
type:Number,
default:0
},
wproduct: {
type:Number,
default:0
},
origintest: {
type:Number,
default:0
},
hasPicture:{
type:Boolean,
default:false
}
},
mounted() {
let that = this;
this.form = this.formID;
let formData=this.results;
this.origins=this.originList;
that.wproductId=this.wproduct;
that.origin_test=this.origintest;
formData.forEach(item => {
let obj = new Object();
obj = item;
obj.is_testok = null;//是否合格
that.formData.push(obj)
});
that.formData=[...that.formData];
//当前表的数据存储
for(let i=0;i<this.results.length;i++){
let key = this.results[i].field_key;
//checkForm接收表单数据的对象
that.checkForm[key]='';
that.$set(that.checkForm,key,'')
}
//判定项
let listJudge = this.formData.filter(item => {
return item.need_judge === true;
});
listJudge.forEach(item => {
let obj = new Object();
obj = item;
that.judgeList.push(obj)
});
//原始表的数据
for(let i=0;i<this.origins.length;i++){
let key = this.origins[i].field_key;
that.originForm[key]=this.origins[i].field_key;
that.$set(that.originForm,key,this.origins[i].field_value)
}
//图片地址
let imag= this.formData.filter(item => {
return item.field_type === 'draw';
});
that.img = 'http://47.95.0.242:2222'+imag[0].draw_template;
let originImag= this.origins.filter(item => {
return item.field_type === 'draw';
});
that.originImg = new Image();
that.originImg.crossOrigin = '';
that.originImg = originImag[0].field_value;
listJudge.forEach(item => {
let obj = new Object();
obj = item;
that.judgeList.push(obj)
});
setTimeout(function(){
that.canvasInit();
},500);
},
data(){
return{
field:[],
origins:[],
checkForm:{},
originForm:{},
testrecord:{
form:this.formID,
record_data:[],
is_testok:true,
wproduct:null,
},
origin_test:null,
canvas:null,
wproductId:null,
ctx:null,
myCanvas_rect:null,
Txt:null,
word:null,
img:null,
originImg:null,
widths:0,
heights:0,
lineW:3,
colorF:"#e42343",
imgUrl:'',
imgData:'',
canvasImg:'',
checkType:'',
formData:[],//表单数组
judgeList:[],//判定数组
is_testok:true,
testokTrue:true,
testokFalse:false,
}
},
methods:{
filterBlock(parent,rule){
// debugger;
let that = this;
if(parent!==''&&parent!==null&&parent!==undefined){
if(rule!==''&&rule!==null&&rule!==undefined){
let reg = /\{(.+?)\}/g;
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(index,key){
let that = this;
let reg = /\{(.+?)\}/g;
that.$forceUpdate();
that.$nextTick(()=>{
if(that.formData[index].need_judge===true){
let arr = [],str = '';
let item = that.formData[index].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]+"'";
if(eval(eval( a))){
str += 'true';
}else{
str += 'false';
}
}
}
if(item.indexOf('&&')>-1){
if(str.indexOf('false')>-1){
that.formData[index].is_testok = true;
that.$set(that.formData[index],'is_testok',true)
}else{
that.formData[index].is_testok = false;
that.$set(that.formData[index],'is_testok',false)
}
}else{
if(str.indexOf('true')>-1){
that.formData[index].is_testok = false;
that.$set(that.formData[index],'is_testok',false)
}else{
that.formData[index].is_testok = true;
that.$set(that.formData[index],'is_testok',true)
}
}
that.$forceUpdate();
}
that.$forceUpdate();
that.judgeList = that.formData.filter(item => {
return item.need_judge === true;
});
that.judgeForm();
})
},
/* 图片保存 */
//初始化canvas
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.setAttribute("crossOrigin",'anonymous');
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(){
let that = this;
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) => {
debugger;
console.log(res);
that.imgUrl=res.data.field;
// console.log(res);
})
},
//base64ToFile
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');
},
/* 图片保存 */
//最终表格判定
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(item.indexOf('&&')>-1){
if(str.indexOf('false')>-1){
that.judgeList[i].is_testok = true;
}else{
that.judgeList[i].is_testok = false;
}
}else{
if(str.indexOf('true')>-1){
that.judgeList[i].is_testok = false;
}else{
that.judgeList[i].is_testok = true;
}
}
}
let real = that.judgeList.filter(item=>{
return item.is_testok===false;
});
if(real.length>0){
that.is_testok = false;
// alert("检验不合格!")
}else{
that.is_testok = true;
// alert("检验合格!")
}
},
//提交检查项目
submitfield() {
let that = this;
let drawArr = that.formData.filter(item=>{
return item.field_type==='draw';
});
if(drawArr.length>0){
that.word.style.display="none";
that.Txt.style.display="none";
let canvas = document.getElementById('canvas');
let image = new Image();
image = canvas.toDataURL('image/png');
that.canvasImg = image;
let file = that.base64ToFile(image);
let formData = new FormData();
formData.append('file', file);
upFile(formData).then((res) => {
if(res){
let key = drawArr[0].field_key;
that.imgUrl=res.data.file;
that.checkForm[key] = that.imgUrl;
that.fieldData();
}
});
}else{
that.fieldData();
}
},
fieldData(){
let that = this;
that.field = []; //检查项目
that.formData.forEach((item) => {
that.field.push({
form_field: item.id,
field_value: that.checkForm[item.field_key],
is_testok: item.is_testok//单项检查结果
});
});
that.testrecord.form = that.formID;//检查表
that.testrecord.record_data = that.field;//检查项列表
that.testrecord.is_testok = that.is_testok;//检查表检查结果
that.testrecord.wproduct = that.wproductId;//半成品ID
this.$emit('formFunc',that.testrecord);
},
}
}
</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;
}
.helpText{
position: absolute;
top: 40px;
left: 100px;
}
.adoptTip{
position: absolute;
top: 38px;
right: 0;
font-size: 12px;
color: #46ce7a;
}
.failTip{
position: absolute;
top: 38px;
right: 0;
font-size: 12px;
color: #ff0000;
}
.halfWidth{
width: 49%!important;
display: inline-block!important;
}
</style>

View File

@ -4,6 +4,8 @@ import 'normalize.css/normalize.css' // A modern alternative to CSS resets
import Element from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import "element-ui/lib/theme-chalk/base.css";
import CollapseTransition from "element-ui/lib/transitions/collapse-transition";
// import locale from 'element-ui/lib/locale/lang/en' // lang i18n
import '@/styles/index.scss' // global css
@ -11,11 +13,13 @@ import '@/styles/index.scss' // global css
import App from './App'
import store from './store'
import router from './router'
import { plugin } from "vue-function-api";
import '@/icons' // icon
import '@/permission' // permission control
import tableHeight from '@/directive/el-table/index'
Vue.use(tableHeight)
Vue.component(CollapseTransition.name, CollapseTransition);
Vue.use(tableHeight).use(plugin);
/**
* If you don't want to use mock-server
* you want to use MockJs for mock api

View File

@ -178,6 +178,14 @@ export const asyncRoutes = [
component: () => import('@/views/pm/resources'),
meta: { title: '生产资源配置', icon: 'example', perms: ['pm_resources'] }
}
,
{
path: 'gantt',
name: 'gantt',
component: () => import('@/views/pm/gantt'),
meta: { title: '甘特图', perms: ['vendor_manage'] },
hidden: true
},
]
}
,

View File

@ -405,6 +405,9 @@
<el-form-item label="字段父级">
<treeselect v-model="field.parent" :multiple="false" :options="treeDate" placeholder="字段父级"/>
</el-form-item>
<el-form-item label="字段说明">
<el-input v-model="field.help_text" placeholder="字段名称"/>
</el-form-item>
<el-form-item label="是否需要判定" prop="need_judge">
<el-switch v-model="field.need_judge"></el-switch>
</el-form-item>
@ -500,14 +503,12 @@
</el-form-item>
</el-form>
<div style="text-align: right">
<el-button type="danger" @click="dialogVisible1 = false"
>取消
</el-button
>
<el-button type="primary" @click="fieldconfirm('Form')"
>确认
</el-button
>
<el-button type="danger" @click="dialogVisible1 = false">
取消
</el-button>
<el-button type="primary" @click="fieldconfirm('Form')">
确认
</el-button>
</div>
</el-dialog>
</el-card>
@ -568,6 +569,7 @@
field_name: "",
sort: "",
parent: "",
help_text: "",
draw_template: "",//图片模板
field_choice: [""],
},
@ -829,22 +831,7 @@
});
that.fieldLists();
},
/*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);
},*/
checkPermission,
handleCurrentChange(row) {
this.formID = row.id;
this.fieldLists();
@ -884,252 +871,6 @@
}
});
},
/*draw() {
let canvasImg = document.getElementById("canvasImg");
canvasImg.style.width = '300px';
canvasImg.style.height = '200px';
this.ctx.drawImage(canvasImg, 0, 0, 300, 200);
},
// 叉号
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);
}
}
},
/!* // 删除批注
restuya(){
this.word.style.display="none";
this.Txt.style.display="none";
this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);
window.location.reload();
},*!/
// 撤销
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() {
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) => {
debugger;
console.log(res);
debugger;
})
},
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');
},
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() {
this.recordform = Object.assign({}, defaultrecordform);

View File

@ -0,0 +1,396 @@
<template>
<div class="tableMneu">
<div
class="mask"
v-if="isShowHeaderBox || menuOpen"
@click="maskClick"
></div>
<el-table
ref="tableMenu"
:data="tableData"
border
fit
style="width: 100%"
row-key="id"
height="100%"
default-expand-all
highlight-current-row
@row-click="handlerRowClick"
@expand-change="handlerExpand"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column
v-for="col in columns"
:prop="col.prop"
:key="col.prop"
:label="col.label"
:align="col.align"
:resizable="col.resizable"
>
<template slot-scope="scope">
<span v-if="col.prop == 'type'">{{
projectType[scope.row.type]
}}</span>
<span v-else>{{ scope.row[col.prop] }}</span>
</template>
</el-table-column>
</el-table>
<el-collapse-transition>
</el-collapse-transition>
<transition name="el-zoom-in-top">
<div class="menulist" v-show="menuOpen" ref="menulist">
<div
class="item"
v-for="(item, index) in menuLists"
@click="handleMenuClick(index, item)"
:key="item + index"
>
{{ item }}
</div>
</div>
</transition>
</div>
</template>
<script>
export default {
props: {
list: Array,
BGScrollTop: Number
},
computed: {
tableData() {
return this.list;
}
},
watch: {
BGScrollTop: {
handler: function(newValue) {
let table = this.$refs.tableMenu.bodyWrapper;
// console.log(newValue, table);
table.scrollTo(0, newValue);
// table.scrollTo({
// top: newValue,
// left: 0,
// behavior: "smooth"
// });
}
}
},
data() {
return {
// tableData: [],
checkList: [],
isShowHeaderBox: false,
menuOpen: false,
headerList: {
name: true,
ower: true,
per: true,
type: true
},
projectType: {
1: "计划项目",
2: "里程碑",
3: "分组"
},
menuLists: ["编辑", "里程碑", "分组", "删除"],
columns: [
{
prop: "name",
label: "名称",
width: "200px",
resizable: false
},
{
prop: "ower",
label: "负责人",
align: "center",
resizable: false
},
{
prop: "per",
label: "进度",
align: "center",
resizable: false
},
{
prop: "type",
label: "项目类型",
align: "center",
resizable: false
}
],
columnsCopy: [
{
prop: "name",
label: "名称",
width: "200px",
resizable: false
},
{
prop: "ower",
label: "负责人",
align: "center",
resizable: false
},
{
prop: "per",
label: "进度",
align: "center",
resizable: false
},
{
prop: "type",
label: "项目类型",
align: "center",
resizable: false
}
],
//当前点击的row
currentRow: {}
};
},
methods: {
handlerWatchScroll() {
let table = this.$refs.tableMenu.bodyWrapper;
table.addEventListener("scroll", e => {
// console.log(e.srcElement.scrollTop);
this.$emit("TableScrollTop", e.srcElement.scrollTop);
});
},
handlerSelect(row) {
this.$refs.tableMenu.setCurrentRow(row);
},
handlerExpand(row, expand) {
// console.log(row, expanded);
this.$emit("handlerExpand", row, expand);
},
handlerSave() {
this.isShowHeaderBox = false;
let arr = [];
this.columnsCopy.forEach(item => {
if (this.headerList[item.prop] == true) {
arr.push(item);
}
});
this.columns = arr;
},
maskClick() {
this.isShowHeaderBox = false;
this.menuOpen = false;
this.currentRow = {};
},
handlerRowClick(row, column) {
// console.log(column);
if (row.type != 3) {
this.$emit("handlerRowClick", row);
}
},
handleRowMore(row, e) {
this.menuLists = ["编辑", "里程碑", "分组", "删除"];
if (row.parentId) {
this.menuLists = ["编辑", "里程碑", "删除"];
}
if (row.type == "1") {
this.menuLists[1] = "里程碑";
} else if (row.type == "2") {
this.menuLists[1] = "计划项目";
} else if (row.type == "3") {
this.menuLists = ["编辑", "添加任务", "删除分组"];
}
this.menuOpen = true;
this.currentRow = row;
let s = this.$refs.menulist.style;
s.top = e.y - 10 - 40 + "px";
s.left = e.x + 20 + "px";
},
handleShowHeaderCheckBox() {
this.isShowHeaderBox = !this.isShowHeaderBox;
},
handleMenuClick(index, name) {
this.menuOpen = false;
if (index == 3) {
this.$confirm("此操作将永久删除该项目, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
center: true
})
.then(() => {
this.$emit("handlerDel", this.currentRow);
})
.catch(() => {});
} else if (index == 1) {
if (this.currentRow.type == 3) {
console.log("添加任务");
this.$emit("handleGroupAdd", this.currentRow);
return;
}
this.$confirm(`确定转为${this.menuLists[1]}`, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info",
center: true
})
.then(() => {
if (this.currentRow.type == "1") {
this.$emit("milestone", this.currentRow);
} else if (this.currentRow.type == "2") {
this.$emit("planProject", this.currentRow);
}
})
.catch(() => {});
} else if (index == 0) {
this.$emit("handlerEdit", this.currentRow);
} else if (index == 2) {
console.log(name);
if (this.currentRow.type == 3 && name == "删除分组") {
this.$confirm("此操作将永久删除该分组及其子项目, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
center: true
})
.then(() => {
this.$emit("handlerDel", this.currentRow);
})
.catch(() => {});
return;
}
if (name == "删除") {
this.$confirm("此操作将永久删除该项目, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
center: true
})
.then(() => {
this.$emit("handlerDel", this.currentRow);
})
.catch(() => {});
return;
}
this.$confirm(`确定转为分组`, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info",
center: true
})
.then(() => {
this.$emit("handlerGroup", this.currentRow);
})
.catch(() => {});
}
}
},
mounted() {
this.handlerWatchScroll();
}
};
</script>
<style lang="scss" scoped>
.tableMneu {
width: 100%;
position: relative;
height: 100%;
.mask {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: transparent;
z-index: 9999;
}
.icons {
cursor: pointer;
&:hover {
color: #409eff;
}
}
.menulist {
width: 100px;
position: absolute;
background-color: rgb(255, 255, 255);
border-radius: 5px;
border: 1px solid #ebeef5;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
transition: 0.3s;
width: 70px;
z-index: 9999;
.item {
background-color: rgb(255, 255, 255);
line-height: 30px;
text-align: center;
font-size: 12px;
color: rgb(102, 102, 102);
cursor: pointer;
height: 30px;
}
.item:hover {
color: #409eff;
}
}
.headerBox {
z-index: 9999;
position: absolute;
right: -128px;
top: 50px;
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
width: 170px;
background-color: #fff;
&::after {
content: " ";
position: absolute;
top: -5px;
left: 16px;
width: 0;
height: 0;
border-right: 7px solid transparent;
border-left: 7px solid transparent;
border-bottom: 7px solid #fff;
}
.title {
margin: 0;
padding: 8px 16px;
min-height: 32px;
border-bottom: 1px solid #e9e9e9;
color: #303030;
font-weight: 500;
}
.main {
.line {
padding: 8px 10px;
display: flex;
flex-direction: row;
align-items: center;
width: 150px;
.pre {
flex: 1 1 auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
}
</style>
<style lang="scss" >
.tableMneu {
.el-table th.gutter {
display: table-cell !important;
}
.el-table td,
.el-table th {
padding: 8px 0;
}
.el-table--border td {
border-right: none;
}
}
</style>

View File

@ -0,0 +1,173 @@
<template>
<div class="slider" ref="slider" :style="{ width: '100%' }">
<div class="process" :style="{ width }" style="font-size: 12px;color: #ffffff;text-align: right">
{{ per }}
</div>
<div class="process1" :style="{width:process1Width}" style="font-size: 12px;color: #ffffff;text-align: right"> {{ per1 }}</div>
</div>
</template>
<script>
export default {
props: ["min", "max", "value", "widths", "per1", "id", "parentId"],
data() {
return {
//滚动条DOM元素
slider: null,
//拖拽DOM元素
thunk: null,
//当前值
per: this.value,
perOk: this.per1,
//当前是否拖拽tip
isMove: false,
// process1Width:'10px',
};
},
watch: {
value(newValue, oldValue) {
this.per = newValue;
}
},
methods: {
thunkMousedown(e) {
let width = parseInt(this.width);
let disX = e.clientX;
this.$emit("thunkMousedown");
this.isMove = true;
console.log(this.isMove);
document.onmousemove = e => {
let newWidth = e.clientX - disX + width;
let scale = newWidth / this.slider.offsetWidth;
this.per = Math.ceil((this.max - this.min) * scale + this.min);
this.per = Math.max(this.per, this.min);
this.per = Math.min(this.per, this.max);
this.$emit("thunkMousemove", e, this.index);
};
document.onmouseup = event => {
this.isMove = false;
this.$emit(
"thunkMouseup",
parseInt(this.scale * 100),
event,
this.id,
this.parentId
);
document.onmousemove = document.onmouseup = null;
};
return false;
}
},
//渲染到页面的时候
mounted() {
this.slider = this.$refs.slider;
this.thunk = this.$refs.trunk;
},
computed: {
scale() {
return (this.per - this.min) / (this.max - this.min);
},
width() {
if (this.slider) {
return this.widths * this.scale + "px";
} else {
return 0 + "px";
}
},
process1Width() {
if (this.slider) {
let scale1 = (this.perOk - this.min) / (this.max - this.min);
return this.widths * scale1 + "px";
} else {
return 0 + "px";
}
},
left() {
if (this.slider) {
return this.widths * this.scale - this.thunk.offsetWidth / 2 + "px";
} else {
return 0 + "px";
}
}
}
};
</script>
<style>
.box {
margin: 100px auto 0;
width: 80%;
}
.clear:after {
content: "";
display: block;
clear: both;
}
.slider {
position: relative;
height: 20px;
background: #e4e7ed;
border-radius: 3px;
cursor: move;
user-select: none;
}
.slider .process {
position: absolute;
left: 0;
top: 0;
width: 112px;
height: 20px;
border-radius: 3px;
background: #409eff;
}
.slider .process1 {
position: absolute;
left: 0;
top: 0;
width: 10px;
height: 20px;
border-radius: 3px;
background: #11c750;
}
.slider .thunk {
position: absolute;
left: 100px;
top: -7px;
width: 20px;
height: 20px;
}
.slider .block {
transition: 0.2s all;
}
.slider .block i {
font-size: 25px;
position: relative;
left: -3px;
top: 15px;
cursor: pointer;
}
.slider .tips {
position: absolute;
left: -3px;
bottom: 0px;
font-size: 12px;
line-height: 24px;
min-width: 15px;
text-align: center;
padding: 1px 5px;
background: #000;
border-radius: 5px;
height: 24px;
color: #fff;
}
.slider .tips i {
position: absolute;
margin-left: -5px;
left: 50%;
bottom: -9px;
font-size: 16px;
color: #000;
}
.slider .block:hover {
transform: scale(1.1);
opacity: 0.6;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -36,8 +36,7 @@
v-if="checkPermission(['warehouse_update'])"
@click="handleInspection(scope)"
>检验
</el-link
>
</el-link>
</template>
</el-table-column>
</el-table>
@ -74,7 +73,6 @@
{{ actstate_[scope.row.act_state] }}
</template>
</el-table-column>
<el-table-column label="所在子工序">
<template slot-scope="scope">{{ scope.row.step_.name }}</template>
</el-table-column>
@ -82,10 +80,10 @@
<template slot-scope="scope">
<el-link
v-if="checkPermission(['warehouse_update'])"
@click="handleInspection(scope)"
>检验
</el-link
>
@click="handleReview(scope)"
>
检验
</el-link>
</template>
</el-table-column>
</el-table>
@ -100,10 +98,9 @@
</el-tab-pane>
<el-tab-pane label="已合格半成品">
<el-card style="margin-top: 2px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>批量入库
</el-button
>
<el-button type="primary" icon="el-icon-plus" @click="handleCreate">
批量入库
</el-button>
<el-table
v-loading="listLoading"
:data="wproductList1.results"
@ -211,15 +208,14 @@
<el-select style="width: 100%" v-model="recordform" placeholder="请选择" @change="recordformChange">
<el-option
v-for="item in recordformList"
:key="item.id"
:key="item.name"
:label="item.name"
:value="item.id"
>
>
</el-option>
</el-select>
<el-dialog
width="50%"
width="60%"
:title="formName"
:visible.sync="innerVisible"
append-to-body
@ -233,10 +229,27 @@
/>
</el-dialog>
<div slot="footer" class="dialog-footer">
<el-button @click="outerVisible = false"> </el-button>
<el-button @click="outerVisible = false">
</el-button>
<el-button type="primary" @click="submitrecordform">填写检查项目</el-button>
</div>
</el-dialog>
<el-dialog
width="60%"
:title="formName"
:visible.sync="limitedReview"
>
<reviewForm
:results="fieldList"
:originList="originList"
:formID="recordform"
:hasPicture="hasPicture"
:wproduct="wproduct"
:origintest="origintest"
@formFunc="formFunc"
/>
</el-dialog>
<el-dialog title="半成品入库" :close-on-click-modal="false" :visible.sync="dialogFormVisible">
<el-form :model="form">
<el-form-item label="仓库" :label-width="formLabelWidth">
@ -295,7 +308,8 @@
</template>
<script>
import customForm from '@/components/customForm/index';
import {getwproductList, wproductTest, wproductPutin, createputins} from "@/api/wpm";
import reviewForm from '@/components/customForm/review';
import {getwproductList, wproductTest, wproductPutin, createputins,wproductReview} from "@/api/wpm";
import checkPermission from "@/utils/permission";
import {getWarehouseList} from "@/api/inm";
import {getMaterialList, getrecordformList, getrffieldList} from "@/api/mtm";
@ -303,7 +317,7 @@
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
const defaultetestitem = {};
export default {
components: {Pagination, customForm},
components: {Pagination, customForm,reviewForm},
data() {
return {
testitem: defaultetestitem,
@ -360,25 +374,28 @@
],
options: [],
listLoading: true,
fieldList: "",
fieldList: [],
originList: [],
is_testok: "true",
field: [],
recordformList: [],
recordform: "",
recordform: null,
fifo_detail: "",
listQueryrecordform: {
page: 0,
},
origintest:null,
mutipID: [],
wproduct:null,
wproduct: null,
hasPicture: false,
outerVisible: false,
innerVisible: false,
limitedReview: false,
dialogFormVisible: false,
dialogFormVisibles: false,
testrecord: {},
WarehouseData: "",
formName:'项目检查表',
formName: '项目检查表',
};
},
computed: {},
@ -476,6 +493,7 @@
},
handleInspection(scope) {
//调该物料对应的检查表
// this.step = step;
this.outerVisible = true;
this.wproduct = scope.row.id;//半成品ID
this.wproductactstate = scope.row.act_state;//半成品状态
@ -488,17 +506,41 @@
}
});
},
recordformChange(){
//半产品复检
handleReview(scope) {
let that = this;
let arr = this.recordformList.filter(item=>{
return item.id=that.recordform;
})
this.wproduct = scope.row.id;//半成品ID
wproductReview({ wproduct: this.wproduct}).then((response) => {
if (response.data) {
that.hasPicture = false;
that.formName = response.data.name;
let fieldList = response.data.form_fields;
that.fieldList = [...fieldList];
that.origintest = response.data.origin_test.id;
that.recordform = response.data.origin_test.form;
let originList = response.data.origin_test.record_data_;
that.originList = [...originList];
let arr = fieldList.filter(item => {
return item.field_type === 'draw'
});
if (arr.length > 0) {
that.hasPicture = true;
}
this.limitedReview = true;
}
});
},
recordformChange() {
let that = this;
let arr = this.recordformList.filter(item => {
return item.id === that.recordform;
});
that.formName = arr[0].name;
},
//根据选择的表渲染检查项目
submitrecordform() {
let that = this;
if (this.recordform != "") {
if (that.recordform != "") {
getrffieldList({form: this.recordform, page: 1, page_size: 100}).then((response) => {
if (response.data) {
that.hasPicture = false;
@ -515,26 +557,21 @@
});
} else this.$message.error("请选择检查表!");
},
//提交检查项目
submitfield() {
/* submitfield() {
let _this = this;
_this.field = []; //检查项目
this.fieldList.forEach((item) => {
_this.field.push({
form_field: item.id,
field_value: item.sort,
is_testok: item.is_testok//单项检查结果
});
});
console.log(this.recordform);
this.testrecord.form = this.recordform;//检查表
this.testrecord.record_data = _this.field;//检查项列表
this.testrecord.is_testok = this.is_testok;//检查表检查结果
this.testrecord.wproduct = this.wproduct;//半成品ID
wproductTest(this.testrecord).then((res) => {
if (res.code >= 200) {
this.innerVisible = false;
@ -547,7 +584,7 @@
});
},
},*/
//半成品入库
handlePutin(scope) {
this.dialogFormVisible = true;
@ -563,6 +600,7 @@
}
});
},
//提交检查项目
formFunc(value) {
wproductTest(value).then((res) => {
if (res.code >= 200) {

View File

@ -14,4 +14,4 @@ class IProductFilterSet(filters.FilterSet):
order = filters.NumberFilter(field_name="wproduct__subproduction_plan__production_plan__order")
class Meta:
model = IProduct
fields = ['material', 'warehouse', 'batch', 'order', 'is_mtested', 'is_mtestok']
fields = ['material', 'warehouse', 'batch', 'order', 'is_mtested', 'is_mtestok', 'material__type']

View File

@ -5,11 +5,11 @@ from apps.mtm.models import TechDoc
class TechDocFilterset(filters.FilterSet):
# operation = filters.NumberFilter(method='filter_operation')
operation = filters.CharFilter(field_name="subproduction__subplan_subprod__ow_subplan__operation")
operation = filters.NumberFilter(method='filter_operation')
# operation = filters.CharFilter(field_name="subproduction__subplan_subprod__ow_subplan__operation")
class Meta:
model = TechDoc
fields = ['subproduction', 'operation']
# def filter_operation(self, queryset, name, value):
# return queryset.filter(subproduction__subplan_subprod__ow_subplan__operation=value)
def filter_operation(self, queryset, name, value):
return queryset.filter(subproduction__subplan_subprod__ow_subplan__operation=value).distinct()

View File

@ -208,7 +208,7 @@ class RecordFormDetailSerializer(serializers.ModelSerializer):
return queryset
def get_form_fields(self, obj):
serializer = RecordFormFieldSerializer(instance=RecordFormField.objects.filter(form=obj, is_deleted=False), many=True)
serializer = RecordFormFieldSerializer(instance=RecordFormField.objects.filter(form=obj, is_deleted=False).order_by('sort'), many=True)
data = serializer.data
if obj.type == RecordForm.RF_TYPE_TEST:
for i in data:

View File

@ -14,6 +14,13 @@ class ProductionPlan(CommonAModel):
"""
生产计划
"""
# PLAN_STATE_WAIT = 6
# PLAN_STATE_WORKING = 10
# PLAN_STATE_DONE = 20
# state_choices = (
# (PLAN_STATE_WORKING, '进行中'),
# (PLAN_STATE_DONE, '已完成')
# )
number = models.CharField('编号', max_length=50, unique=True)
order = models.ForeignKey(Order, verbose_name='关联订单', null=True, blank=True, on_delete=models.SET_NULL)
product = models.ForeignKey(Material, verbose_name='生产产品', on_delete=models.CASCADE)
@ -47,7 +54,7 @@ class SubProductionPlan(CommonAModel):
(SUBPLAN_STATE_DONE, '已完成')
)
number = models.CharField('子计划编号', max_length=50, unique=True, null=True, blank=True)
production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE)
production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE, related_name='subplan_plan')
subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE, related_name='subplan_subprod')
start_date = models.DateField('计划开工日期')
end_date = models.DateField('计划完工日期')

View File

@ -238,5 +238,3 @@ class ResourceViewSet(GenericViewSet):
equips = Equipment.objects.filter(step_equips__in=steps, is_deleted=False).distinct()
serializer = EquipmentSerializer(instance=equips, many=True)
return Response(serializer.data)

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.9 on 2021-12-10 05:38
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('qm', '0015_alter_testrecord_test_record'),
]
operations = [
migrations.RemoveField(
model_name='testrecord',
name='test_record',
),
migrations.AddField(
model_name='testrecord',
name='origin_test',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='qm.testrecord', verbose_name='原检验记录'),
),
]

View File

@ -64,12 +64,12 @@ class TestRecord(CommonAModel):
is_testok = models.BooleanField('是否合格', default=True)
is_testok_robot = models.BooleanField('自动判定的是否合格', default=True)
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, related_name='test_wproduct')
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)
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)
origin_test = models.ForeignKey('self', verbose_name='检验记录', on_delete=models.CASCADE, null=True, blank=True)
remark = models.TextField('备注', default='')

View File

@ -50,6 +50,7 @@ class TestRecordViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
perms_map = {'*': '*'}
queryset = TestRecord.objects.select_related('fifo_item', 'form').all()
serializer_class = TestRecordListSerializer
filterset_fields = ['wproduct', 'material', 'step', 'subproduction_plan', 'fifo_item', 'origin_test', 'type']
ordering = ['-id']
def get_serializer_class(self):

View File

@ -7,6 +7,7 @@ from apps.inm.serializers import IProductListSerializer
from .models import Contract, Customer, Order, Sale, SaleProduct
from apps.mtm.serializers import MaterialSimpleSerializer
from utils.tools import ranstr
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
@ -44,6 +45,10 @@ class OrderCreateUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = ['number', 'customer', 'contract', 'product', 'count', 'delivery_date']
def create(self, validated_data):
validated_data['number'] = 'DD' + ranstr(7)
return super().create(validated_data)
class OrderSerializer(serializers.ModelSerializer):
contract_ = ContractSimpleSerializer(source='contract', read_only=True)

View File

View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class SrmConfig(AppConfig):
name = 'apps.srm'
verbose_name = '统计报表'

View File

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View File

@ -0,0 +1,22 @@
from rest_framework import serializers
from apps.pm.models import ProductionPlan, SubProductionPlan
from apps.mtm.serializers import ProcessSimpleSerializer
class SubplanGanttSerializer(serializers.ModelSerializer):
count = serializers.IntegerField(source='main_count')
count_real = serializers.IntegerField(source='main_count_real')
count_ok = serializers.IntegerField(source='main_count_ok')
process_ = ProcessSimpleSerializer(source='process', read_only=True)
class Meta:
model = SubProductionPlan
fields = ['id', 'number', 'start_date', 'end_date', 'count', 'count_real', 'count_ok', 'start_date_real', 'end_date_real', 'process_']
class PlanGanttSerializer(serializers.ModelSerializer):
children = serializers.SerializerMethodField()
class Meta:
model = ProductionPlan
fields = ['id', 'number', 'start_date', 'end_date', 'children', 'count', 'count_real', 'count_ok']
def get_children(self, obj):
subplans = SubProductionPlan.objects.filter(production_plan=obj).order_by('process__number')
return SubplanGanttSerializer(instance=subplans, many=True).data

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@ -0,0 +1,13 @@
from django.db.models import base
from rest_framework import urlpatterns
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from apps.srm.views import GanttPlan
router = DefaultRouter()
urlpatterns = [
path('gantt/plan/', GanttPlan.as_view()),
path('', include(router.urls)),
]

View File

@ -0,0 +1,17 @@
from django.shortcuts import render
from rest_framework import serializers
from rest_framework.generics import ListAPIView
from rest_framework.response import Response
from apps.pm.models import ProductionPlan, SubProductionPlan
from apps.srm.serializers import PlanGanttSerializer
# Create your views here.
class GanttPlan(ListAPIView):
"""
计划-子计划甘特图
"""
perms_map = {'get':'*'}
serializer_class = PlanGanttSerializer
queryset = ProductionPlan.objects.filter(is_deleted=False, is_planed=True).prefetch_related('subplan_plan', 'subplan_plan__process')
ordering = ['-id']

View File

@ -13,6 +13,7 @@ class Workflow(CommonAModel):
工作流
"""
name = models.CharField('名称', max_length=50)
key = models.CharField('工作流标识', unique=True, max_length=20)
sn_prefix = models.CharField('流水号前缀', max_length=50, default='hb')
description = models.CharField('描述', max_length=200)
view_permission_check = models.BooleanField('查看权限校验', default=True, help_text='开启后,只允许工单的关联人(创建人、曾经的处理人)有权限查看工单')

View File

@ -5,6 +5,7 @@ import django.utils.timezone as timezone
from django.db.models.query import QuerySet
from apps.inm.models import FIFO, WareHouse
from apps.pm.models import ProductionPlan, SubProductionPlan, SubProductionProgress
from apps.qm.models import TestRecord
from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File
from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords
@ -56,6 +57,12 @@ class WProduct(CommonAModel):
operation = models.ForeignKey('wpm.operation', verbose_name='关联操作',
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation')
@property
def last_process_test(self):
"""
最后的工序自检
"""
return self.test_wproduct.filter(type=TestRecord.TEST_PROCESS).order_by('-id').first()
class WprouctTicket(CommonAModel):
"""
玻璃审批工单

View File

@ -294,8 +294,15 @@ class WpmTestRecordCreateSerializer(serializers.ModelSerializer):
class WpmTestFormInitSerializer(serializers.Serializer):
wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True)
form = serializers.PrimaryKeyRelatedField(queryset=RecordForm.objects.all(), required=True)
form = serializers.PrimaryKeyRelatedField(queryset=RecordForm.objects.all(), required=False)
def validate(self, attrs):
wproduct = attrs['wproduct']
form = attrs.get('form', None)
if wproduct.act_state != WProduct.WPR_ACT_STATE_TORETEST:
if not form:
raise exceptions.APIException('请指定检查表')
return super().validate(attrs)
class WplanPutInSerializer(serializers.Serializer):
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")

View File

@ -193,22 +193,22 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
wproduct = vdata['wproduct']
form = vdata['form']
form = vdata.get('form', None)
# 如果是复检记录, 需要带入原数据
if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST:
# 查找最近一条检验记录
trs = TestRecord.objects.filter(wproduct=wproduct, type=TestRecord.TEST_PROCESS).order_by('-id').first()
trs = wproduct.last_process_test
if trs:
origin_data = TestRecordDetailSerializer(instance=trs).data
data = RecordFormDetailSerializer(instance=form).data
data['origin_data'] = origin_data
origin_test = TestRecordDetailSerializer(instance=trs).data
data = RecordFormDetailSerializer(instance=trs.form).data
data['origin_test'] = origin_test
o_dict = {}
for i in origin_data['record_data_']:
for i in origin_test['record_data_']:
o_dict[i['field_key']] = i['field_value']
for i in data['form_fields']:
i['origin_value'] = o_dict[i['field_key']]
i['origin_value'] = o_dict[i['field_key']] if i['field_key'] in o_dict else None
else:
raise exceptions.APIException('原工序检验记录不存在')
else:
@ -249,7 +249,6 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
m['field_name'] = form_field.field_name
m['field_key'] = form_field.field_key
m['field_type'] = form_field.field_type
m['field_value'] = m['field_value']
m['sort'] = form_field.sort
m['need_judge'] = form_field.need_judge
m['is_testok'] = m['is_testok'] if 'is_testok' in m else None
@ -261,6 +260,8 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
if obj.is_testok:
if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: # 复检
obj.origin_test = wproduct.last_process_test
obj.save()
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
@ -660,7 +661,6 @@ class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
m['field_name'] = form_field.field_name
m['field_key'] = form_field.field_key
m['field_type'] = form_field.field_type
m['field_value'] = m['field_value']
m['sort'] = form_field.sort
m['operation_record'] = opr
wrds.append(OperationRecordItem(**m))

View File

@ -57,7 +57,8 @@ INSTALLED_APPS = [
'apps.sam',
'apps.qm',
'apps.pm',
'apps.wpm'
'apps.wpm',
'apps.srm'
]
MIDDLEWARE = [

View File

@ -69,7 +69,7 @@ urlpatterns = [
path('api/qm/', include('apps.qm.urls')),
path('api/pm/', include('apps.pm.urls')),
path('api/wpm/', include('apps.wpm.urls')),
path('api/srm/', include('apps.srm.urls')),
# 工具
path('api/utils/signature/', GenSignature.as_view()),
path('api/utils/develop/', UpdateDevelop.as_view()),