收付记录

pull/853/head
wersd 2025-07-07 23:39:32 +08:00
parent 551ff57329
commit 94530a85ed
8 changed files with 195 additions and 156 deletions

View File

@ -21,6 +21,7 @@ export interface ProjectVO {
supplementaryMaterials: string // 其他补充材料文件路径
type: number // 类型
projectStatus: number // 状态
estimatedPiles: number //枪数
}
// 查询CRM 项目信息分页

View File

@ -11,15 +11,6 @@
class="-mb-15px"
label-width="68px"
>
<el-form-item label="合同编号" prop="no">
<el-input
v-model="queryParams.no"
class="!w-240px"
clearable
placeholder="请输入合同编号"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="合同名称" prop="name">
<el-input
v-model="queryParams.name"
@ -28,25 +19,57 @@
placeholder="请输入合同名称"
@keyup.enter="handleQuery"
/>
<el-form-item label="客户签约方" prop="customerId">
<el-select
v-model="queryParams.customerId"
class="!w-240px"
clearable
lable-key="name"
placeholder="请选择客户签约方"
value-key="id"
@keyup.enter="handleQuery"
>
<el-option
v-for="item in customerList"
:key="item.id"
:label="item.name"
:value="item.id!"
/>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item label="客户签约方" prop="customerId" label-width="100px">
<el-select
v-model="queryParams.customerId"
class="!w-240px"
clearable
filterable
lable-key="name"
placeholder="请选择客户签约方"
value-key="id"
@keyup.enter="handleQuery"
>
<el-option
v-for="item in customerList"
:key="item.id"
:label="item.name"
:value="item.id!"
/>
</el-select>
</el-form-item>
<el-form-item label="合同状态" prop="contractStatus">
<el-select
v-model="queryParams.contractStatus"
class="!w-150px"
clearable
placeholder="请选择合同状态"
>
<el-option
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-form-item label="合同类型" prop="contractType">
<el-select
v-model="queryParams.contractType"
class="!w-150px"
clearable
placeholder="请选择合同类型"
>
<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-form-item>
<el-button @click="handleQuery">
<Icon class="mr-5px" icon="ep:search" />
@ -205,7 +228,7 @@ import { dateFormatter, dateFormatter2 } from '@/utils/formatTime'
import download from '@/utils/download'
import * as ContractApi from '@/api/crm/contract'
import ContractForm from './ContractForm.vue'
import { DICT_TYPE } from '@/utils/dict'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { erpPriceInputFormatter, erpPriceTableColumnFormatter } from '@/utils'
import * as CustomerApi from '@/api/crm/customer'
import { TabsPaneContext } from 'element-plus'
@ -224,7 +247,9 @@ const queryParams = reactive({
name: null,
customerId: null,
orderDate: [],
no: null
no: null,
contractType: null,
contractStatus: null,
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
@ -342,12 +367,12 @@ const tableRowClassName = ({ row }: { row: any }) => {
return '';
}
//
const diffTime = today.getTime() - endTime.getTime();
const diffTime = endTime.getTime() - today.getTime();
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
console.log('diffDays', diffDays, endTime);
if (diffDays <= 90) { // 3
console.log('diffDays', diffDays, today, endTime);
if (diffDays <= 90 && (row.contractStatus === 1 || row.contractStatus === 2)) { // 3
return 'expiring-soon-row';
} else if (diffDays <= 180) { // 6
} else if (diffDays <= 180 && (row.contractStatus === 1 || row.contractStatus === 2)) { // 6
return 'expiring-row';
}
return '';

View File

@ -58,7 +58,9 @@
</el-col>
<el-col :span="12">
<el-form-item label="状态" prop="projectStatus">
<el-radio-group v-model="formData.projectStatus">
<el-radio-group
v-model="formData.projectStatus"
>
<el-radio value="0">关闭</el-radio>
<el-radio value="1">开启</el-radio>
</el-radio-group>
@ -145,10 +147,10 @@
<el-col>
<el-form-item v-if="formData.type === 2" label="合伙人明细">
<ProjectPartnetForm
v-model:partners="partners"
ref="partnerFormRef"
v-model:partners="formData.partners"
:disabled="formLoading"
:price="formData.totalInvestment"
ref="partnerFormRef"
/>
</el-form-item>
</el-col>
@ -157,36 +159,66 @@
<el-row>
<el-col :span="12">
<el-form-item label="同意建桩证明" prop="buildPermit">
<UploadFile v-model="formData.buildPermit" :isShowTip="false" :limit="1" :file-type="['pdf']" />
<UploadFile
v-model="formData.buildPermit"
:isShowTip="false"
:limit="1"
:file-type="['pdf']"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="场地权属证明" prop="ownershipProof">
<UploadFile v-model="formData.ownershipProof" :isShowTip="false" :limit="1" :file-type="['pdf']" />
<UploadFile
v-model="formData.ownershipProof"
:isShowTip="false"
:limit="1"
:file-type="['pdf']"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="项目备案" prop="projectRecord">
<UploadFile v-model="formData.projectRecord" :isShowTip="false" :limit="1" :file-type="['pdf']" />
<UploadFile
v-model="formData.projectRecord"
:isShowTip="false"
:limit="1"
:file-type="['pdf']"
/>
</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']" />
<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']" />
<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">
<UploadFile v-model="formData.supplementaryMaterials" :isShowTip="false" :limit="5" :file-type="['pdf']" />
<UploadFile
v-model="formData.supplementaryMaterials"
:isShowTip="false"
:limit="5"
:file-type="['pdf']"
/>
</el-form-item>
</el-col>
</el-row>
@ -218,7 +250,6 @@ const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const partners = ref([]) //
const formData = ref({
id: undefined,
@ -237,6 +268,7 @@ const formData = ref({
powerSupplyReply: '',
investmentAgreement: '',
supplementaryMaterials: [],
partners:[],
type: undefined,
projectStatus: undefined
})
@ -287,7 +319,7 @@ const open = async (type: string, id?: number) => {
}
}
//
deptList.value = await DeptApi.getSimpleDeptList()
deptList.value = await DeptApi.querySimpleDeptList(3)
//
contractOptions.value = await ContractApi.getContractSimpleAllList()
//
@ -343,6 +375,7 @@ const resetForm = () => {
powerSupplyReply: '',
investmentAgreement: '',
supplementaryMaterials: [],
partners:[],
type: undefined,
projectStatus: undefined
}

View File

@ -76,13 +76,7 @@ const emit = defineEmits(['update:partners'])
const formLoading = ref(false)
const userOptions = ref<any[]>([])
interface PartnerRow {
partner?: string
ratio?: string | number
investment?: string | number
}
const formData = ref<PartnerRow[]>([])
const formData = ref([])
const formRules = reactive({
partner: [
@ -109,19 +103,15 @@ onMounted(async () => {
userOptions.value = await UserApi.getSimpleUserList()
})
watch(
() => props.partners,
(val) => {
formData.value = (val || []).map(item => ({
...item,
partner: item.partner ? String(item.partner) : ''
}))
},
{ immediate: true }
)
const handleAdd = () => {
formData.value.push({ partner: '', ratio: '', investment: '' })
formData.value.push()
const row = {
partner: '',
ratio: '',
investment: ''
}
formData.value.push(row)
}
const handleDelete = (index: number) => {
@ -139,7 +129,7 @@ const validate = async () => {
}
return true
}
const calcInvestment = (row: PartnerRow) => {
const calcInvestment = (row) => {
const ratio = Number(row.ratio) || 0
const price = Number(props.price) || 0
return ratio && price ? ((ratio * price) / 100).toFixed(2) : ''
@ -149,16 +139,6 @@ const getMaxRatio = (index: number) => {
const used = formData.value.reduce((sum, item, idx) => idx !== index ? sum + (Number(item.ratio) || 0) : sum, 0)
return Math.max(0, 100 - used)
}
watch(
() => formData.value.map(item => item.ratio),
() => {
formData.value.forEach(row => {
row.investment = calcInvestment(row)
})
},
{ deep: true }
)
watch(
() => formData.value,
(val) => {

View File

@ -8,25 +8,22 @@
:inline="true"
label-width="68px"
>
<el-form-item label="部门ID" prop="deptId">
<el-input
<el-form-item label="项目名称" prop="deptId">
<el-select
v-model="queryParams.deptId"
placeholder="请输入部门ID"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="场地ID" prop="siteId">
<el-input
v-model="queryParams.siteId"
placeholder="请输入场地ID"
clearable
placeholder="请选择项目名称"
@keyup.enter="handleQuery"
class="!w-240px"
/>
>
<el-option
v-for="item in deptList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="项目合伙人" prop="ownerUserId">
<!-- <el-form-item label="项目合伙人" prop="ownerUserId">
<el-input
v-model="queryParams.ownerUserId"
placeholder="请输入项目合伙人"
@ -34,7 +31,7 @@
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
</el-form-item> -->
<el-form-item label="类型" prop="type">
<el-select
v-model="queryParams.type"
@ -42,30 +39,15 @@
clearable
class="!w-240px"
>
<el-option label="请选择字典生成" value="" />
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CRM_PROJECT_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="projectStatus">
<el-select
v-model="queryParams.projectStatus"
placeholder="请选择状态"
clearable
class="!w-240px"
>
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-220px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
@ -93,21 +75,27 @@
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="主键ID" align="center" prop="id" />
<el-table-column label="部门ID" align="center" prop="deptId" />
<el-table-column label="场地ID" align="center" prop="siteId" />
<el-table-column label="项目总投资额" align="center" prop="totalInvestment" />
<el-table-column label="项目合伙人" align="center" prop="ownerUserId" />
<el-table-column label="类型" align="center" prop="type" />
<el-table-column label="状态" align="center" prop="projectStatus" />
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center" min-width="120px">
<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">
<template #default="{ row }">
<span>{{ calculateCostPerPile(row) }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="类型" prop="type" width="160">
<template #default="scope">
<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="projectStatus" width="160">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.projectStatus" />
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" align="center" min-width="120px">
<template #default="scope">
<el-button
link
@ -145,7 +133,9 @@
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import * as ProjectApi from '@/api/crm/project'
import * as DeptApi from '@/api/system/dept'
import ProjectForm from './ProjectForm.vue'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
/** CRM 项目信息 列表 */
defineOptions({ name: 'CrmProject' })
@ -164,10 +154,12 @@ const queryParams = reactive({
ownerUserId: undefined,
type: undefined,
projectStatus: undefined,
estimatedPiles: undefined,
createTime: [],
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const deptList = ref<DeptApi.DeptVO[]>([])
/** 查询列表 */
const getList = async () => {
@ -181,6 +173,11 @@ const getList = async () => {
}
}
/** 打开场地详情 */
const { push } = useRouter()
const openSiteDetail = (id: number) => {
push({ name: 'CrmStationSiteDetail', params: { id } })
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
@ -227,8 +224,26 @@ const handleExport = async () => {
}
}
const calculateCostPerPile = (row) => {
//
if (!row.estimatedPiles || isNaN(row.estimatedPiles) || row.estimatedPiles <= 0) {
return ''; //
}
//
if (!row.totalInvestment || isNaN(row.totalInvestment)) {
return ''; //
}
//
const cost = (row.totalInvestment / row.estimatedPiles).toFixed(2);
return parseFloat(cost); // 0
};
/** 初始化 **/
onMounted(() => {
getList()
onMounted(async () => {
await getList()
//
deptList.value = await DeptApi.querySimpleDeptList(3)
})
</script>

View File

@ -44,7 +44,7 @@
<el-form-item label="收款单位" prop="customerId">
<el-select
v-model="formData.customerId"
:disabled="formType !== 'create'"
disabled
class="w-1/1"
filterable
placeholder="请选择收款单位"
@ -63,7 +63,7 @@
<el-form-item label="合同名称" prop="contractId">
<el-select
v-model="formData.contractId"
:disabled="formType !== 'create' || !formData.customerId"
disabled
class="w-1/1"
filterable
placeholder="请选择合同"
@ -80,12 +80,13 @@
</el-form-item>
</el-col>
</el-row>
<!-- :max="maxPayableAmount" -->
<el-row>
<el-col :span="12">
<el-form-item label="付款金额" prop="price">
<el-input-number
v-model="formData.price"
:max="maxPayableAmount"
:precision="2"
class="!w-100%"
controls-position="right"
@ -118,6 +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">
@ -132,8 +138,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
@ -152,11 +156,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">

View File

@ -157,16 +157,17 @@
</el-text>
</template>
</el-table-column>
<el-table-column label="审核状态" align="center" width="90" prop="auditStatus">
<!-- <el-table-column label="审核状态" align="center" width="90" prop="auditStatus">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CRM_AUDIT_STATUS" :value="scope.row.auditStatus" />
</template>
</el-table-column>
</el-table-column> -->
<!-- v-if ="(scope.row.type === 1 && scope.row.auditStatus === 20) || (scope.row.type === 0)" -->
<!-- v-if="(scope.row.price - ((scope.row.receivable && Array.isArray(scope.row.receivable) && scope.row.receivable.length > 0) ? scope.row.receivable.reduce((sum, r) => sum + (r.price || 0), 0) : 0) > 0)" -->
<el-table-column align="center" fixed="right" label="操作" min-width="180px">
<template #default="scope">
<el-button
v-if="(scope.row.price - ((scope.row.receivable && Array.isArray(scope.row.receivable) && scope.row.receivable.length > 0) ? scope.row.receivable.reduce((sum, r) => sum + (r.price || 0), 0) : 0) > 0)"
v-hasPermi="['crm:receivable:create']"
link
type="success"

View File

@ -191,8 +191,6 @@ const exportLoading = ref(false) // 导出的加载中
const areaList = ref([])
const mapDialogVisible = ref(false)
const tencentLbsUrl = ref('')
const currentRow = ref<any>(null)
const TENCENT_MAP_KEY = import.meta.env.VITE_APP_TENCENT_MAP_KEY // key
/** 打开场地信息详情 */
const { currentRoute, push } = useRouter()
@ -259,19 +257,6 @@ const handleExport = async () => {
}
}
/** 地图弹窗相关操作 */
const openMapDialog = (row: any) => {
currentRow.value = row
// url
let url = `https://apis.map.qq.com/tools/locpicker?type=1&key=${TENCENT_MAP_KEY}&referer=myapp`
if (row.locationLat && row.locationLng) {
url += `&coord=${row.locationLat},${row.locationLng}`
}
tencentLbsUrl.value = url
mapDialogVisible.value = true
}
watch(mapDialogVisible, (val) => {
if (!val) {
tencentLbsUrl.value = '' //