| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- <template>
- <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 agreementProgressStats" :key="s.key" class="flex-1 flex flex-col p-2 items-center" :style="{width: agreementProgressStatsSpan + '%'}">
- <span class="text-2xl bold">{{ s.value }}</span>
- <span class="text-xs text-secondary text-align-center max-h-12 overflow-hidden text-ellipsis">{{ s.title }}</span>
- </div>
- <div class="p-2" :style="{width: agreementProgressStatsSpan + '%'}">
- <v-chart :option="agreementPieChartOption" 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 agreementRejectStats" :key="s.key" class="flex-1 flex flex-col p-2 items-center" :style="{width: agreementRejectStatsSpan + '%'}">
- <span class="text-2xl bold">{{ s.value }}</span>
- <span class="text-xs text-secondary text-align-center max-h-12 overflow-hidden text-ellipsi">{{ s.title }}</span>
- </div>
- <div class="p-2" :style="{width: agreementProgressStatsSpan + '%'}">
- <v-chart :option="agreementBarChartOption" autoresize />
- </div>
- </div>
- </div>
- <CommonListBlock
- ref="listRef"
- :show-total="true"
- :row-count="1"
- :row-type="5"
- :page-size="10"
- :drop-down-names="[
- {
- options: agreementProgressOptions,
- label: '状态',
- defaultSelectedValue: lastAgreementProgress,
- },
- {
- options: agreementLevelOptions,
- label: '等级',
- defaultSelectedValue: lastAgreementLevel,
- },
- ]"
- :load="(page: number, pageSize: number, _tag: number, searchText: string, drop: number[]) => loadAgreementSignAdminList(page, pageSize, searchText, drop)"
- :show-detail="handleShowDetail"
- >
- <template #headLeft>
- <div class="flex flex-row items-center gap-2">
- <span>{{ progressHint }}</span>
- </div>
- </template>
- <template #itemRight="{ item }">
- <div class="flex flex-col md:flex-row md:items-center shrink-0 mt-3 md:mt-2">
- <!-- 自查评估表 状态与审核 -->
- <div class="relative flex flex-row items-center flex-wrap">
- <span class="text-xs text-gray-300 absolute -top-2 left-0">自查评估表状态</span>
- <span
- class="text-sm text-gray-600 truncate max-w-35"
- :title="checkFormProgressLabel(item.checkFormProgress)"
- >
- {{ checkFormProgressLabel(item.checkFormProgress) }}
- </span>
- <a-button type="link" @click.stop="handleEditCheckForm(item)">编辑</a-button>
- <div v-if="item.checkFormId && canReviewButPrevNotCompleted(item.checkFormProgress)" class="flex flex-row items-center text-sm">
- <ExclamationCircleOutlined /> 上一阶段未完成
- </div>
- <a-button
- type="primary"
- v-else-if="item.checkFormId && canReview(item.checkFormProgress)"
- @click.stop="handleReviewCheckForm(item)"
- >
- 审核
- </a-button>
- <a-button
- type="primary"
- disabled
- v-else-if="item.checkFormId && isCurrentLevelReviewed(item.checkFormProgress)"
- >
- 已审核
- </a-button>
- </div>
- <!-- 分隔线(移动端横向 / 桌面端竖向) -->
- <div class="my-3 border-t border-gray-300 md:my-0 md:mx-3 md:border-t-0 md:border-l md:h-6"></div>
- <!-- 传承协议 状态与审核 -->
- <div class="relative flex flex-row items-center flex-wrap">
- <span class="text-xs text-gray-300 absolute -top-2 left-0">传承协议状态</span>
- <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="text-sm" style="color: #f5222d; cursor: pointer;">
- <ExclamationCircleOutlined /> 已退回
- </span>
- </a-popover>
- <span v-else
- class="text-sm text-gray-600 truncate max-w-35"
- :title="agreementProgressLabel(item.progress)"
- >
- {{ agreementProgressLabel(item.progress) }}
- </span>
- <a-button type="link" @click.stop="handleEdit(item)">编辑</a-button>
- <div v-if="item.agreementId && canReviewButPrevNotCompleted(item.progress)" class="flex flex-row items-center text-sm">
- <ExclamationCircleOutlined /> 上一阶段未完成
- </div>
- <a-button
- type="primary"
- v-else-if="item.agreementId && canReview(item.progress)"
- @click.stop="handleReview(item)"
- >
- 审核
- </a-button>
- <a-button
- type="primary"
- disabled
- v-else-if="item.agreementId && isCurrentLevelReviewed(item.progress)"
- >
- 已审核
- </a-button>
- </div>
- </div>
- </template>
- </CommonListBlock>
- </template>
- <script setup lang="ts">
- import { computed, onMounted, ref, watch } from 'vue';
- import { useRoute, useRouter } from 'vue-router';
- import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
- import { useMemorizeVar } from '@/composeables/useMemorizeVar';
- import { useAuthStore } from '@/stores/auth';
- import { GROUP_TO_REVIEW_PROGRESS } from './composeables/GroupData';
- import { useReview } from './composeables/Review';
- import { use } from "echarts/core";
- import { CanvasRenderer } from "echarts/renderers";
- import { PieChart, BarChart, LineChart } from "echarts/charts";
- import {
- TitleComponent,
- TooltipComponent,
- LegendComponent,
- GridComponent,
- } from "echarts/components";
- use([CanvasRenderer, PieChart, BarChart, LineChart, TitleComponent, TooltipComponent, LegendComponent, GridComponent]);
- import VChart from "vue-echarts";
- import CommonListBlock, { type DropdownCommonItem } from '@/components/content/CommonListBlock.vue';
- import AssessmentContentApi, { type UserAgreementListRow } from '@/api/collect/AssessmentContent';
- import { LEVEL_NATIONAL, LEVEL_PROVINCE, LEVEL_DISTRICT } from '@/api/collect/AssessmentConsts';
- const dataStats = ref<Awaited<ReturnType<typeof AssessmentContentApi.getDataCount>>|null>(null);
- const agreementProgressLabels: Record<string, string> = {
- '-1': '未提交',
- '0': '草稿',
- '1': '已提交待审核',
- '2': '单位审核完成',
- '3': '县级审核完成',
- '4': '市级审核完成',
- '5': '省级审核完成',
- };
- const agreementRejectLabels: Record<string, string> = {
- '1': '自评阶段退回',
- '2': '项目保护单位退回',
- '3': '县(区)退回',
- '4': '设区市/省非遗中心退回',
- '5': '省文旅厅退回',
- };
- const agreementProgressStats = computed(() => dataStats.value?.agreement || []);
- const agreementProgressStatsSpan = computed(() => 100 / (Math.max(agreementProgressStats.value.length, 1) - 1));
- const agreementRejectStats = computed(() => dataStats.value?.agreementReject || []);
- const agreementRejectStatsSpan = computed(() => 100 / (Math.max(agreementRejectStats.value.length, 1) - 1));
- const agreementPieChartOption = computed(() => {
- const data = (dataStats.value?.agreement || []).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 agreementBarChartOption = computed(() => {
- const data = (dataStats.value?.agreementReject || []).map((s: any) => s.value);
- const titles = (dataStats.value?.agreementReject || []).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 router = useRouter();
- const route = useRoute();
- const authStore = useAuthStore();
- const listRef = ref<any>(null);
- const { variable: lastAgreementProgress } = useMemorizeVar('adminUserAgreementProgress', -100);
- const { variable: lastAgreementLevel } = useMemorizeVar('adminUserAgreementLevel', 0);
- const agreementLevelOptions: DropdownCommonItem[] = [
- { id: 0, name: '全部等级' },
- { id: LEVEL_NATIONAL, name: '国家级' },
- { id: LEVEL_PROVINCE, name: '省级' },
- { id: LEVEL_DISTRICT, name: '市级' },
- ];
- const agreementProgressOptions: DropdownCommonItem[] = [
- { id: -100, name: '全部状态' },
- { id: 0, name: '未提交' },
- { id: 1, name: '已提交待审核' },
- { id: 2, name: '项目保护单位审核完成' },
- { id: 3, name: '县(区)文旅部门审核完成' },
- { id: 4, name: '设区市文旅部门、省非遗中心审核完成' },
- { id: 5, name: '省文化和旅游厅审核完成' },
- ];
- const { canReview, canReviewButPrevNotCompleted, isCurrentLevelReviewed, progressHint } = useReview();
- function agreementProgressLabel(progress: number | null | undefined) {
- if (progress === null || progress === undefined)
- return '未填写';
- const hit = agreementProgressOptions.find((o) => o.id === progress);
- return hit?.name ?? `进度 ${progress}`;
- }
- const checkFormProgressLabels: Record<number, string> = {
- [-1]: '未提交',
- [0]: '草稿',
- [1]: '已提交审核',
- [2]: '项目保护单位审核完成',
- [3]: '县(区)文旅部门审核完成',
- [4]: '设区市文旅部门/省非遗中心审核完成',
- [5]: '省文化和旅游厅审核完成',
- };
- function checkFormProgressLabel(progress: number | null | undefined) {
- if (progress === null || progress === undefined)
- return '未填写';
- return checkFormProgressLabels[progress] ?? `进度 ${progress}`;
- }
- function handleEditCheckForm(item: any) {
- router.push({
- name: 'CollectEvaluationForm',
- query: { id: item.checkFormId ?? 0, userId: item.userId ?? 0 },
- });
- }
- function handleReviewCheckForm(item: any) {
- if (!item.checkFormId || !item.userId) return;
- router.push({
- name: 'CollectEvaluationFormReview',
- query: {
- id: String(item.checkFormId),
- userId: String(item.userId),
- ...(item.checkFormProgress != null ? { progress: String(item.checkFormProgress) } : {}),
- },
- });
- }
- async function loadAgreementSignAdminList(page: number, pageSize: number, searchText: string, dropDownValues: number[]) {
- const pv = dropDownValues?.[0];
- const lv = dropDownValues?.[1];
- lastAgreementProgress.value = pv ?? -100;
- lastAgreementLevel.value = lv ?? 0;
- const progress = pv != null && pv > -50 ? pv : undefined;
- const level = lv != null && lv > 0 ? lv : undefined;
- const list = await AssessmentContentApi.getUserAgreementList({
- year: new Date().getFullYear(),
- page,
- pageSize,
- keywords: searchText?.trim() || undefined,
- progress,
- level,
- });
- return {
- page,
- total: list.total,
- data: list.data.map((row) => ({
- ...row,
- id: row.id,
- agreementId: row.agreementId,
- userId: row.userId,
- title: row.title,
- desc: [row.mobile, row.basicUnit, row.ichTitle].filter(Boolean).join(' · ') || '—',
- })),
- };
- }
- function handleShowDetail(item: any) {
- router.push({
- name: 'CollectAgreementSign',
- query: { id: item.agreementId && item.agreementId > 0 ? item.agreementId : 0, userId: item.userId ?? 0 },
- });
- }
- function handleEdit(item: any) {
- router.push({
- name: 'CollectAgreementSign',
- query: { id: item.agreementId && item.agreementId > 0 ? item.agreementId : 0, userId: item.userId ?? 0 },
- });
- }
- function handleReview(item: any) {
- if (!item.agreementId || !item.userId) return;
- router.push({
- name: 'CollectAgreementSignReview',
- query: {
- id: String(item.agreementId),
- userId: String(item.userId),
- ...(item.progress != null ? { progress: String(item.progress) } : {}),
- },
- });
- }
- watch(route, () => {
- listRef.value?.reload();
- })
- defineExpose({
- reload: () => listRef.value?.reload(),
- });
- </script>
|