evaluation-form-list-block.vue 9.9 KB

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