fourcal/src/main/resources/templates/admin/business/process-edit.ftl

1162 lines
43 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<#assign base=request.contextPath />
<#import "../../common/defaultLayout.ftl" as defaultLayout>
<@defaultLayout.layout>
<link rel="stylesheet" href="${base}/element-ui/element-ui.css">
<style>
#businessPurchaseDetailsModal {
overflow: auto;
}
#businessPurchaseDetailsModal > table {
}
#procurementContractProcess {
overflow: auto;
}
.el-upload__input {
display: none !important;
}
.el-textarea .el-input__count {
line-height: 15px;
}
.admin-content-body {
margin-bottom: 100px;
}
.el-table__empty-block {
height: 60px !important;
}
.el-upload-list__item-name [class^="el-icon"] {
height: unset;
}
.el-checkbox {
margin-right: 10px;
}
.supplierChoose {
margin-bottom: 20px;
}
[v-cloak] {
display: none;
}
.el-table .warning-row {
background: oldlace;
}
.el-table .child-row {
background: #f0f9eb;
}
</style>
<div class="admin-content" id="app">
<div class="admin-content-body">
<div class="am-cf am-padding">
<div class="am-fl am-cf"><strong class="am-text-primary am-text-lg">{{title}}</strong> /
<small v-cloak>{{subTitle}}</small></div>
</div>
<div class="am-g" v-cloak>
<#-- 新增销售合同流程 -->
<div class="am-u-sm-12 am-u-md-12" v-if="isSalesContractMode || isProcurementContractMode">
<el-form :inline="true" ref="contractProcessForm" :model="processForm" label-position="right" label-width="110px">
<div class="am-form-inline">
<el-form-item label="项目编号">
<span>{{processForm.projectNo}}</span>
</el-form-item>
<el-form-item label="项目标题">
<span>{{processForm.projectTitle}}</span>
</el-form-item>
<el-form-item label="申请时间">
<span>{{processForm.applyDate}}</span>
</el-form-item>
<el-form-item label="采购模式" v-if="isProcurementContractMode">
<el-select v-model="processForm.procurementMode" placeholder="请选择采购模式">
<#list procurementMode as item>
<el-option label="${item.description}" value="${item.name()}"></el-option>
</#list>
</el-select>
</el-form-item>
<el-form-item label="项目类型" v-if="isSalesContractMode">
<span>{{processForm.projectTypeDesc}}</span>
</el-form-item>
<el-form-item label="合作类型">
<span>{{processForm.cooperationTypeDesc}}</span>
</el-form-item>
</div>
<div>
<el-form-item label="申请部门" :rules="[{ required: true, message: '申请部门不能为空'}]" prop="applyDeptId">
<el-cascader :options="applyDeptSectorOptions" clearable v-model="processForm.applyDeptId"
:props="{ expandTrigger: 'hover', label:'name', value: 'id'}" @change="applyDeptSelected">
<template slot-scope="{ node, data }">
<span>{{ data.name }}</span>
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
</template>
</el-cascader>
</el-form-item>
<el-form-item label="申请人">
<span>{{processForm.applyPersonName}}</span>
</el-form-item>
<el-form-item label="申请部门领导">
<span>{{processForm.applyDeptLeaderName}}</span>
</el-form-item>
<el-form-item v-if="isSalesContractMode" label="申请人电话" prop="applyPersonPhone"
:rules="[{ required: true, message: '申请人电话不能为空'}]">
<el-input placeholder="请输入内容" v-model="processForm.applyPersonPhone"></el-input>
</el-form-item>
</div>
<div>
<el-form-item label="合同编号" :rules="[{ required: true, message: '合同编号不能为空'}]" prop="contractNo">
<el-input placeholder="请输入合同编号" v-model="processForm.contractNo"></el-input>
</el-form-item>
<el-form-item v-if="isSalesContractMode" label="合同名称" :rules="[{ required: true, message: '合同名称不能为空'}]"
prop="contractName">
<el-input placeholder="请输入合同名称" v-model="processForm.contractName"></el-input>
</el-form-item>
<el-form-item v-if="isProcurementContractMode" label="采购合同名称"
:rules="[{ required: true, message: '采购合同名称不能为空'}]" prop="contractName">
<el-input placeholder="请输入采购合同名称" v-model="processForm.contractName"></el-input>
</el-form-item>
<el-form-item label="合同金额">
<span>{{processForm.contractAmount}}元</span>
</el-form-item>
</div>
<div>
<el-form-item v-if="isSalesContractMode" label="客户名称" :rules="[{ required: true, message: '客户名称不能为空'}]">
<el-input placeholder="请输入客户名称" v-model="processForm.clientName"></el-input>
</el-form-item>
<el-form-item v-if="isProcurementContractMode" label="供应商名称" :rules="[{ required: true, message: '供应商名称不能为空'}]">
<el-input placeholder="请输入供应商" v-model="processForm.supplierName"></el-input>
</el-form-item>
<el-form-item label="最终用户名称">
<span>{{processForm.terminalCustomer}}</span>
</el-form-item>
</div>
<div>
<el-form-item label="用印类型" :rules="[{ required: true, message: '用印类型不能为空'}]">
<el-checkbox-group v-model="processForm.sealTypes">
<#list sealTypes as sealType>
<el-checkbox label="${sealType.name()}" key="key-${sealType.name()}">${sealType.description}</el-checkbox>
</#list>
</el-checkbox-group>
</el-form-item>
</div>
<div>
<el-form-item label="税率" :rules="[{ required: true, message: '税率不能为空'}]" prop="taxRate">
<el-select v-model="processForm.taxRate" placeholder="请选择税率">
<#list taxRate as rate>
<el-option label="${rate}%" value="${rate}"></el-option>
</#list>
</el-select>
</el-form-item>
<el-form-item label="是否垫资">
<span>{{processForm.isPrepaid}}</span>
</el-form-item>
<el-form-item label="垫资金额">
<span>{{processForm.repaidAmount}}</span>
</el-form-item>
<el-form-item label="预算毛利率">
<span>{{processForm.budgetGrossMargin}}</span>
</el-form-item>
</div>
<div>
<el-form-item v-if="isSalesContractMode" label="收款条件" prop="paymentTerms"
:rules="[{ required: true, message: '收款条件不能为空'}]">
<el-input type="textarea" :autosize="{ minRows: 5, maxRows: 10}" cols="90" maxlength="5000" show-word-limit
v-model="processForm.paymentTerms" placeholder="请输入收款条件限制5000字"></el-input>
</el-form-item>
<el-form-item v-if="isProcurementContractMode" label="付款条件" prop="paymentTerms"
:rules="[{ required: true, message: '付款条件不能为空'}]">
<el-input type="textarea" :autosize="{ minRows: 5, maxRows: 10}" cols="90" maxlength="5000" show-word-limit
v-model="processForm.paymentTerms" placeholder="请输入付款条件限制5000字"></el-input>
</el-form-item>
</div>
<div>
<el-form-item label="备注">
<el-input type="textarea" :autosize="{ minRows: 5, maxRows: 10}" maxlength="5000" show-word-limit
v-model="processForm.remark" placeholder="请输入备注限制5000字" cols="90"></el-input>
</el-form-item>
</div>
<div>
<el-form-item label="上传附件" :rules="[{ required: true, message: '未上传附件'}]">
<el-upload class="upload-demo"
action="${base}/file/upload"
name="files[]"
:on-remove="handleRemove"
:before-remove="beforeRemove"
:before-upload="beforeUpload"
:on-success="handleFileUploaded"
:limit="10" :file-list="fileList"
:on-exceed="handleExceed"
accept=".rar,.zip,.7z,.doc,.docx,.pdf,.xls,.xlsx,.png,.jpg,.jpeg,.gif,.bmp">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传PDF、excel、word、图片、压缩包且不超过50MB</div>
</el-upload>
</el-form-item>
</div>
<div>
<el-form-item label="合同清单明细">
<el-button type="text" @click="goToContractDetail">详细清单</el-button>
</el-form-item>
</div>
</el-form>
<#-- 供应商比选材料 -->
<div class="am-u-sm-12 am-u-md-12 supplierChoose" v-if="isProcurementContractMode">
<el-alert title="供应商比选材料" type="success" center :closable="false"></el-alert>
<el-table style="width: 100%" border :data="supplierMaterialsForm" v-model="supplierMaterialsForm" empty-text="暂无">
<el-table-column type="index" :index="1" label="序号" fixed></el-table-column>
<el-table-column prop="companyName" label="公司名称" width="180" align="center">
<template slot-scope="scope">
<el-input size="mini" placeholder="请输入公司名称" v-model="scope.row.companyName"></el-input>
</template>
</el-table-column>
<el-table-column prop="totalAmount" label="合计金额" width="160" align="center">
<template slot-scope="scope">
<el-input-number size="mini" :precision="2" :step="0.1" :max="100" :min="0"
v-model="scope.row.totalAmount" controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column prop="serviceTerms" label="服务条款" width="180" align="center">
<template slot-scope="scope">
<el-input size="mini" placeholder="请输入服务条款" v-model="scope.row.serviceTerms"></el-input>
</template>
</el-table-column>
<el-table-column prop="paymentTerms" label="付款条件" align="center">
<template slot-scope="scope">
<el-input size="mini" placeholder="请输入付款条件" v-model="scope.row.paymentTerms"></el-input>
</template>
</el-table-column>
<el-table-column prop="taxRate" label="税率(%" width="160" align="center">
<template slot-scope="scope">
<el-input-number size="mini" :precision="2" :step="0.1" :max="100" :min="0"
v-model="scope.row.taxRate" controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" align="center">
<template slot-scope="scope">
<#--
<el-input type="textarea" size="mini" maxlength="100"
v-model="scope.row.remark" placeholder="请输入备注限制100字" cols="90"></el-input>
-->
<el-input size="mini" placeholder="请输入备注"
v-model="scope.row.remark"></el-input>
</template>
</el-table-column>
<el-table-column prop="attachment" label="附件" align="center" width="150">
<template slot-scope="scope">
<el-upload :file-list="scope.row.fileList"
:limit="10" size="mini" name="files[]" action="${base}/file/upload"
accept=".rar,.zip,.7z,.doc,.docx,.pdf,.xls,.xlsx,.png,.jpg,.jpeg,.gif,.bmp"
:on-remove="(_, fileList) => handleSupplierMaterialRemove(scope, fileList)"
:before-remove="(file, fileList) => beforeSupplierMaterialRemove(scope, file, fileList)"
:on-success="(response, file, fileList) => handleSupplierMaterialFileUploaded(scope, response, file, fileList)"
:on-exceed="(files, fileList) => handleSupplierMaterialExceed(scope, files, fileList)">
<el-button size="small" type="text">上传附件</el-button>
</el-upload>
</template>
</el-table-column>
<el-table-column width="49" fixed="right">
<template slot-scope="scope">
<el-popconfirm title="确定删除吗?填写的表单将丢弃" @confirm="removeSupplierMaterialRow(scope)">
<el-button slot="reference" type="danger" icon="el-icon-delete" circle size="mini"></el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-button type="primary" icon="el-icon-plus" circle size="mini" @click="addSupplierRow"
style="float: right;margin: 10px 10px 0 0"></el-button>
</div>
<el-row class="am-u-sm-12 am-u-md-12" v-cloak>
<el-button type="info" @click="backLastPage">返回上一级</el-button>
<el-button type="primary" @click="saveDraft">保存草稿</el-button>
<el-button type="success" @click="submitForm">提交</el-button>
</el-row>
</div>
<#-- 销售合同清单明细 -->
<div class="am-u-sm-12 am-u-md-12" v-if="isSaleContractDetailMode">
<el-table border :data="incomeDetails">
<el-table-column type="index" :index="1" label="序号" fixed></el-table-column>
<el-table-column prop="name" label="名称" fixed width="120"></el-table-column>
<el-table-column prop="type" label="类别"></el-table-column>
<el-table-column prop="spec" label="规格型号"></el-table-column>
<el-table-column prop="param" label="参数"></el-table-column>
<el-table-column prop="amount" label="数量"></el-table-column>
<el-table-column prop="unit" label="单位"></el-table-column>
<el-table-column prop="price" label="单价(元)" width="120"></el-table-column>
<el-table-column prop="taxRate" label="税率(%"></el-table-column>
<el-table-column prop="totalTaxInclude" label="含税金额(元)" width="120"></el-table-column>
<el-table-column prop="totalTaxExclude" label="不含税金额(元)" width="120"></el-table-column>
<el-table-column prop="totalTax" label="税金(元)" width="120"></el-table-column>
<el-table-column prop="expirationDate" label="质保期" fixed="right" width="150">
<template slot-scope="scope">
<el-input maxlength="5" size="mini" placeholder="请输入质保期" v-model="scope.row.expirationDate"
oninput="value=value.replace(/[^\d\u4E00-\u9FA5]/g, '')" show-word-limit>
</el-input>
</template>
</el-table-column>
</el-table>
<el-row style="margin: 20px 0">
<el-button type="primary" @click="submitToSaleContractProcess">保存并返回上一级</el-button>
</el-row>
</div>
<#-- 业务采购清单明细 -->
<div v-cloak class="am-u-sm-12 am-u-md-12" v-if="isProcurementContractDetailMode">
<el-table border :data="procurementDetails" row-key="rowKey" default-expand-all :row-class-name="procurementDetailRowClassName">
<el-table-column type="index" :index="1" label="序号" fixed></el-table-column>
<el-table-column prop="feeType" label="费用项目" width="100" fixed></el-table-column>
<el-table-column prop="name" label="产品名称" fixed></el-table-column>
<el-table-column prop="category" label="采购类别" fixed></el-table-column>
<el-table-column prop="amount" label="数量"></el-table-column>
<el-table-column prop="unit" label="单位"></el-table-column>
<el-table-column prop="price" label="预算单价" width="100"></el-table-column>
<el-table-column prop="taxRate" label="税率(%"></el-table-column>
<el-table-column prop="totalTaxInclude_" label="含税总金额(元)" width="120"></el-table-column>
<el-table-column prop="totalTaxExclude" label="不含税金额(元)" width="120"></el-table-column>
<el-table-column prop="totalTax" label="税金(元)" width="110"></el-table-column>
<el-table-column prop="isUnderwrittenDesc" label="是否垫资"></el-table-column>
<el-table-column prop="payTime" label="支出时间" width="160"></el-table-column>
<el-table-column prop="payAmount" label="支出金额(元)" width="120"></el-table-column>
<el-table-column prop="amountAlready" label="已采购数量" width="100"></el-table-column>
<el-table-column prop="amountCurrent" label="本次采购数量" width="180">
<template slot-scope="scope">
<span v-if="scope.row.newRow"></span>
<el-input-number v-else :precision="2" :step="0.1" :min="0" v-model="scope.row.amountCurrent"
:disabled="scope.row.amount - scope.row.amountAlready===0" size="mini"
:max="scope.row.amount - scope.row.amountAlready" controls-position="right">
</el-input-number>
</template>
</el-table-column>
<el-table-column prop="amountLeft" label="未采购数量" width="100">
<template slot-scope="scope">
<span v-if="scope.row.amount && scope.row.amountAlready">{{scope.row.amount - scope.row.amountAlready}}</span>
</template>
</el-table-column>
<el-table-column prop="supplierName" label="供应商名称" width="200">
<template slot-scope="scope">
<el-input size="mini" placeholder="请输入供应商名称" v-model="scope.row.supplierName"></el-input>
</template>
</el-table-column>
<el-table-column prop="manufacturerName" label="设备厂商名称" width="200">
<template slot-scope="scope">
<el-input size="mini" placeholder="请输入设备厂商名称" v-model="scope.row.manufacturerName"></el-input>
</template>
</el-table-column>
<el-table-column prop="purchaseList" label="对应采购清单" width="200">
<template slot-scope="scope">
<el-input size="mini" placeholder="请输入对应采购清单" v-model="scope.row.purchaseList"></el-input>
</template>
</el-table-column>
<el-table-column prop="spec" label="规格型号" width="200">
<template slot-scope="scope">
<el-input size="mini" placeholder="请输入规格型号" v-model="scope.row.spec"></el-input>
</template>
</el-table-column>
<el-table-column prop="procurementAmount" label="对应采购数目" width="200">
<template slot-scope="scope">
<el-input-number size="mini" :precision="2" :step="0.1" :min="0"
v-model="scope.row.procurementAmount" controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column prop="procurementPrice" label="采购单价" width="200">
<template slot-scope="scope">
<el-input-number size="mini" :precision="2" :step="1" :min="0"
v-model="scope.row.procurementPrice" controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column prop="totalTaxInclude" label="含税总金额(元)" width="200">
<template slot-scope="scope">
<el-input-number size="mini" :precision="2" :step="0.1" :min="0"
v-model="scope.row.totalTaxInclude" controls-position="right"></el-input-number>
</template>
</el-table-column>
<el-table-column width="49" fixed="right">
<template slot-scope="scope">
<el-popconfirm v-if="scope.row.newRow" title="确定删除吗?填写的表单将丢弃" @confirm="removeProcurementDetailRow(scope)">
<el-button slot="reference" type="danger" icon="el-icon-delete" circle size="mini"></el-button>
</el-popconfirm>
<el-button v-else type="primary" icon="el-icon-plus" circle size="mini"
@click="addProcurementDetailRow(scope)"></el-button>
</template>
</el-table-column>
</el-table>
<el-row style="margin: 20px 0">
<el-button type="primary" @click="saveProcurementContractDetail">保存并返回上一级</el-button>
</el-row>
</div>
</div>
</div>
</div>
<script src="${base}/vue/vue.js"></script>
<script src="${base}/element-ui/element-ui.js"></script>
<script>
const procurementContractDetail = "procurementContractDetail"
const procurementContractProcess = "procurementContractProcess"
const saleContractProcess = "saleContractProcess"
const saleContractDetail = "saleContractDetail"
const BUTTON = "btn"
const saleContract = "sale_contract"
const procurementContract = "procurement_contract"
const procurementDetailProperties = [
"spec",
"amount",
"purchaseList",
"amountCurrent",
"supplierName",
"totalTaxInclude",
"manufacturerName",
"procurementPrice",
"procurementAmount"
]
const isEmpty = (obj) => {
if (!obj) {
return true
}
if (obj.hasOwnProperty('length')) {
return obj.length === 0
}
return false
}
const isNotEmpty = (obj) => {
return !isEmpty(obj)
}
const isBlank = (obj) => {
return isEmpty(obj) || (obj.trim && isEmpty(obj.trim()))
}
const hasText = (obj) => {
return !isBlank(obj)
}
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response
}
else {
const error = new Error(response.statusText);
error.response = response
throw error
}
}
function parseJSON(response) {
return response.json()
}
const hasProperties = obj => {
return isNotEmpty(Object.keys(obj));
}
const data = () => {
return {
mode: "btn", // btn
processForm: {
sealTypes: [],
applyDeptId: []
},
processType: '',
projectSelected: false,
applyDeptSectorOptions: [],
fileList: [],
// 销售合同收入明细
incomeDetails: [],
supplierMaterialsForm: [],
rowKeyCounter: 0,
procurementDetails: [],
}
}
const methods = {
changeMode(mode) {
this.mode = mode
},
backLastPage() {
window.history.back();
},
goToSaleContractProcess() {
this.changeMode(saleContractProcess)
},
goToProcurementContract() {
this.changeMode(procurementContractProcess)
this.processType = procurementContract
},
/**
* 校验不通过提示
* @returns {boolean} 校验通过否
*/
checkProcurementDetails() {
const emptyRows = this.procurementDetails.filter(detail => {
return isNotEmpty(procurementDetailProperties.filter(property => isBlank(detail[property])))
})
if (isNotEmpty(emptyRows)) {
this.procurementDetails.forEach(detail => {
const properties = procurementDetailProperties.filter(property => isBlank(detail[property]))
console.log(properties)
})
const row = emptyRows[0]
this.$message.error("合同清单明细 费用项目为:'" + row.feeType + "' 采购类别为:'" + row.category + "' 的数据未填写")
return false
}
return true
},
/**
* 保存 业务采购合同清单明细,返回上一级的表单界面
*/
saveProcurementContractDetail() {
this.goToProcurementContract()
},
goToContractDetail() {
const { projectId } = this.processForm
if (projectId) {
// 选择了才能编辑详情
if (this.isSalesContractMode) {
this.changeMode(saleContractDetail)
}
else if (this.isProcurementContractMode) {
this.changeMode(procurementContractDetail)
}
}
else {
this.$message.warning("项目还未选择")
}
},
render(obj) {
console.log(obj)
},
resetForm() {
this.initForm({})
this.fileList = []
this.rowKeyCounter = 0
this.incomeDetails = []
this.projectSelected = false
this.procurementDetails = []
this.supplierMaterialsForm = []
},
initForm(form) {
this.processForm = { ...form }
},
loadProject(id) {
const loading = this.$loading({
lock: true,
text: '正在加载项目',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
fetch("${base}/process/" + id)
.then(checkStatus)
.then(parseJSON)
.then(data => {
const {
incomeDetails, process, supplierMaterials,
contract, procurementDetails, attachments, ...form
} = data
// 转换数据
// @formatter:off
const computeType = type => {
switch (type) {
case 1: return '设备'
case 2: return '工程'
case 3: return '服务'
default: return '未知'
}
}
const computeFeeType = type => {
switch (type) {
case 1: return '设备'
case 2: return '施工'
case 3: return '服务'
case 4: return '其他'
default: return '未知'
}
}
// @formatter:on
const applyDeptId = process?.applyDeptId?.split(',').map(id => parseInt(id))
this.initForm({ ...form, ...process, ...contract, applyDeptId })
this.projectSelected = true
this.processType = process.processType
this.incomeDetails = incomeDetails && incomeDetails.map(detail => ({
...detail, type: computeType(detail.type)
}))
this.fileList = attachments.map(item => ({
name: item.name, url: item.uri
}))
const mapAttachment = attachment => {
if (hasText(attachment)) {
try {
return JSON.parse(attachment).map(item => ({
name: item.name, url: item.uri
}))
} catch (e) {
return []
}
}
else {
return []
}
}
this.supplierMaterialsForm = supplierMaterials && supplierMaterials.map(material => ({
...material, attachment: mapAttachment(material.attachment)
}))
let rowKey = 0
const convertCommon = detail => {
return {
rowKey: rowKey++, feeType: computeFeeType(detail.type),
totalTaxInclude_: detail.totalTaxInclude, // 存在相同字段转换一下
}
}
const computeProcurementDetails = procurementDetails => {
const ret = []
for (let detail of procurementDetails || []) {
//父级数据
const parent = {
...detail, ...convertCommon(detail),
}
// mapChildren
let { purchaseDetails } = parent
if (isNotEmpty(purchaseDetails)) {
// 先取出第一个合并
const first = purchaseDetails.shift();
// 再处理剩余的子元素
purchaseDetails = purchaseDetails.map(purchase => ({
...purchase, rowKey: rowKey++, parent, newRow: true
}))
// 合并第一行到父级
Object.assign(parent, first)
delete parent['parent']
delete parent['purchaseDetails']
parent['children'] = purchaseDetails
}
ret.push(parent)
}
return ret
}
this.procurementDetails = computeProcurementDetails(procurementDetails)
this.rowKeyCounter = rowKey
if (process.processType === saleContract) {
this.changeMode(saleContractProcess)
}
else if (process.processType === procurementContract) {
this.changeMode(procurementContractProcess)
}
})
.catch(({ response }) => {
if (response) {
parseJSON(response)
.then(json => {
this.$message.error(json.message || "项目加载失败");
})
}
else {
this.$message.error("项目加载失败")
}
})
.finally(() => loading.close())
},
clearProjectProcess() {
this.resetForm()
},
saveDraft() {
this.processForm.status = 'draft'
this.submit(false)
},
submitForm() {
this.processForm.status = 'to_be_audit'
this.submit(true)
},
submit(needValid) {
const fileList = this.fileList
const processForm = this.processForm
const processType = this.processType
const supplierMaterialsForm = this.supplierMaterialsForm
let validStatus = !needValid
if (needValid) {
// 校验表单
this.$refs["contractProcessForm"].validate((valid) => {
if (valid) {
if (fileList.length === 0) {
this.$message.error("未上传附件");
return false
}
if (processType === saleContract) {
if (!this.checkExpirationDate()) {
return false
}
}
// 采购合同需要验证 供应商比选材料
if (processType === procurementContract) {
if (!this.checkProcurementDetails()) {
return false
}
const { procurementMode } = processForm
// specify_purchase("指定采购"),
// simple_price_comparison("简单比价"),
// price_comparison("比价"),
// competitive_evaluation("竞争性评估");
// 当“采购模式”为“指定采购”“简单比价”时,本模块为非必填模块,当为“比价”“竞争性评估”时,本模块为必填项(“备注”除外)
if (procurementMode === 'price_comparison'
|| procurementMode === 'competitive_evaluation') {
if (isEmpty(supplierMaterialsForm)) {
this.$message.error("供应商比选材料未填写,请检查表单")
return false
}
let idx = 0
for (const item in supplierMaterialsForm) {
idx++
if (isEmptyObject(item)) {
this.$message.error("供应商比选材料第'" + idx + "'行未填写,请检查表单")
return false
}
for (const [key, value] of Object.entries(item)) {
if (value) {
if (typeof value === 'string') {
if (isBlank(value)) {
this.$message.error("供应商比选材料第'" + idx + "'行有数据未填写,请检查表单")
return false
}
}
}
else {
// 没有值
if (key !== 'remark') {
this.$message.error("供应商比选材料第'" + idx + "'行有数据未填写,请检查表单")
}
}
}
}
}
}
if (!processForm.applyDeptId) {
this.$message.error("申请部门还未选择");
return false
}
// 验证通过
validStatus = true
return true;
}
else {
return false
}
})
}
if (!validStatus) {
return false
}
const budgetCostIdMap = new Map()
this.procurementDetails.forEach(detail => {
budgetCostIdMap.set(detail.budgetCostId, detail)
})
const computePurchaseAmountDetail = budgetCostId => {
const detail = budgetCostIdMap.get(budgetCostId)
const ret = []
const map = detail => {
const ret = { id: detail.id }
procurementDetailProperties.forEach(property => {
ret[property] = detail[property]
})
return ret
}
ret.push(map(detail))
detail.children.forEach(detail => {
ret.push(map(detail))
})
return ret
}
const mapAttachment = attachments => {
return attachments && JSON.stringify(attachments.map(file => ({
uri: file.response.data.url,
name: file.response.data.originName
})))
}
const form = {
...processForm,
processType,
applyDeptId: processForm.applyDeptId?.join(','), // (逗号分割),
attachments: fileList.map(file => {
if (file.url) {
return { uri: file.url, name: file.name }
}
return { uri: file.response.data.url, name: file.name }
}),
incomeDetails: this.incomeDetails.map(detail => ({
id: detail.id, expirationDate: detail.expirationDate
})),
purchaseAmount: this.procurementDetails.map(detail => ({
amount: detail.amount,
amountId: detail.amountId,
budgetCostId: detail.budgetCostId,
amountAlready: detail.amountAlready,
amountCurrent: detail.amountCurrent,
details: computePurchaseAmountDetail(detail.budgetCostId)
})),
supplierMaterials: supplierMaterialsForm.filter(hasProperties).map(item => ({
...item, attachment: mapAttachment(item.attachment)
})),
}
const loading = this.$loading({
lock: true,
text: processForm.status === 'draft' ? '正在保存草稿' : "正在提交",
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
fetch("${base}/process/" + form.processId, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(form),
}).then(checkStatus).then(data => {
this.$message({
showClose: true,
message: processForm.status === 'draft' ? '草稿保存成功' : "提交成功",
type: 'success',
onClose: () => {
this.resetForm()
this.backLastPage()
}
})
}).catch(({ response }) => {
const defaultMessage = () => {
return processForm.status === 'draft' ? '草稿保存失败' : "项目提交失败"
}
if (response) {
parseJSON(response)
.then(json => {
this.$message.error(json.message || defaultMessage())
})
}
else {
this.$message.error(defaultMessage())
}
}).finally(() => loading.close())
},
submitToSaleContractProcess() {
this.goToSaleContractProcess()
},
handleRemove(file, fileList) {
this.fileList = fileList
},
handleExceed(files, fileList) {
this.$message.warning("当前限制选择只能选择10个文件");
this.fileList = fileList
},
beforeRemove(file, fileList) {
return this.$confirm("确定移除 " + file.name + "");
},
beforeUpload(file) {
if (file.size > 50 * 1024 * 1024) {
this.$message.warning("上传文件大小不能超过 50MB");
return false;
}
},
handleFileUploaded(response, file, fileList) {
if (response.success) {
this.fileList = fileList
}
else {
this.$message.warning("上传失败");
}
},
handleSupplierMaterialRemove(scope, fileList) {
scope.row['attachment'] = fileList
},
handleSupplierMaterialExceed(scope, files, fileList) {
this.$message.warning("当前限制选择只能选择10个文件");
scope.row['attachment'] = fileList
},
beforeSupplierMaterialRemove(scope, file, fileList) {
return this.$confirm("确定移除 " + file.name + "");
},
handleSupplierMaterialFileUploaded(scope, response, file, fileList) {
if (response.success) {
scope.row['attachment'] = fileList
}
else {
this.$message.warning("上传失败");
}
},
indexMethod(index) {
return index * 1;
},
addSupplierRow() {
this.supplierMaterialsForm.push({
rowKey: this.rowKeyCounter++,
})
},
addProcurementDetailRow(scope) {
const { row } = scope
const { children } = row
const newRow = {
...row,
rowKey: this.rowKeyCounter++,
newRow: true,
parent: row // 记录上一级元素,在删除的时候使用
}
delete newRow['children']
if (children) {
row['children'].push(newRow)
}
else {
row['children'] = [newRow]
}
scope.store.table.toggleRowExpansion(row, true)
},
removeProcurementDetailRow(scope) {
const { rowKey, parent } = scope.row
parent.children = parent.children.filter(child => child.rowKey !== rowKey)
},
// 区别子项
procurementDetailRowClassName({ row, rowIndex }) {
if (row.parent) {
// 有父项说明就是子项
return 'child-row';
}
return '';
},
removeSupplierMaterialRow(scope) {
const { rowKey } = scope.row
this.supplierMaterialsForm = this.supplierMaterialsForm.filter(child => child.rowKey !== rowKey)
},
applyDeptSelected(value) {
if (value.length === 0) {
this.processForm['applyDept'] = null
this.processForm['applyDeptId'] = null
this.processForm['applyDeptLeaderId'] = null
this.processForm['applyDeptLeaderName'] = null
return;
}
const level1Value = value[0]
const level2Value = value.length >= 2 && value[1]
const level3Value = value.length === 3 && value[2]
const find = (options, value) => {
return options.find(option => option.id === value)
}
const leveled = []
let selected = find(this.applyDeptSectorOptions, level1Value)
leveled.push(selected)
if (selected && level2Value) {
selected = find(selected.children, level2Value)
leveled.push(selected)
if (selected && level3Value) {
selected = find(selected.children, level3Value)
if (selected) {
leveled.push(selected)
}
}
}
// applyDeptId 提交时处理
this.processForm['applyDept'] = leveled.map(level => level.name).join(',') // (逗号分割)
this.processForm['applyDeptLeaderId'] = selected.leaderId
this.processForm['applyDeptLeaderName'] = selected.leaderName
},
}
new Vue({
el: '#app',
data,
computed: {
isButtonMode() {
return this.mode === BUTTON
},
isProcurementContractMode() {
return this.mode === procurementContractProcess
},
isProcurementContractDetailMode() {
return this.mode === procurementContractDetail
},
isSalesContractMode() {
return this.mode === saleContractProcess
},
isSaleContractDetailMode() {
return this.mode === saleContractDetail
},
title() {
switch (this.mode) {
case saleContractDetail:
case procurementContractDetail:
return "新增流程"
default:
return "业务应用"
}
},
subTitle() {
switch (this.mode) {
case BUTTON:
return "编辑流程"
case saleContractProcess:
return "编辑销售合同流程"
case saleContractDetail:
return "编辑销售合同清单明细"
case procurementContractDetail:
return "编辑业务采购合同清单明细"
case procurementContractProcess:
return "编辑业务采购合同流程"
}
}
},
methods,
mounted() {
const processId = ${processId}
this.loadProject(processId)
this.applyDeptSectorOptions = JSON.parse('${applyDeptSectorOptions}')
},
})
</script>
</@defaultLayout.layout>