crm 添加合同模式 添加合同状态 客户签约方

pull/853/head
wersd 2025-06-22 21:30:16 +08:00
parent 3f527669ed
commit 8ec57f041d
8 changed files with 169 additions and 155 deletions

View File

@ -4,8 +4,11 @@ import { TransferReqVO } from '@/api/crm/permission'
export interface ContactVO {
id: number // 编号
name: string // 联系人名称
customerId: number // 客户编号
customerName?: string // 客户名称
customerId: number[] // 客户编号
customer?: {
id: number // 客户编号
name: string // 客户名称
}
contactLastTime: Date // 最后跟进时间
contactLastContent: string // 最后跟进内容
contactNextTime: Date // 下次联系时间

View File

@ -5,8 +5,12 @@ export interface ContractVO {
id: number
name: string
no: string
customerId: number
customerName?: string
customerId: number[]
customer?:{
id: number
name: string
}
businessId: number
businessName: string
contactLastTime: Date
@ -14,6 +18,9 @@ export interface ContractVO {
ownerUserName?: string
ownerUserDeptName?: string
processInstanceId: number
contractStatus: number
contractType: number
contractAttribute: number
auditStatus: number
orderDate: Date
startTime: Date

View File

@ -214,6 +214,10 @@ export enum DICT_TYPE {
CRM_FOLLOW_UP_TYPE = 'crm_follow_up_type', // CRM 跟进方式
CRM_STATION_SITE_STATUS = 'crm_station_site_status', // CRM 场地状态
CRM_STATION_SITE_TYPE = 'crm_station_site_type', // CRM 场地类型
CRM_CONTRACT_TYPE = 'crm_contract_type', // CRM 合同类型
CRM_CONTRACT_STATUS = 'crm_contract_status', // CRM 合同状态
CRM_CONTRACT_ATTRIBUTE = 'crm_contract_attribute', // CRM 合同属性
// ========== ERP - 企业资源计划模块 ==========
ERP_AUDIT_STATUS = 'erp_audit_status', // ERP 审批状态

View File

@ -8,10 +8,46 @@
label-width="120px"
>
<el-row>
<el-col :span="8">
<!-- <el-col :span="8">
<el-form-item label="合同编号" prop="no">
<el-input disabled v-model="formData.no" placeholder="保存时自动生成" />
</el-form-item>
</el-col> -->
<el-col :span="8">
<el-form-item label="客户签约方 " prop="customerId">
<el-select
v-model="formData.customerId"
placeholder="请选择客户签约方 "
class="w-1/1"
@change="handleCustomerChange"
:multiple-limit="3"
filterable
clearable
multiple
>
<el-option
v-for="item in customerList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="公司签约方主体" prop="deptId">
<el-select
v-model="formData.deptId"
class="w-1/1"
>
<el-option
v-for="item in deptList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="合同名称" prop="name">
@ -37,29 +73,49 @@
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="客户名称" prop="customerId">
<el-select
v-model="formData.customerId"
placeholder="请选择客户"
class="w-1/1"
@change="handleCustomerChange"
>
<el-form-item label="合同状态" prop="contractStatus">
<el-select v-model="formData.contractStatus" placeholder="请选择合同状态" class="w-1/1">
<el-option
v-for="item in customerList"
:key="item.id"
:label="item.name"
:value="item.id"
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CONTRACT_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="合同类型" prop="contractType">
<el-select v-model="formData.contractType" placeholder="请选择合同类型" class="w-1/1">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CONTRACT_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="合同属性" prop="contractAttribute">
<el-select v-model="formData.contractAttribute" placeholder="请选择合同属性" class="w-1/1">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CONTRACT_ATTRIBUTE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="下单日期" prop="orderDate">
<el-form-item label="签订日期" prop="orderDate">
<el-date-picker
v-model="formData.orderDate"
placeholder="选择下单日期"
placeholder="选择签订日期"
type="date"
value-format="x"
class="!w-1/1"
@ -90,34 +146,7 @@
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="公司签约人" prop="signUserId">
<el-select v-model="formData.signUserId" class="w-1/1">
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.nickname"
:value="item.id!"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="客户签约人" prop="signContactId">
<el-select
v-model="formData.signContactId"
:disabled="!formData.customerId"
class="w-1/1"
>
<el-option
v-for="item in getContactOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" />
@ -185,6 +214,8 @@ import * as BusinessApi from '@/api/crm/business'
import { erpPriceMultiply, erpPriceInputFormatter } from '@/utils'
import { useUserStore } from '@/store/modules/user'
import ContractProductForm from '@/views/crm/contract/components/ContractProductForm.vue'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import * as DeptApi from '@/api/system/dept'
const { t } = useI18n() //
const message = useMessage() //
@ -197,7 +228,10 @@ const formData = ref({
id: undefined,
no: undefined,
name: undefined,
customerId: undefined,
customerId: [],
contractStatus: undefined,
contractType: undefined,
contractAttribute: undefined,
businessId: undefined,
orderDate: undefined,
startTime: undefined,
@ -205,6 +239,7 @@ const formData = ref({
signUserId: undefined,
signContactId: undefined,
ownerUserId: undefined,
deptId: undefined,
discountPercent: 0,
totalProductPrice: undefined,
remark: undefined,
@ -214,13 +249,17 @@ const formRules = reactive({
name: [{ required: true, message: '合同名称不能为空', trigger: 'blur' }],
customerId: [{ required: true, message: '客户不能为空', trigger: 'blur' }],
orderDate: [{ required: true, message: '下单日期不能为空', trigger: 'blur' }],
ownerUserId: [{ required: true, message: '负责人不能为空', trigger: 'blur' }]
ownerUserId: [{ required: true, message: '负责人不能为空', trigger: 'blur' }],
contractStatus: [{ required: true, message: '合同状态不能为空', trigger: 'blur' }],
contractType: [{ required: true, message: '合同类型不能为空', trigger: 'blur' }],
contractAttribute: [{ required: true, message: '合同属性不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
const userOptions = ref<UserApi.UserVO[]>([]) //
const customerList = ref([]) //
const businessList = ref<BusinessApi.BusinessVO[]>([])
const contactList = ref<ContactApi.ContactVO[]>([])
const deptList = ref<DeptApi.DeptVO[]>([])
/** 子表的表单 */
const subTabsName = ref('product')
@ -271,6 +310,8 @@ const open = async (type: string, id?: number) => {
}
//
contactList.value = await ContactApi.getSimpleContactList()
//
deptList.value = await DeptApi.getSimpleDeptList()
}
defineExpose({ open }) // open
@ -307,7 +348,10 @@ const resetForm = () => {
id: undefined,
no: undefined,
name: undefined,
customerId: undefined,
customerId: [],
contractStatus: undefined,
contractType: undefined,
contractAttribute: undefined,
businessId: undefined,
orderDate: undefined,
startTime: undefined,
@ -315,6 +359,7 @@ const resetForm = () => {
signUserId: undefined,
signContactId: undefined,
ownerUserId: undefined,
deptId: undefined,
discountPercent: 0,
totalProductPrice: undefined,
remark: undefined,

View File

@ -16,21 +16,48 @@
</div>
</div>
<ContentWrap class="mt-10px">
<el-descriptions :column="5" direction="vertical">
<el-descriptions-item label="客户名称">
{{ contract.customerName }}
<el-descriptions :column="3">
<!-- <el-descriptions-item label="合同编号">{{ contract.no }}</el-descriptions-item> -->
<el-descriptions-item label="合同名称">{{ contract.name }}</el-descriptions-item>
<el-descriptions-item label="客户签约方">
<div>
<template v-if="Array.isArray(contract.customer)">
<span v-for="(c, idx) in contract.customer" :key="c.id">
{{ c.name }}<span v-if="idx < contract.customer.length - 1"><br /> </span>
</span>
</template>
<template v-else>
{{ contract.customer?.name || '' }}
</template>
</div>
</el-descriptions-item>
<el-descriptions-item label="责任人">
{{ contract.ownerUserName }}
</el-descriptions-item>
<el-descriptions-item label="合同金额(元)">
{{ erpPriceInputFormatter(contract.totalPrice) }}
</el-descriptions-item>
<el-descriptions-item label="下单时间">
{{ formatDate(contract.orderDate) }}
<el-descriptions-item label="签订时间">
{{ formatDate(contract.orderDate, 'YYYY-MM-DD') }}
</el-descriptions-item>
<el-descriptions-item label="合同开始时间">
{{ formatDate(contract.startTime, 'YYYY-MM-DD') }}
</el-descriptions-item>
<el-descriptions-item label="合同结束时间">
{{ formatDate(contract.endTime, 'YYYY-MM-DD') }}
</el-descriptions-item>
<el-descriptions-item label="合同状态">
<dict-tag :type="DICT_TYPE.CRM_AUDIT_STATUS" :value="contract.auditStatus" />
</el-descriptions-item>
<el-descriptions-item label="合同金额(元)">
{{ erpPriceInputFormatter(contract.totalPrice) }}
</el-descriptions-item>
<el-descriptions-item label="付款金额(元)">
{{ erpPriceInputFormatter(contract.totalReceivablePrice) }}
</el-descriptions-item>
<el-descriptions-item label="负责人">
{{ contract.ownerUserName }}
<el-descriptions-item label="备注">
{{ contract.remark }}
</el-descriptions-item>
</el-descriptions>
</ContentWrap>
@ -38,6 +65,7 @@
<script lang="ts" setup>
import * as ContractApi from '@/api/crm/contract'
import { formatDate } from '@/utils/formatTime'
import { DICT_TYPE } from '@/utils/dict'
import { erpPriceInputFormatter } from '@/utils'
defineOptions({ name: 'ContractDetailsHeader' })

View File

@ -10,25 +10,19 @@
</ContractDetailsHeader>
<el-col>
<el-tabs>
<el-tab-pane label="跟进记录">
<FollowUpList :biz-id="contract.id" :biz-type="BizTypeEnum.CRM_CONTRACT" />
</el-tab-pane>
<el-tab-pane label="基本信息">
<ContractDetailsInfo :contract="contract" />
</el-tab-pane>
<el-tab-pane label="产品">
<ContractProductList :contract="contract" />
</el-tab-pane>
<el-tab-pane label="付款">
<ReceivablePlanList
:contract-id="contract.id!"
:customer-id="contract.customerId"
:customer-id="Array.isArray(contract.customerId) ? contract.customerId[0] : contract.customerId"
@create-receivable="createReceivable"
/>
<ReceivableList
ref="receivableListRef"
:contract-id="contract.id!"
:customer-id="contract.customerId"
:customer-id="Array.isArray(contract.customerId) ? contract.customerId[0] : contract.customerId"
/>
</el-tab-pane>
<el-tab-pane label="团队成员">

View File

@ -76,13 +76,8 @@
<!-- 列表 -->
<ContentWrap>
<el-tabs v-model="activeName" @tab-click="handleTabClick">
<el-tab-pane label="我负责的" name="1" />
<el-tab-pane label="我参与的" name="2" />
<el-tab-pane label="下属负责的" name="3" />
</el-tabs>
<el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true">
<el-table-column align="center" fixed="left" label="合同编号" prop="no" width="180" />
<!-- <el-table-column align="center" fixed="left" label="合同编号" prop="no" width="180" /> -->
<el-table-column align="center" fixed="left" label="合同名称" prop="name" width="160">
<template #default="scope">
<el-link :underline="false" type="primary" @click="openDetail(scope.row.id)">
@ -90,77 +85,48 @@
</el-link>
</template>
</el-table-column>
<el-table-column align="center" label="客户名称" prop="customerName" width="120">
<el-table-column align="center" label="客户签约方" prop="customer.id" width="350">
<template #default="scope">
<el-link
:underline="false"
type="primary"
@click="openCustomerDetail(scope.row.customerId)"
@click="openCustomerDetail(scope.row.customer[0].id)"
>
{{ scope.row.customerName }}
{{ scope.row.customer[0].name }}
</el-link>
</template>
</el-table-column>
<el-table-column align="center" label="商机名称" prop="businessName" width="130">
<template #default="scope">
<el-link
:underline="false"
type="primary"
@click="openBusinessDetail(scope.row.businessId)"
>
{{ scope.row.businessName }}
</el-link>
</template>
</el-table-column>
<el-table-column
<el-table-column align="center" label="所属部门" prop="ownerUserDeptName" width="160" />
<!-- <el-table-column
align="center"
label="合同金额(元)"
prop="totalPrice"
width="140"
:formatter="erpPriceTableColumnFormatter"
/>
<el-table-column
align="center"
label="下单时间"
prop="orderDate"
width="120"
:formatter="dateFormatter2"
/>
/> -->
<el-table-column
align="center"
label="合同开始时间"
prop="startTime"
width="120"
width="160"
:formatter="dateFormatter2"
/>
<el-table-column
align="center"
label="合同结束时间"
prop="endTime"
width="120"
width="160"
:formatter="dateFormatter2"
/>
<el-table-column align="center" label="客户签约人" prop="contactName" width="130">
<template #default="scope">
<el-link
:underline="false"
type="primary"
@click="openContactDetail(scope.row.signContactId)"
>
{{ scope.row.signContactName }}
</el-link>
</template>
</el-table-column>
<el-table-column align="center" label="公司签约人" prop="signUserName" width="130" />
<el-table-column align="center" label="备注" prop="remark" width="200" />
<el-table-column
align="center"
label="已付款金额(元)"
label="已付款金额(万元)"
prop="totalReceivablePrice"
width="140"
width="160"
:formatter="erpPriceTableColumnFormatter"
/>
<el-table-column
<!-- <el-table-column
align="center"
label="未付款金额(元)"
prop="totalReceivablePrice"
@ -170,37 +136,20 @@
<template #default="scope">
{{ erpPriceInputFormatter(scope.row.totalPrice - scope.row.totalReceivablePrice) }}
</template>
</el-table-column>
<el-table-column
:formatter="dateFormatter"
align="center"
label="最后跟进时间"
prop="contactLastTime"
width="180px"
/>
<el-table-column align="center" label="负责人" prop="ownerUserName" width="120" />
<el-table-column align="center" label="所属部门" prop="ownerUserDeptName" width="100px" />
<el-table-column
:formatter="dateFormatter"
align="center"
label="更新时间"
prop="updateTime"
width="180px"
/>
<el-table-column
:formatter="dateFormatter"
align="center"
label="创建时间"
prop="createTime"
width="180px"
/>
<el-table-column align="center" label="创建人" prop="creatorName" width="120" />
<el-table-column align="center" fixed="right" label="合同状态" prop="auditStatus" width="120">
</el-table-column> -->
<el-table-column align="center" label="责任人" prop="ownerUserName" width="160" />
<el-table-column align="center" fixed="right" label="合同状态" prop="contractStatus" width="160">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_AUDIT_STATUS" :value="scope.row.auditStatus" />
<dict-tag :type="DICT_TYPE.CRM_CONTRACT_STATUS" :value="scope.row.contractStatus" />
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="250">
<el-table-column align="center" fixed="right" label="合同类型" prop="contractType" width="160">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_CONTRACT_TYPE" :value="scope.row.contractType" />
</template>
</el-table-column>
<el-table-column align="center" fixed="right" label="操作" min-width="250">
<template #default="scope">
<el-button
v-if="scope.row.auditStatus === 0"
@ -229,14 +178,6 @@
>
查看审批
</el-button>
<el-button
v-hasPermi="['crm:contract:query']"
link
type="primary"
@click="openDetail(scope.row.id)"
>
详情
</el-button>
<el-button
v-hasPermi="['crm:contract:delete']"
link
@ -281,7 +222,6 @@ const list = ref([]) // 列表的数据
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
sceneType: '1', // activeName
name: null,
customerId: null,
orderDate: [],
@ -289,14 +229,8 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const activeName = ref('1') // tab
const customerList = ref<CustomerApi.CustomerVO[]>([]) //
/** tab 切换 */
const handleTabClick = (tab: TabsPaneContext) => {
queryParams.sceneType = tab.paneName
handleQuery()
}
/** 查询列表 */
const getList = async () => {

View File

@ -6,7 +6,6 @@
<el-select
v-model="queryParams.creator"
filterable
remote
clearable
placeholder="请选择"
style="width: 150px"