离开页面给提示
2022-11-08 本文已影响0人
糖醋里脊120625
<template>
<el-main>
<el-form :model="form.model" :rules="form.rules" ref="form" style="margin-bottom: 56px" v-loading="form.loading"
label-width="120px">
<span>基本信息</span>
<el-divider></el-divider>
<el-form-item label="采购类型" required>
<el-radio-group v-model="form.model.purchaseType" @change="onPurchaseTypeChanged">
<el-radio label="0">市场自采</el-radio>
<el-radio label="1">供应商采购</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-show="isMarketPurchase" label="采购员" prop="purchaserName">
<el-col :span="8">
<el-input v-model="form.model.purchaserName"></el-input>
</el-col>
</el-form-item>
<el-form-item v-show="isSupplierPurchase" label="供应商" prop="supplierName">
<el-col :span="8">
<SupplierSearcher @change="onSupplierChanged" style="width: 100%" ref="supplierSearcher"
/>
</el-col>
</el-form-item>
<el-form-item label="交货日期" prop="planSupplyDate" required>
<el-col :span="8">
<el-date-picker
style="width: 100%"
v-model="form.model.planSupplyDate"
type="date"
value-format="yyyy-MM-dd"
@change="onSupplyDateChanged">
</el-date-picker>
</el-col>
</el-form-item>
<el-form-item label="采购协议" v-if="purchaseAgreementSelect.options.length>0">
<el-col :span="8">
<el-select
style="width: 100%"
v-model="form.model.purchaseAgreementId" value-key="id"
placeholder="请选择"
@change="onPurchaseAgreementChanged"
clearable>
<el-option v-for="item in purchaseAgreementSelect.options" :key="item.id" :label="item.name"
:value="item.id"
style="height: 56px">
<span style="float: left;display: block;position: relative">{{ item.name }}</span>
<span
style="float:left;display: block;position: absolute;margin-top: 20px; color: #8492a6; font-size: 13px">
{{ item.beginDate | momentFormat('YYYY-MM-DD') }}至{{ item.endDate | momentFormat('YYYY-MM-DD') }}</span>
</el-option>
</el-select>
</el-col>
</el-form-item>
<div class="block-margin"></div>
<div>商品条目</div>
<el-divider></el-divider>
<el-form-item prop="itemList" label-width="0px">
<el-card shadow="never">
<div slot="header">
<el-form :inline="true" :model="itemForm.model" ref="itemForm">
<el-form-item label="品种" prop="product">
<PurchaseAgreementProductSearcher v-if="isAgreement"
ref="productSearcher"
:onSelected="onProductSelected"
:agreementId="form.model.purchaseAgreementId"/>
<ProductSearcher v-else ref="productSearcher" :onSelected="onProductSelected"/>
</el-form-item>
<el-form-item label="数量" prop="num">
<el-input v-model="itemForm.model.num"
v-input-number.decimal="{decimal:2,min:0}"
ref="numInput"
@keyup.enter.native="onItemAddBtnClicked"/>
</el-form-item>
<el-form-item label="单价" prop="unitPrice">
<el-input v-model="itemForm.model.unitPrice"
v-input-number.decimal="{decimal:2,min:0}"
ref="unitPriceInput"
:disabled="isAgreement"
@keyup.enter.native="onItemAddBtnClicked"/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onItemAddBtnClicked">添加
</el-button>
</el-form-item>
</el-form>
</div>
<el-table :data="form.model.itemList"
show-summary :summary-method="getSummaries">
<el-table-column type="index" width="50"></el-table-column>
<el-table-column label="品种">
<template slot-scope="scope">
<GoodsItem :imageSrc="scope.row.product.piImageUrl"
:name="scope.row.product.piProductName"
:spec="scope.row.product.piSpec"
:netContent="scope.row.product.piNetContent"
:netContentUnit="scope.row.product.piNetContentUnit"
:level="scope.row.product.piLevel"/>
</template>
</el-table-column>
<el-table-column label="数量">
<template slot-scope="scope">
<el-input @mousewheel.native.prevent v-model="scope.row.num" size="small"
v-input-number.decimal="{decimal:2,min:0}"
@change="onItemNumPriceChanged(scope.row,'num')"/>
</template>
</el-table-column>
<el-table-column label="单价">
<template slot-scope="scope">
<el-input @mousewheel.native.prevent v-model="scope.row.unitPrice" size="small"
v-input-number.decimal="{decimal:2,min:0}"
:disabled="isAgreement"
@change="onItemNumPriceChanged(scope.row,'unitPrice')"/>
</template>
</el-table-column>
<el-table-column label="小计" prop="amount" align="right">
<!-- <template slot-scope="scope">-->
<!-- <el-input @mousewheel.native.prevent v-model="scope.row.amount" size="small"-->
<!-- v-input-number.decimal="{decimal:2,min:0}"-->
<!-- @change="onItemNumPriceChanged(scope.row,'amount')"/>-->
<!-- </template>-->
</el-table-column>
<el-table-column label="备注">
<template slot-scope="scope">
<el-input v-model="scope.row.remark" size="small"/>
</template>
</el-table-column>
<el-table-column label="操作" width="100" align="center">
<template slot-scope="scope">
<el-button size="small" type="danger" @click="onItemDeleteClicked(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</el-form-item>
<el-form-item label-width="0px">
<el-input type="textarea" v-model="form.model.remark" placeholder="备注"/>
</el-form-item>
</el-form>
<div class="el-main_foot_fixed">
<el-button @click="back">取消</el-button>
<el-button type="primary" v-loading="submitLoading" @click="onSubmitBtnClicked">提交</el-button>
<el-button type="primary" plain @click="onStagingBtnClicked" v-if="!isUpdateStatus">暂存</el-button>
</div>
</el-main>
</template>
<script>
import ProductSearcher from "../../components/business/ProductSearcher";
import PurchaseAgreementProductSearcher from "../../components/business/PurchaseAgreementProductSearcher";
import GoodsItem from "../../components/common/GoodsItem";
import SupplierSearcher from "../../components/business/SupplierSearcher";
import purchaseAgreementApi from "../../service/api/purchase-agreement-api";
import selfPurchaseOrderApi from "../../service/api/self-purchase-order-api";
import {centToYuan, yuanToCent} from "../../utils/priceUtil";
import {Decimal} from "decimal.js";
const MODEL_CACHE_KEY = "self-purchase-order/form/model";
export default {
components: {
SupplierSearcher,
PurchaseAgreementProductSearcher,
ProductSearcher, GoodsItem
},
data() {
return {
form: {
model: {
id: '',
purchaserName: '',
purchaseType: '0',
supplierName: '',
supplierId: '',
purchaseAgreementId: '',
planSupplyDate: '',
itemList: [],
remark: '',
},
modelBackup: '',
rules: {
purchaseType: [
{required: true, message: "请选择采购类型", trigger: "change"}
],
planSupplyDate: [
{required: true, message: "请选择交货日期", trigger: "change"}
],
itemList: [
{required: true, message: "商品条目不可为空"}
],
},
modelInitialValue: '',
loading: false
},
itemForm: {
model: {
product: '',
unitPrice: '',
num: '',
}
},
purchaseAgreementSelect: {
options: []
},
submitLoading: false,
isUpdateStatus: false,
}
},
computed: {
isAgreement: function () {
return this.form.model.purchaseAgreementId !== '';
},
isMarketPurchase: function () {
return this.form.model.purchaseType === '0';
},
isSupplierPurchase: function () {
return this.form.model.purchaseType === '1';
},
pageHasBeenEdited: function () {
return this.form.modelInitialValue !== JSON.stringify(this.form.model);
}
},
watch: {
'form.model.purchaseType'(newValue, oldValue) {
this.backupFormData('purchaseType', oldValue);
},
'form.model.planSupplyDate'(newValue, oldValue) {
this.backupFormData('planSupplyDate', oldValue);
},
'form.model.purchaseAgreementId'(newValue, oldValue) {
this.backupFormData('purchaseAgreementId', oldValue);
},
},
created() {
this.id = this.$route.query.id;
},
mounted() {
let id = this.$route.query.id;
if (id) {
this.isUpdateStatus = true;
this.loadDetail(id);
} else {
this.restoreTemporaryData();
}
},
methods: {
loadDetail(id) {
this.form.loading = true;
selfPurchaseOrderApi.get(id)
.then(value => {
this.setValueToView(value)
}).finally(() => {
this.form.loading = false;
});
},
loadPurchaseAgreements(supplierName, supplyDate) {
// 获取且协议,并判断是否协议的数据源改变了
purchaseAgreementApi.search({keyword: supplierName, queryDate: supplyDate, pageIndex: 1, pageSize: 20})
.then(value => {
// 数据源不包含当前选择的协议的情况弹出确认窗口
let noCurrentAgreement = this.purchaseAgreementSelect.options.length > 0
&& !value.list.some(item => item.id === this.form.model.purchaseAgreementId);
if (noCurrentAgreement && this.form.model.itemList.length > 0) {
this.alertClearConfirm(() => {
this.purchaseAgreementSelect.options = value.list;
this.form.model.purchaseAgreementId = '';
})
} else {
this.purchaseAgreementSelect.options = value.list;
}
})
},
alertClearConfirm(confirm) {
this.$confirm('协议发生改变,当前商品条目将被清空', '是否继续', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 清空商品条目
this.form.model.itemList = [];
confirm();
}).catch(() => {
this.restoreBackupFormData();
})
},
setValueToView(value) {
this.form.model = this.$clone(value);
this.form.model.purchaseType = this.form.model.purchaseType + "";
this.form.model.itemList = value.itemList.map(el => {
return {
product: el.productInfo,
unitPrice: centToYuan(el.unitPrice),
num: el.actualPurchaseNum,
amount: centToYuan(el.amount),
remark: el.remark,
};
});
if (this.isSupplierPurchase) {
this.$refs['supplierSearcher'].setValue({
id: this.form.model.supplierId,
name: this.form.model.supplierName,
});
this.loadPurchaseAgreements(this.form.model.supplierName, this.form.model.planSupplyDate);
}
this.initModelInitialValue();
},
onSupplierChanged(value) {
this.backupFormData();
this.form.model.supplierName = value.name;
this.form.model.supplierId = value.id;
this.loadPurchaseAgreements(this.form.model.supplierName, this.form.model.planSupplyDate)
},
onPurchaseTypeChanged(val) {
if (this.isMarketPurchase) {// 切换到市场采购
let change = () => {
this.purchaseAgreementSelect.options = [];
this.form.model.purchaseAgreementId = '';
this.form.model.supplierId = '';
this.form.model.supplierName = '';
this.$refs['supplierSearcher'].setValue({});
}
if (JSON.stringify(this.purchaseAgreementSelect.options) !== JSON.stringify([])
&& this.form.model.itemList.length > 0) {
this.alertClearConfirm(change);
} else {
change();
}
} else {// 供应商采购
this.form.model.purchaserName = '';
}
},
onSupplyDateChanged(val) {
if (this.isSupplierPurchase) {
this.loadPurchaseAgreements(this.form.model.supplierName, this.form.model.planSupplyDate);
}
},
onProductSelected(item) {
this.itemForm.model.product = item.obj;
if (this.isAgreement) {
this.itemForm.model.unitPrice = item.obj.unitPrice;
}
this.$nextTick(() => {
this.$refs['numInput'].focus();
})
},
onPurchaseAgreementChanged(value) {
if (this.form.model.itemList.length > 0) {
this.alertClearConfirm(() => {
// nothing to do
});
}
},
onItemAddBtnClicked() {
let item = this.$clone(this.itemForm.model);
if (!item.product) {
this.$message.error("请选择品种");
return;
}
if (!item.num || item.num < 0) {
this.$message.error("请输入正确数量");
return;
}
if (!item.unitPrice || item.unitPrice < 0) {
this.$message.error("请输入正确价格");
return;
}
if (this.checkItemExist(item)) {
this.$message.error("已存在相同品种");
return;
}
item.amount = Decimal.mul(item.num, item.unitPrice).toFixed(2, Decimal.ROUND_DOWN);
this.form.model.itemList.push(item);
this.$refs['itemForm'].resetFields();
this.$refs['unitPriceInput'].blur();
this.$refs['numInput'].blur();
this.$refs.productSearcher.clearSelected();
},
onItemDeleteClicked(index) {
this.form.model.itemList.splice(index, 1);
},
onItemNumPriceChanged(row, type) {
switch (type) {
case 'amount':
row.unitPrice = Decimal.div(row.amount, row.num).toFixed(2, Decimal.ROUND_DOWN);
break
default:
row.amount = Decimal.mul(row.num, row.unitPrice).toFixed(2, Decimal.ROUND_DOWN);
break
}
},
checkItemExist(item) {
if (this.form.model.itemList <= 0) {
return false;
}
return this.form.model.itemList.some(el => {
return el.product.piId === item.product.piId
})
},
getSummaries(param) {
const {columns, data} = param;
const sums = [];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = "合计";
return
}
if (index === 4) {
const values = data.map(item => Number(item[column.property]));
sums[index] = values.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return prev + curr;
} else {
return prev;
}
}, 0);
sums[index] = sums[index].toFixed(2);
}
});
return sums;
},
onStagingBtnClicked() {
sessionStorage.setItem(MODEL_CACHE_KEY, JSON.stringify(this.form.model));
this.initModelInitialValue();
this.$message.success("暂存成功");
},
restoreTemporaryData() {
let value = sessionStorage.getItem(MODEL_CACHE_KEY);
if (value) {
this.form.model = JSON.parse(value);
if (this.isSupplierPurchase) {
this.$refs['supplierSearcher'].setValue({
id: this.form.model.supplierId,
name: this.form.model.supplierName,
});
this.loadPurchaseAgreements(this.form.model.supplierName, this.form.model.planSupplyDate);
}
}
this.initModelInitialValue()
},
clearTemporaryData() {
sessionStorage.removeItem(MODEL_CACHE_KEY);
},
initModelInitialValue() {
this.form.modelInitialValue = JSON.stringify(this.form.model);
},
back() {
this.$router.back();
},
onSubmitBtnClicked() {
this.$refs.form.validate((valid) => {
if (!valid) {
return false;
}
// 转换视图的明细为参数需要的明细
let items = this.form.model.itemList.map(value => {
return {
productId: value.product.piId,
unitPrice: yuanToCent(value.unitPrice),
num: value.num,
remark: value.remark,
}
})
let model = this.$clone(this.form.model);
model.itemList = items;
this.submitLoading = true;
let promise = model.id ? selfPurchaseOrderApi.update(model) : selfPurchaseOrderApi.add(model);
promise.then(value => {
this.$message.success("提交成功");
// 为了跳过离开页面时的验证
this.initModelInitialValue();
// 新增成功的情况下清除缓存
if (model.id === '') {
this.clearTemporaryData();
}
this.back();
}).finally(() => {
this.submitLoading = false;
})
})
},
backupFormData(property, oldValue) {
let modelClone = this.$clone(this.form.model);
if (property) {
modelClone[property] = oldValue;
}
this.form.modelBackup = JSON.stringify(modelClone);
},
restoreBackupFormData() {
this.form.model = JSON.parse(this.form.modelBackup);
let supplierSearcherValue = {
id: this.form.model.supplierId,
name: this.form.model.supplierName,
}
this.$refs['supplierSearcher'].setValue(supplierSearcherValue);
},
alertDataChangeConfirm(confirm, cancel) {
if (this.pageHasBeenEdited) {
this.$confirm('数据发生改变,是否离开?', {
confirmButtonText: '考虑一下',
cancelButtonText: '直接离开',
type: 'warning'
}).then(confirm).catch(cancel);
} else {
cancel();
}
}
},
beforeRouteLeave(to, from, next) {
next(false);
setTimeout(() => {
this.alertDataChangeConfirm(() => {
}, () => {
next()
});
}, 200);
}
}
</script>
<style lang="less" scoped>
.el-card {
.el-form-item {
margin-bottom: 0;
}
.el-card__header {
background: #F5F7FA;
}
}
.el-divider--horizontal {
margin: 10px 0 20px;
}
.block-margin {
height: 22px;
}
</style>