Browse Source

完成客户预测新需求

pull/23/head
xuxiaoming 3 years ago
parent
commit
5fd5c71e33
16 changed files with 351 additions and 73 deletions
  1. BIN
      src/assets/icon/independent_demand.png
  2. BIN
      src/assets/icon/mps_button_icon.png
  3. BIN
      src/assets/icon/net_production.png
  4. BIN
      src/assets/icon/outsourcing_demand.png
  5. BIN
      src/assets/icon/refresh.png
  6. BIN
      src/assets/icon/reload.png
  7. BIN
      src/assets/icon/save.png
  8. +15
    -2
      src/server/productionPlanning/customerForecastDemandReview.js
  9. +1
    -3
      src/views/productionPlanning/customerForecastDemandReview/demandPlanning/articleChar/index.vue
  10. +166
    -9
      src/views/productionPlanning/customerForecastDemandReview/demandPlanning/articleDemand/index.vue
  11. +50
    -10
      src/views/productionPlanning/customerForecastDemandReview/demandPlanning/index.vue
  12. +14
    -4
      src/views/productionPlanning/customerForecastDemandReview/index.vue
  13. +5
    -1
      src/views/productionPlanning/customerForecastDemandReview/resourceContent/evaluation/char.vue
  14. +69
    -28
      src/views/productionPlanning/customerForecastDemandReview/resourceContent/evaluation/index.vue
  15. +29
    -15
      src/views/productionPlanning/customerForecastDemandReview/resourceContent/index.vue
  16. +2
    -1
      src/views/productionPlanning/customerForecastDemandReview/resourceContent/resourceLoad/index.vue

BIN
src/assets/icon/independent_demand.png View File

Before After
Width: 24  |  Height: 24  |  Size: 1.5 KiB

BIN
src/assets/icon/mps_button_icon.png View File

Before After
Width: 18  |  Height: 18  |  Size: 360 B

BIN
src/assets/icon/net_production.png View File

Before After
Width: 24  |  Height: 24  |  Size: 1.5 KiB

BIN
src/assets/icon/outsourcing_demand.png View File

Before After
Width: 24  |  Height: 24  |  Size: 1.4 KiB

BIN
src/assets/icon/refresh.png View File

Before After
Width: 24  |  Height: 24  |  Size: 1.7 KiB

BIN
src/assets/icon/reload.png View File

Before After
Width: 24  |  Height: 24  |  Size: 1.6 KiB

BIN
src/assets/icon/save.png View File

Before After
Width: 24  |  Height: 24  |  Size: 1.2 KiB

+ 15
- 2
src/server/productionPlanning/customerForecastDemandReview.js View File

@ -1,5 +1,6 @@
import {
get,
post,
postForm
} from "../api";
// 工厂列表
@ -26,12 +27,24 @@ export const getMpsPlan = (params) => postForm("/admin/ap/balance/getmpsplan", p
// 计划调整
export const changeMpsPlan = (params) => postForm("/admin/ap/balance/mpsplan", params);
// 保存计划
export const saveMpsPlan = (params) => postForm("/admin/ap/balance/savempsplan", params);
// 获得资源负载
export const getResourceCapacity = (params) => get("/admin/ap/balance/getresourcecapacityanddemand",params)
// 获得版本列表
export const getVersionList = () => get("/admin/ap/custdemandverhead/selectversionlist")
// 获得客户需求
export const getCustomerDemand = (params) => get('/admin/ap/custdemandverhead/selectversioncustomerlist', params);
// 数据重载
export const reloadData = () => get('/admin/ap/balance/refreshdata')
// 客户主要资源查询
export const searchResource = (artId) => get(`/admin/ap/articleresource/search/${artId}`);
// 保存客户需求
export const saveDemand = (data) => post('/admin/ap/balance/savecustomerarticledemand', data)
export const getCustomerDemand = (params) => get('/admin/ap/custdemandverhead/selectversioncustomerlist', params);

+ 1
- 3
src/views/productionPlanning/customerForecastDemandReview/demandPlanning/articleChar/index.vue View File

@ -153,9 +153,8 @@ export default {
</script>
<style lang="less" scoped>
.wrapper{
// margin-top: 10px;
display:flex;
.wrapper-button{
@ -166,7 +165,6 @@ export default {
display:flex;
flex-direction:column;
justify-content:center;
.toggle-char-btn{
display:block;
height:56px;


+ 166
- 9
src/views/productionPlanning/customerForecastDemandReview/demandPlanning/articleDemand/index.vue View File

@ -1,8 +1,46 @@
<template>
<div class="articleDemand-wrapper" :style="{width: Width}">
<div class="content-table-wrap" ref="topTableRef">
<div class="tool_list">
<div class="search">
<div style="padding:8px">
模式选择
</div>
<div>
<el-select
v-model="mode"
placeholder="请选择"
>
<el-option
v-for="item in mpsPlanMode"
:key="item['Stdef-StdefTyp']"
:label="item['Stdef-Bez']"
:value="item['Stdef-StdefTyp']"
/>
</el-select>
</div>
<div style="margin-left:15px">
<el-button
class="add-button-style mps-button"
@click="calcHandle"
><div class="icon-upload"></div> MPS计算</el-button>
</div>
</div>
<div class="button_list">
<img class="image_button" :src="outsourcingDemandImageUrl" @click="editField = '外购需求'" title="外购需求">
<div class="button_split"></div>
<img class="image_button" :src="independentDemandImageUrl" @click="editField = '独立需求'" title="独立需求">
<div class="button_split"></div>
<img class="image_button" :src="netProductionImageUrl" @click="editField = '净生产量'" title="净生产量">
<div class="button_split"></div>
<img class="image_button" :src="refreshImageUrl" title="刷新数据">
<div class="button_split"></div>
<img class="image_button" :src="saveImageUrl" @click="saveDemandData" title="保存">
<div class="button_split"></div>
<img class="image_button" :src="reloadImageUrl" @click="reloadData" title="数据重载">
</div>
</div>
<el-table
class="articleDemand-table"
:data="TableData"
:height="Height"
@ -12,13 +50,28 @@
:key="index"
:prop="item.prop"
:label="item.label" >
<template #default="scope">
<el-input size='mini' v-if="scope.row['-'] == editField && index != 0 "
v-model.number="scope.row[item.prop]"></el-input>
<span v-else>{{scope.row[item.prop]}}</span>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script>
import independentDemandImageUrl from '@/assets/icon/independent_demand.png'
import outsourcingDemandImageUrl from '@/assets/icon/outsourcing_demand.png'
import netProductionImageUrl from '@/assets/icon/net_production.png'
import reloadImageUrl from '@/assets/icon/reload.png'
import refreshImageUrl from '@/assets/icon/refresh.png'
import saveImageUrl from '@/assets/icon/save.png'
import { reloadData } from "@/server/productionPlanning/customerForecastDemandReview";
export default {
props: {
Width:{
@ -37,6 +90,27 @@ export default {
type:String
}
},
data(){
return {
mode:"",
tableHeight:0,
mpsPlanMode:[],
independentDemandImageUrl:independentDemandImageUrl,
outsourcingDemandImageUrl:outsourcingDemandImageUrl,
netProductionImageUrl:netProductionImageUrl,
reloadImageUrl:reloadImageUrl,
refreshImageUrl:refreshImageUrl,
saveImageUrl:saveImageUrl,
editField:"",
}
},
created () {
this.getStanderOne({ statid: `MpsPlanMode` }).then(({ data = [] }) => {
this.mpsPlanMode = data;
});
},
mounted() {
this.$nextTick(()=>{
this.tableHeight = this.calculationTableHeight(
@ -46,24 +120,107 @@ export default {
this.$emit('calculateTableHeight', this.tableHeight)
})
},
data(){
return {
tableHeight:0
}
methods: {
reloadData(){
reloadData().then( ({msg}) => {
this.$message({
type:"success",
message: msg
})
}).catch(()=> {
this.$message({
type:"error",
message: "访问失败"
})
})
},
saveDemandData(){
if(!this.editField) {
this.$message({
type:"error",
message: "请先编辑数据"
})
return false
}
this.TableData.forEach(item => {
if(item['-'] == this.editField){
this.$emit("saveDemandData",item)
this.editField = ""
}
})
},
calcHandle() {
},
},
}
</script>
<style lang="less" scoped>
.articleDemand-wrapper {
height: 100%;
background-color: #F1F1F1;
.content-table-wrap {
width: 100%;
height: 100%;
.tool_list{
width: 100%;
height: 30px;
padding-top:12px;
display: flex;
justify-content: space-between;
.search{
width: 500px;
display: flex;
.mps-button{
width: 98px;
height: 32px;
background: linear-gradient(180deg, #3C8F87 0%, #28A89E 43%, #24645E 100%);
box-shadow: 1px 1px 1px 0px #FFFFFF;
border-radius: 2px;
border: 1px solid #073A35;
line-height: 20px;
.icon-upload{
width: 18px;
height: 18px;
background: url("../../../../../assets/icon/mps_button_icon.png");
float: left;
margin-left: 5px;
}
}
}
.button_list {
width: 220px;
height: 32px;
display: flex;
align-items: center;
.image_button {
margin: 2px 5px;
width: 24px;
height: 24px;
box-shadow: 2px 2px 0px 0px #DADADA;
border: 1px solid #FFFFFF;
}
.image_button:hover {
background: #DFDFDF;
box-shadow: 2px 2px 0px 0px #FFFFFF;
border-radius: 1px;
border: 1px solid #DADADA;
}
.button_split {
width: 1px;
height: 30px;
background: #DFDFDF;
box-shadow: 1px 0px 0px 0px #FFFFFF;
border-radius: 1px;
}
}
}
.articleDemand-table {
margin-top: 10px;
width: 100%;
}
}
.articleDemand-table {
margin-top: 10px;
width: 100%;
}
}
</style>

+ 50
- 10
src/views/productionPlanning/customerForecastDemandReview/demandPlanning/index.vue View File

@ -12,21 +12,23 @@
:Headers="headers"
:Height="tableHeight+'px'"
:TableData="tableData"
@saveDemandData="saveDemandData"
@calculateTableHeight="calculateTableHeight"
/>
<ArticleChar
:Width="charWidth"
:Height="tableHeight+'px'"
:Height="charTableHeight+'px'"
@toggleChar="toggleChar"
:XAxis="XAxis"
:YAxis="YAxis"
/>
</el-tab-pane>
</el-tabs>
</ContentContainer>
</template>
<script>
import { getCustomerArticleDemand } from "@/server/productionPlanning/customerForecastDemandReview";
import { getCustomerArticleDemand,saveDemand } from "@/server/productionPlanning/customerForecastDemandReview";
//
import ArticleDemand from "./articleDemand";
//
@ -65,24 +67,56 @@ export default {
// Y
YAxis: [],
showChar: true,
mode:"",
tableHeight: 0,
charTableHeight:0,
activeName: "demandPlanning",
demandWidth: "calc(100% - 15px)",
charWidth: "15px",
mpsPlanMode:[],
apiData:[],
keyLabelMap:{
"外购需求":"AP_ArticleDemand-OutSourcingQty",
"独立需求":"AP_ArticleDemand-IndependentDemandQty",
"净生产量":"AP_ArticleDemand-NetDemandQty",
}
};
},
created() {},
created() {
this.getStanderOne({ statid: `MpsPlanMode` }).then(({ data = [] }) => {
this.mpsPlanMode = data;
});
},
methods: {
saveDemandData(data){
this.apiData.forEach(item => {
let key = "WK" + item['AP_ArticleDemand-DemandWeek']
item[this.keyLabelMap[data['-']]] = data[key]
})
saveDemand(this.apiData).then( ()=> {
this.$message({
type:"success",
message: "保存成功"
})
}).catch(() => {
this.$message({
type:"error",
message: "保存失败"
})
})
},
handlePublic(){
},
calculateTableHeight(data) {
this.tableHeight = (data -10)+"";
this.tableHeight = (data -40)+"";
this.charTableHeight = (data + 10)+"";
},
//
getDataList(customerId, artId) {
this.loading = true;
//
// customerId = 3;
// artId = "CAADQ00001A";
this.articleLoading = true;
getCustomerArticleDemand(customerId, artId)
.then(({ data = [] }) => {
@ -93,6 +127,7 @@ export default {
this.tableData = [];
this.headers = [];
if (data.length != 0) {
this.apiData = data
this.dealData(data);
} else {
this.$message({
@ -128,8 +163,7 @@ export default {
forecastDemandQty[key] = item["AP_ArticleDemand-ForecastDemandQty"];
orderQty[key] = item["AP_ArticleDemand-OrderQty"];
outSourcingQty[key] = item["AP_ArticleDemand-OutSourcingQty"];
independentDemandQty[key] =
item["AP_ArticleDemand-IndependentDemandQty"];
independentDemandQty[key] = item["AP_ArticleDemand-IndependentDemandQty"];
wipQty[key] = item["AP_ArticleDemand-WipQty"];
openingInventory[key] = item["AP_ArticleDemand-OpeningInventory"];
targetInventory[key] = item["AP_ArticleDemand-TargetInventory"];
@ -189,7 +223,12 @@ export default {
height: 100%;
overflow-y: auto;
overflow-x: hidden;
padding: 0;
padding: 0 !important;
.tool-list{
width: 100%;
height: 46px;
background: #F1F1F1;
}
.el-tabs {
.el-tabs__header {
margin: 0;
@ -201,6 +240,7 @@ export default {
.need_card {
display: flex;
}
}
}
</style>

+ 14
- 4
src/views/productionPlanning/customerForecastDemandReview/index.vue View File

@ -49,9 +49,9 @@
</div>
<!-- 右侧 资源负荷资源产能评估 -->
<div class="homepage-bottom-right-wrap">
<ResourceContent
:resourceId="resourceId"
:resourceType="resourceType"
<ResourceContent
:resourceId="resourceId"
:resourceType="resourceType"
@handleCancelResource="handleCancelResource"/>
</div>
</div>
@ -64,7 +64,12 @@ import DemandPlanning from "./demandPlanning";
//
import ResourceContent from "./resourceContent";
// api
import { getMainResourceList,getSecondaryResourceList,custartSearch} from "@/server/productionPlanning/customerForecastDemandReview";
import {
getMainResourceList,
getSecondaryResourceList,
custartSearch,
searchResource
} from "@/server/productionPlanning/customerForecastDemandReview";
export default {
components: {
@ -146,6 +151,10 @@ export default {
//
this.customerId = data.CustomerId;
this.artId = data.ArtId;
searchResource(this.artId).then(({data = []}) => {
this.resourceId = data['AP_ArticleResource-ResourceId']
this.resourceType = "1"
} )
}
},
//
@ -256,6 +265,7 @@ export default {
border: 2px solid #919191;
border-right: none;
.customer-tree-wrapper {
height: calc(100% - 50px);
.customer-tree-wrapper-tree {
padding-left: 10px;


+ 5
- 1
src/views/productionPlanning/customerForecastDemandReview/resourceContent/evaluation/char.vue View File

@ -17,7 +17,7 @@ export default {
},
Height:{
type:String,
default:() => "200px"
default:() => "90%"
},
Opacity:{
type:Number,
@ -26,6 +26,7 @@ export default {
},
data(){
return {
chart:{},
weeksList:[],
resourceWorkTime:[],
legendList:[],
@ -33,12 +34,14 @@ export default {
customeLegend:"资源每周产能上限"
}
},
mounted () {
this.clearData()
this.initData(this.DataList);
},
methods: {
clearData(){
this.chart = {}
this.weeksList = []
this.resourceWorkTime = []
this.legendList = []
@ -47,6 +50,7 @@ export default {
//
initData(DataList){
console.log('%cchar.vue line:50 DataList', 'color: #007acc;', DataList);
this.legendList.push(this.customeLegend)
DataList.forEach((item) => {
this.weeksList.push("WK" + item.DemandKey.slice(5));


+ 69
- 28
src/views/productionPlanning/customerForecastDemandReview/resourceContent/evaluation/index.vue View File

@ -1,31 +1,38 @@
<template>
<div class="wrapper" v-if="evaluationDataNew.length != 0">
<el-row>
<el-col :span="3">
<el-select
v-model="mode"
placeholder="请选择模式"
@change="handleModeChange"
>
<el-option
v-for="item in mpsPlanMode"
:key="item['Stdef-StdefTyp']"
:label="item['Stdef-Bez']"
:value="item['Stdef-StdefTyp']"
/>
</el-select>
</el-col>
<el-col :span="3">
<el-button
icon="el-icon-plus"
class="add-button-style"
@click="handlePublic"
>发布</el-button
>
</el-col>
</el-row>
<Char v-if="evaluationDataOld.length" :DataList="evaluationDataOld" Height="calc(50% - 20px)"></Char>
<Char v-if="evaluationDataNew.length" :DataList="evaluationDataNew" Height="calc(50% - 20px)" :Opacity=0.8></Char>
<div class="wrapper">
<div class="tool_list">
<div class="search">
<div style="padding:8px">
模式选择
</div>
<div>
<el-select
v-model="mode"
placeholder="请选择"
@change="handleModeChange"
>
<el-option
v-for="item in mpsPlanMode"
:key="item['Stdef-StdefTyp']"
:label="item['Stdef-Bez']"
:value="item['Stdef-StdefTyp']"
/>
</el-select>
</div>
<div style="margin-left:15px">
<el-button
class="add-button-style mps-button"
@click="handlePublic"
> 发布</el-button>
</div>
</div>
</div>
<div class="char_box" style="" v-loading='evaluationOldLoading'>
<Char v-if="evaluationDataOld.length" :DataList="evaluationDataOld" ></Char>
</div>
<div class="char_box" v-loading='evaluationNewLoading'>
<Char v-if="evaluationDataNew.length" :DataList="evaluationDataNew" :Opacity=0.8></Char>
</div>
</div>
</template>
<script>
@ -35,6 +42,14 @@ export default {
Char,
},
props: {
evaluationNewLoading: {
type: Boolean,
default: () => false
},
evaluationOldLoading: {
type: Boolean,
default: () => false
},
evaluationDataNew: {
type: Array,
default: [],
@ -76,6 +91,32 @@ export default {
width: 100%;
display: flex;
flex-direction: column;
justify-content: space-around;
justify-content: space-between;
.tool_list{
width: 100%;
height: 30px;
display: flex;
justify-content: space-between;
.search{
width: 500px;
display: flex;
.mps-button{
width: 98px;
height: 32px;
background: linear-gradient(180deg, #3C8F87 0%, #28A89E 43%, #24645E 100%);
box-shadow: 1px 1px 1px 0px #FFFFFF;
border-radius: 2px;
border: 1px solid #073A35;
line-height: 20px;
}
}
}
.char_box{
width:100%; height: calc( 50% - 20px)
}
}
</style>

+ 29
- 15
src/views/productionPlanning/customerForecastDemandReview/resourceContent/index.vue View File

@ -1,9 +1,10 @@
<template>
<ContentContainer class="homepage-beta-wrapper">
<el-tabs v-model="activeName" type="card" >
<el-tab-pane label="资源负荷" name="evaluation" v-loading="evaluationLoading">
<el-tab-pane label="资源负荷" name="evaluation">
<Evaluation
v-if="evaluationDataOld.length != 0"
:evaluationNewLoading="evaluationNewLoading"
:evaluationOldLoading="evaluationOldLoading"
:evaluationDataNew="evaluationDataNew"
:evaluationDataOld="evaluationDataOld"
@handleModeChange="handleModeChange"
@ -14,7 +15,7 @@
ref="resourceLoadComponents"
:resourceId="resourceId"
:resourceType="resourceType"
:Height="tableHeight+'px'"
:Height="tableHeight"
@calculateTableHeight="calculateTableHeight"
@handleCancelResource="handleCancelResource" />
</el-tab-pane>
@ -46,17 +47,18 @@ export default {
},
data() {
return {
tableHeight:0,
evaluationLoading:false,
tableHeight:"100%",
evaluationNewLoading:false,
evaluationOldLoading:false,
evaluationDataNew: [],
evaluationDataOld: [],
activeName: 'resourceLoad'
activeName: 'evaluation'
}
},
methods: {
calculateTableHeight(height) {
console.log('%cindex.vue line:58 height', 'color: #007acc;', height);
this.tableHeight = (height -10)+"";
this.tableHeight = (height -10)+"px";
},
//
handlePublic(param){
@ -72,12 +74,21 @@ export default {
handleModeChange(param){
// param.resouceid = "0102" //
param.data = JSON.stringify(param.data);
if(this.resourceType == 1) {
param.resouceid = this.resourceId
}
if(this.resourceType == 2) {
param.secondresourceid = param.resouceid
param.secondresourceid = this.resourceId
}
this.evaluationNewLoading = true
this.evaluationDataNew = []
changeMpsPlan(param).then( ({ data = []}) => {
this.evaluationNewLoading = false
this.evaluationDataNew = data['ArticleResourceMpsGroupLst']
} )
console.log('%cindex.vue line:87 this.evaluationDataNew', 'color: #007acc;', this.evaluationDataNew);
} ).catch(()=> {
this.evaluationNewLoading = false
})
},
// ID
handleCancelResource(){
@ -90,7 +101,8 @@ export default {
this.evaluationDataOld = this.evaluationDataNew = []
this.$refs.resourceLoadComponents.isCancelResource = false
if(this.activeName == "evaluation") {
this.evaluationLoading = true
this.evaluationNewLoading = true
this.evaluationOldLoading = true
let queryParam = {}
if(this.resourceType == 1) {
queryParam.resouceid = value
@ -99,7 +111,8 @@ export default {
}
getMpsPlan(queryParam).then( ({data = [] }) => {
this.evaluationDataOld = this.evaluationDataNew = data?data:[]
this.evaluationLoading = false
this.evaluationNewLoading = false
this.evaluationOldLoading = false
if(this.evaluationDataOld.length == 0) {
this.$message({
type:"error",
@ -107,7 +120,8 @@ export default {
})
}
}).catch(() => {
this.evaluationLoading = false
this.evaluationNewLoading = false
this.evaluationOldLoading = false
})
}
}
@ -119,14 +133,14 @@ export default {
height: 100%;
overflow-y: auto;
overflow-x: hidden;
padding: 0;
padding: 0 !important;
.el-tabs {
el-tabs__header{
margin:0;
}
.el-tabs__content {
overflow: inherit;
height: 100%;
height: calc(100% - 60px) !important;
}
}
}

+ 2
- 1
src/views/productionPlanning/customerForecastDemandReview/resourceContent/resourceLoad/index.vue View File

@ -121,7 +121,8 @@ export default {
default:""
},
Height:{
type:String
type:String,
default:"100%"
}
},
data(){


Loading…
Cancel
Save