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
|
package-lock.json
|
||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
.idea/
|
||||||
server/static/
|
server/static/
|
||||||
|
|
@ -7,3 +7,11 @@ export function getPlanGantt(data) {
|
||||||
params: 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"
|
@expand-change="handlerExpand"
|
||||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
: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>
|
||||||
<el-table-column label="产品名称" prop="productName" width="120" show-overflow-tooltip>
|
<el-table-column label="产品名称" prop="productName" width="120" show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -35,12 +35,56 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.init();
|
this.openTheCamera();
|
||||||
},
|
},
|
||||||
methods: {
|
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() {
|
init() {
|
||||||
this.video = document.getElementById('video');
|
// this.video = document.getElementById('video');
|
||||||
this.screenshotCanvas = document.getElementById('screenshotCanvas');
|
this.screenshotCanvas = document.getElementById('screenshotCanvas');
|
||||||
let canvas = document.getElementById('canvas');
|
let canvas = document.getElementById('canvas');
|
||||||
let context = canvas.getContext('2d');
|
let context = canvas.getContext('2d');
|
||||||
|
|
@ -64,7 +108,6 @@
|
||||||
event.data.forEach(function (rect) {
|
event.data.forEach(function (rect) {
|
||||||
context.strokeStyle = '#0764B7';
|
context.strokeStyle = '#0764B7';
|
||||||
context.strokeRect(rect.x, rect.y, rect.width, rect.height);
|
context.strokeRect(rect.x, rect.y, rect.width, rect.height);
|
||||||
// window.plot(rect.x, rect.y, rect.width, rect.height+20);
|
|
||||||
// 避免重复发送请求
|
// 避免重复发送请求
|
||||||
if(!_this.uploadLock){
|
if(!_this.uploadLock){
|
||||||
_this.uploadLock = true;
|
_this.uploadLock = true;
|
||||||
|
|
@ -133,7 +176,10 @@
|
||||||
that.uploadLock = false;
|
that.uploadLock = false;
|
||||||
// this.$message.error('面部识别失败请重新验证');
|
// this.$message.error('面部识别失败请重新验证');
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
closeCamera () {
|
||||||
|
this.video.srcObject.getTracks()[0].stop();
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,55 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.init();
|
this.openTheCamera();
|
||||||
},
|
},
|
||||||
methods: {
|
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() {
|
init() {
|
||||||
this.video = document.getElementById('video');
|
|
||||||
this.screenshotCanvas = document.getElementById('screenshotCanvas');
|
this.screenshotCanvas = document.getElementById('screenshotCanvas');
|
||||||
let canvas = document.getElementById('canvas');
|
let canvas = document.getElementById('canvas');
|
||||||
let context = canvas.getContext('2d');
|
let context = canvas.getContext('2d');
|
||||||
|
|
@ -46,7 +89,6 @@
|
||||||
let _this = this;
|
let _this = this;
|
||||||
//添加事件
|
//添加事件
|
||||||
tracker.on('track', function (event) {
|
tracker.on('track', function (event) {
|
||||||
|
|
||||||
// 检测出人脸 绘画人脸位置
|
// 检测出人脸 绘画人脸位置
|
||||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
// 给每个人脸绘制对应的框
|
// 给每个人脸绘制对应的框
|
||||||
|
|
@ -112,7 +154,10 @@
|
||||||
that.uploadLock = false;
|
that.uploadLock = false;
|
||||||
// this.$message.error('面部识别失败请重新验证');
|
// this.$message.error('面部识别失败请重新验证');
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
closeCamera () {
|
||||||
|
this.video.srcObject.getTracks()[0].stop();
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,122 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="dashboard-container">
|
<div class="dashboard-container">
|
||||||
<el-card class="dashboardTopCard">
|
<div class="dashboardTopCard">
|
||||||
<div class="CardTitleWrap">
|
<div class="CardTitleWrap">
|
||||||
<span class="verticalLine"></span><span class="dashboardCardTitle">数据统计</span>
|
<span class="verticalLine"></span><span class="dashboardCardTitle">数据统计</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="cards" @click="toDetail('1')">
|
<div style="padding: 20px;overflow: hidden;">
|
||||||
<div class="cardCurrentText">本月:{{contractTotalCurrent}}</div>
|
<div class="cardsWrap" @click="toDetail('1')">
|
||||||
<div class="cardTotalText">{{contractTotalCount}}</div>
|
<div class="svgIconWrap">
|
||||||
<div>合同总数</div>
|
<svg-icon
|
||||||
|
icon-class="form"
|
||||||
|
class="svgIcon"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="cards" @click="toDetail('2')">
|
<div class="totalCountWrap">
|
||||||
<div class="cardCurrentText">本月:{{orderTotalCurrent}}</div>
|
<span class="totalCountText">本月合同数</span>
|
||||||
<div class="cardTotalText">{{orderTotalCount}}</div>
|
<div class="totalCountNum">
|
||||||
<div>生产订单总数</div>
|
<span class="totalCount">{{contractTotalCurrent}}</span>
|
||||||
|
<span>个</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="cards" @click="toDetail('3')">
|
|
||||||
<div class="cardCurrentText">在制:{{planTotalCurrent}}</div>
|
|
||||||
<div class="cardTotalText">{{planTotalCount}}</div>
|
|
||||||
<div>已排产生产任务</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="cards" @click="toDetail('4')">
|
|
||||||
<div class="cardCurrentText">本月:4</div>
|
|
||||||
<div class="cardTotalText">20</div>
|
|
||||||
<div>累计交付产品数</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="cards" @click="toDetail('5')">
|
<div class="cardsWrap" @click="toDetail('2')">
|
||||||
<div class="cardCurrentText">本月:2</div>
|
<div class="svgIconWrap">
|
||||||
<div class="cardTotalText">2</div>
|
<svg-icon
|
||||||
<div>累计不合格产品数</div>
|
icon-class="form"
|
||||||
|
class="svgIcon"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
<div class="totalCountWrap">
|
||||||
<el-row class="dashboardSubRow" :gutter="5">
|
<span class="totalCountText">本月生产订单数</span>
|
||||||
<el-col :span="12">
|
<div class="totalCountNum">
|
||||||
<el-card style="border-radius: 10px;">
|
<span class="totalCount">{{orderTotalCurrent}}</span>
|
||||||
<div class="dashboardCardHand">
|
<span>个</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cardsWrap" @click="toDetail('3')">
|
||||||
|
<div class="svgIconWrap">
|
||||||
|
<svg-icon
|
||||||
|
icon-class="form"
|
||||||
|
class="svgIcon"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="totalCountWrap">
|
||||||
|
<span class="totalCountText">本月在制任务</span>
|
||||||
|
<div class="totalCountNum">
|
||||||
|
<span class="totalCount">{{planTotalCurrent}}</span>
|
||||||
|
<span>个</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cardsWrap" @click="toDetail('4')">
|
||||||
|
<div class="svgIconWrap">
|
||||||
|
<svg-icon
|
||||||
|
icon-class="form"
|
||||||
|
class="svgIcon"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="totalCountWrap">
|
||||||
|
<span class="totalCountText">本月交付产品</span>
|
||||||
|
<div class="totalCountNum">
|
||||||
|
<span class="totalCount">30</span>
|
||||||
|
<span>个</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cardsWrap" @click="toDetail('5')">
|
||||||
|
<div class="svgIconWrap">
|
||||||
|
<svg-icon
|
||||||
|
icon-class="form"
|
||||||
|
class="svgIcon"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="totalCountWrap">
|
||||||
|
<span class="totalCountText">本月不合格产品</span>
|
||||||
|
<div class="totalCountNum">
|
||||||
|
<span class="totalCount">30</span>
|
||||||
|
<span>个</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="dashboardMiddle" class="dashboardMiddle">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="15">
|
||||||
<div class="CardTitleWrap">
|
<div class="CardTitleWrap">
|
||||||
<span class="verticalLine"></span><span class="dashboardCardTitle">任务排期</span>
|
<span class="verticalLine"></span><span class="dashboardCardTitle">任务进度</span>
|
||||||
</div>
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1" style="height: 1px"></el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<div class="CardTitleWrap">
|
||||||
|
<span class="verticalLine"></span><span class="dashboardCardTitle">成品率</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row class="dashboardCardPadding">
|
||||||
|
<el-col :span="15">
|
||||||
|
<div style="height: 40px;line-height: 40px;"></div>
|
||||||
|
<div>
|
||||||
|
<gantt
|
||||||
|
v-if="proList.length>0"
|
||||||
|
style="position: relative"
|
||||||
|
:proList="proList"
|
||||||
|
:ganttHeight="ganttHeight"
|
||||||
|
></gantt>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1" style="height: 1px"></el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<div class="dashboardCardHand">
|
||||||
<div class="dashboardCardFilter">
|
<div class="dashboardCardFilter">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="tableDate"
|
v-model="chartDate"
|
||||||
type="month"
|
type="monthrange"
|
||||||
placeholder="查询日期"
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
range-separator="至"
|
range-separator="至"
|
||||||
format="yyyy 年 MM 月"
|
format="yyyy 年 MM 月"
|
||||||
value-format="yyyy-MM"
|
value-format="yyyy-MM"
|
||||||
|
|
@ -49,74 +124,30 @@
|
||||||
>
|
>
|
||||||
</el-date-picker>
|
</el-date-picker>
|
||||||
<div class="convenientWrap">
|
<div class="convenientWrap">
|
||||||
<div class="convenientBtn" :class="{activeIndex:tableIndex==='1'}" @click="convenientClick('1','week')">本周</div>
|
<div class="convenientBtn" :class="{activeIndex:chartIndex==='1'}" @click="convenientClick('1','week')">
|
||||||
<div class="convenientBtn" :class="{activeIndex:tableIndex==='2'}" @click="convenientClick('1','month')">本月</div>
|
本周
|
||||||
<div class="convenientBtn" :class="{activeIndex:tableIndex==='3'}" @click="convenientClick('1','quarter')">三个月</div>
|
</div>
|
||||||
|
<div class="convenientBtn" :class="{activeIndex:chartIndex==='2'}"
|
||||||
|
@click="convenientClick('1','month')">本月
|
||||||
|
</div>
|
||||||
|
<div class="convenientBtn" :class="{activeIndex:chartIndex==='3'}"
|
||||||
|
@click="convenientClick('1','quarter')">三个月
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-table
|
|
||||||
v-loading="listLoadingPlan"
|
|
||||||
:data="planList"
|
|
||||||
border fit stripe
|
|
||||||
:height="cardTabelHeight"
|
|
||||||
>
|
|
||||||
<el-table-column type="index" width="50" />
|
|
||||||
<el-table-column label="任务编号" prop="number">
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="产品名称">
|
|
||||||
<template slot-scope="scope">{{ scope.row.product_.name }}</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="产品型号">
|
|
||||||
<template slot-scope="scope">{{ scope.row.product_.specification }}</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="生产数量" prop="count">
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="开始时间" prop="start_date">
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="结束时间" prop="end_date">
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-card style="border-radius: 10px;">
|
|
||||||
<div class="dashboardCardHand">
|
|
||||||
<div class="CardTitleWrap">
|
|
||||||
<span class="verticalLine"></span><span class="dashboardCardTitle">成品率</span>
|
|
||||||
</div>
|
</div>
|
||||||
<!--<div class="dashboardCardTitle">成品率</div>-->
|
<div id="chartColumn" style="width:100%;" :style="{height:ganttHeight+'px'}"></div>
|
||||||
<div class="dashboardCardFilter">
|
|
||||||
<el-date-picker
|
|
||||||
v-model="chartDate"
|
|
||||||
type="month"
|
|
||||||
placeholder="查询日期"
|
|
||||||
range-separator="至"
|
|
||||||
format="yyyy 年 MM 月"
|
|
||||||
value-format="yyyy-MM"
|
|
||||||
@change="searchTimeChange('2')"
|
|
||||||
>
|
|
||||||
</el-date-picker>
|
|
||||||
<div class="convenientWrap">
|
|
||||||
<div class="convenientBtn" :class="{activeIndex:chartIndex==='1'}" @click="convenientClick('2','week')">本周</div>
|
|
||||||
<div class="convenientBtn" :class="{activeIndex:chartIndex==='2'}" @click="convenientClick('2','month')">本月</div>
|
|
||||||
<div class="convenientBtn" :class="{activeIndex:chartIndex==='3'}" @click="convenientClick('2','quarter')">三个月</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="chartColumn" style="width:100%;" :style="{height:cardTabelHeight+'px'}"></div>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row class="dashboardSubRow" :gutter="5">
|
</div>
|
||||||
|
<el-row :gutter="5">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-card style="border-radius: 10px;">
|
<div class="dashboardBottomRow">
|
||||||
<div class="dashboardCardHand">
|
<div class="dashboardCardHand">
|
||||||
<div class="CardTitleWrap">
|
<div class="CardTitleWrap">
|
||||||
<span class="verticalLine"></span><span class="dashboardCardTitle">库存列表</span>
|
<span class="verticalLine"></span><span class="dashboardCardTitle">库存列表</span>
|
||||||
<span class="stockMore" @click="stockMore">更多>></span>
|
<span class="stockMore" @click="stockMore">更多>></span>
|
||||||
</div>
|
</div>
|
||||||
<!--<div class="dashboardCardTitle">库存列表 </div>-->
|
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<el-pagination
|
<el-pagination
|
||||||
:current-page.sync="stockPage"
|
:current-page.sync="stockPage"
|
||||||
|
|
@ -129,19 +160,22 @@
|
||||||
</el-pagination>
|
</el-pagination>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="dashboardCardPadding">
|
||||||
<el-table
|
<el-table
|
||||||
v-loading="listLoadingStock"
|
v-loading="listLoadingStock"
|
||||||
:data="stockList"
|
:data="stockList"
|
||||||
border fit stripe
|
fit stripe
|
||||||
|
size="mini"
|
||||||
:height="cardTabelHeight"
|
:height="cardTabelHeight"
|
||||||
|
style="border-top: 1px solid #f5f5f5;"
|
||||||
>
|
>
|
||||||
<el-table-column label="物料编号" prop="material_">
|
<el-table-column label="物料编号" prop="material_">
|
||||||
<template slot-scope="scope">{{ scope.row.material_.number }}</template>
|
<template slot-scope="scope">{{ scope.row.material_.number }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="物料名称" prop="material_">
|
<el-table-column label="物料名称" prop="material_" show-overflow-tooltip>
|
||||||
<template slot-scope="scope">{{ scope.row.material_.name }}</template>
|
<template slot-scope="scope">{{ scope.row.material_.name }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="规格型号" prop="material_">
|
<el-table-column label="规格型号" prop="material_" show-overflow-tooltip>
|
||||||
<template slot-scope="scope">{{ scope.row.material_.specification }}</template>
|
<template slot-scope="scope">{{ scope.row.material_.specification }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="物料类型" prop="material_">
|
<el-table-column label="物料类型" prop="material_">
|
||||||
|
|
@ -156,15 +190,15 @@
|
||||||
<template slot-scope="scope">{{ scope.row.warehouse_.name }}</template>
|
<template slot-scope="scope">{{ scope.row.warehouse_.name }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-card>
|
</div>
|
||||||
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-card style="height: 350px;border-radius: 10px;">
|
<div class="dashboardBottomRow">
|
||||||
<div class="dashboardCardHand">
|
<div class="dashboardCardHand">
|
||||||
<div class="CardTitleWrap">
|
<div class="CardTitleWrap">
|
||||||
<span class="verticalLine"></span><span class="dashboardCardTitle">提醒</span>
|
<span class="verticalLine"></span><span class="dashboardCardTitle">提醒</span>
|
||||||
</div>
|
</div>
|
||||||
<!--<div class="dashboardCardTitle">提醒</div>-->
|
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<el-pagination
|
<el-pagination
|
||||||
:current-page.sync="remindPage"
|
:current-page.sync="remindPage"
|
||||||
|
|
@ -177,29 +211,16 @@
|
||||||
</el-pagination>
|
</el-pagination>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-tabs type="card" :style="{height:cardTabelHeight+'px'}" v-model="activeName" @tab-click="activeNameClick">
|
<div class="dashboardCardPadding">
|
||||||
|
<el-tabs type="card" :style="{height:cardTabelHeight+'px'}" v-model="activeName"
|
||||||
|
@tab-click="activeNameClick">
|
||||||
<el-tab-pane label="库存警告" name="库存警告">
|
<el-tab-pane label="库存警告" name="库存警告">
|
||||||
<ul class="lists">
|
<ul :style="{height:cardTabelHeight-47+'px'}" class="lists" :class="{anim:animate}" @mouseenter="Stop()" @mouseleave="Up()">
|
||||||
<li class="listItem">
|
<li v-for="item in list" :key="item.id" class="listItem">
|
||||||
<div class="itemText">
|
<div class="itemText">
|
||||||
<span>玻璃低于安全库存</span><span>2021-12-30</span>
|
<span>{{item.name}}</span><span style="float: right">2021-12-30</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="listItem" v-for="item in warningList" :key="item.id">
|
|
||||||
<div class="itemText">
|
|
||||||
<span>{{item}}</span><span>2021-12-20</span>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<!--<li class="listItem">
|
|
||||||
<div class="itemText">
|
|
||||||
<span>玻璃低于安全库存</span><span>2021-11-30</span>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="listItem">
|
|
||||||
<div class="itemText">
|
|
||||||
<span>某某批货临近交货日期</span><span>2021-11-20</span>
|
|
||||||
</div>
|
|
||||||
</li>-->
|
|
||||||
</ul>
|
</ul>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="临近交货" name="临近交货">
|
<el-tab-pane label="临近交货" name="临近交货">
|
||||||
|
|
@ -231,7 +252,8 @@
|
||||||
</ul>
|
</ul>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</el-card>
|
</div>
|
||||||
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -240,16 +262,22 @@
|
||||||
<script>
|
<script>
|
||||||
import echarts from 'echarts'
|
import echarts from 'echarts'
|
||||||
import {mapGetters} from 'vuex';
|
import {mapGetters} from 'vuex';
|
||||||
|
import {getPlanGantt} from "@/api/srm";
|
||||||
|
import {getProcessYield} from "@/api/srm";
|
||||||
import {getMaterialList} from "@/api/mtm";
|
import {getMaterialList} from "@/api/mtm";
|
||||||
import {getInventoryList} from "@/api/inm";
|
import {getInventoryList} from "@/api/inm";
|
||||||
import {getProductionplanList} from "@/api/pm";
|
import {getProductionplanList} from "@/api/pm";
|
||||||
import {getmaterialbatchList} from "@/api/inm";
|
import {getmaterialbatchList} from "@/api/inm";
|
||||||
|
import gantt from "@/components/Gantt/dashGantt";
|
||||||
import {getContractList, getOrderList} from "@/api/sam";
|
import {getContractList, getOrderList} from "@/api/sam";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {gantt},
|
||||||
name: 'Dashboard',
|
name: 'Dashboard',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
animate: false,
|
||||||
|
intNum: null,
|
||||||
chartColumn: null,
|
chartColumn: null,
|
||||||
week: null,
|
week: null,
|
||||||
currentTime: null,
|
currentTime: null,
|
||||||
|
|
@ -265,15 +293,20 @@ export default {
|
||||||
tableIndex: null,
|
tableIndex: null,
|
||||||
chartIndex: null,
|
chartIndex: null,
|
||||||
tableDate: '2021-12',
|
tableDate: '2021-12',
|
||||||
chartDate:'2021-12',
|
chartDate: [],
|
||||||
|
proList: [],
|
||||||
planList: [],
|
planList: [],
|
||||||
stockList: [],
|
stockList: [],
|
||||||
remindList: [],
|
remindList: [],
|
||||||
warningList: [],
|
warningList: [],
|
||||||
list: [
|
list: [
|
||||||
{id:1,name:'HIehd9',card:'3337',sco:'REF-32'},
|
{id: 1, name: 'HIehd91', card: '3337', sco: 'REF-32'},
|
||||||
{id:1,name:'HIehd9',card:'3337',sco:'REF-32'},
|
{id: 2, name: 'HIehd92', card: '3337', sco: 'REF-32'},
|
||||||
{id:1,name:'HIehd9',card:'3337',sco:'REF-32'}
|
{id: 3, name: 'HIehd93', card: '3337', sco: 'REF-32'},
|
||||||
|
{id: 4, name: 'HIehd94', card: '3337', sco: 'REF-32'},
|
||||||
|
{id: 5, name: 'HIehd95', card: '3337', sco: 'REF-32'},
|
||||||
|
{id: 6, name: 'HIehd96', card: '3337', sco: 'REF-32'},
|
||||||
|
{id: 7, name: 'HIehd97', card: '3337', sco: 'REF-32'},
|
||||||
],
|
],
|
||||||
options: {
|
options: {
|
||||||
"1": '成品',
|
"1": '成品',
|
||||||
|
|
@ -284,7 +317,10 @@ export default {
|
||||||
"6": '辅助工装',
|
"6": '辅助工装',
|
||||||
},
|
},
|
||||||
activeName: '库存警告',
|
activeName: '库存警告',
|
||||||
|
chartData: {
|
||||||
|
xAxisData: ["冷加工", "热弯", "钢化", "镀膜", "夹层", "包边", "装框"],
|
||||||
seriesData: [80, 95, 96, 96, 96, 98, 99, 100],
|
seriesData: [80, 95, 96, 96, 96, 98, 99, 100],
|
||||||
|
},
|
||||||
contractTotalCount: null,//合同总数
|
contractTotalCount: null,//合同总数
|
||||||
contractTotalCurrent: null,
|
contractTotalCurrent: null,
|
||||||
orderTotalCount: null,//生产订单总数
|
orderTotalCount: null,//生产订单总数
|
||||||
|
|
@ -296,6 +332,7 @@ export default {
|
||||||
listLoadingPlan: false,
|
listLoadingPlan: false,
|
||||||
listLoadingStock: false,
|
listLoadingStock: false,
|
||||||
cardTabelHeight: null,
|
cardTabelHeight: null,
|
||||||
|
ganttHeight: 0,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -306,8 +343,25 @@ export default {
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openWord(){
|
getNoticeData() {
|
||||||
window.open("http://47.95.0.242:2222/media/2021/09/07/004-%E8%AF%B7%E5%81%87%E5%8D%95_LL8uZdx.docx");
|
this.ScrollUp();
|
||||||
|
},
|
||||||
|
ScrollUp() {
|
||||||
|
this.intNum = setInterval(() => {
|
||||||
|
this.animate = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.list.push(this.list[0]);
|
||||||
|
this.list.shift();
|
||||||
|
this.animate = false;
|
||||||
|
}, 500)
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
//鼠标移上去停止
|
||||||
|
Stop() {
|
||||||
|
clearInterval(this.intNum);
|
||||||
|
},
|
||||||
|
Up() {
|
||||||
|
this.ScrollUp();
|
||||||
},
|
},
|
||||||
getStatisticsData() {
|
getStatisticsData() {
|
||||||
let that = this;
|
let that = this;
|
||||||
|
|
@ -353,11 +407,35 @@ export default {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//获取交付产品
|
//获取交付产品
|
||||||
|
|
||||||
//获取不合格产品
|
//获取不合格产品
|
||||||
|
|
||||||
getMaterialList({page:0,tag:'low_inm'}).then((response) => {
|
//获取成品率
|
||||||
|
let d = new Date(that.currentYear, month, 0);
|
||||||
|
let days = d.getDate();
|
||||||
|
let start = that.currentYear + '-' + that.currentMonth;
|
||||||
|
let startDate = start + '-01';
|
||||||
|
let endDate = start + '-' + days;
|
||||||
|
that.chartDate = [start, start];
|
||||||
|
getProcessYield({datetime_start: startDate, datetime_end: endDate}).then((response) => {
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
that.warningList = response.data;
|
let list = response.data;
|
||||||
|
let xAxisData = [], seriesData = [];
|
||||||
|
list.forEach(item => {
|
||||||
|
xAxisData.push(item.name);
|
||||||
|
let rate = item.rate * 100;
|
||||||
|
seriesData.push(rate.toFixed(2))
|
||||||
|
});
|
||||||
|
that.chartData.xAxisData = xAxisData;
|
||||||
|
that.chartData.seriesData = seriesData;
|
||||||
|
this.drawChart();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//获取库存警告
|
||||||
|
getMaterialList({tag: 'low_inm'}).then((response) => {
|
||||||
|
if (response.data) {
|
||||||
|
that.warningList = response.data.results;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -394,6 +472,7 @@ export default {
|
||||||
},
|
},
|
||||||
//图标渲染
|
//图标渲染
|
||||||
drawChart() {
|
drawChart() {
|
||||||
|
let that = this;
|
||||||
this.chartColumn = echarts.init(document.getElementById('chartColumn'));
|
this.chartColumn = echarts.init(document.getElementById('chartColumn'));
|
||||||
this.chartColumn.setOption({
|
this.chartColumn.setOption({
|
||||||
// title: { text: '成品率' },
|
// title: { text: '成品率' },
|
||||||
|
|
@ -429,7 +508,7 @@ export default {
|
||||||
splitLine: {
|
splitLine: {
|
||||||
show: false, //去掉X轴分割线
|
show: false, //去掉X轴分割线
|
||||||
},
|
},
|
||||||
data: ["冷加工", "热弯", "钢化", "镀膜", "夹层", "包边", "装框", "成品"]
|
data: that.chartData.xAxisData,
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
axisLine: {
|
axisLine: {
|
||||||
|
|
@ -451,8 +530,8 @@ export default {
|
||||||
series: [{
|
series: [{
|
||||||
name: '成品率',
|
name: '成品率',
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
barWidth: 40,
|
barWidth: 20,
|
||||||
data: this.seriesData,
|
data: that.chartData.seriesData,
|
||||||
label: {
|
label: {
|
||||||
show: true, //开启显示
|
show: true, //开启显示
|
||||||
position: 'top', //在上方显示
|
position: 'top', //在上方显示
|
||||||
|
|
@ -464,13 +543,13 @@ export default {
|
||||||
},
|
},
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
normal: {
|
normal: {
|
||||||
/*color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
||||||
offset: 0,
|
offset: 0,
|
||||||
color: '#adcff3'
|
color: '#adcff3'
|
||||||
}, {
|
}, {
|
||||||
offset: 1,
|
offset: 1,
|
||||||
color: '#409EFF'
|
color: '#409EFF'
|
||||||
}]),*/
|
}]),
|
||||||
|
|
||||||
/*color: function(params) {
|
/*color: function(params) {
|
||||||
let colorList = [
|
let colorList = [
|
||||||
|
|
@ -492,13 +571,13 @@ export default {
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
},*/
|
},*/
|
||||||
color: function(params) {
|
/*color: function(params) {
|
||||||
let colorList = [
|
let colorList = [
|
||||||
'#5fcdc2','#a378e4','#fea94c','#f27197',
|
'#5fcdc2','#a378e4','#fea94c','#f27197',
|
||||||
'#409eff','#5fcdc2','#a378e4','#fea94c'
|
'#409eff','#5fcdc2','#a378e4','#fea94c'
|
||||||
];
|
];
|
||||||
return colorList[params.dataIndex]
|
return colorList[params.dataIndex]
|
||||||
},
|
},*/
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}]
|
}]
|
||||||
|
|
@ -513,7 +592,7 @@ export default {
|
||||||
} else if (index === '2') {
|
} else if (index === '2') {
|
||||||
this.$router.push({name: 'order', params: {page: 1, page_size: 20}})
|
this.$router.push({name: 'order', params: {page: 1, page_size: 20}})
|
||||||
} else if (index === '3') {
|
} else if (index === '3') {
|
||||||
this.$router.push({name:'plan',params:{page:1,page_size:20}})
|
this.$router.push({name: 'management', params: {page: 1, page_size: 20}})
|
||||||
} else if (index === '4') {
|
} else if (index === '4') {
|
||||||
this.$router.push({name: 'product', params: {page: 1, page_size: 20, material__type: 1}})
|
this.$router.push({name: 'product', params: {page: 1, page_size: 20, material__type: 1}})
|
||||||
} else if (index === '5') {
|
} else if (index === '5') {
|
||||||
|
|
@ -556,18 +635,22 @@ export default {
|
||||||
startTime = yea + '-' + mon + '-01';
|
startTime = yea + '-' + mon + '-01';
|
||||||
}
|
}
|
||||||
if (index === '1') {
|
if (index === '1') {
|
||||||
this.tableDate = null;
|
|
||||||
this.tableIndex = activeIndex;
|
|
||||||
this.listLoadingPlan = true;
|
|
||||||
getProductionplanList({page:0,create_time_start:startTime,create_time_end:endTime}).then((response) => {
|
|
||||||
if (response.data) {
|
|
||||||
that.planList = response.data;
|
|
||||||
}
|
|
||||||
this.listLoadingPlan = false;
|
|
||||||
});
|
|
||||||
}else{
|
|
||||||
this.chartDate = null;
|
|
||||||
this.chartIndex = activeIndex;
|
this.chartIndex = activeIndex;
|
||||||
|
getProcessYield({datetime_start: startTime, datetime_end: endTime}).then((response) => {
|
||||||
|
if (response.data) {
|
||||||
|
let list = response.data;
|
||||||
|
let xAxisData = [], seriesData = [];
|
||||||
|
list.forEach(item => {
|
||||||
|
xAxisData.push(item.name);
|
||||||
|
let rate = item.rate * 100;
|
||||||
|
seriesData.push(rate.toFixed(2))
|
||||||
|
});
|
||||||
|
that.chartData.xAxisData = xAxisData;
|
||||||
|
that.chartData.seriesData = seriesData;
|
||||||
|
this.drawChart();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
//根据时间和类型获取数据
|
//根据时间和类型获取数据
|
||||||
},
|
},
|
||||||
|
|
@ -578,33 +661,34 @@ export default {
|
||||||
let year = null, month = null, days = null;
|
let year = null, month = null, days = null;
|
||||||
if (index === '1') {
|
if (index === '1') {
|
||||||
this.tableIndex = null;
|
this.tableIndex = null;
|
||||||
startDate = this.tableDate+'-01';
|
startDate = that.chartDate[0] + '-01';
|
||||||
year = this.tableDate.split("-")[0];
|
year = that.chartDate[1].split("-")[0];
|
||||||
month = this.tableDate.split("-")[1];
|
month = that.chartDate[1].split("-")[1];
|
||||||
let d = new Date(year, month, 0);
|
let d = new Date(year, month, 0);
|
||||||
days = d.getDate();
|
days = d.getDate();
|
||||||
endDate = this.tableDate + '-' + days;
|
endDate = this.tableDate + '-' + days;
|
||||||
this.listLoadingPlan = true;
|
getProcessYield({datetime_start: startDate, datetime_end: endDate}).then((response) => {
|
||||||
getProductionplanList({page:0,create_time_start:startDate,create_time_end:endDate}).then((response) => {
|
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
that.planList = response.data;
|
let list = response.data;
|
||||||
}
|
let xAxisData = [], seriesData = [];
|
||||||
this.listLoadingPlan = false;
|
list.forEach(item => {
|
||||||
|
xAxisData.push(item.name);
|
||||||
|
let rate = item.rate * 100;
|
||||||
|
seriesData.push(rate.toFixed(2))
|
||||||
|
});
|
||||||
|
that.chartData.xAxisData = xAxisData;
|
||||||
|
that.chartData.seriesData = seriesData;
|
||||||
|
this.drawChart();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}else{
|
|
||||||
this.chartIndex = null;
|
|
||||||
startDate = this.chartDate+'-01';
|
|
||||||
year = this.chartDate.split("-")[0];
|
|
||||||
month = this.chartDate.split("-")[1];
|
|
||||||
let d = new Date(year, month, 0);
|
|
||||||
days = d.getDate();
|
|
||||||
endDate = this.chartDate + '-'+days;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
//库存
|
||||||
handleStockSizeChange(val) {
|
handleStockSizeChange(val) {
|
||||||
this.stockPageSize = val;
|
this.stockPageSize = val;
|
||||||
this.stockPage = 1;
|
this.stockPage = 1;
|
||||||
},
|
},
|
||||||
|
//库存
|
||||||
handleStockCurrentChange(val) {
|
handleStockCurrentChange(val) {
|
||||||
let that = this;
|
let that = this;
|
||||||
this.listLoading = true;
|
this.listLoading = true;
|
||||||
|
|
@ -617,17 +701,15 @@ export default {
|
||||||
this.listLoading = false;
|
this.listLoading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
activeNameClick(tab, event) {
|
//提示
|
||||||
|
activeNameClick(tab) {
|
||||||
let that = this;
|
let that = this;
|
||||||
// debugger;
|
|
||||||
// console.log(tab, event);
|
|
||||||
if (tab.label === '库存警告') {
|
if (tab.label === '库存警告') {
|
||||||
getMaterialList({page: 0, tag: 'low_inm'}).then((response) => {
|
getMaterialList({page: 0, tag: 'low_inm'}).then((response) => {
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
that.warningList = response.data;
|
that.warningList = response.data;
|
||||||
that.remindTotal = response.data.length;
|
that.remindTotal = response.data.length;
|
||||||
}
|
}
|
||||||
this.listLoadingPlan = false;
|
|
||||||
});
|
});
|
||||||
} else if (tab.label === '临近交货') {
|
} else if (tab.label === '临近交货') {
|
||||||
getmaterialbatchList({page: 0, tag: 'expired'}).then((response) => {
|
getmaterialbatchList({page: 0, tag: 'expired'}).then((response) => {
|
||||||
|
|
@ -635,7 +717,6 @@ export default {
|
||||||
that.warningList = response.data;
|
that.warningList = response.data;
|
||||||
that.remindTotal = response.data.length;
|
that.remindTotal = response.data.length;
|
||||||
}
|
}
|
||||||
this.listLoadingPlan = false;
|
|
||||||
});
|
});
|
||||||
} else if (tab.label === '过期提醒') {
|
} else if (tab.label === '过期提醒') {
|
||||||
getmaterialbatchList({page: 0, tag: 'expired'}).then((response) => {
|
getmaterialbatchList({page: 0, tag: 'expired'}).then((response) => {
|
||||||
|
|
@ -643,7 +724,6 @@ export default {
|
||||||
that.warningList = response.data;
|
that.warningList = response.data;
|
||||||
that.remindTotal = response.data.length;
|
that.remindTotal = response.data.length;
|
||||||
}
|
}
|
||||||
this.listLoadingPlan = false;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -654,18 +734,91 @@ export default {
|
||||||
handleRemindCurrentChange(val) {
|
handleRemindCurrentChange(val) {
|
||||||
console.log(`当前页: ${val}`);
|
console.log(`当前页: ${val}`);
|
||||||
},
|
},
|
||||||
|
getGanttData() {
|
||||||
|
let that = this;
|
||||||
|
getPlanGantt({}).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
let arr = [];
|
||||||
|
let list = res.data.results;
|
||||||
|
list.forEach(item => {
|
||||||
|
if (!item.children || item.children.length < 1) {
|
||||||
|
let startTime = new Date(item.start_date).getTime();
|
||||||
|
let endTime = new Date(item.end_date).getTime();
|
||||||
|
let obj = new Object();
|
||||||
|
obj.name = item.number;
|
||||||
|
obj.id = item.id;
|
||||||
|
obj.top = 20;
|
||||||
|
obj.startTime = startTime;
|
||||||
|
obj.endTime = endTime;
|
||||||
|
obj.planTime = [startTime, endTime];
|
||||||
|
obj.per = item.count;
|
||||||
|
obj.type = 1;
|
||||||
|
obj.productName = item.product_.name;
|
||||||
|
obj.productNum = item.product_.specification;
|
||||||
|
obj.isShow = true;
|
||||||
|
arr.push(obj);
|
||||||
|
} else if (item.children && item.children.length >= 1) {
|
||||||
|
let startTime = new Date(item.start_date).getTime();
|
||||||
|
let endTime = new Date(item.end_date).getTime();
|
||||||
|
let temp = [];
|
||||||
|
let parentId = item.id;
|
||||||
|
let children = item.children;
|
||||||
|
children.forEach(child => {
|
||||||
|
let start = new Date(child.start_date).getTime();
|
||||||
|
let end = new Date(child.end_date).getTime();
|
||||||
|
let objChild = new Object();
|
||||||
|
objChild.name = child.number;
|
||||||
|
objChild.id = child.id;
|
||||||
|
objChild.top = 50;
|
||||||
|
objChild.parentId = parentId;
|
||||||
|
objChild.startTime = start;
|
||||||
|
objChild.endTime = end;
|
||||||
|
objChild.planTime = [start, end];
|
||||||
|
objChild.per = child.count;
|
||||||
|
objChild.per1 = child.count_real;
|
||||||
|
objChild.type = 1;
|
||||||
|
objChild.productName = child.product_.name;
|
||||||
|
objChild.productNum = child.product_.specification;
|
||||||
|
objChild.isShow = true;
|
||||||
|
|
||||||
|
temp.push(objChild);
|
||||||
|
});
|
||||||
|
let obj = new Object();
|
||||||
|
obj.name = item.number;
|
||||||
|
obj.id = item.id;
|
||||||
|
obj.top = 20;
|
||||||
|
obj.startTime = startTime;
|
||||||
|
obj.endTime = endTime;
|
||||||
|
obj.planTime = [startTime, endTime];
|
||||||
|
obj.per = item.count;
|
||||||
|
obj.per1 = item.count_real;
|
||||||
|
obj.type = 3;
|
||||||
|
obj.productName = item.product_.name;
|
||||||
|
obj.productNum = item.product_.specification;
|
||||||
|
obj.children = temp;
|
||||||
|
obj.isShow = true;
|
||||||
|
arr.push(obj);
|
||||||
|
}
|
||||||
|
that.proList = arr;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
that.$message.error(res.msg);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
// let he = document.documentElement.clientHeight || document.body.clientHeight;
|
|
||||||
let hei = document.getElementsByClassName('app-main')[0].clientHeight;
|
let hei = document.getElementsByClassName('app-main')[0].clientHeight;
|
||||||
let heig = document.getElementsByClassName('dashboardTopCard')[0].clientHeight;
|
let heig = document.getElementsByClassName('dashboardTopCard')[0].clientHeight;
|
||||||
this.cardTabelHeight = ((hei - heig - 130) / 2);
|
this.cardTabelHeight = ((hei - heig - 130) / 2);
|
||||||
document.getElementById('chartColumn').style.height = this.cardTabelHeight+'px';
|
this.ganttHeight = this.cardTabelHeight - 50;
|
||||||
this.drawChart();
|
document.getElementById('chartColumn').style.height = this.cardTabelHeight - 35 + 'px';
|
||||||
this.getPlanList();
|
this.getPlanList();
|
||||||
this.getStockList();
|
this.getStockList();
|
||||||
|
this.getGanttData();
|
||||||
this.getStatisticsData();
|
this.getStatisticsData();
|
||||||
|
this.getNoticeData();
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
this.drawChart()
|
this.drawChart()
|
||||||
|
|
@ -674,90 +827,130 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
ul{
|
|
||||||
margin: 0!important;
|
|
||||||
}
|
|
||||||
.el-card.is-always-shadow {
|
.el-card.is-always-shadow {
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
}
|
}
|
||||||
.dashboard-container {
|
.dashboard-container {
|
||||||
margin: 5px 6px;
|
margin: 5px 6px;
|
||||||
}
|
}
|
||||||
.dashboard-text {
|
.dashboardTopCard, .dashboardMiddle, .dashboardBottomRow {
|
||||||
font-size: 30px;
|
-webkit-border-radius: 5px;
|
||||||
line-height: 46px;
|
-moz-border-radius: 5px;
|
||||||
}
|
border-radius: 5px;
|
||||||
.dashboardTopCard{
|
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
border-radius: 10px;
|
background: #ffffff;
|
||||||
.cards{
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
|
||||||
width: 18%;
|
}
|
||||||
color: #ffffff;
|
.dashboardBottomRow {
|
||||||
background: #5fcdc2;
|
margin-bottom: 0;
|
||||||
text-align: center;
|
}
|
||||||
border-radius: 10px;
|
.dashboardCardPadding {
|
||||||
padding: 10px;
|
padding: 5px 20px 20px 20px;
|
||||||
line-height: 30px;
|
}
|
||||||
|
/**/
|
||||||
|
.cardsWrap {
|
||||||
|
display: flex;
|
||||||
|
width: 20%;
|
||||||
|
color: #777777;
|
||||||
float: left;
|
float: left;
|
||||||
margin: 15px 1%;
|
font-size: 14px;
|
||||||
.cardCurrentText{
|
|
||||||
text-align: left;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
}
|
||||||
.cardTotalText{
|
.svgIconWrap {
|
||||||
font-size: 30px;
|
margin-right: 20px;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 15px;
|
||||||
|
text-align: center;
|
||||||
|
.svgIcon {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-top: 13px
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.cards:nth-of-type(2){
|
.cardsWrap:nth-child(1) {
|
||||||
background:#5fcdc2;;
|
.svgIconWrap {
|
||||||
}
|
background: #e9f3ff;
|
||||||
.cards:nth-child(3){
|
.svgIcon {
|
||||||
background:#a378e4;;
|
color: #409EFF;
|
||||||
}
|
|
||||||
.cards:nth-of-type(4){
|
|
||||||
background:#fea94c;;
|
|
||||||
}
|
|
||||||
.cards:nth-of-type(5){
|
|
||||||
background:#f27197;;
|
|
||||||
}
|
|
||||||
.cards:nth-of-type(6){
|
|
||||||
background:#409eff;;
|
|
||||||
}
|
|
||||||
.cards:hover{
|
|
||||||
box-shadow: 0 0 12px 5px rgba(0,0,0,.1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.cardsWrap:nth-child(2) {
|
||||||
|
.svgIconWrap {
|
||||||
|
background: #fff1de;
|
||||||
|
.svgIcon {
|
||||||
|
color: #ffb23f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cardsWrap:nth-child(3) {
|
||||||
|
.svgIconWrap {
|
||||||
|
background: #d9f6d8;
|
||||||
|
.svgIcon {
|
||||||
|
color: #54cb48;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cardsWrap:nth-child(4) {
|
||||||
|
.svgIconWrap {
|
||||||
|
background: #f0e8fd;
|
||||||
|
.svgIcon {
|
||||||
|
color: #a378e4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cardsWrap:nth-child(5) {
|
||||||
|
.svgIconWrap {
|
||||||
|
background: #f7e5ea;
|
||||||
|
.svgIcon {
|
||||||
|
color: #f27197;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.totalCountText {
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px
|
||||||
|
}
|
||||||
|
.totalCountNum {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
.totalCount {
|
||||||
|
font-size: 25px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #626262;
|
||||||
|
}
|
||||||
|
/**/
|
||||||
.CardTitleWrap {
|
.CardTitleWrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 35px;
|
height: 35px;
|
||||||
line-height: 35px;
|
line-height: 35px;
|
||||||
padding-left: 1%;
|
padding-left: 1%;
|
||||||
padding-top: 6px;
|
box-sizing: border-box;
|
||||||
|
border-bottom: 1px solid #f5f5f5;
|
||||||
|
/*padding-top: 6px;*/
|
||||||
.verticalLine {
|
.verticalLine {
|
||||||
width: 4px;
|
width: 4px;
|
||||||
height: 20px;
|
height: 15px;
|
||||||
background: orangered;
|
background: #409EFF;
|
||||||
margin-right: 7px;
|
margin-right: 7px;
|
||||||
margin-top: 6px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
.dashboardCardTitle {
|
.dashboardCardTitle {
|
||||||
height: 35px;
|
height: 34px;
|
||||||
line-height:35px;
|
line-height: 34px;
|
||||||
font-size: 20px;
|
font-size: 14px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
width: 70px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-right: 7px;
|
margin-right: 7px;
|
||||||
}
|
}
|
||||||
.stockMore {
|
.stockMore {
|
||||||
font-size: 14px;
|
font-size: 12px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: #409EFF;
|
color: #409EFF;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*成品率筛选条件*/
|
||||||
.dashboardSubRow{
|
|
||||||
margin-bottom: 5px;
|
|
||||||
.dashboardCardHand {
|
.dashboardCardHand {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
@ -767,12 +960,13 @@ export default {
|
||||||
display: flex;
|
display: flex;
|
||||||
border: 1px solid #DCDFE6;
|
border: 1px solid #DCDFE6;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
height: 35px;
|
height: 30px;
|
||||||
line-height:35px;
|
line-height: 30px;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
|
font-size: 12px;
|
||||||
.convenientBtn {
|
.convenientBtn {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 60px;
|
width: 50px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-right: 1px solid #DCDFE6;
|
border-right: 1px solid #DCDFE6;
|
||||||
}
|
}
|
||||||
|
|
@ -789,13 +983,18 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
.anim {
|
||||||
|
transition: all 0.5s;
|
||||||
|
margin-top: -35px; //高度等于行高
|
||||||
}
|
}
|
||||||
|
|
||||||
.lists {
|
.lists {
|
||||||
|
height: 100%;
|
||||||
|
line-height: 35px;
|
||||||
|
transition: top 0.5s;
|
||||||
|
overflow-y: scroll;
|
||||||
padding-right: 40px;
|
padding-right: 40px;
|
||||||
|
margin: 0 !important;
|
||||||
.listItem {
|
.listItem {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
|
|
@ -812,4 +1011,8 @@ export default {
|
||||||
height: 100% !important;
|
height: 100% !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#dashboardMiddle .el-range-editor--medium.el-input__inner,
|
||||||
|
#dashboardMiddle .el-range-editor.el-input__inner {
|
||||||
|
height: 30px !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -64,10 +64,10 @@
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
</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 style="font-size: 28px;color: #333333;text-align: center;font-weight: bold;margin-bottom: 15px;">打卡</div>
|
||||||
<div class="testTracking">
|
<div class="testTracking">
|
||||||
<faceLogin name="faceLogin" @func="getMsgFormSon"></faceLogin>
|
<faceLogin ref="faceTracking" name="faceLogin" @func="getMsgFormSon"></faceLogin>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -179,9 +179,61 @@
|
||||||
//人脸登录
|
//人脸登录
|
||||||
takePhoto(){
|
takePhoto(){
|
||||||
this.limitedPhoto = true;
|
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){
|
getMsgFormSon(data){
|
||||||
this.limitedPhoto = data;
|
// this.limitedPhoto = data;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@
|
||||||
<el-form
|
<el-form
|
||||||
ref="Form"
|
ref="Form"
|
||||||
:model="material"
|
:model="material"
|
||||||
label-width="80px"
|
label-width="100px"
|
||||||
label-position="right"
|
label-position="right"
|
||||||
:rules="rule1"
|
:rules="rule1"
|
||||||
>
|
>
|
||||||
|
|
@ -131,41 +131,42 @@
|
||||||
<el-form-item label="物料编号" prop="number">
|
<el-form-item label="物料编号" prop="number">
|
||||||
<el-input v-model="material.number" placeholder="物料编号"/>
|
<el-input v-model="material.number" placeholder="物料编号"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="规格型号" prop="specification">
|
<el-form-item label="规格型号">
|
||||||
<el-input v-model="material.specification" placeholder="规格型号"/>
|
<el-input v-model="material.specification" placeholder="规格型号"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="计量单位" prop="unit">
|
<el-form-item label="计量单位">
|
||||||
<el-select style="width: 100%" v-model="material.unit" placeholder="请选择">
|
<el-select style="width: 100%" v-model="material.unit" placeholder="请选择">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in unitoptions"
|
v-for="item in unitoptions"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="item.label"
|
:label="item.label"
|
||||||
:value="item.value">
|
:value="item.value"
|
||||||
|
>
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="物料类别" prop="type">
|
<el-form-item label="物料类别">
|
||||||
|
<el-select style="width: 100%" v-model="material.type" placeholder="请选择物料类别">
|
||||||
<el-select style="width: 100%" v-model="material.type" placeholder="请选择">
|
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in options"
|
v-for="item in options"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="item.label"
|
:label="item.label"
|
||||||
:value="item.value">
|
:value="item.value"
|
||||||
|
>
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</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-input v-model="material.piece_count" placeholder="单片玻璃数量"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<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 label="排序" prop="sort_str">
|
</el-form-item>
|
||||||
<el-input v-model="material.sort_str" placeholder="排序"/>
|
<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-item>
|
||||||
|
|
||||||
</el-form>
|
</el-form>
|
||||||
<div style="text-align: right">
|
<div style="text-align: right">
|
||||||
<el-button type="danger" @click="dialogVisible = false">取消</el-button>
|
<el-button type="danger" @click="dialogVisible = false">取消</el-button>
|
||||||
|
|
@ -189,8 +190,14 @@
|
||||||
import {genTree} from "@/utils";
|
import {genTree} from "@/utils";
|
||||||
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
|
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
|
||||||
const defaultmaterial = {
|
const defaultmaterial = {
|
||||||
name: "",
|
name: null,
|
||||||
number: "",
|
number: null,
|
||||||
|
specification: null,
|
||||||
|
unit: null,
|
||||||
|
type: null,
|
||||||
|
piece_count: null,
|
||||||
|
sort_str: null,
|
||||||
|
count_safe: 0,
|
||||||
processes: [],
|
processes: [],
|
||||||
};
|
};
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -270,19 +277,13 @@
|
||||||
created() {
|
created() {
|
||||||
this.getList();
|
this.getList();
|
||||||
this.getProcessList();
|
this.getProcessList();
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
checkPermission,
|
checkPermission,
|
||||||
|
|
||||||
//物料详情
|
//物料详情
|
||||||
handledetail(scope)
|
handledetail(scope){
|
||||||
{
|
|
||||||
this.$router.push({name: "MaterialDetail", params: { id: scope.row.id,type: scope.row.type }, })
|
this.$router.push({name: "MaterialDetail", params: { id: scope.row.id,type: scope.row.type }, })
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
//选项卡切换
|
//选项卡切换
|
||||||
handleClick(tab) {
|
handleClick(tab) {
|
||||||
this.listLoading = true;
|
this.listLoading = true;
|
||||||
|
|
@ -311,10 +312,8 @@
|
||||||
},
|
},
|
||||||
//绑定工序
|
//绑定工序
|
||||||
handlebind(scope) {
|
handlebind(scope) {
|
||||||
|
|
||||||
this.$router.push({name: "MaterialDO", params: {id: scope.row.id},})
|
this.$router.push({name: "MaterialDO", params: {id: scope.row.id},})
|
||||||
}
|
},
|
||||||
,
|
|
||||||
handleFilter() {
|
handleFilter() {
|
||||||
this.listQuery.page = 1;
|
this.listQuery.page = 1;
|
||||||
this.getList();
|
this.getList();
|
||||||
|
|
@ -324,7 +323,7 @@
|
||||||
this.listQuery = {
|
this.listQuery = {
|
||||||
page: 1,
|
page: 1,
|
||||||
page_size: 20,
|
page_size: 20,
|
||||||
}
|
};
|
||||||
this.getList();
|
this.getList();
|
||||||
},
|
},
|
||||||
handleCreate() {
|
handleCreate() {
|
||||||
|
|
@ -335,7 +334,6 @@
|
||||||
this.$refs["Form"].clearValidate();
|
this.$refs["Form"].clearValidate();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
handleEdit(scope) {
|
handleEdit(scope) {
|
||||||
this.material = Object.assign({}, scope.row); // copy obj
|
this.material = Object.assign({}, scope.row); // copy obj
|
||||||
this.dialogType = "edit";
|
this.dialogType = "edit";
|
||||||
|
|
@ -359,7 +357,6 @@
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async confirm(form) {
|
async confirm(form) {
|
||||||
this.$refs[form].validate((valid) => {
|
this.$refs[form].validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,8 @@
|
||||||
<div style="text-align: right">
|
<div style="text-align: right">
|
||||||
<el-button type="danger" @click="dialogVisible = false">取消
|
<el-button type="danger" @click="dialogVisible = false">取消
|
||||||
</el-button>
|
</el-button>
|
||||||
<!--<el-button type="primary" @click="recordformconfirm('Forms')">确认</el-button>-->
|
<el-button type="primary" @click="recordformconfirm('Forms')">确认</el-button>
|
||||||
<el-button type="primary" @click="recordformcon">管理员授权</el-button>
|
<!--<el-button type="primary" @click="recordformcon">管理员授权</el-button>-->
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!--表格展示-->
|
<!--表格展示-->
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,15 @@
|
||||||
<el-card style="margin-top: 2px">
|
<el-card style="margin-top: 2px">
|
||||||
<el-descriptions title="任务详情" :column="4" border style="margin-bottom: 20px">
|
<el-descriptions title="任务详情" :column="4" border style="margin-bottom: 20px">
|
||||||
<el-descriptions-item label="任务编号">{{productionplan.number}}</el-descriptions-item>
|
<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_.name}}
|
||||||
<el-descriptions-item label="规格型号" v-if="productionplan.product_">{{productionplan.product_.specification}}</el-descriptions-item>
|
</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="生产数量">{{productionplan.count}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="生产状态">{{state_[productionplan.state]}}</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.start_date}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="计划完工时间">{{productionplan.end_date}}</el-descriptions-item>
|
<el-descriptions-item label="计划完工时间">{{productionplan.end_date}}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
|
|
||||||
|
|
||||||
<el-table
|
<el-table
|
||||||
:data="wproduct"
|
:data="wproduct"
|
||||||
border
|
border
|
||||||
|
|
@ -20,34 +20,30 @@
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
height="500"
|
height="500"
|
||||||
>
|
>
|
||||||
|
|
||||||
<el-table-column type="index" label="序号" width="50"/>
|
<el-table-column type="index" label="序号" width="50"/>
|
||||||
|
|
||||||
|
|
||||||
<el-table-column label="玻璃编号/产品编号">
|
<el-table-column label="玻璃编号/产品编号">
|
||||||
<template slot-scope="scope">{{ scope.row.number }}</template>
|
<template slot-scope="scope">{{ scope.row.number }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column label="所在子工序">
|
<el-table-column label="所在子工序">
|
||||||
<template slot-scope="scope" >{{
|
<template slot-scope="scope">
|
||||||
scope.row.step_.name
|
{{scope.row.step_.name}}
|
||||||
}}</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="产品状态">
|
<el-table-column label="产品状态">
|
||||||
<template slot-scope="scope">{{
|
<template slot-scope="scope">{{
|
||||||
actstate_[scope.row.act_state]
|
actstate_[scope.row.act_state]
|
||||||
}}</template>
|
}}
|
||||||
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="生产状态">
|
<el-table-column label="生产状态">
|
||||||
<template slot-scope="scope" >{{
|
<template slot-scope="scope">
|
||||||
scope.row.step_.name
|
{{scope.row.step_.name}}
|
||||||
}}</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="最后检验结果">
|
<el-table-column label="最后检验结果">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-span v-if="scope.row.last_test_result==false">不合格</el-span>
|
<span v-if="scope.row.last_test_result==false">不合格</span>
|
||||||
<el-span v-if="scope.row.last_test_result==true">合格</el-span>
|
<span v-if="scope.row.last_test_result==true">合格</span>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="生产记录">
|
<el-table-column label="生产记录">
|
||||||
|
|
@ -61,19 +57,15 @@
|
||||||
width="220px"
|
width="220px"
|
||||||
>
|
>
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
|
|
||||||
<el-link
|
<el-link
|
||||||
v-if="checkPermission(['material_delete'])"
|
v-if="checkPermission(['material_delete'])"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="handleoption(scope)"
|
@click="handleoption(scope)"
|
||||||
>生成流程卡</el-link
|
>生成流程卡
|
||||||
>
|
</el-link>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<!--检验记录-->
|
<!--检验记录-->
|
||||||
<el-dialog title="检验记录" :visible.sync="limitedCheckRecord">
|
<el-dialog title="检验记录" :visible.sync="limitedCheckRecord">
|
||||||
<el-table
|
<el-table
|
||||||
|
|
@ -85,66 +77,49 @@
|
||||||
<el-table-column label="表单名称">
|
<el-table-column label="表单名称">
|
||||||
<template slot-scope="scope">{{ scope.row.form_.name }}</template>
|
<template slot-scope="scope">{{ scope.row.form_.name }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
|
||||||
<el-table-column align="center" label="操作">
|
<el-table-column align="center" label="操作">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
|
|
||||||
<el-link
|
<el-link
|
||||||
|
|
||||||
@click="handleRecordDetail(scope)"
|
@click="handleRecordDetail(scope)"
|
||||||
>查看
|
>查看
|
||||||
</el-link>
|
</el-link>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<div slot="footer" class="dialog-footer">
|
<div slot="footer" class="dialog-footer">
|
||||||
<el-button @click="dialogFormVisible = false">取 消</el-button>
|
<el-button @click="dialogFormVisible = false">取 消</el-button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!--非检查表显示-->
|
<!--非检查表显示-->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
width="60%"
|
|
||||||
:title="formName"
|
:title="formName"
|
||||||
:visible.sync="recordVisible"
|
:visible.sync="recordVisible"
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
@close="recordCancel"
|
|
||||||
>
|
>
|
||||||
<customForm
|
<el-row>
|
||||||
v-if="recordVisible"
|
<el-col v-for="item in fieldList" :key="item.id" :span="12">
|
||||||
:results="fieldList"
|
<div class="items" v-if="item.field_type!=='draw'">
|
||||||
:hasPicture="hasPicture"
|
<span class="itemLabel">{{item.field_name}}:</span>
|
||||||
:formID="recordform"
|
<span>{{item.field_value}}</span>
|
||||||
:wproduct="wproduct"
|
</div>
|
||||||
:recordId="recordId"
|
</el-col>
|
||||||
:isDisabled="isDisabled"
|
<el-col v-for="item in fieldList" :key="item.id" :span="24">
|
||||||
@recordSubmit="recordSubmit"
|
<div class="items" v-if="item.field_type==='draw'" style="height: 400px">
|
||||||
@recordSave="recordSave"
|
<span class="itemLabel">{{item.field_name}}:</span>
|
||||||
@recordCancel="recordCancel"
|
<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-dialog>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import {getProductionplan} from "@/api/pm";
|
||||||
import { getProductionplan,getsubproductionplanList } from "@/api/pm";
|
import {getwproductList, getrecordList,recordInit} from "@/api/wpm";
|
||||||
import { getwproductList,getrecordList} from "@/api/wpm";
|
|
||||||
import checkPermission from "@/utils/permission";
|
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};
|
const defaultrecordform = {enabled: false};
|
||||||
export default {
|
export default {
|
||||||
components: { Pagination,customForm },
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
productionplan: {
|
productionplan: {
|
||||||
|
|
@ -164,7 +139,8 @@ export default {
|
||||||
30: '已接受',
|
30: '已接受',
|
||||||
40: '生产中',
|
40: '生产中',
|
||||||
50: '已完成',
|
50: '已完成',
|
||||||
60:'军检完成'},
|
60: '军检完成'
|
||||||
|
},
|
||||||
actstate_: {
|
actstate_: {
|
||||||
6: "待复检",
|
6: "待复检",
|
||||||
10: "操作进行中",
|
10: "操作进行中",
|
||||||
|
|
@ -180,23 +156,17 @@ export default {
|
||||||
process_json: null,
|
process_json: null,
|
||||||
productionplanID: null,
|
productionplanID: null,
|
||||||
dialogVisibleForm: false,
|
dialogVisibleForm: false,
|
||||||
tableForm:{
|
|
||||||
name:'',
|
|
||||||
},
|
|
||||||
|
|
||||||
recordform: defaultrecordform,
|
recordform: defaultrecordform,
|
||||||
dialogType: "new",
|
dialogType: "new",
|
||||||
dialogVisible: false,
|
dialogVisible: false,
|
||||||
dialogType1: "new",
|
dialogType1: "new",
|
||||||
dialogVisible1: false,
|
dialogVisible1: false,
|
||||||
tableForm: defaultrecordform,
|
|
||||||
checkForm: {
|
checkForm: {
|
||||||
hhh: '',
|
hhh: '',
|
||||||
},
|
},
|
||||||
|
|
||||||
recordVisible: false,
|
recordVisible: false,
|
||||||
customfieldList: [],
|
customfieldList: [],
|
||||||
recordform: null,
|
|
||||||
recordId: null,
|
recordId: null,
|
||||||
fifo_detail: "",
|
fifo_detail: "",
|
||||||
formName: "项目检查表",
|
formName: "项目检查表",
|
||||||
|
|
@ -229,32 +199,24 @@ export default {
|
||||||
obj = response.data.process_json[item];
|
obj = response.data.process_json[item];
|
||||||
process_json.push(obj)
|
process_json.push(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.process_json = process_json;
|
this.process_json = process_json;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
getwproductList() {
|
||||||
getwproductList()
|
|
||||||
{
|
|
||||||
getwproductList({production_plan: this.id, page: 0,}).then((response) => {
|
getwproductList({production_plan: this.id, page: 0,}).then((response) => {
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
this.wproduct = response.data;
|
this.wproduct = response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//查看该玻璃检验记录表
|
//查看该玻璃检验记录表
|
||||||
handleoption(scope) {
|
handleoption(scope) {
|
||||||
|
|
||||||
this.$router.push({name: "processcard", params: {id: scope.row.id},})
|
this.$router.push({name: "processcard", params: {id: scope.row.id},})
|
||||||
|
|
||||||
},
|
},
|
||||||
//查看生产记录
|
//查看生产记录
|
||||||
select(scope)
|
select(scope) {
|
||||||
{
|
|
||||||
this.limitedCheckRecord = true;
|
this.limitedCheckRecord = true;
|
||||||
getrecordList({wproduct: scope.row.id, page: 0}).then(res => {
|
getrecordList({wproduct: scope.row.id, page: 0}).then(res => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
|
|
@ -262,52 +224,32 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
//点击记录里的查看
|
//点击记录里的查看
|
||||||
handleRecordDetail(scope) {
|
handleRecordDetail(scope) {
|
||||||
let that = this;
|
let that = this;
|
||||||
that.recordVisible = false;
|
that.fieldList = [];
|
||||||
that.recordId = scope.row.id;
|
recordInit(scope.row.id).then((res) => {
|
||||||
that.recordform = scope.row.form;
|
if (res.code >= 200) {
|
||||||
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;
|
that.recordVisible = true;
|
||||||
});
|
that.formName = res.data.form_.name;
|
||||||
});
|
that.fieldList = res.data.record_data;
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</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"
|
:title="formName"
|
||||||
:visible.sync="recordVisible"
|
:visible.sync="recordVisible"
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
@close="recordCancel"
|
|
||||||
>
|
>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col v-for="item in fieldList" :key="item.id" :span="12">
|
<el-col v-for="item in fieldList" :key="item.id" :span="12">
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,16 @@
|
||||||
<el-card style="margin-top: 2px">
|
<el-card style="margin-top: 2px">
|
||||||
<el-descriptions title="任务详情" :column="5" border style="margin-bottom: 20px">
|
<el-descriptions title="任务详情" :column="5" border style="margin-bottom: 20px">
|
||||||
<el-descriptions-item label="任务编号">{{productionplan.number}}</el-descriptions-item>
|
<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_.name}}
|
||||||
<el-descriptions-item label="规格型号" v-if="productionplan.product_">{{productionplan.product_.specification}}</el-descriptions-item>
|
</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="生产状态">{{state_[productionplan.state]}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="不合格品数量">{{productionplan.count_notok}}</el-descriptions-item>
|
<el-descriptions-item label="不合格品数量">{{productionplan.count_notok}}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<el-card style="margin-bottom: 20px">
|
<el-card style="margin-bottom: 20px">
|
||||||
<div slot="header" class="clearfix">
|
<div slot="header" class="clearfix">
|
||||||
<span>下料清单</span>
|
<span>下料清单</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<el-table
|
<el-table
|
||||||
:data="cut"
|
:data="cut"
|
||||||
|
|
@ -20,10 +21,7 @@
|
||||||
stripe
|
stripe
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
>
|
>
|
||||||
|
|
||||||
<el-table-column label="序号" type="index" width="50"/>
|
<el-table-column label="序号" type="index" width="50"/>
|
||||||
|
|
||||||
|
|
||||||
<el-table-column label="玻璃批次">
|
<el-table-column label="玻璃批次">
|
||||||
<template slot-scope="scope">{{ scope.row.from_batch }}</template>
|
<template slot-scope="scope">{{ scope.row.from_batch }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
@ -62,9 +60,6 @@
|
||||||
<el-table-column label="检验员">
|
<el-table-column label="检验员">
|
||||||
<template slot-scope="scope">{{ scope.row.create_by_.username }}</template>
|
<template slot-scope="scope">{{ scope.row.create_by_.username }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-tabs v-model="activeName" type="card">
|
<el-tabs v-model="activeName" type="card">
|
||||||
|
|
@ -77,51 +72,41 @@
|
||||||
stripe
|
stripe
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
height="500"
|
height="500"
|
||||||
:load="load"
|
|
||||||
:tree-props="{children: 'children'}">
|
:tree-props="{children: 'children'}">
|
||||||
|
|
||||||
<el-table-column type="index" width="50"/>
|
<el-table-column type="index" width="50"/>
|
||||||
|
|
||||||
|
|
||||||
<el-table-column label="玻璃编号">
|
<el-table-column label="玻璃编号">
|
||||||
<template slot-scope="scope">{{ scope.row.number }}</template>
|
<template slot-scope="scope">{{ scope.row.number }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column label="所在子工序">
|
<el-table-column label="所在子工序">
|
||||||
<template slot-scope="scope" >{{
|
<template slot-scope="scope">
|
||||||
scope.row.step_.name
|
{{scope.row.step_.name}}
|
||||||
}}</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="玻璃状态">
|
<el-table-column label="玻璃状态">
|
||||||
<template slot-scope="scope" >{{
|
<template slot-scope="scope">
|
||||||
scope.row.material_.name
|
{{scope.row.material_.name}}
|
||||||
}}</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="状态">
|
<el-table-column label="状态">
|
||||||
<template slot-scope="scope" >{{
|
<template slot-scope="scope">
|
||||||
actstate_[scope.row.act_state]
|
{{actstate_[scope.row.act_state]}}
|
||||||
}}</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column
|
<el-table-column
|
||||||
align="center"
|
align="center"
|
||||||
label="过程记录"
|
label="过程记录"
|
||||||
width="220px"
|
width="220px"
|
||||||
>
|
>
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
|
|
||||||
<el-link
|
<el-link
|
||||||
v-if="checkPermission(['material_delete'])"
|
v-if="checkPermission(['material_delete'])"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="handleoption(scope)"
|
@click="handleoption(scope)"
|
||||||
>查看</el-link
|
>查看
|
||||||
>
|
</el-link>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="工序" name="2">
|
<el-tab-pane label="工序" name="2">
|
||||||
<el-table
|
<el-table
|
||||||
|
|
@ -132,51 +117,37 @@
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
height="500"
|
height="500"
|
||||||
>
|
>
|
||||||
|
|
||||||
<el-table-column type="index" width="50"/>
|
<el-table-column type="index" width="50"/>
|
||||||
|
|
||||||
|
|
||||||
<el-table-column label="工序名称">
|
<el-table-column label="工序名称">
|
||||||
<template slot-scope="scope">{{ scope.row.process_name }}</template>
|
<template slot-scope="scope">{{ scope.row.process_name }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="玻璃数量">
|
<el-table-column label="玻璃数量">
|
||||||
<template slot-scope="scope">{{ scope.row.count_real }}</template>
|
<template slot-scope="scope">{{ scope.row.count_real }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column label="合格数量">
|
<el-table-column label="合格数量">
|
||||||
<template slot-scope="scope">{{ scope.row.count_ok }}</template>
|
<template slot-scope="scope">{{ scope.row.count_ok }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column label="不合格数量">
|
<el-table-column label="不合格数量">
|
||||||
<template slot-scope="scope">{{ scope.row.count_notok }}</template>
|
<template slot-scope="scope">{{ scope.row.count_notok }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
|
||||||
<el-table-column
|
<el-table-column
|
||||||
align="center"
|
align="center"
|
||||||
label="过程记录"
|
label="过程记录"
|
||||||
width="220px"
|
width="220px"
|
||||||
>
|
>
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
|
|
||||||
<el-link
|
<el-link
|
||||||
v-if="checkPermission(['material_delete'])"
|
v-if="checkPermission(['material_delete'])"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="handleprocess(scope)"
|
@click="handleprocess(scope)"
|
||||||
>查看</el-link
|
>查看
|
||||||
>
|
</el-link>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -209,7 +180,8 @@ export default {
|
||||||
30: '已接受',
|
30: '已接受',
|
||||||
40: '生产中',
|
40: '生产中',
|
||||||
50: '已完成',
|
50: '已完成',
|
||||||
60:'军检完成'},
|
60: '军检完成'
|
||||||
|
},
|
||||||
actstate_: {
|
actstate_: {
|
||||||
6: "待复检",
|
6: "待复检",
|
||||||
10: "操作进行中",
|
10: "操作进行中",
|
||||||
|
|
@ -268,8 +240,7 @@ export default {
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
getwproductList()
|
getwproductList() {
|
||||||
{
|
|
||||||
getwproductList({production_plan: this.id, page: 0,}).then((response) => {
|
getwproductList({production_plan: this.id, page: 0,}).then((response) => {
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
this.wproduct = response.data;
|
this.wproduct = response.data;
|
||||||
|
|
@ -278,8 +249,7 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//下料清单
|
//下料清单
|
||||||
gecutList()
|
gecutList() {
|
||||||
{
|
|
||||||
getcutList({production_plan: this.id, page: 0}).then((response) => {
|
getcutList({production_plan: this.id, page: 0}).then((response) => {
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
this.cut = response.data;
|
this.cut = response.data;
|
||||||
|
|
@ -291,7 +261,15 @@ export default {
|
||||||
//查看该玻璃检验记录表
|
//查看该玻璃检验记录表
|
||||||
handleoption(scope) {
|
handleoption(scope) {
|
||||||
|
|
||||||
this.$router.push({name: "taskrecordfrom", params: { id: scope.row.id ,productionplanid:this.id ,number:scope.row.number,process:scope.row.step_.name}, })
|
this.$router.push({
|
||||||
|
name: "taskrecordfrom",
|
||||||
|
params: {
|
||||||
|
id: scope.row.id,
|
||||||
|
productionplanid: this.id,
|
||||||
|
number: scope.row.number,
|
||||||
|
process: scope.row.step_.name
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
},
|
},
|
||||||
//查看工序对应的玻璃
|
//查看工序对应的玻璃
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@
|
||||||
:title="formName"
|
:title="formName"
|
||||||
:visible.sync="recordVisible"
|
:visible.sync="recordVisible"
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
@close="recordCancel"
|
|
||||||
>
|
>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col v-for="item in fieldList" :key="item.id" :span="12">
|
<el-col v-for="item in fieldList" :key="item.id" :span="12">
|
||||||
|
|
|
||||||
|
|
@ -102,10 +102,12 @@
|
||||||
<p>创建时间 :{{watchedCreateTime}}</p>
|
<p>创建时间 :{{watchedCreateTime}}</p>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<svg height=800 id="mySvg" style="width: 100%;">
|
<div style="width: 90%;margin: auto;">
|
||||||
|
<svg height=1000 id="mySvg" style="width:100%!important;">
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<el-dialog
|
<el-dialog
|
||||||
:visible.sync="dialogVisible"
|
:visible.sync="dialogVisible"
|
||||||
:title="dialogType === 'edit' ? '编辑工作流' : '新增工作流'">
|
:title="dialogType === 'edit' ? '编辑工作流' : '新增工作流'">
|
||||||
|
|
@ -481,7 +483,7 @@ export default {
|
||||||
margin: 10vh auto 0;
|
margin: 10vh auto 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
max-height: 75vh;
|
max-height: 80vh;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
.svgItem{
|
.svgItem{
|
||||||
|
|
|
||||||
|
|
@ -241,7 +241,7 @@
|
||||||
</el-step>
|
</el-step>
|
||||||
</el-steps>
|
</el-steps>
|
||||||
<div style="width: 90%;margin: auto;">
|
<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>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -613,6 +613,27 @@
|
||||||
<el-button type="primary" @click="retrialSubmit">确 定</el-button>
|
<el-button type="primary" @click="retrialSubmit">确 定</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -755,6 +776,7 @@
|
||||||
dialogFormVisible: false,
|
dialogFormVisible: false,
|
||||||
dialogFormVisibles: false,
|
dialogFormVisibles: false,
|
||||||
limitedCheckRecord: false,
|
limitedCheckRecord: false,
|
||||||
|
recordFinishedVisible: false,
|
||||||
testrecord: {},
|
testrecord: {},
|
||||||
retrialItem: {},//复检对象
|
retrialItem: {},//复检对象
|
||||||
retrialResponse: {},//复检对象
|
retrialResponse: {},//复检对象
|
||||||
|
|
@ -862,13 +884,10 @@
|
||||||
handleRetrial(scope) {
|
handleRetrial(scope) {
|
||||||
let that = this;
|
let that = this;
|
||||||
this.retrialItem = Object.assign({}, scope.row);
|
this.retrialItem = Object.assign({}, scope.row);
|
||||||
console.log(this.retrialItem);
|
|
||||||
getRetrial(scope.row.id).then(res => {
|
getRetrial(scope.row.id).then(res => {
|
||||||
that.retrialResponse = res.data;
|
that.retrialResponse = res.data;
|
||||||
getWorkflowInit(res.data.workflow).then((response) => {
|
getWorkflowInit(res.data.workflow).then((response) => {
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
debugger;
|
|
||||||
console.log(response.data);
|
|
||||||
that.retrialForm.transition = response.data.transitions[0].id;
|
that.retrialForm.transition = response.data.transitions[0].id;
|
||||||
that.customfieldList = response.data.field_list;
|
that.customfieldList = response.data.field_list;
|
||||||
for (let i = 0; i < that.customfieldList.length; i++) {
|
for (let i = 0; i < that.customfieldList.length; i++) {
|
||||||
|
|
@ -926,10 +945,8 @@
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
this.wproductList3 = response.data;
|
this.wproductList3 = response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
//半成品批量入库
|
//半成品批量入库
|
||||||
handleCreate() {
|
handleCreate() {
|
||||||
this.dialogFormVisibles = true;
|
this.dialogFormVisibles = true;
|
||||||
|
|
@ -941,7 +958,6 @@
|
||||||
_this.mutipID = [];
|
_this.mutipID = [];
|
||||||
this.$refs.multipleTable.selection.forEach((item) => {
|
this.$refs.multipleTable.selection.forEach((item) => {
|
||||||
_this.mutipID.push(item.id);
|
_this.mutipID.push(item.id);
|
||||||
|
|
||||||
});
|
});
|
||||||
createputins({
|
createputins({
|
||||||
warehouse: this.form.warehouse,
|
warehouse: this.form.warehouse,
|
||||||
|
|
@ -1093,44 +1109,13 @@
|
||||||
handleRecordDetail(scope) {
|
handleRecordDetail(scope) {
|
||||||
let that = this;
|
let that = this;
|
||||||
that.fieldList = [];
|
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) => {
|
getTestRecordItem(scope.row.id).then((res) => {
|
||||||
let arr = [];
|
if (res.code >= 200) {
|
||||||
let fieldList = res.data.record_data;
|
that.recordFinishedVisible = true;
|
||||||
for (let i = 0; i < that.fieldList.length; i++) {
|
that.formName = res.data.form_.name;
|
||||||
let obj = that.fieldList[i];
|
that.fieldList = res.data.record_data;
|
||||||
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;
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
//半产品复检
|
//半产品复检
|
||||||
handleReview() {
|
handleReview() {
|
||||||
|
|
@ -1331,3 +1316,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</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 rest_framework import urlpatterns
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from rest_framework.routers import DefaultRouter
|
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 = [
|
urlpatterns = [
|
||||||
path('cleandata/', CleanDataView.as_view()),
|
path('cleandata/', CleanDataView.as_view()),
|
||||||
path('update_cutting/', UpdateCuttingView.as_view()),
|
path('update_cutting/', UpdateCuttingView.as_view()),
|
||||||
path('update_last_result/', UpdateLastTestResult.as_view()),
|
path('update_last_result/', UpdateLastTestResult.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 rest_framework.response import Response
|
||||||
from apps.inm.models import FIFO, FIFOItem, Inventory, MaterialBatch
|
from apps.inm.models import FIFO, FIFOItem, Inventory, MaterialBatch
|
||||||
from apps.mtm.models import Material
|
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.sam.models import Order
|
||||||
from apps.wf.models import Ticket
|
from apps.wf.models import Ticket
|
||||||
from apps.wpm.models import Operation, OperationMaterial, WProduct, WproductFlow
|
from apps.wpm.models import Operation, OperationMaterial, WProduct, WproductFlow
|
||||||
|
|
@ -80,3 +80,14 @@ class UpdateFIFOItem(APIView):
|
||||||
i.is_testok = None
|
i.is_testok = None
|
||||||
i.save()
|
i.save()
|
||||||
return Response()
|
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
|
from django.db.models.base import Model
|
||||||
import django.utils.timezone as timezone
|
import django.utils.timezone as timezone
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File
|
from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File
|
||||||
#from apps.mtm.models import Process
|
|
||||||
from utils.model import SoftModel, BaseModel
|
from utils.model import SoftModel, BaseModel
|
||||||
from simple_history.models import HistoricalRecords
|
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 = (
|
state_choices = (
|
||||||
(0, '完好'),
|
(EQUIP_STATE_OK, '完好'),
|
||||||
(1, '限用'),
|
(EQUIP_STATE_LIMIT, '限用'),
|
||||||
(2, '在修'),
|
(EQUIP_STATE_FIX, '在修'),
|
||||||
(3, '禁用')
|
(EQUIP_STATE_DISABLE, '禁用')
|
||||||
)
|
|
||||||
statedm_choices = (
|
|
||||||
(0, '合格'),
|
|
||||||
(1, '准用'),
|
|
||||||
(2, '限用'),
|
|
||||||
(3, '禁用'),
|
|
||||||
(4, '停用'),
|
|
||||||
(5, '封存')
|
|
||||||
)
|
|
||||||
|
|
||||||
|
)
|
||||||
|
state2_choices = (
|
||||||
|
(EQUIP_STATE_OK, '合格'),
|
||||||
|
(EQUIP_STATE_DISABLE, '禁用')
|
||||||
|
|
||||||
|
)
|
||||||
|
EQUIP_TYPE_PRO = 1
|
||||||
|
EQUIP_TYPE_TEST = 2
|
||||||
type_choices = (
|
type_choices = (
|
||||||
(1, '生产设备'),
|
(1, '生产设备'),
|
||||||
(2, '检验工具')
|
(2, '检验工具')
|
||||||
|
|
@ -54,20 +56,21 @@ class Equipment(CommonBModel):
|
||||||
factory = models.CharField('生产厂', max_length=50, null=True, blank=True)
|
factory = models.CharField('生产厂', max_length=50, null=True, blank=True)
|
||||||
production_date = models.DateField('生产日期', null=True, blank=True)
|
production_date = models.DateField('生产日期', null=True, blank=True)
|
||||||
buy_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)
|
parameter = models.TextField('技术参数', null=True, blank=True)
|
||||||
place = models.CharField('存放位置', max_length=50, null=True, blank=True)
|
place = models.CharField('存放位置', max_length=50, null=True, blank=True)
|
||||||
count = models.IntegerField('数量', default=0)
|
count = models.IntegerField('数量', default=0)
|
||||||
keeper = models.ForeignKey(User, verbose_name='保管人', on_delete=models.CASCADE, null=True, blank=True)
|
keeper = models.ForeignKey(User, verbose_name='保管人', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
description = models.CharField('描述', max_length=200, blank=True, null=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)#监视,测量设备
|
mgmtype = models.IntegerField('管理类别', choices=mgmtype_choices, default=1)
|
||||||
way = models.IntegerField('校准或检定方式', choices=way_choices, default=1)#监视,测量设备
|
way = models.IntegerField('校准或检定方式', choices=way_choices, default=1)
|
||||||
standard = models.CharField('溯源标准或依据', max_length=200, blank=True, null=True)#监视,测量设备
|
standard = models.CharField('溯源标准或依据', max_length=200, blank=True, null=True)
|
||||||
cycle = models.IntegerField('校准或检定周期', default=0)#监视,测量设备
|
cycle = models.IntegerField('校准或检定周期(月)', null=True, blank=True)
|
||||||
usetype = models.IntegerField('使用类别', choices=usetype_choices, default=1)#监视,测量设备
|
usetype = models.IntegerField('使用类别', choices=usetype_choices, default=1)
|
||||||
statedm = models.IntegerField('设备状态', choices=statedm_choices, default=0)#监视,测量设备
|
|
||||||
|
|
||||||
|
check_date = models.DateField('最近校准检查日期', blank=True, null=True)
|
||||||
|
next_check_date = models.DateField('预计下次校准检查日期',blank=True, null=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '设备信息'
|
verbose_name = '设备信息'
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
|
|
@ -75,8 +78,10 @@ class Equipment(CommonBModel):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.number + '-' + self.name
|
return self.number + '-' + self.name
|
||||||
|
|
||||||
class Equipmentrecord(CommonBModel):
|
class ECheckRecord(CommonADModel):
|
||||||
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)
|
"""
|
||||||
|
equipment = models.ForeignKey(Equipment, verbose_name='校准检定设备', on_delete=models.CASCADE)
|
||||||
|
check_date = models.DateField('校准检查日期')
|
||||||
description = models.CharField('描述', max_length=200, blank=True, null=True)
|
description = models.CharField('描述', max_length=200, blank=True, null=True)
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
from apps.mtm.models import Step
|
from apps.mtm.models import Step
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.serializers import ModelSerializer
|
from rest_framework.serializers import ModelSerializer
|
||||||
|
from rest_framework import exceptions
|
||||||
from .models import Equipment,Equipmentrecord
|
from .models import Equipment, ECheckRecord
|
||||||
from apps.system.serializers import OrganizationSimpleSerializer, UserSimpleSerializer
|
from apps.system.serializers import OrganizationSimpleSerializer, UserSimpleSerializer
|
||||||
|
|
||||||
|
|
||||||
class EquipmentSerializer(ModelSerializer):
|
class EquipmentListSerializer(ModelSerializer):
|
||||||
belong_dept_ = OrganizationSimpleSerializer(source='belong_dept', read_only=True)
|
|
||||||
keeper_ = UserSimpleSerializer(source='keeper', read_only=True)
|
keeper_ = UserSimpleSerializer(source='keeper', read_only=True)
|
||||||
step_ = serializers.SerializerMethodField()
|
step_ = serializers.SerializerMethodField()
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -17,24 +16,35 @@ class EquipmentSerializer(ModelSerializer):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def setup_eager_loading(queryset):
|
def setup_eager_loading(queryset):
|
||||||
""" Perform necessary eager loading of data. """
|
""" Perform necessary eager loading of data. """
|
||||||
queryset = queryset.select_related('belong_dept','keeper')
|
queryset = queryset.select_related('keeper')
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def get_step_(self, obj):
|
def get_step_(self, obj):
|
||||||
return Step.objects.filter(equipments=obj).values('id', 'name', 'number')
|
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 EquipmentSimpleSerializer(ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Equipment
|
model = Equipment
|
||||||
fields = ['id', 'number', 'name', 'state']
|
fields = ['id', 'number', 'name', 'state', 'model']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class EquipmentrecordSerializer(ModelSerializer):
|
class ECheckRecordListSerializer(ModelSerializer):
|
||||||
equipment_ = EquipmentSerializer(source='equipment', read_only=True)
|
equipment_ = EquipmentSimpleSerializer(source='equipment', read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Equipmentrecord
|
model = ECheckRecord
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -43,6 +53,11 @@ class EquipmentrecordSerializer(ModelSerializer):
|
||||||
queryset = queryset.select_related('equipment')
|
queryset = queryset.select_related('equipment')
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
class EChcekRecordCreateSerializer(ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = ECheckRecord
|
||||||
|
fields = ['equipment', 'check_date', 'description']
|
||||||
|
|
||||||
class DaqCreateSerializer(serializers.Serializer):
|
class DaqCreateSerializer(serializers.Serializer):
|
||||||
number = serializers.CharField()
|
number = serializers.CharField()
|
||||||
file = serializers.FileField()
|
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 django.db.models import base
|
||||||
from rest_framework import urlpatterns
|
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 django.urls import path, include
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
router.register('equipment', EquipmentViewSet, basename='equipment')
|
router.register('equipment', EquipmentViewSet, basename='equipment')
|
||||||
router.register('equipmentrecord', EquipmentrecordViewSet, basename='equipmentrecord')
|
router.register('echeck_record', EChcekRecordViewSet, basename='echeck_record')
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('daq/', DaqView.as_view()),
|
path('daq/', DaqView.as_view()),
|
||||||
path('', include(router.urls)),
|
path('', include(router.urls)),
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,20 @@
|
||||||
|
from datetime import timedelta
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from numpy import delete
|
||||||
from rest_framework.exceptions import APIException
|
from rest_framework.exceptions import APIException
|
||||||
from rest_framework.views import APIView
|
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 import serializers, status
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from apps.em.models import Equipment,Equipmentrecord
|
from apps.em.models import Equipment, ECheckRecord
|
||||||
from apps.em.serializers import DaqCreateSerializer, EquipmentSerializer,EquipmentrecordSerializer
|
from apps.em.serializers import DaqCreateSerializer, EChcekRecordCreateSerializer, ECheckRecordListSerializer, \
|
||||||
|
EquipmentCreateUpdateSerializer, EquipmentListSerializer
|
||||||
|
from apps.em.services import EmService
|
||||||
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||||
|
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
class EquipmentViewSet(CreateUpdateModelAMixin, OptimizationMixin, ModelViewSet):
|
class EquipmentViewSet(CreateUpdateModelAMixin, OptimizationMixin, ModelViewSet):
|
||||||
|
|
@ -18,48 +24,48 @@ class EquipmentViewSet(CreateUpdateModelAMixin, OptimizationMixin, ModelViewSet)
|
||||||
perms_map = {'get': '*', 'post': 'equipment_create',
|
perms_map = {'get': '*', 'post': 'equipment_create',
|
||||||
'put': 'equipment_update', 'delete': 'equipment_delete'}
|
'put': 'equipment_update', 'delete': 'equipment_delete'}
|
||||||
queryset = Equipment.objects.all()
|
queryset = Equipment.objects.all()
|
||||||
serializer_class = EquipmentSerializer
|
serializer_class = EquipmentListSerializer
|
||||||
search_fields = ['number', 'name','description']
|
search_fields = ['number', 'name','description']
|
||||||
filterset_fields = ['belong_dept', 'keeper', 'type']
|
filterset_fields = ['keeper', 'type']
|
||||||
ordering_fields = ['create_time']
|
ordering_fields = ['create_time']
|
||||||
ordering = ['-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.
|
# Create your views here.
|
||||||
class EquipmentrecordViewSet(CreateUpdateModelAMixin, OptimizationMixin, ModelViewSet):
|
class EChcekRecordViewSet(CreateUpdateModelAMixin, OptimizationMixin,
|
||||||
|
CreateModelMixin, RetrieveModelMixin, ListModelMixin, DestroyModelMixin, GenericViewSet):
|
||||||
"""
|
"""
|
||||||
设备校准-增删改查
|
设备校准-增删改查
|
||||||
"""
|
"""
|
||||||
perms_map = {'get': '*', 'post': 'equipmentrecord_create',
|
perms_map = {'get': '*', 'post': 'echeckrecord_create', 'delete': 'echeckrecord_delete'}
|
||||||
'put': 'equipmentrecord_update', 'delete': 'equipmentrecord_delete'}
|
queryset = ECheckRecord.objects.all()
|
||||||
queryset = Equipmentrecord.objects.all()
|
serializer_class = ECheckRecordListSerializer
|
||||||
serializer_class = EquipmentrecordSerializer
|
|
||||||
filterset_fields = ['equipment']
|
filterset_fields = ['equipment']
|
||||||
ordering_fields = ['create_time']
|
ordering = ['-id']
|
||||||
ordering = ['-create_time']
|
|
||||||
|
|
||||||
|
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):
|
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 = self.get_serializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
serializer.save()
|
instance = serializer.save(create_by=request.user)
|
||||||
return Response(status=status.HTTP_200_OK)
|
EmService.update_check_date(equip=instance.equipment)
|
||||||
def update(self, request, *args, **kwargs):
|
return Response()
|
||||||
data = request.data
|
|
||||||
if data.get('equipment', None):
|
@transaction.atomic
|
||||||
equipment = Equipment.objects.get(pk=data['equipment'])
|
def destroy(self, request, *args, **kwargs):
|
||||||
equipment.statedm = data['state']
|
instance = self.get_object()
|
||||||
equipment.save()
|
instance.delete()
|
||||||
id = self.get_object()
|
EmService.update_check_date(equip=instance.equipment)
|
||||||
serializer = self.get_serializer(id, data=data)
|
return Response()
|
||||||
serializer.is_valid(raise_exception=True)
|
|
||||||
serializer.save()
|
|
||||||
return Response(status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
import os
|
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):
|
def __str__(self):
|
||||||
return self.name
|
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 apps.system.models import User
|
||||||
from rest_framework.serializers import ModelSerializer
|
from rest_framework.serializers import ModelSerializer
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from .models import Employee
|
from .models import ClockRecord, Employee
|
||||||
from apps.system.serializers import UserListSerializer, UserSimpleSerializer
|
from apps.system.serializers import UserListSerializer, UserSimpleSerializer
|
||||||
from django.db.models.query import Prefetch
|
from django.db.models.query import Prefetch
|
||||||
|
|
||||||
|
|
@ -23,3 +23,13 @@ class EmployeeSerializer(ModelSerializer):
|
||||||
|
|
||||||
class FaceLoginSerializer(serializers.Serializer):
|
class FaceLoginSerializer(serializers.Serializer):
|
||||||
base64 = serializers.CharField()
|
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 django.db.models import base
|
||||||
from rest_framework import urlpatterns
|
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 django.urls import path, include
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
router.register('employee', EmployeeViewSet, basename='employee')
|
router.register('employee', EmployeeViewSet, basename='employee')
|
||||||
|
router.register('clock_record', ClockRecordViewSet, basename='clock_record')
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('facelogin/', FaceLogin.as_view()),
|
path('facelogin/', FaceLogin.as_view()),
|
||||||
path('', include(router.urls)),
|
path('', include(router.urls)),
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from django.utils import timezone
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.viewsets import ModelViewSet, GenericViewSet
|
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.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||||
from apps.hrm.models import Employee
|
from apps.hrm.models import ClockRecord, Employee
|
||||||
from apps.hrm.serializers import EmployeeSerializer, FaceLoginSerializer
|
from apps.hrm.serializers import ClockRecordListSerializer, EmployeeSerializer, FaceClockCreateSerializer, FaceLoginSerializer
|
||||||
import face_recognition
|
import face_recognition
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
|
@ -12,8 +15,10 @@ import logging
|
||||||
from rest_framework.generics import CreateAPIView
|
from rest_framework.generics import CreateAPIView
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework_simplejwt.tokens import RefreshToken
|
from rest_framework_simplejwt.tokens import RefreshToken
|
||||||
|
from rest_framework import exceptions
|
||||||
from apps.system.models import User
|
from apps.system.models import User
|
||||||
|
from apps.system.serializers import UserSimpleSerializer
|
||||||
|
from rest_framework.permissions import AllowAny
|
||||||
logger = logging.getLogger('log')
|
logger = logging.getLogger('log')
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -50,9 +55,56 @@ class EmployeeViewSet(CreateUpdateModelAMixin, OptimizationMixin, UpdateModelMix
|
||||||
except:
|
except:
|
||||||
logger.error('人脸识别出错')
|
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 base64
|
||||||
import os
|
|
||||||
|
|
||||||
def tran64(s):
|
def tran64(s):
|
||||||
missing_padding = len(s) % 4
|
missing_padding = len(s) % 4
|
||||||
|
|
@ -70,41 +122,13 @@ class FaceLogin(CreateAPIView):
|
||||||
"""
|
"""
|
||||||
人脸识别登录
|
人脸识别登录
|
||||||
"""
|
"""
|
||||||
# serializer = FaceLoginSerializer(data=request.data)
|
base64_data = base64.urlsafe_b64decode(tran64(request.data.get('base64').replace(' ', '+')))
|
||||||
# serializer.is_valid(raise_exception=True)
|
user, msg = HRMService.face_compare_from_base64(base64_data)
|
||||||
filename = str(uuid.uuid4())
|
if user:
|
||||||
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)
|
refresh = RefreshToken.for_user(user)
|
||||||
return Response({
|
return Response({
|
||||||
'refresh': str(refresh),
|
'refresh': str(refresh),
|
||||||
'access': str(refresh.access_token),
|
'access': str(refresh.access_token),
|
||||||
'username':user.username
|
'username':user.username
|
||||||
})
|
})
|
||||||
return Response('未找到对应用户', status=status.HTTP_400_BAD_REQUEST)
|
return Response(msg, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
@ -21,7 +21,10 @@ class MbFilterSet(filters.FilterSet):
|
||||||
|
|
||||||
class IProductFilterSet(filters.FilterSet):
|
class IProductFilterSet(filters.FilterSet):
|
||||||
order = filters.NumberFilter(field_name="wproduct__subproduction_plan__production_plan__order")
|
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:
|
class Meta:
|
||||||
model = IProduct
|
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
|
from django.db import transaction
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WareHouseSerializer(serializers.ModelSerializer):
|
class WareHouseSerializer(serializers.ModelSerializer):
|
||||||
create_by_ = UserSimpleSerializer('create_by', read_only=True)
|
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)
|
name = models.CharField('命名', max_length=50, null=True, blank=True)
|
||||||
product = models.ForeignKey(Material, verbose_name='产品', on_delete=models.CASCADE)
|
product = models.ForeignKey(Material, verbose_name='产品', on_delete=models.CASCADE)
|
||||||
process = models.ForeignKey(Process, verbose_name='隶属大工序', on_delete=models.CASCADE, related_name='subproduction_process')
|
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)
|
sort = models.IntegerField('排序号', default=1)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,11 @@ class SubProductionSerializer(serializers.ModelSerializer):
|
||||||
model = SubProduction
|
model = SubProduction
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
class SubProductionCreateUpdateSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = SubProduction
|
||||||
|
fields = ['name', 'product', 'process', 'need_combtest', 'sort']
|
||||||
|
|
||||||
class OtherMaterialSerializer(serializers.ModelSerializer):
|
class OtherMaterialSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SubprodctionMaterial
|
model = SubprodctionMaterial
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelM
|
||||||
from apps.mtm.filters import MaterialFilterSet, TechDocFilterset
|
from apps.mtm.filters import MaterialFilterSet, TechDocFilterset
|
||||||
|
|
||||||
from apps.mtm.models import Material, Process, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc, UsedStep, SubProduction
|
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 apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
@ -80,6 +80,10 @@ class SubProductionViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
||||||
search_fields = ['name']
|
search_fields = ['name']
|
||||||
serializer_class = SubProductionSerializer
|
serializer_class = SubProductionSerializer
|
||||||
ordering = ['sort']
|
ordering = ['sort']
|
||||||
|
def get_serializer_class(self):
|
||||||
|
if self.action in ['create', 'update']:
|
||||||
|
return SubProductionCreateUpdateSerializer
|
||||||
|
return super().get_serializer_class()
|
||||||
|
|
||||||
class InputMaterialViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
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 import serializers
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from apps.em.models import Equipment
|
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.models import MaterialBatch
|
||||||
from apps.inm.serializers import MaterialBatchSerializer
|
from apps.inm.serializers import MaterialBatchSerializer
|
||||||
from apps.mtm.models import Step, SubProduction, SubprodctionMaterial, UsedStep
|
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)
|
subproductions = SubProduction.objects.filter(product__id__in=rdata_l, is_deleted=False)
|
||||||
steps = Step.objects.filter(usedstep__is_deleted=False, usedstep__subproduction__in=subproductions)
|
steps = Step.objects.filter(usedstep__is_deleted=False, usedstep__subproduction__in=subproductions)
|
||||||
equips = Equipment.objects.filter(step_equips__in=steps, is_deleted=False).distinct()
|
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)
|
return Response(serializer.data)
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ class ContractCreateUpdateSerializer(serializers.ModelSerializer):
|
||||||
class OrderCreateUpdateSerializer(serializers.ModelSerializer):
|
class OrderCreateUpdateSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Order
|
model = Order
|
||||||
fields = ['number', 'customer', 'contract', 'product', 'count', 'delivery_date']
|
fields = ['customer', 'contract', 'product', 'count', 'delivery_date']
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
validated_data['number'] = 'DD' + ranstr(7)
|
validated_data['number'] = 'DD' + ranstr(7)
|
||||||
|
|
@ -60,6 +60,7 @@ class OrderSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class OrderSimpleSerializer(serializers.ModelSerializer):
|
class OrderSimpleSerializer(serializers.ModelSerializer):
|
||||||
contract_ = ContractSimpleSerializer(source='contract', read_only=True)
|
contract_ = ContractSimpleSerializer(source='contract', read_only=True)
|
||||||
|
customer_ = CustomerSimpleSerializer(source='customer', read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Order
|
model = Order
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
|
||||||
|
|
@ -20,3 +20,7 @@ class PlanGanttSerializer(serializers.ModelSerializer):
|
||||||
def get_children(self, obj):
|
def get_children(self, obj):
|
||||||
subplans = SubProductionPlan.objects.filter(production_plan=obj).order_by('process__number')
|
subplans = SubProductionPlan.objects.filter(production_plan=obj).order_by('process__number')
|
||||||
return SubplanGanttSerializer(instance=subplans, many=True).data
|
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 django.urls import path, include
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
from apps.srm.views import GanttPlan
|
from apps.srm.views import GanttPlan, ProcessYieldView
|
||||||
|
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('gantt/plan/', GanttPlan.as_view()),
|
path('gantt/plan/', GanttPlan.as_view()),
|
||||||
|
path('process/yield/', ProcessYieldView.as_view()),
|
||||||
path('', include(router.urls)),
|
path('', include(router.urls)),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,14 @@
|
||||||
|
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from rest_framework import serializers
|
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 rest_framework.response import Response
|
||||||
|
from apps.mtm.models import Process, Step
|
||||||
from apps.pm.models import ProductionPlan, SubProductionPlan
|
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.
|
# Create your views here.
|
||||||
|
|
||||||
class GanttPlan(ListAPIView):
|
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')
|
queryset = ProductionPlan.objects.filter(is_deleted=False, is_planed=True).prefetch_related('subplan_plan', 'subplan_plan__process')
|
||||||
ordering = ['-id']
|
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(
|
superior = models.ForeignKey(
|
||||||
'self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='上级主管')
|
'self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='上级主管')
|
||||||
roles = models.ManyToManyField(Role, blank=True, verbose_name='角色')
|
roles = models.ManyToManyField(Role, blank=True, verbose_name='角色')
|
||||||
|
is_atwork = models.BooleanField('当前在岗', default=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '用户信息'
|
verbose_name = '用户信息'
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,9 @@ class UserListSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = ['id', 'name', 'phone', 'email', 'position',
|
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
|
@staticmethod
|
||||||
def setup_eager_loading(queryset):
|
def setup_eager_loading(queryset):
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,12 @@ class WProductFilterSet(filters.FilterSet):
|
||||||
def filter_tag(self, queryset, name, value):
|
def filter_tag(self, queryset, name, value):
|
||||||
if value == 'no_scrap':
|
if value == 'no_scrap':
|
||||||
queryset = queryset.exclude(act_state=WProduct.WPR_ACT_STATE_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
|
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='当前工单',
|
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
|
||||||
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_ticket')
|
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_mtested = models.BooleanField('是否军检', default=False)
|
||||||
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
|
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
|
||||||
remark_mtest = models.TextField('军检备注', 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)
|
on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
|
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
|
||||||
on_delete=models.SET_NULL, null=True, blank=True)
|
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_mtested = models.BooleanField('是否军检', default=False)
|
||||||
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
|
is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
|
||||||
remark_mtest = models.TextField('军检备注', 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')
|
Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='oe_operation')
|
||||||
equip = models.ForeignKey(Equipment, verbose_name='生产设备',
|
equip = models.ForeignKey(Equipment, verbose_name='生产设备',
|
||||||
on_delete=models.CASCADE, related_name='oe_equip')
|
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)
|
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.system.serializers import UserSimpleSerializer
|
||||||
from apps.wpm.models import Operation, OperationEquip, OperationMaterial, OperationWproduct, Pick, WMaterial, WProduct, OperationRecord, OperationRecordItem, WprouctTicket
|
from apps.wpm.models import Operation, OperationEquip, OperationMaterial, OperationWproduct, Pick, WMaterial, WProduct, OperationRecord, OperationRecordItem, WprouctTicket
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
from apps.sam.models import Order
|
||||||
|
|
||||||
class PickHalfSerializer(serializers.Serializer):
|
class PickHalfSerializer(serializers.Serializer):
|
||||||
id = serializers.PrimaryKeyRelatedField(queryset=SubProductionProgress.objects.all(), label='子计划进度ID')
|
id = serializers.PrimaryKeyRelatedField(queryset=SubProductionProgress.objects.all(), label='子计划进度ID')
|
||||||
|
|
@ -155,6 +156,7 @@ class WProductListSerializer(serializers.ModelSerializer):
|
||||||
subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
|
subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
|
||||||
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
|
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
|
||||||
children = serializers.SerializerMethodField()
|
children = serializers.SerializerMethodField()
|
||||||
|
to_order_ = OrderSimpleSerializer(source='to_order', read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = WProduct
|
model = WProduct
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
@ -561,3 +563,7 @@ class WproductMtestSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = WProduct
|
model = WProduct
|
||||||
fields = ['remark_mtest', 'is_mtestok']
|
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: # 成品检验
|
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
|
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
|
wproduct.act_state = WProduct.WPR_ACT_STATE_TOCOMBTEST
|
||||||
else:
|
else:
|
||||||
wproduct.act_state = WProduct.WPR_ACT_STATE_OK
|
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)
|
objs = WproductFlow.objects.filter(subproduction_plan=sp, is_lastlog=True)
|
||||||
count_ok = objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_INM,
|
count_ok = objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_INM,
|
||||||
WProduct.WPR_ACT_STATE_OK, WProduct.WPR_ACT_STATE_SELLED]).count()
|
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,
|
count_real = objs.exclude(act_state__in=[WProduct.WPR_ACT_STATE_TORETEST,
|
||||||
WProduct.WPR_ACT_STATE_DOWAIT, WProduct.WPR_ACT_STATE_DOING]).count()
|
WProduct.WPR_ACT_STATE_DOWAIT, WProduct.WPR_ACT_STATE_DOING]).count()
|
||||||
ins = SubProductionProgress.objects.filter(subproduction_plan=sp,
|
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.wf.models import Workflow
|
||||||
from apps.wpm.filters import CuttingFilterSet, OperationRecordFilterSet, WMaterialFilterSet, WProductFilterSet
|
from apps.wpm.filters import CuttingFilterSet, OperationRecordFilterSet, WMaterialFilterSet, WProductFilterSet
|
||||||
from apps.wpm.models import OperationEquip, OperationWproduct, Pick, PickWproduct, WMaterial, WProduct, Operation, \
|
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, \
|
from apps.wpm.serializers import CuttingListSerializer, OperationEquipListSerializer, OperationEquipUpdateSerializer, \
|
||||||
OperationMaterialCreate1ListSerailizer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2ListSerailizer, \
|
OperationMaterialCreate1ListSerailizer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2ListSerailizer, \
|
||||||
|
|
@ -27,7 +27,7 @@ from apps.wpm.serializers import CuttingListSerializer, OperationEquipListSerial
|
||||||
PickSerializer, OperationInitSerializer, OperationSubmitSerializer, ScrapSerializer, WMaterialListSerializer, \
|
PickSerializer, OperationInitSerializer, OperationSubmitSerializer, ScrapSerializer, WMaterialListSerializer, \
|
||||||
WProductCardSerializer, WProductDetailSerializer, WProductListSerializer, \
|
WProductCardSerializer, WProductDetailSerializer, WProductListSerializer, \
|
||||||
WpmTestFormInitSerializer, WproductMtestSerializer, WproductPutInSerializer, \
|
WpmTestFormInitSerializer, WproductMtestSerializer, WproductPutInSerializer, \
|
||||||
WproductPutInsSerializer, WproductTicketListSerializer
|
WproductPutInsSerializer, WproductTicketListSerializer, WproductToOrderSerializer
|
||||||
|
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
@ -148,7 +148,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
||||||
"""
|
"""
|
||||||
perms_map = {'*': '*'}
|
perms_map = {'*': '*'}
|
||||||
queryset = WProduct.objects.select_related('step', 'material',
|
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
|
serializer_class = WProductListSerializer
|
||||||
filterset_class = WProductFilterSet
|
filterset_class = WProductFilterSet
|
||||||
search_fields = ['number']
|
search_fields = ['number']
|
||||||
|
|
@ -441,6 +441,30 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
||||||
ret.append([str(index + 1), item['step_name'], item['actions']])
|
ret.append([str(index + 1), item['step_name'], item['actions']])
|
||||||
return Response(ret)
|
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):
|
class WproductTicketViewSet(ListModelMixin, GenericViewSet):
|
||||||
"""
|
"""
|
||||||
|
|
@ -559,6 +583,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
|
||||||
ope = OperationEquip()
|
ope = OperationEquip()
|
||||||
ope.operation = op
|
ope.operation = op
|
||||||
ope.equip = i
|
ope.equip = i
|
||||||
|
ope.state = i.state
|
||||||
ope.save()
|
ope.save()
|
||||||
# 查询所需的工具工装
|
# 查询所需的工具工装
|
||||||
for i in SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL,
|
for i in SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL,
|
||||||
|
|
|
||||||
|
|
@ -47,17 +47,20 @@ class FitJSONRenderer(JSONRenderer):
|
||||||
"""
|
"""
|
||||||
response_body = BaseResponse()
|
response_body = BaseResponse()
|
||||||
response = renderer_context.get("response")
|
response = renderer_context.get("response")
|
||||||
response_body.code = response.status_code
|
status_code = response.status_code # Http状态异常码
|
||||||
if response_body.code >= 400: # 响应异常
|
if status_code >= 400: # 如果http响应异常
|
||||||
|
if isinstance(data, dict) and 'code' in data: # 如果自定义了异常码
|
||||||
|
response_body = data
|
||||||
|
else:
|
||||||
response_body.data = data # data里是详细异常信息
|
response_body.data = data # data里是详细异常信息
|
||||||
prefix = ""
|
prefix = ""
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
prefix = list(data.keys())[0]
|
prefix = list(data.keys())[0]
|
||||||
data = data[prefix]
|
data = data[prefix]
|
||||||
if isinstance(data, list):
|
elif isinstance(data, list):
|
||||||
data = data[0]
|
data = data[0]
|
||||||
response_body.msg = prefix + ":" + str(data) # 取一部分放入msg,方便前端alert
|
response_body.msg = prefix + ":" + str(data) # 取一部分放入msg,方便前端alert
|
||||||
else:
|
else:
|
||||||
response_body.data = data
|
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)
|
return super(FitJSONRenderer, self).render(response_body.dict, accepted_media_type, renderer_context)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue