|
@@ -36,6 +36,10 @@
|
|
|
:current-form-check-items="(currentFormCheckItems as SelfAssessmentCheckItemAnswer[])"
|
|
:current-form-check-items="(currentFormCheckItems as SelfAssessmentCheckItemAnswer[])"
|
|
|
:readonly="false"
|
|
:readonly="false"
|
|
|
/>
|
|
/>
|
|
|
|
|
+ <template v-if="isReviewer">
|
|
|
|
|
+ <a-divider />
|
|
|
|
|
+ <a-button type="primary" block :loading="submitLoading" @click="reviewModalVisible = true">编辑审核意见</a-button>
|
|
|
|
|
+ </template>
|
|
|
<a-divider />
|
|
<a-divider />
|
|
|
<a-space direction="vertical" class="w-full" size="middle">
|
|
<a-space direction="vertical" class="w-full" size="middle">
|
|
|
<a-button type="primary" block :loading="submitLoading" @click="saveForm">保存评估表</a-button>
|
|
<a-button type="primary" block :loading="submitLoading" @click="saveForm">保存评估表</a-button>
|
|
@@ -57,6 +61,42 @@
|
|
|
>
|
|
>
|
|
|
<iframe :src="previewUrl" class="w-full h-full" style="min-height: 60vh"></iframe>
|
|
<iframe :src="previewUrl" class="w-full h-full" style="min-height: 60vh"></iframe>
|
|
|
</a-modal>
|
|
</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>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -72,12 +112,15 @@ import AssessmentContentApi, {
|
|
|
SelfAssessmentDetail,
|
|
SelfAssessmentDetail,
|
|
|
CheckItemInfo,
|
|
CheckItemInfo,
|
|
|
SelfAssessmentCheckItemAnswer,
|
|
SelfAssessmentCheckItemAnswer,
|
|
|
|
|
+ type SelfAssessmentReviewOnlyPayload,
|
|
|
} from '@/api/collect/AssessmentContent';
|
|
} from '@/api/collect/AssessmentContent';
|
|
|
import SelfAssessmentFormDisplay from './components/SelfAssessmentFormDisplay.vue';
|
|
import SelfAssessmentFormDisplay from './components/SelfAssessmentFormDisplay.vue';
|
|
|
import { useSimpleDataLoader } from '@/composeables/useSimpleDataLoader';
|
|
import { useSimpleDataLoader } from '@/composeables/useSimpleDataLoader';
|
|
|
import { injectAppConfiguration } from '@/api/system/useAppConfiguration.ts';
|
|
import { injectAppConfiguration } from '@/api/system/useAppConfiguration.ts';
|
|
|
import { getFormErrorFieldsMessage } from '@/common/Form.ts';
|
|
import { getFormErrorFieldsMessage } from '@/common/Form.ts';
|
|
|
import { LEVEL_NATIONAL, LEVEL_PROVINCE, LEVEL_DISTRICT } from '@/api/collect/AssessmentConsts.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';
|
|
|
|
|
|
|
|
|
|
|
|
|
function formatErr(e: unknown): string {
|
|
function formatErr(e: unknown): string {
|
|
@@ -100,6 +143,10 @@ const currentForm = ref<SelfAssessmentDetail | null>(null);
|
|
|
const currentFormCheckItems = ref([] as SelfAssessmentCheckItemAnswer[]);
|
|
const currentFormCheckItems = ref([] as SelfAssessmentCheckItemAnswer[]);
|
|
|
const checkItemList = ref([] as CheckItemInfo[]);
|
|
const checkItemList = ref([] as CheckItemInfo[]);
|
|
|
|
|
|
|
|
|
|
+const currentProgress = computed(() => currentForm.value?.progress ?? 0);
|
|
|
|
|
+const { currentUserGroup, isDistrict, isEndLevel, isProtectUnit } = useReview(currentProgress);
|
|
|
|
|
+const isReviewer = computed(() => isDistrict.value || isEndLevel.value || isProtectUnit.value);
|
|
|
|
|
+
|
|
|
const blockRef = ref<InstanceType<typeof SelfAssessmentFormDisplay> | null>(null);
|
|
const blockRef = ref<InstanceType<typeof SelfAssessmentFormDisplay> | null>(null);
|
|
|
const submitLoading = ref(false);
|
|
const submitLoading = ref(false);
|
|
|
|
|
|
|
@@ -305,6 +352,72 @@ 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 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 () => {
|
|
const loader = useSimpleDataLoader(async () => {
|
|
|
if (queryId.value > 0) {
|
|
if (queryId.value > 0) {
|
|
|
const detail = await AssessmentContentApi.getSelfAssessmentDetail(queryId.value, queryUserId.value || undefined);
|
|
const detail = await AssessmentContentApi.getSelfAssessmentDetail(queryId.value, queryUserId.value || undefined);
|