|
|
@@ -1,101 +1,30 @@
|
|
|
<template>
|
|
|
<a-tabs v-model:activeKey="activeKey" centered type="card">
|
|
|
<a-tab-pane key="1" tab="传承人列表">
|
|
|
- <div class="mb-4 p-4 bg-gray-50 rounded border border-gray-200 flex flex-row flex-wrap">
|
|
|
- <div class="w-full lg:w-1/2 flex flex-row flex-wrap">
|
|
|
- <div v-for="s in checkProgressStats" :key="s.key" class="flex-1 flex flex-col p-2 items-center" :style="{width: checkProgressStatsSpan + '%'}">
|
|
|
- <span class="text-2xl bold">{{ s.count }}</span>
|
|
|
- <span class="text-xs text-secondary text-align-center max-h-12 overflow-hidden text-ellipsis">{{ s.label }}</span>
|
|
|
- </div>
|
|
|
- <div class="p-2" :style="{width: checkProgressStatsSpan + '%'}">
|
|
|
- <v-chart :option="checkPieChartOption" autoresize />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="w-full lg:w-1/2 flex flex-row flex-wrap border-l border-gray-200">
|
|
|
- <div v-for="s in checkRejectStats" :key="s.key" class="flex-1 flex flex-col p-2 items-center" :style="{width: checkRejectStatsSpan + '%'}">
|
|
|
- <span class="text-2xl bold">{{ s.count }}</span>
|
|
|
- <span class="text-xs text-secondary text-align-center max-h-12 overflow-hidden text-ellipsi">{{ s.label }}</span>
|
|
|
- </div>
|
|
|
- <div class="p-2" :style="{width: checkRejectStatsSpan + '%'}">
|
|
|
- <v-chart :option="checkBarChartOption" autoresize />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <CommonListBlock
|
|
|
- ref="listRef"
|
|
|
- :show-total="true"
|
|
|
- :row-count="1"
|
|
|
- :row-type="5"
|
|
|
- :page-size="10"
|
|
|
- :drop-down-names="[
|
|
|
- {
|
|
|
- options: selfAssessmentProgressOptions,
|
|
|
- label: '状态',
|
|
|
- defaultSelectedValue: lastSelfAssessmentProgress,
|
|
|
- },
|
|
|
- {
|
|
|
- options: selfAssessmentLevelOptions,
|
|
|
- label: '等级',
|
|
|
- defaultSelectedValue: lastSelfAssessmentLevel,
|
|
|
- },
|
|
|
- {
|
|
|
- options: [
|
|
|
- { id: 0, name: '全部审核' },
|
|
|
- { id: 1, name: '审核通过' },
|
|
|
- { id: 2, name: '审核退回' },
|
|
|
- ],
|
|
|
- label: '审核状态',
|
|
|
- defaultSelectedValue: 0,
|
|
|
- }
|
|
|
- ]"
|
|
|
- :load="(page: number, pageSize: number, _tag: number, searchText: string, drop: number[]) => loadSelfAssessmentAdminList(page, pageSize, searchText, drop)"
|
|
|
- :show-detail="handleReviewSelfAssessment"
|
|
|
- >
|
|
|
- <template #headLeft>
|
|
|
- <div class="flex flex-row items-center gap-2">
|
|
|
- <a-button type="primary" @click="openDownloadModal">打包下载</a-button>
|
|
|
- <a-button @click="openExportExcelModal">导出Excel</a-button>
|
|
|
- <span>{{ progressHint }}</span>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- <template #itemRight="{ item }">
|
|
|
- <a-popover v-if="item.rejectType && item.rejectType > 0" title="退回原因" trigger="hover">
|
|
|
- <template #content>
|
|
|
- <div style="max-width: 300px">{{ item.rejectReason || '无' }}</div>
|
|
|
- </template>
|
|
|
- <span class="mr-3 text-sm" style="color: #f5222d; cursor: pointer;">
|
|
|
- <ExclamationCircleOutlined /> 已退回
|
|
|
- </span>
|
|
|
- </a-popover>
|
|
|
- <span
|
|
|
- v-else
|
|
|
- class="mr-3 text-sm text-gray-600"
|
|
|
- >
|
|
|
- {{ selfAssessmentProgressLabel(item.progress) }}
|
|
|
- </span>
|
|
|
- <a-button type="link" @click.stop="router.push({ name: 'CollectEvaluationForm', query: { id: item.checkId ?? item.id, userId: item.userId } })">编辑</a-button>
|
|
|
-
|
|
|
- <div v-if="item.checkId && canReviewButPrevNotCompleted(item.progress)" class="flex flex-row items-center mr-3 text-sm">
|
|
|
- <ExclamationCircleOutlined /> 上一阶段未审核完成
|
|
|
- </div>
|
|
|
- <a-button
|
|
|
- type="primary"
|
|
|
- v-else-if="item.checkId && canReview(item.progress)"
|
|
|
- @click.stop="handleReviewSelfAssessment(item)"
|
|
|
- >
|
|
|
- 审核
|
|
|
- </a-button>
|
|
|
- <a-button
|
|
|
- type="primary"
|
|
|
- v-else-if="item.agreementId && isCurrentLevelReviewed(item.progress)"
|
|
|
- disabled
|
|
|
- >
|
|
|
- 已审核
|
|
|
- </a-button>
|
|
|
- </template>
|
|
|
- </CommonListBlock>
|
|
|
+ <template v-if="activeKey==='1'">
|
|
|
+ <EvaluationFormListSummary @changeProgressFilter="subListRef?.changeProgressFilter" />
|
|
|
+ <EvaluationFormListBlock ref="subListRef" />
|
|
|
+ </template>
|
|
|
</a-tab-pane>
|
|
|
- <a-tab-pane key="2" tab="审核记录">
|
|
|
+ <a-tab-pane key="2" tab="国家级传承人">
|
|
|
+ <template v-if="activeKey==='2'">
|
|
|
+ <EvaluationFormListSummary :level="LEVEL_NATIONAL" @changeProgressFilter="subListRef?.changeProgressFilter" />
|
|
|
+ <EvaluationFormListBlock ref="subListRef" :level="LEVEL_NATIONAL" />
|
|
|
+ </template>
|
|
|
+ </a-tab-pane>
|
|
|
+ <a-tab-pane key="3" tab="省级传承人">
|
|
|
+ <template v-if="activeKey==='3'">
|
|
|
+ <EvaluationFormListSummary :level="LEVEL_PROVINCE" @changeProgressFilter="subListRef?.changeProgressFilter" />
|
|
|
+ <EvaluationFormListBlock ref="subListRef" :level="LEVEL_PROVINCE" />
|
|
|
+ </template>
|
|
|
+ </a-tab-pane>
|
|
|
+ <a-tab-pane key="4" tab="市级传承人">
|
|
|
+ <template v-if="activeKey==='4'">
|
|
|
+ <EvaluationFormListSummary :level="LEVEL_DISTRICT" @changeProgressFilter="subListRef?.changeProgressFilter" />
|
|
|
+ <EvaluationFormListBlock ref="subListRef" :level="LEVEL_DISTRICT" />
|
|
|
+ </template>
|
|
|
+ </a-tab-pane>
|
|
|
+ <a-tab-pane key="10" tab="审核记录">
|
|
|
<CommonListBlock
|
|
|
ref="listRef"
|
|
|
:show-total="true"
|
|
|
@@ -124,187 +53,28 @@
|
|
|
</CommonListBlock>
|
|
|
</a-tab-pane>
|
|
|
</a-tabs>
|
|
|
-
|
|
|
- <a-modal
|
|
|
- v-model:open="showDownloadModal"
|
|
|
- title="打包下载自查表"
|
|
|
- @ok="handleDownloadZip"
|
|
|
- :confirmLoading="downloading"
|
|
|
- okText="下载"
|
|
|
- cancelText="取消"
|
|
|
- >
|
|
|
- <a-form layout="vertical">
|
|
|
- <a-form-item label="年份">
|
|
|
- <a-input-number v-model:value="downloadYear" :min="2020" :max="2030" style="width: 100%" />
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="状态">
|
|
|
- <a-select v-model:value="downloadProgress" style="width: 100%">
|
|
|
- <a-select-option v-for="opt in downloadProgressOptions" :key="opt.id" :value="opt.id">{{ opt.name }}</a-select-option>
|
|
|
- </a-select>
|
|
|
- </a-form-item>
|
|
|
- </a-form>
|
|
|
- </a-modal>
|
|
|
-
|
|
|
- <a-modal
|
|
|
- v-model:open="showExportExcelModal"
|
|
|
- title="导出自查表汇总Excel"
|
|
|
- @ok="handleExportExcel"
|
|
|
- :confirmLoading="exporting"
|
|
|
- okText="导出"
|
|
|
- cancelText="取消"
|
|
|
- >
|
|
|
- <a-form layout="vertical">
|
|
|
- <a-form-item label="年份">
|
|
|
- <a-input-number v-model:value="exportYear" :min="2020" :max="2030" style="width: 100%" />
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="等级">
|
|
|
- <a-select v-model:value="exportLevel" style="width: 100%">
|
|
|
- <a-select-option v-for="opt in selfAssessmentLevelOptions" :key="opt.id" :value="opt.id">{{ opt.name }}</a-select-option>
|
|
|
- </a-select>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="状态">
|
|
|
- <a-select v-model:value="exportProgress" style="width: 100%">
|
|
|
- <a-select-option v-for="opt in downloadProgressOptions" :key="opt.id" :value="opt.id">{{ opt.name }}</a-select-option>
|
|
|
- </a-select>
|
|
|
- </a-form-item>
|
|
|
- </a-form>
|
|
|
- </a-modal>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { computed, onMounted, ref, watch } from 'vue';
|
|
|
-import { useRoute, useRouter } from 'vue-router';
|
|
|
+import { ref, watch, type Ref } from 'vue';
|
|
|
+import { useRoute } from 'vue-router';
|
|
|
import { useMemorizeVar } from '@/composeables/useMemorizeVar';
|
|
|
-import { useReview } from './composeables/Review';
|
|
|
-import { message } from 'ant-design-vue';
|
|
|
-import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
|
|
-import { use } from "echarts/core";
|
|
|
-import { CanvasRenderer } from "echarts/renderers";
|
|
|
-import { PieChart, BarChart } from "echarts/charts";
|
|
|
-import {
|
|
|
- TooltipComponent,
|
|
|
- GridComponent,
|
|
|
-} from "echarts/components";
|
|
|
-use([CanvasRenderer, PieChart, BarChart, TooltipComponent, GridComponent]);
|
|
|
-import VChart from "vue-echarts";
|
|
|
import CommonListBlock, { type DropdownCommonItem } from '@/components/content/CommonListBlock.vue';
|
|
|
-import AssessmentContentApi, { SelfAssessmentDetail } from '@/api/collect/AssessmentContent';
|
|
|
+import AssessmentContentApi from '@/api/collect/AssessmentContent';
|
|
|
+import EvaluationFormListSummary from './evaluation-form-list-summary.vue';
|
|
|
+import EvaluationFormListBlock from './evaluation-form-list-block.vue';
|
|
|
+import { LEVEL_NATIONAL, LEVEL_PROVINCE, LEVEL_DISTRICT } from '@/api/collect/AssessmentConsts.ts';
|
|
|
|
|
|
-const router = useRouter();
|
|
|
const route = useRoute();
|
|
|
|
|
|
const activeKey = ref('1');
|
|
|
-const listRef = ref<any>(null);
|
|
|
-
|
|
|
-const showDownloadModal = ref(false);
|
|
|
-const downloading = ref(false);
|
|
|
-const downloadYear = ref(new Date().getFullYear() - 1);
|
|
|
-const downloadProgress = ref(-100);
|
|
|
-
|
|
|
-const showExportExcelModal = ref(false);
|
|
|
-const exporting = ref(false);
|
|
|
-const exportYear = ref(new Date().getFullYear() - 1);
|
|
|
-const exportLevel = ref(0);
|
|
|
-const exportProgress = ref(-100);
|
|
|
-
|
|
|
-const dataStats = ref<Awaited<ReturnType<typeof AssessmentContentApi.getDataCount>>|null>(null);
|
|
|
-
|
|
|
-const checkProgressLabels: Record<string, string> = {
|
|
|
- '-1': '未提交',
|
|
|
- '0': '草稿',
|
|
|
- '1': '已提交审核',
|
|
|
- '2': '单位审核完成',
|
|
|
- '3': '县级审核完成',
|
|
|
- '4': '市级审核完成',
|
|
|
- '5': '省级审核完成',
|
|
|
-};
|
|
|
-
|
|
|
-const checkRejectLabels: Record<string, string> = {
|
|
|
- '1': '自评阶段退回',
|
|
|
- '2': '项目保护单位退回',
|
|
|
- '3': '县(区)退回',
|
|
|
- '4': '设区市/省非遗中心退回',
|
|
|
- '5': '省文旅厅退回',
|
|
|
-};
|
|
|
-
|
|
|
-const checkProgressStats = computed(() => {
|
|
|
- if (!dataStats.value?.check) return [];
|
|
|
- return dataStats.value.check.map((d) => ({ key: d.key, label: d.title, count: d.value, isReject: false }));
|
|
|
-});
|
|
|
-const checkProgressStatsSpan = computed(() => {
|
|
|
- const len = checkProgressStats.value.length;
|
|
|
- return len > 1 ? 100 / (len - 1) : 100;
|
|
|
-});
|
|
|
-const checkRejectStats = computed(() => {
|
|
|
- if (!dataStats.value?.checkReject) return [];
|
|
|
- return dataStats.value.checkReject.map((d) => ({ key: 'r' + d.key, label: d.title, count: d.value, isReject: true }));
|
|
|
-});
|
|
|
-const checkRejectStatsSpan = computed(() => {
|
|
|
- const len = checkRejectStats.value.length;
|
|
|
- return len > 1 ? 100 / (len - 1) : 100;
|
|
|
-});
|
|
|
-
|
|
|
-const checkPieChartOption = computed(() => {
|
|
|
- const data = (dataStats.value?.check || []).map((s: any) => ({ name: s.title, value: s.value }));
|
|
|
- return {
|
|
|
- tooltip: { trigger: 'item' },
|
|
|
- series: [{
|
|
|
- type: 'pie',
|
|
|
- radius: ['40%', '70%'],
|
|
|
- center: ['50%', '50%'],
|
|
|
- data,
|
|
|
- label: { show: false },
|
|
|
- emphasis: { label: { show: true } },
|
|
|
- }],
|
|
|
- };
|
|
|
-});
|
|
|
-
|
|
|
-const checkBarChartOption = computed(() => {
|
|
|
- const data = (dataStats.value?.checkReject || []).map((s: any) => s.value);
|
|
|
- const titles = (dataStats.value?.checkReject || []).map((s: any) => s.title);
|
|
|
- const max = Math.max(...data, 1);
|
|
|
- return {
|
|
|
- tooltip: { trigger: 'axis' },
|
|
|
- grid: { left: 0, right: 0, top: 8, bottom: 0, containLabel: true },
|
|
|
- xAxis: { type: 'category', data: titles, axisLabel: { show: false }, axisTick: { show: false } },
|
|
|
- yAxis: { type: 'value', axisLabel: { show: false }, splitLine: { show: false }, max },
|
|
|
- series: [
|
|
|
- { type: 'bar', data: data.map(v => max - v), barWidth: 12, itemStyle: { color: '#f0f0f0', borderRadius: 2 }, stack: 'total', silent: true, z: 1 },
|
|
|
- { type: 'bar', data, barWidth: 12, itemStyle: { color: '#1890ff', borderRadius: 2 }, stack: 'total', z: 2 },
|
|
|
- ],
|
|
|
- };
|
|
|
-});
|
|
|
-
|
|
|
+const listRef = ref<InstanceType<typeof CommonListBlock>>();
|
|
|
+const subListRef = ref<InstanceType<typeof EvaluationFormListBlock>>();
|
|
|
|
|
|
-onMounted(async () => {
|
|
|
- dataStats.value = await AssessmentContentApi.getDataCount();
|
|
|
-});
|
|
|
-
|
|
|
-const { variable: lastSelfAssessmentProgress } = useMemorizeVar('adminSelfAssessmentProgress', -100);
|
|
|
const { variable: lastSelfAssessmentLevel } = useMemorizeVar('adminSelfAssessmentLevel', 0);
|
|
|
const { variable: lastCheckLogStatus } = useMemorizeVar('adminCheckLogStatus', 0);
|
|
|
const { variable: lastCheckLogReviewType } = useMemorizeVar('adminCheckLogReviewType', 0);
|
|
|
|
|
|
-const { canReview, canReviewButPrevNotCompleted, isCurrentLevelReviewed, progressHint } = useReview();
|
|
|
-
|
|
|
-const selfAssessmentLevelOptions: DropdownCommonItem[] = [
|
|
|
- { id: 0, name: '全部等级' },
|
|
|
- { id: 23, name: '国家级' },
|
|
|
- { id: 24, name: '省级' },
|
|
|
- { id: 25, name: '市级' },
|
|
|
-];
|
|
|
-
|
|
|
-const selfAssessmentProgressOptions: DropdownCommonItem[] = [
|
|
|
- { id: -100, name: '全部状态' },
|
|
|
- { id: -1, name: '未提交' },
|
|
|
- { id: 0, name: '草稿' },
|
|
|
- { id: 1, name: '已提交审核' },
|
|
|
- { id: 2, name: '项目保护单位审核完成' },
|
|
|
- { id: 3, name: '县(区)文旅部门审核完成' },
|
|
|
- { id: 4, name: '设区市文旅部门/省非遗中心审核完成' },
|
|
|
- { id: 5, name: '省文化和旅游厅审核完成' },
|
|
|
-];
|
|
|
-
|
|
|
const checkLogStatusOptions: DropdownCommonItem[] = [
|
|
|
{ id: 0, name: '全部状态' },
|
|
|
{ id: 1, name: '通过' },
|
|
|
@@ -320,54 +90,6 @@ const checkLogReviewTypeOptions: DropdownCommonItem[] = [
|
|
|
{ id: 5, name: '省文化和旅游厅' },
|
|
|
];
|
|
|
|
|
|
-const downloadProgressOptions: DropdownCommonItem[] = [
|
|
|
- { id: -100, name: '全部状态' },
|
|
|
- { id: -1, name: '未提交' },
|
|
|
- { id: 0, name: '草稿' },
|
|
|
- { id: 1, name: '已提交审核' },
|
|
|
- { id: 2, name: '项目保护单位审核完成' },
|
|
|
- { id: 3, name: '县(区)文旅部门审核完成' },
|
|
|
- { id: 4, name: '设区市文旅部门/省非遗中心审核完成' },
|
|
|
- { id: 5, name: '省文化和旅游厅审核完成' },
|
|
|
-];
|
|
|
-
|
|
|
-function selfAssessmentProgressLabel(progress: number | null | undefined) {
|
|
|
- if (progress === null || progress === undefined)
|
|
|
- return '未填写';
|
|
|
- const hit = selfAssessmentProgressOptions.find((o) => o.id === progress);
|
|
|
- return hit?.name ?? `进度 ${progress}`;
|
|
|
-}
|
|
|
-
|
|
|
-async function loadSelfAssessmentAdminList(page: number, pageSize: number, searchText: string, dropDownValues: number[]) {
|
|
|
- const pv = dropDownValues?.[0];
|
|
|
- const lv = dropDownValues?.[1];
|
|
|
- const st = dropDownValues?.[2];
|
|
|
- lastSelfAssessmentProgress.value = pv ?? -100;
|
|
|
- lastSelfAssessmentLevel.value = lv ?? 0;
|
|
|
- const progress = pv != null && pv > -50 ? pv : undefined;
|
|
|
- const level = lv != null && lv > 0 ? lv : undefined;
|
|
|
- const list = await AssessmentContentApi.getInheritorList({
|
|
|
- year: new Date().getFullYear(),
|
|
|
- page,
|
|
|
- pageSize,
|
|
|
- keywords: searchText?.trim() || undefined,
|
|
|
- progress,
|
|
|
- level,
|
|
|
- logStatus: st > 0 ? st : undefined,
|
|
|
- });
|
|
|
- return {
|
|
|
- page,
|
|
|
- total: list.total,
|
|
|
- data: list.data.map((row) => ({
|
|
|
- ...row,
|
|
|
- id: row.id,
|
|
|
- userId: row.userId,
|
|
|
- title: row.title ?? '?',
|
|
|
- desc: [row.mobile, row.unit, row.ichTitle].filter(Boolean).join(' · ') || '—',
|
|
|
- })),
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
async function loadCheckLogList(page: number, pageSize: number, searchText: string, dropDownValues: number[]) {
|
|
|
const sv = dropDownValues?.[0];
|
|
|
const rv = dropDownValues?.[1];
|
|
|
@@ -400,70 +122,6 @@ async function loadCheckLogList(page: number, pageSize: number, searchText: stri
|
|
|
};
|
|
|
}
|
|
|
|
|
|
-function handleReviewSelfAssessment(item: SelfAssessmentDetail) {
|
|
|
- const cid = item.checkId;
|
|
|
- const uid = item.userId;
|
|
|
- if (!cid || !uid) {
|
|
|
- message.warning('缺少自查表 ID 或传承人用户 ID');
|
|
|
- return;
|
|
|
- }
|
|
|
- router.push({
|
|
|
- name: 'CollectEvaluationFormReview',
|
|
|
- query: {
|
|
|
- id: String(cid),
|
|
|
- userId: String(uid),
|
|
|
- ...(item.progress != null && item.progress !== undefined ? { progress: String(item.progress) } : {}),
|
|
|
- },
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
-async function handleDownloadZip() {
|
|
|
- downloading.value = true;
|
|
|
- try {
|
|
|
- const progress = downloadProgress.value > -50 ? downloadProgress.value : undefined;
|
|
|
- await AssessmentContentApi.downloadCheckZip({
|
|
|
- year: downloadYear.value,
|
|
|
- progress,
|
|
|
- });
|
|
|
- showDownloadModal.value = false;
|
|
|
- message.success('下载成功');
|
|
|
- } catch (e: any) {
|
|
|
- message.error(e?.message || '下载失败');
|
|
|
- } finally {
|
|
|
- downloading.value = false;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-function openDownloadModal() {
|
|
|
- downloadProgress.value = lastSelfAssessmentProgress.value;
|
|
|
- showDownloadModal.value = true;
|
|
|
-}
|
|
|
-
|
|
|
-function openExportExcelModal() {
|
|
|
- exportProgress.value = lastSelfAssessmentProgress.value;
|
|
|
- exportLevel.value = lastSelfAssessmentLevel.value;
|
|
|
- showExportExcelModal.value = true;
|
|
|
-}
|
|
|
-
|
|
|
-async function handleExportExcel() {
|
|
|
- exporting.value = true;
|
|
|
- try {
|
|
|
- const progress = exportProgress.value > -50 ? exportProgress.value : undefined;
|
|
|
- const level = exportLevel.value > 0 ? exportLevel.value : undefined;
|
|
|
- await AssessmentContentApi.exportCheckExcel({
|
|
|
- year: exportYear.value,
|
|
|
- progress,
|
|
|
- level,
|
|
|
- });
|
|
|
- showExportExcelModal.value = false;
|
|
|
- message.success('导出成功');
|
|
|
- } catch (e: any) {
|
|
|
- message.error(e?.message || '导出失败');
|
|
|
- } finally {
|
|
|
- exporting.value = false;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
watch(route, () => {
|
|
|
listRef.value?.reload();
|
|
|
})
|