|
|
@@ -1,6 +1,26 @@
|
|
|
<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"
|
|
|
@@ -126,14 +146,23 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { ref, watch } from 'vue';
|
|
|
+import { computed, onMounted, ref, watch } from 'vue';
|
|
|
import { useRoute, useRouter } 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, { SelfAssessmentDetail } from '@/api/collect/AssessmentContent';
|
|
|
|
|
|
const router = useRouter();
|
|
|
const route = useRoute();
|
|
|
@@ -146,6 +175,79 @@ const downloading = ref(false);
|
|
|
const downloadYear = ref(new Date().getFullYear() - 1);
|
|
|
const downloadProgress = 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 },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+});
|
|
|
+
|
|
|
+
|
|
|
+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);
|