新增员工党员字段

This commit is contained in:
wkc
2026-04-17 11:04:52 +08:00
parent 3286795f98
commit 03a4acb63a
23 changed files with 453 additions and 68 deletions

View File

@@ -43,6 +43,10 @@ public class CcdiBaseStaff implements Serializable {
/** 入职时间 */ /** 入职时间 */
private Date hireDate; private Date hireDate;
/** 是否党员0-否 1-是 */
@TableField("is_party_member")
private Integer partyMember;
/** 状态 */ /** 状态 */
private String status; private String status;

View File

@@ -53,6 +53,10 @@ public class CcdiBaseStaffAddDTO implements Serializable {
/** 入职时间 */ /** 入职时间 */
private Date hireDate; private Date hireDate;
/** 是否党员0-否 1-是 */
@NotNull(message = "是否党员不能为空")
private Integer partyMember;
/** 状态 */ /** 状态 */
@NotBlank(message = "状态不能为空") @NotBlank(message = "状态不能为空")
private String status; private String status;

View File

@@ -52,6 +52,10 @@ public class CcdiBaseStaffEditDTO implements Serializable {
/** 入职时间 */ /** 入职时间 */
private Date hireDate; private Date hireDate;
/** 是否党员0-否 1-是 */
@NotNull(message = "是否党员不能为空")
private Integer partyMember;
/** 状态 */ /** 状态 */
private String status; private String status;

View File

@@ -63,8 +63,15 @@ public class CcdiBaseStaffExcel implements Serializable {
@ColumnWidth(15) @ColumnWidth(15)
private Date hireDate; private Date hireDate;
/** 是否党员 */
@ExcelProperty(value = "是否党员", index = 7)
@ColumnWidth(12)
@DictDropdown(dictType = "ccdi_yes_no_flag")
@Required
private Integer partyMember;
/** 状态 */ /** 状态 */
@ExcelProperty(value = "状态", index = 7) @ExcelProperty(value = "状态", index = 8)
@ColumnWidth(10) @ColumnWidth(10)
@DictDropdown(dictType = "ccdi_employee_status") @DictDropdown(dictType = "ccdi_employee_status")
@Required @Required

View File

@@ -44,6 +44,9 @@ public class CcdiBaseStaffVO implements Serializable {
/** 入职时间 */ /** 入职时间 */
private Date hireDate; private Date hireDate;
/** 是否党员0-否 1-是 */
private Integer partyMember;
/** 状态 */ /** 状态 */
private String status; private String status;

View File

@@ -32,6 +32,9 @@ public class ImportFailureVO {
@Schema(description = "年收入") @Schema(description = "年收入")
private BigDecimal annualIncome; private BigDecimal annualIncome;
@Schema(description = "是否党员0-否 1-是")
private Integer partyMember;
@Schema(description = "状态") @Schema(description = "状态")
private String status; private String status;

View File

@@ -320,6 +320,9 @@ public class CcdiBaseStaffImportServiceImpl implements ICcdiBaseStaffImportServi
if (StringUtils.isEmpty(addDTO.getPhone())) { if (StringUtils.isEmpty(addDTO.getPhone())) {
throw new RuntimeException("电话不能为空"); throw new RuntimeException("电话不能为空");
} }
if (addDTO.getPartyMember() == null) {
throw new RuntimeException("是否党员不能为空");
}
if (StringUtils.isEmpty(addDTO.getStatus())) { if (StringUtils.isEmpty(addDTO.getStatus())) {
throw new RuntimeException("状态不能为空"); throw new RuntimeException("状态不能为空");
} }
@@ -357,6 +360,9 @@ public class CcdiBaseStaffImportServiceImpl implements ICcdiBaseStaffImportServi
if (!"0".equals(addDTO.getStatus()) && !"1".equals(addDTO.getStatus())) { if (!"0".equals(addDTO.getStatus()) && !"1".equals(addDTO.getStatus())) {
throw new RuntimeException("状态只能填写'在职'或'离职'"); throw new RuntimeException("状态只能填写'在职'或'离职'");
} }
if (addDTO.getPartyMember() != 0 && addDTO.getPartyMember() != 1) {
throw new RuntimeException("是否党员只能填写'0'或'1'");
}
validateAnnualIncome(addDTO.getAnnualIncome(), "年收入"); validateAnnualIncome(addDTO.getAnnualIncome(), "年收入");
} }

View File

@@ -112,7 +112,7 @@ public class CcdiBaseStaffServiceImpl implements ICcdiBaseStaffService {
CcdiBaseStaff staff = baseStaffMapper.selectById(staffId); CcdiBaseStaff staff = baseStaffMapper.selectById(staffId);
CcdiBaseStaffVO vo = convertToVO(staff); CcdiBaseStaffVO vo = convertToVO(staff);
if (staff != null) { if (staff != null) {
vo.setAssetInfoList(assetInfoService.selectByFamilyId(staff.getIdCard()).stream().map(asset -> { vo.setAssetInfoList(assetInfoService.selectByFamilyIdAndPersonId(staff.getIdCard(), staff.getIdCard()).stream().map(asset -> {
CcdiAssetInfoVO assetInfoVO = new CcdiAssetInfoVO(); CcdiAssetInfoVO assetInfoVO = new CcdiAssetInfoVO();
BeanUtils.copyProperties(asset, assetInfoVO); BeanUtils.copyProperties(asset, assetInfoVO);
return assetInfoVO; return assetInfoVO;
@@ -131,6 +131,7 @@ public class CcdiBaseStaffServiceImpl implements ICcdiBaseStaffService {
@Transactional @Transactional
public int insertBaseStaff(CcdiBaseStaffAddDTO addDTO) { public int insertBaseStaff(CcdiBaseStaffAddDTO addDTO) {
validateAnnualIncome(addDTO.getAnnualIncome(), "年收入"); validateAnnualIncome(addDTO.getAnnualIncome(), "年收入");
validatePartyMember(addDTO.getPartyMember(), "是否党员");
// 检查员工ID唯一性 // 检查员工ID唯一性
if (baseStaffMapper.selectById(addDTO.getStaffId()) != null) { if (baseStaffMapper.selectById(addDTO.getStaffId()) != null) {
throw new RuntimeException("该员工ID已存在"); throw new RuntimeException("该员工ID已存在");
@@ -161,6 +162,7 @@ public class CcdiBaseStaffServiceImpl implements ICcdiBaseStaffService {
@Transactional @Transactional
public int updateBaseStaff(CcdiBaseStaffEditDTO editDTO) { public int updateBaseStaff(CcdiBaseStaffEditDTO editDTO) {
validateAnnualIncome(editDTO.getAnnualIncome(), "年收入"); validateAnnualIncome(editDTO.getAnnualIncome(), "年收入");
validatePartyMember(editDTO.getPartyMember(), "是否党员");
CcdiBaseStaff existing = baseStaffMapper.selectById(editDTO.getStaffId()); CcdiBaseStaff existing = baseStaffMapper.selectById(editDTO.getStaffId());
if (existing == null) { if (existing == null) {
throw new RuntimeException("员工不存在"); throw new RuntimeException("员工不存在");
@@ -291,4 +293,13 @@ public class CcdiBaseStaffServiceImpl implements ICcdiBaseStaffService {
} }
} }
private void validatePartyMember(Integer partyMember, String fieldLabel) {
if (partyMember == null) {
throw new RuntimeException(fieldLabel + "不能为空");
}
if (partyMember != 0 && partyMember != 1) {
throw new RuntimeException(fieldLabel + "只能填写'0'或'1'");
}
}
} }

View File

@@ -14,13 +14,14 @@
<result property="phone" column="phone"/> <result property="phone" column="phone"/>
<result property="annualIncome" column="annual_income"/> <result property="annualIncome" column="annual_income"/>
<result property="hireDate" column="hire_date"/> <result property="hireDate" column="hire_date"/>
<result property="partyMember" column="is_party_member"/>
<result property="status" column="status"/> <result property="status" column="status"/>
<result property="createTime" column="create_time"/> <result property="createTime" column="create_time"/>
</resultMap> </resultMap>
<select id="selectBaseStaffPageWithDept" resultMap="CcdiBaseStaffVOResult"> <select id="selectBaseStaffPageWithDept" resultMap="CcdiBaseStaffVOResult">
SELECT SELECT
e.staff_id, e.name, e.dept_id, e.id_card, e.phone, e.annual_income, e.hire_date, e.status, e.create_time, e.staff_id, e.name, e.dept_id, e.id_card, e.phone, e.annual_income, e.hire_date, e.is_party_member, e.status, e.create_time,
d.dept_name d.dept_name
FROM ccdi_base_staff e FROM ccdi_base_staff e
LEFT JOIN sys_dept d ON e.dept_id = d.dept_id LEFT JOIN sys_dept d ON e.dept_id = d.dept_id
@@ -47,12 +48,12 @@
<!-- 批量插入或更新员工信息只更新非null字段 --> <!-- 批量插入或更新员工信息只更新非null字段 -->
<insert id="insertOrUpdateBatch" parameterType="java.util.List"> <insert id="insertOrUpdateBatch" parameterType="java.util.List">
INSERT INTO ccdi_base_staff INSERT INTO ccdi_base_staff
(staff_id, name, dept_id, id_card, phone, annual_income, hire_date, status, (staff_id, name, dept_id, id_card, phone, annual_income, hire_date, is_party_member, status,
create_time, create_by, update_by, update_time) create_time, create_by, update_by, update_time)
VALUES VALUES
<foreach collection="list" item="item" separator=","> <foreach collection="list" item="item" separator=",">
(#{item.staffId}, #{item.name}, #{item.deptId}, #{item.idCard}, (#{item.staffId}, #{item.name}, #{item.deptId}, #{item.idCard},
#{item.phone}, #{item.annualIncome}, #{item.hireDate}, #{item.status}, NOW(), #{item.phone}, #{item.annualIncome}, #{item.hireDate}, #{item.partyMember}, #{item.status}, NOW(),
#{item.createBy}, #{item.updateBy}, NOW()) #{item.createBy}, #{item.updateBy}, NOW())
</foreach> </foreach>
ON DUPLICATE KEY UPDATE ON DUPLICATE KEY UPDATE
@@ -61,6 +62,7 @@
phone = COALESCE(VALUES(phone), phone), phone = COALESCE(VALUES(phone), phone),
annual_income = COALESCE(VALUES(annual_income), annual_income), annual_income = COALESCE(VALUES(annual_income), annual_income),
hire_date = COALESCE(VALUES(hire_date), hire_date), hire_date = COALESCE(VALUES(hire_date), hire_date),
is_party_member = COALESCE(VALUES(is_party_member), is_party_member),
status = COALESCE(VALUES(status), status), status = COALESCE(VALUES(status), status),
update_by = COALESCE(VALUES(update_by), update_by), update_by = COALESCE(VALUES(update_by), update_by),
update_time = NOW() update_time = NOW()
@@ -69,12 +71,12 @@
<!-- 批量插入员工信息 --> <!-- 批量插入员工信息 -->
<insert id="insertBatch" parameterType="java.util.List"> <insert id="insertBatch" parameterType="java.util.List">
INSERT INTO ccdi_base_staff INSERT INTO ccdi_base_staff
(staff_id, name, dept_id, id_card, phone, annual_income, hire_date, status, (staff_id, name, dept_id, id_card, phone, annual_income, hire_date, is_party_member, status,
create_time, create_by, update_by, update_time) create_time, create_by, update_by, update_time)
VALUES VALUES
<foreach collection="list" item="item" separator=","> <foreach collection="list" item="item" separator=",">
(#{item.staffId}, #{item.name}, #{item.deptId}, #{item.idCard}, (#{item.staffId}, #{item.name}, #{item.deptId}, #{item.idCard},
#{item.phone}, #{item.annualIncome}, #{item.hireDate}, #{item.status}, NOW(), #{item.phone}, #{item.annualIncome}, #{item.hireDate}, #{item.partyMember}, #{item.status}, NOW(),
#{item.createBy}, #{item.updateBy}, NOW()) #{item.createBy}, #{item.updateBy}, NOW())
</foreach> </foreach>
</insert> </insert>

View File

@@ -17,6 +17,8 @@ class CcdiBaseStaffMapperTest {
assertTrue(xml.contains("annual_income"), xml); assertTrue(xml.contains("annual_income"), xml);
assertTrue(xml.contains("#{item.annualIncome}"), xml); assertTrue(xml.contains("#{item.annualIncome}"), xml);
assertTrue(xml.contains("is_party_member"), xml);
assertTrue(xml.contains("#{item.partyMember}"), xml);
} }
} }
} }

View File

@@ -27,6 +27,28 @@ class CcdiBaseStaffImportServiceImplTest {
assertDoesNotThrow(() -> service.validateStaffData(buildDto(new BigDecimal("12345.67")), false, Collections.emptySet(), Collections.emptySet())); assertDoesNotThrow(() -> service.validateStaffData(buildDto(new BigDecimal("12345.67")), false, Collections.emptySet(), Collections.emptySet()));
} }
@Test
void validateStaffData_shouldAllowPartyMemberValuesZeroAndOne() {
CcdiBaseStaffAddDTO nonPartyMember = buildDto(null);
nonPartyMember.setPartyMember(0);
CcdiBaseStaffAddDTO partyMember = buildDto(null);
partyMember.setPartyMember(1);
assertDoesNotThrow(() -> service.validateStaffData(nonPartyMember, false, Collections.emptySet(), Collections.emptySet()));
assertDoesNotThrow(() -> service.validateStaffData(partyMember, false, Collections.emptySet(), Collections.emptySet()));
}
@Test
void validateStaffData_shouldRejectInvalidPartyMemberValue() {
CcdiBaseStaffAddDTO dto = buildDto(null);
dto.setPartyMember(2);
RuntimeException exception = assertThrows(RuntimeException.class,
() -> service.validateStaffData(dto, false, Set.of(), Set.of()));
assertEquals("是否党员只能填写'0'或'1'", exception.getMessage());
}
@Test @Test
void validateStaffData_shouldRejectNegativeAnnualIncome() { void validateStaffData_shouldRejectNegativeAnnualIncome() {
RuntimeException exception = assertThrows(RuntimeException.class, RuntimeException exception = assertThrows(RuntimeException.class,
@@ -51,6 +73,7 @@ class CcdiBaseStaffImportServiceImplTest {
dto.setIdCard("320101199001010014"); dto.setIdCard("320101199001010014");
dto.setPhone("13812345678"); dto.setPhone("13812345678");
dto.setStatus("0"); dto.setStatus("0");
dto.setPartyMember(1);
dto.setAnnualIncome(annualIncome); dto.setAnnualIncome(annualIncome);
return dto; return dto;
} }

View File

@@ -55,6 +55,7 @@ class CcdiBaseStaffServiceImplTest {
addDTO.setIdCard("320101199001010011"); addDTO.setIdCard("320101199001010011");
addDTO.setPhone("13812345678"); addDTO.setPhone("13812345678");
addDTO.setStatus("0"); addDTO.setStatus("0");
addDTO.setPartyMember(1);
addDTO.setAnnualIncome(new BigDecimal("12345.67")); addDTO.setAnnualIncome(new BigDecimal("12345.67"));
addDTO.setAssetInfoList(List.of( addDTO.setAssetInfoList(List.of(
buildAssetDto("房产"), buildAssetDto("房产"),
@@ -70,6 +71,7 @@ class CcdiBaseStaffServiceImplTest {
assertEquals(1, result); assertEquals(1, result);
ArgumentCaptor<CcdiBaseStaff> staffCaptor = ArgumentCaptor.forClass(CcdiBaseStaff.class); ArgumentCaptor<CcdiBaseStaff> staffCaptor = ArgumentCaptor.forClass(CcdiBaseStaff.class);
verify(baseStaffMapper).insert(staffCaptor.capture()); verify(baseStaffMapper).insert(staffCaptor.capture());
assertEquals(1, staffCaptor.getValue().getPartyMember());
assertEquals(new BigDecimal("12345.67"), staffCaptor.getValue().getAnnualIncome()); assertEquals(new BigDecimal("12345.67"), staffCaptor.getValue().getAnnualIncome());
ArgumentCaptor<List<CcdiAssetInfoDTO>> captor = ArgumentCaptor.forClass(List.class); ArgumentCaptor<List<CcdiAssetInfoDTO>> captor = ArgumentCaptor.forClass(List.class);
verify(assetInfoService).replaceByFamilyId(eq("320101199001010011"), captor.capture()); verify(assetInfoService).replaceByFamilyId(eq("320101199001010011"), captor.capture());
@@ -92,6 +94,7 @@ class CcdiBaseStaffServiceImplTest {
editDTO.setIdCard("320101199001010011"); editDTO.setIdCard("320101199001010011");
editDTO.setPhone("13812345678"); editDTO.setPhone("13812345678");
editDTO.setStatus("0"); editDTO.setStatus("0");
editDTO.setPartyMember(0);
editDTO.setAnnualIncome(new BigDecimal("45678.90")); editDTO.setAnnualIncome(new BigDecimal("45678.90"));
editDTO.setAssetInfoList(List.of(buildAssetDto("车辆"))); editDTO.setAssetInfoList(List.of(buildAssetDto("车辆")));
@@ -104,6 +107,7 @@ class CcdiBaseStaffServiceImplTest {
assertEquals(1, result); assertEquals(1, result);
ArgumentCaptor<CcdiBaseStaff> staffCaptor = ArgumentCaptor.forClass(CcdiBaseStaff.class); ArgumentCaptor<CcdiBaseStaff> staffCaptor = ArgumentCaptor.forClass(CcdiBaseStaff.class);
verify(baseStaffMapper).updateById(staffCaptor.capture()); verify(baseStaffMapper).updateById(staffCaptor.capture());
assertEquals(0, staffCaptor.getValue().getPartyMember());
assertEquals(new BigDecimal("45678.90"), staffCaptor.getValue().getAnnualIncome()); assertEquals(new BigDecimal("45678.90"), staffCaptor.getValue().getAnnualIncome());
verify(assetInfoService, never()).deleteByFamilyId("320101199001010011"); verify(assetInfoService, never()).deleteByFamilyId("320101199001010011");
verify(assetInfoService).replaceByFamilyId("320101199001010011", editDTO.getAssetInfoList()); verify(assetInfoService).replaceByFamilyId("320101199001010011", editDTO.getAssetInfoList());
@@ -122,6 +126,7 @@ class CcdiBaseStaffServiceImplTest {
editDTO.setIdCard("320101199001010011"); editDTO.setIdCard("320101199001010011");
editDTO.setPhone("13812345678"); editDTO.setPhone("13812345678");
editDTO.setStatus("0"); editDTO.setStatus("0");
editDTO.setPartyMember(1);
editDTO.setAssetInfoList(List.of(buildAssetDto("车辆"))); editDTO.setAssetInfoList(List.of(buildAssetDto("车辆")));
when(baseStaffMapper.selectById(1001L)).thenReturn(existing); when(baseStaffMapper.selectById(1001L)).thenReturn(existing);
@@ -135,17 +140,18 @@ class CcdiBaseStaffServiceImplTest {
} }
@Test @Test
void selectBaseStaffById_shouldReturnAssetInfoList() { void selectBaseStaffById_shouldReturnSelfOwnedAssetInfoList() {
CcdiBaseStaff staff = new CcdiBaseStaff(); CcdiBaseStaff staff = new CcdiBaseStaff();
staff.setStaffId(1001L); staff.setStaffId(1001L);
staff.setName("张三"); staff.setName("张三");
staff.setIdCard("320101199001010011"); staff.setIdCard("320101199001010011");
staff.setStatus("0"); staff.setStatus("0");
staff.setPartyMember(1);
staff.setAnnualIncome(new BigDecimal("88888.88")); staff.setAnnualIncome(new BigDecimal("88888.88"));
CcdiAssetInfo assetInfo = new CcdiAssetInfo(); CcdiAssetInfo assetInfo = new CcdiAssetInfo();
assetInfo.setFamilyId("320101199001010011"); assetInfo.setFamilyId("320101199001010011");
assetInfo.setPersonId("320101199201010022"); assetInfo.setPersonId("320101199001010011");
assetInfo.setAssetMainType("车辆"); assetInfo.setAssetMainType("车辆");
assetInfo.setAssetSubType("小汽车"); assetInfo.setAssetSubType("小汽车");
assetInfo.setAssetName("家庭车辆"); assetInfo.setAssetName("家庭车辆");
@@ -153,14 +159,16 @@ class CcdiBaseStaffServiceImplTest {
assetInfo.setAssetStatus("正常"); assetInfo.setAssetStatus("正常");
when(baseStaffMapper.selectById(1001L)).thenReturn(staff); when(baseStaffMapper.selectById(1001L)).thenReturn(staff);
when(assetInfoService.selectByFamilyId("320101199001010011")).thenReturn(List.of(assetInfo)); when(assetInfoService.selectByFamilyIdAndPersonId("320101199001010011", "320101199001010011"))
.thenReturn(List.of(assetInfo));
CcdiBaseStaffVO result = service.selectBaseStaffById(1001L); CcdiBaseStaffVO result = service.selectBaseStaffById(1001L);
assertNotNull(result.getAssetInfoList()); assertNotNull(result.getAssetInfoList());
assertEquals(1, result.getPartyMember());
assertEquals(new BigDecimal("88888.88"), result.getAnnualIncome()); assertEquals(new BigDecimal("88888.88"), result.getAnnualIncome());
assertEquals(1, result.getAssetInfoList().size()); assertEquals(1, result.getAssetInfoList().size());
assertEquals("320101199201010022", result.getAssetInfoList().get(0).getPersonId()); assertEquals("320101199001010011", result.getAssetInfoList().get(0).getPersonId());
assertEquals("车辆", result.getAssetInfoList().get(0).getAssetMainType()); assertEquals("车辆", result.getAssetInfoList().get(0).getAssetMainType());
} }

View File

@@ -2,6 +2,7 @@ package com.ruoyi.info.collection.utils;
import com.ruoyi.common.core.domain.entity.SysDictData; import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.utils.DictUtils; import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.info.collection.domain.excel.CcdiBaseStaffExcel;
import com.ruoyi.info.collection.domain.excel.CcdiAssetInfoExcel; import com.ruoyi.info.collection.domain.excel.CcdiAssetInfoExcel;
import com.ruoyi.info.collection.domain.excel.CcdiStaffFmyRelationExcel; import com.ruoyi.info.collection.domain.excel.CcdiStaffFmyRelationExcel;
import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.CellStyle;
@@ -72,6 +73,31 @@ class EasyExcelUtilTemplateTest {
} }
} }
@Test
void importTemplateWithDictDropdown_shouldAddPartyMemberDropdownToBaseStaffTemplate() throws Exception {
MockHttpServletResponse response = new MockHttpServletResponse();
try (MockedStatic<DictUtils> mocked = mockStatic(DictUtils.class)) {
mocked.when(() -> DictUtils.getDictCache("ccdi_employee_status"))
.thenReturn(List.of(
buildDictData("在职", "0"),
buildDictData("离职", "1")
));
mocked.when(() -> DictUtils.getDictCache("ccdi_yes_no_flag"))
.thenReturn(List.of(
buildDictData("", "1"),
buildDictData("", "0")
));
EasyExcelUtil.importTemplateWithDictDropdown(response, CcdiBaseStaffExcel.class, "员工信息");
}
try (Workbook workbook = WorkbookFactory.create(new ByteArrayInputStream(response.getContentAsByteArray()))) {
Sheet sheet = workbook.getSheetAt(0);
assertTrue(hasValidationOnColumn(sheet, 7), "是否党员列应包含下拉校验");
}
}
private void assertTextColumn(Sheet sheet, int columnIndex) { private void assertTextColumn(Sheet sheet, int columnIndex) {
CellStyle style = sheet.getColumnStyle(columnIndex); CellStyle style = sheet.getColumnStyle(columnIndex);
assertNotNull(style, "文本列应设置默认样式"); assertNotNull(style, "文本列应设置默认样式");
@@ -90,9 +116,13 @@ class EasyExcelUtilTemplateTest {
} }
private SysDictData buildDictData(String label) { private SysDictData buildDictData(String label) {
return buildDictData(label, label);
}
private SysDictData buildDictData(String label, String value) {
SysDictData dictData = new SysDictData(); SysDictData dictData = new SysDictData();
dictData.setDictLabel(label); dictData.setDictLabel(label);
dictData.setDictValue(label); dictData.setDictValue(value);
return dictData; return dictData;
} }
} }

View File

@@ -0,0 +1,83 @@
# 员工基础信息新增是否党员字段后端实施计划
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 在员工基础信息后端链路中新增“是否党员”字段,保证数据库、实体、接口、导入导出与最小测试契约保持一致。
**Architecture:** 继续沿用 `ccdi_base_staff` 现有维护链路,在表上增加 `is_party_member` 字段,并在 `CcdiBaseStaff` 的实体、DTO、VO、Excel、Mapper XML 与服务校验中同步补齐。实现保持最短路径,不新增新的接口层或旁路转换逻辑,只在现有员工维护链路上扩字段。
**Tech Stack:** MySQL, Java 21, Spring Boot 3, MyBatis Plus, EasyExcel, JUnit 5, Markdown
---
## 文件结构与职责
**后端源码**
- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/CcdiBaseStaff.java`
新增 `partyMember` 字段并映射 `is_party_member`
- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiBaseStaffAddDTO.java`
新增新增接口入参字段与非空校验。
- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiBaseStaffEditDTO.java`
新增编辑接口入参字段与非空校验。
- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiBaseStaffVO.java`
新增详情/列表返回字段。
- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/excel/CcdiBaseStaffExcel.java`
新增 Excel 导入导出列,并挂接“是/否”字典下拉。
- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/ImportFailureVO.java`
新增导入失败记录字段回显。
- `ccdi-info-collection/src/main/resources/mapper/info/collection/CcdiBaseStaffMapper.xml`
在列表查询、批量新增、批量更新 SQL 中补 `is_party_member`
- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffServiceImpl.java`
补新增/编辑链路校验,约束 `partyMember` 只能为 `0/1`
- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffImportServiceImpl.java`
补导入链路的必填和枚举值校验。
**SQL**
- `sql/migration/2026-04-17-add-base-staff-party-member.sql`
以幂等方式为 `ccdi_base_staff` 增加字段,并补充 `ccdi_yes_no_flag` 字典数据。
- `sql/ccdi_yes_no_flag_dict.sql`
提供“是/否标记”字典初始化脚本,供新环境或独立初始化使用。
**测试**
- `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/service/CcdiBaseStaffServiceImplTest.java`
验证服务层新增/修改/详情查询会透传 `partyMember`
- `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/service/CcdiBaseStaffImportServiceImplTest.java`
验证导入场景仅允许 `0/1`
- `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/mapper/CcdiBaseStaffMapperTest.java`
验证 Mapper XML 已包含 `is_party_member``#{item.partyMember}`
- `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/utils/EasyExcelUtilTemplateTest.java`
验证员工模板已补“是否党员”下拉列。
## 实施步骤
- [ ]`ccdi_base_staff` 表增加 `is_party_member`,默认值为 `0`,避免历史数据为空。
- [ ] 在员工基础信息实体、DTO、VO、Excel 对象中补齐 `partyMember`
- [ ]`CcdiBaseStaffMapper.xml` 的列表、批量新增、批量更新 SQL 中补 `is_party_member`
- [ ]`CcdiBaseStaffServiceImpl``CcdiBaseStaffImportServiceImpl` 中增加 `0/1` 值域校验。
- [ ] 新增 `ccdi_yes_no_flag` 字典脚本,保证导入模板下拉可用。
- [ ] 补充并执行后端定向测试;若执行受现有依赖问题阻塞,需要在记录中明确注明阻塞原因。
## 验证记录
- 已尝试执行:
```bash
mvn -pl ccdi-info-collection -Dtest=CcdiBaseStaffServiceImplTest,CcdiBaseStaffImportServiceImplTest,CcdiBaseStaffMapperTest,EasyExcelUtilTemplateTest test
mvn -pl ccdi-info-collection -DskipTests compile
```
- 当前结果:
- `test` 在进入本次新增断言前,被模块内既有测试编译问题拦截,表现为缺少 `org.springframework.data.redis.core.*` 类型。
- `compile` 被模块当前既有依赖缺失拦截,表现为缺少 `com.ruoyi.common.annotation.*``org.springframework.data.redis.core.*``IdCardUtil` 等类型。
- 上述阻塞不是本次“是否党员”字段新增引入的新问题,但会影响自动化验证结论,需要后续先修复模块依赖基线。
## 完成标准
- 员工基础信息接口可读写 `partyMember`
- 员工列表、详情、导入导出链路都包含 `partyMember`
- 数据库字段与字典 SQL 已补齐
- 后端测试契约已同步更新
- 已明确记录当前自动化验证阻塞点

View File

@@ -0,0 +1,22 @@
# 员工信息仅展示本人资产后端实施计划
## 变更目标
- 员工详情接口返回的 `assetInfoList` 仅包含员工本人资产
- 员工信息页不再通过详情接口混入亲属资产数据
## 变更范围
- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffServiceImpl.java`
- `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/service/CcdiBaseStaffServiceImplTest.java`
## 实施步骤
1. 将员工详情聚合资产的查询口径从 `family_id = 员工身份证号` 调整为 `family_id = 员工身份证号 and person_id = 员工身份证号`
2. 保持员工新增、编辑时的 `replaceByFamilyId` 逻辑不变,继续由后端写入本人资产
3. 调整单元测试,验证员工详情仅返回本人资产
## 验证要点
- 查询员工详情时,`assetInfoList` 不再返回亲属资产
- 现有员工新增、编辑、删除链路不受影响

View File

@@ -0,0 +1,23 @@
# 修复员工资产信息表注释乱码后端实施计划
## 变更目标
- 修复 `ccdi_asset_info` 表中 `family_id``person_id` 列注释乱码问题
- 保持表结构、字段类型和业务数据不变,仅修正元数据注释
## 变更范围
- `sql/migration/2026-04-17-fix-ccdi-asset-info-comment-encoding.sql`
## 实施步骤
1. 查询 `information_schema.COLUMNS`,确认 `ccdi_asset_info` 列注释实际存在乱码
2. 新增增量 SQL使用 `ALTER TABLE ... MODIFY COLUMN ... COMMENT` 修复 `family_id``person_id` 注释
3. 通过 `bin/mysql_utf8_exec.sh``utf8mb4` 会话执行脚本
4. 再次查询 `information_schema.COLUMNS` 验证注释已恢复为中文
## 验证要点
- `family_id` 注释显示为“归属员工证件号”
- `person_id` 注释显示为“资产实际持有人证件号”
- 字段类型仍为 `VARCHAR(100) NOT NULL`

View File

@@ -0,0 +1,33 @@
# 员工信息页资产提示文案移除前端实施计划
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 移除员工信息页资产信息区域中“员工信息页仅维护员工本人资产”“资产持有人默认为当前员工本人,无需额外填写”的备注展示。
**Architecture:** 本次仅调整员工信息维护页模板展示,不改动资产表单字段、默认值、提交参数或后端接口。实现上直接删除备注 DOM 和对应样式,保持页面其余交互不变。
**Tech Stack:** Vue 2, Element UI, JavaScript, Markdown
---
## 文件结构与职责
- `ruoyi-ui/src/views/ccdiBaseStaff/index.vue`
删除资产信息区域的备注文案和无用样式。
## 实施步骤
- [ ] 删除资产信息区备注展示块
- [ ] 删除 `assets-helper` 对应样式,避免残留无用 CSS
- [ ] 运行前端构建确认页面模板调整未引入语法错误
## 验证
```bash
source ~/.nvm/nvm.sh && nvm use 14.21.3 >/dev/null && npm run build:prod
```
## 完成标准
- 员工信息页不再展示上述两条资产备注
- 资产新增、编辑、提交逻辑保持不变

View File

@@ -0,0 +1,53 @@
# 员工基础信息新增是否党员字段前端实施计划
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 在员工信息维护页面新增“是否党员”基础字段,并打通列表展示、详情回显、编辑录入与导入失败记录展示。
**Architecture:** 保持 `ruoyi-ui/src/views/ccdiBaseStaff/index.vue` 的现有页面结构不变,仅在已有“基本信息”区域与员工列表中插入一个新字段。字段值与后端保持一致,前端统一使用 `0/1` 数值口径,并通过页面内格式化方法展示为“是/否”。
**Tech Stack:** Vue 2, Element UI, JavaScript, npm, nvm, Markdown
---
## 文件结构与职责
**前端源码**
- `ruoyi-ui/src/views/ccdiBaseStaff/index.vue`
新增列表列、编辑表单、详情弹窗、失败记录弹窗和格式化方法。
**依赖接口**
- `ruoyi-ui/src/api/ccdiBaseStaff.js`
本次接口路径不变,继续复用现有新增/编辑/详情 API只承接新增字段。
## 实施步骤
- [ ] 在员工列表中增加“是否党员”列,统一显示“是/否”。
- [ ] 在新增/编辑弹窗的基本信息区域增加“是否党员”单选项,默认值设为“否”。
- [ ] 在详情弹窗中增加“是否党员”展示,保证历史员工查看时能回显。
- [ ] 在导入失败记录弹窗中增加“是否党员”列,便于排查模板数据问题。
- [ ] 在页面 methods 中新增 `formatPartyMember`,统一处理 `0/1/null` 的展示。
- [ ] 使用 `nvm` 选择当前机器可用的 Node 版本后执行前端构建验证。
## 验证记录
- 已尝试执行:
```bash
source ~/.nvm/nvm.sh && nvm use
source ~/.nvm/nvm.sh && nvm use 14.21.3 && npm run build:prod
```
- 当前结果:
- 仓库内未提供 `.nvmrc`,直接执行 `nvm use` 无法自动切到项目版本。
- 当前机器存在 `v14.21.3``v25.9.0``system(v24.14.0)`,后续前端验证建议优先使用 `v14.21.3`
- 已使用 `v14.21.3` 成功执行 `npm run build:prod`,构建通过,仅保留项目原有的包体积告警。
## 完成标准
- 员工列表、详情、编辑弹窗可见“是否党员”
- 提交新增/编辑时会带上 `partyMember`
- 导入失败记录能展示该字段
- 已明确前端构建使用 `nvm` 的版本前提与当前环境限制

View File

@@ -0,0 +1,24 @@
# 员工信息仅展示本人资产前端实施计划
## 变更目标
- 员工信息页资产区域统一按“本人资产”口径展示
- 详情弹窗移除“资产实际持有人身份证号”和“归属类型”
- 员工资产编辑表单不再保留亲属资产相关提示与校验
## 变更范围
- `ruoyi-ui/src/views/ccdiBaseStaff/index.vue`
## 实施步骤
1. 更新资产信息区提示文案,明确员工信息页仅维护员工本人资产
2. 删除详情弹窗中的“资产实际持有人身份证号”“归属类型”列
3. 清理表单中 `personId` 的必填与格式校验,新增资产时默认带入当前员工身份证号
4. 更新员工资产导入弹窗提示文案,明确仅允许导入员工本人资产
## 验证要点
- 员工详情弹窗仅显示本人资产字段
- 新增、编辑员工资产时不再出现亲属资产口径提示
- 员工身份证号变更后,表单内资产仍跟随当前员工身份证号

View File

@@ -116,6 +116,11 @@
<el-table-column label="所属部门" align="center" prop="deptName" :show-overflow-tooltip="true"/> <el-table-column label="所属部门" align="center" prop="deptName" :show-overflow-tooltip="true"/>
<el-table-column label="电话" align="center" prop="phone" width="120"/> <el-table-column label="电话" align="center" prop="phone" width="120"/>
<el-table-column label="年收入" align="center" prop="annualIncome" width="140"/> <el-table-column label="年收入" align="center" prop="annualIncome" width="140"/>
<el-table-column label="是否党员" align="center" prop="partyMember" width="100">
<template slot-scope="scope">
<span>{{ formatPartyMember(scope.row.partyMember) }}</span>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status" width="100"> <el-table-column label="状态" align="center" prop="status" width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag v-if="scope.row.status === '0'" type="success">在职</el-tag> <el-tag v-if="scope.row.status === '0'" type="success">在职</el-tag>
@@ -217,7 +222,14 @@
<el-date-picker v-model="form.hireDate" type="date" placeholder="选择入职时间" value-format="yyyy-MM-dd" style="width: 100%" /> <el-date-picker v-model="form.hireDate" type="date" placeholder="选择入职时间" value-format="yyyy-MM-dd" style="width: 100%" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12" /> <el-col :span="12">
<el-form-item label="是否党员" prop="partyMember">
<el-radio-group v-model="form.partyMember">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row> </el-row>
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status"> <el-radio-group v-model="form.status">
@@ -229,10 +241,6 @@
<span>资产信息</span> <span>资产信息</span>
<el-button type="primary" plain size="mini" icon="el-icon-plus" @click="handleAddAsset">新增资产</el-button> <el-button type="primary" plain size="mini" icon="el-icon-plus" @click="handleAddAsset">新增资产</el-button>
</div> </div>
<div class="assets-helper">
<div>新增编辑时无需填写实际持有人身份证号</div>
<div>系统会默认带入并保留已有归属信息</div>
</div>
<el-form-item label-width="0" prop="assetInfoList"> <el-form-item label-width="0" prop="assetInfoList">
<div v-if="!form.assetInfoList || !form.assetInfoList.length" class="empty-assets"> <div v-if="!form.assetInfoList || !form.assetInfoList.length" class="empty-assets">
<i class="el-icon-office-building"></i> <i class="el-icon-office-building"></i>
@@ -333,6 +341,9 @@
<el-descriptions-item label="入职时间"> <el-descriptions-item label="入职时间">
{{ employeeDetail.hireDate ? parseTime(employeeDetail.hireDate, '{y}-{m}-{d}') : '-' }} {{ employeeDetail.hireDate ? parseTime(employeeDetail.hireDate, '{y}-{m}-{d}') : '-' }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="是否党员">
{{ formatPartyMember(employeeDetail.partyMember) }}
</el-descriptions-item>
<el-descriptions-item label="状态"> <el-descriptions-item label="状态">
<el-tag v-if="employeeDetail.status === '0'" type="success" size="small">在职</el-tag> <el-tag v-if="employeeDetail.status === '0'" type="success" size="small">在职</el-tag>
<el-tag v-else type="danger" size="small">离职</el-tag> <el-tag v-else type="danger" size="small">离职</el-tag>
@@ -351,12 +362,6 @@
暂无资产信息 暂无资产信息
</div> </div>
<el-table v-else :data="employeeDetail.assetInfoList" border class="detail-assets-table"> <el-table v-else :data="employeeDetail.assetInfoList" border class="detail-assets-table">
<el-table-column label="资产实际持有人身份证号" prop="personId" min-width="220" />
<el-table-column label="归属类型" prop="ownerType" min-width="100">
<template slot-scope="scope">
<span>{{ formatAssetOwnerType(scope.row) }}</span>
</template>
</el-table-column>
<el-table-column label="资产大类" prop="assetMainType" min-width="120" /> <el-table-column label="资产大类" prop="assetMainType" min-width="120" />
<el-table-column label="资产小类" prop="assetSubType" min-width="120" /> <el-table-column label="资产小类" prop="assetSubType" min-width="120" />
<el-table-column label="资产名称" prop="assetName" min-width="140" /> <el-table-column label="资产名称" prop="assetName" min-width="140" />
@@ -429,7 +434,7 @@
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline;" @click="importAssetTemplate">下载员工资产模板</el-link> <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline;" @click="importAssetTemplate">下载员工资产模板</el-link>
</div> </div>
<div class="el-upload__tip" slot="tip"> <div class="el-upload__tip" slot="tip">
<span>仅支持导入员工本人资产数据文件需为"xls""xlsx"格式系统将根据 personId/person_id 自动识别归属员工</span> <span>仅支持导入员工本人资产数据文件需为"xls""xlsx"格式导入身份证号需与员工本人一致</span>
</div> </div>
</el-upload> </el-upload>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
@@ -460,12 +465,17 @@
style="margin-bottom: 15px" style="margin-bottom: 15px"
/> />
<el-table :data="failureList" v-loading="failureLoading"> <el-table :data="failureList" v-loading="failureLoading">
<el-table-column label="姓名" prop="name" align="center" /> <el-table-column label="姓名" prop="name" align="center" />
<el-table-column label="柜员号" prop="staffId" align="center" /> <el-table-column label="柜员号" prop="staffId" align="center" />
<el-table-column label="身份证号" prop="idCard" align="center" /> <el-table-column label="身份证号" prop="idCard" align="center" />
<el-table-column label="电话" prop="phone" align="center" /> <el-table-column label="电话" prop="phone" align="center" />
<el-table-column label="年收入" prop="annualIncome" align="center" width="140" /> <el-table-column label="年收入" prop="annualIncome" align="center" width="140" />
<el-table-column label="是否党员" prop="partyMember" align="center" width="100">
<template slot-scope="scope">
<span>{{ formatPartyMember(scope.row.partyMember) }}</span>
</template>
</el-table-column>
<el-table-column label="失败原因" prop="errorMessage" align="center" min-width="200" :show-overflow-tooltip="true" /> <el-table-column label="失败原因" prop="errorMessage" align="center" min-width="200" :show-overflow-tooltip="true" />
</el-table> </el-table>
@@ -622,6 +632,9 @@ export default {
annualIncome: [ annualIncome: [
{ validator: (rule, value, callback) => this.validateAnnualIncomeRule(value, callback, "年收入"), trigger: "blur" } { validator: (rule, value, callback) => this.validateAnnualIncomeRule(value, callback, "年收入"), trigger: "blur" }
], ],
partyMember: [
{ required: true, message: "请选择是否党员", trigger: "change" }
],
status: [ status: [
{ required: true, message: "请选择状态", trigger: "change" } { required: true, message: "请选择状态", trigger: "change" }
] ]
@@ -701,8 +714,14 @@ export default {
} }
}, },
watch: { watch: {
'form.idCard'(newIdCard, oldIdCard) { 'form.idCard'(newIdCard) {
this.syncAssetPersonIds(newIdCard, oldIdCard); if (!Array.isArray(this.form.assetInfoList)) {
return;
}
this.form.assetInfoList = this.form.assetInfoList.map(asset => ({
...asset,
personId: newIdCard || ""
}));
} }
}, },
created() { created() {
@@ -956,6 +975,7 @@ export default {
phone: null, phone: null,
annualIncome: null, annualIncome: null,
hireDate: null, hireDate: null,
partyMember: 0,
status: "0", status: "0",
relatives: [], relatives: [],
assetInfoList: [] assetInfoList: []
@@ -1008,7 +1028,6 @@ export default {
}, },
validateAssetInfoList(assetInfoList) { validateAssetInfoList(assetInfoList) {
const requiredFields = [ const requiredFields = [
{ key: "personId", label: "资产实际持有人身份证号" },
{ key: "assetMainType", label: "资产大类" }, { key: "assetMainType", label: "资产大类" },
{ key: "assetSubType", label: "资产小类" }, { key: "assetSubType", label: "资产小类" },
{ key: "assetName", label: "资产名称" }, { key: "assetName", label: "资产名称" },
@@ -1033,11 +1052,6 @@ export default {
} }
} }
if (!idCardPattern.test(asset.personId)) {
this.$modal.msgError(`${rowNo}条资产的资产实际持有人身份证号格式不正确`);
return false;
}
for (const field of numericFields) { for (const field of numericFields) {
const value = asset[field.key]; const value = asset[field.key];
if (value !== null && value !== undefined && String(value).trim() !== "") { if (value !== null && value !== undefined && String(value).trim() !== "") {
@@ -1056,9 +1070,9 @@ export default {
return true; return true;
}, },
createEmptyAssetRow(defaultPersonId = "") { createEmptyAssetRow() {
return { return {
personId: defaultPersonId || "", personId: this.form.idCard || "",
assetMainType: "", assetMainType: "",
assetSubType: "", assetSubType: "",
assetName: "", assetName: "",
@@ -1080,29 +1094,11 @@ export default {
return value !== null && value !== undefined && String(value).trim() !== ""; return value !== null && value !== undefined && String(value).trim() !== "";
}); });
}, },
syncAssetPersonIds(newIdCard, oldIdCard) {
if (!Array.isArray(this.form.assetInfoList)) {
return;
}
this.form.assetInfoList = this.form.assetInfoList.map(asset => {
if (!asset || typeof asset !== "object") {
return asset;
}
const shouldSync = !asset.personId || asset.personId === oldIdCard;
if (!shouldSync) {
return asset;
}
return {
...asset,
personId: newIdCard || ""
};
});
},
handleAddAsset() { handleAddAsset() {
if (!Array.isArray(this.form.assetInfoList)) { if (!Array.isArray(this.form.assetInfoList)) {
this.form.assetInfoList = []; this.form.assetInfoList = [];
} }
this.form.assetInfoList.push(this.createEmptyAssetRow(this.form.idCard)); this.form.assetInfoList.push(this.createEmptyAssetRow());
}, },
handleRemoveAsset(index) { handleRemoveAsset(index) {
if (!Array.isArray(this.form.assetInfoList)) { if (!Array.isArray(this.form.assetInfoList)) {
@@ -1110,11 +1106,14 @@ export default {
} }
this.form.assetInfoList.splice(index, 1); this.form.assetInfoList.splice(index, 1);
}, },
formatAssetOwnerType(asset) { formatPartyMember(value) {
if (!asset) { if (value === 1 || value === "1") {
return "-"; return "";
} }
return asset.personId && asset.personId === this.employeeDetail.idCard ? "本人" : "亲属"; if (value === 0 || value === "0") {
return "否";
}
return "-";
}, },
/** 搜索按钮操作 */ /** 搜索按钮操作 */
handleQuery() { handleQuery() {
@@ -1159,6 +1158,7 @@ export default {
getBaseStaff(staffId).then(response => { getBaseStaff(staffId).then(response => {
this.form = { this.form = {
...response.data, ...response.data,
partyMember: response.data.partyMember !== null && response.data.partyMember !== undefined ? response.data.partyMember : 0,
assetInfoList: response.data.assetInfoList || [] assetInfoList: response.data.assetInfoList || []
}; };
this.form.annualIncome = response.data.annualIncome; this.form.annualIncome = response.data.annualIncome;
@@ -1673,16 +1673,6 @@ export default {
margin-right: 20px; margin-right: 20px;
} }
.employee-edit-dialog .assets-helper {
margin: -4px 0 12px;
padding: 10px 12px;
background: #f4f8ff;
border: 1px solid #d9ecff;
border-radius: 6px;
color: #606266;
line-height: 1.8;
}
.employee-edit-dialog .assets-table-wrapper { .employee-edit-dialog .assets-table-wrapper {
width: 100%; width: 100%;
overflow-x: auto; overflow-x: auto;

View File

@@ -0,0 +1,14 @@
-- 是否标记字典初始化脚本
DELETE FROM sys_dict_data WHERE dict_type = 'ccdi_yes_no_flag';
DELETE FROM sys_dict_type WHERE dict_type = 'ccdi_yes_no_flag';
INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark)
VALUES ('是否标记', 'ccdi_yes_no_flag', '0', 'admin', NOW(), '是否标记列表');
INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
VALUES
(1, '', '1', 'ccdi_yes_no_flag', '', 'primary', 'N', '0', 'admin', NOW(), ''),
(2, '', '0', 'ccdi_yes_no_flag', '', 'danger', 'Y', '0', 'admin', NOW(), '');
-- 执行完成后,请在字典管理中刷新缓存,确保模板下拉立即生效。

View File

@@ -0,0 +1,33 @@
SET @base_staff_party_member_sql = IF(
EXISTS(
SELECT 1
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'ccdi_base_staff'
AND column_name = 'is_party_member'
),
'SELECT 1',
'ALTER TABLE `ccdi_base_staff` ADD COLUMN `is_party_member` TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''是否党员0-否 1-是'' AFTER `hire_date`'
);
PREPARE base_staff_party_member_stmt FROM @base_staff_party_member_sql;
EXECUTE base_staff_party_member_stmt;
DEALLOCATE PREPARE base_staff_party_member_stmt;
INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark)
SELECT '是否标记', 'ccdi_yes_no_flag', '0', 'admin', NOW(), '是否标记列表'
WHERE NOT EXISTS (
SELECT 1 FROM sys_dict_type WHERE dict_type = 'ccdi_yes_no_flag'
);
INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
SELECT 1, '', '1', 'ccdi_yes_no_flag', '', 'primary', 'N', '0', 'admin', NOW(), ''
WHERE NOT EXISTS (
SELECT 1 FROM sys_dict_data WHERE dict_type = 'ccdi_yes_no_flag' AND dict_value = '1'
);
INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
SELECT 2, '', '0', 'ccdi_yes_no_flag', '', 'danger', 'Y', '0', 'admin', NOW(), ''
WHERE NOT EXISTS (
SELECT 1 FROM sys_dict_data WHERE dict_type = 'ccdi_yes_no_flag' AND dict_value = '0'
);

View File

@@ -0,0 +1,3 @@
ALTER TABLE `ccdi_asset_info`
MODIFY COLUMN `family_id` VARCHAR(100) NOT NULL COMMENT '归属员工证件号',
MODIFY COLUMN `person_id` VARCHAR(100) NOT NULL COMMENT '资产实际持有人证件号';