Просмотр исходного кода

📦 对接过会后修改分数和意见接口

快乐的梦鱼 недель назад: 3
Родитель
Сommit
148fb68d03

+ 39 - 0
src/api/collect/AssessmentContent.ts

@@ -718,6 +718,23 @@ export interface IchCheckReviewPayload {
   sendMsg?: boolean;
 }
 
+/** 过会后修改分数和意见请求体(POST /ich/check/checkReview) */
+export interface CheckReviewPayload {
+  checkId: number;
+  ichUnit?: number;
+  unitPoints?: number;
+  county?: number;
+  countyPoints?: number;
+  district?: number;
+  districtPoints?: number;
+  province?: number;
+  provincePoints?: number;
+  progress?: number;
+  rejectType?: number;
+  rejectReason?: string;
+  scan?: string;
+}
+
 /** 自查评估表审核(新)请求体(POST /ich/check/reviewOnly) */
 export interface SelfAssessmentReviewOnlyPayload {
   /** 自查表 ID */
@@ -1100,6 +1117,28 @@ export class AssessmentContentApi extends AppServerRequestModule<DataModel> {
     });
   }
 
+  /**
+   * 过会后修改分数和意见
+   * POST `/ich/check/checkReview`
+   */
+  async checkReview(payload: CheckReviewPayload) {
+    return this.post('/ich/check/checkReview', '过会后修改分数和意见', {
+      check_id: payload.checkId,
+      ich_unit: payload.ichUnit,
+      unit_points: payload.unitPoints,
+      county: payload.county,
+      county_points: payload.countyPoints,
+      district: payload.district,
+      district_points: payload.districtPoints,
+      province: payload.province,
+      province_points: payload.provincePoints,
+      progress: payload.progress,
+      reject_type: payload.rejectType,
+      reject_reason: payload.rejectReason,
+      scan: payload.scan,
+    });
+  }
+
   async downloadSelfAssessmentPdf(id: number) {
     await downloadPdfBlob('/pdf/create', id, this.config.baseUrl, `self-assessment-${id}.pdf`);
   }

+ 142 - 1
src/pages/collect/assessment/components/SelfAssessmentFormDisplay.vue

@@ -12,24 +12,165 @@
       :current-form="currentForm"
       :readonly="true"
     />
+    <template v-if="isReviewer && currentForm">
+      <a-divider />
+      <h3 class="mt-3 font-bold">盖章版存档扫描图片</h3>
+      <a-image v-if="currentForm.scan" :src="currentForm.scan" class="small-preview" alt="avatar" />
+      <a-upload
+        class="flex flex-row items-center gap-2 mt-2"
+        list-type="picture-card"
+        :show-upload-list="false"
+        :custom-request="(options: any) => handleScanUpload(options)"
+      >
+        <UploadOutlined /> 上传
+      </a-upload>
+
+      <a-button type="primary" block @click="reviewModalVisible = true">过会后编辑分数和意见</a-button>
+    </template>
   </div>
+  
+  <a-modal
+    title="过会后编辑分数和意见"
+    v-model:visible="reviewModalVisible"
+    :confirm-loading="reviewSubmitting"
+    ok-text="提交"
+    cancel-text="取消"
+    :width="700"
+    @ok="handleCheckReviewSubmit"
+  >
+    <a-table
+      :columns="reviewColumns"
+      :data-source="reviewTableData"
+      :pagination="false"
+      bordered
+      size="small"
+    >
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.dataIndex === 'opinion'">
+          <a-select
+            v-model:value="reviewForm[record.opinionField as keyof typeof reviewForm]"
+            :options="opinionOptions"
+            placeholder="请选择"
+            allow-clear
+            style="width: 130px"
+          />
+        </template>
+        <template v-else-if="column.dataIndex === 'points'">
+          <a-input-number
+            v-model:value="reviewForm[record.pointsField as keyof typeof reviewForm]"
+            :min="0"
+            :max="200"
+            placeholder="评分"
+          />
+        </template>
+      </template>
+    </a-table>
+  </a-modal>
 </template>
 
 <script setup lang="ts">
-import { computed, ref } from 'vue';
+import { ref, reactive, computed } from 'vue';
 import type { CheckItemInfo, SelfAssessmentCheckItemAnswer, SelfAssessmentDetail } from '@/api/collect/AssessmentContent';
+import AssessmentContentApi from '@/api/collect/AssessmentContent';
 import SelfAssessmentFormBlock from './SelfAssessmentFormBlock.vue';
 import SelfAssessmentResultBlock from './SelfAssessmentResultBlock.vue';
+import { UploadOutlined } from '@ant-design/icons-vue';
+import CommonContent from '@/api/CommonContent.ts';
+import { StringUtils } from '@imengyu/imengyu-utils';
+import { type UploadProps, message } from 'ant-design-vue';
+import { LEVEL_NATIONAL } from '@/api/collect/AssessmentConsts';
 
 const props = withDefaults(defineProps<{
   currentForm: SelfAssessmentDetail;
   checkItemList: CheckItemInfo[];
   currentFormCheckItems: SelfAssessmentCheckItemAnswer[];
   readonly?: boolean;
+  isReviewer?: boolean;
 }>(), {
   readonly: false,
 });
 
+
+const reviewModalVisible = ref(false);
+const reviewSubmitting = ref(false);
+
+const reviewForm = reactive({
+  ichUnit: undefined as number | undefined,
+  unitPoints: undefined as number | undefined,
+  county: undefined as number | undefined,
+  countyPoints: undefined as number | undefined,
+  district: undefined as number | undefined,
+  districtPoints: undefined as number | undefined,
+  province: undefined as number | undefined,
+  provincePoints: undefined as number | undefined,
+});
+
+const opinionOptions = [
+  { label: '优秀', value: 1 },
+  { label: '合格', value: 2 },
+  { label: '不合格', value: 3 },
+  { label: '丧失传承能力', value: 4 },
+  { label: '取消资格', value: 5 },
+];
+
+const reviewColumns = [
+  { title: '审核环节', dataIndex: 'title', width: 220 },
+  { title: '审核意见', dataIndex: 'opinion', width: 150 },
+  { title: '评分', dataIndex: 'points', width: 120 },
+];
+
+const reviewTableData = computed(() => {
+  const rows = [
+    { key: 'ichUnit', title: '项目保护单位意见', opinionField: 'ichUnit', pointsField: 'unitPoints' },
+    { key: 'county', title: '县(区)文旅部门意见', opinionField: 'county', pointsField: 'countyPoints' },
+    { key: 'district', title: '设区市文旅部门、省非遗中心意见', opinionField: 'district', pointsField: 'districtPoints' },
+  ];
+  if (props.currentForm?.level === LEVEL_NATIONAL) {
+    rows.push({ key: 'province', title: '省文化和旅游厅意见', opinionField: 'province', pointsField: 'provincePoints' });
+  }
+  return rows;
+});
+
+async function handleCheckReviewSubmit() {
+  reviewSubmitting.value = true;
+  try {
+    const res = await AssessmentContentApi.checkReview({
+      checkId: props.currentForm.id,
+      ichUnit: reviewForm.ichUnit,
+      unitPoints: reviewForm.unitPoints,
+      county: reviewForm.county,
+      countyPoints: reviewForm.countyPoints,
+      district: reviewForm.district,
+      districtPoints: reviewForm.districtPoints,
+      province: reviewForm.province,
+      provincePoints: reviewForm.provincePoints,
+      scan: props.currentForm.scan || undefined,
+    });
+    message.success('提交成功');
+    reviewModalVisible.value = false;
+  } catch (err) {
+    message.error(err instanceof Error ? err.message : String(err));
+  } finally {
+    reviewSubmitting.value = false;
+  }
+}
+
+
+async function handleScanUpload(options: Parameters<NonNullable<UploadProps['customRequest']>>[0]) {
+  const { file, onSuccess, onError } = options;
+  try {
+    const res = await CommonContent.uploadSmallFile(file as File, 'image', 'file');
+    onSuccess?.({
+      url: res.fullurl,
+      name: StringUtils.path.getFileName(res.fullurl),
+    });
+    props.currentForm!.scan = res.fullurl;
+  } catch (err) {
+    onError?.(err as Error);
+    message.error(err instanceof Error ? err.message : String(err));
+  }
+}
+
 const blockRef = ref<InstanceType<typeof SelfAssessmentFormBlock> | null>(null);
 
 defineExpose({

+ 1 - 0
src/pages/collect/assessment/evaluation-form-review.vue

@@ -30,6 +30,7 @@
               :check-item-list="(checkItemList as CheckItemInfo[])"
               :current-form-check-items="(currentFormCheckItems as SelfAssessmentCheckItemAnswer[])"
               :readonly="true"
+              :isReviewer="true"
             />
             <a-divider />
             <a-card title="审核提交" size="small" class="review-submit-card" :class="{ collapsed: reviewCardCollapsed }">

+ 3 - 138
src/pages/collect/assessment/evaluation-form.vue

@@ -35,22 +35,8 @@
               :check-item-list="(checkItemList as CheckItemInfo[])"
               :current-form-check-items="(currentFormCheckItems as SelfAssessmentCheckItemAnswer[])"
               :readonly="false"
+              :isReviewer="isReviewer"
             />
-            <template v-if="isReviewer && currentForm">
-              
-              <a-image v-if="currentForm.scan" :src="currentForm.scan" class="small-preview" alt="avatar" />
-              <a-upload
-                class="flex flex-row items-center gap-2 mt-2"
-                list-type="picture-card"
-                :show-upload-list="false"
-                :custom-request="(options: any) => handleScanUpload(options)"
-              >
-                <UploadOutlined /> 上传
-              </a-upload>
-
-              <a-divider />
-              <a-button type="primary" block :loading="submitLoading" @click="reviewModalVisible = true">过会后编辑分数和意见</a-button>
-            </template>
             <a-divider />
             <a-space direction="vertical" class="w-full" size="middle">
               <a-button type="primary" block :loading="submitLoading" @click="saveForm">保存评估表</a-button>
@@ -72,51 +58,14 @@
     >
       <iframe :src="previewUrl" class="w-full h-full" style="min-height: 60vh"></iframe>
     </a-modal>
-    <a-modal
-      title="过会后编辑分数和意见"
-      v-model:visible="reviewModalVisible"
-      :confirm-loading="reviewSubmitting"
-      ok-text="提交审核"
-      cancel-text="取消"
-      @ok="handleReviewSubmit"
-    >
-      <a-form :label-col="{ span: 6 }" :wrapper-col="{ span: 16 }">
-        <a-form-item label="审核角色" required>
-          <a-select v-model:value="reviewForm.groupId" placeholder="请选择审核角色">
-            <a-select-option v-for="opt in groupOptions" :key="opt.value" :value="Number(opt.value)">{{ opt.label }}</a-select-option>
-          </a-select>
-        </a-form-item>
-        <a-form-item label="审核操作" required>
-          <a-radio-group v-model:value="reviewForm.rejectType">
-            <a-radio :value="0">通过</a-radio>
-            <a-radio :value="rejectTypeForGroup">退回</a-radio>
-          </a-radio-group>
-        </a-form-item>
-        <a-form-item v-if="reviewForm.rejectType === 0" label="评估级别">
-          <a-select v-model:value="reviewForm.opinion" placeholder="请选择评估级别">
-            <a-select-option v-for="opt in opinionOptions" :key="opt.value" :value="opt.value">{{ opt.label }}</a-select-option>
-          </a-select>
-        </a-form-item>
-        <a-form-item v-if="reviewForm.rejectType === 0" label="评分">
-          <a-input-number v-model:value="reviewForm.points" :min="0" :max="100" class="w-full" placeholder="请输入评分" />
-        </a-form-item>
-        <a-form-item v-if="reviewForm.rejectType > 0" label="退回意见">
-          <a-textarea v-model:value="reviewForm.rejectReason" :rows="3" :maxlength="500" show-count placeholder="请输入退回意见" />
-        </a-form-item>
-        <a-form-item label="发送短信">
-          <a-switch v-model:checked="reviewSendMsg" />
-        </a-form-item>
-      </a-form>
-    </a-modal>
   </div>
 </template>
 
 <script setup lang="ts">
 import { computed, h, onMounted, ref, watch } from 'vue';
 import { useRoute, useRouter } from 'vue-router';
-import { message, Modal, type UploadProps } from 'ant-design-vue';
-import { UploadOutlined } from '@ant-design/icons-vue';
-import { StringUtils, waitTimeOut } from '@imengyu/imengyu-utils';
+import { message, Modal } from 'ant-design-vue';
+import { waitTimeOut } from '@imengyu/imengyu-utils';
 import { RequestApiError } from '@imengyu/imengyu-utils';
 import { ArrowLeftOutlined } from '@ant-design/icons-vue';
 import { useAuthStore } from '@/stores/auth';
@@ -132,9 +81,6 @@ import { injectAppConfiguration } from '@/api/system/useAppConfiguration.ts';
 import { getFormErrorFieldsMessage } from '@/common/Form.ts';
 import { LEVEL_NATIONAL, LEVEL_PROVINCE, LEVEL_DISTRICT } from '@/api/collect/AssessmentConsts.ts';
 import { useReview } from './composeables/Review.ts';
-import { GROUP_LABELS, GROUP_TO_REVIEW_PROGRESS } from './composeables/GroupData.ts';
-import CommonContent from '@/api/CommonContent.ts';
-
 
 function formatErr(e: unknown): string {
   if (e instanceof RequestApiError)
@@ -364,87 +310,6 @@ function reviewerView() {
     },
   });
 }
-
-const reviewModalVisible = ref(false);
-const reviewSubmitting = ref(false);
-const reviewSendMsg = ref(false);
-const reviewForm = ref({
-  groupId: Number(currentUserGroup.value?.id ?? 0),
-  rejectType: 0,
-  opinion: undefined as number | undefined,
-  points: undefined as number | undefined,
-  rejectReason: '',
-});
-
-const groupOptions = computed(() => {
-  return Object.entries(GROUP_LABELS)
-    .filter(([key]) => Number(key) > 0)
-    .map(([key, label]) => ({ value: key, label }));
-});
-
-const opinionOptions = [
-  { label: '优秀', value: 1 },
-  { label: '合格', value: 2 },
-  { label: '不合格', value: 3 },
-  { label: '丧失传承能力', value: 4 },
-  { label: '取消资格', value: 5 },
-];
-
-const rejectTypeForGroup = computed(() => {
-  const gid = Number(reviewForm.value.groupId);
-  return GROUP_TO_REVIEW_PROGRESS[gid]?.rejectTarget || 0;
-});
-
-async function handleScanUpload(options: Parameters<NonNullable<UploadProps['customRequest']>>[0]) {
-  const { file, onSuccess, onError } = options;
-  try {
-    const res = await CommonContent.uploadSmallFile(file as File, 'image', 'file');
-    onSuccess?.({
-      url: res.fullurl,
-      name: StringUtils.path.getFileName(res.fullurl),
-    });
-    currentForm.value!.scan = res.fullurl;
-  } catch (err) {
-    onError?.(err as Error);
-    message.error(err instanceof Error ? err.message : String(err));
-  }
-}
-async function handleReviewSubmit() {
-  const cf = currentForm.value;
-  if (!cf?.id) {
-    message.warning('请先保存评估表');
-    return;
-  }
-  if (!reviewForm.value.groupId) {
-    message.warning('请选择审核角色');
-    return;
-  }
-  reviewSubmitting.value = true;
-  try {
-    const payload: SelfAssessmentReviewOnlyPayload = {
-      checkId: cf.id,
-      groupId: reviewForm.value.groupId,
-      rejectType: reviewForm.value.rejectType,
-      rejectReason: reviewForm.value.rejectType > 0 ? reviewForm.value.rejectReason : undefined,
-      opinion: reviewForm.value.rejectType === 0 ? reviewForm.value.opinion : undefined,
-      points: reviewForm.value.rejectType === 0 ? reviewForm.value.points : undefined,
-      sendMsg: reviewSendMsg.value ? 1 : 0,
-    };
-    await AssessmentContentApi.reviewOnly(payload);
-    message.success('审核提交成功');
-    reviewModalVisible.value = false;
-    reviewForm.value = { groupId: currentUserGroup.value?.id ?? 0, rejectType: 0, opinion: undefined, points: undefined, rejectReason: '' };
-    reviewSendMsg.value = false;
-    await loader.load();
-  } catch (error) {
-    Modal.error({
-      title: '审核提交失败',
-      content: formatErr(error),
-    });
-  }
-  reviewSubmitting.value = false;
-}
-
 const loader = useSimpleDataLoader(async () => {
   if (queryId.value > 0) {
     const detail = await AssessmentContentApi.getSelfAssessmentDetail(queryId.value, queryUserId.value || undefined);