add 项目利润结算文档生成
parent
f08f0df6b6
commit
563db197b3
|
|
@ -69,3 +69,13 @@ export const exportProjectSettlement = async (params: any) => {
|
|||
export const exportProjectSettlementDetail = async (params: any) => {
|
||||
return await request.download({ url: `/crm/receivable/export-settlement-excel`, params })
|
||||
}
|
||||
|
||||
// 导出项目利润结算明细 DOCX
|
||||
export const exportProjectSettlementDetailDocx = async (params: any) => {
|
||||
return await request.download({ url: `/crm/project/settlement/export-docx`, params })
|
||||
}
|
||||
|
||||
// 项目利润结算
|
||||
export const settelmentProjectSettlementDetail = async (id: number) => {
|
||||
return await request.post({ url: `/crm/project/settlement/generate?id=` + id })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export interface ProjectTransactionDetailVO {
|
|||
userName: string // 投资人名称
|
||||
investmentAmount: number // 投资金额
|
||||
saveAmount: number // 缴存金额
|
||||
remainAmount: number // 余额
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -228,6 +228,8 @@ export enum DICT_TYPE {
|
|||
CRM_FINANCE_INVOICE_TYPE = 'crm_finance_invoice_type', // CRM 票据发票类型
|
||||
CRM_FINANCE_INVOICE_AUXILIARY_TYPE = 'crm_finance_invoice_auxiliary_type', // CRM 票据辅助类型
|
||||
CRM_FINANCE_INVOICE_WRITE_OFF_STATUS = 'crm_finance_invoice_write_off_status', // CRM 票据核销状态
|
||||
CRM_PROJECT_SETTLEMENT_STATUS = 'crm_project_settlement_status', // CRM 项目结算状态
|
||||
|
||||
|
||||
// ========== ERP - 企业资源计划模块 ==========
|
||||
ERP_AUDIT_STATUS = 'erp_audit_status', // ERP 审批状态
|
||||
|
|
|
|||
|
|
@ -153,6 +153,23 @@
|
|||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item v-if="formData.type === 2 || formData.type === 3"
|
||||
label="合作投资协议日期"
|
||||
prop="investmentAgreementDate"
|
||||
label-width="150px"
|
||||
>
|
||||
<el-date-picker
|
||||
v-model="formData.investmentAgreementDate"
|
||||
type="date"
|
||||
placeholder="选择合作投资协议日期"
|
||||
style="width: 100%"
|
||||
popper-class="full-width-datepicker"
|
||||
/>
|
||||
</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">
|
||||
|
|
@ -302,6 +319,7 @@ const formData = ref({
|
|||
projectRecord: undefined,
|
||||
powerSupplyReply: undefined,
|
||||
investmentAgreement: undefined,
|
||||
investmentAgreementDate: undefined,
|
||||
investmentShareAgreement: undefined,
|
||||
supplementaryMaterials: [],
|
||||
partners:[],
|
||||
|
|
@ -320,6 +338,7 @@ const formRules = computed(() => ({
|
|||
cooperationAgreement: [{ required: true, message: '场地合同不能为空', trigger: 'blur' }],
|
||||
epcContractId: [{ required: true, message: 'EPC合同不能为空', trigger: 'blur' }],
|
||||
purchaseContractId: [{ required: true, message: '设备合同不能为空', trigger: 'blur' }],
|
||||
investmentAgreementDate: [{ required: true, message: '合作投资协议日期不能为空', trigger: 'blur' }],
|
||||
}))
|
||||
const formRef = ref() // 表单 Ref
|
||||
const deptList = ref<DeptApi.DeptVO[]>([])
|
||||
|
|
@ -420,6 +439,7 @@ const resetForm = () => {
|
|||
projectRecord: undefined,
|
||||
powerSupplyReply: undefined,
|
||||
investmentAgreement: undefined,
|
||||
investmentAgreementDate: undefined,
|
||||
investmentShareAgreement: undefined,
|
||||
supplementaryMaterials: [],
|
||||
partners:[],
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
<el-option
|
||||
v-for="item in projectList"
|
||||
:key="item.id"
|
||||
:label="item.deptName"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<el-option
|
||||
v-for="item in projectList"
|
||||
:key="item.id"
|
||||
:label="item.deptName"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
|
|
@ -149,7 +149,7 @@ function updateChartOption() {
|
|||
onMounted(async () => {
|
||||
// 获取项目列表
|
||||
const list = await ProjectMonthlyStatApi.getProjectSimpleList()
|
||||
projectList.value = [{ id: undefined, deptName: '全部' }, ...list]
|
||||
projectList.value = [{ id: undefined, name: '全部' }, ...list]
|
||||
queryParams.projectIds = []
|
||||
await getChartData()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -126,8 +126,8 @@
|
|||
:show-overflow-tooltip="true"
|
||||
@sort-change="handleSortChange"
|
||||
>
|
||||
{{ SCOPE.row }}
|
||||
<el-table-column label="项目名称" align="center" prop="name" fixed="left" min-width="200px"/>
|
||||
|
||||
<el-table-column label="项目名称" align="center" prop="projectName" fixed="left" min-width="200px"/>
|
||||
<el-table-column label="枪数" align="center" prop="estimatedPiles" width="100px"/>
|
||||
<el-table-column label="统计月份" align="center" prop="statMonth" sortable="custom" width="160px"/>
|
||||
<el-table-column label="总充电量(度)" align="center" prop="chargingQuantity" sortable="custom" width="160px"/>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,14 @@
|
|||
>
|
||||
导出明细
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="exportLoading"
|
||||
@click="handleExportDocxDetailRow(settlement)"
|
||||
v-hasPermi="['crm:project-settlement:export']"
|
||||
>
|
||||
导出文档
|
||||
</el-button>
|
||||
</ProjectSettlementDetailsHeader>
|
||||
|
||||
<div class="settlement-detail-section">
|
||||
|
|
@ -37,12 +45,45 @@
|
|||
<el-table-column prop="remark" label="说明" />
|
||||
</el-table>
|
||||
<div>备注:当期利润如有亏损则自动结转至下一季度支出项</div>
|
||||
|
||||
<h4 style="margin-top: 32px;">四、利润分配</h4>
|
||||
<el-table :data="profitDistributionTable" border style="width: 100%; margin-bottom: 16px;">
|
||||
<el-table-column prop="name" label="投资人" />
|
||||
<el-table-column prop="ratio" label="出资比例" />
|
||||
<el-table-column prop="shareAmount" label="可分配利润/元" />
|
||||
<el-table-column prop="payableAmount" label="应付金额/元" />
|
||||
<el-table-column prop="method" label="分配方式" />
|
||||
</el-table>
|
||||
<div style="margin-bottom: 12px;">合计:100%</div>
|
||||
|
||||
<h4 style="margin-top: 32px;">五、往来款平账利润分配</h4>
|
||||
<el-table :data="clearingDistributionTable" border style="width: 100%; margin-bottom: 16px;">
|
||||
<el-table-column prop="name" label="投资人" />
|
||||
<el-table-column prop="lastUnbalancedAmount" label="上期往来款未平账金额/元" />
|
||||
<el-table-column prop="afterSettlementAmount" label="本期结算平账后金额/元" />
|
||||
</el-table>
|
||||
<div style="margin-bottom: 12px;">备注:未平账期间,利润分配通过甲方法定代表人个人向乙方支付,平账后按发票结算方式执行。</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import ProjectSettlementDetailsHeader from './ProjectSettlementDetailsHeader.vue'
|
||||
import { useTagsViewStore } from '@/store/modules/tagsView'
|
||||
import * as ProjectSettlementApi from '@/api/crm/project/settlement'
|
||||
|
||||
// 扩展类型,兼容 partners 字段
|
||||
interface Partner {
|
||||
userId: number;
|
||||
userName?: string;
|
||||
ratio: number;
|
||||
shareAmount: number;
|
||||
payableAmount: number;
|
||||
lastUnbalancedAmount: number;
|
||||
afterSettlementAmount: number;
|
||||
}
|
||||
interface ProjectSettlementWithPartners extends ProjectSettlementApi.ProjectSettlementVO {
|
||||
partners?: Partner[];
|
||||
}
|
||||
import download from '@/utils/download'
|
||||
defineOptions({ name: 'CrmProjectSettlementDetail' })
|
||||
|
||||
|
|
@ -52,7 +93,7 @@ const message = useMessage() // 消息弹窗
|
|||
const exportLoading = ref(false) // 导出的加载中
|
||||
const { delView } = useTagsViewStore() // 视图操作
|
||||
const { push, currentRoute } = useRouter() // 路由
|
||||
const settlement = ref<ProjectSettlementApi.ProjectSettlementVO>({} as ProjectSettlementApi.ProjectSettlementVO) // 结算详情
|
||||
const settlement = ref<ProjectSettlementWithPartners>({} as ProjectSettlementWithPartners) // 结算详情
|
||||
|
||||
const close = () => {
|
||||
delView(unref(currentRoute))
|
||||
|
|
@ -96,11 +137,25 @@ const handleExportDetailRow = async (row: ProjectSettlementApi.ProjectSettlement
|
|||
return ''
|
||||
}
|
||||
const params = {
|
||||
|
||||
projectId: row.projectId,
|
||||
returnTime: [formatDateTime(row.startDate), formatDateTime(row.endDate)]
|
||||
}
|
||||
const data = await ProjectSettlementApi.exportProjectSettlementDetail(params)
|
||||
download.excel(data, `${row.projectName || '项目'}结算明细.xls`)
|
||||
download.excel(data, `${row.name || '项目'}结算明细.xls`)
|
||||
} catch {
|
||||
} finally {
|
||||
exportLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 导出明细按钮操作 */
|
||||
const handleExportDocxDetailRow = async (row: ProjectSettlementApi.ProjectSettlementVO) => {
|
||||
try {
|
||||
await message.exportConfirm()
|
||||
exportLoading.value = true
|
||||
const data = await ProjectSettlementApi.exportProjectSettlementDetailDocx(params)
|
||||
download.word(data, `${row.name || '项目'}第${row.period}期利润结算分配表.docx`)
|
||||
} catch {
|
||||
} finally {
|
||||
exportLoading.value = false
|
||||
|
|
@ -113,10 +168,7 @@ const incomeTable = computed(() => [
|
|||
{ name: '政府补贴收入', amount: settlement.value.governmentSubsidy, remark: '扣除应纳税额后的净补贴额' },
|
||||
{ name: '其他收入', amount: settlement.value.otherIncome, remark: '如项目或设备转让、征用赔偿款等' },
|
||||
])
|
||||
// 收入备注表格数据
|
||||
const incomeRemarkTable = computed(() => [
|
||||
{ name: settlement.value.incomeRemark ? settlement.value.incomeRemark : '无', remark: '其他需注明的内容' },
|
||||
])
|
||||
// ...existing code...
|
||||
// 支出项表格数据
|
||||
const expenseTable = computed(() => [
|
||||
{ name: '电费成本', amount: settlement.value.electricityCost, remark: '以电力公司账单为准' },
|
||||
|
|
@ -134,8 +186,37 @@ const expenseTable = computed(() => [
|
|||
// 利润表格数据
|
||||
const profitTable = computed(() => [
|
||||
{ name: '当期利润/亏损', amount: settlement.value.grossProfit, remark: '收入合计-支出合计' },
|
||||
{ name: '当期可分配利润', amount: settlement.value.shareAmount < 0 ? 0 : settlement.value.shareAmount, remark: '当期利润亏损时填0' },
|
||||
{ name: '当期可分配利润', amount: settlement.value.shareAmount && settlement.value.shareAmount < 0 ? 0 : (settlement.value.shareAmount ?? 0), remark: '当期利润亏损时填0' },
|
||||
])
|
||||
const profitDistributionTable = computed(() => {
|
||||
const partners = settlement.value.partners || [];
|
||||
// 乙方比例合计
|
||||
const totalPartnerRatio = partners.reduce((sum, p) => sum + (typeof p.ratio === 'number' ? p.ratio : Number(p.ratio) || 0), 0);
|
||||
// 甲方比例 = 100 - 乙方比例合计
|
||||
const mainRatio = (100 - totalPartnerRatio).toFixed(2).replace(/\.00$/, '');
|
||||
const table = [
|
||||
{ name: '甲方', ratio: `${mainRatio}%`, shareAmount: '不参与分配', payableAmount: '——', method: '——' }
|
||||
];
|
||||
partners.forEach((p) => {
|
||||
table.push({
|
||||
name: p.userName ? `${p.userName}` : '',
|
||||
ratio: p.ratio ? `${p.ratio}%` : '',
|
||||
shareAmount: p.shareAmount?.toFixed(2) ?? '',
|
||||
payableAmount: p.payableAmount?.toFixed(2) ?? '',
|
||||
method: '往来款平账/发票结算'
|
||||
});
|
||||
});
|
||||
return table;
|
||||
});
|
||||
|
||||
const clearingDistributionTable = computed(() => {
|
||||
const partners = settlement.value.partners || [];
|
||||
return partners.map((p) => ({
|
||||
name: p.userName ? `${p.userName}` : '',
|
||||
lastUnbalancedAmount: p.lastUnbalancedAmount?.toFixed(2) ?? '',
|
||||
afterSettlementAmount: p.afterSettlementAmount?.toFixed(2) ?? ''
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
|||
|
|
@ -112,8 +112,22 @@
|
|||
{{ scope.row.settlementDate ? formatDate(scope.row.settlementDate, 'YYYY-MM-DD') : '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="结算状态" prop="settlementStatus" width="160">
|
||||
<template #default="scope">
|
||||
<dict-tag :type="DICT_TYPE.CRM_PROJECT_SETTLEMENT_STATUS" :value="scope.row.settlementStatus" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="180px" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
v-if="scope.row.settlementStatus === 0"
|
||||
link
|
||||
type="success"
|
||||
@click="settelment(scope.row.id)"
|
||||
v-hasPermi="['crm:project-settlement:update']"
|
||||
>
|
||||
结算
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
|
|
@ -153,6 +167,7 @@ import * as ProjectSettlementApi from '@/api/crm/project/settlement'
|
|||
import * as ProjectApi from '@/api/crm/project'
|
||||
import ProjectSettlementForm from './ProjectSettlementForm.vue'
|
||||
import ElQuarterPicker from '@/components/ElQuarterPicker/index.vue'
|
||||
import { DICT_TYPE,getIntDictOptions } from '@/utils/dict'
|
||||
|
||||
// 结算周期格式化:'2024-1' => '2024年第一季度'
|
||||
function formatQuarterPeriod(val?: string) {
|
||||
|
|
@ -245,6 +260,18 @@ const handleExport = async () => {
|
|||
}
|
||||
}
|
||||
|
||||
// 结算按钮方法
|
||||
const settelment = async (id: number) => {
|
||||
try {
|
||||
// 结算的二次确认
|
||||
await message.confirm("是否发起结算?")
|
||||
// 发起结算
|
||||
await ProjectSettlementApi.settelmentProjectSettlementDetail(id)
|
||||
message.success(t('结算成功'))
|
||||
// 刷新列表
|
||||
await getList()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
|
||||
/** 跳转到项目结算明细页面 */
|
||||
|
|
@ -262,4 +289,5 @@ onMounted(async () => {
|
|||
// 获取项目列表
|
||||
projectOptions.value = await ProjectApi.getProjectSimpleList();
|
||||
})
|
||||
|
||||
</script>
|
||||
|
|
@ -62,13 +62,6 @@
|
|||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="缴存金额" prop="saveAmount">
|
||||
<el-input v-model="formData.saveAmount" placeholder="请输入缴存金额" type="number" @input="onAmountInput('saveAmount')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||
|
|
@ -77,17 +70,7 @@
|
|||
</Dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
const validateProjectRequired = (_: any, __: any, callback: any) => {
|
||||
const userId = formData.value.userId;
|
||||
const projectId = formData.value.projectId;
|
||||
if (userId !== 1 && userId !== '1') {
|
||||
if (projectId === undefined || projectId === '' || projectId === null) {
|
||||
callback(new Error('请选择项目'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback();
|
||||
};
|
||||
|
||||
import * as ProjectTransactionDetailApi from '@/api/crm/project/transaction'
|
||||
import * as ProjectApi from '@/api/crm/project'
|
||||
import * as UserApi from '@/api/system/user'
|
||||
|
|
@ -110,24 +93,12 @@ const formData = ref({
|
|||
investmentAmount: undefined,
|
||||
saveAmount: undefined,
|
||||
})
|
||||
const validateAmountExclusive = (_: any, __: any, callback: any) => {
|
||||
const investment = formData.value.investmentAmount;
|
||||
const save = formData.value.saveAmount;
|
||||
if ((investment === undefined || investment === '' || investment === null) && (save === undefined || save === '' || save === null)) {
|
||||
callback(new Error('投资金额和缴存金额必须填写一个'));
|
||||
} else if ((investment !== undefined && investment !== '' && investment !== null) && (save !== undefined && save !== '' && save !== null)) {
|
||||
callback(new Error('投资金额和缴存金额只能填写一个'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
const formRules = reactive({
|
||||
date: [{ required: true, message: '缴存日期不能为空', trigger: 'blur' }],
|
||||
userId: [{ required: true, message: '投资人不能为空', trigger: 'blur' }],
|
||||
projectId: [{ validator: validateProjectRequired, trigger: 'blur' }],
|
||||
investmentAmount: [{ validator: validateAmountExclusive, trigger: 'blur' }],
|
||||
saveAmount: [{ validator: validateAmountExclusive, trigger: 'blur' }],
|
||||
projectId: [{ required: true, message: '项目不能为空', trigger: 'blur' }],
|
||||
investmentAmount: [{ required: true, message: '投资金额不能为空', trigger: 'blur' }],
|
||||
})
|
||||
const formRef = ref() // 表单 Ref
|
||||
const projectOptions = ref<ProjectApi.ProjectVO[]>([])
|
||||
|
|
|
|||
|
|
@ -102,11 +102,12 @@
|
|||
{{ scope.row.date ? formatDate(scope.row.date, 'YYYY-MM-DD') : '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="投资人/代管人" align="center" prop="userName" width="300px"/>
|
||||
<el-table-column label="投资人/代管人" align="center" prop="userName" />
|
||||
<el-table-column label="项目名称" align="center" prop="projectName" min-width="260px"/>
|
||||
<el-table-column label="投资款/分红" align="center" prop="investmentAmount" width="300px"/>
|
||||
<el-table-column label="缴存/支取" align="center" prop="saveAmount" width="300px"/>
|
||||
<el-table-column label="相差数" align="center" prop="diff" width="300px"/>
|
||||
<el-table-column label="投资款/分红" align="center" prop="investmentAmount" />
|
||||
<el-table-column label="缴存/支取" align="center" prop="saveAmount" />
|
||||
<el-table-column label="相差数" align="center" prop="diff" />
|
||||
<el-table-column label="待还投资额" align="center" prop="remainAmount" />
|
||||
<el-table-column label="操作" align="center" fixed="right" min-width="120px">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
|
|
|
|||
Loading…
Reference in New Issue