ProjectMembers.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <template>
  2. <view class="module-container">
  3. <!-- 成员列表容器 -->
  4. <view class="member-list" v-if="memberList?.length">
  5. <view class="member-item" v-for="(row, index) in memberList" :key="index">
  6. <!-- 默认头像装饰 -->
  7. <image src="/static/imgs/tabBar/my.png" mode="aspectFit" class="avatar"></image>
  8. <view class="member-info">
  9. <!-- 姓名与身份标签 -->
  10. <view class="header">
  11. <text class="m-name">{{ row.memberName }}</text>
  12. <text class="m-tag m-role">{{ getRoleName(row.projectRole) }}</text>
  13. <text class="m-tag m-type">{{ getMemberTypeName(row.memberType) }}</text>
  14. </view>
  15. <!-- 详情信息区块 -->
  16. <view class="m-detail">
  17. <CommonInfoRow
  18. label="学位职称"
  19. :value="(getDictLabel('sci_academic_degree', row.degree) || '-') + ' / ' + (row.technicalTitle || '-')"
  20. />
  21. <CommonInfoRow
  22. label="所属科室"
  23. :value="row.deptName"
  24. />
  25. <CommonInfoRow
  26. label="负责内容"
  27. :value="row.responsibleContent"
  28. noBorder
  29. />
  30. </view>
  31. </view>
  32. </view>
  33. </view>
  34. <!-- 空状态展示 -->
  35. <view v-else class="empty-wrap">
  36. <uv-empty mode="data" text="暂无成员信息"></uv-empty>
  37. </view>
  38. </view>
  39. </template>
  40. <script setup lang="ts">
  41. import { useDict } from '@/hooks/useDict';
  42. import { computed } from 'vue';
  43. import type { ProjectMember } from '@/types/project';
  44. import { projectRoleOptions, memberTypeOptions } from '@/constants';
  45. import CommonInfoRow from '@/components/ui/CommonInfoRow.vue';
  46. /**
  47. * 接收父组件传递的属性
  48. * projectId: 项目内码
  49. * projectType: 项目分类标识
  50. * projectData: 包含完整成员列表的项目基本信息对象
  51. */
  52. const props = defineProps<{
  53. projectId: number;
  54. projectType: string;
  55. projectData: any;
  56. }>();
  57. // 使用字典 hooks 获取学位职称的明细标签
  58. const { getDictLabel } = useDict('sci_academic_degree');
  59. /**
  60. * 计算属性:成员列表
  61. * 针对不同类型的项目,后端返回的成员列表字段名存差异,此处统一进行向下兼容提取
  62. */
  63. const memberList = computed<ProjectMember[]>(() => {
  64. return props.projectData?.memberList ||
  65. props.projectData?.member ||
  66. [];
  67. });
  68. /**
  69. * 获取项目角色显示文本
  70. * @param roleVal 字典数值形式的状态
  71. * @returns 对应的中文解释说明
  72. */
  73. const getRoleName = (roleVal: string) => {
  74. const match = projectRoleOptions.find(o => o.dictValue === roleVal);
  75. return match ? match.dictLabel : '未知角色';
  76. };
  77. /**
  78. * 获取人员类型显示文本
  79. * @param typeVal 类型代码值
  80. * @returns 对应人员类型的文字标识(本院/非本院...)
  81. */
  82. const getMemberTypeName = (typeVal: string) => {
  83. const match = memberTypeOptions.find(o => o.dictValue === typeVal);
  84. return match ? match.dictLabel : '未知类型';
  85. };
  86. </script>
  87. <style lang="scss" scoped>
  88. .module-container {
  89. padding: 30rpx;
  90. background-color: #fff;
  91. border-radius: 16rpx;
  92. box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.03);
  93. .member-list {
  94. .member-item {
  95. display: flex;
  96. align-items: flex-start;
  97. padding: 30rpx 0;
  98. border-bottom: 2rpx dashed #f5f5f5;
  99. &:last-child { border-bottom: none; }
  100. .avatar {
  101. width: 88rpx;
  102. height: 88rpx;
  103. border-radius: 50%;
  104. background-color: #f0f4ff;
  105. margin-right: 24rpx;
  106. border: 2rpx solid #e1e8ff;
  107. }
  108. .member-info {
  109. flex: 1;
  110. display: flex;
  111. flex-direction: column;
  112. .header {
  113. display: flex;
  114. align-items: center;
  115. margin-bottom: 16rpx;
  116. flex-wrap: wrap;
  117. gap: 12rpx;
  118. .m-name {
  119. font-size: 32rpx;
  120. color: #343A3F;
  121. font-weight: bold;
  122. }
  123. .m-tag {
  124. font-size: 20rpx;
  125. padding: 4rpx 12rpx;
  126. border-radius: 6rpx;
  127. }
  128. .m-role {
  129. background-color: #e6f4ff;
  130. color: #1677ff;
  131. border: 2rpx solid #91caff;
  132. }
  133. .m-type {
  134. background-color: #f6ffed;
  135. color: #52c41a;
  136. border: 2rpx solid #b7eb8f;
  137. }
  138. }
  139. .m-detail {
  140. background-color: #fafbfc;
  141. padding: 16rpx;
  142. border-radius: 12rpx;
  143. }
  144. }
  145. }
  146. }
  147. .empty-wrap {
  148. padding: 60rpx 0;
  149. display: flex;
  150. justify-content: center;
  151. }
  152. }
  153. </style>