SpecialActivityForm.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <template>
  2. <view class="document-form">
  3. <uv-loading-icon v-if="loading" mode="circle" text="正在加载活动详情..."></uv-loading-icon>
  4. <template v-else-if="form">
  5. <!-- 基本信息 -->
  6. <CommonSection title="基本信息" :isFirst="true">
  7. <CommonInfoRow label="活动名称" :value="form.activityName" />
  8. <CommonInfoRow label="申请人" :value="form.applicantBy" />
  9. <CommonInfoRow label="所属部门" :value="deptName" />
  10. <CommonInfoRow label="所属年度" :value="form.belongYear" />
  11. <CommonInfoRow label="活动类型" :value="activityTypeLabel" />
  12. <CommonInfoRow label="活动地点" :value="form.activityPlace" />
  13. <CommonInfoRow label="展览类别" :value="exhibitionCategoryLabel" />
  14. <CommonInfoRow label="开始日期" :value="formatDate(form.activityStartTime)" />
  15. <CommonInfoRow label="结束日期" :value="formatDate(form.activityEndTime)" />
  16. <CommonInfoRow label="活动规模" :value="form.activityScale" />
  17. <CommonInfoRow label="产出成果" :value="form.outputAchievement" />
  18. <CommonInfoRow label="所属平台" :value="platformNames" />
  19. <CommonInfoRow label="备注" :value="form.remark" isColumn />
  20. </CommonSection>
  21. <!-- 审核信息 -->
  22. <CommonSection title="审核信息" v-if="showAuditOpinion">
  23. <CommonInfoRow label="审核意见" :value="form.auditOpinion" isColumn />
  24. </CommonSection>
  25. <!-- 佐证材料 -->
  26. <AttachmentList :list="mergedFileList" title="佐证材料" />
  27. </template>
  28. <uv-empty v-else mode="data" text="暂无数据"></uv-empty>
  29. </view>
  30. </template>
  31. <script setup lang="ts">
  32. import { ref, onMounted, computed } from 'vue';
  33. import { useAchievementApi } from '@/api/achievement/index';
  34. import { useDeptApi } from '@/api/system/index';
  35. import { formatDate } from '@/utils/date';
  36. import to from 'await-to-js';
  37. import AttachmentList from './AttachmentList.vue';
  38. import CommonSection from '@/components/ui/CommonSection.vue';
  39. import CommonInfoRow from '@/components/ui/CommonInfoRow.vue';
  40. const props = defineProps<{
  41. code: string | number; // 接收 ID
  42. }>();
  43. const achievementApi = useAchievementApi();
  44. const deptApi = useDeptApi();
  45. const form = ref<any>(null);
  46. const loading = ref(false);
  47. const unitList = ref<any[]>([]);
  48. const activityTypeDict = ref<any[]>([]);
  49. const exhibitionCategoryDict = ref<any[]>([]);
  50. const deptName = computed(() => {
  51. if (!form.value?.belongDeptId) return '-';
  52. const findNode = (nodes: any[]): string | null => {
  53. for (const node of nodes) {
  54. if (node.id === form.value.belongDeptId) return node.deptName;
  55. if (node.children?.length) {
  56. const name = findNode(node.children);
  57. if (name) return name;
  58. }
  59. }
  60. return null;
  61. };
  62. return findNode(unitList.value) || form.value.deptName || '-';
  63. });
  64. const activityTypeLabel = computed(() => {
  65. const item = activityTypeDict.value.find(d => d.dictValue === form.value?.activityType);
  66. return item ? item.dictLabel : (form.value?.activityType || '-');
  67. });
  68. const exhibitionCategoryLabel = computed(() => {
  69. const item = exhibitionCategoryDict.value.find(d => d.dictValue === form.value?.exhibitionCategory);
  70. return item ? item.dictLabel : (form.value?.exhibitionCategory || '-');
  71. });
  72. const platformNames = computed(() => {
  73. return form.value?.platformInfo?.map((item: any) => item.platformName).join('、') || '-';
  74. });
  75. const showAuditOpinion = computed(() => {
  76. if (!form.value) return false;
  77. // 参考 PC 逻辑: 驳回(1) 或 审核通过(3) 时展示
  78. return form.value.auditOpinion && (form.value.auditStatus === 1 || form.value.auditStatus === 3);
  79. });
  80. const mergedFileList = computed(() => {
  81. if (!form.value?.evidenceMaterials) return [];
  82. let rawFiles: string[] = [];
  83. try {
  84. rawFiles = typeof form.value.evidenceMaterials === 'string'
  85. ? JSON.parse(form.value.evidenceMaterials)
  86. : form.value.evidenceMaterials;
  87. if (!Array.isArray(rawFiles)) rawFiles = [rawFiles];
  88. } catch (e) {
  89. return [];
  90. }
  91. return rawFiles.map(fileData => {
  92. if (!fileData) return null;
  93. const name = fileData.split('/').pop() || '文件';
  94. const startIndex = fileData.indexOf('/');
  95. const url = import.meta.env.VITE_SCIENTIFIC_FILE_URL + fileData.slice(startIndex + 1);
  96. return { name, url };
  97. }).filter(Boolean);
  98. });
  99. const fetchData = async () => {
  100. if (!props.code) return;
  101. loading.value = true;
  102. // 并行获取详情、部门树、字典
  103. const [
  104. [err, res],
  105. [deptErr, deptRes],
  106. [typeDictErr, typeDictRes],
  107. [categoryDictErr, categoryDictRes]
  108. ] = await Promise.all([
  109. to(achievementApi.getSpecialActivityDetail(props.code)),
  110. to(deptApi.getDeptTree()),
  111. to(achievementApi.getDictData('cxy_research_special_activity_type')),
  112. to(achievementApi.getDictData('cxy_research_special_exhibition_category'))
  113. ]);
  114. if (!err && res?.data) {
  115. form.value = res.data;
  116. }
  117. if (!deptErr && deptRes?.data) {
  118. unitList.value = deptRes.data || [];
  119. }
  120. if (!typeDictErr && typeDictRes?.data) {
  121. activityTypeDict.value = Array.isArray(typeDictRes.data) ? typeDictRes.data : [];
  122. }
  123. if (!categoryDictErr && categoryDictRes?.data) {
  124. exhibitionCategoryDict.value = Array.isArray(categoryDictRes.data) ? categoryDictRes.data : [];
  125. }
  126. loading.value = false;
  127. };
  128. onMounted(() => {
  129. fetchData();
  130. });
  131. </script>
  132. <style lang="scss" scoped>
  133. @import "./common.scss";
  134. </style>