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.

3490 lines
112 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 ref="contractList" style="padding: 0 20px;">
<lx-header icon="md-apps" style="margin-bottom: 10px; border: 0px; margin-top: 15px" text="合同列表">
<div slot="content"></div>
<slot>
<div class="selects">
<div>
<span style="padding: 0 6px;word-break: keep-all;">关键字</span>
<span>
<Input v-model="select.keyword" clearable placeholder="关键字搜索" style="width: 200px"/>
</span>
</div>
<div>
<span style="padding: 0 6px;word-break: keep-all;">服务商/供应商</span>
<span>
<Input v-model="select.supply" clearable placeholder="请输入服务商/供应商" style="width: 200px"/>
</span>
</div>
<div>
<span style="padding: 0 6px;word-break: keep-all;">预算计划</span>
<span>
<Input v-model="select.plan_name" clearable placeholder="请选择预算计划" @on-focus="showPlanForSearch()"
style="width: 200px" @on-clear="clearSelectForSearch"/>
</span>
</div>
<div>
<span style="padding: 0 6px;word-break: keep-all;">签订年份</span>
<span>
<DatePicker :value="select.year" placeholder="选择年份" placement="bottom" style="width: 90px;"
type="year"
@on-change="(e)=>select.year = e"></DatePicker>
</span>
</div>
<div>
<span style="padding: 0 6px;word-break: keep-all;">创建日期</span>
<span>
<DatePicker v-model="select.showDatePicker" clearable placeholder="请选择日期" placement="bottom-start"
style="width: 200px" type="daterange" @on-change="datePick"></DatePicker>
</span>
</div>
<div>
<span style="padding: 0 6px;word-break: keep-all;">
项目类型
</span>
<Select v-model="select.type" clearable placeholder="请选择项目类型" style="width:140px;">
<Option v-for="item in type" :key="item.value" :value="item.value">{{ item.label }}</Option>
</Select>
</div>
<div>
<span style="padding: 0 6px;word-break: keep-all;">
业务科室
</span>
<el-select v-model="select.department_id" clearable placeholder="业务科室选择" size="small"
style="width: 120px;">
<el-option v-for="item in departments" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</div>
<div>
<span style="padding: 0 6px;word-break: keep-all;">
采购形式
</span>
<Select v-model="select.purchase_type_id" clearable placeholder="请选择采购形式" style="width:140px;">
<Option v-for="item in purchaseType" :key="item.id" :value="item.id">{{ item.value }}</Option>
</Select>
</div>
<div>
<span style="padding: 0 6px;word-break: keep-all;">
采购方式
</span>
<Select v-model="select.purchase_way_id" clearable placeholder="请选择采购方式" style="width:200px;">
<Option v-for="item in purchaseWay" :key="item.id" :value="item.id">{{ item.value }}</Option>
</Select>
</div>
<div>
<span style="padding: 0 6px;word-break: keep-all;">
预算金额
</span>
<el-input-number size="small" :controls="false" v-model="select.start_plan_price" :min="0" placeholder="最小金额" style="width: 100px;"/>
<span style="padding: 0 5px;">-</span>
<el-input-number size="small" :controls="false" v-model="select.end_plan_price" :min="0" placeholder="最大金额" style="width: 100px;"/>
</div>
<div>
<span style="padding: 0 6px;word-break: keep-all;">
合同状态
</span>
<Select v-model="select.status" clearable placeholder="请选择" style="width:100px;">
<Option v-for="item in [{label:'待签订',value:1},{label:'已签订',value:2}]" :key="item.value"
:value="item.value">{{ item.label }}
</Option>
</Select>
</div>
<div>
<span style="padding: 0 6px;word-break: keep-all;">
招标流程状态
</span>
<Select v-model="select.invite_status" clearable placeholder="请选择" style="width:100px;">
<Option v-for="item in options" :key="item.value" :value="item.value">{{ item.label }}
</Option>
</Select>
</div>
<div>
<span style="padding: 0 6px;word-break: keep-all;">
采购流程状态
</span>
<Select v-model="select.purchase_status" clearable placeholder="请选择" style="width:100px;">
<Option v-for="item in options" :key="item.value" :value="item.value">{{ item.label }}
</Option>
</Select>
</div>
<div>
<span style="padding: 0 6px;word-break: keep-all;">
合同会签状态
</span>
<Select v-model="select.join_status" clearable placeholder="请选择" style="width:100px;">
<Option v-for="item in options" :key="item.value" :value="item.value">{{ item.label }}
</Option>
</Select>
</div>
<div>
<span style="padding: 0 6px;word-break: keep-all;">
请示流程状态
</span>
<Select v-model="select.req_status" clearable placeholder="请选择" style="width:100px;">
<Option v-for="item in options" :key="item.value" :value="item.value">{{ item.label }}
</Option>
</Select>
</div>
<Button style="margin-left: 10px" type="primary" @click="handleAddContract">新增</Button>
<Button style="margin-left: 10px" type="primary" @click="getContracts">查询</Button>
<Button ghost style="margin-left: 10px" type="primary"
@click=" select = {showDatePicker:'',ageIndex:1,startDate:'',endDate:'',type:'',department:'',purchaseModality:'',purchaseMethods:'',priceMin:null,priceMax:null,status:''}">
重置
</Button>
<Button type="primary" @click="downloadExel()" style="margin-left: 10px">导出</Button>
<!-- <Button type="primary" style="margin-left: 10px">导出</Button>-->
</div>
</slot>
</lx-header>
<xy-table ref="xyTable" :cell-style="cellStyle" :list="list" :show-summary="true" :summary-method="summary"
:table-item="table" @cellClick="showPaymentPlan" @delete="(row)=>deleteContract(row.id)" @editor="">
<template v-slot:btns>
<el-table-column fixed="right" header-align="center" label="操作" width="200">
<template slot-scope="scope">
<div class="slot-btns">
<template v-if="scope.row.status === 2&&scope.row.is_end===0">
<template v-if="scope.row.is_assurance==1">
<!-- 如果是 履约文件-->
<template v-if="scope.row.assurance_status==1">
<!-- 那么必须财务审核通过-->
<Button class="slot-btns-item" size="small" type="primary"
@click="$refs['paymentRegistration'].getContract(scope.row),$refs['paymentRegistration'].isShowPaymentRegistration = true">
付款登记
</Button>
</template>
</template>
<template v-else>
<Button class="slot-btns-item" size="small" type="primary"
@click="$refs['paymentRegistration'].getContract(scope.row),$refs['paymentRegistration'].isShowPaymentRegistration = true">
付款登记
</Button>
</template>
</template>
<template v-if="scope.row.status === 1 && scope.row.join_status === 3">
<Button class="slot-btns-item" size="small" type="primary"
@click="$refs['contractSign'].isShow = true,$refs['contractSign'].contractId = scope.row.id">
签订合同
</Button>
</template>
<template
v-if="scope.row.invite_status === 1 && scope.row.purchase_status === 3 && (scope.row.purchase_way ? scope.row.purchase_way.remark === 'true' : false) && !scope.row.is_substitute">
<Button class="slot-btns-item" size="small" type="primary" @click="bidding(scope.row)">招标审查</Button>
</template>
<!-- <Button class="slot-btns-item" type="primary" size="small">附件管理</Button>-->
<template v-if="scope.row.req_status === 1 && (scope.row.is_plan === 0 && !scope.row.is_substitute || scope.row.has_charge)">
<Button class="slot-btns-item" size="small" type="primary" @click="askProcess(scope.row)">请示流程
</Button>
</template>
<!--不需要走采购流程那么直接就是会签,如果采购方式不需要招标的也是直接会签-->
<template
v-if="(scope.row.has_charge && scope.row.req_status === 3 && scope.row.join_status === 1) || (scope.row.join_status === 1 && ((scope.row.invite_status === 3)||((scope.row.purchase_way ? scope.row.purchase_way.remark === 'false' : false) && scope.row.purchase_status === 3)) || ( scope.row.is_substitute && scope.row.join_status === 1) ) ">
<Button class="slot-btns-item" size="small" type="primary" @click="signProcess(scope.row)">合同会签
</Button>
</template>
<template
v-if="!scope.row.has_charge && scope.row.is_simple !== 1 && scope.row.purchase_status === 1 && ((scope.row.req_status === 3 && scope.row.is_plan === 0)||scope.row.is_plan === 1)&& !scope.row.is_substitute ">
<Button class="slot-btns-item" size="small" type="primary" @click="buyProcess(scope.row)">采购流程
</Button>
</template>
<Poptip trigger="hover" placement="bottom" transfer>
<Button ghost size="small" type="primary">更多</Button>
<div slot="content">
<template
v-if="!(scope.row.req_status != 1 || scope.row.join_status != 1 || scope.row.invite_status != 1 || scope.row.purchase_status != 1 || scope.row.status === 2)">
<Poptip :transfer="true" confirm placement="bottom" title="确认要删除吗"
@on-ok="()=>deleteContract(scope.row.id)">
<i-button class="slot-btns-item" ghost size="small" type="error">删除
</i-button>
</Poptip>
</template>
<Button class="slot-btns-item" size="small" type="primary"
@click="$refs['detailContract'].getDetail(scope.row.id),$refs['detailContract'].isShowDetail = true">
查看
</Button>
<template v-if="scope.row.status != 2||hasEdit">
<Button class="slot-btns-item" size="small" type="primary"
@click="handleEdit(scope.row)">编辑
</Button>
</template>
<template v-if="hasEdit&&scope.row.status === 2">
<Button class="slot-btns-item" size="small" type="primary"
@click="$refs['contractSign'].isShow = true,$refs['contractSign'].contractId = scope.row.id">
签订修改
</Button>
</template>
</div>
</Poptip>
</div>
</template>
</el-table-column>
</template>
</xy-table>
<div style="display: flex;justify-content: flex-end;">
<Page :total="total" show-elevator @on-change="pageChange" show-sizer @on-page-size-change="pageSizeChange"/>
</div>
<!-- 新增合同模态框 -->
<Modal
v-model="isShowAdd"
:title="isEditMode ? '编辑合同' : '新增合同'"
width="800"
:mask-closable="false"
:closable="false"
class="contract-add-modal"
>
<!-- Steps Header -->
<div class="steps-header">
<div class="step" :class="{ active: currentStep === 1 }">
<span class="step-number">1</span>
<span class="step-text">选择类型</span>
</div>
<div class="step" :class="{ active: currentStep === 2 }">
<span class="step-number">2</span>
<span class="step-text">基本信息</span>
</div>
<div class="step" :class="{ active: currentStep === 3 }">
<span class="step-number">3</span>
<span class="step-text">附件信息</span>
</div>
</div>
<!-- Step Content -->
<div class="step-content">
<!-- Step 1: Type Selection -->
<div v-show="currentStep === 1" class="step-content">
<div class="form-group">
<label class="form-label">分类</label>
<Select v-model="form.category" @on-change="handleCategoryChange" placeholder="请选择分类" class="form-input">
<Option v-for="item in categoryOptions" :key="item.id" :value="item.id">{{ item.name }}</Option>
</Select>
</div>
<div class="form-group">
<label class="form-label">事项类型</label>
<Select v-model="form.affairType" @on-change="handleAffairTypeChange" placeholder="请选择事项类型" class="form-input">
<Option v-for="item in affairTypeOptions" :key="item.id" :value="item.id">{{ item.name }}</Option>
</Select>
</div>
<div class="form-group">
<label class="form-label">合同类型</label>
<Select v-model="form.contractType" @on-change="handleContractTypeChange" placeholder="请选择合同类型" class="form-input">
<Option v-for="item in contractTypeOptions" :key="item.id" :value="item.id">{{ item.name }}</Option>
</Select>
</div>
<div class="form-group">
<label class="form-label">采购形式</label>
<Select v-model="form.purchaseForm" @on-change="handlePurchaseFormChange" placeholder="请选择采购形式" class="form-input">
<Option v-for="item in purchaseFormOptions" :key="item.id" :value="item.id">{{ item.name }}</Option>
</Select>
</div>
<div class="form-group">
<label class="form-label">采购方式</label>
<Select v-model="form.purchaseMethod" @on-change="handlePurchaseMethodChange" placeholder="请选择采购方式" class="form-input">
<Option v-for="item in purchaseMethodOptions" :key="item.id" :value="item.id">{{ item.name }}</Option>
</Select>
</div>
</div>
<!-- Step 2: Basic Information -->
<div v-show="currentStep === 2" class="step-content">
<!-- 选择的合同模版类型信息 -->
<div class="template-info">
<div class="info-title">合同类型</div>
<div class="info-content">
<div class="info-item">
<span class="label">合同分类:</span>
<span class="value">{{ getCategoryName(form.category) }}</span>
</div>
<div class="info-item">
<span class="label">事务类型:</span>
<span class="value">{{ getAffairTypeName(form.affairType) }}</span>
</div>
<div class="info-item">
<span class="label">合同类型:</span>
<span class="value">{{ getContractTypeName(form.contractType) }}</span>
</div>
<div class="info-item">
<span class="label">采购形式:</span>
<span class="value">{{ getPurchaseFormName(form.purchaseForm) }}</span>
</div>
<div class="info-item">
<span class="label">采购方式:</span>
<span class="value">{{ getPurchaseMethodName(form.purchaseMethod) }}</span>
</div>
</div>
</div>
<!-- 流程控制 -->
<div class="form-section">
<div class="section-title">合同配置</div>
<div class="process-control-grid">
<div class="control-item">
<div class="control-label">是否为简易流程</div>
<div class="control-content">
<el-radio-group v-model="form.is_simple">
<el-radio :label="0">否</el-radio>
<el-radio :label="1">是</el-radio>
</el-radio-group>
<div class="helper-text">(水电煤、报刊订阅、网络通讯、车辆使用等费用付款)</div>
</div>
</div>
<div class="control-item">
<div class="control-label">是否为河道处收费类项目</div>
<div class="control-content">
<el-radio-group v-model="form.has_charge">
<el-radio :label="0">否</el-radio>
<el-radio :label="1">是</el-radio>
</el-radio-group>
</div>
</div>
<div class="control-item">
<div class="control-label">是否为预算内确定项目</div>
<div class="control-content">
<el-radio-group v-model="form.isBudget">
<el-radio :label="0">否</el-radio>
<el-radio :label="1">是</el-radio>
</el-radio-group>
</div>
</div>
<div class="control-item">
<div class="control-label">是否为代建项目</div>
<div class="control-content">
<el-radio-group v-model="form.is_substitute">
<el-radio :label="0">否</el-radio>
<el-radio :label="1"></el-radio>
</el-radio-group>
</div>
</div>
</div>
</div>
<!-- 基本信息表单 -->
<div class="form-section">
<div class="section-title">基本信息</div>
<el-form :model="form" label-width="140px" ref="basicInfoForm">
<el-form-item label="项目名称" prop="name" :rules="[{ required: true, message: '请输入项目名称', trigger: 'submit' }]" v-show="showFields.projectName">
<el-input v-model="form.name" placeholder="请输入项目名称"></el-input>
</el-form-item>
<el-form-item label="项目类型" prop="type" :rules="[{ required: true, message: '请选择项目类型', trigger: 'submit' }]" v-show="showFields.projectType">
<el-select v-model="form.type" placeholder="请选择项目类型" style="width: 100%">
<el-option v-for="item in type" :key="item.value" :value="item.value" :label="item.label"></el-option>
</el-select>
</el-form-item>
<!-- 新增承包商/供应商输入框 -->
<el-form-item
label="承包商/供应商"
prop="supply"
:rules="[{ required: form.is_simple === 1, message: '请输入承包商/供应商', trigger: 'submit' }]"
v-show="form.is_simple === 1">
<el-input v-model="form.supply" placeholder="请输入承包商/供应商"></el-input>
</el-form-item>
<!-- 新增执行科室选择 -->
<el-form-item label="执行科室" prop="contract_carry_department" :rules="[{ required: true, message: '请选择执行科室', trigger: 'submit' }]">
<div class="department-selector">
<el-select
v-model="form.contract_carry_department"
placeholder="请选择执行科室"
style="width: 100%"
multiple
collapse-tags
@remove-tag="removeDepartment">
<el-option
v-for="item in departments"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
<div class="department-tags" v-if="form.contract_carry_department && form.contract_carry_department.length > 0">
<el-tag
v-for="id in form.contract_carry_department"
:key="id"
closable
@close="removeDepartment(id)">
{{ getDepartmentName(id) }}
</el-tag>
</div>
</div>
</el-form-item>
<el-form-item label="合同预算金额(元)" prop="price" :rules="[{ required: true, message: '请输入预算金额', trigger: 'submit' }]" v-show="showFields.budgetPrice">
<el-input-number v-model="form.price" :min="0" :precision="2" :step="1000" style="width: 100%"></el-input-number>
</el-form-item>
<el-form-item label="资金渠道" prop="moneyWay" :rules="[{ required: true, message: '请选择资金渠道', trigger: 'submit' }]" v-show="showFields.fundChannel">
<div class="money-way-selector">
<el-select
v-model="form.moneyWay"
placeholder="请选择资金渠道"
style="width: 100%"
multiple
collapse-tags
@remove-tag="removeMoneyWay">
<el-option
v-for="item in moneyWay"
:key="item.id"
:label="item.value"
:value="item.id">
</el-option>
</el-select>
<div class="money-way-tags" v-if="form.moneyWay && form.moneyWay.length > 0">
<el-tag
v-for="id in form.moneyWay"
:key="id"
closable
@close="removeMoneyWay(id)">
{{ getMoneyWayName(id) }}
</el-tag>
</div>
</div>
</el-form-item>
<el-form-item label="关联预算计划" prop="plan" v-show="showFields.budgetPlan" :rules="[{ required: true, message: '请选择关联预算计划', trigger: 'change' }]">
<div class="plan-selector">
<el-input
v-model="form.plan_display"
placeholder="请选择预算计划"
readonly
class="plan-input"
@focus="showPlanForSearch('modal')">
</el-input>
<div class="plan-tags" v-if="form.plan && form.plan.length > 0">
<el-tag
v-for="item in form.plan"
:key="item.id"
closable
@close="removePlan(item)">
{{ item.label }}
</el-tag>
</div>
</div>
</el-form-item>
</el-form>
</div>
</div>
<!-- Step 3: Attachment Information -->
<div v-show="currentStep === 3" class="step-content">
<!-- 事前支付表格 -->
<div v-if="form.before_contract_template && !form.showAfterPayment" class="form-section">
<div class="section-title">事前支付表格</div>
<div ref="beforePaymentForm" v-html="form.before_forms || form.before_contract_template.template"></div>
</div>
<!-- 事后支付表格 -->
<div v-else-if="form.contract_template" class="form-section">
<div class="section-title">事后支付表格</div>
<div ref="afterPaymentForm" v-html="form.forms || form.contract_template.template"></div>
</div>
<!-- 无支付表格提示 -->
<div v-else class="form-section">
<div class="section-title">无支付表格</div>
<div class="no-payment-form">当前选择的合同类型没有配置支付表格</div>
</div>
</div>
</div>
<div slot="footer">
<div class="modal-footer">
<Button v-if="currentStep > 1" @click="prevStep" class="action-button">上一步</Button>
<Button v-if="currentStep < 3" type="primary" @click="nextStep" class="action-button">下一步</Button>
<!-- 当有事前支付表格且未显示事后支付表格时 -->
<template v-if="currentStep === 3 && form.before_contract_template && !form.showAfterPayment">
<!-- 新增模式下显示跳过按钮 -->
<template v-if="!isEditMode">
<Button type="primary" @click="nextPaymentStep" class="action-button">下一步</Button>
<Button @click="skipPrePayment" class="action-button">跳过,稍后填写</Button>
</template>
<!-- 编辑模式下只有当before_forms为空时才显示跳过按钮 -->
<template v-else-if="(!form.before_forms || form.before_forms.trim() === '' || !form.skipBeforeTemplate)">
<Button type="primary" @click="nextPaymentStep" class="action-button">下一步</Button>
<Button @click="skipPrePayment" class="action-button">跳过,稍后填写</Button>
</template>
<!-- 编辑模式下如果before_forms不为空只显示下一步按钮 -->
<template v-else>
<Button type="primary" @click="nextPaymentStep" class="action-button">下一步</Button>
</template>
</template>
<!-- 当显示事后支付表格时 -->
<template v-else-if="currentStep === 3 && form.contract_template">
<!-- 新增模式下显示跳过按钮 -->
<template v-if="!isEditMode">
<Button type="primary" @click="submit" class="action-button">提交</Button>
<Button @click="skipPostPayment" class="action-button">跳过,稍后填写</Button>
</template>
<!-- 编辑模式下只有当forms为空时才显示跳过按钮 -->
<template v-else-if="(!form.forms || form.forms.trim() === '' || !form.skipAfterTemplate)">
<Button type="primary" @click="submit" class="action-button">提交</Button>
<Button @click="skipPostPayment" class="action-button">跳过,稍后填写</Button>
</template>
<!-- 编辑模式下如果forms不为空只显示提交按钮 -->
<template v-else>
<Button type="primary" @click="submit" class="action-button">提交</Button>
</template>
</template>
<!-- 当没有支付表格时,只显示"提交"按钮 -->
<Button v-else-if="currentStep === 3" type="primary" @click="submit" class="action-button">提交</Button>
<Button @click="cancel" class="action-button">取消</Button>
</div>
</div>
</Modal>
<!-- 搜索使用 预算计划 -->
<xy-dialog :is-show.sync="isShowPlanForSearch" title="预算计划" :width="720" @on-ok="planSelectForSearch">
<template v-slot:normalContent>
<Input v-model="planSearch.name" search enter-button="搜 索" placeholder="搜索预算计划.."
@on-search="searchBudgets"/>
<div style="margin: 10px 0;display: flex;justify-content: space-between;align-items: center;">
<div v-if="planSource === 'search'">已选择:<span style="margin-right:10px">{{ select.plan_name }}</span></div>
<div v-if="planSource === 'modal'">已选择:<span style="margin-right:10px">{{ form.plan_display }}</span></div>
<el-link type="success" @click="clearSelectForSearch">清空选择</el-link>
</div>
<xy-table :list="plans" @rowClick="selectPlanForSearch" :show-index="false" :table-item="planTableSearch"
:height="310" style="margin-top: 10px;" ref="singlePlanTable">
<template v-slot:btns>
<el-table-column label="使用金额" header-align="center" v-if="planSource === 'modal'">
<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>
<el-tag type="warning">点击行进行选择</el-tag>
</template>
<template v-slot:footerContent>
<Button type="primary" @click="planSelectForSearch">确定</Button>
</template>
</xy-dialog>
<!-- 新增表 预算计划 -->
<xy-dialog :is-show.sync="isShowPlan" :width="720" title="预算计划" @on-ok="planSelect">
<template v-slot:normalContent>
<div style="display: flex;">
<el-select placeholder="科室选择" clearable size="small" v-model="planSearch.plan_department_id"
style="width: 160px;">
<el-option v-for="item in departments" :label="item.name" :value="item.id" :key="item.id">
</el-option>
</el-select>
<Input v-model="planSearch.name" enter-button="搜 索" placeholder="搜索预算计划.." search
@on-search="searchBudgets"/>
</div>
<xy-table ref="planTable" :height="300" :list="plans" :show-index="false" :table-item="planTable"
style="margin-top: 10px;" @select="selectPlan">
<template v-slot:btns>
<el-table-column header-align="center" label="使用金额" fixed="right" width="140">
<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>
<!-- 编辑-->
<editor ref="editor" :departments="departments" :is-show-editor.sync="isShowEditor" :money-way="moneyWay" :purchase-type="purchaseType"
:purchase-way="purchaseWay" @success="getContracts"></editor>
<!-- 查看-->
<detail ref="detailContract"></detail>
<!--付款登记-->
<paymentRegistration ref="paymentRegistration"></paymentRegistration>
<!-- 合同签订-->
<contractSign ref="contractSign" @signSuccess="getContracts"></contractSign>
<!-- 查看付款计划-->
<contractPaymentRegistration ref="contractPaymentRegistration"></contractPaymentRegistration>
<govPlane ref="govPlane" @selected="row => form.gov_plane_id = row.id"></govPlane>
</div>
</template>
<script>
import {
getContract,
addContrant,
delContract,
checkContractName,
editorContract
} from "@/api/contract/contract"
import {
getparameter
} from "@/api/system/dictionary"
import {
getContractCategoryTemplateBaseConfig,
getContractCategoryTemplateConfigParams,
getContractFormList
} from '@/api/businessConfig/businessConfig'
import {
listdeptNoAuth
} from "@/api/system/department";
import {
getBudget
} from "@/api/budget/budget"
import {
getOatoken
} from "@/api/oatoken"
import {
parseTime
} from "@/utils"
import {
Message
} from "element-ui";
import {
getInfo
} from '@/api/user.js'
import {
getToken
} from '@/utils/auth'
import editor from "./components/editorContract"
import detail from "./components/detailContract"
import paymentRegistration from "./components/paymentRegistration";
import contractSign from "@/views/contract/components/contractSign";
import contractPaymentRegistration from "@/views/contract/components/contractPaymentRegistration";
import govPlane from './components/govPlane.vue';
import {
download
} from '@/utils/downloadRequest'
export default {
components: {
editor,
detail,
paymentRegistration,
contractSign,
contractPaymentRegistration,
govPlane,
},
data() {
var planPass = (rule, value, callback) => {
if (this.form.isBudget) {
if (this.form.plan.length === 0) {
callback(new Error('必选'))
} else {
callback()
}
} else {
callback()
}
}
var supplyPass = (rule,value,callback) => {
if(this.form.is_simple){
if(value === ''){
callback(new Error('必填'))
}else{
callback()
}
}else{
callback()
}
}
var moneyPass = (rule,value,callback) => {
if(this.form.is_simple){
if(value === ''){
callback(new Error('必填'))
}else{
if(/^\d+(\.\d+)?$/.test(value)){
callback()
}else{
callback(new Error('必须为数字'))
}
}
}else{
callback()
}
}
var typePass = (rule,value,callback) => {
if(!this.form.is_simple){
if(value === ''){
callback(new Error('必填'))
}else{
callback()
}
}else{
callback()
}
}
var methodsPass = (rule,value,callback) => {
if(!this.form.is_simple){
if(value === ''){
callback(new Error('必填'))
}else{
callback()
}
}else{
callback()
}
}
var modalityPass = (rule,value,callback) => {
if(!this.form.is_simple){
if(value === ''){
callback(new Error('必填'))
}else{
callback()
}
}else{
callback()
}
}
var pricePass = (rule,value,callback) => {
if(!this.form.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"],
window: {
width: 0,
height: 0,
top: 0,
left: 0
},
hasEdit: false,
// 添加控制显示/隐藏的变量
showFields: {
purchaseMethod: true,
projectName: true,
projectType: true,
budgetPrice: true,
fundChannel: true,
budgetPlan: true,
request: true,
purchaseApproval: true,
tenderReview: true,
contractSign: true
},
planSource: 'search',
isShowPlanForSearch: false,
options: [{
value: "",
label: '全部'
}, {
value: 1,
label: '待申请'
}, {
value: 2,
label: '流转中'
}, {
value: 3,
label: '已办结'
}],
//搜索
select: {
keyword: '',
showDatePicker: '',
pageIndex: 1,
pageSize: 10,
startDate: "",
endDate: "",
type: "",
department_id: "",
purchaseModality: "",
purchaseMethods: "",
priceMin: null,
priceMax: null,
status: "",
year: "",
plan_id: "",
plan_name: "请选择预算计划",
start_plan_price: undefined,
end_plan_price: undefined,
},
type: [{
label: '服务',
value: 1
}, {
label: '货物',
value: 2
}, {
label: '工程',
value: 3
}],
purchaseType: [], //购买形式
purchaseWay: [], //购买方式
moneyWay: [], //资金渠道
departments: [], //部门科室
list: [], //数据
total: 0,
//表格
table: [{
label: "项目名称",
width: 380,
prop: 'name',
fixed: 'left',
align: 'left'
},
{
label: "采购形式",
width: 120,
prop: 'purchase_type.value',
formatter:(cell, data, value) => {
return value ? value : '无'
}
},
{
label: "项目类型",
width: 120,
prop: 'type',
formatter: (cell, data, value) => {
switch (value) {
case 1:
return "服务"
break;
case 2:
return "货物"
break;
case 3:
return "工程"
break;
default:
return "无"
}
}
},
{
label: "采购流程",
multiHd: [{
label: "请示流程",
width: 140,
prop: 'req_status',
formatter: (cell, data, value) => {
if (cell.is_substitute && !cell.has_charge) {
return '无'
}
if (cell.is_plan === 1 && !cell.has_charge) {
return '无'
}
switch (value) {
case 1:
return "待申请"
break;
case 2:
return "流转中"
break;
case 3:
return "已办结"
break;
default:
return "异常"
break;
}
}
},
{
label: "采购业务审批流程",
width: 158,
prop: 'purchase_status',
formatter: (cell, data, value) => {
if (cell.is_substitute || cell.is_simple) {
return '无'
}
switch (value) {
case 1:
return "待申请"
break;
case 2:
return "流转中"
break;
case 3:
return "已办结"
break;
default:
return "异常"
break;
}
}
},
{
label: "招标审核流程",
width: 145,
prop: 'invite_status',
formatter: (cell, data, value) => {
if (cell.is_substitute || cell.is_simple) {
return '无'
}
if (cell.purchase_way?.remark === 'false') {
return '无'
}
switch (value) {
case 1:
return "待申请"
break;
case 2:
return "流转中"
break;
case 3:
return "已办结"
break;
default:
return "异常"
break;
}
}
},
{
label: "合同会签流程",
width: 145,
prop: 'join_status',
formatter: (cell, data, value) => {
if(cell.is_simple){
return "无"
}
switch (value) {
case 1:
return "待申请"
break;
case 2:
return "流转中"
break;
case 3:
return "已办结"
break;
default:
return "异常"
break;
}
}
}
]
},
{
label: "采购方式",
width: 120,
prop: "purchase_way.value",
formatter:(cell,data,value) => {
return value ? value : "无"
}
},
{
label: "资金渠道",
width: 320,
align: "left",
customFn: (row) => {
return row.money_way_detail.map(item => item.value).join('')
}
},
{
label: "预算计划",
width: 320,
align: "left",
customFn: (row) => {
return row.plans.map(item => {
return (
<div>
[{item.year}] - {item.name}
</div>
)
})
}
},
{
label: '已申请金额(元)',
prop: 'apply_money_total',
width: 140,
align: 'right',
formatter: (cell, data, value) => {
return Number(value).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
}
},
{
label: '已付金额(元)',
prop: 'fund_log_total',
width: 140,
align: 'right',
formatter: (cell, data, value) => {
return Number(value).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
}
},
{
label: '支付占比',
width: 140,
customFn: (row) => {
let per = ((((row.fund_log_total) / row.money) || 0) * 100)?.toFixed(2) || 0
return `${per}%`
}
},
{
label: "合同预算价(元)",
width: 140,
prop: "plan_price",
align: 'right',
formatter: (v1, v2, value) => {
return Number(value).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
}
},
{
label: '合同签订价(元)',
width: 140,
prop: 'money',
align: 'right',
formatter: (cell, data, value) => {
return Number(value).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
}
},
{
label: "合同状态",
width: 120,
prop: "status",
formatter: (cell, data, value) => {
switch (value) {
case 1:
return "待签订"
break;
case 2:
return "已签订"
break;
default:
return "未知"
}
}
},
{
label: "结算状态",
width: 120,
prop: "is_end",
formatter: (cell, data, value) => {
return value === 0 ? "未结清" : "已结清";
}
},
{
label: '付款计划',
prop: 'sign_plan_count',
width: 120,
formatter: (cell, data, value) => {
if (value == 0) return '暂无'
return value + '期'
}
},
{
label: "供应商/服务商",
width: 220,
prop: 'supply',
align: "left"
},
{
label: "业务科室",
width: 140,
prop: 'department.name'
},
{
label: "经办人",
width: 140,
prop: 'admin.name'
},
{
label: "签订日期",
width: 160,
prop: 'date',
formatter: (cell, data, value) => {
if (value)
return parseTime(new Date(value), "{y}-{m}-{d}")
}
},
{
label: "创建日期",
width: 160,
prop: 'created_at',
formatter: (cell, data, value) => {
return parseTime(new Date(value), "{y}-{m}-{d}")
}
},
{
label: "执行科室",
minWidth: 200,
prop: "contract_carry_department",
customFn: row => {
return row.contract_carry_department.map(i => i.carry_department.name).join('')
}
}
],
//总计
tableTotal: {
fundLogTotal: 0,
moneyTotal: 0,
planPriceTotal: 0
},
planTypes: [],
planTableSearch: [{
label: "分类",
prop: 'type',
formatter: (cell, data, value) => {
let res = this.moneyWay.filter(item => {
return item.id === value
})
return res[0]?.value || '未知'
}
},
{
label: "年份",
prop: 'year',
align: 'center'
},
{
label: "名称",
prop: 'name',
align: 'left'
},
{
label: "计划金额",
prop: 'money',
align: 'right',
width: 120,
customFn: (row) => {
let m1 = row.money;
let m2 = row.update_money;
return m2 == 0 ? m1 : m2;
}
}
],
planTable: [{
width: 36,
sortable: false,
type: 'selection',
fixed: "left"
},
{
label: "分类",
prop: 'type',
formatter: (cell, data, value) => {
let res = this.moneyWay.filter(item => {
return item.id === value
})
return res[0]?.value || '未知'
},
width: 100,
fixed: "left"
},
{
label: "科室",
prop: 'plan_department.name',
width: 100,
align: 'center'
},
{
label: "年份",
prop: 'year',
width: 80,
align: 'center'
},
{
label: "隶属",
prop: 'pid_info.name',
width: 180,
align: 'left'
},
{
label: "名称",
prop: 'name',
width: 320,
align: 'left'
},
{
label: "计划金额",
prop: 'money',
align: 'right',
width: 120,
customFn: (row) => {
let m1 = row.money;
let m2 = row.update_money;
return m2 == 0 ? m1 : m2;
}
},
{
label: "已用金额",
prop: 'use_money_total',
width: 120,
align: 'right'
},
],
//新增
isShowAdd: false,
currentStep: 1,
form: {
category: '',
affairType: '',
contractType: '',
purchaseForm: '',
purchaseSubForm: '',
purchaseMethod: '',
forms:'',
before_forms:'',
originBeforeForms:'',
originAfterForms:'',
other_data:[],
before_other_data:[],
skipBeforeTemplate:false,
skipAfterTemplate:false,
name: '',
type: '', // 项目类型
moneyWay: [],
plan: [],
plan_display: '', // 预算计划显示文本
price: 0,
supply: '',
// 流程控制字段
is_simple: 0, // 是否为简易流程
has_charge: 0, // 是否为河道处收费类项目
isBudget: 0, // 是否为预算内确定项目
is_substitute: 0, // 是否为代建项目
// 新增流程控制字段
request: 0, // 请示流程
purchaseApproval: 0, // 采购业务审批流程
tenderReview: 0, // 招标文件审查流程
contractSign: 0, // 合同会签流程
expenses: [
{
content: '',
amount: 0,
ratio: '',
payee: ''
}
],
showAfterPayment: false, // 是否显示事后支付表格
contract_carry_department: [] // 新增执行科室字段
},
categoryOptions: [],
purchaseMethodsMap: {},
affairTypeOptions: [],
contractTypeOptions: [],
purchaseFormOptions: [],
purchaseMethodOptions: [],
isShowPlan: false, //新增中预算计划
plans: [], //预算数据
planSearch: {
name: "",
plan_department_id: ""
},
planTotal: 0,
plansPageIndex: 1,
isShowEditor: false,
contractTypes: [
{ label: '设备采购', value: 'equipment' },
{ label: '工程合同', value: 'project' },
{ label: '服务合同', value: 'service' }
],
plan: [], // 添加这个来存储选中的预算计划
isEditMode: false, // 添加编辑模式标识
currentContractId: null, // 添加当前编辑的合同ID
}
},
methods: {
toExport() {
this.select.is_export = 1;
this.getContracts(true);
},
clearSelectForSearch() {
this.select.plan_id = "";
this.select.plan_name = "请选择预算计划";
},
async getPlanTypes() {
const res = await getparameter({
number: 'money_way'
})
this.planTypes = res.detail
console.log(this.planTypes)
},
//预算计划金额输入
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
},
//合计
summary(param) {
this.$nextTick(() => {
this.$refs['xyTable'].$children[0].doLayout()
})
const {
columns,
data
} = param
const sums = []
columns.map((column, index) => {
if (index === 0) {
sums[index] = '总计'
return
}
if (column.property === 'fund_log_total') {
sums[index] = this.tableTotal.fundLogTotal
return
}
if (column.property === 'plan_price') {
sums[index] = this.tableTotal.planPriceTotal
return
}
if (column.property === 'money') {
sums[index] = this.tableTotal.moneyTotal
return
}
// const values = data.map(item => Number(item[column.property]));
// if (!values.every(value => isNaN(value)) && (column.property === 'money' || column.property === 'plan_price'|| column.property === 'fund_log_total')) {
//
// sums[index] = sums[index].toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
// } else {
// sums[index] = '';
// }
})
return sums
},
cellStyle({
row,
column,
rowIndex,
columnIndex
}) {
if (column.property === 'req_status') {
if ((row.is_plan || row.is_substitute || row.is_simple) && !row.has_charge) {
return {
'color': 'rgb(140,140,140)'
}
}
switch (row.req_status) {
case 1:
return {
'color': 'rgb(96,109,241)'
}
break;
case 2:
return {
'color': 'rgb(219,122,122)'
}
break;
case 3:
return {
'color': 'rgb(147,201,134)'
}
break;
default:
return {
'color': 'rgb(220,185,126)'
}
}
}
if (column.property === 'purchase_status') {
if (row.is_substitute || row.is_simple) {
return {
'color': 'rgb(140,140,140)'
}
}
switch (row.purchase_status) {
case 1:
return {
'color': 'rgb(96,109,241)'
}
break;
case 2:
return {
'color': 'rgb(219,122,122)'
}
break;
case 3:
return {
'color': 'rgb(147,201,134)'
}
break;
default:
return {
'color': 'rgb(220,185,126)'
}
}
}
if (column.property === 'invite_status') {
if (row.purchase_way?.remark === 'false' || row.is_substitute || row.is_simple) {
return {
'color': 'rgb(140,140,140)'
}
}
switch (row.invite_status) {
case 1:
return {
'color': 'rgb(96,109,241)'
}
break;
case 2:
return {
'color': 'rgb(219,122,122)'
}
break;
case 3:
return {
'color': 'rgb(147,201,134)'
}
break;
default:
return {
'color': 'rgb(220,185,126)'
}
}
}
if (column.property === 'join_status') {
if(row.is_simple){
return {
'color': 'rgb(140,140,140)'
}
}
switch (row.join_status) {
case 1:
return {
'color': 'rgb(96,109,241)'
}
break;
case 2:
return {
'color': 'rgb(219,122,122)'
}
break;
case 3:
return {
'color': 'rgb(147,201,134)'
}
break;
default:
return {
'color': 'rgb(220,185,126)'
}
}
}
},
//y验证合同的名称是否存在重复
checkName(name) {
// 暂时不调用 API,直接返回
console.log('检查名称:', name)
},
confirmPlanForSearch() {
this.isShowPlanForSearch = false;
this.getContracts();
},
//点击付款计划查看
showPaymentPlan(row, column, cell) {
if (column.property === 'sign_plan_count') {
this.$refs['contractPaymentRegistration'].getSignPlan(row.id)
row.status === 2 ? this.$refs['contractPaymentRegistration'].isSign = true : this.$refs[
'contractPaymentRegistration'].isSign = false
this.$refs['contractPaymentRegistration'].isShow = true
}
if (column.property === 'fund_log_total') {
this.$router.push(`/contract/paymentRegistrationList?contractId=${row.id}`)
}
},
//招标文件审查
async bidding(row) {
let baseInfo = {
"项目名称": row?.name,
"项目预算(元)": row?.plan_price
}
let res = await getOatoken()
let url =
`${process.env.VUE_APP_OUT_URL}/admin/flow/create/27?oatoken=${res.oatoken}&out_contract_id=${row.id}&contract_json=${JSON.stringify(baseInfo)}`
let bidding = window.open(url, 'bidding',
`top=${this.window.top},left=${this.window.left},width=${this.window.width},height=${this.window.height},location=0`
)
},
//采购流程
async buyProcess(row) {
let baseInfo = {
"项目名称": row?.name,
"采购形式": row?.purchase_type?.value,
"采购方式": row?.purchase_way?.value,
"项目类型": this.type.find(item => {
return item.value === row.type
})?.label,
"资金渠道": row?.money_way?.value,
"项目预算(元)": row?.plan_price
}
let res = await getOatoken()
let url =
`${process.env.VUE_APP_OUT_URL}/admin/flow/create/2?oatoken=${res.oatoken}&out_contract_id=${row.id}&contract_json=${JSON.stringify(baseInfo)}`
let buyProcess = window.open(url, 'buyProcess',
`top=${this.window.top},left=${this.window.left},width=${this.window.width},height=${this.window.height},location=0`
)
},
//会签流程
async signProcess(row) {
let baseInfo = {
"合同名称": row?.name,
"执行部门": row?.carry_department,
"合同金额(元)": row?.money,
//"承包商\\供应商":row.supply
}
let res = await getOatoken()
let url =
`${process.env.VUE_APP_OUT_URL}/admin/flow/create/3?oatoken=${res.oatoken}&out_contract_id=${row.id}&contract_json=${JSON.stringify(baseInfo)}`
let signProcess = window.open(url, 'signProcess',
`top=${this.window.top},left=${this.window.left},width=${this.window.width},height=${this.window.height},location=0`
)
},
//请示流程
async askProcess(row) {
let res = await getOatoken()
let url =
`${process.env.VUE_APP_OUT_URL}/admin/flow/create/17?oatoken=${res.oatoken}&out_contract_id=${row.id}`
let askProcess = window.open(url, 'askProcess',
`top=${this.window.top},left=${this.window.left},width=${this.window.width},height=${this.window.height},location=0`
)
},
//防抖
debounce(fn, delay = 500) {
let timer = null
return function _debounce() {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn()
}, delay)
}
},
//翻页
pageChange(e) {
this.select.pageIndex = e
this.getContracts()
},
planPageChange(e) {
this.plansPageIndex = e
this.getBudgets()
},
//日期选择
datePick(e) {
this.select.start_created_at = e[0]
this.select.end_created_at = e[1]
},
//获取预算计划
async getBudgets() {
let res = await getBudget({
name: this.planSearch.name,
page_size: 10,
page: this.plansPageIndex,
plan_department_id: this.planSearch.plan_department_id,
top_pid: 1
})
this.plans = res.list.data
this.planTotal = res.list.total;
this.toggleSelection(this.plan.map(item => {
return item.value.plan_id
}), 1)
},
//获取资金渠道
async getMoneyWay() {
this.moneyWay = (await getparameter({
number: 'money_way'
})).detail
this.form.moneyWay = this.moneyWay
},
//获取购买方式
async getPurchaseWay() {
this.purchaseWay = (await getparameter({
number: 'purchase_way'
})).detail
}, //计划搜索
searchBudgets() {
this.plansPageIndex = 1;
this.getBudgets();
},
//获取科室
async getDepartment() {
this.departments = await listdeptNoAuth()
},
//获取购买形式列表
async getPurchaseType() {
this.purchaseType = (await getparameter({
number: 'purchase_type'
})).detail
},
pageSizeChange(e) {
this.select.pageSize = e;
this.select.pageIndex = 1;
this.getContracts();
},
downloadExel() {
download(
'/api/admin/contract/index',
'get', {
is_auth: 1,
is_export: 1,
...this.select
},
'合同列表.xlsx')
},
//获取合同列表
async getContracts(is_export,noloading=false) {
const res = await getContract({
page_size: this.select.pageSize,
page: this.select.pageIndex,
is_auth: 1,
...this.select
},noloading)
let tokens = getToken();
// if (is_export) {
// this.select.is_export == 1
// var url = "/api/admin/contract/index?is_auth=1&token=" + tokens
// Object.keys(this.select).map((key, item) => {
// url += "&" + key + "=" + this.select[key];
// });
// url = location.host + url;
// console.log(url)
// window.open("http://" + url, '_blank')
// this.select.is_export = 0
// return;
// }
this.list = res.list.data
this.total = res.list.total
this.tableTotal.fundLogTotal = res.fund_log_total
this.tableTotal.moneyTotal = Number(res.money_total).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,')
this.tableTotal.planPriceTotal = Number(res.plan_price_total).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g,
'$1,')
},
//新建合同
//显示
async showPlan() {
this.isShowPlan = true
await this.getBudgets()
},
showPlanForSearch(source) {
this.planSource = source
this.isShowPlan = true
this.getBudgets()
// 初始化 plan 数组
if (source === 'modal') {
this.plan = this.form.plan || []
} else {
this.plan = []
}
},
selectPlanForSearch(sel, row) {
if (this.planSource === 'modal') {
if (sel) {
let select = sel.map(item => {
let plan = this.plans.find(p => p.id === item.id)
return {
label: plan.name,
value: {
plan_id: plan.id,
use_money: plan.useMoney || 0,
new_money: plan.money
}
}
})
this.plan = [...this.form.plan, ...select]
// 更新显示文本,显示所有已选择的计划
this.form.plan_display = this.plan.map(item => item.label).join(', ')
} else {
this.plan = this.form.plan
// 更新显示文本,显示所有已选择的计划
this.form.plan_display = this.plan.map(item => item.label).join(', ')
}
} else {
this.select.plan_name = row.name
this.select.plan_id = row.id
}
},
planSelectForSearch() {
if (this.plan.length === 0) {
Message({
type: 'warning',
message: '选择计划不能为空'
})
return
}
for (let item of this.plan) {
if (!item.value.use_money) {
Message({
type: 'warning',
message: '金额不能为空'
})
return
}
}
// 设置表单数据
this.form.plan = this.plan
// 设置显示文本
this.form.plan_display = this.plan.map(item => item.label).join(', ')
// 关闭对话框
this.isShowPlan = false
},
//选择计划
selectPlan(sel, row) {
console.log(sel)
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.form.plan, ...select]
} else {
this.plan = this.form.plan
}
},
//确认计划选择
planSelect() {
if (this.plan.length === 0) {
Message({
type: 'warning',
message: '选择计划不能为空'
})
return
}
for (let item of this.plan) {
if (!item.value.use_money) {
Message({
type: 'warning',
message: '金额不能为空'
})
return
}
}
// 设置表单数据
this.form.plan = this.plan
// 设置显示文本,使用换行符分隔
this.form.plan_display = this.plan.map(item => item.label).join('\n')
// 关闭对话框
this.isShowPlan = false
},
delPlan(val) {
this.form.plan = this.form.plan.filter(item => item.value.plan_id !== val.value.plan_id)
},
//默认选择计划
toggleSelection(plans) {
if (plans) {
this.plans.filter(plan => {
if (plans.includes(plan.id)) {
let selectedPlan = this.plan.find(item => item.value.plan_id === plan.id)
if (selectedPlan) {
plan.useMoney = selectedPlan.value.use_money
}
return true
}
}).map(row => {
this.$refs.planTable.toggleRowSelection(row)
})
} else {
this.$refs.planTable.clearSelection()
}
},
//提交新建
async submit() {
try {
// 保存事前支付表格的数据
if (!this.form.showAfterPayment && this.form.before_contract_template) {
// 获取所有输入控件
const inputs = this.$refs.beforePaymentForm.querySelectorAll('input, select, textarea');
// 遍历所有输入控件,更新值到 HTML
inputs.forEach(input => {
const fieldName = input.getAttribute('data-field');
if (fieldName) {
const field = this.form.before_contract_template.contract_template_fields.find(f => f.field === fieldName);
if (field) {
if (input.type === 'checkbox' || input.type === 'radio') {
// 对于复选框和单选框,需要找到选中的值
const checkedInput = this.$refs.beforePaymentForm.querySelector(`[data-field="${fieldName}"]:checked`);
field.value = checkedInput ? checkedInput.value : '';
// 更新 HTML 中的 checked 状态
if (checkedInput) {
checkedInput.setAttribute('checked', 'checked');
}
} else {
field.value = input.value;
// 更新 HTML 中的 value
input.setAttribute('value', input.value);
}
}
}
});
// 获取更新后的 HTML
const beforeFormHtml = this.$refs.beforePaymentForm.innerHTML;
// 更新模板和保存数据
this.form.before_forms = beforeFormHtml;
}
// 保存事后支付表格的数据
if (this.form.showAfterPayment && this.form.contract_template) {
// 获取所有输入控件
const inputs = this.$refs.afterPaymentForm.querySelectorAll('input, select, textarea');
// 遍历所有输入控件,更新值到 HTML
inputs.forEach(input => {
const fieldName = input.getAttribute('data-field');
if (fieldName) {
const field = this.form.contract_template.contract_template_fields.find(f => f.field === fieldName);
if (field) {
if (input.type === 'checkbox' || input.type === 'radio') {
// 对于复选框和单选框,需要找到选中的值
const checkedInput = this.$refs.afterPaymentForm.querySelector(`[data-field="${fieldName}"]:checked`);
field.value = checkedInput ? checkedInput.value : '';
// 更新 HTML 中的 checked 状态
if (checkedInput) {
checkedInput.setAttribute('checked', 'checked');
}
} else {
field.value = input.value;
// 更新 HTML 中的 value
input.setAttribute('value', input.value);
}
}
}
});
// 获取更新后的 HTML
const afterFormHtml = this.$refs.afterPaymentForm.innerHTML;
// 更新模板和保存数据
this.form.forms = afterFormHtml;
}
// 构建提交数据
const submitData = {
...this.form,
is_plan: this.form.isBudget ? 1 : 0,
money_way_id: this.form.moneyWay.join(','),
contract_plan_links: this.form.plan.map(item => ({
plan_id: item.value.plan_id,
use_money: item.value.use_money
})),
contract_carry_department: this.form.contract_carry_department.map(id => ({
carry_department_id: id
}))
};
submitData.contract_category = this.form.category
submitData.work_type = this.form.affairType
submitData.contract_type = this.form.contractType
submitData.purchase_type_id = this.form.purchaseForm
submitData.purchase_way_id = this.form.purchaseMethod
// 处理事前支付模板
if (this.form.skipBeforeTemplate && !this.isEditMode) {
// 如果用户选择跳过,提交空的模板和字段列表
submitData.before_forms = '';
submitData.before_other_data = [];
} else if (this.form.before_contract_template) {
// 如果用户填写了模板,提交当前填写的模板和字段列表
submitData.before_forms = this.form.before_forms;
submitData.before_other_data = this.form.before_contract_template.contract_template_fields;
}
// 处理事后支付模板
if (this.form.skipAfterTemplate && !this.isEditMode) {
// 如果用户选择跳过,提交空的模板和字段列表
submitData.forms = '';
submitData.other_data = [];
} else if (this.form.contract_template) {
// 如果用户填写了模板,提交当前填写的模板和字段列表
submitData.forms = this.form.forms;
submitData.other_data = this.form.contract_template.contract_template_fields;
}
// 根据是新增还是编辑调用不同的API
if (this.isEditMode) {
submitData.id = this.currentContractId;
await editorContract(submitData);
} else {
await addContrant(submitData);
}
// 提交成功后关闭弹窗并刷新列表
this.isShowAdd = false;
this.getContracts();
Message({
type: 'success',
message: this.isEditMode ? '编辑成功' : '新增成功'
});
} catch (error) {
console.error('提交失败:', error);
Message({
type: 'error',
message: '提交失败'
});
}
},
//删除合同
deleteContract(id) {
delContract({
id
}).then(res => {
Message({
type: 'success',
message: '操作成功'
})
this.getContracts()
})
},
handleCategoryChange() {
this.form.affairType = ''
this.form.contractType = ''
this.form.purchaseForm = ''
this.form.purchaseMethod = ''
this.updateTypeOptions()
},
handleAffairTypeChange() {
this.form.contractType = ''
this.form.purchaseForm = ''
this.form.purchaseMethod = ''
this.updateTypeOptions()
},
handleContractTypeChange() {
this.form.purchaseForm = ''
this.form.purchaseMethod = ''
this.updateTypeOptions()
},
handlePurchaseFormChange() {
this.form.purchaseMethod = ''
this.updateTypeOptions()
},
handlePurchaseMethodChange() {
this.updateTypeOptions()
},
updateTypeOptions() {
// 重置所有选项
this.affairTypeOptions = []
this.contractTypeOptions = []
this.purchaseFormOptions = []
this.purchaseMethodOptions = []
this.purchaseSubFormOptions = []
// 获取当前选中的分类
const selectedCategory = this.categoryOptions.find(item => item.id === this.form.category)
if (!selectedCategory) return
// 更新事项类型选项
this.affairTypeOptions = selectedCategory.children || []
// 获取当前选中的事项类型
const selectedAffairType = this.affairTypeOptions.find(item => item.id === this.form.affairType)
if (!selectedAffairType) return
// 更新合同类型选项
this.contractTypeOptions = selectedAffairType.children || []
// 获取当前选中的合同类型
const selectedContractType = this.contractTypeOptions.find(item => item.id === this.form.contractType)
if (!selectedContractType) return
// 更新采购形式选项
this.purchaseFormOptions = selectedContractType.children || []
// 获取当前选中的采购形式
const selectedPurchaseForm = this.purchaseFormOptions.find(item => item.id === this.form.purchaseForm)
if (!selectedPurchaseForm) return
// 更新采购子形式选项
this.purchaseSubFormOptions = selectedPurchaseForm.children || []
// 获取当前选中的采购子形式
const selectedPurchaseSubForm = this.purchaseSubFormOptions.find(item => item.id === this.form.purchaseSubForm)
// 如果有采购子形式使用其children作为采购方式
if (selectedPurchaseSubForm && selectedPurchaseSubForm.children) {
this.purchaseMethodOptions = selectedPurchaseSubForm.children
}
// 如果没有采购子形式使用采购形式的children作为采购方式
else if (selectedPurchaseForm.children) {
this.purchaseMethodOptions = selectedPurchaseForm.children
}
},
nextStep() {
if (this.currentStep === 1) {
// 验证是否至少选择了一个下拉框
if (!this.form.category && !this.form.affairType && !this.form.contractType &&
!this.form.purchaseForm && !this.form.purchaseMethod) {
this.$Message.warning('请至少选择一个选项');
return;
}
// 获取模版配置
this.getTemplateConfig();
} else if (this.currentStep === 2) {
// 验证基本信息表单
const visibleFields = [];
// 检查项目名称是否显示
if (this.showFields.projectName) {
visibleFields.push('name');
}
// 检查项目类型是否显示
if (this.showFields.projectType) {
visibleFields.push('type');
}
// 检查预算价格是否显示
if (this.showFields.budgetPrice) {
visibleFields.push('price');
}
// 检查资金渠道是否显示
if (this.showFields.fundChannel) {
visibleFields.push('moneyWay');
}
// 检查预算计划是否显示
if (this.showFields.budgetPlan) {
visibleFields.push('plan');
}
// 检查显示的表单项是否都已填写
const missingFields = visibleFields.filter(field => {
if (field === 'moneyWay') {
return !this.form.moneyWay || this.form.moneyWay.length === 0;
} else if (field === 'plan') {
return !this.form.plan || this.form.plan.length === 0;
} else {
return !this.form[field];
}
});
if (missingFields.length > 0) {
this.$Message.warning('请填写所有必填项');
return;
}
// 在进入第三步之前,确保所有必要的数据都被正确设置
if (!this.form.type) {
this.form.type = '';
}
if (!this.form.contract_carry_department) {
this.form.contract_carry_department = [];
}
if (!this.form.moneyWay) {
this.form.moneyWay = [];
}
// 如果存在事前支付表格,则跳转到事前支付表格
if (this.form.before_contract_template) {
this.form.showAfterPayment = false;
}
this.currentStep++;
} else if (this.currentStep === 3) {
this.currentStep++;
}
},
prevStep() {
if (this.currentStep === 3) {
// 如果在事后支付表格,先保存内容
if (this.form.showAfterPayment &&
this.form.contract_template &&
this.form.contract_template.contract_template_fields &&
this.$refs.afterPaymentForm) {
// 获取所有输入控件
const inputs = this.$refs.afterPaymentForm.querySelectorAll('input, select, textarea');
// 遍历所有输入控件,更新值到 HTML
inputs.forEach(input => {
const fieldName = input.getAttribute('data-field');
if (fieldName) {
const field = this.form.contract_template.contract_template_fields.find(f => f.field === fieldName);
if (field) {
if (input.type === 'checkbox' || input.type === 'radio') {
// 对于复选框和单选框,需要找到选中的值
const checkedInput = this.$refs.afterPaymentForm.querySelector(`[data-field="${fieldName}"]:checked`);
field.value = checkedInput ? checkedInput.value : '';
// 更新 HTML 中的 checked 状态
if (checkedInput) {
checkedInput.setAttribute('checked', 'checked');
}
} else {
field.value = input.value;
// 更新 HTML 中的 value
input.setAttribute('value', input.value);
}
}
}
});
// 获取更新后的 HTML
const afterFormHtml = this.$refs.afterPaymentForm.innerHTML;
// 更新模保存数据
this.form.forms = afterFormHtml;
}
if (this.form.showAfterPayment && this.form.before_contract_template) {
// 如果在事后支付表格且有事前支付表格,则返回事前支付表格
this.form.showAfterPayment = false;
} else {
// 其他情况正常返回上一步
this.currentStep--;
}
} else {
this.currentStep--;
}
},
// 获取模版配置参数
async getTemplateConfig() {
try {
const params = {
category: this.form.category || 0,
work_type: this.form.affairType || 0,
contract_type: this.form.contractType || 0,
purchase_form: this.form.purchaseForm || 0
}
console.log('请求模版配置参数:', params)
const res = await getContractCategoryTemplateConfigParams(params)
console.log('模版配置返回数据:', res)
if (res.errcode !== undefined) {
this.$message.error(res.errmsg || '获取模版配置失败')
return
}
// 在编辑模式下保存当前的forms和before_forms值
let currentForms = null;
let currentBeforeForms = null;
if (this.isEditMode) {
currentForms = this.form.forms;
currentBeforeForms = this.form.before_forms;
}
// 根据返回的配置参数设置表单
this.setFormConfig(res)
// 在编辑模式下恢复forms和before_forms的值
if (this.isEditMode) {
this.form.forms = currentForms;
this.form.before_forms = currentBeforeForms;
}
if (this.form.forms && this.form.forms.trim() !== '') {
this.form.skipAfterTemplate = true;
}
if (this.form.before_forms && this.form.before_forms.trim() !== '') {
this.form.skipBeforeTemplate = true;
}
// 进入下一步
this.currentStep++
} catch (error) {
console.error('获取模版配置失败:', error)
this.$message.error('获取模版配置失败')
}
},
// 设置表单配置
setFormConfig(config) {
console.log('模版配置参数:', config)
// 只更新显示/隐藏状态,不影响数据来源
Object.assign(this.showFields, {
projectName: config.project_name === 1, // 项目名称
projectType: config.project_type === 1, // 项目类型
budgetPrice: config.budget_price === 1, // 预算价格
fundChannel: config.fund_channel === 1, // 资金渠道
budgetPlan: config.budget_plan === 1 // 预算计划
})
// 保存支付表格模板
if (config.before_contract_template) {
// 处理事前支付表格模板
let beforeTemplate = config.before_contract_template.template;
if (beforeTemplate && config.before_contract_template.contract_template_fields) {
console.log('处理事前支付表格模板:', config.before_contract_template.contract_template_fields)
// 遍历字段列表,为每个字段找到对应的控件
config.before_contract_template.contract_template_fields.forEach(field => {
// 在模板中查找 data-field 属性值与字段名相同的控件
const regex = new RegExp(`<[^>]*data-field="${field.field}"[^>]*>`, 'g');
const matches = beforeTemplate.match(regex);
if (matches) {
matches.forEach(match => {
// 获取控件类型
let controlType = 'text';
if (match.includes('type="number"')) controlType = 'number';
else if (match.includes('type="date"')) controlType = 'date';
else if (match.includes('type="checkbox"')) controlType = 'checkbox';
else if (match.includes('type="radio"')) controlType = 'radio';
else if (match.includes('<select')) controlType = 'select';
else if (match.includes('<textarea')) controlType = 'textarea';
// 根据控件类型设置 id 和 value
let newControl = match;
// 添加 id
if (!newControl.includes('id=')) {
newControl = newControl.replace('data-field', `id="before_${field.field}" data-field`);
}
// 设置 value
if (controlType === 'checkbox' || controlType === 'radio') {
// 对于复选框和单选框,需要处理 options
const options = field.options ? JSON.parse(field.options) : [];
options.forEach(opt => {
const optionRegex = new RegExp(`<input[^>]*value="${opt.value}"[^>]*>`, 'g');
const optionMatches = newControl.match(optionRegex);
if (optionMatches) {
optionMatches.forEach(optionMatch => {
const checked = field.value === opt.value ? 'checked' : '';
newControl = newControl.replace(optionMatch, optionMatch.replace('>', ` ${checked}>`));
});
}
});
} else {
// 对于其他控件,直接设置 value
if (!newControl.includes('value=')) {
newControl = newControl.replace('>', ` value="${field.value || ''}">`);
} else {
newControl = newControl.replace(/value="[^"]*"/, `value="${field.value || ''}"`);
}
}
// 替换原控件
beforeTemplate = beforeTemplate.replace(match, newControl);
});
}
});
}
this.form.before_contract_template = config.before_contract_template;
this.form.before_contract_template.template = beforeTemplate;
}
if (config.contract_template) {
// 处理事后支付表格模板
let afterTemplate = config.contract_template.template;
if (afterTemplate && config.contract_template.contract_template_fields) {
console.log('处理事后支付表格模板:', config.contract_template.contract_template_fields)
// 遍历字段列表,为每个字段找到对应的控件
config.contract_template.contract_template_fields.forEach(field => {
// 在模板中查找 data-field 属性值与字段名相同的控件
const regex = new RegExp(`<[^>]*data-field="${field.field}"[^>]*>`, 'g');
const matches = afterTemplate.match(regex);
if (matches) {
matches.forEach(match => {
// 获取控件类型
let controlType = 'text';
if (match.includes('type="number"')) controlType = 'number';
else if (match.includes('type="date"')) controlType = 'date';
else if (match.includes('type="checkbox"')) controlType = 'checkbox';
else if (match.includes('type="radio"')) controlType = 'radio';
else if (match.includes('<select')) controlType = 'select';
else if (match.includes('<textarea')) controlType = 'textarea';
// 根据控件类型设置 id 和 value
let newControl = match;
// 添加 id
if (!newControl.includes('id=')) {
newControl = newControl.replace('data-field', `id="after_${field.field}" data-field`);
}
// 设置 value
if (controlType === 'checkbox' || controlType === 'radio') {
// 对于复选框和单选框,需要处理 options
const options = field.options ? JSON.parse(field.options) : [];
options.forEach(opt => {
const optionRegex = new RegExp(`<input[^>]*value="${opt.value}"[^>]*>`, 'g');
const optionMatches = newControl.match(optionRegex);
if (optionMatches) {
optionMatches.forEach(optionMatch => {
const checked = field.value === opt.value ? 'checked' : '';
newControl = newControl.replace(optionMatch, optionMatch.replace('>', ` ${checked}>`));
});
}
});
} else {
// 对于其他控件,直接设置 value
if (!newControl.includes('value=')) {
newControl = newControl.replace('>', ` value="${field.value || ''}">`);
} else {
newControl = newControl.replace(/value="[^"]*"/, `value="${field.value || ''}"`);
}
}
// 替换原控件
afterTemplate = afterTemplate.replace(match, newControl);
});
}
});
}
this.form.contract_template = config.contract_template;
this.form.contract_template.template = afterTemplate;
}
},
handleAddContract() {
this.isShowAdd = true;
// Call API to get category options
this.getCategoryOptions();
// Reset form
this.resetForm();
},
handleAddContractOk() {
// 这个方法可以移除,因为功能已经被 nextStep 和 submit 方法替代
},
handleAddContractCancel() {
// 这个方法可以移除,因为功能已经被 cancel 方法替代
},
cancel() {
this.isShowAdd = false
this.resetForm()
},
resetForm() {
this.currentStep = 1;
this.isEditMode = false;
this.currentContractId = null;
this.form = {
category: '',
affairType: '',
contractType: '',
purchaseForm: '',
purchaseSubForm: '',
purchaseMethod: '',
name: '',
type: '',
moneyWay: [],
plan: [],
plan_display: '',
price: 0,
supply: '',
is_simple: 0,
has_charge: 0,
isBudget: 0,
is_substitute: 0,
request: 0,
purchaseApproval: 0,
tenderReview: 0,
contractSign: 0,
expenses: [
{
content: '',
amount: 0,
ratio: '',
payee: ''
}
],
showAfterPayment: false,
contract_carry_department: []
};
this.affairTypeOptions = [];
this.contractTypeOptions = [];
this.purchaseFormOptions = [];
this.purchaseSubFormOptions = [];
this.purchaseMethodOptions = [];
},
// 获取分类配置
async getCategoryOptions() {
try {
// 获取分类配置
const res = await getContractCategoryTemplateBaseConfig()
if (res.errcode !== undefined) {
this.$message.error(res.errmsg || '获取分类配置失败')
return
}
// 保存采购方式映射
this.purchaseMethodsMap = res.purchase_methods || {}
// 设置分类选项 - 从第二级开始(合同类、报销类、其他支出类)
this.categoryOptions = res.map?.[0]?.children || []
// 递归处理每一层的 children确保所有层级都被正确解析
const processChildren = (items) => {
if (!items) return
items.forEach(item => {
if (item.children) {
// 确保每个子项都有正确的 id 和 name
item.children = item.children.map(child => ({
id: child.id,
name: child.name || child.value, // 添加对 value 字段的支持
children: child.children || []
}))
processChildren(item.children)
}
})
}
// 处理所有层级的 children
processChildren(this.categoryOptions)
// 初始化其他选项
this.updateTypeOptions()
} catch (error) {
console.error('获取分类配置失败:', error)
this.$message.error('获取分类配置失败')
}
},
// 初始化采购方式映射
initPurchaseMethodsMap() {
this.purchaseMethodsMap = {}
// 递归遍历分类选项,构建采购方式映射
const traverse = (items) => {
items.forEach(item => {
if (item.children) {
traverse(item.children)
} else {
// 如果是叶子节点,添加到映射中
this.purchaseMethodsMap[item.id] = item.name
}
})
}
traverse(this.categoryOptions)
},
// 获取分类名称的方法
getCategoryName(id) {
const category = this.categoryOptions.find(item => item.id === id)
return category ? category.name : ''
},
getAffairTypeName(id) {
const category = this.categoryOptions.find(item => item.id === this.form.category)
if (category && category.children) {
const affairType = category.children.find(item => item.id === id)
return affairType ? affairType.name : ''
}
return ''
},
getContractTypeName(id) {
const category = this.categoryOptions.find(item => item.id === this.form.category)
if (category && category.children) {
const affairType = category.children.find(item => item.id === this.form.affairType)
if (affairType && affairType.children) {
const contractType = affairType.children.find(item => item.id === id)
return contractType ? contractType.name : ''
}
}
return ''
},
getPurchaseFormName(id) {
const category = this.categoryOptions.find(item => item.id === this.form.category)
if (category && category.children) {
const affairType = category.children.find(item => item.id === this.form.affairType)
if (affairType && affairType.children) {
const contractType = affairType.children.find(item => item.id === this.form.contractType)
if (contractType && contractType.children) {
const purchaseForm = contractType.children.find(item => item.id === id)
return purchaseForm ? purchaseForm.name : ''
}
}
}
return ''
},
getPurchaseMethodName(id) {
// 从嵌套结构中查找采购方式名称
const category = this.categoryOptions.find(item => item.id === this.form.category)
if (category && category.children) {
const affairType = category.children.find(item => item.id === this.form.affairType)
if (affairType && affairType.children) {
const contractType = affairType.children.find(item => item.id === this.form.contractType)
if (contractType && contractType.children) {
const purchaseForm = contractType.children.find(item => item.id === this.form.purchaseForm)
if (purchaseForm && purchaseForm.children) {
// 如果有选择子表单,从子表单中查找
if (this.form.purchaseSubForm) {
const purchaseSubForm = purchaseForm.children.find(item => item.id === this.form.purchaseSubForm)
if (purchaseSubForm && purchaseSubForm.children) {
const purchaseMethod = purchaseSubForm.children.find(item => item.id === id)
if (purchaseMethod) {
return purchaseMethod.name
}
}
}
// 直接从采购形式中查找
const purchaseMethod = purchaseForm.children.find(item => item.id === id)
if (purchaseMethod) {
return purchaseMethod.name
}
}
}
}
}
// 备用:从映射中查找
return this.purchaseMethodsMap[id] || ''
},
// 更新预算计划显示文本
updatePlanDisplay() {
if (this.form.plan && this.form.plan.length > 0) {
this.form.plan_display = `已选择 ${this.form.plan.length} 个预算计划`
} else {
this.form.plan_display = ''
}
},
// 新增方法:移除预算计划
removePlan(item) {
// 从 plan 数组中移除
this.plan = this.plan.filter(p => p.value.plan_id !== item.value.plan_id)
// 从 form.plan 中移除
this.form.plan = this.form.plan.filter(p => p.value.plan_id !== item.value.plan_id)
// 更新显示文本
this.form.plan_display = this.plan.map(p => p.label).join(', ')
},
// 切换到事后支付表格
nextPaymentStep() {
// 保存事前支付表格的数据
if (this.form.before_contract_template && !this.form.showAfterPayment) {
// 获取所有输入控件
const inputs = this.$refs.beforePaymentForm.querySelectorAll('input, select, textarea');
// 遍历所有输入控件,更新值到 HTML
inputs.forEach(input => {
const fieldName = input.getAttribute('data-field');
if (fieldName) {
const field = this.form.before_contract_template.contract_template_fields.find(f => f.field === fieldName);
if (field) {
if (input.type === 'checkbox' || input.type === 'radio') {
// 对于复选框和单选框,需要找到选中的值
const checkedInput = this.$refs.beforePaymentForm.querySelector(`[data-field="${fieldName}"]:checked`);
field.value = checkedInput ? checkedInput.value : '';
// 更新 HTML 中的 checked 状态
if (checkedInput) {
checkedInput.setAttribute('checked', 'checked');
}
} else {
field.value = input.value;
// 更新 HTML 中的 value
input.setAttribute('value', input.value);
}
}
}
});
// 获取更新后的 HTML
const beforeFormHtml = this.$refs.beforePaymentForm.innerHTML;
// 更新模板和保存数据
this.form.before_forms = beforeFormHtml;
}
this.form.showAfterPayment = true;
},
// 获取资金渠道名称的方法
getMoneyWayName(id) {
const way = this.moneyWay.find(item => item.id === id)
return way ? way.value : ''
},
// 移除资金渠道
removeMoneyWay(id) {
this.form.moneyWay = this.form.moneyWay.filter(item => item !== id)
},
// 获取科室名称的方法
getDepartmentName(id) {
const dept = this.departments.find(item => item.id === id)
return dept ? dept.name : ''
},
// 移除科室
removeDepartment(id) {
this.form.contract_carry_department = this.form.contract_carry_department.filter(item => item !== id)
},
// 跳过事前支付表格
skipPrePayment() {
this.form.showAfterPayment = true
if (this.isEditMode) {
this.form.before_forms = this.originBeforeForms;
}else{
this.form.before_forms = '';
this.form.before_other_data = [];
this.form.skipBeforeTemplate = true;
}
},
// 跳过事后支付表格
skipPostPayment() {
if (this.isEditMode) {
this.form.forms = this.originAfterForms;
}else{
this.form.forms = '';
this.form.other_data = [];
this.form.skipAfterTemplate = true;
}
this.submit()
},
// 更新事前表格字段值
updateBeforeFieldValue(field, value) {
if (this.form.before_contract_template && this.form.before_contract_template.contract_template_fields) {
const fieldObj = this.form.before_contract_template.contract_template_fields.find(f => f.field === field);
if (fieldObj) {
fieldObj.value = value;
}
}
},
// 更新事后表格字段值
updateAfterFieldValue(field, value) {
if (this.form.contract_template && this.form.contract_template.contract_template_fields) {
const fieldObj = this.form.contract_template.contract_template_fields.find(f => f.field === field);
if (fieldObj) {
fieldObj.value = value;
}
}
},
// 编辑按钮点击事件
async handleEdit(row) {
this.isEditMode = true;
this.currentContractId = row.id;
this.isShowAdd = true;
this.currentStep = 1;
try {
// 1. 先获取分类选项
await this.getCategoryOptions();
// 2. 获取合同详情
const res = await getContract({ id: row.id });
if (res && res.list && res.list.data && res.list.data.length > 0) {
const detail = res.list.data[0];
// 3. 通过正常的流程来初始化下拉框
// 设置分类
if (detail.contract_category) {
this.form.category = detail.contract_category;
this.handleCategoryChange(detail.contract_category);
}
// 设置事项类型
if (detail.work_type) {
this.form.affairType = detail.work_type;
this.handleAffairTypeChange(detail.work_type);
}
// 设置合同类型
if (detail.contract_type) {
this.form.contractType = detail.contract_type;
this.handleContractTypeChange(detail.contract_type);
}
// 设置采购形式
if (detail.purchase_type_id) {
this.form.purchaseForm = detail.purchase_type_id;
this.handlePurchaseFormChange(detail.purchase_type_id);
}
// 设置采购方式
if (detail.purchase_way_id) {
this.form.purchaseMethod = detail.purchase_way_id;
}
console.log("detail", detail);
// 保存其他表单数据
this.form = {
...this.form,
forms: detail.forms,
before_forms: detail.before_forms,
originBeforeForms: detail.before_forms,
originAfterForms: detail.forms,
other_data: detail.other_data,
before_other_data: detail.before_other_data,
type: detail.type,
isBudget: detail.is_plan,
is_simple: detail.is_simple,
has_charge: detail.has_charge,
is_substitute: detail.is_substitute,
supply: detail.supply,
price: detail.plan_price,
name: detail.name,
moneyWay: detail.money_way_id ? detail.money_way_id.split(',').map(Number) : [],
plan: detail.plans.map(item => {
return {
label: item.name,
value: {
plan_id: item.id,
use_money: detail.plan_link ? detail.plan_link.filter(item1 => {
return item1.plan_id === item.id
})[0]?.use_money : 0,
new_money: item.money
}
}
}),
contract_carry_department: detail.contract_carry_department.map(i => i.carry_department_id),
before_contract_template: detail.before_contract_template,
contract_template: detail.contract_template
};
// 设置预算计划显示文本
if (this.form.plan && this.form.plan.length > 0) {
this.form.plan_display = this.form.plan.map(item => item.label).join(', ');
}
}
} catch (error) {
console.error('初始化编辑数据失败:', error);
Message({
type: 'error',
message: '初始化编辑数据失败'
});
}
},
// 新增按钮点击事件
handleAdd() {
this.isEditMode = false;
this.currentContractId = null;
this.isShowAdd = true;
this.currentStep = 1;
this.form = {
...this.form,
category: '',
affairType: '',
contractType: '',
purchaseForm: '',
purchaseMethod: '',
type: '',
isBudget: false,
is_simple: 0,
has_charge: 0,
is_substitute: 0,
supply: '',
price: '',
name: '',
moneyWay: [],
plan: [],
contract_carry_department: [],
before_contract_template: null,
contract_template: null
};
this.getCategoryOptions();
},
// 新增获取合同详情方法
async getContractDetail(id) {
try {
const res = await getContract({ id });
if (res && res.list && res.list.data && res.list.data.length > 0) {
const detail = res.list.data[0];
console.log("detail", detail);
// 填充表单数据
this.form = {
...this.form,
// 第一步的五个分类选择
category: detail.category,
affairType: detail.work_type,
contractType: detail.contract_type,
purchaseForm: detail.purchase_type_id, // 采购形式
purchaseMethod: detail.purchase_way_id, // 采购方式
// 其他基本信息
type: detail.type,
isBudget: detail.is_plan,
is_simple: detail.is_simple,
has_charge: detail.has_charge,
is_substitute: detail.is_substitute,
supply: detail.supply,
price: detail.plan_price,
name: detail.name,
moneyWay: detail.money_way_id ? detail.money_way_id.split(',').map(Number) : [],
plan: detail.plans.map(item => {
return {
label: item.name,
value: {
plan_id: item.id,
use_money: detail.plan_link ? detail.plan_link.filter(item1 => {
return item1.plan_id === item.id
})[0]?.use_money : 0,
new_money: item.money
}
}
}),
contract_carry_department: detail.contract_carry_department.map(i => i.carry_department_id),
before_contract_template: detail.before_contract_template,
contract_template: detail.contract_template,
before_forms: detail.before_forms,
before_other_data: detail.before_other_data,
forms: detail.forms,
other_data: detail.other_data,
};
// 设置预算计划显示文本
if (this.form.plan && this.form.plan.length > 0) {
this.form.plan_display = this.form.plan.map(item => item.label).join(', ');
}
// 确保停留在第一步
this.currentStep = 1;
}
} catch (error) {
console.error('获取合同详情失败:', error);
Message({
type: 'error',
message: '获取合同详情失败'
});
}
},
// 验证表单
validateForm() {
// 验证第一步的必填字段
if (this.currentStep === 1) {
if (!this.form.category) {
Message({
type: 'error',
message: '请选择合同分类'
});
return false;
}
if (!this.form.affairType) {
Message({
type: 'error',
message: '请选择事项类型'
});
return false;
}
if (!this.form.contractType) {
Message({
type: 'error',
message: '请选择合同类型'
});
return false;
}
if (!this.form.purchaseForm) {
Message({
type: 'error',
message: '请选择采购形式'
});
return false;
}
if (!this.form.purchaseMethod) {
Message({
type: 'error',
message: '请选择采购方式'
});
return false;
}
}
// 验证第二步的必填字段
if (this.currentStep === 2) {
if (!this.form.type) {
Message({
type: 'error',
message: '请选择合同性质'
});
return false;
}
if (!this.form.name) {
Message({
type: 'error',
message: '请输入合同名称'
});
return false;
}
if (!this.form.price) {
Message({
type: 'error',
message: '请输入合同金额'
});
return false;
}
if (!this.form.moneyWay || this.form.moneyWay.length === 0) {
Message({
type: 'error',
message: '请选择资金来源'
});
return false;
}
if (!this.form.plan || this.form.plan.length === 0) {
Message({
type: 'error',
message: '请选择预算计划'
});
return false;
}
if (!this.form.contract_carry_department || this.form.contract_carry_department.length === 0) {
Message({
type: 'error',
message: '请选择合同承办部门'
});
return false;
}
}
return true;
},
},
mounted() {
this.window.width = screen.availWidth * 0.95
this.window.height = screen.availHeight * 0.95
this.window.top = (window.screen.height - 30 - this.window.height) / 2
this.window.left = (window.screen.width - 10 - this.window.width) / 2
let that = this;
getInfo().then(response => {
console.log(response)
this.user = response;
if (that.userList.indexOf(response.username) != -1) {
that.hasEdit = true;
}
}).catch(error => {
})
this.getPurchaseType()
this.getContracts()
this.getDepartment()
this.getPurchaseWay()
this.getMoneyWay()
//页面激活后刷新合同列表
window.onfocus = () => {
this.getContracts(false, true)
}
},
destroyed() {
window.onfocus = null
}
}
</script>
<style lang="scss" scoped>
.selects {
display: flex;
flex-wrap: wrap;
& > div {
margin-bottom: 6px;
}
}
.selectTop {
margin-top: 10px;
}
.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;
}
}
.slot-btns {
display: flex;
flex-wrap: wrap;
align-content: center;
justify-content: flex-start;
&-item {
margin: 0 6px 4px 0;
}
}
.xy-table-item-label {
width: 200px;
}
.xy-table-item-price {
position: relative;
&::after {
position: absolute;
right: 0;
top: 0;
content: '(元)'
}
}
.contract-add-modal {
:deep(.ivu-modal-content) {
border-radius: 8px;
overflow: hidden;
}
:deep(.ivu-modal-header) {
background: #f8f8f9;
padding: 16px 24px;
border-bottom: 1px solid #e8eaec;
}
:deep(.ivu-modal-body) {
padding: 24px;
}
.steps-header {
display: flex;
justify-content: space-between;
margin-bottom: 32px;
padding: 0 20px;
.step {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
flex: 1;
&:not(:last-child)::after {
content: '';
position: absolute;
top: 16px;
left: 50%;
width: 100%;
height: 2px;
background: #e8eaec;
z-index: 1;
}
.step-number {
width: 32px;
height: 32px;
border-radius: 50%;
background: #e8eaec;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 8px;
position: relative;
z-index: 2;
}
.step-text {
color: #808695;
font-size: 14px;
}
&.active {
.step-number {
background: #2d8cf0;
}
.step-text {
color: #2d8cf0;
font-weight: 500;
}
}
}
}
.step-content {
padding: 0 20px;
}
.form-group {
margin-bottom: 20px;
.form-label {
display: block;
margin-bottom: 8px;
color: #515a6e;
font-weight: 500;
}
.form-input {
width: 100%;
}
.form-button {
width: 100%;
}
}
.expense-table {
width: 100%;
border-collapse: collapse;
margin-top: 8px;
th, td {
padding: 8px;
border: 1px solid #e8eaec;
text-align: center;
}
th {
background: #f8f8f9;
color: #515a6e;
font-weight: 500;
}
td {
.ivu-input {
border: none;
&:focus {
box-shadow: none;
}
}
}
}
.step-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
margin-top: 32px;
padding: 0 20px;
.action-button {
min-width: 100px;
}
}
}
.template-info {
background-color: #f5f7fa;
border-radius: 4px;
padding: 16px;
margin-bottom: 24px;
.info-title {
font-size: 16px;
font-weight: 600;
color: #1f2937;
margin-bottom: 16px;
padding-bottom: 12px;
border-bottom: 1px solid #e5e7eb;
}
.info-content {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 16px;
.info-item {
display: flex;
align-items: center;
.label {
color: #4b5563;
font-weight: 500;
margin-right: 8px;
min-width: 84px;
}
.value {
color: #1f2937;
}
}
}
}
.form-section {
background-color: #ffffff;
border-radius: 4px;
padding: 20px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
.section-title {
font-size: 16px;
font-weight: 600;
color: #1f2937;
margin-bottom: 20px;
padding-bottom: 12px;
border-bottom: 1px solid #e5e7eb;
}
:deep(.el-form-item) {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
:deep(.el-form-item__label) {
font-weight: 500;
color: #4b5563;
}
:deep(.el-input),
:deep(.el-input-number),
:deep(.el-select) {
width: 100%;
}
}
.helper-text {
margin-top: 8px;
color: #666;
font-size: 13px;
line-height: 1.4;
}
.form-section {
& + .form-section {
margin-top: 24px;
}
:deep(.el-radio-group) {
.el-radio {
margin-right: 30px;
&:last-child {
margin-right: 0;
}
}
}
}
.process-control-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
.control-item {
background: #f9fafb;
border-radius: 4px;
padding: 16px;
.control-label {
color: #4b5563;
font-weight: 500;
margin-bottom: 12px;
}
.control-content {
.helper-text {
margin-top: 8px;
color: #666;
font-size: 13px;
line-height: 1.4;
}
}
:deep(.el-radio-group) {
display: flex;
gap: 24px;
.el-radio {
margin-right: 0;
}
}
}
}
.plan-selector {
width: 100%;
.plan-input {
width: 100%;
}
.plan-tags {
margin-top: 8px;
display: flex;
flex-wrap: wrap;
gap: 8px;
.el-tag {
margin-right: 0;
}
}
}
.search-box {
margin-bottom: 16px;
}
.plan-list {
height: 400px;
overflow-y: auto;
}
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 12px;
padding: 10px 0;
.action-button {
min-width: 100px;
}
}
.no-payment-form {
padding: 20px;
text-align: center;
color: #909399;
font-size: 14px;
background-color: #f5f7fa;
border-radius: 4px;
}
.money-way-selector {
width: 100%;
.money-way-tags {
margin-top: 8px;
display: flex;
flex-wrap: wrap;
gap: 8px;
.el-tag {
margin-right: 0;
}
}
}
.department-selector {
width: 100%;
.department-tags {
margin-top: 8px;
display: flex;
flex-wrap: wrap;
gap: 8px;
.el-tag {
margin-right: 0;
}
}
}
.skip-option {
margin-top: 16px;
text-align: center;
.el-button {
color: #909399;
&:hover {
color: #409EFF;
}
}
}
</style>
<style scoped lang="scss">
// ... existing styles ...
// require
::v-deep .el-form-item__error {
width: 200px;
white-space: normal;
word-break: break-all;
text-align: right;
right: 0;
left: auto;
}
</style>