Przeglądaj źródła

🎨 按要求增加审核日志和回退提示

快乐的梦鱼 3 tygodni temu
rodzic
commit
58575d1305

+ 4 - 1
.claude/settings.local.json

@@ -3,7 +3,10 @@
     "allow": [
       "Read(//Users/**)",
       "Bash(find . -path \"*/composeables/useMemorizeVar*\" -o -path \"*/composables/useMemorizeVar*\")",
-      "Bash(find . -name \"useMemorizeVar*\")"
+      "Bash(find . -name \"useMemorizeVar*\")",
+      "mcp__chrome-devtools__navigate_page",
+      "mcp__chrome-devtools__take_screenshot",
+      "mcp__chrome-devtools__evaluate_script"
     ]
   }
 }

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

@@ -230,6 +230,7 @@ export class InheritorCheckListRow extends DataModel<InheritorCheckListRow> {
       provincePoints: { clientSide: 'number', serverSide: 'number' },
       progress: { clientSide: 'number', serverSide: 'number' },
       level: { clientSide: 'number', serverSide: 'string' },
+      rejectType: { clientSide: 'number', serverSide: 'number' },
     };
     this._convertKeyType = (key) => {
       if (key.endsWith('Text') || key.endsWith('_text')) {
@@ -276,6 +277,9 @@ export class InheritorCheckListRow extends DataModel<InheritorCheckListRow> {
   updatetime = '' as string|null;
   /** -1=未提交,0=草稿,1=已自评,2=项目保护单位审核完成,3=县(区)文旅部门审核完成,4=设区市文旅部门/省非遗中心审核完成,5=省文化和旅游厅审核完成 */
   progress = null as number|null;
+  /** 退回状态: 0=无,1=自评阶段退回,2=项目保护单位退回,3=县(区)文旅部门退回,4=设区市文旅部门/省非遗中心退回,5=省文化和旅游厅退回 */
+  rejectType = null as number|null;
+  rejectReason = '' as string|null;
   flagText = '' as string;
   typeText = '' as string;
   openStatusText = '' as string;
@@ -290,6 +294,44 @@ export class InheritorCheckListRow extends DataModel<InheritorCheckListRow> {
   ichSiteTypeText = '' as string;
 }
 
+/** 自查表审核日志列表行(checkLogList) */
+export class CheckLogListRow extends DataModel<CheckLogListRow> {
+  constructor() {
+    super(CheckLogListRow, '自查表审核日志');
+    this.setNameMapperCase('Camel', 'Snake');
+    this._convertTable = {
+      id: { clientSide: 'number', serverSide: 'number' },
+      checkId: { clientSide: 'number', serverSide: 'number' },
+      reviewType: { clientSide: 'number', serverSide: 'number' },
+      status: { clientSide: 'number', serverSide: 'number' },
+      operator: { clientSide: 'number', serverSide: 'number' },
+      progress: { clientSide: 'number', serverSide: 'number' },
+      userId: { clientSide: 'number', serverSide: 'number' },
+    };
+    this._convertKeyType = (key) => {
+      if (key.endsWith('Text') || key.endsWith('_text')) {
+        return { clientSide: 'string', serverSide: 'undefined' };
+      }
+      return undefined;
+    };
+  }
+
+  id = 0 as number;
+  checkId = 0 as number;
+  /** 审核环节: 1=自评阶段,2=项目保护单位,3=县(区)文旅部门,4=设区市文旅部门、省非遗中心,5=省文化和旅游厅 */
+  reviewType = 0 as number;
+  /** 状态: 1=通过,2=退回 */
+  status = 0 as number;
+  reason = '' as string|null;
+  operator = 0 as number;
+  createtime = '' as string|null;
+  progress = 0 as number;
+  inheritor = '' as string|null;
+  userId = 0 as number;
+  reviewTypeText = '' as string;
+  statusText = '' as string;
+}
+
 /** 传承人基础信息(ich/check/basic) */
 export class InheritorCheckBasicInfo extends DataModel<InheritorCheckBasicInfo> {
   constructor() {
@@ -749,6 +791,34 @@ export class AssessmentContentApi extends AppServerRequestModule<DataModel> {
   }
 
   /**
+   * 自查表审核日志列表
+   */
+  async getCheckLogList(data: {
+    userId?: number;
+    reviewType?: number;
+    year?: number;
+    status?: number;
+    operator?: number;
+    checkId?: number;
+    keywords?: string;
+    page?: number;
+    pageSize?: number;
+  }) {
+    const res = await this.post<KeyValue>('/ich/check/checkLogList', '自查表审核日志', {
+      user_id: data.userId,
+      review_type: data.reviewType,
+      year: data.year,
+      status: data.status,
+      operator: data.operator,
+      check_id: data.checkId,
+      keywords: data.keywords,
+      page: data.page,
+      pageSize: data.pageSize,
+    });
+    return normalizePaginated<CheckLogListRow>(CheckLogListRow, res.requireData());
+  }
+
+  /**
    * 保护单位账号:传承人分页列表
    * @param data.progress -1=未提交,0=草稿,1=已自评,2=项目保护单位审核完成,3=县(区)文旅部门审核完成,4=设区市文旅部门/省非遗中心审核完成,5=省文化和旅游厅审核完成
    */

+ 2 - 97
src/pages/admin.vue

@@ -144,36 +144,7 @@
             </CommonListBlock>
           </a-tab-pane>
           <a-tab-pane key="8" tab="自查评估表">
-            <CommonListBlock
-              :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,
-                },
-              ]"
-              :load="(page: number, pageSize: number, _tag: number, searchText: string, drop: number[]) => loadSelfAssessmentAdminList(page, pageSize, searchText, drop)"
-              :show-detail="(item) => router.push({ name: 'CollectEvaluationForm', query: { id: item.checkId ?? item.id, userId: item.userId } })"
-            >
-              <template #itemRight="{ item }">
-                <span 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>
-                <a-button
-                  type="primary"
-                  v-if="item.checkId && item.progress != null && item.progress >= 1 && item.progress < 5"
-                  @click.stop="handleReviewSelfAssessment(item)"
-                >审核</a-button>             
-              </template>
-            </CommonListBlock>
+            <EvaluationFormList />
           </a-tab-pane>
           <a-tab-pane v-if="false" key="4" tab="重点区域">
             <div class="flex justify-end">
@@ -216,6 +187,7 @@ import CommonListBlock, { type DropdownCommonItem } from '@/components/content/C
 import InheritorContent from '@/api/inheritor/InheritorContent';
 import AssessmentContentApi from '@/api/collect/AssessmentContent';
 import AdminItemState from './components/AdminItemState.vue';
+import EvaluationFormList from './collect/assessment/evaluation-form-list.vue';
 import { InfoCircleOutlined } from '@ant-design/icons-vue';
 import { useSimpleDataLoader } from '@/composeables/useSimpleDataLoader';
 import { useMemorizeVar } from '@/composeables/useMemorizeVar';
@@ -229,8 +201,6 @@ const inheritorData = ref<GetContentListItem[]>([]);
 
 const { variable: lastValueCategory } = useMemorizeVar('categoryLastSelectValue', 0);
 const { variable: lastValueStatus } = useMemorizeVar('statusLastSelectValue', -10);
-const { variable: lastSelfAssessmentProgress } = useMemorizeVar('adminSelfAssessmentProgress', -100);
-const { variable: lastSelfAssessmentLevel } = useMemorizeVar('adminSelfAssessmentLevel', 0);
 const { variable: lastAgreementProgress } = useMemorizeVar('adminUserAgreementProgress', -100);
 const { variable: lastAgreementLevel } = useMemorizeVar('adminUserAgreementLevel', 0);
 
@@ -241,18 +211,6 @@ const selfAssessmentLevelOptions: DropdownCommonItem[] = [
   { id: 25, name: '市级' },
 ];
 
-/** 自查评估表列表:进度筛选(与 ich/check/getList 一致) */
-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: '省文化和旅游厅审核完成' },
-];
-
 /** 传承人传承协议列表:进度筛选(与 ich/check/getUserAgreement 一致) */
 const agreementProgressOptions: DropdownCommonItem[] = [
   { id: -100, name: '全部状态' },
@@ -269,13 +227,6 @@ function agreementProgressLabel(progress: number | null | undefined) {
   return hit?.name ?? `进度 ${progress}`;
 }
 
-function selfAssessmentProgressLabel(progress: number | null | undefined) {
-  if (progress === null || progress === undefined)
-    return '未填写';
-  const hit = selfAssessmentProgressOptions.find((o) => o.id === progress);
-  return hit?.name ?? `进度 ${progress}`;
-}
-
 const computedCategoryOptions = computed<DropdownCommonItem[]>(() => {
   if (authStore.isReviewer) {
     return [
@@ -421,35 +372,6 @@ async function loadAreaData(page: number, pageSize: number, dropDownValues: numb
   }
 }
 
-/** 管理员:自查评估表分页(关键词、进度走接口) */
-async function loadSelfAssessmentAdminList(page: number, pageSize: number, searchText: string, dropDownValues: number[]) {
-  const pv = dropDownValues?.[0];
-  const lv = dropDownValues?.[1];
-  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,
-  });
-  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(' · ') || '—',
-    })),
-  };
-}
-
 /** 管理员:传承人传承协议分页(ich/check/getUserAgreement) */
 async function loadAgreementSignAdminList(page: number, pageSize: number, searchText: string, dropDownValues: number[]) {
   const pv = dropDownValues?.[0];
@@ -521,21 +443,4 @@ function handleGoWorks(item: GetContentListItem) {
   } })
 }
 
-/** 自查评估表:进入审核页(只读表单 + 提交 /ich/check/review) */
-function handleReviewSelfAssessment(item: { checkId: number | null; userId: number | null; progress?: number | null }) {
-  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) } : {}),
-    },
-  });
-}
 </script>

+ 207 - 0
src/pages/collect/assessment/evaluation-form-list.vue

@@ -0,0 +1,207 @@
+<template>
+  <a-tabs v-model:activeKey="activeKey" centered type="card">
+    <a-tab-pane key="1" tab="传承人列表">
+      <CommonListBlock
+        :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,
+          },
+        ]"
+        :load="(page: number, pageSize: number, _tag: number, searchText: string, drop: number[]) => loadSelfAssessmentAdminList(page, pageSize, searchText, drop)"
+        :show-detail="(item) => router.push({ name: 'CollectEvaluationForm', query: { id: item.checkId ?? item.id, userId: item.userId } })"
+      >
+        <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 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>
+          <a-button
+            type="primary"
+            v-if="item.checkId && item.progress != null && item.progress >= 1 && item.progress < 5"
+            @click.stop="handleReviewSelfAssessment(item)"
+          >审核</a-button>
+        </template>
+      </CommonListBlock>
+    </a-tab-pane>
+    <a-tab-pane key="2" tab="审核记录">
+      <CommonListBlock
+        :show-total="true"
+        :row-count="1"
+        :row-type="5"
+        :page-size="10"
+        :drop-down-names="[
+          {
+            options: checkLogStatusOptions,
+            label: '状态',
+            defaultSelectedValue: lastCheckLogStatus,
+          },
+          {
+            options: checkLogReviewTypeOptions,
+            label: '审核环节',
+            defaultSelectedValue: lastCheckLogReviewType,
+          },
+        ]"
+        :load="(page: number, pageSize: number, _tag: number, searchText: string, drop: number[]) => loadCheckLogList(page, pageSize, searchText, drop)"
+        :show-detail="() => {}"
+      >
+        <template #itemRight="{ item }">
+          <a-tag :color="item.status === 1 ? 'green' : 'red'">{{ item.statusText || (item.status === 1 ? '通过' : '退回') }}</a-tag>
+          <span class="mr-3 text-sm text-gray-600">{{ item.reviewTypeText }}</span>
+        </template>
+      </CommonListBlock>
+    </a-tab-pane>
+  </a-tabs>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+import { message } from 'ant-design-vue';
+import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
+import CommonListBlock, { type DropdownCommonItem } from '@/components/content/CommonListBlock.vue';
+import AssessmentContentApi from '@/api/collect/AssessmentContent';
+import { useMemorizeVar } from '@/composeables/useMemorizeVar';
+
+const router = useRouter();
+
+const activeKey = ref('1');
+
+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 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: '通过' },
+  { id: 2, name: '退回' },
+];
+
+const checkLogReviewTypeOptions: DropdownCommonItem[] = [
+  { 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];
+  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,
+  });
+  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];
+  lastCheckLogStatus.value = sv ?? 0;
+  lastCheckLogReviewType.value = rv ?? 0;
+  const status = sv != null && sv > 0 ? sv : undefined;
+  const reviewType = rv != null && rv > 0 ? rv : undefined;
+  const list = await AssessmentContentApi.getCheckLogList({
+    year: new Date().getFullYear(),
+    page,
+    pageSize,
+    keywords: searchText?.trim() || undefined,
+    status,
+    reviewType,
+  });
+  return {
+    page,
+    total: list.total,
+    data: list.data.map((row) => ({
+      ...row,
+      id: row.id,
+      title: row.inheritor ?? '?',
+      desc: [
+        row.reviewTypeText,
+        row.statusText,
+        row.reason,
+        row.createtime,
+      ].filter(Boolean).join(' · ') || '—',
+    })),
+  };
+}
+
+function handleReviewSelfAssessment(item: { checkId: number | null; userId: number | null; progress?: number | null }) {
+  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) } : {}),
+    },
+  });
+}
+</script>