Files
yunzerwebsiteallinone/backend/src/views/apps/crm/project/components/detail_basic.vue
T
2026-09-14 16:15:44 +08:00

149 lines
6.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div v-if="project" class="project-basic">
<el-divider content-position="left">基本信息</el-divider>
<el-descriptions :column="2" border size="small">
<el-descriptions-item label="项目名称" :span="2">{{ project.project_name }}</el-descriptions-item>
<el-descriptions-item label="项目编号">{{ project.project_no || "-" }}</el-descriptions-item>
<el-descriptions-item label="项目类型">
<el-tag :type="projectTypeTag(project.project_type)" size="small" effect="plain">
{{ projectTypeText(project.project_type) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="项目状态">
<el-tag :type="projectStatusTag(project.status)" size="small">
{{ projectStatusText(project.status) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="负责人">{{ project.owner_user_name || "-" }}</el-descriptions-item>
<el-descriptions-item v-if="isBackToBack" label="项目毛利">
<span class="profit">¥{{ formatMoney(profitAmount) }}</span>
</el-descriptions-item>
<el-descriptions-item label="项目起止时间" :span="2">
{{ formatDateOnly(contractStart) }} ~ {{ formatDateOnly(contractEnd) }}
</el-descriptions-item>
<el-descriptions-item label="来源商机">
{{ project.business_name || (project.business_id ? `#${project.business_id}` : "-") }}
</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ formatDateTime(project.create_time) }}</el-descriptions-item>
<el-descriptions-item label="更新时间">{{ formatDateTime(project.update_time) }}</el-descriptions-item>
<el-descriptions-item label="项目地址" :span="2">{{ project.address || "-" }}</el-descriptions-item>
<el-descriptions-item label="备注" :span="2">{{ project.remark || "-" }}</el-descriptions-item>
</el-descriptions>
<!-- 单一项目不存在上下游概念,只展示客户信息;上下游 / 上中游项目区分上游(客户侧) -->
<el-divider content-position="left">{{ hasCounterparty ? "上游信息" : "客户信息" }}</el-divider>
<el-descriptions :column="2" border size="small">
<el-descriptions-item :label="hasCounterparty ? '上游客户' : '客户名称'">
{{ project.customer_name || "-" }}
</el-descriptions-item>
<el-descriptions-item :label="hasCounterparty ? '上游金额' : '项目金额'">
{{ formatMoney(upstreamAmount) }}
</el-descriptions-item>
<el-descriptions-item :label="hasCounterparty ? '上游对接人' : '对接人'">
{{ project.upstream_contact || project.contact_person || "-" }}
</el-descriptions-item>
<el-descriptions-item :label="hasCounterparty ? '上游联系电话' : '联系电话'">
{{ project.upstream_phone || project.contact_phone || "-" }}
</el-descriptions-item>
</el-descriptions>
<!-- 对方主体(上下游的下游供应商 / 上中游的中游中间方):仅这两类项目展示 -->
<template v-if="hasCounterparty">
<el-divider content-position="left">{{ counterpartyLabel }}信息</el-divider>
<el-descriptions :column="2" border size="small">
<el-descriptions-item :label="isUpMid ? '中游企业' : '供应商/客户'">
{{ project.supplier_name || "-" }}
<el-tag v-if="Number(project.supplier_ref_type) === 1" size="small" effect="plain" type="success">客户</el-tag>
<el-tag v-else-if="Number(project.supplier_ref_type) === 2" size="small" effect="plain" type="warning">
供应商
</el-tag>
</el-descriptions-item>
<el-descriptions-item :label="`${counterpartyLabel}金额`">
{{ formatMoney(project.downstream_amount) }}
</el-descriptions-item>
<el-descriptions-item :label="`${counterpartyLabel}对接人`">
{{ project.downstream_contact || "-" }}
</el-descriptions-item>
<el-descriptions-item :label="`${counterpartyLabel}联系电话`">
{{ project.downstream_phone || "-" }}
</el-descriptions-item>
<!-- 上中游项目:下游固定为本公司 -->
<el-descriptions-item v-if="isUpMid" label="下游(本公司)" :span="2">
{{ ownCompanyName }}
</el-descriptions-item>
</el-descriptions>
</template>
</div>
</template>
<script setup>
import { computed } from "vue";
import { useAuthStore } from "@/stores/auth";
import {
projectStatusText,
projectStatusTag,
projectTypeText,
projectTypeTag,
formatDateTime,
formatMoney,
formatDateOnly,
} from "../../dict";
const props = defineProps({
// 项目详情对象
project: { type: Object, default: null },
});
const authStore = useAuthStore();
/** 是否背靠背项目:需要展示下游(供应商)信息 */
const isBackToBack = computed(() => Number(props.project?.project_type) === 2);
/** 是否上中游项目:上游 A 公司 + 中游 B 公司,下游固定为本公司 */
const isUpMid = computed(() => Number(props.project?.project_type) === 3);
/** 是否需要展示「对方主体」(上下游的下游 / 上中游的中游) */
const hasCounterparty = computed(() => isBackToBack.value || isUpMid.value);
/** 对方主体称谓:上下游项目叫「下游」,上中游项目叫「中游」 */
const counterpartyLabel = computed(() => (isUpMid.value ? "中游" : "下游"));
/** 本公司名称:上中游项目的下游固定为本公司 */
const ownCompanyName = computed(() => authStore.user?.tenant_name || "本公司");
/** 上游金额:新字段优先,兼容存量项目仅有旧「项目金额」的情况 */
const upstreamAmount = computed(
() => Number(props.project?.upstream_amount) || Number(props.project?.amount) || 0
);
/** 项目毛利:上游金额 − 下游金额 */
const profitAmount = computed(
() => upstreamAmount.value - (Number(props.project?.downstream_amount) || 0)
);
/** 项目起止时间:由关联合同汇总(最早开始 / 最晚结束),兼容历史手工日期 */
const contractStart = computed(() => props.project?.contract_start_date || props.project?.start_date || "");
const contractEnd = computed(() => props.project?.contract_end_date || props.project?.end_date || "");
</script>
<style lang="less" scoped>
.project-basic {
padding-top:20px;
/* 首段标题紧贴容器顶部,避免多余留白 */
:deep(.el-divider:first-child) {
margin-top: 0;
}
}
.profit {
font-weight: 600;
color: var(--el-color-danger);
}
.tip {
margin-left: 6px;
font-size: 12px;
color: var(--el-text-color-secondary);
}
</style>