| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- <template>
- <view class="module-container">
- <uv-empty v-if="projectStore.fetchFundingLoading" mode="list" text="加载中..."></uv-empty>
- <view v-else class="content-wrapper">
-
- <!-- 经费汇总概览 -->
- <view class="summary-card">
- <view class="sum-row">
- <view class="sum-item">
- <text class="sum-label">到款合计({{ projectStore.fundsData?.fundAllotCount || 0 }}笔)</text>
- <text class="sum-value text-blue">{{ amountUnitFormatter(projectStore.fundsData?.fundAllotSum) }}<text class="unit">元</text></text>
- </view>
- <view class="sum-item">
- <text class="sum-label">结余</text>
- <text class="sum-value text-green">{{ amountUnitFormatter(projectStore.fundsData?.surplus) }}<text class="unit">元</text></text>
- </view>
- </view>
- <view class="sum-row">
- <view class="sum-item">
- <text class="sum-label">支出合计({{ projectStore.fundsData?.expenseCount || 0 }}笔)</text>
- <text class="sum-value text-red">{{ amountUnitFormatter(projectStore.fundsData?.expenseSum) }}<text class="unit">元</text></text>
- </view>
- <view class="sum-item">
- <text class="sum-label">外拨合计({{ projectStore.fundsData?.externalAllotCount || 0 }}笔)</text>
- <text class="sum-value text-orange">{{ amountUnitFormatter(projectStore.fundsData?.externalAllotSum) }}<text class="unit">元</text></text>
- </view>
- </view>
- </view>
- <!-- 标签页切换 -->
- <view class="tabs-wrapper">
- <uv-tabs :list="fundingTabs" :current="currentTab" @click="handleTabClick" lineColor="#1c9bfd" activeColor="#1c9bfd" inactiveColor="#666"></uv-tabs>
- </view>
- <!-- 入账列表 -->
- <view class="section" v-show="currentTab === 0">
- <uv-empty v-if="!projectStore.claimdData || projectStore.claimdData.length === 0" mode="data" text="暂无入账记录"></uv-empty>
- <template v-else>
- <CommonListCard
- v-for="(item, index) in projectStore.claimdData"
- :key="'in'+index"
- :title="item.allotNo || '入账记录'"
- statusType="primary"
- >
- <CommonInfoRow label="认领金额(元)" :value="amountUnitFormatter(item.amount)" isAmount />
- <CommonInfoRow label="外拨金额(元)" :value="amountUnitFormatter(item.externalAmount)" />
- <CommonInfoRow label="留校金额(元)" :value="amountUnitFormatter(item.internalAmount)" />
- <CommonInfoRow label="认领时间" :value="item.applyTime ? formatDate(item.applyTime) : '--'" />
- <CommonInfoRow label="摘要" :value="item.remark" />
- <CommonInfoRow label="创建人" :value="item.createBy || item.createName" />
- <CommonInfoRow label="创建时间" :value="item.createTime ? formatDate(item.createTime) : '--'" noBorder />
- </CommonListCard>
- </template>
- </view>
- <!-- 外拨列表 -->
- <view class="section" v-show="currentTab === 1">
- <uv-empty v-if="!projectStore.outBoundData || projectStore.outBoundData.length === 0" mode="data" text="暂无外拨记录"></uv-empty>
- <template v-else>
- <CommonListCard
- v-for="(item, index) in projectStore.outBoundData"
- :key="'out'+index"
- :title="item.externalAllotNo || '外拨记录'"
- statusType="warning"
- >
- <CommonInfoRow label="项目编号" :value="item.projectNo" />
- <CommonInfoRow label="外拨总额(元)" :value="amountUnitFormatter(item.amount)" isAmount />
- <CommonInfoRow label="已拨金额(元)" :value="amountUnitFormatter(item.allottedAmount)" />
- <CommonInfoRow label="未拨金额(元)" :value="amountUnitFormatter(item.notAllottedAmount)" />
- <CommonInfoRow label="申请日期" :value="item.applyTime ? formatDate(item.applyTime) : '--'" />
- <CommonInfoRow label="摘要" :value="item.remark" />
- <CommonInfoRow label="创建人" :value="item.createBy || item.createName" />
- <CommonInfoRow label="创建时间" :value="item.createTime ? formatDate(item.createTime) : '--'" noBorder />
- </CommonListCard>
- </template>
- </view>
- <!-- 支出列表 -->
- <view class="section" v-show="currentTab === 2">
- <uv-empty v-if="!projectStore.rebateData || projectStore.rebateData.length === 0" mode="data" text="暂无支出记录"></uv-empty>
- <template v-else>
- <CommonListCard
- v-for="(item, index) in projectStore.rebateData"
- :key="'exp'+index"
- :title="item.expenseNo || '支出记录'"
- :statusLabel="getExpenseStatusLabel(item.status)"
- :statusType="getExpenseStatusType(item.status)"
- >
- <CommonInfoRow label="支出金额(元)" :value="amountUnitFormatter(item.amount)" isAmount />
- <CommonInfoRow label="支出科目" :value="item.subject" />
- <CommonInfoRow label="收款人" :value="item.receiver" />
- <CommonInfoRow label="支出日期" :value="item.expendTime ? formatDate(item.expendTime) : '--'" />
- <CommonInfoRow label="摘要" :value="item.remark" />
- <CommonInfoRow label="创建人" :value="item.createBy || item.createName" />
- <CommonInfoRow label="创建时间" :value="item.createTime ? formatDate(item.createTime) : '--'" :noBorder="!(item.fileName && item.fileUrl)" />
-
- <view v-if="item.fileName && item.fileUrl" style="margin-top: 20rpx;">
- <CommonFileList :files="[{ fileName: item.fileName, fileUrl: item.fileUrl }]" />
- </view>
- </CommonListCard>
- </template>
- </view>
- </view>
- </view>
- </template>
- <script setup lang="ts">
- import { ref, watch } from 'vue';
- import { useProjectStore } from '@/store/modules/project';
- import { formatDate } from '@/utils/date';
- import { formatWithComma } from '@/utils/format';
- import { previewFile } from '@/utils/file';
- import CommonListCard from '@/components/ui/CommonListCard.vue';
- import CommonInfoRow from '@/components/ui/CommonInfoRow.vue';
- import CommonFileList from '@/components/ui/CommonFileList.vue';
- /**
- * 接收来自父组件的属性
- * projectId: 项目内码
- * projectType: 项目分类标识
- */
- const props = defineProps<{
- projectId: number;
- projectType: string;
- }>();
- const projectStore = useProjectStore();
- // 当前激活的子 Tab 索引
- const currentTab = ref(0);
- // 经费模块内部的子 Tab 配置
- const fundingTabs = ref([
- { name: '入账记录' },
- { name: '外拨记录' },
- { name: '支出记录' }
- ]);
- /**
- * 切换子 Tab 处理
- */
- const handleTabClick = (item: any) => {
- currentTab.value = item.index;
- };
- /**
- * 监听项目 ID 变化,触发经费数据加载
- */
- watch(() => props.projectId, (id) => {
- if (id) {
- projectStore.fetchFunding(id, props.projectType);
- }
- }, { immediate: true });
- /**
- * 金额格式化处理
- * 使用全局统一的千分位格式化工具
- */
- const amountUnitFormatter = (num: any) => {
- return formatWithComma(num);
- };
- /**
- * 获取项目类型名称 (内部逻辑)
- */
- const getProjectType = (code: string | number) => {
- if (code == 10) return '纵向项目';
- if (code == 20) return '横向项目';
- if (code == 30) return '内部项目';
- if (code == 40) return '重点学科';
- return '未知';
- };
- /**
- * 获取支出记录审批状态说明
- */
- const getExpenseStatusLabel = (status: string | number) => {
- if (status == 10) return '待审核';
- if (status == 20) return '已通过';
- if (status == 30) return '已拒绝';
- return '未知';
- };
- /**
- * 获取支出记录审批状态对应的 UI 类型
- */
- const getExpenseStatusType = (status: string | number) => {
- if (status == 10) return 'info';
- if (status == 20) return 'success';
- if (status == 30) return 'error';
- return 'default';
- };
- /**
- * 统一附件打开/预览处理
- */
- const handleDownload = (file: any) => {
- if (!file.fileUrl) return;
- previewFile(file.fileUrl, file.fileName);
- };
- </script>
- <style lang="scss" scoped>
- .module-container {
- min-height: 400rpx;
- position: relative;
- }
- .content-wrapper {
- display: flex;
- flex-direction: column;
- gap: 30rpx;
- }
- .tabs-wrapper {
- background-color: #fff;
- border-radius: 16rpx;
- overflow: hidden;
- box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.03);
- }
- .summary-card {
- background: #fff;
- border-radius: 16rpx;
- padding: 30rpx;
- box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.03);
- display: flex;
- flex-direction: column;
- gap: 20rpx;
- .sum-row {
- display: flex;
- justify-content: space-between;
- .sum-item {
- flex: 1;
- display: flex;
- flex-direction: column;
- align-items: center;
- .sum-label {
- font-size: 26rpx;
- color: #888;
- margin-bottom: 12rpx;
- }
- .sum-value {
- font-size: 36rpx;
- font-weight: bold;
- font-family: din;
-
- .unit {
- font-size: 24rpx;
- margin-left: 4rpx;
- font-weight: normal;
- }
- }
- .text-blue { color: #1c9bfd; }
- .text-green { color: #52c41a; }
- .text-red { color: #ff4d4f; }
- .text-orange { color: #faad14; }
- }
- }
- }
- .section {
- width: 100%;
- }
- </style>
|