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.

800 lines
25 KiB

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.

<template>
<div>
<!-- 编辑-->
<xy-dialog :is-show.sync="isShowEditor" title="合同编辑" type="form" :form="detail" :rules="rules" @submit="editor"
ref="addContract">
<template v-slot:name>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>项目名称
</div>
<div class="xy-table-item-content">
<el-input clearable placeholder="请填写项目名称" @change="checkName" v-model="detail.name" style="width: 300px;" />
</div>
</div>
</template>
<template #contract_carry_department>
<div class="xy-table-item">
<div class="xy-table-item-label">
执行科室
</div>
<div class="xy-table-item-content">
<el-select multiple v-model="detail.contract_carry_department" placeholder="请选择责任科室" style="width: 300px;">
<el-option v-for="item in departments" :value="item.id" :label="item.name"></el-option>
</el-select>
</div>
</div>
</template>
<template v-slot:is_simple>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*是否为简易流程</span>
</div>
<div class="xy-table-item-content">
<el-switch v-model="detail.is_simple" active-text="是" inactive-text="否" :active-value="1" :inactive-value="0"/>
</div>
<div>(水电煤、报刊订阅、网络通讯、车辆使用等费用付款)</div>
</div>
</template>
<template #has_charge>
<div class="xy-table-item">
<div class="xy-table-item-label" style="width: 200px;">
是否为河道处收费类项目
</div>
<div class="xy-table-item-content">
<el-switch v-model="detail.has_charge" active-text="是" inactive-text="否" :active-value="1" :inactive-value="0"/>
</div>
</div>
</template>
<template v-slot:supply v-if="detail.is_simple">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;font-size: 11px;">*</span>承包商/供货商
</div>
<div class="xy-table-item-content">
<el-input v-model="detail.supply" placeholder="请填写承包商/供货商" style="width: 300px;"/>
</div>
</div>
</template>
<template v-slot:type v-if="!detail.is_simple">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>项目类型
</div>
<div class="xy-table-item-content">
<el-select clearable placeholder="请选择项目类型" v-model="detail.type" style="width: 300px;">
<el-option v-for="item in [{label:'服务',value:1},{label:'货物',value:2},{label:'工程',value:3}]"
:label="item.label" :value="item.value"></el-option>
</el-select>
</div>
</div>
</template>
<template v-slot:methods v-if="!detail.is_simple">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>采购形式
</div>
<div class="xy-table-item-content">
<el-select clearable placeholder="请选择采购形式" v-model="detail.methods" style="width: 300px;">
<el-option v-for="item in purchaseType" :label="item.value" :value="item.id"></el-option>
</el-select>
</div>
</div>
</template>
<template v-slot:modality v-if="!detail.is_simple">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>采购方式
</div>
<div class="xy-table-item-content">
<el-select clearable placeholder="请选择采购方式" v-model="detail.modality" style="width: 300px;">
<el-option v-for="item in purchaseWay" :label="item.value" :value="item.id"></el-option>
</el-select>
</div>
</div>
</template>
<template v-slot:price v-if="!detail.is_simple">
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>合同预算价
</div>
<div class="xy-table-item-content xy-table-item-price">
<el-input clearable placeholder="请填写合同预算价" v-model="detail.price" style="width: 300px;" />
</div>
</div>
</template>
<template v-slot:fundingChannels>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>资金渠道
</div>
<div class="xy-table-item-content">
<el-select multiple clearable placeholder="请选择资金渠道" v-model="detail.fundingChannels" style="width: 300px;">
<el-option v-for="item in moneyWay" :value="item.id" :label="item.value"></el-option>
</el-select>
</div>
</div>
</template>
<template v-slot:isBudget>
<div class="xy-table-item">
<div class="xy-table-item-label" style="width: 200px">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>是否为预算内确定项目
</div>
<div class="xy-table-item-content">
<el-switch v-model="detail.isBudget" />
</div>
</div>
</template>
<template v-slot:plan>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>关联预算计划
</div>
<div class="xy-table-item-content">
<div class="contract-add-plan" style="min-width: 300px;" @click="isShowPlan = true,getBudgets()">
<template v-if="detail.plan.length > 0">
<template v-for="item in detail.plan">
<Tag closable color="primary" @on-close="delPlan(item)">{{item.label}}</Tag>
</template>
</template>
<template v-else>
<div class="contract-add-plan-no-plan">请选择关联计划</div>
</template>
</div>
</div>
</div>
</template>
<template v-slot:date v-if="adminEdit">
<div class="xy-table-item">
<div class="xy-table-item-label">合同签订日期
</div>
<div class="xy-table-item-content">
<el-date-picker style="width: 300px;" value-format="yyyy-MM-dd" v-model="detail.date" type="date">
</el-date-picker>
</div>
</div>
</template>
<template v-slot:req_status v-if="adminEdit">
<div class="xy-table-item">
<div class="xy-table-item-label" style="width: 200px">请示流程
</div>
<div class="xy-table-item-content">
<div style="display: flex;">
<el-select v-model="detail.req_status" placeholder="请选择">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
<el-input v-model="oaFlow.qingshi" style="width: 100px;margin-left: 10px;" placeholder="流水号">
</el-input>
</div>
</div>
</div>
</template>
<template v-slot:purchase_status v-if="adminEdit">
<div class="xy-table-item">
<div class="xy-table-item-label" style="width: 200px">采购流程
</div>
<div class="xy-table-item-content">
<div style="display: flex;">
<el-select v-model="detail.purchase_status" placeholder="请选择">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
<el-input v-model="oaFlow.caigou" style="width: 100px;margin-left: 10px;" placeholder="流水号">
</el-input>
</div>
</div>
</div>
</template>
<template v-slot:invite_status v-if="adminEdit">
<div class="xy-table-item">
<div class="xy-table-item-label" style="width: 200px">招标流程
</div>
<div class="xy-table-item-content">
<div style="display: flex;">
<el-select v-model="detail.invite_status" placeholder="请选择">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
<el-input v-model="oaFlow.zhaobiaowenjianshencha" style="width: 100px;margin-left: 10px;" placeholder="流水号">
</el-input>
</div>
</div>
</div>
</template>
<template v-slot:join_status v-if="adminEdit">
<div class="xy-table-item">
<div class="xy-table-item-label" style="width: 200px">
合同会签流程
</div>
<div class="xy-table-item-content">
<div style="display: flex">
<el-select v-model="detail.join_status" placeholder="请选择">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
<el-input v-model="oaFlow.hetonghuiqian" style="width: 100px;margin-left: 10px;" placeholder="流水号">
</el-input>
</div>
</div>
</div>
</template>
<template #gov_plane_id v-if="detail.methods === 1">
<div class="xy-table-item">
<div class="xy-table-item-label">
政府采购项目
</div>
<div class="xy-table-item-content">
<div class="contract-add-plan" style="width: 300px;" @click="$refs['govPlane'].show()">
<template v-if="detail.gov_plane_id">
<Tag closable color="primary" @on-close="detail.gov_plane_id = ''">{{ $refs['govPlane'].selected.name }}</Tag>
</template>
<template v-else>
<div class="contract-add-plan-no-plan">请选择政府采购项目</div>
</template>
</div>
</div>
</div>
</template>
</xy-dialog>
<!-- 编辑中 预算计划 -->
<xy-dialog :is-show.sync="isShowPlan" title="预算计划" :width="640" @on-ok="planSelect">
<template v-slot:normalContent>
<Input v-model="planSearch" search enter-button="搜 索" placeholder="搜索预算计划.." @on-search="getBudgets" />
<xy-table :list="plans" :show-index="false" :table-item="planTable" :height="310" style="margin-top: 10px;"
ref="editorPlanTable" @select="selectPlan">
<template v-slot:btns>
<el-table-column label="使用金额" header-align="center">
<template slot-scope="scope">
<Input :value="scope.row.useMoney" @input="planInput($event,scope.row)" />
</template>
</el-table-column>
</template>
</xy-table>
<div style="display: flex;justify-content: flex-end;">
<Page :total="planTotal" show-elevator @on-change="planPageChange" />
</div>
</template>
<template v-slot:footerContent>
<Button type="primary" @click="isShowPlan = false">确定</Button>
</template>
</xy-dialog>
<govPlane ref="govPlane" @selected="row => detail.gov_plane_id = row.id"></govPlane>
</div>
</template>
<script>
import { httpCurl } from "@/api/contractSign/contractSign"
import {
editorContract,
detailContract,
checkContractName,
updateContract
} from "@/api/contract/contract";
import {
getBudget
} from "@/api/budget/budget";
import {
getInfo
} from '@/api/user.js'
import {
Message
} from 'element-ui'
import govPlane from "@/views/contract/components/govPlane.vue";
import {getOatoken} from "@/api/oatoken";
export default {
components: {govPlane},
props: {
purchaseType: Array,
moneyWay: Array,
purchaseWay: Array,
departments: Array
},
data() {
var planPass = (rule, value, callback) => {
if (this.detail.isBudget) {
if (this.detail.plan.length === 0) {
return callback(new Error('必选'))
} else {
callback()
}
} else {
callback()
}
}
var supplyPass = (rule,value,callback) => {
if(this.detail.is_simple){
if(value === ''){
callback(new Error('必填'))
}else{
callback()
}
}else{
callback()
}
}
var typePass = (rule,value,callback) => {
if(!this.detail.is_simple){
if(value === ''){
callback(new Error('必填'))
}else{
callback()
}
}else{
callback()
}
}
var methodsPass = (rule,value,callback) => {
if(!this.detail.is_simple){
if(value === ''){
callback(new Error('必填'))
}else{
callback()
}
}else{
callback()
}
}
var modalityPass = (rule,value,callback) => {
if(!this.detail.is_simple){
if(value === ''){
callback(new Error('必填'))
}else{
callback()
}
}else{
callback()
}
}
var pricePass = (rule,value,callback) => {
if(!this.detail.is_simple){
if(value === ''){
callback(new Error('必填'))
}else{
if(/^\d+(\.\d+)?$/.test(value)){
callback()
}else{
callback(new Error('必须为数字'))
}
}
}else{
callback()
}
}
return {
oaFlow: {
hetonghuiqian: '',
caigou: '',
zhaobiaowenjianshencha: '',
qingshi: ''
},
userList: ["liuxiangyu", "zhushulan", "admin", "jiangjiao"],
user: null,
adminEdit: false,
isFocus: false,
contrantId: '',
isShowEditor: false,
isShowPlan: false,
detail: {},
plan: [],
options: [{
value: 1,
label: '待申请'
}, {
value: 2,
label: '流转中'
}, {
value: 3,
label: '已办结'
}],
rules: {
name: [{
required: true,
message: "必填"
}],
supply:[
{
validator:supplyPass,
trigger: 'change'
}
],
type:[
{
validator: typePass,
trigger: 'change'
}
],
methods:[
{
validator:methodsPass,
trigger: 'change'
}
],
modality:[
{
validator:modalityPass,
trigger: 'change'
}
],
price:[
{
validator:pricePass,
trigger: 'change'
}
],
fundingChannels: [{
required: true,
message: "必填"
}],
plan: [{
validator: planPass,
trigger: 'change'
}]
},
plans: [],
planSearch: '',
planTable: [{
sortable: false,
width: 36,
type: "selection"
},
{
label: "科室",
prop: 'plan_department.name',
width: 100,
align: 'center'
},
{
label: "年份",
prop: 'year',
width: 80,
align: 'center'
},
{
label: "分类",
prop: 'type',
formatter: (cell, data, value) => {
let res = this.moneyWay.filter(item => {
return item.id === value
})
return res[0]?.value || '未知'
}
},
{
label: "名称",
prop: 'name',
align: 'left',
width: 220,
},
{
label: "计划金额",
prop: 'money',
align: 'right',
width: 120,
}
],
planTotal: 0,
oatoken: '',
}
},
methods: {
async getOaFlow (table) {
const flow_type = new Map([
['caigou',2],
['hetonghuiqian',3],
['qingshi',17],
['zhaobiaowenjianshencha',27]
])
const flow2contractField = new Map([
['caigou',"purchase_status"],
['hetonghuiqian',"join_status"],
['qingshi',"req_status"],
['zhaobiaowenjianshencha',"invite_status"]
])
if (!this.oatoken) {
this.oatoken = (await getOatoken()).oatoken;
}
updateContract({
out_contract_id: this.contrantId,
flow_type: flow_type.get(table),
status: (this.detail[flow2contractField.get(table)] - 2),
flow_id: this.oaFlow[table]
})
},
//预算计划金额输入
planInput(e, row) {
if (!/^[0-9]+.?[0-9]*$/.test(e) && e) {
Message({
type: 'warning',
message: '金额格式错误'
})
row.useMoney = 0
return
}
if (e <= (Number(row.money) - Number(row.use_money_total))) {
row.useMoney = e
this.plan.forEach(item => {
if (item.value.plan_id == row.id) {
item.value.use_money = e
}
})
return
}
Message({
type: 'warning',
message: '使用金额大于剩余预算'
})
row.useMoney = 0
},
//确认计划选择
planSelect() {
if (this.plan.length === 0) {
Message({
type: 'warning',
message: '选择计划不能为空'
})
return
}
for (let item of this.plan) {
console.log(item)
if (!item.value.use_money) {
Message({
type: 'warning',
message: '金额不能为空'
})
return
}
}
this.detail.plan = this.plan
this.isShowPlan = false
},
//选择计划
selectPlan(sel, row) {
if (sel) {
let select = sel.map(item => {
return {
label: item.name,
value: {
plan_id: item.id,
use_money: item.useMoney || 0,
new_money: item.money
}
}
})
// 合并已选计划和新增计划,去重
const existingPlanIds = this.detail.plan.map(p => p.value.plan_id)
const newPlans = select.filter(p => !existingPlanIds.includes(p.value.plan_id))
this.plan = [...this.detail.plan, ...newPlans]
} else {
this.plan = this.detail.plan
}
},
delPlan(val) {
this.detail.plan.map((item, index) => {
if (item.value.plan_id === val.value.plan_id) {
this.detail.plan.splice(index, 1)
}
})
},
//获取预算计划
async getBudgets() {
let res = await getBudget({
name: this.planSearch,
page_size: 10,
page: this.plansPageIndex
})
this.plans = res.list.data
this.planTotal = res.list.total
var selPlans = [...this.detail.plan, ...this.plan]
//let selPlans = this.detail.plan.contact([]);
console.log(selPlans)
this.toggleSelection(selPlans.map(item => {
return item.value.plan_id
}))
},
planPageChange(e) {
this.plansPageIndex = e
this.getBudgets()
},
//默认选择计划
toggleSelection(plans) {
if (plans && plans.length > 0) {
this.plans.forEach(plan => {
const isSelected = plans.includes(plan.id)
if (isSelected) {
const selectedPlan = this.plan.find(p => p.value.plan_id === plan.id)
if (selectedPlan) {
plan.useMoney = selectedPlan.value.use_money
}
this.$nextTick(() => {
this.$refs.editorPlanTable.toggleRowSelection(plan, true)
})
}
})
} else {
this.$refs.editorPlanTable.clearSelection()
}
},
async getDetail(id) {
let res = await detailContract({
id: id
})
this.contrantId = res.id
this.detail = {
name: res.name,
is_simple: res?.is_simple,
has_charge: res?.has_charge,
date: res.date,
req_status: res.req_status,
purchase_status: res.purchase_status,
join_status: res.join_status,
invite_status: res.invite_status,
supply: res?.supply,
type: res.type,
methods: res.purchase_type_id,
modality: res.purchase_way_id,
fundingChannels: res.money_way_id.split(',').map(item => {
return Number(item)
}),
price: res.plan_price,
isBudget: res.is_plan === 1 ? true : false,
plan: res.plans.map(item => {
const planLink = res.plan_link.find(link => link.plan_id === item.id)
return {
label: item.name,
value: {
plan_id: item.id,
use_money: planLink ? planLink.use_money : 0,
new_money: item.money
}
}
}),
gov_plane_id: res.gov_plane_id,
gov_plane: res.gov_plane,
contract_carry_department: res.contract_carry_department.map(i => i.carry_department_id)
}
this.plan = [...this.detail.plan]
this.$refs['govPlane'].selected = res.gov_plane
},
//y验证合同的名称是否存在重复
checkName(e) {
},
editor() {
const flow2contractField = new Map([
['caigou',"purchase_status"],
['hetonghuiqian',"join_status"],
['qingshi',"req_status"],
['zhaobiaowenjianshencha',"invite_status"]
])
for (let key in this.oaFlow) {
if (this.oaFlow[key] && this.detail[flow2contractField.get(key)] && this.detail[flow2contractField.get(key)] !== 1) {
this.getOaFlow(key).then(res => {
})
}
}
editorContract({
id: this.contrantId,
type: this.detail.type,
is_plan: this.detail.isBudget ? 1 : 0,
is_simple:this.detail?.is_simple,
has_charge: this.detail?.has_charge,
supply:this.detail?.supply,
purchase_type_id: this.detail.methods,
purchase_way_id: this.detail.modality,
money_way_id: this.detail.fundingChannels.toString(),
plan_price: this.detail.price,
name: this.detail.name,
req_status: this.detail.req_status,
purchase_status: this.detail.purchase_status,
join_status: this.detail.join_status,
invite_status: this.detail.invite_status,
date: this.detail.date,
contract_plan_links: this.detail.plan.map(item => {
return item.value
}),
gov_plane_id: this.detail.gov_plane_id,
contract_carry_department: this.detail.contract_carry_department.map(i => ({carry_department_id: i}))
}).then(res => {
this.isShowEditor = false
Message({
type: 'success',
message: "操作成功"
})
this.$emit('success')
})
},
},
computed: {
},
mounted() {
let that = this;
getInfo().then(response => {
console.log(response)
this.user = response;
if (that.userList.indexOf(response.username) != -1) {
that.adminEdit = true;
}
}).catch(error => {})
}
}
</script>
<style scoped lang="scss">
.contract-add-plan {
min-height: 30px;
border: 1px solid #dcdee2;
border-radius: 4px;
display: flex;
flex-wrap: wrap;
align-items: center;
align-content: center;
padding: 0 8px;
&-no-plan {
height: 30px;
line-height: 30px;
color: #CDD0D5;
}
}
.xy-table-item-label {
width: 200px;
}
.xy-table-item-price {
position: relative;
&::after {
z-index: 1;
position: absolute;
right: 0;
top: 0;
content: ''
}
::v-deep .el-input__clear {
position: relative;
right: 30px;
z-index: 2;
}
}
.xy-table-item-price-wan {
position: relative;
&::after {
position: absolute;
right: 0;
top: 0;
content: ''
}
::v-deep .el-input__clear {
position: relative;
right: 46px;
z-index: 2;
}
}
</style>