ProjectAchievements.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <template>
  2. <view class="module-container">
  3. <uv-empty v-if="projectStore.fetchAchievementLoading" mode="list" text="加载中..."></uv-empty>
  4. <view v-else-if="isEmpty" class="empty-wrap">
  5. <uv-empty mode="data" text="暂无科研成果"></uv-empty>
  6. </view>
  7. <view v-else class="list-wrapper">
  8. <!-- 标签页切换 -->
  9. <view class="tabs-wrapper">
  10. <uv-tabs :list="achievementTabs" :current="currentTab" @click="handleTabClick" lineColor="#1c9bfd" activeColor="#1c9bfd" inactiveColor="#666"></uv-tabs>
  11. </view>
  12. <!-- 学术论文 -->
  13. <view class="section" v-show="currentTab === 0">
  14. <uv-empty v-if="!projectStore.paperData || projectStore.paperData.length === 0" mode="data" text="暂无学术论文"></uv-empty>
  15. <template v-else>
  16. <CommonListCard
  17. v-for="(item, index) in projectStore.paperData"
  18. :key="index"
  19. :title="(index + 1) + '. ' + (item.paperName || '未知论文')"
  20. >
  21. <CommonInfoRow label="论文编号" :value="item.paperCode" />
  22. <CommonInfoRow label="发表/出版时间" :value="item.publicationDate ? formatDate(item.publicationDate) : '--'" />
  23. <CommonInfoRow label="发表/刊物论文集" :value="item.publicationName" />
  24. <CommonInfoRow label="论文类型" :value="getLabel(paperTypeOptions, item.paperType)" noBorder />
  25. </CommonListCard>
  26. </template>
  27. </view>
  28. <!-- 学术著作 -->
  29. <view class="section" v-show="currentTab === 1">
  30. <uv-empty v-if="!projectStore.workData || projectStore.workData.length === 0" mode="data" text="暂无学术著作"></uv-empty>
  31. <template v-else>
  32. <CommonListCard
  33. v-for="(item, index) in projectStore.workData"
  34. :key="index"
  35. :title="(index + 1) + '. ' + (item.workName || '未知著作')"
  36. >
  37. <CommonInfoRow label="著作编号" :value="item.workCode" />
  38. <CommonInfoRow label="著作类别" :value="getLabel(workClassOptions, item.workClass)" />
  39. <CommonInfoRow label="出版单位" :value="item.workPublisher" />
  40. <CommonInfoRow label="出版时间" :value="item.workPublicationDate ? formatDate(item.workPublicationDate) : '--'" />
  41. <CommonInfoRow label="所属单位" :value="item.deptName" noBorder />
  42. </CommonListCard>
  43. </template>
  44. </view>
  45. <!-- 学术专利 -->
  46. <view class="section" v-show="currentTab === 2">
  47. <uv-empty v-if="!projectStore.patentData || projectStore.patentData.length === 0" mode="data" text="暂无学术专利"></uv-empty>
  48. <template v-else>
  49. <CommonListCard
  50. v-for="(item, index) in projectStore.patentData"
  51. :key="index"
  52. :title="(index + 1) + '. ' + (item.patentName || '未知专利')"
  53. >
  54. <CommonInfoRow label="专利编号" :value="item.patentCode" />
  55. <CommonInfoRow label="所属单位" :value="item.deptName" />
  56. <CommonInfoRow label="专利类型" :value="getLabel(patentClassOptions, item.patentClass)" />
  57. <CommonInfoRow label="专利简介" :value="item.patentDesc" />
  58. <CommonInfoRow label="申请人" :value="item.applicantName" noBorder />
  59. </CommonListCard>
  60. </template>
  61. </view>
  62. <!-- 奖项荣誉 -->
  63. <view class="section" v-show="currentTab === 3">
  64. <uv-empty v-if="!projectStore.awardData || projectStore.awardData.length === 0" mode="data" text="暂无奖项荣誉"></uv-empty>
  65. <template v-else>
  66. <CommonListCard
  67. v-for="(item, index) in projectStore.awardData"
  68. :key="index"
  69. :title="(index + 1) + '. ' + (item.awardName || '未知奖项')"
  70. >
  71. <CommonInfoRow label="获奖编号" :value="item.awardCode" />
  72. <CommonInfoRow label="成果名称" :value="item.resultName" />
  73. <CommonInfoRow label="奖励类型" :value="getLabel(awardTypeOptions, item.awardType)" />
  74. <CommonInfoRow label="发证机关" :value="item.awardIssueAuthority" />
  75. <CommonInfoRow label="获奖级别" :value="getLabel(awardLevelOptions, item.awardLevel)" />
  76. <CommonInfoRow label="获奖等级" :value="getLabel(awardGradeOptions, item.awardGrade)" />
  77. <CommonInfoRow label="奖励类别" :value="getLabel(awardClassOptions, item.awardClass)" />
  78. <CommonInfoRow label="获奖日期" :value="item.awardDate ? formatDate(item.awardDate) : '--'" />
  79. <CommonInfoRow label="成果形式" :value="item.resultForm" />
  80. <CommonInfoRow label="所属单位" :value="item.deptName" />
  81. <CommonInfoRow label="合作类型" :value="getLabel(cooperationTypeOptions, item.cooperationType)" />
  82. <CommonInfoRow label="项目来源" :value="item.projectSource" noBorder />
  83. </CommonListCard>
  84. </template>
  85. </view>
  86. </view>
  87. </view>
  88. </template>
  89. <script setup lang="ts">
  90. import { onMounted, computed, watch, ref } from 'vue';
  91. import { useProjectStore } from '@/store/modules/project';
  92. import { formatDate } from '@/utils/date';
  93. import {
  94. paperTypeOptions,
  95. workClassOptions,
  96. patentClassOptions,
  97. awardLevelOptions,
  98. awardGradeOptions,
  99. awardClassOptions,
  100. awardTypeOptions,
  101. cooperationTypeOptions
  102. } from '@/constants';
  103. import CommonListCard from '@/components/ui/CommonListCard.vue';
  104. import CommonInfoRow from '@/components/ui/CommonInfoRow.vue';
  105. /**
  106. * 接收来自父组件的属性
  107. * projectId: 项目内码
  108. * projectType: 项目分类标识
  109. * projectData: 包含 projectCode 的项目基本信息
  110. */
  111. const props = defineProps<{
  112. projectId: number;
  113. projectType: string;
  114. projectData: any;
  115. }>();
  116. const projectStore = useProjectStore();
  117. // 当前激活的子 Tab 索引 (学术论文/著作/专利/奖项)
  118. const currentTab = ref(0);
  119. const achievementTabs = ref([
  120. { name: '学术论文' },
  121. { name: '学术著作' },
  122. { name: '学术专利' },
  123. { name: '奖项荣誉' }
  124. ]);
  125. /**
  126. * 切换子 Tab 处理
  127. */
  128. const handleTabClick = (item: any) => {
  129. currentTab.value = item.index;
  130. };
  131. /**
  132. * 计算属性:检查所有成果数据是否都为空
  133. * 用于触发全局暂无数据的占位图展示
  134. */
  135. const isEmpty = computed(() => {
  136. return (
  137. (!projectStore.paperData || projectStore.paperData.length === 0) &&
  138. (!projectStore.workData || projectStore.workData.length === 0) &&
  139. (!projectStore.patentData || projectStore.patentData.length === 0) &&
  140. (!projectStore.awardData || projectStore.awardData.length === 0)
  141. );
  142. });
  143. /**
  144. * 监听项目代码变化,联动发起成果数据查询
  145. */
  146. watch(() => props.projectData?.projectCode, (code) => {
  147. if (code) {
  148. projectStore.fetchAchievements(code, props.projectType);
  149. }
  150. }, { immediate: true });
  151. /**
  152. * 通用方法:根据字典值获取对应的展示文本
  153. * @param options 常量字典数组 (包含 dictLabel 和 dictValue)
  154. * @param value 待匹配的代码值
  155. * @returns 匹配到的中文名称,未匹配到返回 '--'
  156. */
  157. const getLabel = (options: any[], value: string | number) => {
  158. if (!value) return '--';
  159. const match = options.find((item) => item.dictValue == value);
  160. return match ? match.dictLabel : '--';
  161. };
  162. </script>
  163. <style lang="scss" scoped>
  164. .module-container {
  165. min-height: 400rpx;
  166. position: relative;
  167. }
  168. .empty-wrap {
  169. min-height: 300rpx;
  170. display: flex;
  171. justify-content: center;
  172. align-items: center;
  173. }
  174. .tabs-wrapper {
  175. background-color: #fff;
  176. border-radius: 16rpx;
  177. overflow: hidden;
  178. box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.03);
  179. margin-bottom: 24rpx;
  180. }
  181. .section {
  182. display: flex;
  183. flex-direction: column;
  184. gap: 20rpx;
  185. }
  186. </style>