项目 付款优化

pull/853/head
wersd 2025-07-12 22:31:12 +08:00
parent 0043a5e0d8
commit b20779bf9f
11 changed files with 172 additions and 134 deletions

View File

@ -20,6 +20,7 @@ export interface ProjectVO {
investmentAgreement: string // 合作投资协议
supplementaryMaterials: string // 其他补充材料文件路径
type: number // 类型
partners: []
projectStatus: number // 状态
estimatedPiles: number //枪数
}

View File

@ -17,7 +17,6 @@ export interface ReceivableVO {
no: string
totalPrice: number
}
isDeposit: boolean
auditStatus: number
processInstanceId: number
returnTime: Date

View File

@ -207,6 +207,7 @@ export enum DICT_TYPE {
CRM_RECEIVABLE_RETURN_TYPE = 'crm_receivable_return_type', // CRM 付款的付款方式
CRM_RECEIVABLE_TRANSACTION_TYPE = 'crm_receivable_transaction_type', // CRM 付款的收支方向
CRM_RECEIVABLE_TYPE = 'crm_receivable_type', // CRM 付款类型
CRM_PAYMENT_TYPE = 'crm_payment_type', // CRM 收款类型
CRM_RECEIVABLE_PLAN_STATUS = 'crm_receivable_plan_status', // CRM 付款计划状态
CRM_CUSTOMER_INDUSTRY = 'crm_customer_industry', // CRM 客户所属行业
CRM_CUSTOMER_DEAL_STATUS = 'crm_customer_deal_status', // CRM 客户成交状态
@ -222,6 +223,7 @@ export enum DICT_TYPE {
CRM_CONTRACT_STATUS = 'crm_contract_status', // CRM 合同状态
CRM_CONTRACT_ATTRIBUTE = 'crm_contract_attribute', // CRM 合同属性
CRM_PROJECT_TYPE = 'crm_project_type', // CRM 项目类型
CRM_PROJECT_POWER_SUPPLY_TYPE = 'crm_project_power_supply_type', // CRM 项目供电模式
// ========== ERP - 企业资源计划模块 ==========
ERP_AUDIT_STATUS = 'erp_audit_status', // ERP 审批状态

View File

@ -150,7 +150,6 @@
</el-col>
</el-row>
<el-row>
<el-col>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" />

View File

@ -61,8 +61,8 @@
<el-radio-group
v-model="formData.projectStatus"
>
<el-radio value="0">关闭</el-radio>
<el-radio value="1">开启</el-radio>
<el-radio :value=0>开启</el-radio>
<el-radio :value=1>关闭</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
@ -141,24 +141,38 @@
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col>
<el-form-item v-if="formData.type === 2" label="合伙人明细">
<ProjectPartnetForm
ref="partnerFormRef"
v-model:partners="formData.partners"
:disabled="formLoading"
:price="formData.totalInvestment"
/>
<el-col :span="12">
<el-form-item label="供电类型" prop="powerSupplyType">
<el-select v-model="formData.powerSupplyType" placeholder="请选择类型">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_PROJECT_POWER_SUPPLY_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col>
<el-tabs v-if="formData.type === 2" v-model="subTabsName" class="-mt-15px mb-10px">
<el-tab-pane label="合伙人明细" name="partner">
<ProjectPartnetForm
ref="partnerFormRef"
:partners="formData.partners"
:disabled="formLoading"
:price="formData.totalInvestment"
/>
</el-tab-pane>
</el-tabs>
</el-col>
</el-row>
{{formData }}
<el-divider>附件</el-divider>
<el-row>
<el-col :span="12">
<el-form-item label="同意建桩证明" prop="buildPermit">
<el-form-item label="同意建桩证明" prop="buildPermit" label-width="120px">
<UploadFile
v-model="formData.buildPermit"
:isShowTip="false"
@ -168,7 +182,7 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="场地权属证明" prop="ownershipProof">
<el-form-item label="场地权属证明" prop="ownershipProof" label-width="120px">
<UploadFile
v-model="formData.ownershipProof"
:isShowTip="false"
@ -180,7 +194,7 @@
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="项目备案" prop="projectRecord">
<el-form-item label="项目备案" prop="projectRecord" label-width="120px">
<UploadFile
v-model="formData.projectRecord"
:isShowTip="false"
@ -190,29 +204,7 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供电答复单" prop="powerSupplyReply">
<UploadFile
v-model="formData.powerSupplyReply"
:isShowTip="false"
:limit="1"
:file-type="['pdf']"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col v-if="formData.type === 2" :span="12">
<el-form-item label="合作投资协议" prop="investmentAgreement">
<UploadFile
v-model="formData.investmentAgreement"
:isShowTip="false"
:limit="1"
:file-type="['pdf']"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="其他补充材料" prop="supplementaryMaterials">
<el-form-item label="其他补充材料" prop="supplementaryMaterials" label-width="120px">
<UploadFile
v-model="formData.supplementaryMaterials"
:isShowTip="false"
@ -222,7 +214,28 @@
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col v-if="formData.type === 2" :span="12">
<el-form-item label="合作投资协议" prop="investmentAgreement" label-width="120px">
<UploadFile
v-model="formData.investmentAgreement"
:isShowTip="false"
:limit="1"
:file-type="['pdf']"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="formData.powerSupplyType === 2" label="供电答复单" prop="powerSupplyReply" label-width="120px">
<UploadFile
v-model="formData.powerSupplyReply"
:isShowTip="false"
:limit="1"
:file-type="['pdf']"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
@ -256,35 +269,41 @@ const formData = ref({
deptId: undefined,
siteId: undefined,
totalInvestment: 0,
partner: undefined,
ratio: undefined,
investment: 0,
cooperationAgreement: undefined,
purchaseContractId: undefined,
cooperationAgreement:undefined,
epcContractId: undefined,
buildPermit: '',
ownershipProof: '',
projectRecord: '',
powerSupplyReply: '',
investmentAgreement: '',
buildPermit: undefined,
ownershipProof: undefined,
projectRecord: undefined,
powerSupplyReply: undefined,
investmentAgreement: undefined,
supplementaryMaterials: [],
partners:[],
type: undefined,
projectStatus: undefined
projectStatus: undefined,
powerSupplyType: undefined
})
const formRules = reactive({
const formRules = computed(() => ({
deptId: [{ required: true, message: '部门ID不能为空', trigger: 'blur' }],
siteId: [{ required: true, message: '场地ID不能为空', trigger: 'blur' }],
totalInvestment: [{ required: true, message: '项目总投资额不能为空', trigger: 'blur' }],
type: [{ required: true, message: '类型不能为空', trigger: 'change' }],
projectStatus: [{ required: true, message: '状态不能为空', trigger: 'blur' }],
})
powerSupplyType: [{ required: true, message: '供电类型不能为空', trigger: 'blur' }],
powerSupplyReply : formData.value.powerSupplyType === 2 ? [{ required: true, message: '供电答复单不能为空', trigger: 'blur' }] : [],
investmentAgreement: formData.value.type === 2 ?[{ required: true, message: '合作投资协议不能为空', trigger: 'blur' }] : [],
cooperationAgreement: [{ required: true, message: '场地合同不能为空', trigger: 'blur' }],
epcContractId: [{ required: true, message: 'EPC合同不能为空', trigger: 'blur' }],
purchaseContractId: [{ required: true, message: '设备合同不能为空', trigger: 'blur' }],
}))
const formRef = ref() // Ref
const deptList = ref<DeptApi.DeptVO[]>([])
const contractOptions = ref<ContractApi.ContractVO[]>([]) //
const siteOptions = ref<StationSiteApi.StationSiteVO[]>([]) //
const partnerFormRef = ref()
const estimatedPiles = ref<number | undefined>(undefined)
/** 子表的表单 */
const subTabsName = ref('partner')
const gunCost = computed(() => {
if (!estimatedPiles.value || !formData.value.totalInvestment) return ''
if (Number(estimatedPiles.value) === 0) return ''
@ -363,21 +382,19 @@ const resetForm = () => {
deptId: undefined,
siteId: undefined,
totalInvestment: 0,
partner: undefined,
ratio: undefined,
investment: 0,
cooperationAgreement: undefined,
purchaseContractId: undefined,
cooperationAgreement:undefined,
epcContractId: undefined,
buildPermit: '',
ownershipProof: '',
projectRecord: '',
powerSupplyReply: '',
investmentAgreement: '',
buildPermit: undefined,
ownershipProof: undefined,
projectRecord: undefined,
powerSupplyReply: undefined,
investmentAgreement: undefined,
supplementaryMaterials: [],
partners:[],
type: undefined,
projectStatus: undefined
projectStatus: undefined,
powerSupplyType: undefined
}
formRef.value?.resetFields()
}

View File

@ -13,9 +13,9 @@
<el-table-column label="序号" type="index" align="center" width="60" />
<el-table-column label="项目合伙人" min-width="180">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.partner`" :rules="formRules.partner" class="mb-0px!">
<el-form-item :prop="`${$index}.customerId`" :rules="formRules.customerId" class="mb-0px!">
<el-select
v-model="row.partner"
v-model="row.customerId"
filterable
clearable
placeholder="请选择"
@ -39,13 +39,14 @@
:min="0"
:step="1"
:max="getMaxRatio($index)"
:precision="4"
placeholder="请输入比例"
class="w-1/1"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="投资额(元)" min-width="150">
<el-table-column label="投资额(元)" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.investment`" class="mb-0px!">
<el-input v-model="row.investment" placeholder="自动计算" :value="calcInvestment(row)" readonly />
@ -79,12 +80,12 @@ const userOptions = ref<any[]>([])
const formData = ref([])
const formRules = reactive({
partner: [
customerId: [
{ required: true, message: '项目合伙人不能为空', trigger: 'blur' },
{
validator: (_rule: any, value: string, callback: any) => {
//
const count = formData.value.filter(item => item.partner === value).length
const count = formData.value.filter(item => item.customerId === value).length
if (value && count > 1) {
callback(new Error('项目合伙人不能重复'))
} else {
@ -107,9 +108,9 @@ onMounted(async () => {
const handleAdd = () => {
formData.value.push()
const row = {
partner: '',
ratio: '',
investment: ''
customerId: undefined,
ratio: undefined,
investment: undefined
}
formData.value.push(row)
}
@ -132,7 +133,9 @@ const validate = async () => {
const calcInvestment = (row) => {
const ratio = Number(row.ratio) || 0
const price = Number(props.price) || 0
return ratio && price ? ((ratio * price) / 100).toFixed(2) : ''
const investment = Number( ((ratio * price) * 100).toFixed(2) ) || 0
row.investment = investment
return investment
}
const getMaxRatio = (index: number) => {
//
@ -140,11 +143,11 @@ const getMaxRatio = (index: number) => {
return Math.max(0, 100 - used)
}
watch(
() => formData.value,
() => props.partners,
(val) => {
emit('update:partners', val)
formData.value = val || []
},
{ deep: true }
{ immediate: true }
)
defineExpose({ validate })

View File

@ -76,6 +76,7 @@
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column align="center" label="项目名称" prop="deptName" min-width="300"/>
<el-table-column label="项目总投资额(万元)" align="center" prop="totalInvestment" width="180"/>
<el-table-column label="枪数" align="center" prop="estimatedPiles" />
<el-table-column label="单枪成本(万元)" align="center" min-width="120">
@ -88,8 +89,12 @@
<dict-tag :type="DICT_TYPE.CRM_PROJECT_TYPE" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column label="项目合伙人" align="center" prop="ownerUserId" min-width="160" />
<el-table-column align="center" label="供电模式" prop="type" width="160">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_PROJECT_POWER_SUPPLY_TYPE" :value="scope.row.powerSupplyType" />
</template>
</el-table-column>
<el-table-column align="center" label="状态" prop="projectStatus" width="160">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.projectStatus" />

View File

@ -26,8 +26,6 @@
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="付款单位" prop="customerId">
<el-select
@ -89,10 +87,10 @@
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="收类型" prop="type">
<el-select v-model="formData.type" placeholder="请选择收类型" class="w-1/1">
<el-form-item label="收类型" prop="type">
<el-select v-model="formData.type" placeholder="请选择收类型" class="w-1/1">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_RECEIVABLE_TYPE)"
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_PAYMENT_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
@ -100,8 +98,6 @@
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" v-if="showProject">
<el-form-item label="项目名称" prop="projectId">
<el-select
@ -120,11 +116,6 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否押金" prop="isDeposit">
<el-switch v-model="formData.isDeposit" active-text="" inactive-text="" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
@ -162,7 +153,6 @@ const formType = ref('') // 表单的类型create - 新增update - 修改
const formData = ref<ReceivableApi.ReceivableVO & {
date?: number | string
projectId?: number
isDeposit?: boolean
}>({} as ReceivableApi.ReceivableVO)
const formRules = reactive({
customerId: [{ required: true, message: '客户不能为空', trigger: 'blur' }],
@ -172,7 +162,6 @@ const formRules = reactive({
content: [{ required: true, message: '备注不能为空', trigger: 'blur' }],
type: [{ required: true, message: '收支类型不能为空', trigger: 'change' }],
projectId: [{ required: true, message: '项目名称不能为空', trigger: 'change' }],
isDeposit: [{ required: true, message: '请选择是否押金', trigger: 'change' }],
remark: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
@ -182,7 +171,7 @@ const contractList = ref<ContractApi.ContractVO[]>([]) // 合同列表
const receivablePlanList = ref<ReceivablePlanApi.ReceivablePlanVO[]>([]) //
const projectList = ref<ProjectApi.ProjectVO[]>([]) //
const maxPayableAmount = ref(Infinity)
const showProject = computed(() => formData.value.type === 1 || formData.value.type === 2)
const showProject = computed(() => formData.value.type >= 11 && formData.value.type <= 14)
/** 打开弹窗 */
const open = async (
@ -277,7 +266,6 @@ const submitForm = async () => {
const resetForm = () => {
formData.value = {} as ReceivableApi.ReceivableVO
formRef.value?.resetFields()
formData.value.isDeposit = false //
formData.value.transactionType = 0 //
}
@ -330,7 +318,7 @@ const handleReceivablePlanChange = (planId: number) => {
watch(
() => formData.value.type,
(val) => {
if (val === 1 || val === 2) {
if (val === 11 || val === 12 || val === 13 || val === 14) {
formRules.projectId = [{ required: true, message: '项目名称不能为空', trigger: 'change' }]
} else {
formRules.projectId = []

View File

@ -119,16 +119,11 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否押金" prop="isDeposit">
<el-switch v-model="formData.isDeposit" active-text="" inactive-text="" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="支类型" prop="type">
<el-select v-model="formData.type" placeholder="请选择支类型" class="w-1/1">
<el-form-item label="支出类型" prop="type">
<el-select v-model="formData.type" placeholder="请选择支出类型" class="w-1/1">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_RECEIVABLE_TYPE)"
:key="dict.value"
@ -193,7 +188,6 @@ const formType = ref('') // 表单的类型create - 新增update - 修改
const formData = ref<ReceivableApi.ReceivableVO & {
date?: number | string
projectId?: number
isDeposit?: boolean
}>({} as ReceivableApi.ReceivableVO)
const formRules = reactive({
customerId: [{ required: true, message: '客户不能为空', trigger: 'blur' }],
@ -204,7 +198,6 @@ const formRules = reactive({
content: [{ required: true, message: '备注不能为空', trigger: 'blur' }],
type: [{ required: true, message: '收支类型不能为空', trigger: 'change' }],
projectId: [{ required: true, message: '项目名称不能为空', trigger: 'change' }],
isDeposit: [{ required: true, message: '请选择是否押金', trigger: 'change' }],
remark: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
@ -214,7 +207,7 @@ const contractList = ref<ContractApi.ContractVO[]>([]) // 合同列表
const receivablePlanList = ref<ReceivablePlanApi.ReceivablePlanVO[]>([]) //
const projectList = ref<ProjectApi.ProjectVO[]>([]) //
const maxPayableAmount = ref(Infinity)
const showProject = computed(() => formData.value.type === 1 || formData.value.type === 2)
const showProject = computed(() => formData.value.type >= 1 && formData.value.type <= 7)
/** 打开弹窗 */
const open = async (
@ -358,7 +351,7 @@ const handleReceivablePlanChange = (planId: number) => {
watch(
() => formData.value.type,
(val) => {
if (val === 1 || val === 2) {
if (val === 1 || val === 2 || val === 3 || val === 4 || val === 5 || val === 6 || val === 7) {
formRules.projectId = [{ required: true, message: '项目名称不能为空', trigger: 'change' }]
} else {
formRules.projectId = []

View File

@ -52,6 +52,36 @@
/>
</el-select>
</el-form-item>
<el-form-item v-if="queryParams.transactionType === 0" label="收入类型" prop="type">
<el-select
v-model="queryParams.type"
class="!w-150px"
clearable
placeholder="请选择收入类型"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_PAYMENT_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item v-if="queryParams.transactionType === 1" label="支出类型" prop="type">
<el-select
v-model="queryParams.type"
class="!w-150px"
clearable
placeholder="请选择支出类型"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_RECEIVABLE_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="收付主体" prop="deptId">
<el-select
v-model="queryParams.deptId"
@ -84,21 +114,7 @@
placeholder="最大金额"
/>
</el-form-item>
<el-form-item label="是否押金" prop="isDeposit">
<el-select
v-model="queryParams.isDeposit"
class="!w-240px"
clearable
placeholder="请选择是否押金"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon class="mr-5px" icon="ep:search" />
@ -306,6 +322,7 @@ import { TabsPaneContext } from 'element-plus'
import { erpPriceInputFormatter } from '@/utils'
import { is } from 'bpmn-js/lib/util/ModelUtil'
import SummaryForm from './components/SummaryForm.vue'
import PaymentForm from './PaymentForm.vue'
defineOptions({ name: 'Receivable' })
@ -443,7 +460,7 @@ onMounted(async () => {
//
customerList.value = await CustomerApi.getCustomerSimpleList()
//
deptList.value = await DeptApi.getSimpleDeptList()
deptList.value = await DeptApi.querySimpleDeptList(2)
})
watch(

View File

@ -11,11 +11,13 @@
class="-mb-15px"
label-width="68px"
>
<el-form-item label="客户名称" prop="customerId">
<el-form-item label="收款单位" prop="customerId">
<el-select
v-model="queryParams.customerId"
class="!w-240px"
placeholder="请选择客户"
clearable
filterable
placeholder="请选择收款单位"
@keyup.enter="handleQuery"
>
<el-option
@ -26,14 +28,22 @@
/>
</el-select>
</el-form-item>
<el-form-item label="合同编号" prop="contractNo">
<el-input
v-model="queryParams.contractNo"
<el-form-item label="合同名称" prop="contractId">
<el-select
v-model="queryParams.contractId"
class="!w-240px"
clearable
placeholder="请输入合同编号"
filterable
placeholder="请选择合同名称"
@keyup.enter="handleQuery"
/>
>
<el-option
v-for="item in contractList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="类型" prop="status">
<el-select
@ -95,7 +105,7 @@
prop="returnTime"
width="180px"
/>
<el-table-column align="center" label="收款单位名称" prop="customerName" min-width="300">
<el-table-column align="center" label="收款单位" prop="customerName" min-width="300">
<template #default="scope">
<el-link
:underline="false"
@ -235,10 +245,12 @@ import { DICT_TYPE,getIntDictOptions } from '@/utils/dict'
import { dateFormatter2 } from '@/utils/formatTime'
import download from '@/utils/download'
import * as ReceivablePlanApi from '@/api/crm/receivable/plan'
import ReceivablePlanForm from './ReceivablePlanForm.vue'
import * as CustomerApi from '@/api/crm/customer'
import * as ContractApi from '@/api/crm/contract'
import { erpPriceInputFormatter, erpPriceTableColumnFormatter } from '@/utils'
import ReceivableForm from '@/views/crm/receivable/ReceivableForm.vue'
import ReceivablePlanForm from './ReceivablePlanForm.vue'
import ContractList from '../../contract/components/ContractList.vue'
defineOptions({ name: 'ReceivablePlan' })
@ -253,13 +265,13 @@ const queryParams = reactive({
pageSize: 10,
sceneType: undefined, // activeName
customerId: undefined,
contractNo: undefined,
contractId: undefined,
status: undefined
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const customerList = ref<CustomerApi.CustomerVO[]>([]) //
const contractList = ref<ContractApi.ContractVO[]>([])
/** 查询列表 */
const getList = async () => {
@ -345,5 +357,7 @@ onMounted(async () => {
await getList()
//
customerList.value = await CustomerApi.getCustomerSimpleList()
//
contractList.value = await ContractApi.getContractSimpleAllList()
})
</script>