|
|
|
|
@ -0,0 +1,513 @@
|
|
|
|
|
<template>
|
|
|
|
|
<div class="project-ledger-container">
|
|
|
|
|
<el-card shadow="never" class="main-card">
|
|
|
|
|
<template #header>
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
<span class="header-title">项目台账</span>
|
|
|
|
|
<el-button size="default" type="primary" icon="ArrowLeft" @click="handleBack">返回</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
<el-tabs v-model="activeTab" @tab-change="handleTabChange" class="custom-tabs">
|
|
|
|
|
<el-tab-pane label="项目基本信息" name="project">
|
|
|
|
|
<div v-loading="loadingProject" class="tab-content">
|
|
|
|
|
<el-descriptions :column="3" border v-if="projectInfo" class="project-descriptions">
|
|
|
|
|
<el-descriptions-item label="项目编号" :span="1">
|
|
|
|
|
<span class="value-text value-highlight">{{ projectInfo?.projectCode || '-' }}</span>
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="项目名称" :span="2">
|
|
|
|
|
<span class="value-text value-highlight">{{ projectInfo?.projectName || '-' }}</span>
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="有无合同">
|
|
|
|
|
<dict-tag :options="contract_flag" :value="projectInfo?.contractFlag" />
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="业务方向">
|
|
|
|
|
<dict-tag :options="business_direction" :value="projectInfo?.businessDirection" />
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="项目类别">
|
|
|
|
|
<dict-tag :options="project_category" :value="projectInfo?.projectCategory" />
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="项目状态">
|
|
|
|
|
<dict-tag :options="project_status" :value="projectInfo?.projectStatus" />
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="流程状态">
|
|
|
|
|
<dict-tag :options="wf_business_status" :value="projectInfo?.flowStatus" />
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="激活标识">
|
|
|
|
|
<dict-tag :options="active_flag" :value="projectInfo?.activeFlag" />
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="项目经理">{{ projectInfo?.managerName || '-' }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="部门负责人">{{ projectInfo?.chargeName || '-' }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="部门">{{ projectInfo?.deptName || '-' }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="付款方式">{{ projectInfo?.paymentMethod || '-' }}</el-descriptions-item>
|
|
|
|
|
<el-descriptions-item label="金额" :span="1">
|
|
|
|
|
<span class="value-text value-amount">
|
|
|
|
|
{{ projectInfo?.amount ? formatNumber(projectInfo.amount) + ' 元' : '-' }}
|
|
|
|
|
</span>
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
</el-descriptions>
|
|
|
|
|
<el-empty v-else description="暂无项目信息" class="empty-state" />
|
|
|
|
|
</div>
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
|
|
|
|
|
<el-tab-pane label="合同信息" name="contract">
|
|
|
|
|
<div v-loading="loadingContract" class="tab-content">
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
<div class="header-left">
|
|
|
|
|
<i class="el-icon-document-copy section-icon"></i>
|
|
|
|
|
<span class="section-title">合同信息</span>
|
|
|
|
|
<el-tag v-if="contractList.length > 0" type="info" size="small" class="count-tag">
|
|
|
|
|
{{ contractList.length }} 条
|
|
|
|
|
</el-tag>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="header-actions">
|
|
|
|
|
<el-button size="default" type="primary" plain icon="Link" @click="openContractPage">前往合同页面</el-button>
|
|
|
|
|
<el-button size="default" icon="Refresh" @click="loadContractList">刷新</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<el-table :data="contractList" size="default" border stripe v-loading="loadingContract" class="data-table">
|
|
|
|
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
|
|
|
|
<el-table-column label="合同编号" prop="contractCode" width="150" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="合同名称" prop="contractName" min-width="200" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="合同总价" prop="totalPrice" width="130" align="right">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
{{ scope.row.totalPrice ? formatNumber(scope.row.totalPrice) + ' 元' : '-' }}
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="业务方向" prop="businessDirection" width="120">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<dict-tag :options="business_direction" :value="scope.row.businessDirection" />
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="合同状态" prop="contractStatus" width="120">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<dict-tag :options="contract_status" :value="scope.row.contractStatus" />
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="流程状态" prop="flowStatus" width="120">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<dict-tag :options="wf_business_status" :value="scope.row.flowStatus" />
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="备注" prop="remark" min-width="150" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="操作" width="100" align="center" fixed="right">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<el-button size="default" type="primary" text @click="viewContract(scope.row)">查看</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
<el-empty v-if="!loadingContract && contractList.length === 0" description="暂无合同信息" class="empty-state" />
|
|
|
|
|
</div>
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
|
|
|
|
|
<el-tab-pane label="预算信息" name="budget">
|
|
|
|
|
<div v-loading="loadingBudget" class="tab-content">
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
<div class="header-left">
|
|
|
|
|
<i class="el-icon-coin section-icon"></i>
|
|
|
|
|
<span class="section-title">预算信息</span>
|
|
|
|
|
<el-tag v-if="budgetTotal > 0" type="info" size="small" class="count-tag">
|
|
|
|
|
{{ budgetTotal }} 条
|
|
|
|
|
</el-tag>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="header-actions">
|
|
|
|
|
<el-button size="default" type="primary" plain icon="Link" @click="openBudgetPage">预算页面</el-button>
|
|
|
|
|
<el-button size="default" icon="Refresh" @click="loadBudgetList">刷新</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<el-table :data="budgetList" size="default" border stripe v-loading="loadingBudget" class="data-table">
|
|
|
|
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
|
|
|
|
<el-table-column label="预算ID" prop="budgetId" width="120" />
|
|
|
|
|
<el-table-column label="版本" prop="budgetVersion" width="80" align="center" />
|
|
|
|
|
<el-table-column label="预算状态" prop="budgetStatus" width="120" align="center">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<dict-tag :options="budget_status" :value="scope.row.budgetStatus" />
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="合同额(元)" prop="contractAmount" width="130" align="right">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
{{ scope.row.contractAmount ? formatNumber(scope.row.contractAmount) : '-' }}
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="预算成本(元)" prop="budgetCost" width="130" align="right">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
{{ scope.row.budgetCost ? formatNumber(scope.row.budgetCost) : '-' }}
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="预算毛利率(%)" prop="budgetRate" width="130" align="right">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
{{ scope.row.budgetRate ? (scope.row.budgetRate / 100).toFixed(2) + '%' : '-' }}
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="备注" prop="remark" min-width="150" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="操作" width="100" align="center" fixed="right">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<el-button size="default" type="primary" text @click="viewBudget(scope.row)">查看</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
<el-empty v-if="!loadingBudget && budgetList.length === 0" description="暂无预算信息" class="empty-state" />
|
|
|
|
|
<pagination
|
|
|
|
|
v-show="budgetTotal > 0"
|
|
|
|
|
:total="budgetTotal"
|
|
|
|
|
v-model:page="budgetQuery.pageNum"
|
|
|
|
|
v-model:limit="budgetQuery.pageSize"
|
|
|
|
|
@pagination="loadBudgetList"
|
|
|
|
|
class="pagination-wrapper"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
|
|
|
|
|
<el-tab-pane label="项目计划" name="plan">
|
|
|
|
|
<div v-loading="loadingPlan" class="tab-content">
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
<div class="header-left">
|
|
|
|
|
<i class="el-icon-calendar section-icon"></i>
|
|
|
|
|
<span class="section-title">项目计划</span>
|
|
|
|
|
<el-tag v-if="planTotal > 0" type="info" size="small" class="count-tag">
|
|
|
|
|
{{ planTotal }} 条
|
|
|
|
|
</el-tag>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="header-actions">
|
|
|
|
|
<el-button size="default" type="primary" plain icon="Link" @click="openPlanPage">项目计划页面</el-button>
|
|
|
|
|
<el-button size="default" icon="Refresh" @click="loadPlanList">刷新</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<el-table :data="planList" size="default" border stripe v-loading="loadingPlan" class="data-table">
|
|
|
|
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
|
|
|
|
<el-table-column label="计划编号" prop="projectPlanCode" width="180" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="项目名称" prop="projectName" min-width="200" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="项目经理" prop="managerName" width="120" />
|
|
|
|
|
<el-table-column label="部门负责人" prop="chargeName" width="120" />
|
|
|
|
|
<el-table-column label="付款方式" prop="paymentMethod" width="120" />
|
|
|
|
|
<el-table-column label="项目计划状态" prop="projectPlanStatus" width="150" align="center">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<dict-tag :options="project_plan_status" :value="scope.row.projectPlanStatus" />
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="流程状态" prop="flowStatus" width="120" align="center">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<dict-tag :options="wf_business_status" :value="scope.row.flowStatus" />
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="关联合同" prop="contractName" min-width="180" show-overflow-tooltip />
|
|
|
|
|
<el-table-column label="操作" width="100" align="center" fixed="right">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<el-button size="default" type="primary" text @click="viewPlan(scope.row)">查看</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
<el-empty v-if="!loadingPlan && planList.length === 0" description="暂无项目计划" class="empty-state" />
|
|
|
|
|
<pagination
|
|
|
|
|
v-show="planTotal > 0"
|
|
|
|
|
:total="planTotal"
|
|
|
|
|
v-model:page="planQuery.pageNum"
|
|
|
|
|
v-model:limit="planQuery.pageSize"
|
|
|
|
|
@pagination="loadPlanList"
|
|
|
|
|
class="pagination-wrapper"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
</el-tabs>
|
|
|
|
|
</el-card>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts" name="ProjectLedger">
|
|
|
|
|
import { computed, reactive, ref, toRefs, watch } from 'vue';
|
|
|
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
|
|
|
import { getProjectInfo } from '@/api/oa/erp/projectInfo';
|
|
|
|
|
import { listErpBudgetInfo } from '@/api/oa/erp/budgetInfo';
|
|
|
|
|
import { budgetInfoVO } from '@/api/oa/erp/budgetInfo/types';
|
|
|
|
|
import { listErpProjectPlan } from '@/api/oa/erp/erpProjectPlan';
|
|
|
|
|
import { ErpProjectPlanVO } from '@/api/oa/erp/erpProjectPlan/types';
|
|
|
|
|
import { ProjectInfoVO } from '@/api/oa/erp/projectInfo/types';
|
|
|
|
|
import { getErpProjectContractsList } from '@/api/oa/erp/projectContracts';
|
|
|
|
|
import { ProjectContractsVO } from '@/api/oa/erp/projectContracts/types';
|
|
|
|
|
|
|
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
|
|
|
|
const { contract_flag, project_category, business_direction, project_status, wf_business_status, active_flag, contract_status, contract_category, project_plan_status, budget_status } =
|
|
|
|
|
toRefs<any>(proxy?.useDict('contract_flag', 'project_category', 'business_direction', 'project_status', 'wf_business_status', 'active_flag', 'contract_status', 'contract_category', 'project_plan_status', 'budget_status'));
|
|
|
|
|
|
|
|
|
|
const projectId = computed(() => route.params.projectId as string | number | undefined);
|
|
|
|
|
const projectInfo = ref<ProjectInfoVO | null>(null);
|
|
|
|
|
const contractList = ref<ProjectContractsVO[]>([]);
|
|
|
|
|
|
|
|
|
|
const activeTab = ref('project');
|
|
|
|
|
|
|
|
|
|
// 记录已加载的标签页,实现懒加载
|
|
|
|
|
const loadedTabs = ref<Set<string>>(new Set(['project']));
|
|
|
|
|
|
|
|
|
|
const loadingProject = ref(false);
|
|
|
|
|
const loadingContract = ref(false);
|
|
|
|
|
const loadingBudget = ref(false);
|
|
|
|
|
const loadingPlan = ref(false);
|
|
|
|
|
|
|
|
|
|
const budgetList = ref<budgetInfoVO[]>([]);
|
|
|
|
|
const planList = ref<ErpProjectPlanVO[]>([]);
|
|
|
|
|
const budgetTotal = ref(0);
|
|
|
|
|
const planTotal = ref(0);
|
|
|
|
|
|
|
|
|
|
const budgetQuery = reactive({ pageNum: 1, pageSize: 5, projectId: undefined });
|
|
|
|
|
const planQuery = reactive({ pageNum: 1, pageSize: 5, projectId: undefined });
|
|
|
|
|
|
|
|
|
|
const handleBack = () => {
|
|
|
|
|
proxy?.$tab.closePage(route);
|
|
|
|
|
router.back();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const openContractPage = () => {
|
|
|
|
|
proxy?.$tab.openPage('/oa/erp/contractInfo', '合同管理');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const openBudgetPage = () => {
|
|
|
|
|
proxy?.$tab.openPage('/oa/erp/budgetInfo', '项目预算');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const openPlanPage = () => {
|
|
|
|
|
proxy?.$tab.openPage('/oa/erp/erpProjectPlan', '项目计划');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const viewBudget = (row: budgetInfoVO) => {
|
|
|
|
|
if (!row?.budgetId) return;
|
|
|
|
|
proxy?.$tab.openPage('/oa/erp/budgetInfo/edit', '项目预算申请', {
|
|
|
|
|
id: row.budgetId,
|
|
|
|
|
type: 'view'
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const viewPlan = (row: ErpProjectPlanVO) => {
|
|
|
|
|
if (!row?.projectPlanId) return;
|
|
|
|
|
router.push(`/oa/erp/erpProjectPlan/view/${row.projectPlanId}`);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const viewContract = (row: ProjectContractsVO) => {
|
|
|
|
|
if (!row?.contractId) return;
|
|
|
|
|
proxy?.$tab.openPage('/oa/erp/contractInfo/edit', '合同信息', {
|
|
|
|
|
id: row.contractId,
|
|
|
|
|
type: 'view'
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 格式化数字,添加千分位
|
|
|
|
|
const formatNumber = (num: number) => {
|
|
|
|
|
if (!num) return '0';
|
|
|
|
|
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const loadContractList = async () => {
|
|
|
|
|
if (!projectId.value) {
|
|
|
|
|
contractList.value = [];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
loadingContract.value = true;
|
|
|
|
|
try {
|
|
|
|
|
const params = { projectId: projectId.value } as any;
|
|
|
|
|
const res = await getErpProjectContractsList(params);
|
|
|
|
|
// 后端已经通过left join返回了完整的合同信息
|
|
|
|
|
contractList.value = res.data || [];
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('查询项目关联合同失败:', error);
|
|
|
|
|
contractList.value = [];
|
|
|
|
|
} finally {
|
|
|
|
|
loadingContract.value = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const loadBudgetList = async () => {
|
|
|
|
|
if (!projectId.value) {
|
|
|
|
|
budgetList.value = [];
|
|
|
|
|
budgetTotal.value = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
loadingBudget.value = true;
|
|
|
|
|
try {
|
|
|
|
|
const res: any = await listErpBudgetInfo({
|
|
|
|
|
...budgetQuery,
|
|
|
|
|
projectId: projectId.value
|
|
|
|
|
});
|
|
|
|
|
budgetList.value = res.rows || [];
|
|
|
|
|
budgetTotal.value = res.total || 0;
|
|
|
|
|
} finally {
|
|
|
|
|
loadingBudget.value = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const loadPlanList = async () => {
|
|
|
|
|
if (!projectId.value) {
|
|
|
|
|
planList.value = [];
|
|
|
|
|
planTotal.value = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
loadingPlan.value = true;
|
|
|
|
|
try {
|
|
|
|
|
const res: any = await listErpProjectPlan({
|
|
|
|
|
...planQuery,
|
|
|
|
|
projectId: projectId.value
|
|
|
|
|
});
|
|
|
|
|
planList.value = res.rows || [];
|
|
|
|
|
planTotal.value = res.total || 0;
|
|
|
|
|
} finally {
|
|
|
|
|
loadingPlan.value = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const loadProjectInfo = async () => {
|
|
|
|
|
if (!projectId.value) return;
|
|
|
|
|
loadingProject.value = true;
|
|
|
|
|
try {
|
|
|
|
|
const res = await getProjectInfo(projectId.value);
|
|
|
|
|
projectInfo.value = res.data;
|
|
|
|
|
} finally {
|
|
|
|
|
loadingProject.value = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 标签切换处理
|
|
|
|
|
const handleTabChange = (tabName: string) => {
|
|
|
|
|
if (!loadedTabs.value.has(tabName)) {
|
|
|
|
|
loadedTabs.value.add(tabName);
|
|
|
|
|
switch (tabName) {
|
|
|
|
|
case 'contract':
|
|
|
|
|
loadContractList();
|
|
|
|
|
break;
|
|
|
|
|
case 'budget':
|
|
|
|
|
budgetQuery.pageNum = 1;
|
|
|
|
|
budgetQuery.projectId = projectId.value;
|
|
|
|
|
loadBudgetList();
|
|
|
|
|
break;
|
|
|
|
|
case 'plan':
|
|
|
|
|
planQuery.pageNum = 1;
|
|
|
|
|
planQuery.projectId = projectId.value;
|
|
|
|
|
loadPlanList();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const loadAll = async () => {
|
|
|
|
|
await loadProjectInfo();
|
|
|
|
|
budgetQuery.projectId = projectId.value;
|
|
|
|
|
planQuery.projectId = projectId.value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
() => projectId.value,
|
|
|
|
|
() => {
|
|
|
|
|
if (projectId.value) {
|
|
|
|
|
loadedTabs.value.clear();
|
|
|
|
|
loadedTabs.value.add('project');
|
|
|
|
|
loadAll();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{ immediate: true }
|
|
|
|
|
);
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
.project-ledger-container {
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
|
|
|
|
.main-card {
|
|
|
|
|
:deep(.el-card__header) {
|
|
|
|
|
.card-header {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
.header-title {
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: #303133;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-card__body) {
|
|
|
|
|
padding: 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.custom-tabs {
|
|
|
|
|
:deep(.el-tabs__content) {
|
|
|
|
|
padding: 20px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tab-content {
|
|
|
|
|
padding: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.section-header {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
padding-bottom: 12px;
|
|
|
|
|
border-bottom: 1px solid #e4e7ed;
|
|
|
|
|
|
|
|
|
|
.header-left {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
|
|
|
|
.section-icon {
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
color: #409eff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.section-title {
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: #303133;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.header-actions {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.project-descriptions {
|
|
|
|
|
.value-text {
|
|
|
|
|
&.value-highlight {
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: #409eff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
&.value-amount {
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: #f56c6c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.data-table {
|
|
|
|
|
:deep(.el-table__header) {
|
|
|
|
|
th {
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.el-table__body) {
|
|
|
|
|
tr:hover {
|
|
|
|
|
background-color: #f5f7fa;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.empty-state {
|
|
|
|
|
padding: 40px 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.pagination-wrapper {
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|