detail.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <template>
  2. <view class="detail-container">
  3. <view class="header-card">
  4. <view class="title">{{ form.projectName || '未知名称' }}</view>
  5. <view class="meta-row">
  6. <view class="leader" v-if="form.projectIncharge">
  7. 项目负责人:{{ form.projectIncharge }}
  8. </view>
  9. <view class="tags">
  10. <text class="tag bg-blue">{{ getProjectTypeLabel(form.projectType) }}</text>
  11. </view>
  12. </view>
  13. </view>
  14. <view class="scroll-wrapper">
  15. <scroll-view scroll-y class="content-area" :show-scrollbar="false">
  16. <view class="component-wrapper">
  17. <CommonSection title="项目信息">
  18. <CommonInfoRow label="预算金额" :value="amountUnitFormatter(form.contractAmount) + '元'" :isAmount="true" />
  19. </CommonSection>
  20. <CommonSection title="入账经费">
  21. <CommonInfoRow label="经费类型" :value="getDictLabel('PaymentReceivedType', form.amountType)" />
  22. <CommonInfoRow label="入账金额" :value="amountUnitFormatter(form.amount) + '元'" :isAmount="true" />
  23. <CommonInfoRow label="入账时间" :value="formatDate(form.applyTime, 'YYYY-MM-DD')" />
  24. <CommonInfoRow label="拨款单位" :value="form.allotUnit" />
  25. <CommonInfoRow label="拨款时间" :value="formatDate(form.allotTime, 'YYYY-MM-DD')" />
  26. <CommonInfoRow label="入账说明" :value="form.remark" />
  27. </CommonSection>
  28. <CommonSection title="预算情况" v-if="form.fundsList && form.fundsList.length > 0">
  29. <CommonInfoRow v-for="(item, index) in form.fundsList" :key="item.id || index" :label="item.subjName"
  30. :value="amountUnitFormatter(item.amount) + '元'" :isAmount="true" />
  31. </CommonSection>
  32. </view>
  33. </scroll-view>
  34. </view>
  35. </view>
  36. </template>
  37. <script lang="ts" setup>
  38. import { ref } from 'vue';
  39. import { onLoad } from '@dcloudio/uni-app';
  40. import { useClaimApi } from '@/api/fund/index';
  41. import { formatDate } from '@/utils/date';
  42. import CommonSection from '@/components/ui/CommonSection.vue';
  43. import CommonInfoRow from '@/components/ui/CommonInfoRow.vue';
  44. import { useDict } from '@/hooks/useDict';
  45. const claimApi = useClaimApi();
  46. const { getDictLabel } = useDict('PaymentReceivedType');
  47. const form = ref<any>({
  48. id: 0,
  49. amount: '', //金额(元)
  50. projectName: '',
  51. projectType: '',
  52. contractAmount: '',
  53. projectIncharge: '',
  54. applyTime: '',
  55. amountType: '',
  56. allotUnit: '',
  57. allotTime: '',
  58. remark: '',
  59. fundsList: []
  60. });
  61. const getProjectTypeLabel = (type: string) => {
  62. const map: Record<string, string> = {
  63. '10': '纵向项目',
  64. '20': '横向项目',
  65. '30': '内部项目',
  66. '40': '重点学科',
  67. '50': '人才类项目',
  68. '60': '科研平台'
  69. };
  70. return map[type] || '-';
  71. };
  72. const amountUnitFormatter = (val: any) => {
  73. if (val === null || val === undefined || val === '') return '0.00';
  74. const num = Number(val);
  75. return isNaN(num) ? '0.00' : num.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
  76. };
  77. const getFundDetail = async (id: number) => {
  78. try {
  79. const res: any = await claimApi.getRecordDetails({ id });
  80. if (res.code == 200 && res.data) {
  81. form.value = { ...form.value, ...res.data };
  82. }
  83. } catch (err) {
  84. console.error('获取详情失败', err);
  85. }
  86. };
  87. onLoad((options: any) => {
  88. const id = options.id ? Number(options.id) : 0;
  89. if (id) {
  90. getFundDetail(id);
  91. }
  92. });
  93. </script>
  94. <style lang="scss" scoped>
  95. .detail-container {
  96. height: calc(100vh - var(--window-top));
  97. display: flex;
  98. flex-direction: column;
  99. background-color: #f5f7fa;
  100. box-sizing: border-box;
  101. }
  102. .header-card {
  103. flex-shrink: 0;
  104. background: linear-gradient(135deg, #1c9bfd 0%, #15a982 100%);
  105. padding: 40rpx 30rpx 40rpx;
  106. color: #fff;
  107. border-bottom-left-radius: 40rpx;
  108. border-bottom-right-radius: 40rpx;
  109. box-shadow: 0 10rpx 20rpx rgba(28, 155, 253, 0.2);
  110. .title {
  111. font-size: 40rpx;
  112. font-weight: bold;
  113. margin-bottom: 20rpx;
  114. line-height: 1.4;
  115. }
  116. .meta-row {
  117. display: flex;
  118. align-items: center;
  119. justify-content: space-between;
  120. gap: 20rpx;
  121. }
  122. .leader {
  123. font-size: 28rpx;
  124. opacity: 0.9;
  125. }
  126. .tags {
  127. display: flex;
  128. flex-wrap: wrap;
  129. gap: 16rpx;
  130. .tag {
  131. font-size: 24rpx;
  132. padding: 6rpx 20rpx;
  133. border-radius: 30rpx;
  134. border: 2rpx solid rgba(255, 255, 255, 0.4);
  135. background: rgba(255, 255, 255, 0.1);
  136. backdrop-filter: blur(4px);
  137. }
  138. }
  139. }
  140. .scroll-wrapper {
  141. flex: 1;
  142. overflow: hidden;
  143. margin-top: 10rpx;
  144. }
  145. .content-area {
  146. height: 100%;
  147. }
  148. .component-wrapper {
  149. margin: 0 30rpx;
  150. padding-top: 20rpx;
  151. padding-bottom: calc(40rpx + env(safe-area-inset-bottom));
  152. }
  153. </style>