From dd0e84a21934756dfe9bc255ce5f4867ee79c764 Mon Sep 17 00:00:00 2001 From: selfrelease Date: Sun, 16 Aug 2026 09:23:24 +0800 Subject: [PATCH] =?UTF-8?q?ux:=20=E9=83=A8=E9=97=A8=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=94=B9=E4=B8=BA=E4=B8=8B=E6=8B=89=E9=80=89?= =?UTF-8?q?=E6=8B=A9=EF=BC=88=E7=BB=84=E7=BB=87=E6=9E=B6=E6=9E=84=E9=83=A8?= =?UTF-8?q?=E9=97=A8=E6=A0=91=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将以下页面的部门输入框从 Input 改为 Select 下拉选择, 数据源为组织架构部门树(带层级缩进): 1. roster/modals.tsx - RehireModal 重新入职弹窗 2. roster/modals.tsx - AddEmployeeModal 添加员工弹窗 3. roster/BasicInfo.tsx - 编辑员工基本信息 4. Contracts.tsx - 合同管理新增员工弹窗 下拉选项从 /departments 接口获取,按树形结构展示, 提交时传部门名称字符串(保持后端兼容)。 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- frontend/src/pages/Contracts.tsx | 22 ++++++++++++++- frontend/src/pages/roster/BasicInfo.tsx | 18 +++++++++++- frontend/src/pages/roster/modals.tsx | 37 +++++++++++++++++++++++-- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/frontend/src/pages/Contracts.tsx b/frontend/src/pages/Contracts.tsx index a55cb84..832a86d 100644 --- a/frontend/src/pages/Contracts.tsx +++ b/frontend/src/pages/Contracts.tsx @@ -4,6 +4,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { Plus, Search, Paperclip, Trash2, X, FileText, Download } from 'lucide-react' import { toast } from 'sonner' import { rosterApi, employeeApi, attachmentApi } from '../lib/api-services' +import api from '../lib/api' import Card from '../components/ui/Card' import Button from '../components/ui/Button' import { Input, Label, Select } from '../components/ui/Input' @@ -217,6 +218,20 @@ function AddEmployeeModal({ open, onClose, onSubmit, loading, error }: { loading: boolean error: any }) { + // 拉取组织架构部门列表,用于部门下拉选择 + const { data: departments = [] } = useQuery({ + queryKey: ['departments'], + queryFn: () => api.get('/departments').then(r => r.data), + }) + // 构建部门树形下拉选项(带层级缩进) + const deptOptions: { id: string; label: string; level: number }[] = [] + const buildDeptOptions = (items: any[], parentId: string | null, level: number) => { + items.filter(d => d.parentId === parentId).sort((a, b) => a.sortOrder - b.sortOrder).forEach(d => { + deptOptions.push({ id: d.id, label: d.name, level }) + buildDeptOptions(items, d.id, level + 1) + }) + } + buildDeptOptions(departments, null, 0) const [form, setForm] = useState({ name: '', department: '', @@ -280,7 +295,12 @@ function AddEmployeeModal({ open, onClose, onSubmit, loading, error }: {
- setForm({ ...form, department: e.target.value })} placeholder="如:技术部" /> +
diff --git a/frontend/src/pages/roster/BasicInfo.tsx b/frontend/src/pages/roster/BasicInfo.tsx index be9710f..08b9a3c 100644 --- a/frontend/src/pages/roster/BasicInfo.tsx +++ b/frontend/src/pages/roster/BasicInfo.tsx @@ -5,6 +5,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" import { attachmentApi, employeeApi, socialInsuranceApi } from '../../lib/api-services' import { useConfirm } from '../../hooks/useConfirm' import { copyToClipboard } from '../../lib/clipboard' +import api from '../../lib/api' import Card from "../../components/ui/Card" import Button from "../../components/ui/Button" import { Input, Label, Select } from "../../components/ui/Input" @@ -58,6 +59,21 @@ export default function BasicInfo({ profile, employeeId, attachments }: { profil return `${(bytes / 1024 / 1024).toFixed(1)}MB` } + // 拉取组织架构部门列表,用于部门下拉选择 + const { data: departments = [] } = useQuery({ + queryKey: ['departments'], + queryFn: () => api.get('/departments').then(r => r.data), + }) + // 构建部门树形下拉选项(带层级缩进) + const deptOptions: { id: string; label: string; level: number }[] = [] + const buildDeptOptions = (items: any[], parentId: string | null, level: number) => { + items.filter(d => d.parentId === parentId).sort((a, b) => a.sortOrder - b.sortOrder).forEach(d => { + deptOptions.push({ id: d.id, label: d.name, level }) + buildDeptOptions(items, d.id, level + 1) + }) + } + buildDeptOptions(departments, null, 0) + const [form, setForm] = useState({ department: profile.department || '', position: profile.position || '', @@ -346,7 +362,7 @@ export default function BasicInfo({ profile, employeeId, attachments }: { profil
-
setForm({ ...form, department: e.target.value })} />
+
{form.gender === '女' && (
diff --git a/frontend/src/pages/roster/modals.tsx b/frontend/src/pages/roster/modals.tsx index d6cb15a..2ca5158 100644 --- a/frontend/src/pages/roster/modals.tsx +++ b/frontend/src/pages/roster/modals.tsx @@ -408,6 +408,20 @@ export function RehireModal({ employee, onClose, onSubmit, loading, error }: { }, staleTime: Infinity, }) + // 拉取组织架构部门列表,用于部门下拉选择 + const { data: departments = [] } = useQuery({ + queryKey: ['departments'], + queryFn: () => api.get('/departments').then(r => r.data), + }) + // 构建部门树形下拉选项(带层级缩进) + const deptOptions: { id: string; label: string; level: number }[] = [] + const buildDeptOptions = (items: any[], parentId: string | null, level: number) => { + items.filter(d => d.parentId === parentId).sort((a, b) => a.sortOrder - b.sortOrder).forEach(d => { + deptOptions.push({ id: d.id, label: d.name, level }) + buildDeptOptions(items, d.id, level + 1) + }) + } + buildDeptOptions(departments, null, 0) const defaultEndDate = (() => { const d = new Date() d.setFullYear(d.getFullYear() + 3) @@ -543,7 +557,12 @@ export function RehireModal({ employee, onClose, onSubmit, loading, error }: {
- setForm({ ...form, department: e.target.value })} placeholder="如:技术部" /> +
@@ -665,6 +684,20 @@ export function AddEmployeeModal({ onClose, onSubmit, loading, error }: { }, staleTime: Infinity, }) + // 拉取组织架构部门列表,用于部门下拉选择 + const { data: departments = [] } = useQuery({ + queryKey: ['departments'], + queryFn: () => api.get('/departments').then(r => r.data), + }) + // 构建部门树形下拉选项(带层级缩进) + const deptOptions: { id: string; label: string; level: number }[] = [] + const buildDeptOptions = (items: any[], parentId: string | null, level: number) => { + items.filter(d => d.parentId === parentId).sort((a, b) => a.sortOrder - b.sortOrder).forEach(d => { + deptOptions.push({ id: d.id, label: d.name, level }) + buildDeptOptions(items, d.id, level + 1) + }) + } + buildDeptOptions(departments, null, 0) const defaultEndDate = (() => { const d = new Date() d.setFullYear(d.getFullYear() + 3) @@ -872,7 +905,7 @@ export function AddEmployeeModal({ onClose, onSubmit, loading, error }: { {/* 基本信息 */}
setForm({ ...form, name: e.target.value })} placeholder="员工姓名" />
-
setForm({ ...form, department: e.target.value })} placeholder="如:技术部" />
+
setForm({ ...form, position: e.target.value })} placeholder="如:前端工程师" />
handleIdCardChange(e.target.value)} placeholder="18位" maxLength={18} />
{idCardDuplicate?.exists && (