evaluation-form-list.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. <template>
  2. <a-tabs v-model:activeKey="activeKey" centered type="card">
  3. <a-tab-pane key="1" tab="传承人列表">
  4. <CommonListBlock
  5. ref="listRef"
  6. :show-total="true"
  7. :row-count="1"
  8. :row-type="5"
  9. :page-size="10"
  10. :drop-down-names="[
  11. {
  12. options: selfAssessmentProgressOptions,
  13. label: '状态',
  14. defaultSelectedValue: lastSelfAssessmentProgress,
  15. },
  16. {
  17. options: selfAssessmentLevelOptions,
  18. label: '等级',
  19. defaultSelectedValue: lastSelfAssessmentLevel,
  20. },
  21. {
  22. options: [
  23. { id: 0, name: '全部审核' },
  24. { id: 1, name: '审核通过' },
  25. { id: 2, name: '审核退回' },
  26. ],
  27. label: '审核状态',
  28. defaultSelectedValue: 0,
  29. }
  30. ]"
  31. :load="(page: number, pageSize: number, _tag: number, searchText: string, drop: number[]) => loadSelfAssessmentAdminList(page, pageSize, searchText, drop)"
  32. :show-detail="handleReviewSelfAssessment"
  33. >
  34. <template #headLeft>
  35. <a-button type="primary" @click="openDownloadModal">打包下载</a-button>
  36. </template>
  37. <template #itemRight="{ item }">
  38. <a-popover v-if="item.rejectType && item.rejectType > 0" title="退回原因" trigger="hover">
  39. <template #content>
  40. <div style="max-width: 300px">{{ item.rejectReason || '无' }}</div>
  41. </template>
  42. <span class="mr-3 text-sm" style="color: #f5222d; cursor: pointer;">
  43. <ExclamationCircleOutlined /> 已退回
  44. </span>
  45. </a-popover>
  46. <span
  47. v-else
  48. class="mr-3 text-sm text-gray-600"
  49. >
  50. {{ selfAssessmentProgressLabel(item.progress) }}
  51. </span>
  52. <a-button type="link" @click.stop="router.push({ name: 'CollectEvaluationForm', query: { id: item.checkId ?? item.id, userId: item.userId } })">编辑</a-button>
  53. <a-button
  54. type="primary"
  55. v-if="canReview(item)"
  56. @click.stop="handleReviewSelfAssessment(item)"
  57. >
  58. 审核
  59. </a-button>
  60. </template>
  61. </CommonListBlock>
  62. </a-tab-pane>
  63. <a-tab-pane key="2" tab="审核记录">
  64. <CommonListBlock
  65. ref="listRef"
  66. :show-total="true"
  67. :row-count="1"
  68. :row-type="5"
  69. :page-size="10"
  70. :drop-down-names="[
  71. {
  72. options: checkLogStatusOptions,
  73. label: '状态',
  74. defaultSelectedValue: lastCheckLogStatus,
  75. },
  76. {
  77. options: checkLogReviewTypeOptions,
  78. label: '审核环节',
  79. defaultSelectedValue: lastCheckLogReviewType,
  80. },
  81. ]"
  82. :load="(page: number, pageSize: number, _tag: number, searchText: string, drop: number[]) => loadCheckLogList(page, pageSize, searchText, drop)"
  83. :show-detail="() => {}"
  84. >
  85. <template #itemRight="{ item }">
  86. <a-tag :color="item.status === 1 ? 'green' : 'red'">{{ item.statusText || (item.status === 1 ? '通过' : '退回') }}</a-tag>
  87. <span class="mr-3 text-sm text-gray-600">{{ item.reviewTypeText }}</span>
  88. </template>
  89. </CommonListBlock>
  90. </a-tab-pane>
  91. </a-tabs>
  92. <a-modal
  93. v-model:open="showDownloadModal"
  94. title="打包下载自查表"
  95. @ok="handleDownloadZip"
  96. :confirmLoading="downloading"
  97. okText="下载"
  98. cancelText="取消"
  99. >
  100. <a-form layout="vertical">
  101. <a-form-item label="年份">
  102. <a-input-number v-model:value="downloadYear" :min="2020" :max="2030" style="width: 100%" />
  103. </a-form-item>
  104. <a-form-item label="状态">
  105. <a-select v-model:value="downloadProgress" style="width: 100%">
  106. <a-select-option v-for="opt in downloadProgressOptions" :key="opt.id" :value="opt.id">{{ opt.name }}</a-select-option>
  107. </a-select>
  108. </a-form-item>
  109. </a-form>
  110. </a-modal>
  111. </template>
  112. <script setup lang="ts">
  113. import { computed, ref } from 'vue';
  114. import { useRouter } from 'vue-router';
  115. import { message } from 'ant-design-vue';
  116. import { ExclamationCircleOutlined, InfoCircleOutlined } from '@ant-design/icons-vue';
  117. import CommonListBlock, { type DropdownCommonItem } from '@/components/content/CommonListBlock.vue';
  118. import AssessmentContentApi, { SelfAssessmentDetail } from '@/api/collect/AssessmentContent';
  119. import { useMemorizeVar } from '@/composeables/useMemorizeVar';
  120. import { useAuthStore } from '@/stores/auth';
  121. import { GROUP_TO_REVIEW_PROGRESS } from './composeables/GroupData';
  122. const router = useRouter();
  123. const activeKey = ref('1');
  124. const listRef = ref<any>(null);
  125. const showDownloadModal = ref(false);
  126. const downloading = ref(false);
  127. const downloadYear = ref(new Date().getFullYear() - 1);
  128. const downloadProgress = ref(-100);
  129. const { variable: lastSelfAssessmentProgress } = useMemorizeVar('adminSelfAssessmentProgress', -100);
  130. const { variable: lastSelfAssessmentLevel } = useMemorizeVar('adminSelfAssessmentLevel', 0);
  131. const { variable: lastCheckLogStatus } = useMemorizeVar('adminCheckLogStatus', 0);
  132. const { variable: lastCheckLogReviewType } = useMemorizeVar('adminCheckLogReviewType', 0);
  133. const selfAssessmentLevelOptions: DropdownCommonItem[] = [
  134. { id: 0, name: '全部等级' },
  135. { id: 23, name: '国家级' },
  136. { id: 24, name: '省级' },
  137. { id: 25, name: '市级' },
  138. ];
  139. const selfAssessmentProgressOptions: DropdownCommonItem[] = [
  140. { id: -100, name: '全部状态' },
  141. { id: -1, name: '未提交' },
  142. { id: 0, name: '草稿' },
  143. { id: 1, name: '已提交审核' },
  144. { id: 2, name: '项目保护单位审核完成' },
  145. { id: 3, name: '县(区)文旅部门审核完成' },
  146. { id: 4, name: '设区市文旅部门/省非遗中心审核完成' },
  147. { id: 5, name: '省文化和旅游厅审核完成' },
  148. ];
  149. const checkLogStatusOptions: DropdownCommonItem[] = [
  150. { id: 0, name: '全部状态' },
  151. { id: 1, name: '通过' },
  152. { id: 2, name: '退回' },
  153. ];
  154. const checkLogReviewTypeOptions: DropdownCommonItem[] = [
  155. { id: 0, name: '全部环节' },
  156. { id: 1, name: '自评阶段' },
  157. { id: 2, name: '项目保护单位' },
  158. { id: 3, name: '县(区)文旅部门' },
  159. { id: 4, name: '设区市文旅部门、省非遗中心' },
  160. { id: 5, name: '省文化和旅游厅' },
  161. ];
  162. const downloadProgressOptions: DropdownCommonItem[] = [
  163. { id: -100, name: '全部状态' },
  164. { id: -1, name: '未提交' },
  165. { id: 0, name: '草稿' },
  166. { id: 1, name: '已提交审核' },
  167. { id: 2, name: '项目保护单位审核完成' },
  168. { id: 3, name: '县(区)文旅部门审核完成' },
  169. { id: 4, name: '设区市文旅部门/省非遗中心审核完成' },
  170. { id: 5, name: '省文化和旅游厅审核完成' },
  171. ];
  172. const authStore = useAuthStore();
  173. const currentUserGroups = computed(() => authStore.userInfo?.adminGroup || []);
  174. function canReview(item: SelfAssessmentDetail) {
  175. const currentUserGroup = currentUserGroups.value.find((group) => GROUP_TO_REVIEW_PROGRESS[group.id]);
  176. const currentUserReviewProgress = GROUP_TO_REVIEW_PROGRESS[currentUserGroup?.id ?? 0] ?? 0;
  177. return item.checkId
  178. && item.progress != null && item.progress >= 1 && item.progress < 5 //必须已经提交
  179. && item.progress < currentUserReviewProgress; // 当前审核阶段未完成
  180. }
  181. function selfAssessmentProgressLabel(progress: number | null | undefined) {
  182. if (progress === null || progress === undefined)
  183. return '未填写';
  184. const hit = selfAssessmentProgressOptions.find((o) => o.id === progress);
  185. return hit?.name ?? `进度 ${progress}`;
  186. }
  187. async function loadSelfAssessmentAdminList(page: number, pageSize: number, searchText: string, dropDownValues: number[]) {
  188. const pv = dropDownValues?.[0];
  189. const lv = dropDownValues?.[1];
  190. const st = dropDownValues?.[2];
  191. lastSelfAssessmentProgress.value = pv ?? -100;
  192. lastSelfAssessmentLevel.value = lv ?? 0;
  193. const progress = pv != null && pv > -50 ? pv : undefined;
  194. const level = lv != null && lv > 0 ? lv : undefined;
  195. const list = await AssessmentContentApi.getInheritorList({
  196. year: new Date().getFullYear(),
  197. page,
  198. pageSize,
  199. keywords: searchText?.trim() || undefined,
  200. progress,
  201. level,
  202. logStatus: st > 0 ? st : undefined,
  203. });
  204. return {
  205. page,
  206. total: list.total,
  207. data: list.data.map((row) => ({
  208. ...row,
  209. id: row.id,
  210. userId: row.userId,
  211. title: row.title ?? '?',
  212. desc: [row.mobile, row.unit, row.ichTitle].filter(Boolean).join(' · ') || '—',
  213. })),
  214. };
  215. }
  216. async function loadCheckLogList(page: number, pageSize: number, searchText: string, dropDownValues: number[]) {
  217. const sv = dropDownValues?.[0];
  218. const rv = dropDownValues?.[1];
  219. lastCheckLogStatus.value = sv ?? 0;
  220. lastCheckLogReviewType.value = rv ?? 0;
  221. const status = sv != null && sv > 0 ? sv : undefined;
  222. const reviewType = rv != null && rv > 0 ? rv : undefined;
  223. const list = await AssessmentContentApi.getCheckLogList({
  224. year: new Date().getFullYear(),
  225. page,
  226. pageSize,
  227. keywords: searchText?.trim() || undefined,
  228. status,
  229. reviewType,
  230. });
  231. return {
  232. page,
  233. total: list.total,
  234. data: list.data.map((row) => ({
  235. ...row,
  236. id: row.id,
  237. title: row.inheritor ?? '?',
  238. desc: [
  239. row.reviewTypeText,
  240. row.statusText,
  241. row.reason,
  242. row.createtime,
  243. ].filter(Boolean).join(' · ') || '—',
  244. })),
  245. };
  246. }
  247. function handleReviewSelfAssessment(item: SelfAssessmentDetail) {
  248. const cid = item.checkId;
  249. const uid = item.userId;
  250. if (!cid || !uid) {
  251. message.warning('缺少自查表 ID 或传承人用户 ID');
  252. return;
  253. }
  254. router.push({
  255. name: 'CollectEvaluationFormReview',
  256. query: {
  257. id: String(cid),
  258. userId: String(uid),
  259. ...(item.progress != null && item.progress !== undefined ? { progress: String(item.progress) } : {}),
  260. },
  261. });
  262. }
  263. async function handleDownloadZip() {
  264. downloading.value = true;
  265. try {
  266. const progress = downloadProgress.value > -50 ? downloadProgress.value : undefined;
  267. await AssessmentContentApi.downloadCheckZip({
  268. year: downloadYear.value,
  269. progress,
  270. });
  271. showDownloadModal.value = false;
  272. message.success('下载成功');
  273. } catch (e: any) {
  274. message.error(e?.message || '下载失败');
  275. } finally {
  276. downloading.value = false;
  277. }
  278. }
  279. function openDownloadModal() {
  280. downloadProgress.value = lastSelfAssessmentProgress.value;
  281. showDownloadModal.value = true;
  282. }
  283. defineExpose({
  284. reload: () => listRef.value?.reload(),
  285. })
  286. </script>