From 54d138cc730946c98fa96c4adba0f87fec15d4ba Mon Sep 17 00:00:00 2001 From: selfrelease Date: Sun, 16 Aug 2026 15:10:38 +0800 Subject: [PATCH] =?UTF-8?q?ux:=20=E6=96=B0=E5=BB=BA=E8=B4=A6=E6=88=B7?= =?UTF-8?q?=E6=8C=89=E9=92=AE=E7=A7=BB=E5=88=B0=E7=A4=BE=E4=BF=9D/?= =?UTF-8?q?=E5=85=AC=E7=A7=AF=E9=87=91Tab=E5=86=85=E9=83=A8=EF=BC=8C?= =?UTF-8?q?=E6=8C=89=E7=B1=BB=E5=9E=8B=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按钮从页面顶部移到Tab内容区顶部,文案改为"新建社保账户"/"新建公积金账户", 明确表示新建的是当前Tab对应类型的账户。 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- 20260816-社保优化.md | 179 ++++++++++++++----------- frontend/src/pages/SocialInsurance.tsx | 13 +- 2 files changed, 109 insertions(+), 83 deletions(-) diff --git a/20260816-社保优化.md b/20260816-社保优化.md index 70717da..16257a4 100644 --- a/20260816-社保优化.md +++ b/20260816-社保优化.md @@ -3,44 +3,33 @@ > 目标:将社保公积金从"按城市直接关联版本"改为"账户 + 年度标准"两层实体。 > 账户代表用户开设的社保/公积金账户(对应不同子公司/分公司/地区),年度标准是账户下每个年度的缴费比例和基数标准。 +> **状态:已完成实施**(2026-08-16) +> 账户+年度标准模型已上线,前端已重构为账户卡片列表+展开年度标准管理。 + --- ## 一、现状分析 -### 当前数据模型 +### 当前数据模型(已重构) | 表 | 说明 | 唯一约束 | |----|------|---------| -| `SocialInsuranceConfig` | 社保版本(比例+基数+生效月份),按 orgId+city+effectiveFrom | `@@unique([orgId, city, effectiveFrom])` | -| `HousingFundConfig` | 公积金版本,按 orgId+city+accountType+effectiveFrom | `@@unique([orgId, city, accountType, effectiveFrom])` | -| `EmployeeSocialInsRecord` | 员工社保参保记录,字段含 city | `@@index([orgId, city])` | -| `EmployeeHousingFundRecord` | 员工公积金参保记录,字段含 city | 无 city 索引 | +| `SocialAccount` | 社保/公积金账户实体(type=SOCIAL/HOUSING) | `@@unique([orgId, type, name])` | +| `SocialYearStandard` | 年度标准(比例+基数+最低工资+生效月份),关联到账户 | `@@unique([accountId, effectiveFrom])` | +| `SocialInsuranceConfig` | 旧社保版本表(保留兼容,回退用) | `@@unique([orgId, city, effectiveFrom])` | +| `HousingFundConfig` | 旧公积金版本表(保留兼容) | — | +| `EmployeeSocialInsRecord` | 员工社保参保记录,已加 accountId | — | +| `EmployeeHousingFundRecord` | 员工公积金参保记录,已加 accountId | — | | `SocialMonthlyProcess` | 月度办理记录 | `@@unique([orgId, month, type])` | -### 当前问题 +### 已解决的问题 -1. **"城市"只是字符串**:无实体化管理,无法记录账户编号、开户行、缴费主体等 -2. **多子公司/分公司场景缺失**:同一城市可能有多个社保账户(不同主体分别开户),当前按 city 唯一无法支持 -3. **版本直接挂在 orgId+city 上**:缺少"账户"这一层抽象,无法区分同一城市不同主体的账户 -4. **员工参保记录只有 city**:无法精确关联到具体哪个社保账户 -5. **薪资计算中社保配置查询**:按 orgId+city 查 SocialInsuranceConfig,无法按账户区分 - -### 涉及"关联城市"的代码位置 - -| 文件 | 位置 | 说明 | -|------|------|------| -| `backend/prisma/schema.prisma` | `SocialInsuranceConfig.city` | 社保配置按城市区分 | -| `backend/prisma/schema.prisma` | `HousingFundConfig.city` | 公积金配置按城市区分 | -| `backend/prisma/schema.prisma` | `EmployeeSocialInsRecord.city` | 员工社保参保城市 | -| `backend/prisma/schema.prisma` | `EmployeeHousingFundRecord.city` | 员工公积金参保城市 | -| `backend/src/routes/social.routes.ts` | 全文 | 社保配置 CRUD/版本/城市列表/月度办理 均按 city | -| `backend/src/services/payroll.service.ts` | 社保计算逻辑 | 按 city 查 SocialInsuranceConfig | -| `backend/src/routes/payroll2.routes.ts` | 批次计算 | 社保配置查询 | -| `backend/src/routes/roster.routes.ts` | socialInsuranceStatus 派生 | 按 city 判定 | -| `backend/src/services/contract.service.ts` | createEmployee | 社保记录创建时关联 city | -| `frontend/src/pages/SocialInsurance.tsx` | 全文 | 城市选择器、版本管理、月度办理 | -| `frontend/src/pages/roster/modals.tsx` | 社保公积金区 | 员工参保城市 | -| `frontend/src/pages/Settings.tsx` | 社保配置 | 需新增账户管理入口 | +1. ✅ **"城市"只是字符串** → 已改为 SocialAccount 实体化管理 +2. ✅ **多子公司/分公司场景缺失** → 同一城市可有多个账户,按根部门关联 +3. ✅ **版本直接挂在 orgId+city 上** → 改为 SocialYearStandard 关联到 accountId +4. ✅ **员工参保记录只有 city** → 已加 accountId 字段 +5. ✅ **薪资计算中社保配置查询** → 改为按 accountId 查 SocialYearStandard,旧表回退 +6. ✅ **最低工资标准** → SocialYearStandard 新增 minWage 字段,支持最低工资保护和递延扣款 --- @@ -73,6 +62,10 @@ model SocialAccount { socialRecords EmployeeSocialInsRecord[] housingRecords EmployeeHousingFundRecord[] + // 部门关联(根部门 level=0 代表分公司/子公司) + deptSocialAccounts Department[] @relation("SocialAccountDepartments") + deptHousingAccounts Department[] @relation("HousingAccountDepartments") + @@unique([orgId, type, name]) @@index([orgId, type, city]) @@index([orgId, type, isDefault]) @@ -104,6 +97,9 @@ model SocialYearStandard { medicalBaseMax Float @default(0) extraInsurances Json? + // 最低工资标准(仅社保,20260816新增) + minWage Float @default(0) // 当地月最低工资标准,0=不检查 + // 公积金比例(type=HOUSING 时使用) housingOrg Float @default(12) housingEmp Float @default(12) @@ -248,7 +244,7 @@ JOIN "SocialAccount" a ON a."orgId" = c."orgId" AND a.city = c.city AND a.type = ## 四、后端 API 变更 -### 新增:账户管理 API +### 新增:账户管理 API(已实施) | 方法 | 路径 | 说明 | |------|------|------| @@ -257,15 +253,24 @@ JOIN "SocialAccount" a ON a."orgId" = c."orgId" AND a.city = c.city AND a.type = | PUT | `/social/accounts/:id` | 编辑账户 | | DELETE | `/social/accounts/:id` | 删除账户(无关联记录时可删) | | PUT | `/social/accounts/:id/default` | 设为默认账户 | +| PUT | `/social/accounts/:id/departments` | 账户关联根部门(批量) | +| GET | `/social/accounts/:id/departments` | 获取账户已关联的根部门 | -### 改造:年度标准 API(原版本 API) +### 新增:年度标准 API(已实施) -| 方法 | 路径 | 说明 | 变更 | -|------|------|------|------| -| GET | `/social/config` | 获取当前标准 | 改为按 accountId 查询 | -| GET | `/social/config/versions` | 版本列表 | 改为按 accountId 查询 | -| POST | `/social/config/versions` | 新建版本 | 改为按 accountId 创建 | -| GET | `/social/config/by-month/:month` | 按月查标准 | 改为按 accountId+month 查询 | +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/social/accounts/:accountId/standards` | 账户的年度标准列表 | +| GET | `/social/accounts/:accountId/current-standard` | 账户的当前生效标准 | +| GET | `/social/accounts/:accountId/standard-by-month/:month` | 按账户+月份获取适用标准 | +| POST | `/social/accounts/:accountId/standards` | 新建年度标准(旧版本自动归档) | +| PUT | `/social/accounts/:accountId/min-wage` | 快速更新当前标准的最低工资 | + +### 改造:薪资计算(已实施) + +- `payroll.service.ts` 中社保配置查询:从 `orgId + city` 改为通过员工→根部门→账户→年度标准 +- 员工参保记录查询:从 `employeeId + city` 改为 `employeeId + accountId` +- 新增最低工资保护和递延扣款逻辑(详见 20260816-薪税管理逻辑.md 第十五章) ### 废弃:城市相关 API @@ -285,30 +290,36 @@ JOIN "SocialAccount" a ON a."orgId" = c."orgId" AND a.city = c.city AND a.type = --- -## 五、前端 UI 变更 +## 五、前端 UI 变更(已实施) -### 1. 设置页新增"社保公积金账户管理" +### 1. 社保公积金菜单(SocialInsurance.tsx)— 已重构 -- 账户列表(按 type 分社保/公积金 Tab) -- 每个账户卡片:名称、城市、账户编号、缴费主体、关联范围(公司/分公司/子公司)、是否默认 -- 新增/编辑/停用账户弹窗 -- **关联级别**:公司(Organization)或根部门(Department level=0,代表分公司/子公司),不向下到普通部门 -- 员工通过所属根部门自动继承账户,未关联根部门的员工使用公司默认账户 +**社保/公积金 Tab**(20260816 重构): +- ~~原城市选择器 → 改为账户选择器~~ → 已改为**账户卡片列表 + 展开年度标准管理** +- 每个账户卡片:名称、城市、账号、关联部门数、参保记录数 +- 卡片可展开/折叠(ChevronDown/ChevronRight 图标) +- 展开后显示: + - 当前年度标准(比例/基数/最低工资) + - 最低工资快速编辑(仅社保,Input + 保存按钮) + - 操作按钮:新建年度标准 | 批量调基 | 查看历史 + - 新建年度标准弹窗(原"新建版本"改名,保留 AI 建议、附加险种配置) + - 版本历史展示 + - 调基预览(保留原有展示和编辑逻辑) + - 试算工具(使用该账户的城市配置) +- 顶部"新建账户"按钮(账户新建/编辑/删除/设默认已从设置页面迁移到此) +- 新增组件:`AccountCard.tsx`(账户卡片+展开内容)、`AccountFormModal.tsx`(账户新建/编辑弹窗) -### 2. SocialInsurance.tsx 改造 +**月度办理 Tab**:保留不变 -**社保/公积金 Tab**: -- 原城市选择器 → 改为**账户选择器**(下拉,显示"账户名称 - 城市") -- 选中账户后展示该账户下的年度标准(当前版本 + 历史版本) -- 年度标准展示比例和基数(与现在版本展示一致) +**员工参保 Tab**:保留不变 -**月度办理 Tab**: -- 按账户分别办理 -- 选择账户 → 获取该账户的增减员名单 → 确认办理 +**专项附加扣除 Tab**:保留不变 -**员工参保 Tab**: -- 员工参保记录展示关联的账户名称 -- 新增参保时选择账户(而非仅选城市) +### 2. 设置页面(Settings.tsx)— 已简化 + +- ~~新增"社保公积金账户管理"Tab~~ → 已去掉该 Tab +- 账户管理全部移到社保公积金菜单中完成 +- SocialAccountSettings 和 AccountFormModal 组件定义保留在文件中(不再显示) ### 3. 员工表单(roster/modals.tsx) @@ -354,34 +365,48 @@ JOIN "SocialAccount" a ON a."orgId" = c."orgId" AND a.city = c.city AND a.type = --- -## 七、实施计划 +## 七、实施计划与完成状态 -### 第一步:DB schema + 迁移脚本 -- 新增 SocialAccount、SocialYearStandard 表 -- 员工记录表加 accountId 字段(可空) -- 编写并执行迁移脚本 -- 验证数据完整性 +### 第一步:DB schema + 迁移脚本 ✅ 已完成 +- ✅ 新增 SocialAccount、SocialYearStandard 表 +- ✅ 员工记录表加 accountId 字段(可空) +- ✅ SocialYearStandard 新增 minWage 字段(最低工资标准) +- ✅ Department 表新增 socialAccountId / housingAccountId(根部门关联账户) +- ✅ 编写并执行迁移脚本 +- ✅ 验证数据完整性 -### 第二步:后端 API 重构 -- 新增账户 CRUD API -- 年度标准 API 改为按 accountId -- 薪资计算适配 -- 员工参保记录适配 -- 保留旧 API 兼容(过渡期) +### 第二步:后端 API 重构 ✅ 已完成 +- ✅ 新增账户 CRUD API(`/social/accounts`) +- ✅ 年度标准 API 改为按 accountId(`/social/accounts/:accountId/standards`) +- ✅ 新增按账户获取当前标准 API(`/social/accounts/:accountId/current-standard`) +- ✅ 新增快速更新最低工资 API(`/social/accounts/:accountId/min-wage`) +- ✅ 薪资计算适配(payroll.service.ts 按 accountId 查标准,旧表回退) +- ✅ 员工参保记录适配 +- ✅ 保留旧 API 兼容(过渡期) -### 第三步:前端账户管理 -- 设置页新增账户管理 UI -- SocialInsurance.tsx 改为账户选择器 + 年度标准 +### 第三步:前端账户管理 ✅ 已完成 +- ✅ ~~设置页新增账户管理 UI~~ → 已移到社保公积金菜单 +- ✅ SocialInsurance.tsx 改为账户卡片列表 + 展开年度标准管理 +- ✅ 新建版本改名为"新建年度标准" +- ✅ 最低工资快速编辑(当前配置区域可直接编辑) +- ✅ 新增 AccountCard.tsx 组件(账户卡片+展开内容) +- ✅ 新增 AccountFormModal.tsx 组件(账户新建/编辑弹窗) -### 第四步:前端参保流程适配 -- 员工表单社保公积金区改为账户选择 -- 月度办理按账户分别办理 -- 员工参保记录展示账户名称 +### 第四步:前端参保流程适配 ✅ 已完成 +- ✅ 员工表单社保公积金区改为账户选择 +- ✅ 月度办理保留不变 +- ✅ 员工参保记录展示账户名称 -### 第五步:清理 -- 删除旧 SocialInsuranceConfig / HousingFundConfig 表 -- 删除旧 API -- 删除前端城市选择器残留代码 +### 第五步:清理 ⏳ 待执行 +- ⏳ 删除旧 SocialInsuranceConfig / HousingFundConfig 表 +- ⏳ 删除旧 API +- ⏳ 删除前端城市选择器残留代码 + +### 额外完成的功能(20260816) +- ✅ 最低工资保护与递延扣款机制(详见 20260816-薪税管理逻辑.md 第十五章) +- ✅ 最低工资保护支持当月累计实发判断(多批次场景) +- ✅ 预入职状态(PRE_ONBOARD),预入职员工不进入薪资批次 +- ✅ 薪资批次新增 payMonth(发薪年月)字段,支持提前发薪场景 --- diff --git a/frontend/src/pages/SocialInsurance.tsx b/frontend/src/pages/SocialInsurance.tsx index 7e81d48..ec8e6b3 100644 --- a/frontend/src/pages/SocialInsurance.tsx +++ b/frontend/src/pages/SocialInsurance.tsx @@ -175,11 +175,6 @@ export default function SocialInsurance() {

维护社保、公积金、商业保险缴费基数、版本及月度记录

- {(tab === 'social' || tab === 'housing') && ( - - )} {/* Tab 切换 */} @@ -200,10 +195,16 @@ export default function SocialInsurance() { {/* ========== 社保 / 公积金 Tab:账户卡片列表 ========== */} {(tab === 'social' || tab === 'housing') && (
+ {/* 新建对应类型账户按钮 */} +
+ +
{accounts.length === 0 ? (
- 暂无{tab === 'housing' ? '公积金' : '社保'}账户,点击右上角「新建账户」创建 + 暂无{tab === 'housing' ? '公积金' : '社保'}账户,点击上方「新建{tab === 'housing' ? '公积金' : '社保'}账户」创建
) : (