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.

884 lines
27 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 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">
<div style="display:flex;width: 300px;align-items: center;">
<el-switch v-model="detail.is_simple" active-text="是" inactive-text="否" :active-value="1" :inactive-value="0"/>
<div style="flex: 1;text-align: right;">(水电煤、报刊订阅、网络通讯、车辆使用等费用付款)</div>
</div>
</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">
<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>
</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">
<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>
</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">
<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>
</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">
<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>
</div>
</div>
</template>
<template v-slot:is_framework>
<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.is_framework" active-text="是" inactive-text="否" :active-value="1"
:inactive-value="0"/>
</div>
</div>
</template>
<template v-slot:use_framework_buy>
<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.use_framework_buy" active-text="是" inactive-text="否" :active-value="1"
:inactive-value="0"/>
</div>
</div>
</template>
<template v-slot:contract_to_contracts v-if="detail.use_framework_buy">
<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="width: 300px;" @click="isShowContractToContracts = true">
<template v-if="selections.length > 0">
<template v-for="item in selections">
<Tag closable color="primary" @on-close="delSelections(item)">{{ item.name }}</Tag>
</template>
</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="820" @on-ok="planSelect">
<template>
<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" row-key="id" border default-expand-all :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" @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="planSelect">确定</Button>
</template>
</xy-dialog>
<!-- 新增表 框架合同-->
<el-dialog title="框架协议" :visible.sync="isShowContractToContracts" width="54%">
<Table
:data="contractList"
:columns="contractTable"
:loading="loading"
border
size="small"
@on-selection-change="selectionChange"
></Table>
<div style="display: flex; justify-content: center; margin: 10px 0">
<Page :total="contractTotal"
size="small"
show-elevator
show-total
@on-change="e => {
contractSelect.page = e;
getContractToContracts();
}"/>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="isShowContractToContracts = false">取 消</el-button>
<el-button type="primary" @click="isShowContractToContracts = false">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import {
editorContract,
detailContract,
checkContractName, getContract
} from '@/api/contract/contract'
import {
getBudget
} from "@/api/budget/budget";
import {
getInfo
} from '@/api/user.js'
import {
Message
} from 'element-ui'
import { resetSelect } from '@/utils'
export default {
props: {
purchaseType: Array,
moneyWay: Array,
purchaseWay: 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 {
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: 44,
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,
},
{
label: "实付金额",
prop: 'use_money_total',
width: 120,
align: 'right'
},
{
label: '已用金额',
prop: 'has_money_total',
width: 120,
align: 'right'
}
],
planTotal: 0,
selections: [],
contractSelect: {
page: 1,
page_size: 10,
is_framework: 1
},
contractList: [],
loading: false,
contractTable: [
{
type: "selection",
width: 56,
align: "center",
},
{
title: "项目名称",
key: "name",
minWidth: 180,
align: "left",
},
{
title: "采购形势",
width: 120,
render: (h,{row}) => {
return h('span',{},row.purchase_type?.value || "无")
}
},
{
title: "项目类型",
width: 120,
render: (h,{row}) => {
let map = new Map([
[1,"服务"],
[2,"货物"],
[3,"工程"]
])
return h('span',{},map.get(row.type))
}
},
{
title: "采购方式",
width: 120,
render: (h,{row}) => {
return h('span',{},row.purchase_way?.value || "无")
}
}
],
contractTotal: 0,
isShowContractToContracts: false
}
},
methods: {
//预算计划金额输入
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,
new_money: item.money
}
}
})
this.plan = [...this.detail.plan, ...select]
} 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,
is_tree: 1
})
this.plans = res.list;
this.planTotal = res.list.total || 0;
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) {
var selPlans = [...this.detail.plan, ...this.plan]
if (plans) {
this.plans.forEach(plan => {
if (plans.includes(plan.id)) {
plan.useMoney = selPlans[plans.indexOf(plan.id)].value.use_money
this.$refs.editorPlanTable.toggleRowSelection(plan)
}
if (plan.children?.length > 0) {
plan.children.forEach(cplan => {
if (plans.includes(cplan.id)) {
cplan.useMoney = selPlans[plans.indexOf(cplan.id)].value.use_money
this.$refs.editorPlanTable.toggleRowSelection(cplan)
}
})
}
})
// this.plans.filter(plan => {
// if (plans.includes(plan.id)) {
// plan.useMoney = selPlans[plans.indexOf(plan.id)].value.use_money
// return true
// }
// }).map(row => {
// this.$refs.editorPlanTable.toggleRowSelection(row)
// })
} else {
this.$refs.editorPlanTable.clearSelection()
}
},
async getDetail(id) {
let res = await detailContract({
id: id
})
this.contrantId = res.id
this.selections = []
this.detail = {
name: res.name,
is_simple:res?.is_simple,
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,
is_framework:res.is_framework,
use_framework_buy: res.use_framework_buy,
contract_to_contracts: res.contract_to_contracts,
plan: res.plans.map(item => {
return {
label: item.name,
value: {
plan_id: item.id,
use_money: res.plan_link.filter(item1 => {
return item1.plan_id === item.id
})[0].use_money,
new_money: item.money
}
}
})
}
this.plan = this.detail.plan
},
//y验证合同的名称是否存在重复
checkName(e) {
},
editor() {
editorContract({
id: this.contrantId,
type: this.detail.type,
is_plan: this.detail.isBudget ? 1 : 0,
is_simple:this.detail?.is_simple,
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
}),
is_framework:this.detail.is_framework,
use_framework_buy: this.detail.use_framework_buy,
contract_to_contracts:this.selections.map(i => {
return {
contract_id: this.contrantId,
to_contract_id: i.id,
use_money: i.money
}
})
}).then(res => {
this.isShowEditor = false
Message({
type: 'success',
message: "操作成功"
})
this.$emit('success')
})
},
//框架合同
async getContractToContracts() {
const res = await getContract(this.contractSelect)
let selectedIds = this.selections.map(i => i.id)
this.contractList = res.list.data.map(item => {
return {
...item,
_checked: !!selectedIds.find(i => i === item.id),
}
})
this.contractTotal = res.list.total
},
selectionChange(selection) {
this.selections = Array.from(
new Set(
selection
)
);
},
delSelections(val) {
this.selections.map((item, index) => {
if (item.id === val.id) {
this.selections.splice(index, 1)
}
})
},
},
computed: {
},
watch: {
isShowContractToContracts(val) {
if(val){
this.getContractToContracts();
}else{
resetSelect(this.contractSelect);
this.contractList = [];
this.contractTotal = 0;
}
}
},
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>