plm前端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

1571 lines
53 KiB

<script>
import {
againQuoteDetail,
deleteQuoteDetail,
queryQuoteDetail,
saveQuoteDetail,
updateQuoteDetail,
updateQuoteDetailEntry,
updateQuoteDetailShowFlag
} from "../../../../api/quote/quoteDetail";
import {queryQuoteGroupDetail} from "../../../../api/quote/quoteGroupDetail";
import {getProjectPartList} from "../../../../api/project/project";
import QuoteDetailCost from "./primary/quoteDetailCost.vue";
import QuoteDetailTool from "./primary/quoteDetailTool.vue";
import QuoteDetailBom from "./primary/quoteDetailBom.vue";
import QuoteDetailRouting from "./primary/quoteDetailRouting.vue";
import QuoteDetailOtherCost from "./primary/quoteDetailOtherCost.vue";
import DictDataSelect from "../../sys/dict-data-select.vue";
import QuoteDetailTest from "./primary/quoteDetailTest.vue";
import QuoteDetailOther from "./primary/quoteDetailOther.vue";
export default {
name: "quoteDetail",
components: {
QuoteDetailOther,
QuoteDetailTest,
DictDataSelect,
QuoteDetailOtherCost,
QuoteDetailRouting,
QuoteDetailBom,
QuoteDetailTool,
QuoteDetailCost,
},
props:{
quote:{
type:Object,
required:true
},
height:{
type:[Number,String],
default:300
},
authFlag:{
type:Boolean,
default:false
},
quoteGroupDetail:{
type:Object,
},
saveAuth:{
type:Boolean,
default:true
},
isExport:{
type:Boolean,
default:false
},
},
data(){
return{
exportLoading: false,
quoteDetail:{
id:null,
partNo:'',
partDesc:'',
projectNo:'',
projectDesc:'',
buNo: '*',
qty:null,
quoteCount:1,
partCost:0,
adjustPartCost:0,
labourCost:0,
adjustLabourCost:0,
fabricateCost:0,
adjustFabricateCost:0,
toolCost:0,
adjustToolCost:0,
machineCost:0,
adjustMachineCost:0,
otherCost:0,
manageCost:0,
totalCost:0,
profitRate:0,
profitAmount:0,
totalPrice:0,
unitPrice:0,
taxRate:13,
taxTotalPrice:0,
taxUnitPrice:0,
quoteTotalCost:0,
quoteProfitRate:0,
quoteProfitAmount:0,
quoteTotalPrice:0,
quoteUnitPrice:0,
quoteTaxRate:0,
quoteTaxTotalPrice:0,
quoteTaxUnitPrice:0,
currency1:undefined,
finalTransactionPrice:null,
currency2:undefined,
exchangeRate1:undefined,
exchangeRate2:undefined,
currencyTotalCost1:0,
currencyTotalCost2:0,
quoteCurrencyTotalCost1:0,
quoteCurrencyTotalCost2:0,
// moq:'Standard 250K',
moq:'',
calculatedItems:'工具,测试,其他,包装,运输',
testCost:0,
adjustTestCost:0,
elseCost:0,
adjustElseCost:0,
remark:'',
showFlag:'N',
},
saveQuoteDetail:{
},
dataEntryVisible: false,
dataEntryLoading: false,
dataEntryForm: {
finalTransactionPrice: null,
remark: ''
},
dataList:[],
saveLoading:false,
queryLoading:false,
saveVisible:false,
showModalFlag:false,
showFlagChecked:false,
saveQuoteDetailRules:{
partNo: [{required: true, message: '请输入物料编码', trigger: ['blur','change']}],
partDesc: [{required: true, message: '请输入物料名称', trigger: ['blur','change']}],
qty: [{required: true, message: '请输入数量', trigger: ['blur','change']}],
currency1: [{required: true, message: '请选择币种', trigger: ['blur','change']}],
},
columns: [
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2PartNo',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'plmPartNo',
headerAlign: 'center',
align: 'left',
columnLabel: 'PLM物料编码',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 120
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2PartNo',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'ifsPartNo',
headerAlign: 'center',
align: 'left',
columnLabel: 'IFS物料编码',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 120
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2PartDesc',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'partDesc',
headerAlign: 'center',
align: 'left',
columnLabel: '物料名称',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 240
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2QuoteTaxRate',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'customerPartNo',
headerAlign: 'center',
align: 'right',
columnLabel: '客户物料编码',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 90
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2Qty',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'qty',
headerAlign: 'center',
align: 'right',
columnLabel: 'MOQ',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 100
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2QuoteProfitRate',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'quoteProfitRate',
headerAlign: 'center',
align: 'right',
columnLabel: 'VA%',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 60
},
// {
// userId: this.$store.state.user.name,
// functionId: 5011,
// serialNumber: '5011Table2QuoteTaxRate',
// tableId: '5011Table2',
// tableName: '报价详情信息表',
// columnProp: 'quoteTaxRate',
// headerAlign: 'center',
// align: 'right',
// columnLabel: 'Margin%',
// columnHidden: false,
// columnImage: false,
// columnSortable: false,
// sortLv: 0,
// status: true,
// fixed: '',
// columnWidth: 60
// },
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2QuoteProfitAmount',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'quoteProfitAmount',
headerAlign: 'center',
align: 'right',
columnLabel: 'Contribution%',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 100
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2Qty',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'currencyDesc2',
headerAlign: 'center',
align: 'right',
columnLabel: '币种',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 100
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2Qty',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'currencyTotalCost2',
headerAlign: 'center',
align: 'right',
columnLabel: '含税单价',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 100
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2Qty',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'unitPriceRate',
headerAlign: 'center',
align: 'right',
columnLabel: '未税单价',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 100
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2Remark',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'remark',
headerAlign: 'center',
align: 'left',
columnLabel: '备注',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 120
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2AdjustPartCost',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'adjustPartCost',
headerAlign: 'center',
align: 'right',
columnLabel: '材料成本',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 130
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2AdjustLabourCost',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'adjustLabourCost',
headerAlign: 'center',
align: 'right',
columnLabel: '人工成本',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 120
},
// {
// userId: this.$store.state.user.name,
// functionId: 5011,
// serialNumber: '5011Table2AdjustMachineCost',
// tableId: '5011Table2',
// tableName: '报价详情信息表',
// columnProp: 'adjustMachineCost',
// headerAlign: 'center',
// align: 'right',
// columnLabel: '机器成本',
// columnHidden: false,
// columnImage: false,
// columnSortable: false,
// sortLv: 0,
// status: true,
// fixed: '',
// columnWidth: 120
// },
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2AdjustToolCost',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'adjustToolCost',
headerAlign: 'center',
align: 'right',
columnLabel: '工具成本',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 120
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2AdjustTestCost',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'adjustTestCost',
headerAlign: 'center',
align: 'right',
columnLabel: '测试成本',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 120
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2PackCost',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'packCost',
headerAlign: 'center',
align: 'right',
columnLabel: '包装成本',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 120
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2ShippingCost',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'shippingCost',
headerAlign: 'center',
align: 'right',
columnLabel: '运输成本',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 120
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2AdjustElseCost',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'adjustElseCost',
headerAlign: 'center',
align: 'right',
columnLabel: '其他成本',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 120
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2TotalCost',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'totalCost',
headerAlign: 'center',
align: 'right',
columnLabel: '总成本',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 80
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2FinalTransactionPrice',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'finalTransactionPrice',
headerAlign: 'center',
align: 'right',
columnLabel: '最终交易价',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 80
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2QuoteTaxTotalPrice',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'quoteTaxTotalPrice',
headerAlign: 'center',
align: 'right',
columnLabel: 'Price ¥(ex VAT)',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 100
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2Qty',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'unitPrice',
headerAlign: 'center',
align: 'right',
columnLabel: '未税单价',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 100
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2Qty',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'taxRate',
headerAlign: 'center',
align: 'right',
columnLabel: '税率',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 100
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2Qty',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'exchangeRate1',
headerAlign: 'center',
align: 'right',
columnLabel: '其他税率',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 100
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2Qty',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'taxUnitPrice',
headerAlign: 'center',
align: 'right',
columnLabel: '含税单价(CNY)',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 100
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2Qty',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'exchangeRate2',
headerAlign: 'center',
align: 'right',
columnLabel: '汇率',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 100
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table2Qty',
tableId: '5011Table2',
tableName: '报价详情信息表',
columnProp: 'unitPrice',
headerAlign: 'center',
align: 'right',
columnLabel: '未税单价(CNY)',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 100
},
],
partVisible:false,
activeName:'bom',
projectPart:{
},
projectPartList:[],
pageNo:1,
pageSize:20,
pageTotal:0,
partQueryLoading:false,
projectPartColumns:[
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table3TestPartNo',
tableId: '5011Table3',
tableName: '项目物料表',
columnProp: 'testPartNo',
headerAlign: 'center',
align: 'left',
columnLabel: '物料编码',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 150
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table3PartDesc',
tableId: '5011Table3',
tableName: '项目物料表',
columnProp: 'partDesc',
headerAlign: 'center',
align: 'left',
columnLabel: '物料名称',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 160
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table3FinalPartNo',
tableId: '5011Table3',
tableName: '项目物料表',
columnProp: 'finalPartNo',
headerAlign: 'center',
align: 'left',
columnLabel: 'IFS物料编码',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 150
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table3CustomerPartNo',
tableId: '5011Table3',
tableName: '项目物料表',
columnProp: 'customerPartNo',
headerAlign: 'center',
align: 'left',
columnLabel: '客户物料编码',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 150
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table3Type',
tableId: '5011Table3',
tableName: '项目物料表',
columnProp: 'type',
headerAlign: 'center',
align: 'left',
columnLabel: '制造类型',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 120
},
{
userId: this.$store.state.user.name,
functionId: 5011,
serialNumber: '5011Table3UmId',
tableId: '5011Table3',
tableName: '项目物料表',
columnProp: 'umId',
headerAlign: 'center',
align: 'left',
columnLabel: '单位',
columnHidden: false,
columnImage: false,
columnSortable: false,
sortLv: 0,
status: true,
fixed: '',
columnWidth: 100
},
],
exportData:[],
exportName: '报价条目明细'+this.dayjs().format('YYYYMMDDHHmmss'),
exportHeader: ["报价条目明细"],
exportFooter: [],
againVisible:false,
againRow:{},
// 平铺视图(不传 quoteGroupDetail 时)内部维护的 quoteGroupDetailId → currentQuoteDetailItemNo 映射
internalDefaultItemNoMap: {},
}
},
methods:{
handleSaveQuoteDetail(row){
this.$nextTick(()=>{
if (this.$refs.handleSaveQuoteDetailClick){
this.$refs.saveQuoteDetailForm.clearValidate();
}
})
if (row){
this.saveQuoteDetail = {
...row
}
// 设置勾选状态
this.showFlagChecked = row.showFlag === 'Y'
}else {
this.saveQuoteDetail = {
...this.quoteDetail,
createBy:this.$store.state.user.name,
status:'草稿',
active:'Y',
qty:1,
isDetail:false,
}
if (this.quoteGroupDetail){
this.saveQuoteDetail.partNo = this.quoteGroupDetail.partNo
this.saveQuoteDetail.partDesc = this.quoteGroupDetail.partDesc
}
this.$nextTick(()=>{
this.saveQuoteDetail.projectNo = this.quote.projectNo
})
// 新建时默认不勾选
this.showFlagChecked = false
}
this.saveQuoteDetail.showModalFlag = false
this.activeName = 'bom';
this.saveVisible = true;
this.showModalFlag = false;
},
handleDetail(row){
this.saveQuoteDetail = {
...row
}
this.saveQuoteDetail.showModalFlag = true
// 设置勾选状态
this.showFlagChecked = row.showFlag === 'Y'
this.activeName = 'bom';
this.saveVisible = true;
this.showModalFlag = true;
},
handleDataEntry() {
this.dataEntryForm = {
finalTransactionPrice: this.saveQuoteDetail.finalTransactionPrice,
remark: this.saveQuoteDetail.remark || ''
}
this.dataEntryVisible = true
},
submitDataEntry() {
this.dataEntryLoading = true
const params = {
id: this.saveQuoteDetail.id,
finalTransactionPrice: this.dataEntryForm.finalTransactionPrice,
remark: this.dataEntryForm.remark,
updateBy: this.$store.state.user.name
}
updateQuoteDetailEntry(params).then(({data}) => {
if (data && data.code === 0) {
this.$message.success('操作成功')
this.saveQuoteDetail.finalTransactionPrice = params.finalTransactionPrice
this.saveQuoteDetail.remark = params.remark
this.dataEntryVisible = false
this.handleQueryQuoteDetail()
} else {
this.$message.error(data.msg)
}
}).finally(() => {
this.dataEntryLoading = false
})
},
handleShowFlagChange(val){
// 勾选变化时直接更新数据库,只修改show_flag字段
if (!this.saveQuoteDetail.id) {
return
}
const newShowFlag = val ? 'Y' : 'N'
const params = {
id: this.saveQuoteDetail.id,
showFlag: newShowFlag
}
updateQuoteDetailShowFlag(params).then(({data}) => {
if (data && data.code === 0) {
this.saveQuoteDetail.showFlag = newShowFlag
this.$message.success('更新成功')
// 刷新列表
this.handleQueryQuoteDetail()
} else {
this.$message.warning(data.msg)
// 恢复勾选状态
this.showFlagChecked = !val
}
}).catch((error) => {
this.$message.error(error)
// 恢复勾选状态
this.showFlagChecked = !val
})
},
handleDeleteQuoteDetail(row){
this.$confirm('确认删除该条报价明细吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let params = {
id: row.id,
}
deleteQuoteDetail(params).then(({data}) => {
if (data && data.code === 0) {
this.$message.success(data.msg);
this.handleQueryQuoteDetail();
// 通知父组件刷新主信息
console.log('emit refresh-quote-info event (delete), quoteId:', this.quote.id)
this.$emit('refresh-quote-info', this.quote.id)
} else {
this.$message.warning(data.msg);
}
}).catch((error) => {
this.$message.error(error);
})
}).catch(() => {
})
},
handlePartNoBlur(){
let params = {
site:this.$store.state.user.site,
testPartNo:this.saveQuoteDetail.partNo,
projectId: this.quote.projectNo,
no:1,
size:20,
}
getProjectPartList(params).then(({data})=>{
if (data && data.code === 0){
if (data.rows && data.rows.length === 1){
this.dblClickProjectPartTable(data.rows[0])
}else {
this.saveQuoteDetail.partDesc = ''
}
}
})
},
handleQueryQuoteDetail(){
let params = {
quoteId: this.quote.id,
}
if (this.quoteGroupDetail){
params.quoteGroupDetailId=this.quoteGroupDetail.id;
} else {
// 平铺模式:同步加载各报价明细组的默认条目映射,用于删除保护
this.loadGroupDetailMap();
}
this.queryLoading = true;
queryQuoteDetail(params).then(({data})=>{
if (data && data.code === 0){
this.dataList = data.rows
}else {
this.$message.warning(data.msg);
}
this.queryLoading = false;
}).catch((error)=>{
this.$message.error(error);
this.queryLoading = false;
})
},
// 平铺模式下加载 quoteGroupDetail 映射,用于判断哪些条目行是默认报价行(不允许删除)
loadGroupDetailMap() {
if (!this.quote.id) {
this.internalDefaultItemNoMap = {}
return
}
queryQuoteGroupDetail({ quoteId: this.quote.id }).then(({ data }) => {
if (data && data.code === 0 && data.rows) {
const map = {}
data.rows.forEach(group => {
if (group.currentQuoteDetailItemNo) {
map[group.id] = group.currentQuoteDetailItemNo
}
})
this.internalDefaultItemNoMap = map
} else {
this.internalDefaultItemNoMap = {}
}
}).catch(() => {
this.internalDefaultItemNoMap = {}
})
},
handleSaveQuoteDetailClick(){
this.$refs.saveQuoteDetailForm.validate((valid,obj) => {
if (valid){
if (this.saveQuoteDetail.id){
this.handleUpdate();
}else {
this.handleSave();
}
}else {
let i = 1;
for (let key in obj) {
this.$message.error(obj[key][0].message);
if (i === 1){
return
}
i++;
}
}
})
},
handleSave(){
console.log('handleSave 被调用, quote.id:', this.quote.id)
let params = {
...this.saveQuoteDetail,
quoteId: this.quote.id,
quoteNo:this.quote.quoteNo,
site:this.quote.site,
buNo:this.quote.buNo,
versionNo:this.quote.versionNo,
createBy:this.saveQuoteDetail.createBy,
active:'Y',
status:'草稿',
internalInquiryNo:this.quote.insideInquiryNo,
}
if (this.quoteGroupDetail){
params.quoteGroupDetailId=this.quoteGroupDetail.id;
}
this.saveLoading = true;
saveQuoteDetail(params).then(({data})=>{
if (data && data.code === 0){
this.$message.success(data.msg);
this.handleQueryQuoteDetail();
if (this.saveQuoteDetail.isDetail){
this.saveQuoteDetail = {
...data.row,
}
}else {
this.saveVisible = false;
}
// 通知父组件刷新主信息
console.log('emit refresh-quote-info event (save), quoteId:', this.quote.id)
this.$emit('refresh-quote-info', this.quote.id)
}else {
this.$message.warning(data.msg);
}
this.saveLoading = false
}).catch((error)=>{
this.$message.error(error);
this.saveLoading = false
})
},
handleUpdate(){
let params = {
...this.saveQuoteDetail,
updateBy:this.$store.state.user.name,
}
updateQuoteDetail(params).then(({data})=>{
if (data && data.code === 0){
this.$message.success(data.msg);
this.handleQueryQuoteDetail();
this.saveVisible = false;
// 通知父组件刷新主信息
console.log('emit refresh-quote-info event (update), quoteId:', this.quote.id)
this.$emit('refresh-quote-info', this.quote.id)
}else {
this.$message.warning(data.msg);
}
}).catch((error)=>{
this.$message.error(error);
})
},
handleClickTab(tab){
if (this.activeName === 'routing'){
this.$refs.routing.handleQueryQuoteDetailBomTree()
}else if (this.activeName === 'tool'){
this.$refs.tool.handleQueryQuoteDetailTool();
}
},
handleAgainQuoteDetail(row){
this.againRow = row;
this.againVisible = true;
},
againQuoteDetail(){
this.$refs.againForm.validate((valid,obj) => {
if (valid){
this.queryLoading = true;
this.saveLoading = true;
againQuoteDetail(this.againRow).then(({data})=>{
if (data && data.code === 0){
this.againVisible = false
this.handleQueryQuoteDetail();
this.$message.success(data.msg);
}else {
this.$message.warning(data.msg);
}
this.queryLoading = false;
this.saveLoading = false;
}).catch((error)=>{
this.$message.error(error);
this.queryLoading = false;
this.saveLoading = false;
})
}else {
let i = 1;
for (let key in obj) {
this.$message.error(obj[key][0].message);
if (i === 1){
return
}
i++;
}
}
})
},
handleQueryPartList(){
this.projectPart = {
testPartNo:this.saveQuoteDetail.partNo,
partDesc:'',
finalPartNo:'',
customerPartNo:'',
site:this.$store.state.user.site,
}
this.partVisible = true;
this.getProjectPartList();
},
getProjectPartList(){
let params = {
...this.projectPart,
no:this.pageNo,
size:this.pageSize,
}
params.projectId = this.quote.projectNo
this.partQueryLoading = true;
getProjectPartList(params).then(({data})=>{
if (data && data.code === 0){
this.projectPartList = data.rows;
this.pageTotal = data.total;
}
this.partQueryLoading = false;
}).catch((error)=>{
this.partQueryLoading = false;
})
},
handleSizeChange(val){
this.pageSize = val;
this.getProjectPartList();
},
handleCurrentChange(val){
this.pageNo = val;
this.getProjectPartList();
},
dblClickProjectPartTable(row){
this.saveQuoteDetail.partNo = row.testPartNo;
this.saveQuoteDetail.partDesc = row.partDesc;
this.partVisible = false;
},
handleClose(){
this.$emit('close');
this.saveVisible = false;
}, startDownload() {
this.exportLoading = true
},
finishDownload() {
this.exportLoading = false
},
fields() {
let json = "{"
this.columns.forEach((item, index) => {
if (index === this.columns.length - 1) {
json += "\"" + item.columnLabel + "\"" + ":" + "\"" + item.columnProp + "\""
} else {
json += "\"" + item.columnLabel + "\"" + ":" + "\"" + item.columnProp + "\"" + ","
}
})
json += "}"
return eval("(" + json + ")")
},
createExportData() {
return this.dataList;
},
toPartMenu (partNo) {
if (this.$router.resolve(`/part-partInformation`).resolved.name === '404') {
this.$alert('权限不足,访问失败', '警告', {confirmButtonText: '确定',})
} else {
this.$router.push({name:`part-partInformation`,params:{partNo:partNo},})
}
},
formatDecimal(value) {
const num = parseFloat(value);
return !isNaN(num) ? num.toFixed(4) : value;
},
handleSetDefaultQuoteRow(row) {
if (!this.isAuth('5011:group:current')) {
return;
}
const oldVal = this.quoteGroupDetail.currentQuoteDetailItemNo;
this.quoteGroupDetail.currentQuoteDetailItemNo = row.itemNo;
// 直接触发emit事件
this.$emit('currentQuoteDetailItemNo', oldVal);
},
// 判断某行是否为默认报价行(不允许删除)
// 单组视图(quoteGroupDetail 已传入):对比 quoteGroupDetail.currentQuoteDetailItemNo
// 平铺视图(quoteGroupDetail 未传):对比内部加载的 internalDefaultItemNoMap
isDefaultQuoteRow(row) {
if (this.quoteGroupDetail) {
return this.quoteGroupDetail.currentQuoteDetailItemNo === row.itemNo;
}
const defaultItemNo = this.internalDefaultItemNoMap[row.quoteGroupDetailId]
return defaultItemNo != null && defaultItemNo === row.itemNo;
},
},
watch:{
quote(newVal,oldVal){
if (newVal.id){
// 只有当 quote.id 真正变化时才重新查询,避免重复查询
if (newVal.id !== (oldVal && oldVal.id)) {
this.quoteDetail.profitRate = this.quote.markup
this.quoteDetail.quoteProfitRate = this.quote.markup
this.handleQueryQuoteDetail();
}
}else {
this.dataList = [];
}
},
"saveQuoteDetail.partNo"(newVal,oldVal){
if (newVal){
this.saveQuoteDetail.partNo = newVal.toUpperCase();
}
},
partVisible(newVal,oldVal){
if (newVal === false){
this.partQueryLoading = false
this.pageNo = 1;
this.projectPartList = [];
}
},
quoteGroupDetail(newVal,oldVal){
if (newVal){
this.quoteDetail.profitRate = this.quote.markup
this.quoteDetail.quoteProfitRate = this.quote.markup
this.handleQueryQuoteDetail();
}
},
// 'quoteGroupDetail.currentQuoteDetailItemNo'(newVal,oldVal){
// // console.log(this.quoteGroupDetail)
// // emit事件触发修改
// if (this.quoteGroupDetail && this.quoteGroupDetail.currentQuoteDetailItemNo){
// this.$emit('currentQuoteDetailItemNo',oldVal);
// }
// }
},
created() {
this.quoteDetail.profitRate = this.quote.markup
this.quoteDetail.quoteProfitRate = this.quote.markup
// 只有当 quote.id 存在时才查询,避免和 watch 重复查询
if (this.quote.id) {
this.handleQueryQuoteDetail();
}
}
}
</script>
<template>
<div>
<template v-if="saveAuth">
<el-button type="primary" v-if="!authFlag" :disabled="quote.status === '已完成' || !quote.status" @click="handleSaveQuoteDetail(null)">新增</el-button>
</template>
<template v-if="isExport">
<download-excel
:fields="fields()"
:data="exportData"
type="xls"
:name="exportName"
:header="exportHeader"
:footer="exportFooter"
:fetch="createExportData"
:before-generate="startDownload"
:before-finish="finishDownload"
worksheet="导出信息"
:class="['el-button', 'el-button--primary', 'el-button--medium', {'is-loading': exportLoading}]">
<i v-if="exportLoading" class="el-icon-loading"></i>
<span>{{ '导出' }}</span>
</download-excel>
</template>
<el-table v-loading="queryLoading" border :data="dataList" style="width: 100%;margin-top: 5px" :height="height">
<el-table-column width="80" align="center" label="默认报价行" v-if="quoteGroupDetail && (quoteGroupDetail.status === '草稿' || quoteGroupDetail.status === '审批中')">
<template slot-scope="{row}">
<div style="cursor: pointer;">
<el-radio
class="radio"
:label="row.itemNo"
:disabled="!isAuth('5011:group:current')"
v-model="quoteGroupDetail.currentQuoteDetailItemNo"
@click.native.prevent="handleSetDefaultQuoteRow(row)"
></el-radio>
</div>
</template>
</el-table-column>
<el-table-column type="index" width="55" align="center" label="序号"></el-table-column>
<el-table-column
v-for="(item,index) in columns" :key="index"
:sortable="item.columnSortable"
:prop="item.columnProp"
:header-align="item.headerAlign"
:show-overflow-tooltip="item.showOverflowTooltip"
:align="item.align"
:fixed="item.fixed === ''?false:item.fixed"
:min-width="item.columnWidth"
:label="item.columnLabel">
<template slot-scope="scope">
<template v-if="item.columnProp === 'unitPriceRate'">
{{ formatDecimal(scope.row.unitPriceRate) }}
</template>
<template v-else-if="!quoteGroupDetail && item.columnProp === 'plmPartNo'">
<el-link style="cursor:pointer;" v-if="!item.columnHidden" @click="toPartMenu(scope.row.plmPartNo)"> {{ scope.row[item.columnProp] }}</el-link>
<span v-if="item.columnImage"><img :src="scope.row[item.columnProp]" style="width: 100px; height: 80px"/></span>
</template>
<template v-else>
<span v-if="!item.columnHidden">{{ scope.row[item.columnProp] }}</span>
<span v-if="item.columnImage"><img :src="scope.row[item.columnProp]"
style="width: 100px; height: 80px"/></span>
</template>
</template>
</el-table-column>
<el-table-column label="操作" v-if="!authFlag" fixed="right" align="center" width="160">
<template slot-scope="{row,$index}">
<template v-if="isAuth('5011:detail:update')">
<a type="text" v-if="row.status === '草稿' || row.status === '审批中'" @click="handleSaveQuoteDetail(row)">编辑</a>
</template>
<template v-if="isAuth('5011:detail:remove')">
<a type="text" v-if="(row.status === '草稿' || row.status === '审批中') && !isDefaultQuoteRow(row)" @click="handleDeleteQuoteDetail(row)">删除</a>
</template>
<template v-if="isAuth('5011:detail:again')">
<!-- <a type="text" v-if="row.status !== '已完成'" @click="againQuoteDetail(row)">复制明细</a>-->
<a type="text" v-if="row.status !== '已完成'" @click="handleAgainQuoteDetail(row)">复制明细</a>
</template>
<template v-if="isAuth('5011:detail:detail')">
<a type="text" @click="handleDetail(row)">详情</a>
</template>
</template>
</el-table-column>
</el-table>
<el-dialog :title="`报价明细`" top="10vh" v-drag :visible.sync="saveVisible" append-to-body :width="`${saveQuoteDetail.id?1200:600}px`" :close-on-click-modal="false">
<el-form :model="saveQuoteDetail" ref="saveQuoteDetailForm" :rules="saveQuoteDetailRules" label-position="top" v-if="!saveQuoteDetail.id">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="物料编码" prop="partNo" :show-message="false">
<span slot="label" v-if="!quoteGroupDetail">
<a @click="handleQueryPartList">物料编码</a>
</span>
<el-input v-model="saveQuoteDetail.partNo" :disabled="quoteGroupDetail" @change="handlePartNoBlur"></el-input>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="物料名称" prop="partDesc" :show-message="false">
<el-input v-model="saveQuoteDetail.partDesc" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="MOQ" prop="qty" :show-message="false">
<el-input-number style="width: 100%;" v-model="saveQuoteDetail.qty" :min="1" :step="0" :precision="0" :controls="false"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="币种" prop="currency1" :show-message="false">
<dict-data-select style="width: 100%" dict-type="plm_customer_information_customer_customer_currency" v-model="saveQuoteDetail.currency1"></dict-data-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="" :show-message="false">
<el-checkbox v-model="saveQuoteDetail.isDetail">保存进入报价页面</el-checkbox>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" class="auto" :show-message="false">
<el-input type="textarea" v-model="saveQuoteDetail.remark" :autosize="{minRows: 3, maxRows: 3}"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-form v-else :model="saveQuoteDetail" ref="saveQuoteDetailForm" :rules="saveQuoteDetailRules" label-position="top">
<el-row :gutter="20">
<el-col :span="4">
<el-form-item label="物料编码" prop="partNo" :show-message="false">
<el-input v-model="saveQuoteDetail.partNo" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="物料名称" prop="partDesc" :show-message="false">
<el-input v-model="saveQuoteDetail.partDesc" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="2">
<el-form-item label="MOQ" prop="qty" :show-message="false">
<el-input-number v-model="saveQuoteDetail.qty" style="width: 100%;" :controls="false" :disabled="showModalFlag||saveQuoteDetail.status === '已完成'"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="3">
<el-form-item label="币种" prop="currency1" :show-message="false">
<dict-data-select :disabled="showModalFlag||saveQuoteDetail.status === '已完成'" style="width: 100%" dict-type="plm_customer_information_customer_customer_currency" v-model="saveQuoteDetail.currency1"></dict-data-select>
</el-form-item>
</el-col>
<el-col :span="3">
<el-form-item label="最终交易价" :show-message="false">
<el-input-number v-model="saveQuoteDetail.finalTransactionPrice" :controls="false" :disabled="showModalFlag||saveQuoteDetail.status === '已完成'" style="width: 100%"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label=" " :show-message="false">
<el-checkbox v-model="showFlagChecked" :disabled="showModalFlag" @change="handleShowFlagChange">询价申请中展示该条目行</el-checkbox>
</el-form-item>
</el-col>
<el-col :span="2">
<el-form-item label=" " :show-message="false">
<el-button v-if="saveQuoteDetail.id && isAuth('5011:detail:dataEntry')" type="warning" @click="handleDataEntry">数据录入</el-button> </el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="备注" class="auto" :show-message="false">
<el-input type="textarea" resize="none" :autosize="{minRows: 3, maxRows: 3}" v-model="saveQuoteDetail.remark" :disabled="showModalFlag||saveQuoteDetail.status === '已完成'"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-tabs v-model="activeName" v-if="saveQuoteDetail.id" @tab-click="handleClickTab">
<el-tab-pane label="材料" name="bom">
<quote-detail-bom v-if="saveVisible && activeName === 'bom'" @close="handleClose" v-model:quoteDetail="saveQuoteDetail"></quote-detail-bom>
</el-tab-pane>
<el-tab-pane label="工艺" name="routing">
<quote-detail-routing ref="routing" v-if="saveVisible && activeName === 'routing'" @close="handleClose" v-model:quoteDetail="saveQuoteDetail"></quote-detail-routing>
</el-tab-pane>
<el-tab-pane label="工具" name="tool">
<quote-detail-tool ref="tool" v-if="saveVisible && activeName === 'tool'" v-model:quoteDetail="saveQuoteDetail"></quote-detail-tool>
</el-tab-pane>
<el-tab-pane label="测试" name="test">
<quote-detail-test v-if="saveVisible && activeName === 'test'" v-model:quoteDetail="saveQuoteDetail"></quote-detail-test>
</el-tab-pane>
<el-tab-pane label="包装&运输" name="otherCost">
<quote-detail-other-cost v-if="saveVisible && activeName === 'otherCost'" v-model:quoteDetail="saveQuoteDetail"></quote-detail-other-cost>
</el-tab-pane>
<el-tab-pane label="其他" name="other">
<quote-detail-other v-if="saveVisible && activeName === 'other'" v-model:quoteDetail="saveQuoteDetail"></quote-detail-other>
</el-tab-pane>
<el-tab-pane label="成本&价格" name="cost">
<quote-detail-cost v-if="saveVisible && activeName === 'cost'" ref="cost" v-model:quoteDetail="saveQuoteDetail"></quote-detail-cost>
</el-tab-pane>
</el-tabs>
<div slot="footer" class="dialog-footer">
<el-button type="primary" v-if="!this.showModalFlag&&(saveQuoteDetail.status === '草稿' || saveQuoteDetail.status === '审批中')" :loading="saveLoading" @click="handleSaveQuoteDetailClick">确 定</el-button>
<el-button @click="saveVisible = false">取 消</el-button>
</div>
</el-dialog>
<el-dialog title="数据录入" v-drag :visible.sync="dataEntryVisible" append-to-body width="500px" :close-on-click-modal="false">
<el-form :model="dataEntryForm" label-position="top">
<el-form-item label="最终交易价">
<el-input-number v-model="dataEntryForm.finalTransactionPrice" :controls="false" style="width: 100%" placeholder="请输入最终交易价"></el-input-number>
</el-form-item>
<el-form-item label="备注">
<el-input type="textarea" v-model="dataEntryForm.remark" :rows="3" resize="none" placeholder="请输入备注"></el-input>
</el-form-item>
</el-form>
<div style="height:35px;margin-top: 55px;text-align:center">
<el-button type="primary" :loading="dataEntryLoading" @click="submitDataEntry">保 存</el-button>
<el-button @click="dataEntryVisible = false">取 消</el-button>
</div>
</el-dialog>
<el-dialog v-drag title="物料信息" append-to-body :close-on-click-modal="false" :visible.sync="partVisible">
<!--搜索条件-->
<el-form :model="projectPart" ref="projectPartDataForm" :inline="true" label-position="top">
<el-form-item label="物料编码" prop="testPartNo">
<el-input v-model="projectPart.testPartNo" clearable/>
</el-form-item>
<el-form-item label="物料名称" prop="partDesc">
<el-input v-model="projectPart.partDesc" clearable/>
</el-form-item>
<el-form-item label="IFS物料编码" prop="finalPartNo">
<el-input v-model="projectPart.finalPartNo" clearable/>
</el-form-item>
<el-form-item label="客户物料编码" prop="customerPartNo">
<el-input v-model="projectPart.customerPartNo" clearable/>
</el-form-item>
<el-form-item label=" ">
<el-button @click="getProjectPartList" type="primary">查 询</el-button>
</el-form-item>
</el-form>
<el-table height="300px" v-loading="partQueryLoading" stripe border @row-dblclick="dblClickProjectPartTable" :data="projectPartList" ref="projectPartDataTable" :style="{marginTop:'10px'}">
<el-table-column
v-for="(item,index) in projectPartColumns" :key="index"
:sortable="item.columnSortable"
:prop="item.columnProp"
:header-align="item.headerAlign"
:show-overflow-tooltip="item.showOverflowTooltip"
:align="item.align"
:fixed="item.fixed===''?false:item.fixed"
:min-width="item.columnWidth"
:label="item.columnLabel">
<template slot-scope="scope">
<span v-if="!item.columnHidden">{{scope.row[item.columnProp]}}</span>
<span v-if="item.columnImage"><img :src="scope.row[item.columnProp]" style="width: 100px; height: 80px"/></span>
</template>
</el-table-column>
</el-table>
<el-pagination style="margin-top: 0"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNo"
:page-sizes="[20, 50, 100, 200, 500]"
:page-size="pageSize"
:total="pageTotal"
layout="total,sizes, prev, pager, next, jumper">
</el-pagination>
</el-dialog>
<el-dialog title="复制明细" v-drag append-to-body :close-on-click-modal="false" :visible.sync="againVisible" width="400px">
<el-form :model="againRow" label-position="top" ref="againForm" :rules="saveQuoteDetailRules">
<el-row :gutter="10">
<el-col :span="8">
<el-form-item label="物料编码" prop="partNo" :show-message="false">
<el-input v-model="againRow.partNo" disabled @change="handlePartNoBlur"></el-input>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="物料名称" prop="partDesc" :show-message="false">
<el-input v-model="againRow.partDesc" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="MOQ" prop="qty" :show-message="false">
<el-input-number style="width: 100%;" v-model="againRow.qty" :min="1" :step="0" :precision="0" :controls="false"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="币种" prop="currency1" :show-message="false">
<dict-data-select style="width: 100%" dict-type="plm_customer_information_customer_customer_currency" v-model="againRow.currency1"></dict-data-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" :loading="saveLoading" @click="againQuoteDetail"> </el-button>
<el-button @click="againVisible = false"> </el-button>
</div>
</el-dialog>
<!-- <part-table v-if="saveVisible" v-model="partVisible" :is-page="true" :part-no="saveQuoteDetail.partNo" @dblclick="handleDblClick"></part-table>-->
<!-- <project-part-table v-if="saveVisible" v-model="partVisible" :project-no="saveQuoteDetail.projectNo" :part-no="saveQuoteDetail.partNo" @dblclick="handleDblClick"></project-part-table>-->
</div>
</template>
<style scoped>
.el-table /deep/ .cell{
height: auto;
line-height: 1.5;
}
.auto /deep/ .el-form-item__content{
height: auto;
line-height: 1.5;
}
.radio /deep/ .el-radio__label{
display: none;
}
</style>