import { useState, useRef } from 'react' import { usePageSize } from '../hooks/usePageSize' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { toast } from 'sonner' import { FileText, Plus, ChevronRight, CheckCircle, Clock, X, Bell, Upload } from 'lucide-react' import mammoth from 'mammoth' import { policiesApi } from '../lib/api-services' import Card from '../components/ui/Card' import Button from '../components/ui/Button' import EmptyState from '../components/ui/EmptyState' import Pagination from '../components/ui/Pagination' import PageGuide from '../components/ui/PageGuide' import QueryError from '../components/ui/QueryError' const STEP_LABELS: Record = { DRAFTING: '起草', DISCUSSION: '讨论', CONSULTATION: '协商', PUBLICATION: '公示', } const STEP_ORDER = ['DRAFTING', 'DISCUSSION', 'CONSULTATION', 'PUBLICATION'] /** * 规章制度民主程序管理页面 */ export default function Policies() { const queryClient = useQueryClient() const [showCreate, setShowCreate] = useState(false) const [selectedPolicy, setSelectedPolicy] = useState(null) const pageSize = usePageSize() const [page, setPage] = useState(1) const { data: listData, isLoading, isError, error, refetch } = useQuery({ queryKey: ['policies', page, pageSize], queryFn: async () => { return await policiesApi.list({ page, pageSize }) }, }) const list = listData?.items || [] const total = listData?.total || 0 const advanceMutation = useMutation({ mutationFn: ({ id, step, note }: { id: string; step: number; note?: string }) => policiesApi.advanceStep(id, step, note), onSuccess: () => { toast.success('流程步骤已推进') queryClient.invalidateQueries({ queryKey: ['policies'] }) // 刷新选中制度详情 if (selectedPolicy) { policiesApi.detail(selectedPolicy.id).then((res: any) => setSelectedPolicy(res)) } }, onError: (err: any) => toast.error(err?.response?.data?.error?.message || '操作失败'), }) return (
规章制度管理遵循民主程序四步法:起草 → 讨论 → 协商 → 公示。每一步均需记录参与人员、会议纪要及员工签字,确保制度合法有效。新建制度后按步骤推进,系统自动生成民主程序履行记录。

规章制度管理

民主程序四步法:起草 → 讨论 → 协商 → 公示

{isLoading ? (
加载中...
) : isError ? ( ) : !list || list.length === 0 ? ( ) : (
{list.map((p: any) => (
setSelectedPolicy(p)}>
{p.title} {p.status === 'PUBLISHED' ? ( 已生效 ) : ( {STEP_LABELS[STEP_ORDER[(p.democracyProgress?.currentStep || 1) - 1]] || '起草中'} )}
{p.content?.slice(0, 80) || '暂无内容'}
{STEP_ORDER.map((step, i) => { const currentStep = p.democracyProgress?.currentStep || 1 const isDone = i < currentStep - 1 || p.status === 'PUBLISHED' const isCurrent = i === currentStep - 1 && p.status !== 'PUBLISHED' return (
{isDone ? : } {STEP_LABELS[step]}
{i < STEP_ORDER.length - 1 && }
) })}
{p.status === 'PUBLISHED' && p.totalEmployees > 0 && (
员工签收:
0 ? Math.round((p.readCount / p.totalEmployees) * 100) : 0}%` }} />
{p.readCount}/{p.totalEmployees}
)}
))}
)} setPage(1)} /> {/* 详情弹窗 */} {selectedPolicy && (
setSelectedPolicy(null)}>
e.stopPropagation()}>

{selectedPolicy.title}

{selectedPolicy.content || '暂无内容'}
民主程序进度
{(selectedPolicy.democracyProgress?.steps || []).map((s: any, i: number) => { const isDone = s.status === 'COMPLETED' || (selectedPolicy.status === 'PUBLISHED') const isCurrent = s.status === 'IN_PROGRESS' && selectedPolicy.status !== 'PUBLISHED' return (
{isDone ? : } {s.name} · {s.description} {isCurrent && ( )}
{s.date && (
{s.status === 'COMPLETED' ? '完成时间' : '开始时间'}:{s.date} {s.note && 备注:{s.note}}
)}
) })}
{/* 阅读签收统计(仅已公示制度显示) */} {selectedPolicy.status === 'PUBLISHED' && ( )}
)} {/* 新建弹窗 */} {showCreate && ( setShowCreate(false)} onSuccess={() => { setShowCreate(false); queryClient.invalidateQueries({ queryKey: ['policies'] }) }} /> )}
) } function CreatePolicyModal({ onClose, onSuccess }: { onClose: () => void; onSuccess: () => void }) { const [title, setTitle] = useState('') const [content, setContent] = useState('') const [type, setType] = useState('RULES') const fileInputRef = useRef(null) const createMutation = useMutation({ mutationFn: () => policiesApi.create({ title, content, type }), onSuccess: () => { toast.success('制度已创建'); onSuccess() }, onError: (err: any) => toast.error(err?.response?.data?.error?.message || '创建失败'), }) return (
e.stopPropagation()}>

新建规章制度

setTitle(e.target.value)} className="w-full mt-1 px-3 py-2 text-sm border rounded-lg focus:outline-none focus:ring-2 focus:ring-primary" placeholder="如:考勤管理制度" />
{ const file = e.target.files?.[0] if (!file) return try { const arrayBuffer = await file.arrayBuffer() const result = await mammoth.convertToHtml({ arrayBuffer }) setContent(result.value) toast.success('文档导入成功') } catch { toast.error('文档解析失败,请确保为 .docx 格式') } e.target.value = '' }} /> 支持 .docx 格式,导入后转为 HTML