ProjectEthical.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. <template>
  2. <view class="module-container">
  3. <uv-empty v-if="loading" mode="list" text="加载中..."></uv-empty>
  4. <uv-empty v-else-if="!listData || listData.length === 0" mode="data" text="暂无伦理信息"></uv-empty>
  5. <view class="list-wrapper" v-else>
  6. <CommonListCard
  7. v-for="(item, index) in listData"
  8. :key="index"
  9. :title="(index + 1) + '. ' + (item.reviewCode || '-')"
  10. :statusLabel="getReviewStatusText(item.reviewStatus)"
  11. :statusType="getReviewStatusType(item.reviewStatus)"
  12. >
  13. <template #status v-if="getApplyStatusText(item)">
  14. <view class="tags-group">
  15. <text class="status-tag" :class="getReviewStatusClass(item.reviewStatus)">{{ getReviewStatusText(item.reviewStatus) }}</text>
  16. <text class="status-tag" :class="getApplyStatusClass(item)">{{ getApplyStatusText(item) }}</text>
  17. </view>
  18. </template>
  19. <CommonInfoRow label="审查类型" :value="getDictLabel('sci_review_type', item.reviewType)" />
  20. <CommonInfoRow label="审查方式" :value="item.reviewMethod == '10' ? '简易审查' : (item.reviewMethod == '20' ? '会议审查' : '--')" />
  21. <CommonInfoRow label="承担科室" :value="item.deptName" />
  22. <CommonInfoRow label="申请人" :value="item.createdName" />
  23. <CommonInfoRow label="申请日期" :value="item.createdTime ? formatDate(item.createdTime) : '--'" noBorder />
  24. </CommonListCard>
  25. </view>
  26. </view>
  27. </template>
  28. <script setup lang="ts">
  29. import { ref, onMounted, watch } from 'vue';
  30. import { useProjectApi } from '@/api/project';
  31. import { formatDate } from '@/utils/date';
  32. import { useDict } from '@/hooks/useDict';
  33. import CommonListCard from '@/components/ui/CommonListCard.vue';
  34. import CommonInfoRow from '@/components/ui/CommonInfoRow.vue';
  35. const props = defineProps<{
  36. projectId: number;
  37. projectType: string;
  38. }>();
  39. const { getEthicalReviewList } = useProjectApi();
  40. const { getDictLabel } = useDict('sci_review_type');
  41. const loading = ref(false);
  42. const listData = ref<any[]>([]);
  43. const fetchList = async () => {
  44. if (!props.projectId) return;
  45. loading.value = true;
  46. try {
  47. const res: any = await getEthicalReviewList({
  48. projectId: props.projectId,
  49. projectType: props.projectType === 'horizontal' ? '20' : '10', // 匹配横向项目时传 20
  50. pageNum: 1,
  51. pageSize: 100
  52. });
  53. if (res && res.data && res.data.list) {
  54. listData.value = res.data.list;
  55. }
  56. } catch (error) {
  57. uni.showToast({ title: '获取伦理信息失败', icon: 'none' });
  58. } finally {
  59. loading.value = false;
  60. }
  61. };
  62. watch(() => props.projectId, (id) => {
  63. if (id) fetchList();
  64. }, { immediate: true });
  65. // 审查状态格式化
  66. const getReviewStatusText = (status: string | number) => {
  67. if (status == 10) return '待提交';
  68. if (status == 20) return '已提交';
  69. if (status == 30) return '形式审查拒绝';
  70. if (status == 40) return '已受理';
  71. if (status == 50) return '审查通过';
  72. if (status == 60) return '审查拒绝';
  73. return '未知状态';
  74. };
  75. const getReviewStatusType = (status: string | number) => {
  76. if (status == 10) return 'info';
  77. if (status == 20) return 'primary';
  78. if (status == 30) return 'error';
  79. if (status == 40) return 'warning';
  80. if (status == 50) return 'success';
  81. if (status == 60) return 'error';
  82. return 'info';
  83. };
  84. const getReviewStatusClass = (status: string | number) => {
  85. if (status == 10) return 'tag-info';
  86. if (status == 20) return 'tag-warning';
  87. if (status == 30) return 'tag-error';
  88. if (status == 40) return 'tag-primary';
  89. if (status == 50) return 'tag-success';
  90. if (status == 60) return 'tag-error';
  91. return 'tag-default';
  92. };
  93. // 审批状态格式化
  94. const getApplyStatusText = (row: any) => {
  95. if ((row.reviewStatus == '10' || row.reviewStatus == '20') && !row.reviewMethod) {
  96. if (row.applyStatus == '10') return '待提交';
  97. if (row.applyStatus == '20') return '审批中';
  98. if (row.applyStatus == '30') return '审批通过';
  99. if (row.applyStatus == '40') return '审批拒绝';
  100. } else if (row.reviewStatus >= '20' && row.reviewMethod == '10') {
  101. if (row.formStatus == '10') return '待提交';
  102. if (row.formStatus == '20') return '审批中';
  103. if (row.formStatus == '30') return '审批通过';
  104. if (row.formStatus == '40') return '审批拒绝';
  105. }
  106. return '';
  107. };
  108. const getApplyStatusClass = (row: any) => {
  109. let status = '';
  110. if ((row.reviewStatus == '10' || row.reviewStatus == '20') && !row.reviewMethod) {
  111. status = row.applyStatus;
  112. } else if (row.reviewStatus >= '20' && row.reviewMethod == '10') {
  113. status = row.formStatus;
  114. }
  115. if (status == '10') return 'tag-info';
  116. if (status == '20') return 'tag-warning';
  117. if (status == '30') return 'tag-success';
  118. if (status == '40') return 'tag-error';
  119. return 'tag-default';
  120. };
  121. </script>
  122. <style lang="scss" scoped>
  123. .module-container {
  124. min-height: 400rpx;
  125. position: relative;
  126. }
  127. .list-wrapper {
  128. display: flex;
  129. flex-direction: column;
  130. gap: 20rpx;
  131. }
  132. .tags-group {
  133. display: flex;
  134. gap: 12rpx;
  135. flex-shrink: 0;
  136. }
  137. .status-tag {
  138. font-size: 24rpx;
  139. padding: 4rpx 16rpx;
  140. border-radius: 6rpx;
  141. white-space: nowrap;
  142. &.tag-success { background-color: #f0f9eb; color: #67c23a; border: 2rpx solid #e1f3d8; }
  143. &.tag-error { background-color: #fef0f0; color: #f56c6c; border: 2rpx solid #fde2e2; }
  144. &.tag-primary { background-color: #ecf5ff; color: #409eff; border: 2rpx solid #d9ecff; }
  145. &.tag-warning { background-color: #fdf6ec; color: #e6a23c; border: 2rpx solid #faecd8; }
  146. &.tag-info { background-color: #f4f4f5; color: #909399; border: 2rpx solid #e9e9eb; }
  147. &.tag-default { background-color: #f4f4f5; color: #909399; }
  148. }
  149. </style>