Files
fad_oa/ruoyi-ui/src/views/oa/project/probox.vue
2026-04-13 17:04:38 +08:00

1424 lines
53 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="项目名称" prop="projectName">
<el-input v-model="queryParams.projectName" placeholder="请输入项目名称" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="项目编号" prop="projectNum">
<el-input v-model="queryParams.projectNum" placeholder="请输入项目编号" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="项目类型" prop="projectType">
<el-select v-model="queryParams.projectType" placeholder="请选择项目类型" clearable @change="handleQuery">
<el-option v-for="dict in dict.type.sys_project_type" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="贸易类型" prop="tradeType">
<el-select v-model="queryParams.tradeType" placeholder="请选择项目类型" clearable @change="handleQuery">
<el-option v-for="dict in dict.type.sys_trade_type" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="项目代号" prop="projectCode">
<el-select v-model="queryParams.projectCode" placeholder="请选择代号类型" style="width: 100%" filterable
@change="handleQuery" :filter-method="filterCode">
<el-option v-for="dict in dict.type.sys_project_code" :key="dict.value" :label="dict.label"
:value="dict.value">
<span style="float: left">{{ dict.label }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ dict.value }}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="projectType">
<el-select v-model="queryParams.projectStatus" placeholder="请选择状态" clearable @change="handleQuery">
<el-option v-for="dict in dict.type.sys_project_status" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="签约公司" prop="signingCompany">
<el-select v-model="queryParams.signingCompany" placeholder="请选择签约公司" style="width: 100%" clearable>
<el-option v-for="dict in dict.type.signing_company" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="签约客户" prop="customerId">
<el-select v-model="queryParams.customerId" placeholder="请选择签约客户" filterable style="width: 100%" clearable>
<el-option v-for="item in customerList" :key="item.customerId" :label="item.name" :value="item.customerId" />
</el-select>
</el-form-item>
<el-form-item label="日期范围">
<el-date-picker v-model="searchTime" type="daterange" start-placeholder="开始日期" end-placeholder="结束日期"
:default-time="['00:00:00', '23:59:59']">
</el-date-picker>
</el-form-item>
<el-form-item label="优质筛选">
<el-switch v-model="queryParams.prePay" active-text="开" active-value="0.1" inactive-value="0"
@change="selectPrePay" inactive-text="">
</el-switch>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['oa:project:add']">新增项目
</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<fad-table v-loading="loading" :data="projectList" @selection-change="handleSelectionChange" floatLayer
:floatLayerConfig="floatLayerConfig">
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="ID" align="center" prop="projectId" v-if="true"/>-->
<el-table-column label="项目类型" prop="tradeType" width="100">
<template slot-scope="scope">
<dict-tag :options="dict.type.sys_trade_type" :value="scope.row.tradeType" />
</template>
</el-table-column>
<el-table-column label="项目代号" prop="projectCode" width="100" align="center">
<template slot-scope="scope">
<el-tag v-if="scope.row.projectCode == null" type="danger"></el-tag>
<el-tag v-else>{{ scope.row.projectCode }}</el-tag>
</template>
</el-table-column>
<el-table-column label="项目名称" align="left" prop="projectName">
<template slot-scope="scope">
<span v-if="scope.row.prePay > 0"></span>
<span>{{ scope.row.projectName }}</span>
</template>
</el-table-column>
<el-table-column label="项目编号" align="left" prop="projectNum" />
<!-- <el-table-column label="签约公司" align="left" prop="signingCompany">
<template slot-scope="scope">
<dict-tag :options="dict.type.signing_company" :value="scope.row.signingCompany" />
</template>
</el-table-column>
<el-table-column label="客户名称" align="center" prop="customerName">
<template slot-scope="scope">
<el-button type="text" @click="toDetail(scope.row)">{{ scope.row.customerName }}</el-button>
</template>
</el-table-column> -->
<el-table-column label="项目总金额" align="center" prop="funds">
<template slot-scope="scope">
<div>{{ convertToTenThousand(scope.row.funds) }}</div>
<div v-if="scope.row.prePay > 0">
<el-tag type="warning">预付款{{ convertToTenThousand(scope.row.prePay) }}</el-tag>
</div>
</template>
</el-table-column>
<!-- <el-table-column label="项目类型" align="center" prop="projectType" width="100">-->
<!-- <template slot-scope="scope">-->
<!-- <dict-tag :options="dict.type.sys_project_type" :value="scope.row.projectType"/>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="负责人" align="center" prop="functionary" />
<el-table-column label="开始时间" align="center" prop="beginTime">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.beginTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="剩余时间" align="center" prop="remainTime">
<template slot-scope="scope">
<div v-if="scope.row.remainTime >= 0">
<div v-if="scope.row.projectStatus === '0'">
<span v-if="scope.row.remainTime > 5">剩余{{ scope.row.remainTime }}</span>
<el-tag v-else-if="scope.row.remainTime <= 5 && scope.row.remainTime > 3" type="warning">
剩余{{ scope.row.remainTime }}
</el-tag>
<el-tag v-else type="danger">剩余{{ scope.row.remainTime }}</el-tag>
</div>
<div v-else>-</div>
</div>
<div v-else>
<el-tag type="danger" v-if="scope.row.projectStatus === '0'">过期{{
Math.abs(scope.row.remainTime)
}}
</el-tag>
<div v-else>-</div>
</div>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="projectStatus">
<template slot-scope="scope">
<dict-tag :options="dict.type.sys_project_status" :value="scope.row.projectStatus" />
</template>
</el-table-column>
<!-- <el-table-column label="是否延期" align="center" prop="remark">
<template slot-scope="scope">
<span v-if="scope.row.isPostpone === 0"></span>
<span v-if="scope.row.isPostpone === 1"></span>
</template>
</el-table-column> -->
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
<el-table-column label="置顶">
<template slot-scope="scope">
<el-switch :active-value="1" :inactive-value="0" v-model="scope.row.isTop"
@change="handleRowChange(scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" v-if="scope.row.projectStatus === '0'" icon="el-icon-edit"
@click="handlePostPone(scope.row)" v-hasPermi="['oa:project:postpone']">延期
</el-button>
<el-button size="mini" type="text" v-if="scope.row.projectStatus === '0' || scope.row.projectStatus === '2'"
icon="el-icon-edit" @click="handleClosure(scope.row)" v-hasPermi="['oa:project:edit']">结项
</el-button>
<el-button size="mini" type="text" v-if="scope.row.projectStatus === '0'" icon="el-icon-check"
@click="handleComplete(scope.row)" v-hasPermi="['oa:project:edit']">完成
</el-button>
<el-button size="mini" type="text" v-if="scope.row.projectStatus === '0'" icon="el-icon-edit"
@click="handleUpdate(scope.row)" v-hasPermi="['oa:project:edit']">修改
</el-button>
<el-button size="mini" type="text" icon="el-icon-view" @click="handleDetail(scope.row)">详情
</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['oa:project:remove']">删除
</el-button>
</template>
</el-table-column>
</fad-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" />
<!-- 修改项目对话框 -->
<el-dialog :title="title" :visible.sync="editShow" @close="closeDialog" width="76%" append-to-body>
<el-form ref="form" :model="form" label-width="120px">
<el-divider content-position="center">基本信息</el-divider>
<el-row>
<el-col :span="12">
<el-form-item label="项目名称" prop="projectName">
<el-input v-model="form.projectName" placeholder="请输入项目名称" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="项目总金额" prop="funds">
<el-input v-model="form.funds" placeholder="请输入项目地址" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预付款" prop="prePay">
<el-input v-model="form.prePay" placeholder="请输入预付款" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="负责人" prop="functionary">
<el-input v-model="form.functionary" placeholder="请输入项目负责人" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="签约公司" prop="signingCompany">
<el-select v-model="form.signingCompany" placeholder="请选择签约公司" style="width: 100%" clearable>
<el-option v-for="dict in dict.type.signing_company" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="签约客户" prop="customerId">
<el-select v-model="form.customerId" placeholder="请选择签约客户" filterable style="width: 100%" clearable>
<el-option v-for="item in customerList" :key="item.customerId" :label="item.name"
:value="item.customerId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目代号" prop="projectCode">
<el-select v-model="form.projectCodeType" placeholder="请选择代号类型" style="width: 50%" filterable
:filter-method="filterCode">
<el-option v-for="dict in dict.type.sys_project_code" :key="dict.value" :label="dict.label"
:value="dict.value">
<span style="float: left">{{ dict.label }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ dict.value }}</span>
</el-option>
</el-select>
<el-input :disabled="!form.projectCodeType" style="width: 50%" v-model="form.projectCodeNumber"
placeholder="请输入代号序号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目编号" prop="projectNum">
<el-input v-model="form.projectNum" placeholder="请输入项目编号" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="项目介绍" prop="introduction">
<el-input v-model="form.introduction" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目地址" prop="address">
<el-input v-model="form.address" placeholder="请输入项目地址" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="贸易类型" prop="tradeType">
<el-select v-model="form.tradeType" placeholder="请选择贸易类型" clearable>
<el-option v-for="dict in dict.type.sys_trade_type" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="项目类型" prop="projectType">
<el-select v-model="form.projectType" placeholder="请选择项目类型" style="width: 100%">
<el-option v-for="dict in dict.type.sys_project_type" :key="dict.value" :label="dict.label"
:value="dict.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="优先级" prop="projectGrade">
<el-radio-group v-model="form.projectGrade">
<el-radio-button v-for="dict in dict.type.sys_sort_grade" :key="dict.value" :label="dict.value">{{
dict.label }}
</el-radio-button>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="项目周期">
<el-date-picker v-model="periodItem" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
range-separator="" start-placeholder="开始日期" end-placeholder="结束日期" @blur="getTimeBlur">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="交货期" prop="delivery">
<el-input v-model="form.delivery" placeholder="请输入交货期" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="质保期" prop="guarantee">
<el-input v-model="form.guarantee" placeholder="请输入质保期" />
</el-form-item>
</el-col>
<!-- <el-col :span="24" v-if="form.isPostpone == 1">
<el-form-item label="周期延长">
<el-date-picker v-model="periodItem" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
range-separator="" start-placeholder="开始日期" end-placeholder="结束日期" @blur="getTimeBlur">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="24" v-if="form.isPostpone == 1">
<el-form-item label="延期原因" prop="postPoneReason">
<el-input v-model="form.postPoneReason" type="textarea" placeholder="请输入延期原因" />
</el-form-item>
</el-col> -->
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件" prop="accessory">
<file-upload v-model="form.accessory" />
</el-form-item>
</el-col>
</el-row>
<el-row v-if="form.projectId">
<el-divider content-position="center">甲方开票信息</el-divider>
<el-col :span="6">
<el-form-item label="开票名称" prop="remark">
<el-input v-model="form.invoiceName" placeholder="请输入开票名称" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="纳税人识别号" prop="remark">
<el-input v-model="form.invoiceNumber" placeholder="请输入纳税人识别号" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="地址电话" prop="remark">
<el-input v-model="form.invoiceAddress" placeholder="请输入地址电话" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="开户行及账号" prop="remark">
<el-input v-model="form.invoiceBank" placeholder="请输入开户行及账号" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">保存</el-button>
</div>
</el-dialog>
<!-- 项目查看对话框 -->
<el-dialog :title="title" :visible.sync="detailShow" @close="closeDialog" width="76%" append-to-body>
<el-tabs tab-position="left" v-model="tabContract" @tab-click="handleTabContract" style="min-height: 400px;">
<el-tab-pane label="项目信息" name="first">
<ProjectInfo :info="form" />
<div style="margin-top: 24px"></div>
<el-descriptions class="margin-top" title="开票信息" :column="4" border>
<el-descriptions-item label="开票名称" :span="2" :labelStyle="lableBg">
{{ form.invoiceName == null ? '未填写' : form.invoiceName }}
</el-descriptions-item>
<el-descriptions-item label="纳税人识别号" :span="2" :labelStyle="lableBg">
{{ form.invoiceNumber == null ? '未填写' : form.invoiceNumber }}
</el-descriptions-item>
<el-descriptions-item label="地址电话" :span="2" :labelStyle="lableBg">
{{ form.invoiceAddress == null ? '未填写' : form.invoiceAddress }}
</el-descriptions-item>
<el-descriptions-item label="开户行及账号" :span="2" :labelStyle="lableBg">
{{ form.invoiceBank == null ? '未填写' : form.invoiceBank }}
</el-descriptions-item>
</el-descriptions>
<div style="margin-top: 24px"></div>
</el-tab-pane>
<el-tab-pane label="项目合同" name="tab01">
<div v-if="contractForm.contractName != undefined">
<el-descriptions :title="desTitle" class="margin-top" :column="3" border>
<template slot="extra">
项目编号{{ projectNum }}
</template>
<el-descriptions-item span="2" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-user"></i>
项目名称
</template>
{{ contractForm.contractName }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-s-unfold"></i>
合同编号
</template>
{{ contractForm.contractNum }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-eleme"></i>
甲方名称
</template>
{{ contractForm.firstName }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-user"></i>
甲方负责人
</template>
{{ contractForm.firstPerson }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-mobile-phone"></i>
甲方电话
</template>
{{ contractForm.firstPhone }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-eleme"></i>
乙方名称
</template>
{{ contractForm.secondName }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-user"></i>
乙方负责人
</template>
{{ contractForm.secondPerson }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-mobile-phone"></i>
乙方电话
</template>
{{ contractForm.secondPhone }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-trophy"></i>
合同金额
</template>
{{ contractForm.contractPrice }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-c-scale-to-original"></i>
签订日期
</template>
{{ contractForm.signTime }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-date"></i>
有效期
</template>
{{ contractForm.validity }}
</el-descriptions-item>
<el-descriptions-item span="3" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-pie-chart"></i>
备注
</template>
{{ contractForm.remark }}
</el-descriptions-item>
<el-descriptions-item span="3" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-paperclip"></i>
附件
</template>
<!--附件-->
<template>
<file-preview v-model="contractForm.accessory"></file-preview>
</template>
<!--附件-->
</el-descriptions-item>
</el-descriptions>
</div>
<div v-else>
<div class="message">暂无项目合同信息请在合同管理里添加项目合同信息</div>
</div>
</el-tab-pane>
<el-tab-pane label="采购合同" name="tab02">
<div v-if="oaContractList.length == 0" class="message">暂无采购合同信息请在合同管理里添加采购合同信息
</div>
<div v-else>
<el-table :data="oaContractList" row-key="projectId" style="margin-bottom: 30px">
<el-table-column label="合同名称" align="left" prop="contractName" />
<el-table-column label="甲方名称" align="center" prop="firstName" width="180" />
<el-table-column label="乙方名称" align="center" prop="secondName" width="220" />
<el-table-column label="乙方负责人" align="center" prop="secondPerson" width="100" />
<el-table-column label="乙方电话" align="center" prop="secondPhone" width="120" />
<el-table-column label="合同金额" align="center" prop="contractPrice" width="150" />
<el-table-column label="签订日期" align="center" prop="signTime" width="100">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.signTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="创建者" align="center" prop="createBy" width="80" />
<el-table-column label="创建时间" align="center" prop="createTime" width="100">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-view" @click="handlePreview(scope.row)"
v-hasPermi="['oa:oaContract:edit']">查看
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="结项文件" name="tab03">
<file-upload v-model="form.closureFiles" @success="handleClosureFiles"></file-upload>
</el-tab-pane>
<el-tab-pane label="其他文件" name="tab04">
<el-table @row-click="handleRowClick" v-if="otherFiles.length > 0" :data="otherFiles"
style="margin-bottom: 30px">
<el-table-column label="文件名称" prop="originalName" />
<el-table-column label="上传人" prop="createBy" />
<el-table-column label="上传时间" prop="createTime" />
<el-table-column label="操作" prop="action">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-delete"
@click="handleDownload(scope.row)">下载</el-button>
</template>
</el-table-column>
</el-table>
<div v-else>暂无其他文件</div>
</el-tab-pane>
<el-tab-pane label="进度文件" name="tab05">
<el-table @row-click="handleRowClick" v-if="paceFiles.length > 0" :data="paceFiles"
style="margin-bottom: 30px">
<el-table-column label="文件名称" prop="originalName" />
<el-table-column label="上传人" prop="createBy" />
<el-table-column label="上传时间" prop="createTime" />
<el-table-column label="操作" prop="action">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-delete"
@click="handleDownload(scope.row)">下载</el-button>
</template>
</el-table-column>
</el-table>
<div v-else>暂无进度文件</div>
</el-tab-pane>
</el-tabs>
</el-dialog>
<!-- 项目合同查看对话框 -->
<el-dialog :title="titleContract" :visible.sync="dialogContract" width="55%" append-to-body>
<el-descriptions :title="desTitle" class="margin-top" :column="3" border>
<template slot="extra">
项目编号{{ projectNum }}
</template>
<el-descriptions-item span="2" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-user"></i>
合同名称
</template>
{{ contractForm.contractName }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-s-unfold"></i>
合同编号
</template>
{{ contractForm.contractNum }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-eleme"></i>
甲方名称
</template>
{{ contractForm.firstName }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-user"></i>
甲方负责人
</template>
{{ contractForm.firstPerson }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-mobile-phone"></i>
甲方电话
</template>
{{ contractForm.firstPhone }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-eleme"></i>
乙方名称
</template>
{{ contractForm.secondName }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-user"></i>
乙方负责人
</template>
{{ contractForm.secondPerson }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-mobile-phone"></i>
乙方电话
</template>
{{ contractForm.secondPhone }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-trophy"></i>
合同金额
</template>
{{ contractForm.contractPrice }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-c-scale-to-original"></i>
签订日期
</template>
{{ contractForm.signTime }}
</el-descriptions-item>
<el-descriptions-item span="1" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-date"></i>
有效期
</template>
{{ contractForm.validity }}
</el-descriptions-item>
<el-descriptions-item span="3" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-pie-chart"></i>
备注
</template>
{{ contractForm.remark }}
</el-descriptions-item>
<el-descriptions-item span="3" :labelStyle="lableBg">
<template slot="label">
<i class="el-icon-paperclip"></i>
附件
</template>
<!--附件-->
<template>
<file-preview v-model="contractForm.accessory"></file-preview>
</template>
<!--附件-->
</el-descriptions-item>
</el-descriptions>
</el-dialog>
<!-- 项目延期对话框 -->
<el-dialog title="项目延期" :visible.sync="postPoneOpen" width="55%">
<PostPone :projectId="currentProjectId" @finish="postPoneOpen = false" />
</el-dialog>
</div>
</template>
<script>
import { listCustomer } from "@/api/oa/customer";
import { findContractByProjectId, getOaContract, selectContractByProjectId } from "@/api/oa/oaContract";
import { addProject, delProject, getProject, listProject, updateProject } from "@/api/oa/project";
import { listProjectSchedule } from "@/api/oa/projectSchedule";
import { listPage } from "@/api/oa/projectScheduleStep";
import { listTask } from "@/api/oa/task";
import { listByIds } from "@/api/system/oss";
import ProjectInfo from "@/components/fad-service/ProjectInfo/index.vue";
import FadTable from "@/components/fad-ui/fad-table/index.vue";
import FilePreview from "@/components/FilePreview/index.vue";
import PostPone from "@/views/oa/project/components/PostPone.vue";
import Dict from "@/views/system/dict/index.vue";
export default {
name: "Project",
components: { FilePreview, Dict, PostPone, ProjectInfo, FadTable },
inject: ['$folder'],
dicts: [
'sys_project_status',
'sys_project_type',
'sys_sort_grade',
'sys_work_type',
'sys_sort_grade',
'sys_trade_type',
'sys_project_code',
'signing_company'],
data () {
return {
floatLayerConfig: {
columns: [
{ prop: 'projectName', label: '项目名称' },
{ prop: 'projectNum', label: '项目编号' },
{ prop: 'projectCode', label: '项目代号' },
{ prop: 'functionary', label: '项目负责人' },
{ prop: 'customerName', label: '客户名称' },
{
prop: 'signingCompany', label: '签订公司', formatter: (value) => {
const dicts = this.dict.type.signing_company
console.log('dicts', dicts, value)
const signingCompany = dicts.find(item => item.value == value)
return signingCompany?.label || value
}
},
{ prop: 'remark', label: '备注' },
{
prop: 'funds', label: '项目总金额', formatter: (value) => {
return this.convertToTenThousand(value)
}
},
{
prop: 'prePay', label: '预付款', formatter: (value) => {
return this.convertToTenThousand(value)
}
},
{
prop: 'beginTime', label: '开始时间'
}
],
title: '详细信息'
},
folderInstance: null,
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 项目管理表格数据
projectList: [],
//tabs标签
tabContract: 'tab01',
// 弹出层标题
title: "",
titleContract: "",
//编辑弹出层
editShow: false,
// 是否显示弹出层
open: false,
//合同项目信息
projectId: '',
desTitle: '8888',
projectNum: '',
contractForm: {},
//附件
fileList: [],
//详情lable背景
lableBg: "background: #f0f9eb; width:150px; text-align: center;",
//采购合同列表
oaContractList: [],
dialogContract: false,
searchTime: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
projectName: undefined,
projectNum: undefined,
beginTime: undefined,
finishTime: undefined,
signingCompany: undefined,
customerId: undefined,
},
// 表单参数
form: {},
periodItem: '',
// 表单校验
rules: {
projectId: [
{ required: true, message: "ID不能为空", trigger: "blur" }
],
projectName: [
{ required: true, message: "项目名称不能为空", trigger: "blur" }
],
projectNum: [
{ required: true, message: "项目编号不能为空", trigger: "blur" }
],
projectType: [
{ required: true, message: "项目类型不能为空", trigger: "change" }
],
functionary: [
{ required: true, message: "项目负责人不能为空", trigger: "blur" }
],
address: [
{ required: true, message: "项目地址不能为空", trigger: "blur" }
],
funds: [
{ required: true, message: '项目总金额不能为空', trigger: 'blur' },
{
validator: (rule, value, callback) => {
const regex = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9]))/;
if (!regex.test(value)) {
callback(new Error('请输入正确的金额格式'));
} else {
callback();
}
},
trigger: 'blur'
}
],
beginTime: [
{ required: true, message: "开始日期不能为空", trigger: "blur" }
],
finishTime: [
{ required: true, message: "结束日期不能为空", trigger: "blur" }
],
contractId: [
{ required: true, message: "关联合同ID不能为空", trigger: "blur" }
],
},
dictBackup: [],
otherFiles: '',
detailShow: false,
otherFilesLoading: false,
currentProjectId: '',
postPoneOpen: false,
customerList: [],
paceFiles: [],
paceFilesLoading: [],
};
},
watch: {
// 监听整个 query 对象,如果有多个 query 参数也一起触发
'$route.query': {
handler () {
this.initFromRoute()
},
immediate: false,
deep: true
},
},
created () {
this.initFromRoute()
this.getDicts();
this.getCustomerList();
this.dictBackup = this.dict.type.sys_project_code;
this.folderInstance = this.$folder();
},
methods: {
getCustomerList () {
listCustomer({ pageNum: 1, pageSize: 999 }).then(response => {
this.customerList = response.rows;
}).catch(() => {
this.customerList = [];
});
},
handleRowChange (row) {
this.loading = true;
const payload = {
...row,
projectId: row.projectId,
isTop: row.isTop ? 1 : 0,
}
updateProject(payload).then(response => {
this.$modal.msgSuccess("更新成功");
this.getList();
}).catch(() => {
this.$modal.msgError("更新失败");
});
},
initFromRoute () {
// 每次路由 query 变化都重新赋值并拉列表
this.queryParams.projectName = this.$route.query.projectName
// 新增逻辑如果有projectId参数拉取单个项目
if (this.$route.query.projectId && this.$route.query.projectId !== '') {
this.getSingleProject(this.$route.query.projectId);
} else {
this.getList();
}
},
// 新增:获取单个项目详情
getSingleProject (projectId) {
this.loading = true;
getProject(projectId).then(response => {
this.projectList = [response.data];
this.total = 1;
this.loading = false;
}).catch(() => {
this.projectList = [];
this.total = 0;
this.loading = false;
});
},
/** 输入时同时按 label / value 本地过滤 */
filterCode (query) {
query = (query || '').toLowerCase();
this.dict.type.sys_project_code = this.dictBackup.filter(item => {
return item.label.toLowerCase().indexOf(query) > -1 || item.value.toLowerCase().indexOf(query) > -1;
});
},
toDetail (row) {
console.log(row)
this.$router.push('/customer/detail/' + row.customerId);
},
handleDetail (row) {
this.loading = true;
this.detailShow = true;
this.reset();
const projectId = row.projectId
this.projectId = row.projectId;
this.handleContract(row);
getProject(projectId).then(response => {
console.log(response.data);
this.loading = false;
this.form = response.data;
let period = [];
period.push(response.data.beginTime);
period.push(response.data.finishTime);
this.periodItem = period;
this.form.signingCompany = this.form.signingCompany.toString();
this.open = true;
this.title = "项目名称:" + response.data.projectName;
});
},
handlePostPone (row) {
this.currentProjectId = row.projectId;
this.postPoneOpen = true;
},
/** 查询项目管理列表 */
getList () {
this.loading = true;
if (null != this.searchTime && '' != this.searchTime) {
this.queryParams["beginCreateTime"] = this.getRealDate(this.searchTime[0]);
this.queryParams["endCreateTime"] = this.getRealDate(this.searchTime[1]);
}
listProject(this.queryParams).then(response => {
this.projectList = response.rows.map(item => {
if (item.projectCode) {
item.projectCodeType = item.projectCode.split('-')[0];
item.projectCodeNumber = item.projectCode.split('-')[1];
} else {
item.projectCodeType = undefined;
item.projectCodeNumber = undefined;
}
return item;
});
this.total = response.total;
this.loading = false;
});
},
/**日期转字符串**/
getRealDate (startDate) {
// 时间转换
var datejson = new Date(startDate).toJSON();
var date = new Date(+new Date(datejson)
+ 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '')
return date;
},
// 取消按钮
cancel () {
this.open = false;
this.reset();
},
// 表单重置
reset () {
this.form = {
projectId: undefined,
projectName: undefined,
projectNum: undefined,
projectType: undefined,
projectCodeType: undefined,
projectCodeNumber: undefined,
address: undefined,
functionary: undefined,
beginTime: undefined,
finishTime: undefined,
delivery: undefined,
guarantee: undefined,
introduction: undefined,
projectGrade: undefined,
projectStatus: undefined,
contractId: undefined,
invoiceName: undefined,
invoiceNumber: undefined,
invoiceAddress: undefined,
invoiceBank: undefined,
accessory: undefined,
remark: undefined,
tradeType: 1,
prePay: undefined,
projectCode: undefined,
closureFiles: undefined,
signingCompany: undefined,
customerId: undefined,
};
this.resetForm("form");
this.contractForm = {};
this.fileList = [];
},
selectPrePay () {
this.handleQuery()
},
/** 搜索按钮操作 */
handleQuery () {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery () {
this.searchTime = [];
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange (selection) {
this.ids = selection.map(item => item.projectId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd () {
this.reset();
this.periodItem = ''
this.editShow = true;
// this.open = true;
this.title = "添加项目";
},
/**
* 时间范围失去焦点时绑定日期数据
* @param e
*/
getTimeBlur (e) {
this.form.beginTime = e.value[0]
this.form.finishTime = e.value[1]
this.form.postponeTime = e.value[1]
},
/** 修改按钮操作 */
handleUpdate (row) {
this.loading = true;
this.editShow = true;
this.reset();
const projectId = row.projectId
this.projectId = row.projectId;
this.handleContract(row);
getProject(projectId).then(response => {
console.log(response.data);
this.loading = false;
this.form = response.data;
let period = [];
period.push(response.data.beginTime);
period.push(response.data.finishTime);
this.periodItem = period;
this.form.signingCompany = this.form.signingCompany.toString();
this.open = true;
this.title = "项目名称:" + response.data.projectName;
});
},
/**项目合同管理**/
handleContract (row) {
this.reset();
this.loading = true;
this.projectId = row.projectId;
this.desTitle = row.projectName;
this.projectNum = row.projectNum
this.findContract(row.projectId)
},
findContract (pId) {
let data = {
projectId: pId,
contractType: '2'
}
findContractByProjectId(data).then(res => {
if (res.data == null) {
this.contractForm = {
contractId: undefined,
projectId: undefined,
contractNum: undefined,
contractName: undefined,
firstName: undefined,
firstPerson: undefined,
firstPhone: undefined,
secondName: undefined,
secondPerson: undefined,
secondPhone: undefined,
contractPrice: undefined,
signTime: undefined,
validity: undefined,
contractStatus: undefined,
accessory: undefined,
remark: undefined,
createBy: undefined,
createTime: undefined,
updateBy: undefined,
updateTime: undefined,
}
} else {
this.contractForm = res.data;
this.getFile(res.data.accessory);
}
})
},
handleRowClick (row) {
// this.folderInstance.setFiles([row]);
this.folderInstance.previewSimple(row);
},
/**采购合同列表**/
getContractList (pId, cType) {
this.loading = true;
let data = {
projectId: pId,
contractType: cType
}
selectContractByProjectId(data).then(response => {
this.oaContractList = response.data;
})
},
handleClosureFiles () {
updateProject(this.form).then(res => {
this.$modal.msgSuccess("结项文件已更新");
this.getList();
})
},
/**查看采购合同**/
handlePreview (row) {
this.loading = true;
this.dialogContract = true;
this.contractForm = {};
this.projectId = row.projectId;
// this.reset();
// this.buyOntractShow = false;
this.titleContract = "查看合同";
this.getContractById(row.contractId);
},
/**获取合同信息**/
getContractById (cId) {
getOaContract(cId).then(response => {
this.loading = false;
this.contractForm = response.data;
this.getFile(response.data.accessory);
});
},
/** 提交按钮 */
submitForm () {
this.$refs["form"].validate(async (valid) => {
if (valid) {
this.buttonLoading = true;
// 只有projectCodeType和projectCodeNumber都有值时才拼接项目代号
const projectCode = (this.form.projectCodeType && this.form.projectCodeNumber) ? this.form.projectCodeType + '-' + this.form.projectCodeNumber : undefined;
const payload = {
...this.form,
beginTime: this.periodItem[0],
finishTime: this.periodItem[1],
customerId: this.form.customerId ? this.form.customerId : 0,
projectCode,
}
//履约保证金转json
try {
if (this.form.projectId != null) {
await updateProject(payload)
this.$modal.msgSuccess("修改成功");
} else {
await addProject(payload)
this.$modal.msgSuccess("新增成功");
this.editShow = false;
this.getList();
}
// 刷新项目选择器中的数据
// this.$store.dispatch('meta/getProjectList')
this.getList();
} finally {
this.buttonLoading = false;
}
}
});
},
/**项目完成后修改项目状态**/
changeProjectStatus () {
this.form.projectStatus = '1';
updateProject(this.form).then(response => {
this.$modal.msgSuccess("任务进度完成");
this.getList()
}).finally(() => {
this.buttonLoading = false;
});
},
/** 金额转为万元 **/
convertToTenThousand (amount) {
const convertToTenThousand = (amount) => `${Number((amount / 10000).toFixed(6))} 万元`;
return convertToTenThousand(amount);
},
/**合同选项卡**/
handleTabContract (tab, event) {
if (tab.index == '1') {
this.getContractList(this.projectId, 2);
} else if (tab.index == '2') {
this.getContractList(this.projectId, 1);
} else if (tab.index == '3') {
console.log(tab.index, '获取结项文件');
} else if (tab.index == '4') {
this.otherFilesLoading = true;
listTask({
projectId: this.projectId,
pageSize: 999,
}).then(res => {
const files = [...new Set(res.rows.map(item => item.accessory).filter(item => item))];
if (!files.length) return;
// 调用listOss获取文件列表详情
listByIds(files).then(res => {
this.otherFiles = res.data;
console.log(this.otherFiles, res, 'otherFiles');
}).finally(() => {
this.otherFilesLoading = false;
})
}).finally(() => {
this.otherFilesLoading = false;
})
} else if (tab.index == '5') {
this.paceFilesLoading = true;
listProjectSchedule({
projectId: this.projectId,
pageSize: 1,
}).then(res => {
if (!res.rows.length) return;
const scheduleId = res.rows[0].scheduleId;
listPage({
scheduleId: scheduleId,
pageSize: 999,
}).then(res => {
const paceFiles = res.rows.map(item => item.relatedDocs).filter(item => item).join(',');
console.log(paceFiles, 'paceFiles', res.rows.map(item => item.relatedDocs));
if (paceFiles.length == 0) return;
listByIds(paceFiles).then(res => {
this.paceFiles = res.data;
console.log(this.paceFiles, res, 'paceFiles');
}).finally(() => {
this.paceFilesLoading = false;
})
}).finally(() => {
this.paceFilesLoading = false;
})
}).finally(() => {
this.paceFilesLoading = false;
})
}
},
/**获取附件**/
getFile (val) {
if (val) {
listByIds(val).then(res => {
this.fileList = res.data;
})
} else {
this.fileList = [];
}
},
/** 关闭弹窗 **/
closeDialog () {
this.editShow = false;
this.detailShow = false;
this.tabContract = 'tab01';
this.getList();
},
/** 删除按钮操作 */
handleDelete (row) {
const projectIds = row.projectId || this.ids;
this.$modal.confirm('是否确认删除项目管理编号为"' + projectIds + '"的数据项?').then(() => {
this.loading = true;
return delProject(projectIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
/** 项目状态改为结项 */
handleClosure (row) {
this.$modal.confirm('是否确认结项"' + row.projectName + '"的数据项?').then(() => {
this.loading = true;
row.projectStatus = '1';
return updateProject(row)
}).then(() => {
this.loading = false;
// this.$router.push('/project/closure/detail/'+row.projectId)
this.$modal.msgSuccess("操作成功")
this.getList();
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
/** 项目状态改为待验收 */
handleComplete (row) {
this.$modal.confirm('是否确认完成"' + row.projectName + '"的数据项?将会将项目状态改为待验收状态').then(() => {
this.loading = true;
row.projectStatus = '2';
return updateProject(row)
}).then(() => {
this.loading = false;
// this.$router.push('/project/closure/detail/'+row.projectId)
this.$modal.msgSuccess("操作成功")
this.getList();
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
handleDownload (row) {
this.$download.oss(row.ossId);
}
}
};
</script>
<style scoped>
.line {
padding-left: 13px
}
.dialog-footer {
padding-left: 70px
}
.el-timeline {
margin: 0;
font-size: 16px;
font-weight: 600;
list-style: none;
padding-left: 20px;
}
.el-card__body {
padding: 0
}
.card-col {
margin-top: 10px;
padding: 10px 15px
}
.el-descriptions__header {
margin-bottom: 5px;
margin-top: 5px;
}
.el-descriptions__extra {
font-size: 12px;
font-weight: 500;
color: #cccccc
}
h4,
p {
line-height: 24px;
padding: 0;
margin: 0;
font-weight: 500
}
.message {
color: #cccccc;
text-align: center
}
/*分割线的样式*/
.el-divider {
background-color: #409eff;
}
.el-divider--horizontal {
display: block;
height: 1px;
width: 100%;
margin: 10px 20px 20px 20px;
}
.el-divider__text.is-left {
color: #409eff;
left: 0;
font-weight: bold;
margin: 0 10px;
padding: 0 5px;
}
/*分割线的样式 end*/
</style>