evaluation-form.vue 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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 type="primary" block :loading="submitLoading" @click="submitForm">提交审核</Button>
  58. <Button :loading="submitLoading" @click="downloadForm">下载评估表PDF</Button>
  59. </FlexCol>
  60. </template>
  61. </SimplePageContentLoader>
  62. <XBarSpace />
  63. </FlexCol>
  64. </CommonRoot>
  65. </template>
  66. <script setup lang="ts">
  67. import { computed, ref } from 'vue';
  68. import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
  69. import { useAuthStore } from '@/store/auth';
  70. import { useLoadQuerys } from '@/components/composeabe/LoadQuerys';
  71. import { assertNotNull, formatError, waitTimeOut } from '@imengyu/imengyu-utils';
  72. import { toast, alert } from '@/components/dialog/CommonRoot';
  73. import AssessmentContentApi, {
  74. SelfAssessmentDetail,
  75. CheckItemInfo,
  76. SelfAssessmentCheckItemAnswer,
  77. } from '@/api/collect/AssessmentContent';
  78. import CommonRoot from '@/components/dialog/CommonRoot.vue';
  79. import Button from '@/components/basic/Button.vue';
  80. import Result from '@/components/feedback/Result.vue';
  81. import FlexCol from '@/components/layout/FlexCol.vue';
  82. import Height from '@/components/layout/space/Height.vue';
  83. import SimplePageContentLoader from '@/components/loader/SimplePageContentLoader.vue';
  84. import FlexRow from '@/components/layout/FlexRow.vue';
  85. import Text from '@/components/basic/Text.vue';
  86. import XBarSpace from '@/components/layout/space/XBarSpace.vue';
  87. import Divider from '@/components/display/Divider.vue';
  88. import CheckBox from '@/components/form/CheckBox.vue';
  89. import Field from '@/components/form/Field.vue';
  90. import SelfAssessmentFormDisplay from './components/SelfAssessmentFormDisplay.vue';
  91. import { buildSelfAssessmentFormOptions } from './evaluationFormOptions';
  92. import { useImageSimpleUploadCo } from '@/common/components/upload/ImageUploadCo';
  93. import { injectAppConfiguration } from '@/api/system/useAppConfiguration';
  94. /** 评估表下方展示用:各级审核意见(不接数据、禁用) */
  95. const externalReviewSectionTitles = ref([
  96. { title: '1. 项目保护单位意见', suggestion: '', disabled: false },
  97. { title: '2. 县(区)文旅部门审核意见', suggestion: '', disabled: true },
  98. { title: '3. 设区市文旅部门、省非遗中心审核意见', suggestion: '', disabled: true },
  99. ]);
  100. const externalReviewScoreRow1 = ['优秀', '合格', '不合格'] as const;
  101. const externalReviewScoreRow2 = ['丧失传承能力', '取消资格'] as const;
  102. let loaded = false;
  103. const { querys } = useLoadQuerys({
  104. id: 0,
  105. userId: 0,
  106. }, () => {
  107. if (loaded)
  108. return;
  109. loaded = true;
  110. loader.load();
  111. });
  112. const currentForm = ref<SelfAssessmentDetail | null>(null);
  113. const currentFormCheckItems = ref<SelfAssessmentCheckItemAnswer[]>([]);
  114. const authStore = useAuthStore();
  115. const appConfig = injectAppConfiguration();
  116. const blockRef = ref<InstanceType<typeof SelfAssessmentFormDisplay> | null>(null);
  117. const signUploadCo = useImageSimpleUploadCo();
  118. const formOptions = buildSelfAssessmentFormOptions(signUploadCo, 'start');
  119. const formOptionsEnd = buildSelfAssessmentFormOptions(signUploadCo, 'end');
  120. const checkItemList = ref<CheckItemInfo[]>([]);
  121. const levelTitle = computed(() => {
  122. if (currentForm.value?.level === 23) return '国家级';
  123. if (currentForm.value?.level === 24) return '省级';
  124. if (currentForm.value?.level === 25) return '市级';
  125. return '国家级';
  126. });
  127. function loadEditorContent() {
  128. if (!currentForm.value)
  129. return;
  130. if (typeof currentForm.value.content !== 'object' || currentForm.value.content === null) {
  131. currentForm.value!.content = {};
  132. }
  133. currentForm.value!.content.title = `传承人填写${currentForm.value.year}年1月1日至${currentForm.value.year}年12月31日${levelTitle.value}非遗传承人义务履行和传承补助经费使用情况等,不超过1000字,如未履行职责请进行说明。参考提纲如下:`;
  134. for (let i = 0; i < 8; i++) {
  135. if (typeof currentForm.value.content[`item${i}`] !== 'string') {
  136. currentForm.value.content[`item${i}`] = '';
  137. }
  138. }
  139. }
  140. async function loadBasicInfo() {
  141. const basicInfo = await AssessmentContentApi.getInheritorBasic(authStore.userInfo?.id);
  142. assertNotNull(currentForm.value, 'currentForm is null');
  143. currentForm.value.inheritor = basicInfo.name;
  144. currentForm.value.unit = basicInfo.unit;
  145. currentForm.value.ichName = basicInfo.ichName;
  146. currentForm.value.mobile = basicInfo.mobile;
  147. currentForm.value.level = basicInfo.level;
  148. currentForm.value.idCard = basicInfo.idCard;
  149. currentForm.value.address = basicInfo.address;
  150. }
  151. async function loadCheckItems() {
  152. assertNotNull(currentForm.value, 'currentForm is null');
  153. const { top } = await AssessmentContentApi.getCheckItems(Number(currentForm.value.level));
  154. checkItemList.value = top;
  155. currentFormCheckItems.value = currentForm.value.checkItems.concat();
  156. }
  157. const submitLoading = ref(false);
  158. async function createForm() {
  159. const detail = new SelfAssessmentDetail();
  160. detail.userId = authStore.userInfo!.id;
  161. detail.year = appConfig.value?.collectFormYear || new Date().getFullYear();
  162. detail.checkItems = [];
  163. currentForm.value = detail;
  164. loadEditorContent();
  165. await loadBasicInfo();
  166. await loadCheckItems();
  167. }
  168. async function saveForm() {
  169. const detail = currentForm.value;
  170. try {
  171. await blockRef.value?.validate();
  172. } catch (error) {
  173. toast('请填写完整信息');
  174. return;
  175. }
  176. submitLoading.value = true;
  177. currentForm.value!.checkItems = currentFormCheckItems.value;
  178. try {
  179. assertNotNull(detail, 'currentForm is null');
  180. await AssessmentContentApi.saveSelfAssessment(detail as SelfAssessmentDetail);
  181. toast('保存评估表成功');
  182. await waitTimeOut(1000);
  183. await loader.reload();
  184. } catch (error) {
  185. alert({
  186. title: '保存评估表失败',
  187. content: formatError(error),
  188. });
  189. }
  190. submitLoading.value = false;
  191. }
  192. async function submitForm() {
  193. const detail = currentForm.value;
  194. try {
  195. await blockRef.value?.validate();
  196. } catch (error) {
  197. toast('请填写完整信息');
  198. return;
  199. }
  200. submitLoading.value = true;
  201. currentForm.value!.checkItems = currentFormCheckItems.value;
  202. try {
  203. assertNotNull(detail, 'currentForm is null');
  204. await AssessmentContentApi.saveSelfAssessment(detail as SelfAssessmentDetail, 1);
  205. toast('提交审核成功');
  206. await waitTimeOut(1000);
  207. await loader.reload();
  208. } catch (error) {
  209. alert({
  210. title: '提交审核失败',
  211. content: formatError(error),
  212. });
  213. }
  214. submitLoading.value = false;
  215. }
  216. async function downloadForm() {
  217. if (!currentForm.value?.id) {
  218. toast('请先保存评估表后再下载PDF');
  219. return;
  220. }
  221. try {
  222. assertNotNull(currentForm.value, 'currentForm is null');
  223. const pdfPath = await AssessmentContentApi.downloadSelfAssessmentPdf(currentForm.value.id);
  224. uni.openDocument({
  225. filePath: pdfPath,
  226. fileType: 'pdf',
  227. showMenu: true,
  228. });
  229. } catch (error) {
  230. alert({
  231. title: '下载评估表失败',
  232. content: formatError(error),
  233. });
  234. }
  235. }
  236. const loader = useSimpleDataLoader(async () => {
  237. await waitTimeOut(1000);
  238. if (querys.value.id > 0) {
  239. const detail = await AssessmentContentApi.getSelfAssessmentDetail(querys.value.id, querys.value.userId);
  240. currentForm.value = detail;
  241. loadEditorContent();
  242. await loadCheckItems();
  243. return;
  244. }
  245. const basicInfo = await AssessmentContentApi.getInheritorBasic(authStore.userInfo?.id);
  246. if (basicInfo.checkId > 0) {
  247. const detail = await AssessmentContentApi.getSelfAssessmentDetail(
  248. basicInfo.checkId,
  249. authStore.userInfo?.id
  250. );
  251. currentForm.value = detail;
  252. loadEditorContent();
  253. await loadCheckItems();
  254. } else {
  255. currentForm.value = null;
  256. }
  257. return currentForm.value;
  258. }, false);
  259. </script>