ソースを参照

🎨 按要求增加保护单位签名

快乐的梦鱼 1 週間 前
コミット
69caa925e8

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

@@ -589,6 +589,7 @@ export class AgreementDetail extends DataModel<AgreementDetail> {
   ich = '' as string|null;
   partyASign = '' as string|null;
   partyBSign = '' as string|null;
+  unitSign = '' as string|null;
   updatetime = new Date();
 }
 

+ 3 - 1
src/pages/collect/assessment/argeement-sign-review.vue

@@ -28,6 +28,8 @@
             <AgreementFormDisplay
               ref="agreementFormRef"
               :currentAgreement="(currentAgreement as AgreementDetail)"
+              :isProtectUnit="isProtectUnit"
+              :isEndLevel="isEndLevel"
               isReviewer
             />
 
@@ -139,7 +141,7 @@ const rejectLoading = ref(false);
 const rejectReason = ref<string | null>(null);
 
 const currentProgress = computed(() => currentAgreement.value?.progress ?? 0);
-const { reviewProgressInfo, canSubmitReview, reviewLevelLabel, progressHint } = useReview(currentProgress);
+const { reviewProgressInfo, canSubmitReview, reviewLevelLabel, progressHint, isEndLevel, isProtectUnit } = useReview(currentProgress);
 
 const loader = useSimpleDataLoader(async () => {
   const id = queryFormId.value;

+ 41 - 18
src/pages/collect/assessment/components/AgreementFormDisplay.vue

@@ -46,6 +46,15 @@
         <a-form-item label="甲方电话" name="partyAMobile">
           <a-input v-model:value="currentAgreement.partyAMobile" :placeholder="isReviewer ? '请填写联系电话' : '待审核人员填写'" :disabled="!isReviewer" />
         </a-form-item>
+        <a-form-item label="保护单位签名" name="unitSign">
+          <Sign 
+            v-if="isReviewer || currentAgreement.unitSign" :model-value="currentAgreement.unitSign ?? ''" 
+            :disabled="!isReviewer"
+            :uploadCo="signUploadCo"
+            @update:model-value="(v) => { currentAgreement.unitSign = v; validate() }" 
+          />
+          <span v-else>待审核人员签名</span>
+        </a-form-item>
 
         <a-divider />
 
@@ -96,8 +105,12 @@ import type { Rules } from 'async-validator';
 const props = withDefaults(defineProps<{
   currentAgreement: AgreementDetail;
   isReviewer?: boolean;
+  isProtectUnit?: boolean;
+  isEndLevel?: boolean;
 }>(), {
   isReviewer: false,
+  isProtectUnit: false,
+  isEndLevel: false,
 });
 
 const agreementYear = computed(() => props.currentAgreement?.year ?? 2027);
@@ -119,22 +132,42 @@ const signUploadCo = useImageSimpleUploadCo();
 
 const formRules = computed<Rules>(() => {
   const rules: Rules = {
-    /* partyA: [
-      { required: props.isReviewer, message: '请填写甲方负责人(代表人)姓名' }
-    ], */
-    partyB: [
-      { required: true, message: '请填写乙方(传承人)姓名' }
+    partyA: [
+      { required: props.isReviewer && props.isEndLevel, message: '请填写甲方负责人(代表人)姓名' }
     ],
-    /* partyAMobile: [
+    partyAMobile: [
       {
-        required: props.isReviewer,
+        required: props.isReviewer && props.isEndLevel,
         asyncValidator: async (_rule, value) => {
           const s = value != null ? String(value).trim() : '';
           if (props.isReviewer && !CN_PHONE_RE.test(s))
             throw new Error('请输入正确的手机号或座机号');
         },
       },
-    ], */
+    ], 
+    partyASign: [
+      {
+        required: props.isReviewer && props.isEndLevel,
+        asyncValidator: async (_rule, value) => {
+          const s = typeof value === 'string' ? value.trim() : '';
+          if (!s && props.isReviewer)
+            throw new Error('请完成甲方签名');
+        },
+      },
+    ],
+    unitSign: [
+      {
+        required: props.isReviewer && props.isProtectUnit,
+        asyncValidator: async (_rule, value) => {
+          const s = typeof value === 'string' ? value.trim() : '';
+          if (!s && props.isReviewer)
+            throw new Error('请完成保护单位签名');
+        },
+      },
+    ],
+    partyB: [
+      { required: true, message: '请填写乙方(传承人)姓名' }
+    ],
     apprentice: [
       { required: true, message: '请填写本年度带徒人数' },
       { type: 'integer', min: 0, message: '须为不小于 0 的整数' },
@@ -143,16 +176,6 @@ const formRules = computed<Rules>(() => {
       { required: true, message: '请填写本年度宣传活动场次' },
       { type: 'integer', min: 0, message: '须为不小于 0 的整数' },
     ],
-    /* partyASign: [
-      {
-        required: props.isReviewer,
-        asyncValidator: async (_rule, value) => {
-          const s = typeof value === 'string' ? value.trim() : '';
-          if (!s && props.isReviewer)
-            throw new Error('请完成甲方签名');
-        },
-      },
-    ], */
     partyBSign: [
       {
         asyncValidator: async (_rule, value) => {

+ 16 - 8
src/pages/collect/assessment/composeables/GroupData.ts

@@ -1,3 +1,9 @@
+
+export const GROUP_PROVINCE = 11;
+export const GROUP_DISTRICT_CENTER = 10;
+export const GROUP_DISTRICT = 5;
+export const GROUP_PROTECT_UNIT = 9;
+
 /** 
  * 用户组 → 本环节提交后的 progress 
  * 
@@ -18,23 +24,24 @@
   5=省文化和旅游厅退回
  * 
 */
+
 export const GROUP_TO_REVIEW_PROGRESS = {
-  9: {
+  [GROUP_PROTECT_UNIT]: {
     target: 2,
     rejectTarget: 2,
     minSource: 1
   }, // 项目保护单位
-  5: {
+  [GROUP_DISTRICT]: {
     target: 3,
     rejectTarget: 3,
     minSource: 2
   }, // 县(区)文旅部门
-  10: {
+  [GROUP_DISTRICT_CENTER]: {
     target: 4, 
     rejectTarget: 4,
     minSource: 3,
   },// 设区市文旅部门、省非遗中心
-  11: {
+  [GROUP_PROVINCE]: {
     target: 5, 
     rejectTarget: 5,
     minSource: 4,
@@ -56,12 +63,13 @@ export const GROUP_TO_REVIEW_PROGRESS = {
 
 export const SUBMITED_PROGRESS = 1;
 
+
 export const GROUP_LABELS: Record<number, string> = {
   0: '无权限',
-  9: '项目保护单位',
-  5: '县(区)文旅部门',
-  10: '设区市文旅部门、省非遗中心',
-  11: '省文化和旅游厅',
+  [GROUP_PROTECT_UNIT]: '项目保护单位',
+  [GROUP_DISTRICT]: '县(区)文旅部门',
+  [GROUP_DISTRICT_CENTER]: '设区市文旅部门、省非遗中心',
+  [GROUP_PROVINCE]: '省文化和旅游厅',
 };
 export const PROGRESS_SUBMIT_LABELS: Record<number, string> = {
   2: '2 — 项目保护单位审核完成',

+ 29 - 1
src/pages/collect/assessment/composeables/Review.ts

@@ -1,5 +1,5 @@
 import { computed, type ComputedRef } from "vue";
-import { GROUP_LABELS, GROUP_TO_REVIEW_PROGRESS, SUBMITED_PROGRESS } from "./GroupData";
+import { GROUP_LABELS, GROUP_PROTECT_UNIT, GROUP_TO_REVIEW_PROGRESS, SUBMITED_PROGRESS, GROUP_PROVINCE, GROUP_DISTRICT_CENTER, GROUP_DISTRICT } from "./GroupData";
 import { useAuthStore } from "@/stores/auth";
 
 export function useReview(sourceProgress?: ComputedRef<number>) {
@@ -14,6 +14,22 @@ export function useReview(sourceProgress?: ComputedRef<number>) {
     return GROUP_TO_REVIEW_PROGRESS[currentUserGroup.value?.id ?? 0];
   });
 
+  /**
+   * 是否是最终级别
+   */
+  const isEndLevel = computed(() => {
+    return currentUserGroup.value?.id === GROUP_PROVINCE;
+  });
+  /**
+   * 是否是项目保护单位
+   */
+  const isProtectUnit = computed(() => {
+    return currentUserGroup.value?.id === GROUP_PROTECT_UNIT;
+  });
+
+  /**
+   * 是否可以提交审核
+   */
   const canSubmitReview = computed(() => {
     const info = reviewProgressInfo.value;
     if (!info || !sourceProgress)
@@ -22,6 +38,11 @@ export function useReview(sourceProgress?: ComputedRef<number>) {
       && sourceProgress.value < info.target;// 当前审核阶段未完成
   });
 
+  /**
+   * 是否可以审核
+   * @param sourceProgress 
+   * @returns 
+   */
   const canReview = (sourceProgress: number) => {
     const info = reviewProgressInfo.value;
     if (!info)
@@ -30,6 +51,11 @@ export function useReview(sourceProgress?: ComputedRef<number>) {
       && sourceProgress < info.target;// 当前审核阶段未完成
   };
 
+  /**
+   * 是否可以审核,但上一阶段未完成
+   * @param sourceProgress 
+   * @returns 
+   */
   const canReviewButPrevNotCompleted = (sourceProgress: number) => {
     const info = reviewProgressInfo.value;
     if (!info)
@@ -54,5 +80,7 @@ export function useReview(sourceProgress?: ComputedRef<number>) {
     canSubmitReview,
     reviewLevelLabel,
     progressHint,
+    isEndLevel,
+    isProtectUnit,
   };
 }