evaluation-form.vue 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. <template>
  2. <CommonRoot>
  3. <FlexCol padding="space.lg">
  4. <SimplePageContentLoader :loader="loader">
  5. <template v-if="loader.isFinished.value">
  6. <Result
  7. v-if="!currentForm"
  8. status="info"
  9. title="您还未填写评估表"
  10. >
  11. <Height :height="30" />
  12. <Button type="primary" @click="createForm">去填写评估表</Button>
  13. </Result>
  14. <FlexCol v-else gap="gap.lg">
  15. <SelfAssessmentFormDisplay
  16. ref="blockRef"
  17. :current-form="(currentForm as SelfAssessmentDetail)"
  18. :form-options="formOptions"
  19. :form-options-end="formOptionsEnd"
  20. :check-item-list="(checkItemList as CheckItemInfo[])"
  21. :current-form-check-items="(currentFormCheckItems as SelfAssessmentCheckItemAnswer[])"
  22. :readonly="false"
  23. />
  24. <Divider />
  25. <FlexCol gap="gap.lg">
  26. <FlexCol v-for="(title, secIdx) in externalReviewSectionTitles" :key="secIdx" gap="gap.sm">
  27. <Text bold :text="title.title" />
  28. <Field v-model="title.suggestion" :disabled="title.disabled" placeholder="(待终审填写)" />
  29. <FlexRow wrap align="center" gap="gap.md">
  30. <CheckBox
  31. v-for="(label, i) in externalReviewScoreRow1"
  32. :key="`${secIdx}-r1-${i}`"
  33. disabled
  34. :model-value="false"
  35. :text="label"
  36. :check-size="28"
  37. />
  38. </FlexRow>
  39. <FlexRow wrap align="center" gap="gap.md">
  40. <CheckBox
  41. v-for="(label, i) in externalReviewScoreRow2"
  42. :key="`${secIdx}-r2-${i}`"
  43. disabled
  44. :model-value="false"
  45. :text="label"
  46. :check-size="28"
  47. />
  48. </FlexRow>
  49. <FlexCol align="flex-end">
  50. <Text color="text.second" text="填写单位(盖章)" />
  51. <Text color="text.second" text="年 月 日" />
  52. </FlexCol>
  53. </FlexCol>
  54. </FlexCol>
  55. <Divider />
  56. <Button type="primary" block :loading="submitLoading" @click="saveForm">保存评估表</Button>
  57. <Button :loading="submitLoading" @click="downloadForm">下载评估表PDF</Button>
  58. </FlexCol>
  59. </template>
  60. </SimplePageContentLoader>
  61. <XBarSpace />
  62. </FlexCol>
  63. </CommonRoot>
  64. </template>
  65. <script setup lang="ts">
  66. import { computed, ref } from 'vue';
  67. import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
  68. import { useAuthStore } from '@/store/auth';
  69. import { useLoadQuerys } from '@/components/composeabe/LoadQuerys';
  70. import { assertNotNull, formatError, waitTimeOut } from '@imengyu/imengyu-utils';
  71. import { toast, alert } from '@/components/dialog/CommonRoot';
  72. import AssessmentContentApi, {
  73. SelfAssessmentDetail,
  74. CheckItemInfo,
  75. SelfAssessmentCheckItemAnswer,
  76. } from '@/api/collect/AssessmentContent';
  77. import CommonRoot from '@/components/dialog/CommonRoot.vue';
  78. import Button from '@/components/basic/Button.vue';
  79. import Result from '@/components/feedback/Result.vue';
  80. import FlexCol from '@/components/layout/FlexCol.vue';
  81. import Height from '@/components/layout/space/Height.vue';
  82. import SimplePageContentLoader from '@/components/loader/SimplePageContentLoader.vue';
  83. import FlexRow from '@/components/layout/FlexRow.vue';
  84. import Text from '@/components/basic/Text.vue';
  85. import XBarSpace from '@/components/layout/space/XBarSpace.vue';
  86. import Divider from '@/components/display/Divider.vue';
  87. import CheckBox from '@/components/form/CheckBox.vue';
  88. import Field from '@/components/form/Field.vue';
  89. import SelfAssessmentFormDisplay from './components/SelfAssessmentFormDisplay.vue';
  90. import { buildSelfAssessmentFormOptions } from './evaluationFormOptions';
  91. import { useImageSimpleUploadCo } from '@/common/components/upload/ImageUploadCo';
  92. /** 评估表下方展示用:各级审核意见(不接数据、禁用) */
  93. const externalReviewSectionTitles = ref([
  94. { title: '1. 项目保护单位意见', suggestion: '', disabled: false },
  95. { title: '2. 县(区)文旅部门审核意见', suggestion: '', disabled: true },
  96. { title: '3. 设区市文旅部门、省非遗中心审核意见', suggestion: '', disabled: true },
  97. ]);
  98. const externalReviewScoreRow1 = ['优秀', '合格', '不合格'] as const;
  99. const externalReviewScoreRow2 = ['丧失传承能力', '取消资格'] as const;
  100. let loaded = false;
  101. const { querys } = useLoadQuerys({
  102. id: 0,
  103. userId: 0,
  104. }, () => {
  105. if (loaded)
  106. return;
  107. loaded = true;
  108. loader.load();
  109. });
  110. const currentForm = ref<SelfAssessmentDetail | null>(null);
  111. const currentFormCheckItems = ref<SelfAssessmentCheckItemAnswer[]>([]);
  112. const authStore = useAuthStore();
  113. const currentYear = new Date().getFullYear();
  114. const blockRef = ref<InstanceType<typeof SelfAssessmentFormDisplay> | null>(null);
  115. const signUploadCo = useImageSimpleUploadCo();
  116. const formOptions = buildSelfAssessmentFormOptions(signUploadCo, 'start');
  117. const formOptionsEnd = buildSelfAssessmentFormOptions(signUploadCo, 'end');
  118. const checkItemList = ref<CheckItemInfo[]>([]);
  119. const levelTitle = computed(() => {
  120. if (currentForm.value?.level === 23) return '国家级';
  121. if (currentForm.value?.level === 24) return '省级';
  122. if (currentForm.value?.level === 25) return '市级';
  123. return '国家级';
  124. });
  125. function loadEditorContent() {
  126. if (!currentForm.value)
  127. return;
  128. if (typeof currentForm.value.content !== 'object' || currentForm.value.content === null) {
  129. currentForm.value!.content = {};
  130. }
  131. currentForm.value!.content.title = `传承人填写${currentYear}年1月1日至${currentYear}年12月31日${levelTitle.value}非遗传承人义务履行和传承补助经费使用情况等,不超过1000字,如未履行职责请进行说明。参考提纲如下:`;
  132. for (let i = 0; i < 8; i++) {
  133. if (typeof currentForm.value.content[`item${i}`] !== 'string') {
  134. currentForm.value.content[`item${i}`] = '';
  135. }
  136. }
  137. }
  138. async function loadBasicInfo() {
  139. const basicInfo = await AssessmentContentApi.getInheritorBasic(authStore.userInfo?.id);
  140. assertNotNull(currentForm.value, 'currentForm is null');
  141. currentForm.value.inheritor = basicInfo.name;
  142. currentForm.value.unit = basicInfo.unit;
  143. currentForm.value.ichName = basicInfo.ichName;
  144. currentForm.value.mobile = basicInfo.mobile;
  145. currentForm.value.level = basicInfo.level;
  146. currentForm.value.idCard = basicInfo.idCard;
  147. currentForm.value.address = basicInfo.address;
  148. }
  149. async function loadCheckItems() {
  150. assertNotNull(currentForm.value, 'currentForm is null');
  151. const { top } = await AssessmentContentApi.getCheckItems(Number(currentForm.value.level));
  152. checkItemList.value = top;
  153. currentFormCheckItems.value = currentForm.value.checkItems.concat();
  154. }
  155. const submitLoading = ref(false);
  156. async function createForm() {
  157. const detail = new SelfAssessmentDetail();
  158. detail.userId = authStore.userInfo!.id;
  159. detail.year = new Date().getFullYear();
  160. detail.checkItems = [];
  161. currentForm.value = detail;
  162. loadEditorContent();
  163. await loadBasicInfo();
  164. await loadCheckItems();
  165. }
  166. async function saveForm() {
  167. const detail = currentForm.value;
  168. try {
  169. await blockRef.value?.validate();
  170. } catch (error) {
  171. toast('请填写完整信息');
  172. return;
  173. }
  174. submitLoading.value = true;
  175. currentForm.value!.checkItems = currentFormCheckItems.value;
  176. try {
  177. assertNotNull(detail, 'currentForm is null');
  178. await AssessmentContentApi.saveSelfAssessment(detail as SelfAssessmentDetail);
  179. toast('保存评估表成功');
  180. await waitTimeOut(1000);
  181. await loader.reload();
  182. } catch (error) {
  183. alert({
  184. title: '保存评估表失败',
  185. content: formatError(error),
  186. });
  187. }
  188. submitLoading.value = false;
  189. }
  190. async function downloadForm() {
  191. if (!currentForm.value?.id) {
  192. toast('请先保存评估表后再下载PDF');
  193. return;
  194. }
  195. try {
  196. assertNotNull(currentForm.value, 'currentForm is null');
  197. const pdfPath = await AssessmentContentApi.downloadSelfAssessmentPdf(currentForm.value.id);
  198. uni.openDocument({
  199. filePath: pdfPath,
  200. fileType: 'pdf',
  201. showMenu: true,
  202. });
  203. } catch (error) {
  204. alert({
  205. title: '下载评估表失败',
  206. content: formatError(error),
  207. });
  208. }
  209. }
  210. const loader = useSimpleDataLoader(async () => {
  211. await waitTimeOut(1000);
  212. if (querys.value.id > 0) {
  213. const detail = await AssessmentContentApi.getSelfAssessmentDetail(querys.value.id, querys.value.userId);
  214. currentForm.value = detail;
  215. loadEditorContent();
  216. await loadCheckItems();
  217. return;
  218. }
  219. const basicInfo = await AssessmentContentApi.getInheritorBasic(authStore.userInfo?.id);
  220. if (basicInfo.checkId > 0) {
  221. const detail = await AssessmentContentApi.getSelfAssessmentDetail(
  222. basicInfo.checkId,
  223. authStore.userInfo?.id
  224. );
  225. currentForm.value = detail;
  226. loadEditorContent();
  227. await loadCheckItems();
  228. } else {
  229. currentForm.value = null;
  230. }
  231. return currentForm.value;
  232. }, false);
  233. </script>