diff --git a/crop-x/src/app/(app)/central-config/tenant/audit-history/components/auditHistoryApi.ts b/crop-x/src/app/(app)/central-config/tenant/audit-history/components/auditHistoryApi.ts new file mode 100644 index 0000000..5214cbf --- /dev/null +++ b/crop-x/src/app/(app)/central-config/tenant/audit-history/components/auditHistoryApi.ts @@ -0,0 +1,240 @@ +/** + * filekorolheader: 审核历史API接口 - 企业审核记录查询接口服务 + * 功能:API请求封装、数据转换、错误处理、分页查询 + * 路径:/central-config/tenant/audit-history/components/auditHistoryApi + * 规范:遵循crop-x/docs/开发项目规范.md,使用SDK API调用,TypeScript类型安全 + */ + +// API响应数据类型定义 +import { getAuthToken } from "@/utils/token.ts"; +import { + getTenantAuditLogsApiV1TenantsAuditLogsGet, +} from "@/lib/api/sdk.gen"; + +export interface AuditLogData { + id: string; + action: string; + action_by: string; + action_time: string; + snapshot_company_name: string; + snapshot_company_type: string | null; + snapshot_province: string | null; + snapshot_city: string | null; + snapshot_district: string | null; + snapshot_detailed_address: string | null; + snapshot_registrant: string | null; + snapshot_contact_phone: string | null; + snapshot_bank_account: string | null; + snapshot_bank_name: string | null; + snapshot_bank_full_name: string | null; + snapshot_bank_address: string | null; + snapshot_social_credit_code: string | null; + snapshot_legal_person_name: string | null; + snapshot_audit_status: string; + snapshot_audit_comment: string | null; + snapshot_company_scale: string | null; + snapshot_registered_capital: string | null; + change_summary: string; + ip_address: string | null; + user_agent: string | null; + request_id: string | null; + created_at: string; +} + +// API响应接口 +export interface AuditLogsApiResponse { + data: AuditLogData[]; + total: number; + page: number; + size: number; + total_pages: number; + has_next: boolean; + has_prev: boolean; +} + +// 查询参数接口 +export interface AuditLogsQueryParams { + tenant_id?: string; + page?: number; + size?: number; + order_by?: string; + sort_order?: 'asc' | 'desc'; +} + +// 审核记录页面数据类型(转换后的) +export interface AuditRecord { + id: string; + enterpriseId?: string; + enterpriseName: string; + action: 'SUBMIT' | 'AUDIT'; + auditType: 'register' | 'update'; + submitTime: string; + actionTime: string; + actionBy: string; + result: 'pending' | 'approved' | 'rejected' | 'draft'; + auditStatus: string; + auditComment?: string; + changeSummary: string; + ipAddress?: string; + userAgent?: string; + requestId?: string; + createdAt: string; + + // 快照数据 + snapshot: { + companyName: string; + companyType: string | null; + province: string | null; + city: string | null; + district: string | null; + detailedAddress: string | null; + registrant: string | null; + contactPhone: string | null; + bankAccount: string | null; + bankName: string | null; + bankFullName: string | null; + bankAddress: string | null; + socialCreditCode: string | null; + legalPersonName: string | null; + auditStatus: string; + auditComment: string | null; + companyScale: string | null; + registeredCapital: string | null; + }; +} + +/** + * 获取审核历史记录数据 + */ +export async function fetchAuditLogs(params: AuditLogsQueryParams = {}): Promise { + try { + // 构建查询参数对象 + const queryParams: any = {}; + + queryParams.tenant_id = ""; + if (params.page) queryParams.page = params.page; + if (params.size) queryParams.size = params.size; + if (params.order_by) queryParams.order_by = params.order_by; + if (params.sort_order) queryParams.sort_order = params.sort_order; + + // 默认参数 + if (!params.page) queryParams.page = 1; + if (!params.size) queryParams.size = 10; + + // 使用SDK API调用审核历史查询接口,添加缓存破坏器和认证头部 + const token = getAuthToken(); + const response = await getTenantAuditLogsApiV1TenantsAuditLogsGet({ + query: { + ...queryParams, + // 添加时间戳防止缓存 + _t: Date.now(), + }, + headers: token ? { + 'Authorization': `Bearer ${token}`, + } : undefined, + }); + + if (response.error) { + throw new Error(`API error: ${response.error.message || 'Unknown error'}`); + } + + const data = response.data as any; + + // 转换响应数据格式以匹配现有的接口 + return { + data: data?.data || [], + total: data?.total || 0, + page: data?.page || 1, + size: data?.size || 10, + total_pages: data?.total_pages || 0, + has_next: data?.has_next || false, + has_prev: data?.has_prev || false, + }; + } catch (error) { + console.error('Failed to fetch audit logs:', error); + throw error; + } +} + +/** + * 将API数据转换为页面所需的审核记录格式 + */ +export function transformAuditLogData(log: AuditLogData): AuditRecord { + // 判断审核类型 + let auditType: 'register' | 'update' = 'register'; + if (log.change_summary.includes('更新') || log.change_summary.includes('修改')) { + auditType = 'update'; + } + + // 映射审核状态 + let result: 'pending' | 'approved' | 'rejected' | 'draft' = 'pending'; + const status = log.snapshot_audit_status.toLowerCase(); + if (status.includes('草稿') || status.includes('draft')) { + result = 'draft'; + } else if (status.includes('待审核') || status.includes('pending')) { + result = 'pending'; + } else if (status.includes('已通过') || status.includes('approved')) { + result = 'approved'; + } else if (status.includes('已拒绝') || status.includes('rejected')) { + result = 'rejected'; + } + + return { + id: log.id, + enterpriseId: log.action_by, // 使用操作人作为企业ID关联 + enterpriseName: log.snapshot_company_name, + action: log.action as 'SUBMIT' | 'AUDIT', + auditType, + submitTime: formatDate(log.action_time), + actionTime: formatDate(log.action_time), + actionBy: log.action_by, + result, + auditStatus: log.snapshot_audit_status, + auditComment: log.snapshot_audit_comment, + changeSummary: log.change_summary, + ipAddress: log.ip_address, + userAgent: log.user_agent, + requestId: log.request_id, + createdAt: formatDate(log.created_at), + + // 快照数据 + snapshot: { + companyName: log.snapshot_company_name, + companyType: log.snapshot_company_type, + province: log.snapshot_province, + city: log.snapshot_city, + district: log.snapshot_district, + detailedAddress: log.snapshot_detailed_address, + registrant: log.snapshot_registrant, + contactPhone: log.snapshot_contact_phone, + bankAccount: log.snapshot_bank_account, + bankName: log.snapshot_bank_name, + bankFullName: log.snapshot_bank_full_name, + bankAddress: log.snapshot_bank_address, + socialCreditCode: log.snapshot_social_credit_code, + legalPersonName: log.snapshot_legal_person_name, + auditStatus: log.snapshot_audit_status, + auditComment: log.snapshot_audit_comment, + companyScale: log.snapshot_company_scale, + registeredCapital: log.snapshot_registered_capital, + }, + }; +} + +/** + * 格式化日期 + */ +function formatDate(dateString: string): string { + try { + const date = new Date(dateString); + return date.toLocaleString('zh-CN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + }).replace(/\//g, '-'); + } catch (error) { + return dateString; + } +} \ No newline at end of file diff --git a/crop-x/src/app/(app)/central-config/tenant/audit-history/components/auditHistoryReducer.tsx b/crop-x/src/app/(app)/central-config/tenant/audit-history/components/auditHistoryReducer.tsx new file mode 100644 index 0000000..a903f17 --- /dev/null +++ b/crop-x/src/app/(app)/central-config/tenant/audit-history/components/auditHistoryReducer.tsx @@ -0,0 +1,125 @@ +/** + * filekorolheader: 审核历史状态管理 - 审核记录数据状态管理核心 + * 功能:API数据管理、分页状态、加载状态、错误处理、筛选状态 + * 路径:/central-config/tenant/audit-history/components/auditHistoryReducer + * 规范:遵循crop-x/docs/开发项目规范.md,使用useReducer状态管理模式 + */ + +import { AuditRecord } from '../types'; + +export interface FilterOptions { + searchKeyword: string; + resultFilter: string; + typeFilter: string; + dateRange: string; +} + +export interface AuditHistoryState { + records: AuditRecord[]; + loading: boolean; + error: string | null; + pagination: { + page: number; + size: number; + total: number; + totalPages: number; + hasNext: boolean; + hasPrev: boolean; + }; + filters: FilterOptions; + showDetailDialog: boolean; + selectedRecord: AuditRecord | null; + sortBy?: string; + sortOrder: 'asc' | 'desc'; +} + +export type AuditHistoryAction = + | { type: 'SET_LOADING'; payload: boolean } + | { type: 'SET_ERROR'; payload: string | null } + | { type: 'SET_RECORDS'; payload: { data: AuditRecord[]; pagination: AuditHistoryState['pagination'] } } + | { type: 'SET_FILTERS'; payload: Partial } + | { type: 'SET_PAGINATION'; payload: Partial } + | { type: 'SET_SORT'; payload: { sortBy?: string; sortOrder: 'asc' | 'desc' } } + | { type: 'TOGGLE_DETAIL_DIALOG'; payload: boolean } + | { type: 'SET_SELECTED_RECORD'; payload: AuditRecord | null } + | { type: 'REFRESH_DATA' }; + +// 初始状态 +export const initialState: AuditHistoryState = { + records: [], + loading: false, + error: null, + pagination: { + page: 1, + size: 10, + total: 0, + totalPages: 0, + hasNext: false, + hasPrev: false, + }, + filters: { + searchKeyword: '', + resultFilter: 'all', + typeFilter: 'all', + dateRange: 'all', + }, + showDetailDialog: false, + selectedRecord: null, + sortBy: undefined, + sortOrder: 'desc', +}; + +// Reducer +export function auditHistoryReducer(state: AuditHistoryState, action: AuditHistoryAction): AuditHistoryState { + switch (action.type) { + case 'SET_LOADING': + return { ...state, loading: action.payload }; + + case 'SET_ERROR': + return { ...state, error: action.payload, loading: false }; + + case 'SET_RECORDS': + return { + ...state, + records: action.payload.data, + pagination: action.payload.pagination, + loading: false, + error: null, + }; + + case 'SET_FILTERS': + return { + ...state, + filters: { ...state.filters, ...action.payload }, + pagination: { ...state.pagination, page: 1 }, // 重置到第一页 + }; + + case 'SET_PAGINATION': + return { + ...state, + pagination: { ...state.pagination, ...action.payload }, + }; + + case 'SET_SORT': + return { + ...state, + sortBy: action.payload.sortBy, + sortOrder: action.payload.sortOrder, + }; + + case 'TOGGLE_DETAIL_DIALOG': + return { ...state, showDetailDialog: action.payload }; + + case 'SET_SELECTED_RECORD': + return { ...state, selectedRecord: action.payload }; + + case 'REFRESH_DATA': + return { + ...state, + error: null, // 清除错误状态 + }; + + default: + return state; + } +} \ No newline at end of file diff --git a/crop-x/src/app/(app)/central-config/tenant/audit-history/page.tsx b/crop-x/src/app/(app)/central-config/tenant/audit-history/page.tsx index 193e8a2..3fd676c 100644 --- a/crop-x/src/app/(app)/central-config/tenant/audit-history/page.tsx +++ b/crop-x/src/app/(app)/central-config/tenant/audit-history/page.tsx @@ -1,211 +1,634 @@ +/** + * filekorolheader: 审核历史页面 - 企业审核记录查询和管理页面 + * 功能:审核历史记录查询、搜索筛选、详情查看、数据分析 + * 路径:/central-config/tenant/audit-history + * 规范:遵循crop-x/docs/开发项目规范.md,使用useReducer状态管理,API集成,shadcn语义化样式 + */ 'use client'; -import { useState, useEffect } from 'react'; +import { useReducer, useEffect, useMemo, useState } from 'react'; import { toast } from 'sonner'; +import { Card } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; -import { Download } from 'lucide-react'; -import { AuditHistoryStatsCards } from './components/AuditHistoryStatsCards'; -import { AuditHistoryFilters } from './components/AuditHistoryFilters'; -import { AuditHistoryList } from './components/AuditHistoryList'; -import { AuditHistoryDetailDialog } from './components/AuditHistoryDetailDialog'; -import { AuditHistoryInstructions } from './components/AuditHistoryInstructions'; -import { AuditRecord, Enterprise, FilterOptions } from './types'; +import { Badge } from '@/components/ui/badge'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; +import { ScrollArea } from '@/components/ui/scroll-area'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { + History, + Search, + Calendar, + FileText, + AlertCircle, + RefreshCw, + ChevronLeft, + ChevronRight, + Building, + User, + CreditCard, + Smartphone +} from 'lucide-react'; + +import { fetchAuditLogs, transformAuditLogData, AuditLogsQueryParams, AuditLogData } from './components/auditHistoryApi'; + +// 审核历史状态管理 +interface AuditHistoryState { + records: AuditLogData[]; + loading: boolean; + error: string | null; + pagination: { + page: number; + size: number; + total: number; + totalPages: number; + hasNext: boolean; + hasPrev: boolean; + }; + filters: { + search_keyword: string; + typeFilter: string; + resultFilter: string; + dateRange: string; + }; + sortBy?: string; + sortOrder: 'asc' | 'desc'; + selectedRecord: AuditLogData | null; + showDetailDialog: boolean; +} + +type AuditHistoryAction = + | { type: 'SET_RECORDS'; payload: { data: AuditLogData[]; pagination: AuditHistoryState['pagination'] } } + | { type: 'SET_LOADING'; payload: boolean } + | { type: 'SET_ERROR'; payload: string | null } + | { type: 'SET_FILTERS'; payload: Partial } + | { type: 'SET_SORT'; payload: { sortBy?: string; sortOrder: 'asc' | 'desc' } } + | { type: 'SET_PAGINATION'; payload: Partial } + | { type: 'SET_SELECTED_RECORD'; payload: AuditLogData | null } + | { type: 'TOGGLE_DETAIL_DIALOG'; payload: boolean } + | { type: 'REFRESH_DATA' }; + +const auditHistoryReducer = (state: AuditHistoryState, action: AuditHistoryAction): AuditHistoryState => { + switch (action.type) { + case 'SET_RECORDS': + return { + ...state, + records: action.payload.data, + pagination: action.payload.pagination, + loading: false, + error: null, + }; + case 'SET_LOADING': + return { ...state, loading: action.payload }; + case 'SET_ERROR': + return { ...state, error: action.payload, loading: false }; + case 'SET_FILTERS': + return { ...state, filters: { ...state.filters, ...action.payload } }; + case 'SET_SORT': + return { ...state, sortBy: action.payload.sortBy, sortOrder: action.payload.sortOrder }; + case 'SET_PAGINATION': + return { ...state, pagination: { ...state.pagination, ...action.payload } }; + case 'SET_SELECTED_RECORD': + return { ...state, selectedRecord: action.payload }; + case 'TOGGLE_DETAIL_DIALOG': + return { ...state, showDetailDialog: !state.showDetailDialog }; + case 'REFRESH_DATA': + return { ...state, error: null }; + default: + return state; + } +}; + +const initialState: AuditHistoryState = { + records: [], + loading: false, + error: null, + pagination: { + page: 1, + size: 10, + total: 0, + totalPages: 0, + hasNext: false, + hasPrev: false, + }, + filters: { + search_keyword: '', + typeFilter: 'all', + resultFilter: 'all', + dateRange: 'all', + }, + sortBy: 'action_time', + sortOrder: 'desc', + selectedRecord: null, + showDetailDialog: false, +}; export default function AuditHistoryPage() { - const [records, setRecords] = useState([]); - const [enterprises, setEnterprises] = useState([]); - const [showDetailDialog, setShowDetailDialog] = useState(false); - const [selectedRecord, setSelectedRecord] = useState(null); - const [selectedEnterprise, setSelectedEnterprise] = useState(null); + const [state, dispatch] = useReducer(auditHistoryReducer, initialState); - const [filters, setFilters] = useState({ - searchKeyword: '', - resultFilter: 'all', - typeFilter: 'all', - dateRange: 'all' - }); + // 加载审核历史数据 + const loadAuditHistory = async (resetPage = false) => { + try { + dispatch({ type: 'SET_LOADING', payload: true }); + const params: AuditLogsQueryParams = { + search: state.filters.search_keyword || undefined, + page: resetPage ? 1 : state.pagination.page, + size: state.pagination.size + }; + + const response = await fetchAuditLogs(params); + const transformedRecords = response.data.map(transformAuditLogData); + + dispatch({ + type: 'SET_RECORDS', + payload: { + data: transformedRecords, + pagination: { + page: response.page, + size: response.size, + total: response.total, + totalPages: response.total_pages, + hasNext: response.has_next, + hasPrev: response.has_prev, + } + } + }); + } catch (error) { + console.error('Failed to load audit history:', error); + dispatch({ + type: 'SET_ERROR', + payload: error instanceof Error ? error.message : '加载审核历史失败' + }); + } + }; + + // 搜索处理 + const handleSearch = (value: string) => { + dispatch({ type: 'SET_FILTERS', payload: { search_keyword: value } }); + }; + + // 类型筛选 + const handleTypeFilter = (value: string) => { + dispatch({ type: 'SET_FILTERS', payload: { typeFilter: value } }); + }; + + // 结果筛选 + const handleResultFilter = (value: string) => { + dispatch({ type: 'SET_FILTERS', payload: { resultFilter: value } }); + }; + + // 时间筛选 + const handleDateFilter = (value: string) => { + dispatch({ type: 'SET_FILTERS', payload: { dateRange: value } }); + }; + + // 排序处理 + const handleSort = (sortBy: string) => { + const newSortOrder = state.sortBy === sortBy && state.sortOrder === 'desc' ? 'asc' : 'desc'; + dispatch({ type: 'SET_SORT', payload: { sortBy, sortOrder: newSortOrder } }); + }; + + // 分页处理 + const handlePageChange = (page: number) => { + // 边界检查,确保页码在有效范围内 + if (page < 1) { + page = 1; + } else if (page > state.pagination.totalPages && state.pagination.totalPages > 0) { + page = state.pagination.totalPages; + } + dispatch({ type: 'SET_PAGINATION', payload: { page } }); + }; + + // 查看详情 + const handleViewDetail = (record: AuditLogData) => { + dispatch({ type: 'SET_SELECTED_RECORD', payload: record }); + dispatch({ type: 'TOGGLE_DETAIL_DIALOG', payload: true }); + }; + + // 刷新数据 + const handleRefresh = () => { + dispatch({ type: 'REFRESH_DATA' }); + loadAuditHistory(true); + toast.success('数据已刷新'); + }; + + // 初始化和监听器 useEffect(() => { - loadEnterprises(); loadAuditHistory(); }, []); - const loadEnterprises = () => { - const data = localStorage.getItem('smart_agriculture_enterprises'); - if (data) { - setEnterprises(JSON.parse(data)); + useEffect(() => { + const timer = setTimeout(() => { + loadAuditHistory(); + }, 300); + + return () => clearTimeout(timer); + }, [state.filters.search_keyword, state.filters.typeFilter, state.filters.resultFilter, state.filters.dateRange, state.sortBy, state.sortOrder]); + + useEffect(() => { + if (state.pagination.page > 1) { + loadAuditHistory(); + } + }, [state.pagination.page]); + + // 工具函数 + const getActionBadge = (action: string) => { + switch (action) { + case 'register': + return 注册审核; + case 'update': + return 变更审核; + default: + return {action}; } }; - const loadAuditHistory = () => { - const data = localStorage.getItem('smart_agriculture_audit_records'); - if (data) { - setRecords(JSON.parse(data)); - } else { - // 初始化审核历史数据 - const mockRecords: AuditRecord[] = [ - { - id: 'audit-1', - enterpriseId: 'ent-2', - enterpriseName: '丰收现代农业集团', - auditType: 'register', - submitTime: '2024-10-05T10:00:00', - auditTime: '2024-10-08T14:30:00', - auditor: '系统管理员', - result: 'approved', - remarks: '企业资质完整,审核通过', - }, - { - id: 'audit-2', - enterpriseId: 'ent-3', - enterpriseName: '金穗农机服务中心', - auditType: 'register', - submitTime: '2024-10-06T09:00:00', - auditTime: '2024-10-09T16:00:00', - auditor: '系统管理员', - result: 'rejected', - reason: '资质材料不完整,请补充营业执照副本', - remarks: '缺少必要的资质证明文件', - }, - { - id: 'audit-3', - enterpriseId: 'ent-1', - enterpriseName: '绿野农业科技有限公司', - auditType: 'register', - submitTime: '2024-10-10T08:00:00', - result: 'pending', - }, - { - id: 'audit-4', - enterpriseId: 'ent-2', - enterpriseName: '丰收现代农业集团', - auditType: 'update', - submitTime: '2024-10-12T15:30:00', - auditTime: '2024-10-13T10:00:00', - auditor: '系统管理员', - result: 'approved', - remarks: '企业地址变更审核通过', - }, - { - id: 'audit-5', - enterpriseId: 'ent-4', - enterpriseName: '智慧农田科技公司', - auditType: 'register', - submitTime: '2024-09-28T11:00:00', - auditTime: '2024-09-30T09:30:00', - auditor: '系统管理员', - result: 'approved', - remarks: '优质企业,快速审核通过', - }, - { - id: 'audit-6', - enterpriseId: 'ent-5', - enterpriseName: '农业机械租赁中心', - auditType: 'register', - submitTime: '2024-10-03T14:20:00', - auditTime: '2024-10-05T11:00:00', - auditor: '系统管理员', - result: 'rejected', - reason: '企业经营范围与平台业务不符', - remarks: '建议企业完善相关资质后重新申请', - }, - ]; - localStorage.setItem('smart_agriculture_audit_records', JSON.stringify(mockRecords)); - setRecords(mockRecords); + const getResultBadge = (result: string) => { + switch (result) { + case 'approved': + return 已通过; + case 'rejected': + return 已驳回; + case 'pending': + return 待审核; + default: + return {result}; } }; - const filteredRecords = records.filter(record => { - const matchKeyword = !filters.searchKeyword || - record.enterpriseName.includes(filters.searchKeyword) || - (record.auditor && record.auditor.includes(filters.searchKeyword)); - - const matchResult = filters.resultFilter === 'all' || record.result === filters.resultFilter; - const matchType = filters.typeFilter === 'all' || record.auditType === filters.typeFilter; - - // 日期筛选 - let matchDate = true; - if (filters.dateRange !== 'all' && record.auditTime) { - const auditDate = new Date(record.auditTime); - const now = new Date(); - const diffDays = Math.floor((now.getTime() - auditDate.getTime()) / (1000 * 60 * 60 * 24)); - - switch (filters.dateRange) { - case 'today': - matchDate = diffDays === 0; - break; - case 'week': - matchDate = diffDays <= 7; - break; - case 'month': - matchDate = diffDays <= 30; - break; - case 'quarter': - matchDate = diffDays <= 90; - break; - } - } - - return matchKeyword && matchResult && matchType && matchDate; - }); - - const handleViewDetail = (record: AuditRecord) => { - setSelectedRecord(record); - // 查找对应的企业信息 - const enterprise = enterprises.find(e => e.id === record.enterpriseId); - setSelectedEnterprise(enterprise || null); - setShowDetailDialog(true); - }; - - const handleExport = () => { - const dataStr = JSON.stringify(filteredRecords, null, 2); - const dataBlob = new Blob([dataStr], { type: 'application/json' }); - const url = URL.createObjectURL(dataBlob); - const link = document.createElement('a'); - link.href = url; - link.download = `audit_history_${new Date().getTime()}.json`; - link.click(); - toast.success('审核历史数据导出成功'); - }; - return (
-
-
-

审核历史

-

追溯查询全部企业的历史审核记录

+ {/* Page Header */} + +
+
+ +
+

审核历史

+

+ 追溯查询全部企业的历史审核记录 +

+
+ + + 智能查询 + + + + 时间筛选 + + + + 详细记录 + +
+
+
+
+ +
- -
+ - {/* 统计卡片 */} - + {/* Filters */} + +
+
+ +
+ + handleSearch(e.target.value)} + className="pl-10" + /> +
+
- {/* 搜索和筛选 */} - +
+
+ + +
- {/* 审核历史列表 */} - +
+ + +
+
+
+
- {/* 详情对话框 */} - + {/* Time Range Filter */} + + +
+ {[ + { value: 'all', label: '全部' }, + { value: 'today', label: '今天' }, + { value: 'week', label: '近7天' }, + { value: 'month', label: '近30天' }, + { value: 'quarter', label: '近90天' }, + ].map((option) => ( + + ))} +
+
- {/* 使用说明 */} - + {/* Error Display */} + {state.error && ( +
+
+ + {state.error} +
+
+ )} + + {/* Loading State */} + {state.loading && ( +
+ +

加载中...

+
+ )} + + {/* Data Table */} + {!state.loading && !state.error && ( + +
+ + + + handleSort('enterprise_name')} + > + 企业名称 + {state.sortBy === 'enterprise_name' && ( + {state.sortOrder === 'asc' ? '↑' : '↓'} + )} + + handleSort('action')} + > + 操作类型 + {state.sortBy === 'action' && ( + {state.sortOrder === 'asc' ? '↑' : '↓'} + )} + + 操作人 + handleSort('action_time')} + > + 操作时间 + {state.sortBy === 'action_time' && ( + {state.sortOrder === 'asc' ? '↑' : '↓'} + )} + + 结果 + 操作 + + + + {state.records.length === 0 ? ( + + + 暂无审核记录 + + + ) : ( + state.records.map((record) => ( + + +
+ + {record.snapshot_company_name} +
+
+ {getActionBadge(record.action)} + +
+ + {record.action_by} +
+
+ {record.action_time} + {getResultBadge(record.result)} + + + +
+ )) + )} +
+
+
+ + {/* Pagination */} + {state.pagination.totalPages > 1 && ( +
+
+ 显示第 {state.pagination.page} 页,共 {state.pagination.totalPages} 页 + 总计 {state.pagination.total} 条记录 +
+
+ + + {state.pagination.page} / {state.pagination.totalPages} + + +
+
+ )} +
+ )} + + {/* Detail Dialog */} + dispatch({ type: 'TOGGLE_DETAIL_DIALOG', payload: open })}> + + + 审核记录详情 + + 查看审核记录的详细信息和企业快照数据 + + + + {state.selectedRecord && ( + + + + + + 基本信息 + + + + 企业快照 + + + + 系统信息 + + + + {/* 基本信息 */} + +
+
+ +
{state.selectedRecord.snapshot_company_name}
+
+
+ +
{getActionBadge(state.selectedRecord.action)}
+
+
+ +
{state.selectedRecord.action_by}
+
+
+ +
{state.selectedRecord.action_time}
+
+
+ +
{getResultBadge(state.selectedRecord.result)}
+
+
+ +
+ {state.selectedRecord.action_summary || '-'} +
+
+
+
+ + {/* 企业快照 */} + +
+
+ +
{state.selectedRecord.snapshot_company_type || '-'}
+
+
+ +
+ {state.selectedRecord.snapshot_province} {state.selectedRecord.snapshot_city} +
+
+
+ +
{state.selectedRecord.snapshot_address || '-'}
+
+
+ +
{state.selectedRecord.snapshot_registrant || '-'}
+
+
+ +
{state.selectedRecord.snapshot_contact_phone || '-'}
+
+
+
+ + {/* 系统信息 */} + +
+
+ +
+ {state.selectedRecord.id} +
+
+
+ +
+ {state.selectedRecord.tenant_id} +
+
+
+ +
{state.selectedRecord.ip_address || '-'}
+
+
+ +
+ {state.selectedRecord.user_agent || '-'} +
+
+
+
+
+
+ )} + + + + +
+
); } \ No newline at end of file diff --git a/crop-x/src/app/(app)/central-config/tenant/audit-history/page.tsx.tmp b/crop-x/src/app/(app)/central-config/tenant/audit-history/page.tsx.tmp new file mode 100644 index 0000000..73be5d9 --- /dev/null +++ b/crop-x/src/app/(app)/central-config/tenant/audit-history/page.tsx.tmp @@ -0,0 +1,525 @@ +/** + * filekorolheader: 审核历史 - 企业审核记录查询与详情查看页面 + * 功能:审核历史查询、筛选过滤、详情查看、数据导出、分页控制 + * 路径:/central-config/tenant/audit-history + * 规范:遵循crop-x/docs/开发项目规范.md,使用useReducer状态管理,API集成,shadcn语义化样式 + */ +'use client'; + +import { useReducer, useEffect, useMemo } from 'react'; +import { Card } from '@/components/ui/card'; +import { Button } from '@/components/ui/button'; +import { Badge } from '@/components/ui/badge'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog'; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; +import { ScrollArea } from '@/components/ui/scroll-area'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { + History, + Download, + Search, + Eye, + AlertCircle, + ChevronLeft, + ChevronRight, + Calendar, + Clock, + User, + FileText, + Building2, + MapPin, + CreditCard, + Phone +} from 'lucide-react'; +import { toast } from 'sonner'; + +import { auditHistoryReducer, initialState, AuditHistoryState, AuditHistoryAction } from './components/auditHistoryReducer'; +import { fetchAuditLogs, transformAuditLogData, AuditLogsQueryParams } from './components/auditHistoryApi'; +import { AuditRecord, FilterOptions, AuditStatus } from './types'; + +// Utility functions +const getStatusBadge = (status: AuditStatus) => { + switch (status) { + case 'draft': + return 草稿; + case 'pending': + return 待审核; + case 'approved': + return 审核通过; + case 'rejected': + return 审核拒绝; + default: + return 未知; + } +}; + +const getActionBadge = (action: string) => { + if (action === 'SUBMIT') { + return 提交; + } else if (action === 'AUDIT') { + return 审核; + } + return {action}; +}; + +export default function AuditHistoryPage() { + const [state, dispatch] = useReducer(auditHistoryReducer, initialState); + + // 加载审核历史数据 + const loadAuditHistory = async (resetPage = false) => { + try { + dispatch({ type: 'SET_LOADING', payload: true }); + + const params: AuditLogsQueryParams = { + page: resetPage ? 1 : state.pagination.page, + size: state.pagination.size, + order_by: state.sortBy, + sort_order: state.sortOrder, + }; + + const response = await fetchAuditLogs(params); + const transformedData = response.data.map(transformAuditLogData); + + console.log('Audit Logs API Response:', response); + console.log('Transformed Audit Data:', transformedData); + + dispatch({ + type: 'SET_RECORDS', + payload: { + data: transformedData, + pagination: { + page: response.page, + size: response.size, + total: response.total, + totalPages: response.total_pages, + hasNext: response.has_next, + hasPrev: response.has_prev, + } + } + }); + } catch (error) { + console.error('Failed to load audit history:', error); + const errorMessage = error instanceof Error ? error.message : '加载审核历史失败'; + dispatch({ type: 'SET_ERROR', payload: errorMessage }); + toast.error(errorMessage); + } + }; + + // 初始加载 + useEffect(() => { + loadAuditHistory(true); + }, [state.sortBy, state.sortOrder]); + + // 分页加载 + useEffect(() => { + if (state.pagination.page > 1) { + loadAuditHistory(false); + } + }, [state.pagination.page]); + + // 计算统计数据 - 按照参考组件的顺序 + const stats = useMemo(() => [ + { + label: '审核总数', + value: state.records.length, + color: 'text-blue-600 dark:text-blue-400', + bg: 'bg-blue-50 dark:bg-blue-950', + borderColor: 'border-blue-200 dark:border-blue-800', + }, + { + label: '已通过', + value: state.records.filter(r => r.result === 'approved').length, + color: 'text-green-600 dark:text-green-400', + bg: 'bg-green-50 dark:bg-green-950', + borderColor: 'border-green-200 dark:border-green-800', + }, + { + label: '已驳回', + value: state.records.filter(r => r.result === 'rejected').length, + color: 'text-red-600 dark:text-red-400', + bg: 'bg-red-50 dark:bg-red-950', + borderColor: 'border-red-200 dark:border-red-800', + }, + { + label: '待审核', + value: state.records.filter(r => r.result === 'pending').length, + color: 'text-yellow-600 dark:text-yellow-400', + bg: 'bg-yellow-50 dark:bg-yellow-950', + borderColor: 'border-yellow-200 dark:border-yellow-800', + }, + ], [state.records]); + + // 筛选记录 + const filteredRecords = useMemo(() => { + return state.records.filter(record => { + const matchKeyword = !state.filters.searchKeyword || + record.enterpriseName.toLowerCase().includes(state.filters.searchKeyword.toLowerCase()) || + record.changeSummary.toLowerCase().includes(state.filters.searchKeyword.toLowerCase()); + + const matchResult = state.filters.resultFilter === 'all' || record.result === state.filters.resultFilter; + const matchType = state.filters.typeFilter === 'all' || record.auditType === state.filters.typeFilter; + + // 日期筛选 + let matchDate = true; + if (state.filters.dateRange !== 'all' && record.actionTime) { + const auditDate = new Date(record.actionTime); + const now = new Date(); + const diffDays = Math.floor((now.getTime() - auditDate.getTime()) / (1000 * 60 * 60 * 24)); + + switch (state.filters.dateRange) { + case 'today': + matchDate = diffDays === 0; + break; + case 'week': + matchDate = diffDays <= 7; + break; + case 'month': + matchDate = diffDays <= 30; + break; + case 'quarter': + matchDate = diffDays <= 90; + break; + } + } + + return matchKeyword && matchResult && matchType && matchDate; + }); + }, [state.records, state.filters]); + + // 事件处理器 + const handleSearch = (value: string) => { + dispatch({ type: 'SET_FILTERS', payload: { searchKeyword: value } }); + }; + + const handleResultFilter = (value: string) => { + dispatch({ type: 'SET_FILTERS', payload: { resultFilter: value } }); + }; + + const handleTypeFilter = (value: string) => { + dispatch({ type: 'SET_FILTERS', payload: { typeFilter: value } }); + }; + + const handleDateFilter = (value: string) => { + dispatch({ type: 'SET_FILTERS', payload: { dateRange: value } }); + }; + + const handleSort = (sortBy?: string) => { + const newSortOrder = state.sortBy === sortBy && state.sortOrder === 'desc' ? 'asc' : 'desc'; + dispatch({ type: 'SET_SORT', payload: { sortBy, sortOrder: newSortOrder } }); + }; + + const handlePageChange = (page: number) => { + // 边界检查 + if (page < 1) { + page = 1; + } else if (page > state.pagination.totalPages && state.pagination.totalPages > 0) { + page = state.pagination.totalPages; + } + dispatch({ type: 'SET_PAGINATION', payload: { page } }); + }; + + const handleViewDetail = (record: AuditRecord) => { + dispatch({ type: 'SET_SELECTED_RECORD', payload: record }); + dispatch({ type: 'TOGGLE_DETAIL_DIALOG', payload: true }); + }; + + const handleExport = () => { + const exportData = filteredRecords.map(record => ({ + 企业名称: record.enterpriseName, + 操作类型: record.action === 'SUBMIT' ? '提交' : '审核', + 审核类型: record.auditType === 'register' ? '注册' : '更新', + 操作时间: record.actionTime, + 操作人: record.actionBy, + 审核结果: record.result === 'approved' ? '审核通过' : + record.result === 'rejected' ? '审核拒绝' : + record.result === 'pending' ? '待审核' : '草稿', + 变更摘要: record.changeSummary, + })); + + const dataStr = JSON.stringify(exportData, null, 2); + const dataBlob = new Blob([dataStr], { type: 'application/json' }); + const url = URL.createObjectURL(dataBlob); + const link = document.createElement('a'); + link.href = url; + link.download = `audit_history_${new Date().getTime()}.json`; + link.click(); + toast.success('审核历史数据导出成功'); + }; + + return ( +
+ {/* Page Header */} + +
+
+ +
+

审核历史

+

+ 追溯查询全部企业的历史审核记录 +

+
+ + + 智能查询 + + + + 时间筛选 + + + + 详情查看 + +
+
+
+
+ +
+
+
+ + {/* Statistics Cards */} +
+ {stats.map((stat, index) => ( + +
+
{stat.label}
+ +
+
{stat.value}
+
+ 条记录 +
+
+ ))} +
+ + {/* Filters */} + +
+
+ +
+ + handleSearch(e.target.value)} + className="pl-10" + /> +
+
+ +
+
+ + +
+ +
+ + +
+ +
+
+
+ + {/* Time Range Filter */} + + +
+ {[ + { value: 'all', label: '全部' }, + { value: 'today', label: '今天' }, + { value: 'week', label: '近7天' }, + { value: 'month', label: '近30天' }, + { value: 'quarter', label: '近90天' }, + ].map((option) => ( + + ))} +
+
+ + {/* Error Display */} + {state.error && ( +
+
+ + {state.error} +
+
+ )} + + {/* Loading State */} + {state.loading && ( +
+ +

加载中...

+
+ )} + + {/* Data Table */} + {!state.loading && !state.error && ( + <> +
+ + + + handleSort('enterprise_name')} + > + 企业名称 + {state.sortBy === 'enterprise_name' && ( + {state.sortOrder === 'asc' ? '↑' : '↓'} + )} + + handleSort('action')} + > + 操作类型 + {state.sortBy === 'action' && ( + {state.sortOrder === 'asc' ? '↑' : '↓'} + )} + + 操作人 + handleSort('action_time')} + > + 操作时间 + {state.sortBy === 'action_time' && ( + {state.sortOrder === 'asc' ? '↑' : '↓'} + )} + + 审核结果 + 变更摘要 + 操作 + + + + {filteredRecords.map((record) => ( + + +
+ + {record.enterpriseName} +
+
+ +
+ {getActionBadge(record.action)} + {record.auditType === 'register' && ( + 注册 + )} + {record.auditType === 'update' && ( + 更新 + )} +
+
+ +
+ + {record.actionBy} +
+
+ {record.actionTime} + {getStatusBadge(record.result)} + + {record.changeSummary} + + + + +
+ ))} +
+
+
+ + {filteredRecords.length === 0 && ( +
+ +

暂无审核历史记录

+
+ )} + + {/* Pagination */} + {state.pagination.totalPages > 1 && ( +
+
+ 显示第 {state.pagination.page} 页,共 {state.pagination.totalPages} 页 + 总计 {state.pagination.total} 条记录 +
+
+ + + {state.pagination.page} / {state.pagination.totalPages} + + +
+
+ )} + + )} + diff --git a/crop-x/src/app/(app)/central-config/tenant/audit-history/types.ts b/crop-x/src/app/(app)/central-config/tenant/audit-history/types.ts index 98b709e..d2007a9 100644 --- a/crop-x/src/app/(app)/central-config/tenant/audit-history/types.ts +++ b/crop-x/src/app/(app)/central-config/tenant/audit-history/types.ts @@ -46,20 +46,48 @@ export interface Enterprise { } export type EnterpriseStatus = 'active' | 'inactive' | 'suspended'; -export type AuditStatus = 'pending' | 'approved' | 'rejected'; +export type AuditStatus = 'pending' | 'approved' | 'rejected' | 'draft'; -// 审核记录 +// 审核记录(基于API响应结构) export interface AuditRecord { id: string; - enterpriseId: string; + enterpriseId?: string; enterpriseName: string; + action: 'SUBMIT' | 'AUDIT'; auditType: 'register' | 'update'; submitTime: string; - auditTime?: string; - auditor?: string; + actionTime: string; + actionBy: string; result: AuditStatus; - reason?: string; - remarks?: string; + auditStatus: string; + auditComment?: string; + changeSummary: string; + ipAddress?: string; + userAgent?: string; + requestId?: string; + createdAt: string; + + // 快照数据 + snapshot: { + companyName: string; + companyType: string | null; + province: string | null; + city: string | null; + district: string | null; + detailedAddress: string | null; + registrant: string | null; + contactPhone: string | null; + bankAccount: string | null; + bankName: string | null; + bankFullName: string | null; + bankAddress: string | null; + socialCreditCode: string | null; + legalPersonName: string | null; + auditStatus: string; + auditComment: string | null; + companyScale: string | null; + registeredCapital: string | null; + }; } // 统计数据 diff --git a/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/AuditPagination.tsx b/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/AuditPagination.tsx new file mode 100644 index 0000000..22782c1 --- /dev/null +++ b/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/AuditPagination.tsx @@ -0,0 +1,83 @@ +/** + * filekorolheader: 企业审核分页组件 - 分页控制界面 + * 功能:分页导航、页面跳转、分页信息展示 + * 路径:/central-config/tenant/enterprise-audit/components/AuditPagination + * 规范:遵循crop-x/docs/开发项目规范.md,使用shadcn/ui组件,TypeScript类型安全 + */ + +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { ChevronLeft, ChevronRight } from 'lucide-react'; + +interface PaginationInfo { + page: number; + size: number; + total: number; + totalPages: number; + hasNext: boolean; + hasPrev: boolean; +} + +interface AuditPaginationProps { + pagination: PaginationInfo; + onPageChange: (page: number) => void; + loading?: boolean; +} + +export function AuditPagination({ + pagination, + onPageChange, + loading = false +}: AuditPaginationProps) { + const { page, size, total, totalPages, hasNext, hasPrev } = pagination; + + if (total === 0) return null; + + return ( +
+
+ 显示第 {(page - 1) * size + 1} - {Math.min(page * size, total)} 条,共 {total} 条记录 +
+
+ + +
+ + { + const newPage = parseInt(e.target.value); + if (!isNaN(newPage)) { + onPageChange(newPage); + } + }} + className="w-16 h-8 text-center" + disabled={loading} + /> + / {totalPages} 页 +
+ + +
+
+ ); +} \ No newline at end of file diff --git a/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/AuditSearchAndFilter.tsx b/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/AuditSearchAndFilter.tsx new file mode 100644 index 0000000..c04b3a6 --- /dev/null +++ b/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/AuditSearchAndFilter.tsx @@ -0,0 +1,68 @@ +/** + * filekorolheader: 企业审核搜索筛选组件 - 搜索和筛选功能界面 + * 功能:关键词搜索、状态筛选、搜索功能实现 + * 路径:/central-config/tenant/enterprise-audit/components/AuditSearchAndFilter + * 规范:遵循crop-x/docs/开发项目规范.md,使用shadcn/ui组件,TypeScript类型安全 + */ + +import { Card } from '@/components/ui/card'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { Search, RotateCcw } from 'lucide-react'; + +interface AuditSearchAndFilterProps { + searchKeyword: string; + onSearchChange: (keyword: string) => void; + statusFilter: string; + onStatusFilterChange: (status: string) => void; + onRefresh: () => void; + loading?: boolean; +} + +export function AuditSearchAndFilter({ + searchKeyword, + onSearchChange, + statusFilter, + onStatusFilterChange, + onRefresh, + loading = false +}: AuditSearchAndFilterProps) { + return ( + +
+
+
+ + onSearchChange(e.target.value)} + className="pl-10" + /> +
+
+ + +
+
+ ); +} \ No newline at end of file diff --git a/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/AuditStatsCards.tsx b/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/AuditStatsCards.tsx index 17114d9..3fa4fae 100644 --- a/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/AuditStatsCards.tsx +++ b/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/AuditStatsCards.tsx @@ -1,30 +1,38 @@ -'use client'; +/** + * filekorolheader: 企业审核统计卡片组件 - 统计数据展示界面 + * 功能:待审核、已通过、已驳回、总企业数统计展示 + * 路径:/central-config/tenant/enterprise-audit/components/AuditStatsCards + * 规范:遵循crop-x/docs/开发项目规范.md,使用shadcn/ui组件,TypeScript类型安全 + */ -import React from 'react'; +import { Enterprise } from './enterpriseAuditApi'; import { Card } from '@/components/ui/card'; -import { AuditStats, Enterprise } from '../types'; interface AuditStatsCardsProps { enterprises: Enterprise[]; + loading?: boolean; } -export function AuditStatsCards({ enterprises }: AuditStatsCardsProps) { - const stats: AuditStats[] = [ +export function AuditStatsCards({ + enterprises, + loading = false +}: AuditStatsCardsProps) { + const stats = [ { label: '待审核', - value: enterprises.filter(e => e.auditStatus === 'pending').length, + value: enterprises.filter(e => e.auditStatus === '待审核').length, color: 'text-yellow-600', bg: 'bg-yellow-100', }, { label: '已通过', - value: enterprises.filter(e => e.auditStatus === 'approved').length, + value: enterprises.filter(e => e.auditStatus === '已通过').length, color: 'text-green-600', bg: 'bg-green-100', }, { label: '已驳回', - value: enterprises.filter(e => e.auditStatus === 'rejected').length, + value: enterprises.filter(e => e.auditStatus === '已驳回').length, color: 'text-red-600', bg: 'bg-red-100', }, @@ -36,12 +44,27 @@ export function AuditStatsCards({ enterprises }: AuditStatsCardsProps) { }, ]; + if (loading) { + return ( +
+ {stats.map((_, index) => ( + +
+
+
+
+
+ ))} +
+ ); + } + return (
{stats.map((stat, index) => (
{stat.label}
-
{stat.value}
+
{stat.value}
))}
diff --git a/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/EnterpriseAuditTable.tsx b/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/EnterpriseAuditTable.tsx new file mode 100644 index 0000000..5f544e7 --- /dev/null +++ b/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/EnterpriseAuditTable.tsx @@ -0,0 +1,121 @@ +/** + * filekorolheader: 企业审核表格组件 - 企业数据列表展示和管理界面 + * 功能:企业数据表格展示、搜索过滤、分页管理、操作按钮 + * 路径:/central-config/tenant/enterprise-audit/components/EnterpriseAuditTable + * 规范:遵循crop-x/docs/开发项目规范.md,使用shadcn/ui组件,TypeScript类型安全 + */ + +import { Enterprise } from './enterpriseAuditApi'; +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import { Card } from '@/components/ui/card'; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; +import { Eye } from 'lucide-react'; + +interface EnterpriseAuditTableProps { + enterprises: Enterprise[]; + loading: boolean; + onViewDetails: (enterprise: Enterprise) => void; +} + +export function EnterpriseAuditTable({ + enterprises, + loading, + onViewDetails +}: EnterpriseAuditTableProps) { + const getAuditStatusBadge = (status: Enterprise['auditStatus']) => { + switch (status) { + case '草稿': + return 草稿; + case '待审核': + return 待审核; + case '已通过': + return 已通过; + case '已驳回': + return 已驳回; + default: + return {status}; + } + }; + + const getStatusBadge = (status: Enterprise['status']) => { + return status === 'active' ? ( + 启用 + ) : ( + 禁用 + ); + }; + + if (loading) { + return ( + +
+
加载中...
+
+
+ ); + } + + return ( + + + + + 企业名称 + 企业类型 + 社会信用代码 + 法人 + 所在地区 + 审核状态 + 企业状态 + 提交时间 + 操作 + + + + {enterprises.length === 0 ? ( + + + 暂无数据 + + + ) : ( + enterprises.map((enterprise) => ( + + {enterprise.name} + {enterprise.type} + + + {enterprise.socialCreditCode} + + + {enterprise.legalPerson || '-'} + + {enterprise.province && enterprise.city ? + `${enterprise.province} ${enterprise.city}` : + '-' + } + + {getAuditStatusBadge(enterprise.auditStatus)} + {getStatusBadge(enterprise.status)} + + {enterprise.submitTime || '-'} + + + + + + )) + )} + +
+
+ ); +} \ No newline at end of file diff --git a/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/EnterpriseDetailDialog.tsx b/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/EnterpriseDetailDialog.tsx index c265b34..0d95208 100644 --- a/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/EnterpriseDetailDialog.tsx +++ b/crop-x/src/app/(app)/central-config/tenant/enterprise-audit/components/EnterpriseDetailDialog.tsx @@ -1,46 +1,54 @@ -'use client'; +/** + * filekorolheader: 企业详情对话框组件 - 企业详情展示和审核操作界面 + * 功能:企业详细信息展示、多标签页布局、审核操作界面 + * 路径:/central-config/tenant/enterprise-audit/components/EnterpriseDetailDialog + * 规范:遵循crop-x/docs/开发项目规范.md,使用shadcn/ui组件,TypeScript类型安全 + */ -import React from 'react'; -import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'; +import { Enterprise } from './enterpriseAuditApi'; +import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; +import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Card } from '@/components/ui/card'; -import { Badge } from '@/components/ui/badge'; -import { Building, FileText, CreditCard, User, CheckCircle, XCircle, Image as ImageIcon } from 'lucide-react'; -import { Enterprise, AuditStatus } from '../types'; +import { Building2, FileText, CreditCard, User, CheckCircle, XCircle } from 'lucide-react'; interface EnterpriseDetailDialogProps { - enterprise: Enterprise | null; open: boolean; onOpenChange: (open: boolean) => void; + enterprise: Enterprise | null; auditReason: string; onAuditReasonChange: (reason: string) => void; onApprove: () => void; onReject: () => void; + loading?: boolean; } export function EnterpriseDetailDialog({ - enterprise, open, onOpenChange, + enterprise, auditReason, onAuditReasonChange, onApprove, - onReject + onReject, + loading = false }: EnterpriseDetailDialogProps) { - const getAuditStatusBadge = (status: AuditStatus) => { + const getAuditStatusBadge = (status: Enterprise['auditStatus']) => { switch (status) { - case 'pending': + case '草稿': + return 草稿; + case '待审核': return 待审核; - case 'approved': + case '已通过': return 已通过; - case 'rejected': + case '已驳回': return 已驳回; default: - return {status}; + return {status}; } }; @@ -48,14 +56,16 @@ export function EnterpriseDetailDialog({ return ( - +
企业详情审核 - {getAuditStatusBadge(enterprise.auditStatus)} +
+ {getAuditStatusBadge(enterprise.auditStatus)} +
- 查看企业的详细信息和审核状态 + 查看企业的详细信息和进行审核操作
@@ -63,7 +73,7 @@ export function EnterpriseDetailDialog({ - + 基本信息 @@ -80,36 +90,103 @@ export function EnterpriseDetailDialog({ - {/* 企业基本信息 */} - -
-
- -
{enterprise.name}
-
-
- -
{enterprise.type}
-
-
- -
- {enterprise.province} {enterprise.city} {enterprise.district} + {/* 基本信息 */} + + {/* 企业基本信息 */} +
+

企业基本信息

+
+
+ +
{enterprise.name}
+
+
+ +
{enterprise.type}
+
+
+ +
+ {enterprise.province} {enterprise.city} {enterprise.district} +
+
+
+ +
{enterprise.address}
+
+
+ +
{enterprise.registrant}
+
+
+ +
{enterprise.contactPhone}
-
- -
{enterprise.address}
-
-
- -
{enterprise.registrant}
-
-
- -
{enterprise.contactPhone}
-
+ + {/* 审核信息 */} +
+

审核信息

+ +
+
+ +
{enterprise.createdAt}
+
+
+ +
{enterprise.updatedAt}
+
+ {enterprise.submitTime && ( +
+ +
{enterprise.submitTime}
+
+ )} + {enterprise.auditTime && ( +
+ +
{enterprise.auditTime}
+
+ )} + {enterprise.auditor && ( +
+ +
{enterprise.auditor}
+
+ )} + {enterprise.auditComment && ( +
+ +
+ {enterprise.auditComment} +
+
+ )} +
+
+
+ + {/* 审核操作区 - 仅待审核状态显示 */} + {enterprise.auditStatus === '待审核' && ( +
+

审核操作

+
+ +
+ 驳回时必填,通过时可选择性填写 +
+