1.1.33 销售合同订单台账:合同总价放到回款信息中,回款信息只允许创建人、合同负责人、刘家欢、业务方向负责人有权限查看。

dev
yinq 1 month ago
parent abe0c8c2e5
commit cdb54f1baa

@ -45,7 +45,7 @@ export interface ContractInfoVO {
contractDeptId: string | number;
/**
*
*
*/
contractDate: string;
@ -124,6 +124,31 @@ export interface ContractInfoVO {
*/
twoDate: string;
/**
*
*/
twoCustomerName?: string;
/**
*
*/
paymentMethodDetails?: string;
/**
*
*/
paymentAccountInfo?: string;
/**
*
*/
detailedAddress?: string;
/**
*
*/
deptName?: string;
/**
* (1 2 3)
*/
@ -160,22 +185,22 @@ export interface ContractInfoVO {
signatureAppendix: number;
/**
*
* SAP erp_contract_info.internal_contract_code
*/
internalContractCode: string;
/**
*
* external_contract_code
*/
externalContractCode: string;
/**
*
* SAP order_contract_code
*/
orderContractCode: string;
/**
*
* SAP project_contract_code
*/
projectContractCode: string;

@ -104,8 +104,8 @@
</el-link>
</template>
</el-table-column>
<el-table-column label="合同编号" align="center" prop="contractCode" width="140" v-if="columns[28].visible" />
<el-table-column label="合同名称" align="center" prop="contractName" width="200" v-if="columns[29].visible" />
<el-table-column label="合同编号" align="center" prop="contractCode" width="140" v-if="columns[27].visible" />
<el-table-column label="合同名称" align="center" prop="contractName" width="200" v-if="columns[28].visible" />
<el-table-column label="业务方向" align="center" prop="businessDirection" width="100" v-if="columns[5].visible">
<template #default="scope">
<dict-tag :options="business_direction" :value="scope.row.businessDirection" />
@ -132,41 +132,40 @@
<el-table-column label="部门负责人" align="center" prop="chargeName" width="120" v-if="columns[12].visible" />
<el-table-column label="分管副总" align="center" prop="deputyName" width="100" v-if="columns[13].visible" />
<el-table-column label="抄送人员" align="center" prop="peopleId" v-if="columns[14].visible" />
<el-table-column label="金额" align="center" prop="amount" width="110" v-if="columns[15].visible" />
<el-table-column label="订单状态" align="center" prop="projectStatus" v-if="columns[16].visible">
<el-table-column label="订单状态" align="center" prop="projectStatus" v-if="columns[15].visible">
<template #default="scope">
<dict-tag :options="project_status" :value="scope.row.projectStatus" />
</template>
</el-table-column>
<el-table-column label="流程状态" align="center" prop="flowStatus" v-if="columns[17].visible">
<el-table-column label="流程状态" align="center" prop="flowStatus" v-if="columns[16].visible">
<template #default="scope">
<dict-tag :options="wf_business_status" :value="scope.row.flowStatus" />
</template>
</el-table-column>
<el-table-column label="采购状态" align="center" prop="orderPurchaseStatus" width="110" v-if="columns[30].visible">
<el-table-column label="采购状态" align="center" prop="orderPurchaseStatus" width="110" v-if="columns[29].visible">
<template #default="scope">
<dict-tag :options="order_purchase_status" :value="scope.row.orderPurchaseStatus" />
</template>
</el-table-column>
<el-table-column label="发货状态" align="center" prop="orderDeliveryStatus" width="110" v-if="columns[31].visible">
<el-table-column label="发货状态" align="center" prop="orderDeliveryStatus" width="110" v-if="columns[30].visible">
<template #default="scope">
<dict-tag :options="order_delivery_status" :value="scope.row.orderDeliveryStatus" />
</template>
</el-table-column>
<el-table-column label="开票状态" align="center" prop="orderInvoiceStatus" width="110" v-if="columns[32].visible">
<el-table-column label="开票状态" align="center" prop="orderInvoiceStatus" width="110" v-if="columns[31].visible">
<template #default="scope">
<dict-tag :options="order_invoice_status" :value="scope.row.orderInvoiceStatus" />
</template>
</el-table-column>
<el-table-column label="回款百分比" align="center" prop="orderPaymentRate" width="120" v-if="columns[33].visible">
<el-table-column label="回款百分比" align="center" prop="orderPaymentRate" width="120" v-if="columns[32].visible">
<template #default="scope">
{{ scope.row.orderPaymentRate ?? 0 }}%
</template>
</el-table-column>
<el-table-column label="排序号" align="center" prop="sortOrder" v-if="columns[18].visible" />
<el-table-column label="合同ID(预留)" align="center" prop="contractId" v-if="columns[19].visible" />
<el-table-column label="备注" align="center" prop="remark" v-if="columns[20].visible" />
<el-table-column label="激活标识" align="center" prop="activeFlag" v-if="columns[21].visible">
<el-table-column label="排序号" align="center" prop="sortOrder" v-if="columns[17].visible" />
<el-table-column label="合同ID(预留)" align="center" prop="contractId" v-if="columns[18].visible" />
<el-table-column label="备注" align="center" prop="remark" v-if="columns[19].visible" />
<el-table-column label="激活标识" align="center" prop="activeFlag" v-if="columns[20].visible">
<template #default="scope">
<dict-tag :options="active_flag" :value="scope.row.activeFlag" />
</template>
@ -253,25 +252,24 @@ const columns = ref<FieldOption[]>([
{ key: 12, label: `部门负责人`, visible: false },
{ key: 13, label: `分管副总`, visible: false },
{ key: 14, label: `抄送人员`, visible: false },
{ key: 15, label: `金额`, visible: true },
{ key: 16, label: `订单状态`, visible: true },
{ key: 17, label: `流程状态`, visible: true },
{ key: 18, label: `排序号`, visible: false },
{ key: 19, label: `合同ID(预留)`, visible: false },
{ key: 20, label: `备注`, visible: true },
{ key: 21, label: `激活标识`, visible: false },
{ key: 22, label: `删除标志`, visible: false },
{ key: 23, label: `创建部门`, visible: false },
{ key: 24, label: `创建人`, visible: false },
{ key: 25, label: `创建时间`, visible: false },
{ key: 26, label: `更新人`, visible: false },
{ key: 27, label: `更新时间`, visible: false },
{ key: 28, label: `合同编号`, visible: true },
{ key: 29, label: `合同名称`, visible: true },
{ key: 30, label: `采购状态`, visible: true },
{ key: 31, label: `发货状态`, visible: true },
{ key: 32, label: `开票状态`, visible: true },
{ key: 33, label: `回款百分比`, visible: true }
{ key: 15, label: `订单状态`, visible: true },
{ key: 16, label: `流程状态`, visible: true },
{ key: 17, label: `排序号`, visible: false },
{ key: 18, label: `合同ID(预留)`, visible: false },
{ key: 19, label: `备注`, visible: true },
{ key: 20, label: `激活标识`, visible: false },
{ key: 21, label: `删除标志`, visible: false },
{ key: 22, label: `创建部门`, visible: false },
{ key: 23, label: `创建人`, visible: false },
{ key: 24, label: `创建时间`, visible: false },
{ key: 25, label: `更新人`, visible: false },
{ key: 26, label: `更新时间`, visible: false },
{ key: 27, label: `合同编号`, visible: true },
{ key: 28, label: `合同名称`, visible: true },
{ key: 29, label: `采购状态`, visible: true },
{ key: 30, label: `发货状态`, visible: true },
{ key: 31, label: `开票状态`, visible: true },
{ key: 32, label: `回款百分比`, visible: true }
]);
const data = reactive<{ queryParams: ProjectInfoQuery }>({

@ -11,30 +11,65 @@
<!-- 合同信息 Tab -->
<el-tab-pane label="合同信息" name="contract">
<div v-loading="loadingContract" class="tab-content">
<el-descriptions :column="3" border v-if="contractInfo" class="order-descriptions">
<el-descriptions-item label="合同编号" :span="1">
<span class="value-text value-highlight">{{ contractInfo?.contractCode || '-' }}</span>
<div v-if="contractInfo" class="contract-info-pane">
<div class="contract-desc-section">
<div class="contract-desc-section__title">基础信息</div>
<el-descriptions :column="3" border class="order-descriptions">
<el-descriptions-item label="合同编号">
<span class="value-text value-highlight">{{ contractInfo.contractCode || '-' }}</span>
</el-descriptions-item>
<el-descriptions-item label="合同名称" :span="2">
<span class="value-text value-highlight">{{ contractInfo?.contractName || '-' }}</span>
<span class="value-text value-highlight">{{ contractInfo.contractName || '-' }}</span>
</el-descriptions-item>
<el-descriptions-item label="客户合同编号">{{ contractInfo?.customerContractCode || '-' }}</el-descriptions-item>
<el-descriptions-item label="内部合同号">{{ contractInfo?.internalContractCode || '-' }}</el-descriptions-item>
<el-descriptions-item label="外部合同号">{{ contractInfo?.externalContractCode || '-' }}</el-descriptions-item>
<el-descriptions-item label="订单号">{{ contractInfo?.orderContractCode || '-' }}</el-descriptions-item>
<el-descriptions-item label="项目号">{{ contractInfo?.projectContractCode || '-' }}</el-descriptions-item>
<el-descriptions-item label="合同负责人">{{ contractInfo.contractManagerName || '-' }}</el-descriptions-item>
<el-descriptions-item label="合同签订日期">
{{ contractInfo.contractDate ? parseTime(contractInfo.contractDate, '{y}-{m}-{d}') : '-' }}
</el-descriptions-item>
<el-descriptions-item label="签订地点">{{ contractInfo.signingPlace || '-' }}</el-descriptions-item>
<el-descriptions-item label="甲方办公地">{{ contractInfo.detailedAddress || '-' }}</el-descriptions-item>
</el-descriptions>
</div>
<div class="contract-desc-section">
<div class="contract-desc-section__title">编号与外部系统</div>
<el-descriptions :column="3" border class="order-descriptions">
<el-descriptions-item label="海威SAP订单号">{{ contractInfo.internalContractCode || '-' }}</el-descriptions-item>
<el-descriptions-item label="海威合同归档编号">{{ contractInfo.externalContractCode || '-' }}</el-descriptions-item>
<el-descriptions-item label="软控SAP订单号">{{ contractInfo.orderContractCode || '-' }}</el-descriptions-item>
<el-descriptions-item label="软控SAP项目号">{{ contractInfo.projectContractCode || '-' }}</el-descriptions-item>
</el-descriptions>
</div>
<div class="contract-desc-section">
<div class="contract-desc-section__title">分类与合同状态</div>
<el-descriptions :column="3" border class="order-descriptions">
<el-descriptions-item label="业务方向">
<dict-tag :options="business_direction" :value="contractInfo?.businessDirection" />
<dict-tag :options="business_direction" :value="contractInfo.businessDirection" />
</el-descriptions-item>
<el-descriptions-item label="合同大类">
<dict-tag :options="contract_category" :value="contractInfo?.contractCategory" />
<dict-tag :options="contract_category" :value="contractInfo.contractCategory" />
</el-descriptions-item>
<el-descriptions-item label="合同类型">
<dict-tag :options="contract_type" :value="contractInfo?.contractType" />
<el-descriptions-item label="合同模板标识">
<dict-tag :options="contract_template_flag" :value="contractInfo.contractTemplateFlag" />
</el-descriptions-item>
<el-descriptions-item label="合同状态">
<dict-tag :options="contract_status" :value="contractInfo?.contractStatus" />
<dict-tag :options="contract_status" :value="contractInfo.contractStatus" />
</el-descriptions-item>
<el-descriptions-item label="已生效客户订单">
<span>{{
contractInfo.effectiveCustomerOrderFlag === '1'
? '是'
: contractInfo.effectiveCustomerOrderFlag === '0'
? '否'
: '-'
}}</span>
</el-descriptions-item>
</el-descriptions>
</div>
<div class="contract-desc-section">
<div class="contract-desc-section__title">本订单执行状态</div>
<el-descriptions :column="3" border class="order-descriptions">
<el-descriptions-item label="采购状态">
<dict-tag :options="order_purchase_status" :value="orderInfo?.orderPurchaseStatus" />
</el-descriptions-item>
@ -47,25 +82,73 @@
<el-descriptions-item label="回款百分比">
<span>{{ orderInfo?.orderPaymentRate ?? 0 }}%</span>
</el-descriptions-item>
<el-descriptions-item label="合同时间">{{ contractInfo?.contractDate || '-' }}</el-descriptions-item>
<el-descriptions-item label="合同总价" :span="1">
<span class="value-text value-amount">
{{ contractInfo?.totalPrice ? formatNumber(contractInfo.totalPrice) + ' 元' : '-' }}
</span>
</el-descriptions-item>
<el-descriptions-item label="付款方式">{{ contractInfo?.paymentMethod || '-' }}</el-descriptions-item>
<el-descriptions-item label="交货地点">{{ contractInfo?.deliveryLocation || '-' }}</el-descriptions-item>
<el-descriptions-item label="运输方式">{{ contractInfo?.shipMethod || '-' }}</el-descriptions-item>
<el-descriptions-item label="发货/交货期">{{
contractInfo?.deliveryStart || '-'
}}</el-descriptions-item>
<el-descriptions-item label="质保期">{{
contractInfo?.warrantyPeriod ? contractInfo.warrantyPeriod + ' 天' : '-'
}}</el-descriptions-item>
<el-descriptions-item label="质保期描述">{{ contractInfo?.warrantyPeriodDescription || '-' }}</el-descriptions-item>
<el-descriptions-item label="签订地点">{{ contractInfo?.signingPlace || '-' }}</el-descriptions-item>
<el-descriptions-item label="备注" :span="3">{{ contractInfo?.remark || '-' }}</el-descriptions-item>
</el-descriptions>
</div>
<div class="contract-desc-section">
<div class="contract-desc-section__title">属地与结算</div>
<el-descriptions :column="3" border class="order-descriptions">
<el-descriptions-item label="合同属地标识">
<dict-tag :options="contract_territorial_flag" :value="contractInfo.contractTerritorialFlag" />
</el-descriptions-item>
<el-descriptions-item label="合同属地国家/地区">
<dict-tag :options="country_region" :value="contractInfo.contractTerritorialCountry" />
</el-descriptions-item>
<el-descriptions-item label="结算币种">
<dict-tag :options="currency_type" :value="contractInfo.settlementCurrency" />
</el-descriptions-item>
<el-descriptions-item label="对人民币汇率">{{ formatExchangeRate(contractInfo.rmbExchangeRate) }}</el-descriptions-item>
</el-descriptions>
</div>
<div class="contract-desc-section">
<div class="contract-desc-section__title">签约主体</div>
<el-descriptions :column="3" border class="order-descriptions">
<el-descriptions-item label="最终客户">{{ contractInfo.finalCustomerName || '-' }}</el-descriptions-item>
<el-descriptions-item label="甲方公司">{{ contractInfo.oneCustomerName || '-' }}</el-descriptions-item>
<el-descriptions-item label="甲方授权代表">{{ contractInfo.oneRepresent || '-' }}</el-descriptions-item>
<el-descriptions-item label="甲方签字日期">
{{ contractInfo.oneDate ? parseTime(contractInfo.oneDate, '{y}-{m}-{d}') : '-' }}
</el-descriptions-item>
<el-descriptions-item label="乙方公司">{{ contractInfo.twoCustomerName || '-' }}</el-descriptions-item>
<el-descriptions-item label="乙方授权代表">{{ contractInfo.twoRepresent || '-' }}</el-descriptions-item>
<el-descriptions-item label="乙方签字日期">
{{ contractInfo.twoDate ? parseTime(contractInfo.twoDate, '{y}-{m}-{d}') : '-' }}
</el-descriptions-item>
</el-descriptions>
</div>
<div class="contract-desc-section">
<div class="contract-desc-section__title">商务与交付</div>
<el-descriptions :column="3" border class="order-descriptions">
<el-descriptions-item label="付款方式" :span="3">{{ contractInfo.paymentMethod || '-' }}</el-descriptions-item>
<el-descriptions-item label="付款账户信息" :span="3">{{ contractInfo.paymentAccountInfo || '-' }}</el-descriptions-item>
<el-descriptions-item label="交货地点">{{ contractInfo.deliveryLocation || '-' }}</el-descriptions-item>
<el-descriptions-item label="运输方式">{{ contractInfo.shipMethod || '-' }}</el-descriptions-item>
<el-descriptions-item label="发货/交货期">{{ contractInfo.deliveryStart || '-' }}</el-descriptions-item>
<el-descriptions-item label="质保期描述" :span="3">{{ contractInfo.warrantyPeriodDescription || '-' }}</el-descriptions-item>
<el-descriptions-item label="合同大写金额" :span="3">{{ contractInfo.capitalizedAmount || '-' }}</el-descriptions-item>
</el-descriptions>
</div>
<div v-if="contractInfo.isFrameworkContract === '1'" class="contract-desc-section">
<div class="contract-desc-section__title">框架合同</div>
<el-descriptions :column="3" border class="order-descriptions">
<el-descriptions-item label="关联框架合同编号">{{ contractInfo.frameworkContractCode || '-' }}</el-descriptions-item>
<el-descriptions-item label="关联框架合同名称" :span="2">{{ contractInfo.frameworkContractName || '-' }}</el-descriptions-item>
<el-descriptions-item label="框架合同有效期" :span="3">
{{ contractInfo.frameworkValidPeriod ? parseTime(contractInfo.frameworkValidPeriod, '{y}-{m}-{d}') : '-' }}
</el-descriptions-item>
</el-descriptions>
</div>
<div class="contract-desc-section">
<div class="contract-desc-section__title">其他</div>
<el-descriptions :column="3" border class="order-descriptions">
<el-descriptions-item label="备注" :span="3">{{ contractInfo.remark || '-' }}</el-descriptions-item>
</el-descriptions>
</div>
</div>
<el-empty v-else description="暂无合同信息" class="empty-state" />
</div>
</el-tab-pane>
@ -246,8 +329,8 @@
</div>
</el-tab-pane>
<!-- 回款信息 Tab -->
<el-tab-pane label="回款信息" name="payment">
<!-- 回款信息 Tab仅创建人合同负责人角色 CVP 可见 -->
<el-tab-pane v-if="canViewPaymentLedger" label="回款信息" name="payment">
<div v-loading="loadingPayment" class="tab-content">
<div class="section-header">
<div class="header-left">
@ -255,7 +338,13 @@
<span class="section-title">回款信息</span>
<el-tag v-if="planStageList.length > 0" type="info" size="small" class="count-tag"> {{ planStageList.length }} </el-tag>
</div>
<div class="header-actions">
<div class="header-actions payment-header-actions">
<div v-if="contractInfo" class="payment-contract-total-inline">
<span class="payment-contract-total-inline__label">合同总价</span>
<span class="value-text value-amount">
{{ contractInfo.totalPrice != null ? formatNumber(contractInfo.totalPrice) + ' 元' : '-' }}
</span>
</div>
<el-button size="default" icon="Refresh" @click="loadPlanStageList"></el-button>
</div>
</div>
@ -405,16 +494,24 @@ import { getErpProjectPlanStageList } from '@/api/oa/erp/erpProjectPlanStage';
import { ErpProjectPlanStageForm } from '@/api/oa/erp/erpProjectPlanStage/types';
import { getBasePaymentStageList } from '@/api/oa/base/paymentStage';
import { PaymentStageVO } from '@/api/oa/base/paymentStage/types';
import { useUserStore } from '@/store/modules/user';
/** 回款台账可见角色标识 */
const PAYMENT_LEDGER_ROLE_KEY = 'CVP';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const userStore = useUserStore();
const route = useRoute();
const router = useRouter();
const {
business_direction,
contract_category,
contract_type,
contract_status,
contract_territorial_flag,
country_region,
currency_type,
contract_template_flag,
shipping_mode,
shipping_status,
order_purchase_status,
@ -431,8 +528,11 @@ const {
proxy?.useDict(
'business_direction',
'contract_category',
'contract_type',
'contract_status',
'contract_territorial_flag',
'country_region',
'currency_type',
'contract_template_flag',
'shipping_mode',
'shipping_status',
'order_purchase_status',
@ -451,6 +551,28 @@ const {
const projectId = computed(() => route.params.projectId as string | number | undefined);
const orderInfo = ref<ProjectInfoVO | null>(null);
const contractInfo = ref<ContractInfoVO | null>(null);
const sameUserId = (a: unknown, b: unknown): boolean => {
if (a === undefined || a === null || a === '') return false;
if (b === undefined || b === null || b === '') return false;
return String(a) === String(b);
};
/** 回款信息:本合同订单创建人、合同负责人、或角色权限字符含 CVP */
const canViewPaymentLedger = computed(() => {
const roles = userStore.roles ?? [];
if (roles.some((r) => r === PAYMENT_LEDGER_ROLE_KEY)) {
return true;
}
const uid = userStore.userId;
if (sameUserId(uid, orderInfo.value?.createBy)) {
return true;
}
if (sameUserId(uid, contractInfo.value?.contractManagerId)) {
return true;
}
return false;
});
const shippingList = ref<WmsShippingBillVO[]>([]);
const planStageList = ref<ErpProjectPlanStageForm[]>([]);
const paymentStageList = ref<PaymentStageVO[]>([]);
@ -496,6 +618,18 @@ const formatAmount = (num?: number | string | null) => {
return value.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
};
/** 对人民币汇率展示(与合同维护一致,最多 4 位小数) */
const formatExchangeRate = (val?: number | string | null) => {
if (val === null || val === undefined || val === '') {
return '-';
}
const n = Number(val);
if (!Number.isFinite(n)) {
return '-';
}
return n.toLocaleString('zh-CN', { minimumFractionDigits: 0, maximumFractionDigits: 4 });
};
/** 合同阶段比例等百分比展示 */
const formatStagePercent = (val: number | string | null | undefined) => {
if (val === null || val === undefined || val === '') {
@ -619,9 +753,19 @@ const loadOrderAndContract = async () => {
if (orderRes.data?.contractId) {
const contractRes = await getContractInfo(orderRes.data.contractId);
contractInfo.value = contractRes.data;
} else {
contractInfo.value = null;
}
} finally {
loadingContract.value = false;
// payment Tab
if (!canViewPaymentLedger.value) {
if (activeTab.value === 'payment') {
activeTab.value = 'contract';
}
loadedTabs.value.delete('payment');
planStageList.value = [];
}
}
};
@ -720,6 +864,10 @@ const loadPaymentStageBaseList = async () => {
/** 加载回款信息(项目阶段计划) */
const loadPlanStageList = async () => {
if (!canViewPaymentLedger.value) {
planStageList.value = [];
return;
}
if (!projectId.value) {
planStageList.value = [];
return;
@ -768,7 +916,9 @@ const handleTabChange = (tabName: string) => {
loadShippingList();
break;
case 'payment':
if (canViewPaymentLedger.value) {
loadPlanStageList();
}
break;
}
}
@ -778,6 +928,7 @@ watch(
() => projectId.value,
() => {
if (projectId.value) {
activeTab.value = 'contract';
loadedTabs.value.clear();
loadedTabs.value.add('contract');
loadPaymentStageBaseList();
@ -822,6 +973,23 @@ watch(
padding: 0;
}
.contract-info-pane {
display: flex;
flex-direction: column;
gap: 20px;
}
.contract-desc-section {
&__title {
margin: 0 0 10px;
font-size: 15px;
font-weight: 600;
color: #303133;
padding-left: 8px;
border-left: 3px solid #409eff;
}
}
.order-descriptions {
.value-text {
&.value-highlight {
@ -867,6 +1035,30 @@ watch(
}
}
.payment-header-actions {
display: flex;
align-items: center;
gap: 16px;
}
.payment-contract-total-inline {
display: flex;
align-items: center;
gap: 8px;
white-space: nowrap;
&__label {
font-size: 14px;
color: #606266;
font-weight: 500;
}
.value-text.value-amount {
font-weight: 600;
color: #e6a23c;
}
}
.data-table {
:deep(.el-table__header) {
th {

Loading…
Cancel
Save