Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop
This commit is contained in:
commit
c35051df0c
|
@ -4,4 +4,5 @@ deploy.sh
|
|||
package-lock.json
|
||||
.idea/
|
||||
.vscode/
|
||||
.idea/
|
||||
server/static/
|
|
@ -7,3 +7,11 @@ export function getPlanGantt(data) {
|
|||
params: data
|
||||
})
|
||||
}
|
||||
//合格率
|
||||
export function getProcessYield(data) {
|
||||
return request({
|
||||
url: '/srm/process/yield/',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
<template>
|
||||
<div class="tableMneu">
|
||||
<div
|
||||
class="mask"
|
||||
v-if="isShowHeaderBox || menuOpen"
|
||||
@click="maskClick"
|
||||
></div>
|
||||
<el-table
|
||||
ref="tableMenu"
|
||||
:data="tableData"
|
||||
size="mini"
|
||||
fit
|
||||
style="width: 100%;border-top: 1px solid #f5f5f5"
|
||||
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 label="任务编号" prop="name" width="140" show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
<el-table-column label="产品名称" prop="productName" width="120" show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
<el-table-column label="产品型号" prop="productNum">
|
||||
</el-table-column>
|
||||
<el-table-column label="生产数量" prop="per">
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</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;
|
||||
table.scrollTo(0, newValue);
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checkList: [],
|
||||
isShowHeaderBox: false,
|
||||
menuOpen: false,
|
||||
//当前点击的row
|
||||
currentRow: {}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handlerWatchScroll() {
|
||||
let table = this.$refs.tableMenu.bodyWrapper;
|
||||
table.addEventListener("scroll", e => {
|
||||
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);
|
||||
},
|
||||
maskClick() {
|
||||
this.isShowHeaderBox = false;
|
||||
this.menuOpen = false;
|
||||
this.currentRow = {};
|
||||
},
|
||||
handlerRowClick(row) {
|
||||
this.$emit("handlerRowClick", row);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.handlerWatchScroll();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.el-table__header>.has-gutter>tr>th{
|
||||
height: 41px!important;
|
||||
}
|
||||
.tableMneu {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
.mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: transparent;
|
||||
z-index: 9999;
|
||||
}
|
||||
}
|
||||
.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;
|
||||
}
|
||||
}
|
||||
.el-table th.el-table__cell>.cell{
|
||||
font-size: 12px!important;
|
||||
}
|
||||
</style>
|
|
@ -19,7 +19,7 @@
|
|||
@expand-change="handlerExpand"
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||
>
|
||||
<el-table-column label="任务编号" prop="name">
|
||||
<el-table-column label="任务编号" prop="name" width="140" show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
<el-table-column label="产品名称" prop="productName" width="120" show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -35,12 +35,56 @@
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
this.openTheCamera();
|
||||
},
|
||||
methods: {
|
||||
openTheCamera () {
|
||||
this.$nextTick(function () {
|
||||
let _this = this;
|
||||
this.video = document.getElementById('video');
|
||||
// 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
|
||||
if (navigator.mediaDevices === undefined) {
|
||||
navigator.mediaDevices = {}
|
||||
}
|
||||
// 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
|
||||
// 使用getUserMedia,因为它会覆盖现有的属性。
|
||||
// 这里,如果缺少getUserMedia属性,就添加它。
|
||||
if (navigator.mediaDevices.getUserMedia === undefined) {
|
||||
navigator.mediaDevices.getUserMedia = function (constraints) {
|
||||
// 首先获取现存的getUserMedia(如果存在)
|
||||
let getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia;
|
||||
// 有些浏览器不支持,会返回错误信息
|
||||
// 保持接口一致
|
||||
if (!getUserMedia) {
|
||||
return Promise.reject(new Error('getUserMedia is not implemented in this browser'))
|
||||
}
|
||||
// 否则,使用Promise将调用包装到旧的navigator.getUserMedia
|
||||
return new Promise(function (resolve, reject) {
|
||||
getUserMedia.call(navigator, constraints, resolve, reject)
|
||||
})
|
||||
}
|
||||
}
|
||||
let constraints = { audio: false, video: { width: this.videoWidth, height: this.videoHeight, transform: 'scaleX(-1)' } };
|
||||
navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
|
||||
// 旧的浏览器可能没有srcObject
|
||||
if ('srcObject' in _this.video) {
|
||||
_this.video.srcObject = stream
|
||||
} else {
|
||||
// 避免在新的浏览器中使用它,因为它正在被弃用。
|
||||
_this.video.src = window.URL.createObjectURL(stream)
|
||||
}
|
||||
_this.video.onloadedmetadata = function (e) {
|
||||
_this.video.play();
|
||||
};
|
||||
_this.init();
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
});
|
||||
},
|
||||
// 初始化设置
|
||||
init() {
|
||||
this.video = document.getElementById('video');
|
||||
// this.video = document.getElementById('video');
|
||||
this.screenshotCanvas = document.getElementById('screenshotCanvas');
|
||||
let canvas = document.getElementById('canvas');
|
||||
let context = canvas.getContext('2d');
|
||||
|
@ -64,7 +108,6 @@
|
|||
event.data.forEach(function (rect) {
|
||||
context.strokeStyle = '#0764B7';
|
||||
context.strokeRect(rect.x, rect.y, rect.width, rect.height);
|
||||
// window.plot(rect.x, rect.y, rect.width, rect.height+20);
|
||||
// 避免重复发送请求
|
||||
if(!_this.uploadLock){
|
||||
_this.uploadLock = true;
|
||||
|
@ -133,7 +176,10 @@
|
|||
that.uploadLock = false;
|
||||
// this.$message.error('面部识别失败请重新验证');
|
||||
});
|
||||
}
|
||||
},
|
||||
closeCamera () {
|
||||
this.video.srcObject.getTracks()[0].stop();
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -24,12 +24,55 @@
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
this.openTheCamera();
|
||||
},
|
||||
methods: {
|
||||
openTheCamera () {
|
||||
this.$nextTick(function () {
|
||||
let _this = this;
|
||||
this.video = document.getElementById('video');
|
||||
// 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
|
||||
if (navigator.mediaDevices === undefined) {
|
||||
navigator.mediaDevices = {}
|
||||
}
|
||||
// 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
|
||||
// 使用getUserMedia,因为它会覆盖现有的属性。
|
||||
// 这里,如果缺少getUserMedia属性,就添加它。
|
||||
if (navigator.mediaDevices.getUserMedia === undefined) {
|
||||
navigator.mediaDevices.getUserMedia = function (constraints) {
|
||||
// 首先获取现存的getUserMedia(如果存在)
|
||||
let getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia;
|
||||
// 有些浏览器不支持,会返回错误信息
|
||||
// 保持接口一致
|
||||
if (!getUserMedia) {
|
||||
return Promise.reject(new Error('getUserMedia is not implemented in this browser'))
|
||||
}
|
||||
// 否则,使用Promise将调用包装到旧的navigator.getUserMedia
|
||||
return new Promise(function (resolve, reject) {
|
||||
getUserMedia.call(navigator, constraints, resolve, reject)
|
||||
})
|
||||
}
|
||||
}
|
||||
let constraints = { audio: false, video: { width: this.videoWidth, height: this.videoHeight, transform: 'scaleX(-1)' } };
|
||||
navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
|
||||
// 旧的浏览器可能没有srcObject
|
||||
if ('srcObject' in _this.video) {
|
||||
_this.video.srcObject = stream
|
||||
} else {
|
||||
// 避免在新的浏览器中使用它,因为它正在被弃用。
|
||||
_this.video.src = window.URL.createObjectURL(stream)
|
||||
}
|
||||
_this.video.onloadedmetadata = function (e) {
|
||||
_this.video.play();
|
||||
};
|
||||
_this.init();
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
});
|
||||
},
|
||||
// 初始化设置
|
||||
init() {
|
||||
this.video = document.getElementById('video');
|
||||
this.screenshotCanvas = document.getElementById('screenshotCanvas');
|
||||
let canvas = document.getElementById('canvas');
|
||||
let context = canvas.getContext('2d');
|
||||
|
@ -46,7 +89,6 @@
|
|||
let _this = this;
|
||||
//添加事件
|
||||
tracker.on('track', function (event) {
|
||||
|
||||
// 检测出人脸 绘画人脸位置
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
// 给每个人脸绘制对应的框
|
||||
|
@ -112,7 +154,10 @@
|
|||
that.uploadLock = false;
|
||||
// this.$message.error('面部识别失败请重新验证');
|
||||
});
|
||||
}
|
||||
},
|
||||
closeCamera () {
|
||||
this.video.srcObject.getTracks()[0].stop();
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -64,10 +64,10 @@
|
|||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog :visible.sync="limitedPhoto">
|
||||
<el-dialog :visible.sync="limitedPhoto" @close="closeCamera">
|
||||
<div style="font-size: 28px;color: #333333;text-align: center;font-weight: bold;margin-bottom: 15px;">打卡</div>
|
||||
<div class="testTracking">
|
||||
<faceLogin name="faceLogin" @func="getMsgFormSon"></faceLogin>
|
||||
<faceLogin ref="faceTracking" name="faceLogin" @func="getMsgFormSon"></faceLogin>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
@ -179,9 +179,61 @@
|
|||
//人脸登录
|
||||
takePhoto(){
|
||||
this.limitedPhoto = true;
|
||||
this.openTheCamera();
|
||||
},
|
||||
/*打开相机*/
|
||||
openTheCamera () {
|
||||
this.$nextTick(function () {
|
||||
let _this = this;
|
||||
this.thisVideo = document.getElementById('videoCamera');
|
||||
// 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
|
||||
if (navigator.mediaDevices === undefined) {
|
||||
navigator.mediaDevices = {}
|
||||
}
|
||||
// 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
|
||||
// 使用getUserMedia,因为它会覆盖现有的属性。
|
||||
// 这里,如果缺少getUserMedia属性,就添加它。
|
||||
if (navigator.mediaDevices.getUserMedia === undefined) {
|
||||
navigator.mediaDevices.getUserMedia = function (constraints) {
|
||||
// 首先获取现存的getUserMedia(如果存在)
|
||||
let getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia;
|
||||
// 有些浏览器不支持,会返回错误信息
|
||||
// 保持接口一致
|
||||
if (!getUserMedia) {
|
||||
return Promise.reject(new Error('getUserMedia is not implemented in this browser'))
|
||||
}
|
||||
// 否则,使用Promise将调用包装到旧的navigator.getUserMedia
|
||||
return new Promise(function (resolve, reject) {
|
||||
getUserMedia.call(navigator, constraints, resolve, reject)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let constraints = { audio: false, video: { width: this.videoWidth, height: this.videoHeight, transform: 'scaleX(-1)' } };
|
||||
navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
|
||||
// 旧的浏览器可能没有srcObject
|
||||
if ('srcObject' in _this.thisVideo) {
|
||||
_this.thisVideo.srcObject = stream
|
||||
} else {
|
||||
// 避免在新的浏览器中使用它,因为它正在被弃用。
|
||||
_this.thisVideo.src = window.URL.createObjectURL(stream)
|
||||
}
|
||||
_this.thisVideo.onloadedmetadata = function (e) {
|
||||
_this.thisVideo.play();
|
||||
}
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
});
|
||||
},
|
||||
/*关闭相机*/
|
||||
closeCamera () {
|
||||
debugger;
|
||||
this.$refs.faceTracking.closeCamera();
|
||||
// this.thisVideo.srcObject.getTracks()[0].stop();
|
||||
},
|
||||
getMsgFormSon(data){
|
||||
this.limitedPhoto = data;
|
||||
// this.limitedPhoto = data;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -121,7 +121,7 @@
|
|||
<el-form
|
||||
ref="Form"
|
||||
:model="material"
|
||||
label-width="80px"
|
||||
label-width="100px"
|
||||
label-position="right"
|
||||
:rules="rule1"
|
||||
>
|
||||
|
@ -131,41 +131,42 @@
|
|||
<el-form-item label="物料编号" prop="number">
|
||||
<el-input v-model="material.number" placeholder="物料编号"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="规格型号" prop="specification">
|
||||
<el-form-item label="规格型号">
|
||||
<el-input v-model="material.specification" placeholder="规格型号"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="计量单位" prop="unit">
|
||||
<el-form-item label="计量单位">
|
||||
<el-select style="width: 100%" v-model="material.unit" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in unitoptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="物料类别" prop="type">
|
||||
|
||||
<el-select style="width: 100%" v-model="material.type" placeholder="请选择">
|
||||
<el-form-item label="物料类别">
|
||||
<el-select style="width: 100%" v-model="material.type" placeholder="请选择物料类别">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="单片玻璃数量" prop="piece_count" v-if="material.type==1">
|
||||
<el-form-item label="单片玻璃数量" v-if="material.type==1">
|
||||
<el-input v-model="material.piece_count" placeholder="单片玻璃数量"/>
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item label="排序" prop="sort_str">
|
||||
<el-input v-model="material.sort_str" placeholder="排序"/>
|
||||
<el-form-item label="安全库存数">
|
||||
<el-input-number style="width: 100%;" v-model="material.count_safe" :step="1" :min="0" step-strictly placeholder="安全库存数"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序">
|
||||
<el-input-number style="width: 100%;" v-model="material.sort_str" :step="1" :min="0" step-strictly placeholder="排序"></el-input-number>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
<div style="text-align: right">
|
||||
<el-button type="danger" @click="dialogVisible = false">取消</el-button>
|
||||
|
@ -189,8 +190,14 @@
|
|||
import {genTree} from "@/utils";
|
||||
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
|
||||
const defaultmaterial = {
|
||||
name: "",
|
||||
number: "",
|
||||
name: null,
|
||||
number: null,
|
||||
specification: null,
|
||||
unit: null,
|
||||
type: null,
|
||||
piece_count: null,
|
||||
sort_str: null,
|
||||
count_safe: 0,
|
||||
processes: [],
|
||||
};
|
||||
export default {
|
||||
|
@ -270,19 +277,13 @@
|
|||
created() {
|
||||
this.getList();
|
||||
this.getProcessList();
|
||||
|
||||
},
|
||||
methods: {
|
||||
checkPermission,
|
||||
|
||||
//物料详情
|
||||
handledetail(scope)
|
||||
{
|
||||
handledetail(scope){
|
||||
this.$router.push({name: "MaterialDetail", params: { id: scope.row.id,type: scope.row.type }, })
|
||||
|
||||
},
|
||||
|
||||
|
||||
//选项卡切换
|
||||
handleClick(tab) {
|
||||
this.listLoading = true;
|
||||
|
@ -311,10 +312,8 @@
|
|||
},
|
||||
//绑定工序
|
||||
handlebind(scope) {
|
||||
|
||||
this.$router.push({name: "MaterialDO", params: {id: scope.row.id},})
|
||||
}
|
||||
,
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.page = 1;
|
||||
this.getList();
|
||||
|
@ -324,7 +323,7 @@
|
|||
this.listQuery = {
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
}
|
||||
};
|
||||
this.getList();
|
||||
},
|
||||
handleCreate() {
|
||||
|
@ -335,7 +334,6 @@
|
|||
this.$refs["Form"].clearValidate();
|
||||
});
|
||||
},
|
||||
|
||||
handleEdit(scope) {
|
||||
this.material = Object.assign({}, scope.row); // copy obj
|
||||
this.dialogType = "edit";
|
||||
|
@ -359,7 +357,6 @@
|
|||
console.error(err);
|
||||
});
|
||||
},
|
||||
|
||||
async confirm(form) {
|
||||
this.$refs[form].validate((valid) => {
|
||||
if (valid) {
|
||||
|
|
|
@ -82,8 +82,8 @@
|
|||
<div style="text-align: right">
|
||||
<el-button type="danger" @click="dialogVisible = false">取消
|
||||
</el-button>
|
||||
<!--<el-button type="primary" @click="recordformconfirm('Forms')">确认</el-button>-->
|
||||
<el-button type="primary" @click="recordformcon">管理员授权</el-button>
|
||||
<el-button type="primary" @click="recordformconfirm('Forms')">确认</el-button>
|
||||
<!--<el-button type="primary" @click="recordformcon">管理员授权</el-button>-->
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!--表格展示-->
|
||||
|
|
|
@ -1,313 +1,255 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-card style="margin-top: 2px">
|
||||
<el-descriptions title="任务详情" :column="4" border style="margin-bottom: 20px">
|
||||
<el-descriptions-item label="任务编号">{{productionplan.number}}</el-descriptions-item>
|
||||
<el-descriptions-item label="产品名称" v-if="productionplan.product_">{{productionplan.product_.name}}</el-descriptions-item>
|
||||
<el-descriptions-item label="规格型号" v-if="productionplan.product_">{{productionplan.product_.specification}}</el-descriptions-item>
|
||||
<el-descriptions-item label="生产数量">{{productionplan.count}}</el-descriptions-item>
|
||||
<el-descriptions-item label="生产状态">{{state_[productionplan.state]}}</el-descriptions-item>
|
||||
<el-descriptions-item label="计划开工时间">{{productionplan.start_date}}</el-descriptions-item>
|
||||
<el-descriptions-item label="计划完工时间">{{productionplan.end_date}}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
|
||||
<el-table
|
||||
:data="wproduct"
|
||||
border
|
||||
fit
|
||||
stripe
|
||||
style="width: 100%"
|
||||
height="500"
|
||||
>
|
||||
|
||||
<el-table-column type="index" label="序号" width="50" />
|
||||
|
||||
|
||||
<el-table-column label="玻璃编号/产品编号" >
|
||||
<template slot-scope="scope" >{{ scope.row.number }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="所在子工序">
|
||||
<template slot-scope="scope" >{{
|
||||
scope.row.step_.name
|
||||
}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="产品状态" >
|
||||
<template slot-scope="scope">{{
|
||||
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>
|
||||
<el-table-column label="最后检验结果">
|
||||
<template slot-scope="scope" >
|
||||
<el-span v-if="scope.row.last_test_result==false">不合格</el-span>
|
||||
<el-span v-if="scope.row.last_test_result==true">合格</el-span>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="生产记录">
|
||||
<template slot-scope="scope" >
|
||||
<el-button @click="select(scope)">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
<el-descriptions title="任务详情" :column="4" border style="margin-bottom: 20px">
|
||||
<el-descriptions-item label="任务编号">{{productionplan.number}}</el-descriptions-item>
|
||||
<el-descriptions-item label="产品名称" v-if="productionplan.product_">{{productionplan.product_.name}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="规格型号" v-if="productionplan.product_">{{productionplan.product_.specification}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="生产数量">{{productionplan.count}}</el-descriptions-item>
|
||||
<el-descriptions-item label="生产状态">{{state_[productionplan.state]}}</el-descriptions-item>
|
||||
<el-descriptions-item label="计划开工时间">{{productionplan.start_date}}</el-descriptions-item>
|
||||
<el-descriptions-item label="计划完工时间">{{productionplan.end_date}}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-table
|
||||
:data="wproduct"
|
||||
border
|
||||
fit
|
||||
stripe
|
||||
style="width: 100%"
|
||||
height="500"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="50"/>
|
||||
<el-table-column label="玻璃编号/产品编号">
|
||||
<template slot-scope="scope">{{ scope.row.number }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="所在子工序">
|
||||
<template slot-scope="scope">
|
||||
{{scope.row.step_.name}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="产品状态">
|
||||
<template slot-scope="scope">{{
|
||||
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>
|
||||
<el-table-column label="最后检验结果">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.last_test_result==false">不合格</span>
|
||||
<span v-if="scope.row.last_test_result==true">合格</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="生产记录">
|
||||
<template slot-scope="scope">
|
||||
<el-button @click="select(scope)">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
align="center"
|
||||
label="操作"
|
||||
width="220px"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
|
||||
<el-link
|
||||
v-if="checkPermission(['material_delete'])"
|
||||
type="primary"
|
||||
@click="handleoption(scope)"
|
||||
>生成流程卡</el-link
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
||||
</el-table>
|
||||
|
||||
<!--检验记录-->
|
||||
<el-dialog title="检验记录" :visible.sync="limitedCheckRecord">
|
||||
<el-table
|
||||
:data="recordList"
|
||||
border
|
||||
height="400"
|
||||
>
|
||||
<el-table-column type="index" width="50"/>
|
||||
<el-table-column label="表单名称">
|
||||
<template slot-scope="scope">{{ scope.row.form_.name }}</template>
|
||||
</el-table-column>
|
||||
|
||||
|
||||
<el-table-column align="center" label="操作">
|
||||
<template slot-scope="scope">
|
||||
|
||||
<el-link
|
||||
|
||||
@click="handleRecordDetail(scope)"
|
||||
>查看
|
||||
>生成流程卡
|
||||
</el-link>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">取 消</el-button>
|
||||
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!--检验记录-->
|
||||
<el-dialog title="检验记录" :visible.sync="limitedCheckRecord">
|
||||
<el-table
|
||||
:data="recordList"
|
||||
border
|
||||
height="400"
|
||||
>
|
||||
<el-table-column type="index" width="50"/>
|
||||
<el-table-column label="表单名称">
|
||||
<template slot-scope="scope">{{ scope.row.form_.name }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="操作">
|
||||
<template slot-scope="scope">
|
||||
<el-link
|
||||
@click="handleRecordDetail(scope)"
|
||||
>查看
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!--非检查表显示-->
|
||||
<el-dialog
|
||||
width="60%"
|
||||
:title="formName"
|
||||
:visible.sync="recordVisible"
|
||||
:close-on-click-modal="false"
|
||||
@close="recordCancel"
|
||||
>
|
||||
<customForm
|
||||
v-if="recordVisible"
|
||||
:results="fieldList"
|
||||
:hasPicture="hasPicture"
|
||||
:formID="recordform"
|
||||
:wproduct="wproduct"
|
||||
:recordId="recordId"
|
||||
:isDisabled="isDisabled"
|
||||
@recordSubmit="recordSubmit"
|
||||
@recordSave="recordSave"
|
||||
@recordCancel="recordCancel"
|
||||
/>
|
||||
<el-row>
|
||||
<el-col v-for="item in fieldList" :key="item.id" :span="12">
|
||||
<div class="items" v-if="item.field_type!=='draw'">
|
||||
<span class="itemLabel">{{item.field_name}}:</span>
|
||||
<span>{{item.field_value}}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col v-for="item in fieldList" :key="item.id" :span="24">
|
||||
<div class="items" v-if="item.field_type==='draw'" style="height: 400px">
|
||||
<span class="itemLabel">{{item.field_name}}:</span>
|
||||
<img style="width: 45%;vertical-align: text-top;" :src="'http://47.95.0.242:2222'+item.field_value"/>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
import { getProductionplan,getsubproductionplanList } from "@/api/pm";
|
||||
import { getwproductList,getrecordList} from "@/api/wpm";
|
||||
import checkPermission from "@/utils/permission";
|
||||
import customForm from '@/components/customForm/index'
|
||||
import {getrffieldList} from "@/api/mtm";
|
||||
|
||||
import { getTestRecord ,getTestRecordItem} from "@/api/qm";
|
||||
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
|
||||
const defaultrecordform = {enabled:false};
|
||||
export default {
|
||||
components: { Pagination,customForm },
|
||||
data() {
|
||||
return {
|
||||
productionplan:{
|
||||
number:""
|
||||
},
|
||||
activeName:"1",
|
||||
wproduct:[],
|
||||
recordList:[],
|
||||
limitedCheckRecord:false,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
},
|
||||
state_:{
|
||||
10:'制定中',
|
||||
20:'已下达',
|
||||
30:'已接受',
|
||||
40:'生产中',
|
||||
50:'已完成',
|
||||
60:'军检完成'},
|
||||
actstate_: {
|
||||
6: "待复检",
|
||||
10: "操作进行中",
|
||||
20: "待检验",
|
||||
30: "已合格",
|
||||
40: "库存中",
|
||||
50: "不合格",
|
||||
60: "待成品检验",
|
||||
8: "操作准备中",
|
||||
26: "待夹层检验",
|
||||
70: "报废",
|
||||
},
|
||||
process_json:null,
|
||||
productionplanID:null,
|
||||
dialogVisibleForm: false,
|
||||
tableForm:{
|
||||
name:'',
|
||||
import {getProductionplan} from "@/api/pm";
|
||||
import {getwproductList, getrecordList,recordInit} from "@/api/wpm";
|
||||
import checkPermission from "@/utils/permission";
|
||||
const defaultrecordform = {enabled: false};
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
productionplan: {
|
||||
number: ""
|
||||
},
|
||||
|
||||
activeName: "1",
|
||||
wproduct: [],
|
||||
recordList: [],
|
||||
limitedCheckRecord: false,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
},
|
||||
state_: {
|
||||
10: '制定中',
|
||||
20: '已下达',
|
||||
30: '已接受',
|
||||
40: '生产中',
|
||||
50: '已完成',
|
||||
60: '军检完成'
|
||||
},
|
||||
actstate_: {
|
||||
6: "待复检",
|
||||
10: "操作进行中",
|
||||
20: "待检验",
|
||||
30: "已合格",
|
||||
40: "库存中",
|
||||
50: "不合格",
|
||||
60: "待成品检验",
|
||||
8: "操作准备中",
|
||||
26: "待夹层检验",
|
||||
70: "报废",
|
||||
},
|
||||
process_json: null,
|
||||
productionplanID: null,
|
||||
dialogVisibleForm: false,
|
||||
recordform: defaultrecordform,
|
||||
dialogType: "new",
|
||||
dialogVisible: false,
|
||||
dialogType1: "new",
|
||||
dialogVisible1: false,
|
||||
tableForm: defaultrecordform,
|
||||
checkForm: {
|
||||
hhh: '',
|
||||
},
|
||||
|
||||
recordVisible: false,
|
||||
customfieldList: [],
|
||||
recordform: null,
|
||||
recordId: null,
|
||||
fifo_detail: "",
|
||||
formName: "项目检查表",
|
||||
hasPicture: false,
|
||||
fieldList: [],
|
||||
customfieldList: [],
|
||||
recordId: null,
|
||||
fifo_detail: "",
|
||||
formName: "项目检查表",
|
||||
hasPicture: false,
|
||||
fieldList: [],
|
||||
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
created() {
|
||||
this.id = this.$route.params.id;
|
||||
this.getList();
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
created() {
|
||||
this.id = this.$route.params.id;
|
||||
this.getList();
|
||||
|
||||
this.getwproductList();
|
||||
this.getwproductList();
|
||||
|
||||
},
|
||||
methods: {
|
||||
checkPermission,
|
||||
},
|
||||
methods: {
|
||||
checkPermission,
|
||||
|
||||
getList() {
|
||||
getProductionplan(this.id).then((response) => {
|
||||
if (response.data) {
|
||||
this.productionplan = response.data;
|
||||
this.productionplanID=response.data.id;
|
||||
getList() {
|
||||
getProductionplan(this.id).then((response) => {
|
||||
if (response.data) {
|
||||
this.productionplan = response.data;
|
||||
this.productionplanID = response.data.id;
|
||||
|
||||
let process_json = [];
|
||||
for(let item in response.data.process_json){
|
||||
let obj = new Object();
|
||||
obj = response.data.process_json[item];
|
||||
process_json.push(obj)
|
||||
let process_json = [];
|
||||
for (let item in response.data.process_json) {
|
||||
let obj = new Object();
|
||||
obj = response.data.process_json[item];
|
||||
process_json.push(obj)
|
||||
}
|
||||
this.process_json = process_json;
|
||||
}
|
||||
|
||||
|
||||
this.process_json= process_json;
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
getwproductList()
|
||||
{
|
||||
getwproductList({production_plan:this.id,page:0,}).then((response) => {
|
||||
if (response.data) {
|
||||
this.wproduct = response.data;
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
//查看该玻璃检验记录表
|
||||
handleoption(scope){
|
||||
|
||||
this.$router.push({name: "processcard", params: { id: scope.row.id }, })
|
||||
|
||||
},
|
||||
//查看生产记录
|
||||
select(scope)
|
||||
{
|
||||
this.limitedCheckRecord=true;
|
||||
getrecordList({wproduct: scope.row.id,page:0}).then(res => {
|
||||
});
|
||||
},
|
||||
getwproductList() {
|
||||
getwproductList({production_plan: this.id, page: 0,}).then((response) => {
|
||||
if (response.data) {
|
||||
this.wproduct = response.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
//查看该玻璃检验记录表
|
||||
handleoption(scope) {
|
||||
this.$router.push({name: "processcard", params: {id: scope.row.id},})
|
||||
},
|
||||
//查看生产记录
|
||||
select(scope) {
|
||||
this.limitedCheckRecord = true;
|
||||
getrecordList({wproduct: scope.row.id, page: 0}).then(res => {
|
||||
if (res.code == 200) {
|
||||
this.recordList = res.data;
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
//点击记录里的查看
|
||||
handleRecordDetail(scope) {
|
||||
let that = this;
|
||||
that.recordVisible = false;
|
||||
that.recordId = scope.row.id;
|
||||
that.recordform = scope.row.form;
|
||||
that.formName = scope.row.form_.name;
|
||||
getrffieldList({ form: this.recordform, page: 1, page_size: 100 }).then(
|
||||
(response) => {
|
||||
if (response.data) {
|
||||
that.hasPicture = false;
|
||||
let fieldList = response.data.results;
|
||||
that.fieldList = [...fieldList];
|
||||
let arr = fieldList.filter((item) => {
|
||||
return item.field_type === "draw";
|
||||
});
|
||||
if (arr.length > 0) {
|
||||
that.hasPicture = true;
|
||||
}
|
||||
getTestRecordItem(scope.row.id).then((res) => {
|
||||
let arr = [];
|
||||
let fieldList = res.data.record_data;
|
||||
for (let i = 0; i < that.fieldList.length; i++) {
|
||||
let obj = that.fieldList[i];
|
||||
obj.is_testok = null;
|
||||
for (let j = 0; j < fieldList.length; j++) {
|
||||
if (that.fieldList[i].field_key === fieldList[j].field_key) {
|
||||
obj.id = fieldList[j].id;
|
||||
obj.is_testok = fieldList[j].is_testok;
|
||||
obj.field_value = fieldList[j].field_value;
|
||||
}
|
||||
}
|
||||
arr.push(obj);
|
||||
}
|
||||
that.fieldList = arr;
|
||||
that.$nextTick(() => {
|
||||
that.isDisabled = true;
|
||||
that.recordVisible = true;
|
||||
});
|
||||
});
|
||||
},
|
||||
//点击记录里的查看
|
||||
handleRecordDetail(scope) {
|
||||
let that = this;
|
||||
that.fieldList = [];
|
||||
recordInit(scope.row.id).then((res) => {
|
||||
if (res.code >= 200) {
|
||||
that.recordVisible = true;
|
||||
that.formName = res.data.form_.name;
|
||||
that.fieldList = res.data.record_data;
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.items {
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.itemLabel {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -119,7 +119,6 @@
|
|||
:title="formName"
|
||||
:visible.sync="recordVisible"
|
||||
:close-on-click-modal="false"
|
||||
@close="recordCancel"
|
||||
>
|
||||
<el-row>
|
||||
<el-col v-for="item in fieldList" :key="item.id" :span="12">
|
||||
|
|
|
@ -1,305 +1,283 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-card style="margin-top: 2px">
|
||||
<el-descriptions title="任务详情" :column="5" border style="margin-bottom: 20px">
|
||||
<el-descriptions-item label="任务编号">{{productionplan.number}}</el-descriptions-item>
|
||||
<el-descriptions-item label="产品名称" v-if="productionplan.product_">{{productionplan.product_.name}}</el-descriptions-item>
|
||||
<el-descriptions-item label="规格型号" v-if="productionplan.product_">{{productionplan.product_.specification}}</el-descriptions-item>
|
||||
<el-descriptions-item label="生产状态">{{state_[productionplan.state]}}</el-descriptions-item>
|
||||
<el-descriptions-item label="不合格品数量">{{productionplan.count_notok}}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-card style="margin-bottom: 20px">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>下料清单</span>
|
||||
|
||||
</div>
|
||||
<el-table
|
||||
:data="cut"
|
||||
border
|
||||
fit
|
||||
stripe
|
||||
style="width: 100%"
|
||||
>
|
||||
|
||||
<el-table-column label="序号" type="index" width="50" />
|
||||
|
||||
|
||||
<el-table-column label="玻璃批次" >
|
||||
<template slot-scope="scope" >{{ scope.row.from_batch }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="生产型号" >
|
||||
<template slot-scope="scope" >{{ scope.row.from_material_.specification }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="切裁规格" >
|
||||
<template slot-scope="scope" >{{ scope.row.from_material_.specification }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="切裁板数" >
|
||||
<template slot-scope="scope" >{{ scope.row.count_cut }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="切裁片数" >
|
||||
<template slot-scope="scope" >{{ scope.row.count_real }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="成品数量" >
|
||||
<template slot-scope="scope" >{{ scope.row.count_ok }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作人" >
|
||||
<template slot-scope="scope" >{{ scope.row.create_by_.username }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="甩片原因及数量(片)" >
|
||||
<el-table-column label="气泡" >
|
||||
<template slot-scope="scope" >{{ scope.row.count_qipao }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="破点" >
|
||||
<template slot-scope="scope" >{{ scope.row.count_podian }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="划伤" >
|
||||
<template slot-scope="scope" >{{ scope.row.count_hua }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="其他" >
|
||||
<template slot-scope="scope" >{{ scope.row.count_other }}</template>
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
<el-table-column label="检验员" >
|
||||
<template slot-scope="scope" >{{ scope.row.create_by_.username }}</template>
|
||||
</el-table-column>
|
||||
|
||||
|
||||
|
||||
</el-table>
|
||||
</el-card>
|
||||
<el-tabs v-model="activeName" type="card" >
|
||||
<el-tab-pane label="玻璃" name="1" >
|
||||
<el-descriptions title="任务详情" :column="5" border style="margin-bottom: 20px">
|
||||
<el-descriptions-item label="任务编号">{{productionplan.number}}</el-descriptions-item>
|
||||
<el-descriptions-item label="产品名称" v-if="productionplan.product_">{{productionplan.product_.name}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="规格型号" v-if="productionplan.product_">{{productionplan.product_.specification}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="生产状态">{{state_[productionplan.state]}}</el-descriptions-item>
|
||||
<el-descriptions-item label="不合格品数量">{{productionplan.count_notok}}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-card style="margin-bottom: 20px">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>下料清单</span>
|
||||
</div>
|
||||
<el-table
|
||||
:data="wproduct"
|
||||
border
|
||||
fit
|
||||
row-key="id"
|
||||
stripe
|
||||
style="width: 100%"
|
||||
height="500"
|
||||
:load="load"
|
||||
:tree-props="{children: 'children'}">
|
||||
|
||||
<el-table-column type="index" width="50" />
|
||||
|
||||
|
||||
<el-table-column label="玻璃编号" >
|
||||
<template slot-scope="scope" >{{ scope.row.number }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="所在子工序">
|
||||
<template slot-scope="scope" >{{
|
||||
scope.row.step_.name
|
||||
}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="玻璃状态">
|
||||
<template slot-scope="scope" >{{
|
||||
scope.row.material_.name
|
||||
}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" >
|
||||
<template slot-scope="scope" >{{
|
||||
actstate_[scope.row.act_state]
|
||||
}}</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
align="center"
|
||||
label="过程记录"
|
||||
width="220px"
|
||||
:data="cut"
|
||||
border
|
||||
fit
|
||||
stripe
|
||||
style="width: 100%"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
|
||||
<el-link
|
||||
v-if="checkPermission(['material_delete'])"
|
||||
type="primary"
|
||||
@click="handleoption(scope)"
|
||||
>查看</el-link
|
||||
<el-table-column label="序号" type="index" width="50"/>
|
||||
<el-table-column label="玻璃批次">
|
||||
<template slot-scope="scope">{{ scope.row.from_batch }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="生产型号">
|
||||
<template slot-scope="scope">{{ scope.row.from_material_.specification }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="切裁规格">
|
||||
<template slot-scope="scope">{{ scope.row.from_material_.specification }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="切裁板数">
|
||||
<template slot-scope="scope">{{ scope.row.count_cut }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="切裁片数">
|
||||
<template slot-scope="scope">{{ scope.row.count_real }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="成品数量">
|
||||
<template slot-scope="scope">{{ scope.row.count_ok }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作人">
|
||||
<template slot-scope="scope">{{ scope.row.create_by_.username }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="甩片原因及数量(片)">
|
||||
<el-table-column label="气泡">
|
||||
<template slot-scope="scope">{{ scope.row.count_qipao }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="破点">
|
||||
<template slot-scope="scope">{{ scope.row.count_podian }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="划伤">
|
||||
<template slot-scope="scope">{{ scope.row.count_hua }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="其他">
|
||||
<template slot-scope="scope">{{ scope.row.count_other }}</template>
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
<el-table-column label="检验员">
|
||||
<template slot-scope="scope">{{ scope.row.create_by_.username }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
<el-tabs v-model="activeName" type="card">
|
||||
<el-tab-pane label="玻璃" name="1">
|
||||
<el-table
|
||||
:data="wproduct"
|
||||
border
|
||||
fit
|
||||
row-key="id"
|
||||
stripe
|
||||
style="width: 100%"
|
||||
height="500"
|
||||
:tree-props="{children: 'children'}">
|
||||
<el-table-column type="index" width="50"/>
|
||||
<el-table-column label="玻璃编号">
|
||||
<template slot-scope="scope">{{ scope.row.number }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="所在子工序">
|
||||
<template slot-scope="scope">
|
||||
{{scope.row.step_.name}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="玻璃状态">
|
||||
<template slot-scope="scope">
|
||||
{{scope.row.material_.name}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态">
|
||||
<template slot-scope="scope">
|
||||
{{actstate_[scope.row.act_state]}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
align="center"
|
||||
label="过程记录"
|
||||
width="220px"
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
||||
</el-table>
|
||||
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="工序" name="2" >
|
||||
<el-table
|
||||
:data="process_json"
|
||||
border
|
||||
fit
|
||||
stripe
|
||||
style="width: 100%"
|
||||
height="500"
|
||||
>
|
||||
|
||||
<el-table-column type="index" width="50" />
|
||||
|
||||
|
||||
<el-table-column label="工序名称" >
|
||||
<template slot-scope="scope" >{{ scope.row.process_name }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="玻璃数量" >
|
||||
<template slot-scope="scope" >{{ scope.row.count_real }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="合格数量" >
|
||||
<template slot-scope="scope" >{{ scope.row.count_ok }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="不合格数量" >
|
||||
<template slot-scope="scope" >{{ scope.row.count_notok }}</template>
|
||||
</el-table-column>
|
||||
|
||||
|
||||
<el-table-column
|
||||
align="center"
|
||||
label="过程记录"
|
||||
width="220px"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
|
||||
<el-link
|
||||
v-if="checkPermission(['material_delete'])"
|
||||
type="primary"
|
||||
@click="handleprocess(scope)"
|
||||
>查看</el-link
|
||||
<template slot-scope="scope">
|
||||
<el-link
|
||||
v-if="checkPermission(['material_delete'])"
|
||||
type="primary"
|
||||
@click="handleoption(scope)"
|
||||
>查看
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="工序" name="2">
|
||||
<el-table
|
||||
:data="process_json"
|
||||
border
|
||||
fit
|
||||
stripe
|
||||
style="width: 100%"
|
||||
height="500"
|
||||
>
|
||||
<el-table-column type="index" width="50"/>
|
||||
<el-table-column label="工序名称">
|
||||
<template slot-scope="scope">{{ scope.row.process_name }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="玻璃数量">
|
||||
<template slot-scope="scope">{{ scope.row.count_real }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="合格数量">
|
||||
<template slot-scope="scope">{{ scope.row.count_ok }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="不合格数量">
|
||||
<template slot-scope="scope">{{ scope.row.count_notok }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
align="center"
|
||||
label="过程记录"
|
||||
width="220px"
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
<template slot-scope="scope">
|
||||
<el-link
|
||||
v-if="checkPermission(['material_delete'])"
|
||||
type="primary"
|
||||
@click="handleprocess(scope)"
|
||||
>查看
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
import { getProductionplan,getsubproductionplanList } from "@/api/pm";
|
||||
import { getwproductList,getcutList} from "@/api/wpm";
|
||||
import checkPermission from "@/utils/permission";
|
||||
import {getProductionplan, getsubproductionplanList} from "@/api/pm";
|
||||
import {getwproductList, getcutList} from "@/api/wpm";
|
||||
import checkPermission from "@/utils/permission";
|
||||
|
||||
import {getTestRecord} from "@/api/qm";
|
||||
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
|
||||
import {getTestRecord} from "@/api/qm";
|
||||
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
|
||||
|
||||
export default {
|
||||
components: { Pagination },
|
||||
data() {
|
||||
return {
|
||||
productionplan:{
|
||||
number:""
|
||||
},
|
||||
cut:[],
|
||||
activeName:"1",
|
||||
wproduct:[],
|
||||
subproductionplanList: "",
|
||||
listQuery: {
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
},
|
||||
state_:{
|
||||
10:'制定中',
|
||||
20:'已下达',
|
||||
30:'已接受',
|
||||
40:'生产中',
|
||||
50:'已完成',
|
||||
60:'军检完成'},
|
||||
actstate_: {
|
||||
6: "待复检",
|
||||
10: "操作进行中",
|
||||
20: "待检验",
|
||||
30: "已合格",
|
||||
40: "库存中",
|
||||
50: "不合格",
|
||||
60: "待成品检验",
|
||||
8: "操作准备中",
|
||||
26: "待夹层检验",
|
||||
70: "报废",
|
||||
},
|
||||
process_json:null,
|
||||
productionplanID:null,
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
created() {
|
||||
this.id = this.$route.params.id;
|
||||
this.getList();
|
||||
this.gecutList();
|
||||
this.getspList();
|
||||
this.getwproductList();
|
||||
export default {
|
||||
components: {Pagination},
|
||||
data() {
|
||||
return {
|
||||
productionplan: {
|
||||
number: ""
|
||||
},
|
||||
cut: [],
|
||||
activeName: "1",
|
||||
wproduct: [],
|
||||
subproductionplanList: "",
|
||||
listQuery: {
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
},
|
||||
state_: {
|
||||
10: '制定中',
|
||||
20: '已下达',
|
||||
30: '已接受',
|
||||
40: '生产中',
|
||||
50: '已完成',
|
||||
60: '军检完成'
|
||||
},
|
||||
actstate_: {
|
||||
6: "待复检",
|
||||
10: "操作进行中",
|
||||
20: "待检验",
|
||||
30: "已合格",
|
||||
40: "库存中",
|
||||
50: "不合格",
|
||||
60: "待成品检验",
|
||||
8: "操作准备中",
|
||||
26: "待夹层检验",
|
||||
70: "报废",
|
||||
},
|
||||
process_json: null,
|
||||
productionplanID: null,
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
created() {
|
||||
this.id = this.$route.params.id;
|
||||
this.getList();
|
||||
this.gecutList();
|
||||
this.getspList();
|
||||
this.getwproductList();
|
||||
|
||||
},
|
||||
methods: {
|
||||
checkPermission,
|
||||
},
|
||||
methods: {
|
||||
checkPermission,
|
||||
|
||||
getList() {
|
||||
getProductionplan(this.id).then((response) => {
|
||||
if (response.data) {
|
||||
this.productionplan = response.data;
|
||||
this.productionplanID=response.data.id;
|
||||
getList() {
|
||||
getProductionplan(this.id).then((response) => {
|
||||
if (response.data) {
|
||||
this.productionplan = response.data;
|
||||
this.productionplanID = response.data.id;
|
||||
|
||||
let process_json = [];
|
||||
for(let item in response.data.process_json){
|
||||
let obj = new Object();
|
||||
obj = response.data.process_json[item];
|
||||
process_json.push(obj)
|
||||
let process_json = [];
|
||||
for (let item in response.data.process_json) {
|
||||
let obj = new Object();
|
||||
obj = response.data.process_json[item];
|
||||
process_json.push(obj)
|
||||
}
|
||||
|
||||
|
||||
this.process_json = process_json;
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
getspList() {
|
||||
|
||||
this.process_json= process_json;
|
||||
}
|
||||
getsubproductionplanList({page: 0, production_plan: this.id}).then((response) => {
|
||||
if (response.data) {
|
||||
this.subproductionplanList = response.data;
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
getwproductList() {
|
||||
getwproductList({production_plan: this.id, page: 0,}).then((response) => {
|
||||
if (response.data) {
|
||||
this.wproduct = response.data;
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
//下料清单
|
||||
gecutList() {
|
||||
getcutList({production_plan: this.id, page: 0}).then((response) => {
|
||||
if (response.data) {
|
||||
this.cut = response.data;
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
//查看该玻璃检验记录表
|
||||
handleoption(scope) {
|
||||
|
||||
this.$router.push({
|
||||
name: "taskrecordfrom",
|
||||
params: {
|
||||
id: scope.row.id,
|
||||
productionplanid: this.id,
|
||||
number: scope.row.number,
|
||||
process: scope.row.step_.name
|
||||
},
|
||||
})
|
||||
|
||||
},
|
||||
//查看工序对应的玻璃
|
||||
handleprocess(scope) {
|
||||
|
||||
this.$router.push({name: "wproduct", params: {id: scope.row.process, productionplanid: this.id}})
|
||||
|
||||
}
|
||||
},
|
||||
getspList() {
|
||||
|
||||
getsubproductionplanList({page:0,production_plan:this.id}).then((response) => {
|
||||
if (response.data) {
|
||||
this.subproductionplanList = response.data;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
getwproductList()
|
||||
{
|
||||
getwproductList({production_plan:this.id,page:0,}).then((response) => {
|
||||
if (response.data) {
|
||||
this.wproduct = response.data;
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
//下料清单
|
||||
gecutList()
|
||||
{
|
||||
getcutList({production_plan:this.id,page:0}).then((response) => {
|
||||
if (response.data) {
|
||||
this.cut = response.data;
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
//查看该玻璃检验记录表
|
||||
handleoption(scope){
|
||||
|
||||
this.$router.push({name: "taskrecordfrom", params: { id: scope.row.id ,productionplanid:this.id ,number:scope.row.number,process:scope.row.step_.name}, })
|
||||
|
||||
},
|
||||
//查看工序对应的玻璃
|
||||
handleprocess (scope){
|
||||
|
||||
this.$router.push({name: "wproduct", params: { id: scope.row.process,productionplanid:this.id} })
|
||||
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
:title="formName"
|
||||
:visible.sync="recordVisible"
|
||||
:close-on-click-modal="false"
|
||||
@close="recordCancel"
|
||||
>
|
||||
<el-row>
|
||||
<el-col v-for="item in fieldList" :key="item.id" :span="12">
|
||||
|
|
|
@ -102,8 +102,10 @@
|
|||
<p>创建时间 :{{watchedCreateTime}}</p>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<svg height=800 id="mySvg" style="width: 100%;">
|
||||
</svg>
|
||||
<div style="width: 90%;margin: auto;">
|
||||
<svg height=1000 id="mySvg" style="width:100%!important;">
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog
|
||||
|
@ -481,7 +483,7 @@ export default {
|
|||
margin: 10vh auto 0;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
max-height: 75vh;
|
||||
max-height: 80vh;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.svgItem{
|
||||
|
|
|
@ -241,7 +241,7 @@
|
|||
</el-step>
|
||||
</el-steps>
|
||||
<div style="width: 90%;margin: auto;">
|
||||
<svg height=800 id="mySvg" style="width:100%!important;">
|
||||
<svg height=1000 id="mySvg" style="width:100%!important;">
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -613,6 +613,27 @@
|
|||
<el-button type="primary" @click="retrialSubmit">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!--已完成检查表查看-->
|
||||
<el-dialog
|
||||
:title="formName"
|
||||
:visible.sync="recordFinishedVisible"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-row>
|
||||
<el-col v-for="item in fieldList" :key="item.id" :span="12">
|
||||
<div class="items" v-if="item.field_type!=='draw'">
|
||||
<span class="itemLabel">{{item.field_name}}:</span>
|
||||
<span>{{item.field_value}}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col v-for="item in fieldList" :key="item.id" :span="24">
|
||||
<div class="items" v-if="item.field_type==='draw'" style="height: 400px">
|
||||
<span class="itemLabel">{{item.field_name}}:</span>
|
||||
<img style="width: 45%;vertical-align: text-top;" :src="'http://47.95.0.242:2222'+item.field_value"/>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
@ -755,6 +776,7 @@
|
|||
dialogFormVisible: false,
|
||||
dialogFormVisibles: false,
|
||||
limitedCheckRecord: false,
|
||||
recordFinishedVisible: false,
|
||||
testrecord: {},
|
||||
retrialItem: {},//复检对象
|
||||
retrialResponse: {},//复检对象
|
||||
|
@ -862,13 +884,10 @@
|
|||
handleRetrial(scope) {
|
||||
let that = this;
|
||||
this.retrialItem = Object.assign({}, scope.row);
|
||||
console.log(this.retrialItem);
|
||||
getRetrial(scope.row.id).then(res => {
|
||||
that.retrialResponse = res.data;
|
||||
getWorkflowInit(res.data.workflow).then((response) => {
|
||||
if (response.data) {
|
||||
debugger;
|
||||
console.log(response.data);
|
||||
that.retrialForm.transition = response.data.transitions[0].id;
|
||||
that.customfieldList = response.data.field_list;
|
||||
for (let i = 0; i < that.customfieldList.length; i++) {
|
||||
|
@ -926,10 +945,8 @@
|
|||
if (response.data) {
|
||||
this.wproductList3 = response.data;
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
//半成品批量入库
|
||||
handleCreate() {
|
||||
this.dialogFormVisibles = true;
|
||||
|
@ -941,7 +958,6 @@
|
|||
_this.mutipID = [];
|
||||
this.$refs.multipleTable.selection.forEach((item) => {
|
||||
_this.mutipID.push(item.id);
|
||||
|
||||
});
|
||||
createputins({
|
||||
warehouse: this.form.warehouse,
|
||||
|
@ -1093,44 +1109,13 @@
|
|||
handleRecordDetail(scope) {
|
||||
let that = this;
|
||||
that.fieldList = [];
|
||||
that.recordVisible = false;
|
||||
that.recordId = scope.row.id;
|
||||
that.recordform = scope.row.form;
|
||||
that.formName = scope.row.form_.name;
|
||||
getrffieldList({form: this.recordform, page: 1, page_size: 100}).then((response) => {
|
||||
if (response.data) {
|
||||
that.hasPicture = false;
|
||||
let fieldList = response.data.results;
|
||||
that.fieldList = [...fieldList];
|
||||
let arr = fieldList.filter(item => {
|
||||
return item.field_type === 'draw'
|
||||
});
|
||||
if (arr.length > 0) {
|
||||
that.hasPicture = true;
|
||||
}
|
||||
getTestRecordItem(scope.row.id).then((res) => {
|
||||
let arr = [];
|
||||
let fieldList = res.data.record_data;
|
||||
for (let i = 0; i < that.fieldList.length; i++) {
|
||||
let obj = that.fieldList[i];
|
||||
obj.is_testok = null;
|
||||
for (let j = 0; j < fieldList.length; j++) {
|
||||
if (that.fieldList[i].field_key === fieldList[j].field_key) {
|
||||
obj.id = fieldList[j].id;
|
||||
obj.is_testok = fieldList[j].is_testok;
|
||||
obj.field_value = fieldList[j].field_value;
|
||||
}
|
||||
}
|
||||
arr.push(obj)
|
||||
}
|
||||
that.fieldList = arr;
|
||||
that.$nextTick(() => {
|
||||
that.isDisabled = true;
|
||||
that.recordVisible = true;
|
||||
});
|
||||
})
|
||||
getTestRecordItem(scope.row.id).then((res) => {
|
||||
if (res.code >= 200) {
|
||||
that.recordFinishedVisible = true;
|
||||
that.formName = res.data.form_.name;
|
||||
that.fieldList = res.data.record_data;
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
//半产品复检
|
||||
handleReview() {
|
||||
|
@ -1331,3 +1316,16 @@
|
|||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.items {
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.itemLabel {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,13 +2,14 @@ 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.develop.views import CleanDataView, UpdateCuttingView, UpdateFIFOItem, UpdateLastTestResult
|
||||
from apps.develop.views import CleanDataView, UpdateCuttingView, UpdateFIFOItem, UpdateLastTestResult, UpdateSpg
|
||||
|
||||
urlpatterns = [
|
||||
path('cleandata/', CleanDataView.as_view()),
|
||||
path('update_cutting/', UpdateCuttingView.as_view()),
|
||||
path('update_last_result/', UpdateLastTestResult.as_view()),
|
||||
path('update_last_result/', UpdateLastTestResult.as_view()),
|
||||
path('update_fifoitem/', UpdateFIFOItem.as_view())
|
||||
path('update_fifoitem/', UpdateFIFOItem.as_view()),
|
||||
path('update_spg/', UpdateSpg.as_view())
|
||||
]
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ from rest_framework.permissions import IsAdminUser
|
|||
from rest_framework.response import Response
|
||||
from apps.inm.models import FIFO, FIFOItem, Inventory, MaterialBatch
|
||||
from apps.mtm.models import Material
|
||||
from apps.pm.models import ProductionPlan
|
||||
from apps.pm.models import ProductionPlan, SubProductionPlan
|
||||
from apps.sam.models import Order
|
||||
from apps.wf.models import Ticket
|
||||
from apps.wpm.models import Operation, OperationMaterial, WProduct, WproductFlow
|
||||
|
@ -80,3 +80,14 @@ class UpdateFIFOItem(APIView):
|
|||
i.is_testok = None
|
||||
i.save()
|
||||
return Response()
|
||||
|
||||
class UpdateSpg(APIView):
|
||||
permission_classes = [IsAdminUser]
|
||||
@transaction.atomic
|
||||
def post(self, request, format=None):
|
||||
"""
|
||||
冷加工重新计算合格率
|
||||
"""
|
||||
for i in SubProductionPlan.objects.filter(subproduction__process__id=1):
|
||||
WpmServies.update_subproduction_progress_main(sp=i)
|
||||
return Response()
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-18 00:39
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('em', '0009_auto_20210916_1108'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='equipment',
|
||||
name='state',
|
||||
field=models.PositiveIntegerField(choices=[(0, '完好'), (1, '限用'), (2, '在修'), (3, '禁用')], default=0, verbose_name='设备状态'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,63 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-20 01:56
|
||||
|
||||
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),
|
||||
('em', '0010_alter_equipment_state'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ECheckRecord',
|
||||
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='删除标记')),
|
||||
('check_date', models.DateField(blank=True, null=True, verbose_name='校准检查日期')),
|
||||
('description', models.CharField(blank=True, max_length=200, null=True, verbose_name='描述')),
|
||||
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='echeckrecord_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='equipment',
|
||||
name='belong_dept',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='equipment',
|
||||
name='statedm',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='equipment',
|
||||
name='next_check_date',
|
||||
field=models.DateField(blank=True, null=True, verbose_name='下次校准检查日期'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='equipment',
|
||||
name='state',
|
||||
field=models.PositiveIntegerField(choices=[(10, '完好'), (20, '限用'), (30, '在修'), (40, '禁用')], default=0, verbose_name='设备状态'),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Equipmentrecord',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='echeckrecord',
|
||||
name='equipment',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='em.equipment', verbose_name='校准检定设备'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='echeckrecord',
|
||||
name='update_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='echeckrecord_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,43 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-20 02:48
|
||||
|
||||
import datetime
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
from django.utils.timezone import utc
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('em', '0011_auto_20220120_0956'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='equipment',
|
||||
name='check_date',
|
||||
field=models.DateField(blank=True, null=True, verbose_name='最近校准检查日期'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='echeckrecord',
|
||||
name='check_date',
|
||||
field=models.DateField(default=datetime.datetime(2022, 1, 20, 2, 48, 20, 706844, tzinfo=utc), verbose_name='校准检查日期'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='echeckrecord',
|
||||
name='equipment',
|
||||
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='em.equipment', verbose_name='校准检定设备'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='equipment',
|
||||
name='cycle',
|
||||
field=models.IntegerField(blank=True, null=True, verbose_name='校准或检定周期(月)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='equipment',
|
||||
name='next_check_date',
|
||||
field=models.DateField(blank=True, null=True, verbose_name='预计下次校准检查日期'),
|
||||
),
|
||||
]
|
|
@ -3,32 +3,34 @@ from django.contrib.auth.models import AbstractUser
|
|||
from django.db.models.base import Model
|
||||
import django.utils.timezone as timezone
|
||||
from django.db.models.query import QuerySet
|
||||
from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File
|
||||
#from apps.mtm.models import Process
|
||||
from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File
|
||||
from utils.model import SoftModel, BaseModel
|
||||
from simple_history.models import HistoricalRecords
|
||||
|
||||
|
||||
|
||||
class Equipment(CommonBModel):
|
||||
class Equipment(CommonAModel):
|
||||
"""
|
||||
设备台账信息
|
||||
"""
|
||||
EQUIP_STATE_OK = 10
|
||||
EQUIP_STATE_LIMIT = 20
|
||||
EQUIP_STATE_FIX = 30
|
||||
EQUIP_STATE_DISABLE = 40
|
||||
state_choices = (
|
||||
(0, '完好'),
|
||||
(1, '限用'),
|
||||
(2, '在修'),
|
||||
(3, '禁用')
|
||||
)
|
||||
statedm_choices = (
|
||||
(0, '合格'),
|
||||
(1, '准用'),
|
||||
(2, '限用'),
|
||||
(3, '禁用'),
|
||||
(4, '停用'),
|
||||
(5, '封存')
|
||||
)
|
||||
(EQUIP_STATE_OK, '完好'),
|
||||
(EQUIP_STATE_LIMIT, '限用'),
|
||||
(EQUIP_STATE_FIX, '在修'),
|
||||
(EQUIP_STATE_DISABLE, '禁用')
|
||||
|
||||
)
|
||||
state2_choices = (
|
||||
(EQUIP_STATE_OK, '合格'),
|
||||
(EQUIP_STATE_DISABLE, '禁用')
|
||||
|
||||
)
|
||||
EQUIP_TYPE_PRO = 1
|
||||
EQUIP_TYPE_TEST = 2
|
||||
type_choices = (
|
||||
(1, '生产设备'),
|
||||
(2, '检验工具')
|
||||
|
@ -54,20 +56,21 @@ class Equipment(CommonBModel):
|
|||
factory = models.CharField('生产厂', max_length=50, null=True, blank=True)
|
||||
production_date = models.DateField('生产日期', null=True, blank=True)
|
||||
buy_date = models.DateField('购置日期', null=True, blank=True)
|
||||
state = models.CharField('设备状态', max_length=11, choices=state_choices, default=0)
|
||||
state = models.PositiveIntegerField('设备状态', choices=state_choices, default=0)
|
||||
parameter = models.TextField('技术参数', null=True, blank=True)
|
||||
place = models.CharField('存放位置', max_length=50, null=True, blank=True)
|
||||
count = models.IntegerField('数量', default=0)
|
||||
keeper = models.ForeignKey(User, verbose_name='保管人', on_delete=models.CASCADE, null=True, blank=True)
|
||||
description = models.CharField('描述', max_length=200, blank=True, null=True)
|
||||
#process = models.ForeignKey(Process, verbose_name='工序', on_delete=models.CASCADE, null=True, blank=True)
|
||||
mgmtype = models.IntegerField('管理类别', choices=mgmtype_choices, default=1)#监视,测量设备
|
||||
way = models.IntegerField('校准或检定方式', choices=way_choices, default=1)#监视,测量设备
|
||||
standard = models.CharField('溯源标准或依据', max_length=200, blank=True, null=True)#监视,测量设备
|
||||
cycle = models.IntegerField('校准或检定周期', default=0)#监视,测量设备
|
||||
usetype = models.IntegerField('使用类别', choices=usetype_choices, default=1)#监视,测量设备
|
||||
statedm = models.IntegerField('设备状态', choices=statedm_choices, default=0)#监视,测量设备
|
||||
# 以下是监视测量设备单独字段
|
||||
mgmtype = models.IntegerField('管理类别', choices=mgmtype_choices, default=1)
|
||||
way = models.IntegerField('校准或检定方式', choices=way_choices, default=1)
|
||||
standard = models.CharField('溯源标准或依据', max_length=200, blank=True, null=True)
|
||||
cycle = models.IntegerField('校准或检定周期(月)', null=True, blank=True)
|
||||
usetype = models.IntegerField('使用类别', choices=usetype_choices, default=1)
|
||||
|
||||
check_date = models.DateField('最近校准检查日期', blank=True, null=True)
|
||||
next_check_date = models.DateField('预计下次校准检查日期',blank=True, null=True)
|
||||
class Meta:
|
||||
verbose_name = '设备信息'
|
||||
verbose_name_plural = verbose_name
|
||||
|
@ -75,8 +78,10 @@ class Equipment(CommonBModel):
|
|||
def __str__(self):
|
||||
return self.number + '-' + self.name
|
||||
|
||||
class Equipmentrecord(CommonBModel):
|
||||
equipment = models.ForeignKey(Equipment, verbose_name='校准检定设备', on_delete=models.CASCADE, null=True, blank=True)
|
||||
recentlydate = models.DateField('最近一次校准/检定日期',blank=True, null=True)
|
||||
nextdate = models.DateField('下次应校准或检定日期',blank=True, null=True)
|
||||
class ECheckRecord(CommonADModel):
|
||||
"""
|
||||
校准鉴定记录
|
||||
"""
|
||||
equipment = models.ForeignKey(Equipment, verbose_name='校准检定设备', on_delete=models.CASCADE)
|
||||
check_date = models.DateField('校准检查日期')
|
||||
description = models.CharField('描述', max_length=200, blank=True, null=True)
|
|
@ -1,13 +1,12 @@
|
|||
from apps.mtm.models import Step
|
||||
from rest_framework import serializers
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
|
||||
from .models import Equipment,Equipmentrecord
|
||||
from rest_framework import exceptions
|
||||
from .models import Equipment, ECheckRecord
|
||||
from apps.system.serializers import OrganizationSimpleSerializer, UserSimpleSerializer
|
||||
|
||||
|
||||
class EquipmentSerializer(ModelSerializer):
|
||||
belong_dept_ = OrganizationSimpleSerializer(source='belong_dept', read_only=True)
|
||||
class EquipmentListSerializer(ModelSerializer):
|
||||
keeper_ = UserSimpleSerializer(source='keeper', read_only=True)
|
||||
step_ = serializers.SerializerMethodField()
|
||||
class Meta:
|
||||
|
@ -17,24 +16,35 @@ class EquipmentSerializer(ModelSerializer):
|
|||
@staticmethod
|
||||
def setup_eager_loading(queryset):
|
||||
""" Perform necessary eager loading of data. """
|
||||
queryset = queryset.select_related('belong_dept','keeper')
|
||||
queryset = queryset.select_related('keeper')
|
||||
return queryset
|
||||
|
||||
def get_step_(self, obj):
|
||||
return Step.objects.filter(equipments=obj).values('id', 'name', 'number')
|
||||
|
||||
|
||||
class EquipmentCreateUpdateSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = Equipment
|
||||
exclude = ['create_by', 'update_by', 'create_time', 'update_time', 'check_date', 'next_check_date']
|
||||
|
||||
def validate(self, attrs):
|
||||
if attrs['type'] == Equipment.EQUIP_TYPE_TEST:
|
||||
if attrs['state'] not in [Equipment.EQUIP_STATE_OK, Equipment.EQUIP_STATE_DISABLE]:
|
||||
raise exceptions.APIException('设备状态错误')
|
||||
return super().validate(attrs)
|
||||
|
||||
class EquipmentSimpleSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = Equipment
|
||||
fields = ['id', 'number', 'name', 'state']
|
||||
fields = ['id', 'number', 'name', 'state', 'model']
|
||||
|
||||
|
||||
|
||||
class EquipmentrecordSerializer(ModelSerializer):
|
||||
equipment_ = EquipmentSerializer(source='equipment', read_only=True)
|
||||
class ECheckRecordListSerializer(ModelSerializer):
|
||||
equipment_ = EquipmentSimpleSerializer(source='equipment', read_only=True)
|
||||
class Meta:
|
||||
model = Equipmentrecord
|
||||
model = ECheckRecord
|
||||
fields = '__all__'
|
||||
|
||||
@staticmethod
|
||||
|
@ -43,6 +53,11 @@ class EquipmentrecordSerializer(ModelSerializer):
|
|||
queryset = queryset.select_related('equipment')
|
||||
return queryset
|
||||
|
||||
class EChcekRecordCreateSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
model = ECheckRecord
|
||||
fields = ['equipment', 'check_date', 'description']
|
||||
|
||||
class DaqCreateSerializer(serializers.Serializer):
|
||||
number = serializers.CharField()
|
||||
file = serializers.FileField()
|
|
@ -0,0 +1,20 @@
|
|||
from tabnanny import check
|
||||
from apps.em.models import ECheckRecord, Equipment
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from django.utils import timezone
|
||||
class EmService:
|
||||
|
||||
@classmethod
|
||||
def update_check_date(cls, equip:Equipment):
|
||||
# 根据校准检定记录变更下次日期
|
||||
check = ECheckRecord.objects.filter(equipment=equip).order_by('id').last()
|
||||
if check:
|
||||
equip.check_date = check.check_date
|
||||
if equip.cycle:
|
||||
equip.next_check_date = equip.check_date + relativedelta(months=equip.cycle)
|
||||
else:
|
||||
equip.next_check_date = None
|
||||
else:
|
||||
equip.check_date = None
|
||||
equip.next_check_date = None
|
||||
equip.save()
|
|
@ -1,12 +1,12 @@
|
|||
from django.db.models import base
|
||||
from rest_framework import urlpatterns
|
||||
from apps.em.views import DaqView, EquipmentViewSet,EquipmentrecordViewSet
|
||||
from apps.em.views import DaqView, EquipmentViewSet, EChcekRecordViewSet
|
||||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register('equipment', EquipmentViewSet, basename='equipment')
|
||||
router.register('equipmentrecord', EquipmentrecordViewSet, basename='equipmentrecord')
|
||||
router.register('echeck_record', EChcekRecordViewSet, basename='echeck_record')
|
||||
urlpatterns = [
|
||||
path('daq/', DaqView.as_view()),
|
||||
path('', include(router.urls)),
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
from datetime import timedelta
|
||||
from django.shortcuts import render
|
||||
from numpy import delete
|
||||
from rest_framework.exceptions import APIException
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from rest_framework.viewsets import ModelViewSet, GenericViewSet
|
||||
from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin, ListModelMixin, DestroyModelMixin
|
||||
from rest_framework import serializers, status
|
||||
from rest_framework.response import Response
|
||||
from apps.em.models import Equipment,Equipmentrecord
|
||||
from apps.em.serializers import DaqCreateSerializer, EquipmentSerializer,EquipmentrecordSerializer
|
||||
from apps.em.models import Equipment, ECheckRecord
|
||||
from apps.em.serializers import DaqCreateSerializer, EChcekRecordCreateSerializer, ECheckRecordListSerializer, \
|
||||
EquipmentCreateUpdateSerializer, EquipmentListSerializer
|
||||
from apps.em.services import EmService
|
||||
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||
|
||||
from django.utils import timezone
|
||||
from django.db import transaction
|
||||
|
||||
# Create your views here.
|
||||
class EquipmentViewSet(CreateUpdateModelAMixin, OptimizationMixin, ModelViewSet):
|
||||
|
@ -18,48 +24,48 @@ class EquipmentViewSet(CreateUpdateModelAMixin, OptimizationMixin, ModelViewSet)
|
|||
perms_map = {'get': '*', 'post': 'equipment_create',
|
||||
'put': 'equipment_update', 'delete': 'equipment_delete'}
|
||||
queryset = Equipment.objects.all()
|
||||
serializer_class = EquipmentSerializer
|
||||
serializer_class = EquipmentListSerializer
|
||||
search_fields = ['number', 'name','description']
|
||||
filterset_fields = ['belong_dept', 'keeper', 'type']
|
||||
filterset_fields = ['keeper', 'type']
|
||||
ordering_fields = ['create_time']
|
||||
ordering = ['-create_time']
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action in ['create', 'update']:
|
||||
return EquipmentCreateUpdateSerializer
|
||||
return super().get_serializer_class()
|
||||
|
||||
# Create your views here.
|
||||
class EquipmentrecordViewSet(CreateUpdateModelAMixin, OptimizationMixin, ModelViewSet):
|
||||
class EChcekRecordViewSet(CreateUpdateModelAMixin, OptimizationMixin,
|
||||
CreateModelMixin, RetrieveModelMixin, ListModelMixin, DestroyModelMixin, GenericViewSet):
|
||||
"""
|
||||
设备校准-增删改查
|
||||
"""
|
||||
perms_map = {'get': '*', 'post': 'equipmentrecord_create',
|
||||
'put': 'equipmentrecord_update', 'delete': 'equipmentrecord_delete'}
|
||||
queryset = Equipmentrecord.objects.all()
|
||||
serializer_class = EquipmentrecordSerializer
|
||||
perms_map = {'get': '*', 'post': 'echeckrecord_create', 'delete': 'echeckrecord_delete'}
|
||||
queryset = ECheckRecord.objects.all()
|
||||
serializer_class = ECheckRecordListSerializer
|
||||
filterset_fields = ['equipment']
|
||||
ordering_fields = ['create_time']
|
||||
ordering = ['-create_time']
|
||||
ordering = ['-id']
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action in ['create']:
|
||||
return EChcekRecordCreateSerializer
|
||||
return super().get_serializer_class()
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, request, *args, **kwargs):
|
||||
|
||||
data = request.data
|
||||
if data.get('equipment', None):
|
||||
equipment = Equipment.objects.get(pk=data['equipment'])
|
||||
equipment.statedm = data['state']
|
||||
equipment.save()
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return Response(status=status.HTTP_200_OK)
|
||||
def update(self, request, *args, **kwargs):
|
||||
data = request.data
|
||||
if data.get('equipment', None):
|
||||
equipment = Equipment.objects.get(pk=data['equipment'])
|
||||
equipment.statedm = data['state']
|
||||
equipment.save()
|
||||
id = self.get_object()
|
||||
serializer = self.get_serializer(id, data=data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return Response(status=status.HTTP_200_OK)
|
||||
instance = serializer.save(create_by=request.user)
|
||||
EmService.update_check_date(equip=instance.equipment)
|
||||
return Response()
|
||||
|
||||
@transaction.atomic
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
instance = self.get_object()
|
||||
instance.delete()
|
||||
EmService.update_check_date(equip=instance.equipment)
|
||||
return Response()
|
||||
|
||||
import uuid
|
||||
import os
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
from django_filters import rest_framework as filters
|
||||
from apps.hrm.models import ClockRecord
|
||||
|
||||
class ClockRecordFilterSet(filters.FilterSet):
|
||||
create_time_start = filters.DateFilter(field_name="create_time", lookup_expr='gte')
|
||||
create_time_end = filters.DateFilter(field_name="create_time", lookup_expr='lte')
|
||||
class Meta:
|
||||
model = ClockRecord
|
||||
fields = ['create_by', 'create_time_start', 'create_time_end']
|
|
@ -0,0 +1,32 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-21 06:45
|
||||
|
||||
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),
|
||||
('hrm', '0003_employee_face_data'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ClockRecord',
|
||||
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, '上班打卡')], default=10, verbose_name='打卡类型')),
|
||||
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='clockrecord_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='clockrecord_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
|
@ -36,8 +36,12 @@ class Employee(CommonAModel):
|
|||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Attendance(CommonADModel):
|
||||
class ClockRecord(CommonADModel):
|
||||
"""
|
||||
出勤记录
|
||||
打卡记录
|
||||
"""
|
||||
|
||||
ClOCK_WORK1 = 10
|
||||
type_choice = (
|
||||
(ClOCK_WORK1, '上班打卡'),
|
||||
)
|
||||
type = models.PositiveSmallIntegerField('打卡类型', choices=type_choice, default=ClOCK_WORK1)
|
|
@ -1,7 +1,7 @@
|
|||
from apps.system.models import User
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework import serializers
|
||||
from .models import Employee
|
||||
from .models import ClockRecord, Employee
|
||||
from apps.system.serializers import UserListSerializer, UserSimpleSerializer
|
||||
from django.db.models.query import Prefetch
|
||||
|
||||
|
@ -23,3 +23,13 @@ class EmployeeSerializer(ModelSerializer):
|
|||
|
||||
class FaceLoginSerializer(serializers.Serializer):
|
||||
base64 = serializers.CharField()
|
||||
|
||||
|
||||
class FaceClockCreateSerializer(serializers.Serializer):
|
||||
base64 = serializers.CharField()
|
||||
|
||||
class ClockRecordListSerializer(serializers.ModelSerializer):
|
||||
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
|
||||
class Meta:
|
||||
model = ClockRecord
|
||||
fields = '__all__'
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
from django.conf import settings
|
||||
import uuid
|
||||
import face_recognition
|
||||
import os
|
||||
from apps.hrm.models import Employee
|
||||
from apps.system.models import User
|
||||
|
||||
class HRMService:
|
||||
|
||||
@classmethod
|
||||
def face_compare_from_base64(cls, base64_data):
|
||||
filename = str(uuid.uuid4())
|
||||
filepath = settings.BASE_DIR +'/temp/' + filename +'.png'
|
||||
with open(filepath, 'wb') as f:
|
||||
f.write(base64_data)
|
||||
try:
|
||||
unknown_picture = face_recognition.load_image_file(filepath)
|
||||
unknown_face_encoding = face_recognition.face_encodings(unknown_picture)[0]
|
||||
os.remove(filepath)
|
||||
except:
|
||||
os.remove(filepath)
|
||||
return None, '头像解码失败'
|
||||
|
||||
# 匹配人脸库
|
||||
user_faces = Employee.objects.filter(face_data__isnull=False,
|
||||
user__is_active=True).values('user', 'face_data')
|
||||
user_l = []
|
||||
face_l = []
|
||||
for i in user_faces:
|
||||
user_l.append(i['user'])
|
||||
face_l.append(i['face_data'])
|
||||
|
||||
results = face_recognition.compare_faces(face_l, unknown_face_encoding, tolerance=0.5)
|
||||
for index, value in enumerate(results):
|
||||
if value:
|
||||
# 识别成功
|
||||
user = User.objects.get(id=user_l[index])
|
||||
return user, ''
|
||||
return None, '识别失败'
|
|
@ -0,0 +1,8 @@
|
|||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from celery import shared_task
|
||||
|
||||
|
||||
@shared_task
|
||||
def x():
|
||||
print('ok')
|
|
@ -1,11 +1,12 @@
|
|||
from django.db.models import base
|
||||
from rest_framework import urlpatterns
|
||||
from apps.hrm.views import EmployeeViewSet, FaceLogin
|
||||
from apps.hrm.views import ClockRecordViewSet, EmployeeViewSet, FaceLogin
|
||||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register('employee', EmployeeViewSet, basename='employee')
|
||||
router.register('clock_record', ClockRecordViewSet, basename='clock_record')
|
||||
urlpatterns = [
|
||||
path('facelogin/', FaceLogin.as_view()),
|
||||
path('', include(router.urls)),
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
from django.shortcuts import render
|
||||
from django.utils import timezone
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.viewsets import ModelViewSet, GenericViewSet
|
||||
from rest_framework.mixins import UpdateModelMixin, RetrieveModelMixin
|
||||
from rest_framework.mixins import UpdateModelMixin, RetrieveModelMixin, CreateModelMixin, ListModelMixin
|
||||
from apps.hrm.filters import ClockRecordFilterSet
|
||||
from apps.hrm.services import HRMService
|
||||
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||
from apps.hrm.models import Employee
|
||||
from apps.hrm.serializers import EmployeeSerializer, FaceLoginSerializer
|
||||
from apps.hrm.models import ClockRecord, Employee
|
||||
from apps.hrm.serializers import ClockRecordListSerializer, EmployeeSerializer, FaceClockCreateSerializer, FaceLoginSerializer
|
||||
import face_recognition
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
|
@ -12,8 +15,10 @@ import logging
|
|||
from rest_framework.generics import CreateAPIView
|
||||
from rest_framework import status
|
||||
from rest_framework_simplejwt.tokens import RefreshToken
|
||||
|
||||
from rest_framework import exceptions
|
||||
from apps.system.models import User
|
||||
from apps.system.serializers import UserSimpleSerializer
|
||||
from rest_framework.permissions import AllowAny
|
||||
logger = logging.getLogger('log')
|
||||
|
||||
|
||||
|
@ -50,9 +55,56 @@ class EmployeeViewSet(CreateUpdateModelAMixin, OptimizationMixin, UpdateModelMix
|
|||
except:
|
||||
logger.error('人脸识别出错')
|
||||
|
||||
import uuid
|
||||
|
||||
class ClockRecordViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
|
||||
"""
|
||||
打卡记录
|
||||
"""
|
||||
perms_map = {'get':'*', 'post':'*'}
|
||||
authentication_classes = []
|
||||
permission_classes = [AllowAny]
|
||||
queryset = ClockRecord.objects.select_related('create_by').all()
|
||||
serializer_class = ClockRecordListSerializer
|
||||
filterset_class = ClockRecordFilterSet
|
||||
ordering = ['-pk']
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == 'create':
|
||||
return FaceClockCreateSerializer
|
||||
return super().get_serializer_class()
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
now = timezone.now()
|
||||
now_local = timezone.localtime()
|
||||
if 8<=now_local.hour<=17:
|
||||
base64_data = base64.urlsafe_b64decode(tran64(
|
||||
request.data.get('base64').replace(' ', '+')))
|
||||
user, msg = HRMService.face_compare_from_base64(base64_data)
|
||||
if user:
|
||||
ins, created = ClockRecord.objects.get_or_create(
|
||||
create_by=request.user, create_time__hour__range = [8,18],
|
||||
create_time__year=now.year, create_time__month=now.month,
|
||||
create_time__day=now.day,
|
||||
defaults={
|
||||
'type':ClockRecord.ClOCK_WORK1,
|
||||
'create_by':user,
|
||||
'create_time':now
|
||||
})
|
||||
if not created:
|
||||
ins.create_time = now
|
||||
ins.save()
|
||||
# 设为在岗
|
||||
user.is_atwork = True
|
||||
user.save()
|
||||
return Response(UserSimpleSerializer(instance=user).data)
|
||||
return Response(msg, status=status.HTTP_400_BAD_REQUEST)
|
||||
return Response('非打卡时间范围', status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
import base64
|
||||
import os
|
||||
|
||||
def tran64(s):
|
||||
missing_padding = len(s) % 4
|
||||
|
@ -70,41 +122,13 @@ class FaceLogin(CreateAPIView):
|
|||
"""
|
||||
人脸识别登录
|
||||
"""
|
||||
# serializer = FaceLoginSerializer(data=request.data)
|
||||
# serializer.is_valid(raise_exception=True)
|
||||
filename = str(uuid.uuid4())
|
||||
filepath = settings.BASE_DIR +'/temp/' + filename +'.png'
|
||||
with open(filepath, 'wb') as f:
|
||||
data = tran64(request.data.get('base64').replace(' ', '+'))
|
||||
f.write(base64.urlsafe_b64decode(data))
|
||||
# picture_of_me = face_recognition.load_image_file(settings.BASE_DIR +'/temp/me.png')
|
||||
# my_face_encoding = face_recognition.face_encodings(picture_of_me)[0]
|
||||
#results = face_recognition.compare_faces([my_face_encoding], unknown_face_encoding, tolerance=0.2)
|
||||
try:
|
||||
unknown_picture = face_recognition.load_image_file(filepath)
|
||||
unknown_face_encoding = face_recognition.face_encodings(unknown_picture)[0]
|
||||
os.remove(filepath)
|
||||
except:
|
||||
os.remove(filepath)
|
||||
return Response('头像解码失败', status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 匹配人脸库
|
||||
user_faces = Employee.objects.filter(face_data__isnull=False, user__is_active=True).values('user', 'face_data')
|
||||
user_l = []
|
||||
face_l = []
|
||||
for i in user_faces:
|
||||
user_l.append(i['user'])
|
||||
face_l.append(i['face_data'])
|
||||
|
||||
results = face_recognition.compare_faces(face_l, unknown_face_encoding, tolerance=0.5)
|
||||
for index, value in enumerate(results):
|
||||
if value:
|
||||
# 识别成功
|
||||
user = User.objects.get(id=user_l[index])
|
||||
refresh = RefreshToken.for_user(user)
|
||||
return Response({
|
||||
'refresh': str(refresh),
|
||||
'access': str(refresh.access_token),
|
||||
'username':user.username
|
||||
})
|
||||
return Response('未找到对应用户', status=status.HTTP_400_BAD_REQUEST)
|
||||
base64_data = base64.urlsafe_b64decode(tran64(request.data.get('base64').replace(' ', '+')))
|
||||
user, msg = HRMService.face_compare_from_base64(base64_data)
|
||||
if user:
|
||||
refresh = RefreshToken.for_user(user)
|
||||
return Response({
|
||||
'refresh': str(refresh),
|
||||
'access': str(refresh.access_token),
|
||||
'username':user.username
|
||||
})
|
||||
return Response(msg, status=status.HTTP_400_BAD_REQUEST)
|
|
@ -21,7 +21,10 @@ class MbFilterSet(filters.FilterSet):
|
|||
|
||||
class IProductFilterSet(filters.FilterSet):
|
||||
order = filters.NumberFilter(field_name="wproduct__subproduction_plan__production_plan__order")
|
||||
|
||||
to_order = filters.NumberFilter(field_name="wproduct__to_order")
|
||||
update_time_start = filters.DateFilter(field_name="update_time", lookup_expr='gte')
|
||||
update_time_end = filters.DateFilter(field_name="update_time", lookup_expr='lte')
|
||||
class Meta:
|
||||
model = IProduct
|
||||
fields = ['material', 'warehouse', 'batch', 'order', 'material__type']
|
||||
fields = ['material', 'warehouse', 'batch', 'order', 'material__type',
|
||||
'is_saled', 'update_time_start', 'update_time_end', 'to_order']
|
||||
|
|
|
@ -9,6 +9,7 @@ from apps.mtm.serializers import MaterialSimpleSerializer
|
|||
from django.db import transaction
|
||||
|
||||
|
||||
|
||||
class WareHouseSerializer(serializers.ModelSerializer):
|
||||
create_by_ = UserSimpleSerializer('create_by', read_only=True)
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-19 07:14
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mtm', '0043_auto_20220106_0942'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='subproduction',
|
||||
name='need_combtest',
|
||||
field=models.BooleanField(default=False, verbose_name='需要质检'),
|
||||
),
|
||||
]
|
|
@ -210,6 +210,7 @@ class SubProduction(CommonAModel):
|
|||
name = models.CharField('命名', max_length=50, null=True, blank=True)
|
||||
product = models.ForeignKey(Material, verbose_name='产品', on_delete=models.CASCADE)
|
||||
process = models.ForeignKey(Process, verbose_name='隶属大工序', on_delete=models.CASCADE, related_name='subproduction_process')
|
||||
need_combtest = models.BooleanField('需要质检', default=False)
|
||||
sort = models.IntegerField('排序号', default=1)
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -72,6 +72,11 @@ class SubProductionSerializer(serializers.ModelSerializer):
|
|||
model = SubProduction
|
||||
fields = '__all__'
|
||||
|
||||
class SubProductionCreateUpdateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SubProduction
|
||||
fields = ['name', 'product', 'process', 'need_combtest', 'sort']
|
||||
|
||||
class OtherMaterialSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SubprodctionMaterial
|
||||
|
|
|
@ -4,7 +4,7 @@ from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelM
|
|||
from apps.mtm.filters import MaterialFilterSet, TechDocFilterset
|
||||
|
||||
from apps.mtm.models import Material, Process, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc, UsedStep, SubProduction
|
||||
from apps.mtm.serializers import InputMaterialSerializer, InputMaterialUpdateSerializer, MaterialDetailSerializer, MaterialSerializer, MaterialSimpleSerializer, OtherMaterialSerializer, OutputMaterialSerializer, OutputMaterialUpdateSerializer, ProcessSerializer, RecordFormCreateSerializer, RecordFormDetailSerializer, RecordFormFieldCreateSerializer, RecordFormFieldSerializer, RecordFormFieldUpdateSerializer, RecordFormSerializer, RecordFormUpdateSerializer, StepDetailSerializer, StepSerializer, SubProductionSerializer, SubprodctionMaterialListSerializer, TechDocCreateSerializer, TechDocListSerializer, TechDocUpdateSerializer, UsedStepCreateSerializer, UsedStepListSerializer, UsedStepUpdateSerializer
|
||||
from apps.mtm.serializers import InputMaterialSerializer, InputMaterialUpdateSerializer, MaterialDetailSerializer, MaterialSerializer, MaterialSimpleSerializer, OtherMaterialSerializer, OutputMaterialSerializer, OutputMaterialUpdateSerializer, ProcessSerializer, RecordFormCreateSerializer, RecordFormDetailSerializer, RecordFormFieldCreateSerializer, RecordFormFieldSerializer, RecordFormFieldUpdateSerializer, RecordFormSerializer, RecordFormUpdateSerializer, StepDetailSerializer, StepSerializer, SubProductionCreateUpdateSerializer, SubProductionSerializer, SubprodctionMaterialListSerializer, TechDocCreateSerializer, TechDocListSerializer, TechDocUpdateSerializer, UsedStepCreateSerializer, UsedStepListSerializer, UsedStepUpdateSerializer
|
||||
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
|
@ -80,6 +80,10 @@ class SubProductionViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
|||
search_fields = ['name']
|
||||
serializer_class = SubProductionSerializer
|
||||
ordering = ['sort']
|
||||
def get_serializer_class(self):
|
||||
if self.action in ['create', 'update']:
|
||||
return SubProductionCreateUpdateSerializer
|
||||
return super().get_serializer_class()
|
||||
|
||||
class InputMaterialViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
||||
"""
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-18 00:39
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('sam', '0010_auto_20211208_1408'),
|
||||
('pm', '0022_auto_20211229_1429'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='productionplan',
|
||||
name='order',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='plan_order', to='sam.order', verbose_name='关联订单'),
|
||||
),
|
||||
]
|
|
@ -4,7 +4,7 @@ from django.db import transaction
|
|||
from rest_framework import serializers
|
||||
from rest_framework.views import APIView
|
||||
from apps.em.models import Equipment
|
||||
from apps.em.serializers import EquipmentSerializer
|
||||
from apps.em.serializers import EquipmentSimpleSerializer
|
||||
from apps.inm.models import MaterialBatch
|
||||
from apps.inm.serializers import MaterialBatchSerializer
|
||||
from apps.mtm.models import Step, SubProduction, SubprodctionMaterial, UsedStep
|
||||
|
@ -248,5 +248,5 @@ class ResourceViewSet(GenericViewSet):
|
|||
subproductions = SubProduction.objects.filter(product__id__in=rdata_l, is_deleted=False)
|
||||
steps = Step.objects.filter(usedstep__is_deleted=False, usedstep__subproduction__in=subproductions)
|
||||
equips = Equipment.objects.filter(step_equips__in=steps, is_deleted=False).distinct()
|
||||
serializer = EquipmentSerializer(instance=equips, many=True)
|
||||
serializer = EquipmentSimpleSerializer(instance=equips, many=True)
|
||||
return Response(serializer.data)
|
||||
|
|
|
@ -44,7 +44,7 @@ class ContractCreateUpdateSerializer(serializers.ModelSerializer):
|
|||
class OrderCreateUpdateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Order
|
||||
fields = ['number', 'customer', 'contract', 'product', 'count', 'delivery_date']
|
||||
fields = ['customer', 'contract', 'product', 'count', 'delivery_date']
|
||||
|
||||
def create(self, validated_data):
|
||||
validated_data['number'] = 'DD' + ranstr(7)
|
||||
|
@ -60,6 +60,7 @@ class OrderSerializer(serializers.ModelSerializer):
|
|||
|
||||
class OrderSimpleSerializer(serializers.ModelSerializer):
|
||||
contract_ = ContractSimpleSerializer(source='contract', read_only=True)
|
||||
customer_ = CustomerSimpleSerializer(source='customer', read_only=True)
|
||||
class Meta:
|
||||
model = Order
|
||||
fields = '__all__'
|
||||
|
|
|
@ -20,3 +20,7 @@ class PlanGanttSerializer(serializers.ModelSerializer):
|
|||
def get_children(self, obj):
|
||||
subplans = SubProductionPlan.objects.filter(production_plan=obj).order_by('process__number')
|
||||
return SubplanGanttSerializer(instance=subplans, many=True).data
|
||||
|
||||
class ProcessYieldSerializer(serializers.Serializer):
|
||||
datetime_start = serializers.DateField(label='开始时间', required=False, allow_null=True)
|
||||
datetime_end = serializers.DateField(label='结束时间', required=False, allow_null=True)
|
|
@ -3,11 +3,12 @@ from rest_framework import urlpatterns
|
|||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
from apps.srm.views import GanttPlan
|
||||
from apps.srm.views import GanttPlan, ProcessYieldView
|
||||
|
||||
router = DefaultRouter()
|
||||
urlpatterns = [
|
||||
path('gantt/plan/', GanttPlan.as_view()),
|
||||
path('process/yield/', ProcessYieldView.as_view()),
|
||||
path('', include(router.urls)),
|
||||
]
|
||||
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
|
||||
from django.shortcuts import render
|
||||
from rest_framework import serializers
|
||||
from rest_framework.generics import ListAPIView
|
||||
from rest_framework.generics import ListAPIView, CreateAPIView
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from apps.mtm.models import Process, Step
|
||||
from apps.pm.models import ProductionPlan, SubProductionPlan
|
||||
from apps.srm.serializers import PlanGanttSerializer
|
||||
from apps.srm.serializers import PlanGanttSerializer, ProcessYieldSerializer
|
||||
from apps.wpm.models import WProduct, WproductFlow
|
||||
from django.db.models import Count
|
||||
# Create your views here.
|
||||
|
||||
class GanttPlan(ListAPIView):
|
||||
|
@ -15,4 +20,48 @@ class GanttPlan(ListAPIView):
|
|||
queryset = ProductionPlan.objects.filter(is_deleted=False, is_planed=True).prefetch_related('subplan_plan', 'subplan_plan__process')
|
||||
ordering = ['-id']
|
||||
|
||||
class ProcessYieldView(CreateAPIView):
|
||||
"""
|
||||
工序成品率统计
|
||||
"""
|
||||
perms_map = {'get':'*'}
|
||||
serializer_class = ProcessYieldSerializer
|
||||
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
vdata = serializer.validated_data
|
||||
wpfs = WproductFlow.objects.filter(is_lastlog=True)
|
||||
if vdata.get('datetime_start', None):
|
||||
wpfs = wpfs.filter(update_time__gte = vdata.get('datetime_start'))
|
||||
if vdata.get('datetime_end', None):
|
||||
wpfs = wpfs.filter(update_time__lte = vdata.get('datetime_end'))
|
||||
# 根据产品日志记录进行聚合
|
||||
count_ok_g = list(wpfs.filter(act_state__in=[WProduct.WPR_ACT_STATE_INM,
|
||||
WProduct.WPR_ACT_STATE_OK, WProduct.WPR_ACT_STATE_SELLED]).values('step__process__id').annotate(count_ok=Count('id')))
|
||||
count_notok_g = list(
|
||||
(
|
||||
wpfs.filter(act_state__in=[WProduct.WPR_ACT_STATE_NOTOK, WProduct.WPR_ACT_STATE_SCRAP]).exclude(step__process__id=1)
|
||||
| wpfs.filter(act_state__in=[WProduct.WPR_ACT_STATE_NOTOK, WProduct.WPR_ACT_STATE_SCRAP],
|
||||
step__process__id=1).exclude(number=None)
|
||||
)\
|
||||
.values('step__process__id',
|
||||
).annotate(count_notok=Count('id')))
|
||||
ret = []
|
||||
process_l = list(Process.objects.filter(is_deleted=False).order_by('number').values('id', 'name'))
|
||||
for i in process_l:
|
||||
ret_item = {'id':i['id'], 'name':i['name'], 'count_ok':0, 'count_notok':0, 'rate':1}
|
||||
for m in count_ok_g:
|
||||
if m['step__process__id'] == ret_item['id']:
|
||||
ret_item['count_ok'] = m['count_ok']
|
||||
for n in count_notok_g:
|
||||
if n['step__process__id'] == ret_item['id']:
|
||||
ret_item['count_notok'] = n['count_notok']
|
||||
rate = (ret_item['count_ok']/(ret_item['count_ok']+ret_item['count_notok'])) \
|
||||
if ret_item['count_ok']+ret_item['count_notok']>0 else 1
|
||||
ret_item['rate'] = rate
|
||||
ret.append(ret_item)
|
||||
return Response(ret)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-21 05:41
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('system', '0003_auto_20210812_0909'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='is_atwork',
|
||||
field=models.BooleanField(default=False, verbose_name='当前在岗'),
|
||||
),
|
||||
]
|
|
@ -116,6 +116,7 @@ class User(AbstractUser):
|
|||
superior = models.ForeignKey(
|
||||
'self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='上级主管')
|
||||
roles = models.ManyToManyField(Role, blank=True, verbose_name='角色')
|
||||
is_atwork = models.BooleanField('当前在岗', default=False)
|
||||
|
||||
class Meta:
|
||||
verbose_name = '用户信息'
|
||||
|
|
|
@ -141,7 +141,9 @@ class UserListSerializer(serializers.ModelSerializer):
|
|||
class Meta:
|
||||
model = User
|
||||
fields = ['id', 'name', 'phone', 'email', 'position',
|
||||
'username', 'is_active', 'date_joined', 'dept_name', 'dept', 'roles', 'avatar', 'roles_name']
|
||||
'username', 'is_active', 'date_joined',
|
||||
'dept_name', 'dept', 'roles', 'avatar',
|
||||
'roles_name', 'is_atwork']
|
||||
|
||||
@staticmethod
|
||||
def setup_eager_loading(queryset):
|
||||
|
|
|
@ -41,6 +41,12 @@ class WProductFilterSet(filters.FilterSet):
|
|||
def filter_tag(self, queryset, name, value):
|
||||
if value == 'no_scrap':
|
||||
queryset = queryset.exclude(act_state=WProduct.WPR_ACT_STATE_SCRAP)
|
||||
elif value == 'notok':
|
||||
queryset = queryset.filter(act_state__in=[WProduct.WPR_ACT_STATE_NOTOK, WProduct.WPR_ACT_STATE_SCRAP])\
|
||||
.exclude(step__process__id = 1) # 不算冷加工的报废
|
||||
elif value == 'ok':
|
||||
queryset = queryset.filter(act_state__in=[WProduct.WPR_ACT_STATE_INM,
|
||||
WProduct.WPR_ACT_STATE_OK, WProduct.WPR_ACT_STATE_SELLED])
|
||||
return queryset
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-18 00:39
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wpm', '0048_operationwproduct_place'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='operationequip',
|
||||
name='state',
|
||||
field=models.PositiveSmallIntegerField(choices=[(0, '完好'), (1, '限用'), (2, '在修'), (3, '禁用')], default=0, verbose_name='当前设备状态'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-20 02:48
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wpm', '0049_operationequip_state'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='operationequip',
|
||||
name='state',
|
||||
field=models.PositiveSmallIntegerField(choices=[(10, '完好'), (20, '限用'), (30, '在修'), (40, '禁用')], default=10, verbose_name='当前设备状态'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-20 07:41
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('sam', '0010_auto_20211208_1408'),
|
||||
('wpm', '0050_alter_operationequip_state'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='wproduct',
|
||||
name='to_order',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='sam.order', verbose_name='指派的订单'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='wproductflow',
|
||||
name='to_order',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='sam.order', verbose_name='指派的订单'),
|
||||
),
|
||||
]
|
|
@ -119,6 +119,7 @@ class WProduct(CommonAModel):
|
|||
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
|
||||
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_ticket')
|
||||
|
||||
to_order = models.ForeignKey('sam.order', verbose_name='指派的订单', null=True, blank=True, on_delete = models.CASCADE)
|
||||
is_mtested = models.BooleanField('是否军检', default=False)
|
||||
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
|
||||
remark_mtest = models.TextField('军检备注', null=True, blank=True)
|
||||
|
@ -192,7 +193,7 @@ class WproductFlow(CommonAModel):
|
|||
on_delete=models.SET_NULL, null=True, blank=True)
|
||||
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
|
||||
on_delete=models.SET_NULL, null=True, blank=True)
|
||||
|
||||
to_order = models.ForeignKey('sam.order', verbose_name='指派的订单', null=True, blank=True, on_delete = models.CASCADE)
|
||||
is_mtested = models.BooleanField('是否军检', default=False)
|
||||
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
|
||||
remark_mtest = models.TextField('军检备注', null=True, blank=True)
|
||||
|
@ -336,4 +337,5 @@ class OperationEquip(BaseModel):
|
|||
Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='oe_operation')
|
||||
equip = models.ForeignKey(Equipment, verbose_name='生产设备',
|
||||
on_delete=models.CASCADE, related_name='oe_equip')
|
||||
state = models.PositiveSmallIntegerField('当前设备状态', choices=Equipment.state_choices, default=Equipment.EQUIP_STATE_OK)
|
||||
remark = models.TextField('备注', null=True, blank=True)
|
||||
|
|
|
@ -19,6 +19,7 @@ from apps.system.models import User
|
|||
from apps.system.serializers import UserSimpleSerializer
|
||||
from apps.wpm.models import Operation, OperationEquip, OperationMaterial, OperationWproduct, Pick, WMaterial, WProduct, OperationRecord, OperationRecordItem, WprouctTicket
|
||||
from django.db import transaction
|
||||
from apps.sam.models import Order
|
||||
|
||||
class PickHalfSerializer(serializers.Serializer):
|
||||
id = serializers.PrimaryKeyRelatedField(queryset=SubProductionProgress.objects.all(), label='子计划进度ID')
|
||||
|
@ -155,6 +156,7 @@ class WProductListSerializer(serializers.ModelSerializer):
|
|||
subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
|
||||
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
|
||||
children = serializers.SerializerMethodField()
|
||||
to_order_ = OrderSimpleSerializer(source='to_order', read_only=True)
|
||||
class Meta:
|
||||
model = WProduct
|
||||
fields = '__all__'
|
||||
|
@ -561,3 +563,7 @@ class WproductMtestSerializer(serializers.ModelSerializer):
|
|||
class Meta:
|
||||
model = WProduct
|
||||
fields = ['remark_mtest', 'is_mtestok']
|
||||
|
||||
class WproductToOrderSerializer(serializers.Serializer):
|
||||
wproducts = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), many=True)
|
||||
order = serializers.PrimaryKeyRelatedField(queryset=Order.objects.all())
|
|
@ -54,7 +54,8 @@ class WpmServies(object):
|
|||
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
|
||||
|
||||
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and wproduct.step.type == Step.STEP_TYPE_COMB: # 夹层检验
|
||||
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and \
|
||||
wproduct.subproduction_plan.subproduction.need_combtest : # 配置中需要质检
|
||||
wproduct.act_state = WProduct.WPR_ACT_STATE_TOCOMBTEST
|
||||
else:
|
||||
wproduct.act_state = WProduct.WPR_ACT_STATE_OK
|
||||
|
@ -113,7 +114,11 @@ class WpmServies(object):
|
|||
objs = WproductFlow.objects.filter(subproduction_plan=sp, is_lastlog=True)
|
||||
count_ok = objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_INM,
|
||||
WProduct.WPR_ACT_STATE_OK, WProduct.WPR_ACT_STATE_SELLED]).count()
|
||||
count_notok = objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_NOTOK, WProduct.WPR_ACT_STATE_SCRAP]).count()
|
||||
count_notok = (
|
||||
objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_NOTOK, WProduct.WPR_ACT_STATE_SCRAP]).exclude(step__process__id=1)
|
||||
| objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_NOTOK, WProduct.WPR_ACT_STATE_SCRAP],
|
||||
step__process__id=1).exclude(number=None)
|
||||
).count()
|
||||
count_real = objs.exclude(act_state__in=[WProduct.WPR_ACT_STATE_TORETEST,
|
||||
WProduct.WPR_ACT_STATE_DOWAIT, WProduct.WPR_ACT_STATE_DOING]).count()
|
||||
ins = SubProductionProgress.objects.filter(subproduction_plan=sp,
|
||||
|
|
|
@ -16,7 +16,7 @@ from rest_framework.decorators import action
|
|||
from apps.wf.models import Workflow
|
||||
from apps.wpm.filters import CuttingFilterSet, OperationRecordFilterSet, WMaterialFilterSet, WProductFilterSet
|
||||
from apps.wpm.models import OperationEquip, OperationWproduct, Pick, PickWproduct, WMaterial, WProduct, Operation, \
|
||||
OperationMaterial, OperationRecord, OperationRecordItem, WprouctTicket
|
||||
OperationMaterial, OperationRecord, OperationRecordItem, WproductFlow, WprouctTicket
|
||||
|
||||
from apps.wpm.serializers import CuttingListSerializer, OperationEquipListSerializer, OperationEquipUpdateSerializer, \
|
||||
OperationMaterialCreate1ListSerailizer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2ListSerailizer, \
|
||||
|
@ -27,7 +27,7 @@ from apps.wpm.serializers import CuttingListSerializer, OperationEquipListSerial
|
|||
PickSerializer, OperationInitSerializer, OperationSubmitSerializer, ScrapSerializer, WMaterialListSerializer, \
|
||||
WProductCardSerializer, WProductDetailSerializer, WProductListSerializer, \
|
||||
WpmTestFormInitSerializer, WproductMtestSerializer, WproductPutInSerializer, \
|
||||
WproductPutInsSerializer, WproductTicketListSerializer
|
||||
WproductPutInsSerializer, WproductTicketListSerializer, WproductToOrderSerializer
|
||||
|
||||
from rest_framework.response import Response
|
||||
from django.db import transaction
|
||||
|
@ -148,7 +148,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
|||
"""
|
||||
perms_map = {'*': '*'}
|
||||
queryset = WProduct.objects.select_related('step', 'material',
|
||||
'subproduction_plan', 'warehouse').prefetch_related('wproduct_child')
|
||||
'subproduction_plan', 'warehouse', 'to_order').prefetch_related('wproduct_child')
|
||||
serializer_class = WProductListSerializer
|
||||
filterset_class = WProductFilterSet
|
||||
search_fields = ['number']
|
||||
|
@ -441,6 +441,30 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
|||
ret.append([str(index + 1), item['step_name'], item['actions']])
|
||||
return Response(ret)
|
||||
|
||||
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=WproductToOrderSerializer)
|
||||
@transaction.atomic
|
||||
def to_order(self, request, pk=None):
|
||||
"""
|
||||
指派发货订单
|
||||
"""
|
||||
serializer = WproductToOrderSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
vdata = serializer.validated_data
|
||||
wps = WProduct.objects.filter(id__in = [i.id for i in vdata.get('wproducts')])
|
||||
wp = wps.first()
|
||||
order = vdata['order']
|
||||
if wp.material != order.product:
|
||||
raise exceptions.ValidationError('所选订单与产品不符')
|
||||
for i in wps:
|
||||
if i.material != wp.material and i.material.type != Material.MA_TYPE_GOOD and i.act_state \
|
||||
not in [WProduct.WPR_ACT_STATE_OK, WProduct.WPR_ACT_STATE_INM]:
|
||||
raise exceptions.ValidationError('所选产品错误')
|
||||
for i in wps:
|
||||
i.to_order = order
|
||||
i.update_by = request.user
|
||||
i.save()
|
||||
WpmServies.add_wproduct_flow_log(i,change_str='to_order')
|
||||
return Response()
|
||||
|
||||
class WproductTicketViewSet(ListModelMixin, GenericViewSet):
|
||||
"""
|
||||
|
@ -559,6 +583,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
|
|||
ope = OperationEquip()
|
||||
ope.operation = op
|
||||
ope.equip = i
|
||||
ope.state = i.state
|
||||
ope.save()
|
||||
# 查询所需的工具工装
|
||||
for i in SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL,
|
||||
|
|
|
@ -47,17 +47,20 @@ class FitJSONRenderer(JSONRenderer):
|
|||
"""
|
||||
response_body = BaseResponse()
|
||||
response = renderer_context.get("response")
|
||||
response_body.code = response.status_code
|
||||
if response_body.code >= 400: # 响应异常
|
||||
response_body.data = data # data里是详细异常信息
|
||||
prefix = ""
|
||||
if isinstance(data, dict):
|
||||
prefix = list(data.keys())[0]
|
||||
data = data[prefix]
|
||||
if isinstance(data, list):
|
||||
data = data[0]
|
||||
response_body.msg = prefix + ":" + str(data) # 取一部分放入msg,方便前端alert
|
||||
status_code = response.status_code # Http状态异常码
|
||||
if status_code >= 400: # 如果http响应异常
|
||||
if isinstance(data, dict) and 'code' in data: # 如果自定义了异常码
|
||||
response_body = data
|
||||
else:
|
||||
response_body.data = data # data里是详细异常信息
|
||||
prefix = ""
|
||||
if isinstance(data, dict):
|
||||
prefix = list(data.keys())[0]
|
||||
data = data[prefix]
|
||||
elif isinstance(data, list):
|
||||
data = data[0]
|
||||
response_body.msg = prefix + ":" + str(data) # 取一部分放入msg,方便前端alert
|
||||
else:
|
||||
response_body.data = data
|
||||
renderer_context.get("response").status_code = 200 # 统一成200响应,用code区分
|
||||
renderer_context.get("response").status_code = 200 # 统一成200响应, 可用body里code区分业务异常
|
||||
return super(FitJSONRenderer, self).render(response_body.dict, accepted_media_type, renderer_context)
|
||||
|
|
Loading…
Reference in New Issue