From db53938d887ea0b3a3c6e1823ad32366305472d4 Mon Sep 17 00:00:00 2001 From: yuance <182865460@qq.com> Date: Sun, 4 Jan 2026 14:33:15 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AE=A1=E8=AE=A1=E5=86=85?= =?UTF-8?q?=E5=AE=B99=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AuditContent9PersonnelConstants.java | 273 +++++++++++++ .../controller/AuditContent9Controller.java | 72 ++++ .../ai/dto/export/PersonnelExportEntity.java | 40 ++ .../AuditContent9PersonnelService.java | 13 + .../AuditContent9PersonnelServiceImpl.java | 360 ++++++++++++++++++ 5 files changed, 758 insertions(+) create mode 100644 src/main/java/com/gxwebsoft/ai/constants/AuditContent9PersonnelConstants.java create mode 100644 src/main/java/com/gxwebsoft/ai/controller/AuditContent9Controller.java create mode 100644 src/main/java/com/gxwebsoft/ai/dto/export/PersonnelExportEntity.java create mode 100644 src/main/java/com/gxwebsoft/ai/service/AuditContent9PersonnelService.java create mode 100644 src/main/java/com/gxwebsoft/ai/service/impl/AuditContent9PersonnelServiceImpl.java diff --git a/src/main/java/com/gxwebsoft/ai/constants/AuditContent9PersonnelConstants.java b/src/main/java/com/gxwebsoft/ai/constants/AuditContent9PersonnelConstants.java new file mode 100644 index 0000000..e3a66c2 --- /dev/null +++ b/src/main/java/com/gxwebsoft/ai/constants/AuditContent9PersonnelConstants.java @@ -0,0 +1,273 @@ +package com.gxwebsoft.ai.constants; + +import java.util.*; + +/** + * 审计内容9 - 人员编制管理审计常量类 + */ +public class AuditContent9PersonnelConstants { + + // 7个审计内容 + public static final String[] AUDIT_CONTENTS = { + "检查劳务派遣用工的合规性", + "核查被审计单位是否通过'假外包,真派遣'形式规避用工责任及成本", + "检查人员经费的使用是否规范", + "检查借用人员管理规范性", + "绩效管理体系健全性、合规性", + "检查机构编制合规性", + "预算编制与实际执行差异" + }; + + // 审计子内容映射 + public static final Map> AUDIT_SUB_CONTENTS = new LinkedHashMap<>(); + static { + // 1. 检查劳务派遣用工的合规性 + AUDIT_SUB_CONTENTS.put(AUDIT_CONTENTS[0], Arrays.asList( + new AuditSubContent( + "1.检查劳务派遣人数占企业用工总量比例是否≤10%", + "年度、半年度或月度员工花名册(区分正式工与派遣工,标注入职时间)", + "核查被审计单位审计期间年度(或半年度或月度)用工情况,计算派遣工占比,\n公式如下:派遣工比例=派遣工人数/(正式工人数+派遣工人数)\n合规标准:该比例不得超过10%。若计算结果>10%,则判定为用工比例不合规。", + "合并生成一个审计取证单", + "①劳务派遣暂行规定_人力资源和社会保障部_中国政府网——第四条;\n②《中华人民共和国劳动合同法》第六十六条" + ), + new AuditSubContent( + "2.检查派遣岗位是否均符合'三性'标准(临时性≤6个月,辅助性,替代性)", + "①劳务派遣合同及岗位说明书;涉及转正的,需补充提供劳动合同;\n②职代会决议文件,并附公示记录照片;\n③核心岗位清单;\n④如涉及替代性岗位,需提供原岗位员工的脱产、休假证明等。", + "岗位标准:派遣岗位仅限于临时性(不超过6个月)、辅助性(需职代会通过并公示)、替代性(如产假顶岗)岗位。核心岗位(如技术、管理等)必须转为正式工;用工单位决定使用被派遣劳动者的辅助性岗位,应当经职工代表大会或者全体职工讨论,提出方案和意见,与工会或者职工代表平等协商确定,并在用工单位内公示。\n①核查临时性工作岗位存续时间,若超过6个月,则判定该岗位不符合劳务派遣的临时性规定;\n②核查派遣岗位名称是否与公示辅助性岗位清单一致,不一致则违反劳务派遣辅助性规定;\n③检查替代性岗位是否提供休假证明等材料,若材料无法证实其符合设立条件,则派遣岗位设立存在瑕疵,违反劳务派遣的替代性规定。", + "", + "①劳务派遣暂行规定_人力资源和社会保障部_中国政府网——第三条;\n②《中华人民共和国劳动合同法》第六十六条" + ), + new AuditSubContent( + "3.检查派遣工与同类岗位的正式工是否同工同酬", + "正式工与派遣工薪酬对比表(或工资表)、社保缴纳凭证、福利发放记录", + "对同一(类)岗位的劳务派遣和正式工进行薪酬差额分析,并形成派遣工权益保障差异分析记录:\n①核查社保是否按用工单位所在地标准缴纳;\n②抽检加班费、绩效奖金及福利待遇等项目的核算差异。", + "", + "①劳务派遣暂行规定_人力资源和社会保障部_中国政府网——第七、第九条;\n②《中华人民共和国劳动合同法》第六十三条" + ), + new AuditSubContent( + "4.检查工伤处理程序中用工单位的配合义务履行情况", + "①工伤事故通报派遣单位的书面记录;\n②用工单位参与工伤调查的会议纪要/现场核查记录;\n③职业病诊断过程记录(委托书、交接单等);\n④提供的职业史证明、危害因素检测报告;\n⑤《劳务派遣协议》关于工伤保险责任条款及补偿办法;\n⑥用工单位支付协议约定补偿的财务凭证", + "①工伤事故:检查事故发生后及时向派遣单位通报的证据;核实派员参与调查、提供现场材料的记录;\n②职业病诊断:确认用工单位是否主动处理诊断事宜(如对接机构);验证所提供职业史、检测报告的真实性(比对考勤、检测备案);\n③责任约定:审查协议是否包含'用工单位不承担工伤保险责任'等违法条款;核查补偿办法中用工单位义务的财务履行凭证;\n④询问:访谈近审计期间工伤派遣工,核实用工单位配合度。", + "", + "①劳务派遣暂行规定_人力资源和社会保障部_中国政府网——第十条;\n②《工伤保险条例》第十七条、第十九条;\n③《中华人民共和国职业病防治法》第四十七条;\n④企业内控制度" + ) + )); + + // 2. 核查被审计单位是否通过"假外包,真派遣"形式规避用工责任及成本 + AUDIT_SUB_CONTENTS.put(AUDIT_CONTENTS[1], Arrays.asList( + new AuditSubContent( + "1.确认'外包'合同约定的是'劳务派遣'还是'劳务外包'的法律关系", + "外包合同及其补充协议", + "检查合同条款性质认定的关键要点:\n①若合同约定发包单位享有人员'用工管理权',包括直接调配权及要求员工遵守发包方《员工手册》等管理规定,则构成'劳务派遣'法律关系;若合同主要约定'业务成果验收标准',且外包公司自主安排生产服务、负责人员考勤管理,则构成'劳务外包'法律关系。\n②费用结算条款约定'按项目工作量'还是'验收成果计费':如存在以'人员数量、岗位配置、服务时长或出勤天数(隐含'人头费'逻辑)'等指标结算费用的情形,则构成'劳务派遣'法律关系;如基于'基于项目成果结算',如验收合格报告数量、项目阶段交付清单等,则构成'劳务外包'法律关系。", + "合并生成一个审计取证单。\n取证单主要内容包括:审计(调查)事项摘要、处理建议、附件(与问题相匹配的支撑资料,即工作底稿索引)等。\n其中'审计(调查)事项摘要'包含:标题、审计记录、审计发现、定性依据。\n1.标题:突出核心问题,采用观点性语句。一般为审计内容、审计目标的结论性描述。例如:\n在审计期间,XX单位存在'假外包,真派遣'行为。\n2.审计记录:仅客观记录审计核查的具体事实(时间、地点、主体、行为、数据等);不使用主观评价性语言(如'违规''不合理')或问题判断性表述;确保事实可交叉验证(引证合同条款、凭证编号等原始文件)。一般采用白描句式:'经核查[具体资料/凭证],……[事实描述]……'例如:\n① 核查2019年1月1日签订的《XX服务合同》(编号:XYZ-2019-001)第3条约定:'乙方(服务商)员工需遵守甲方考勤制度,甲方有权对乙方人员工作质量进行考核并决定留用'。\n② 调取2019年6月外包人员考勤表显示:实际出勤记录由甲方部门主管李某签字确认,绩效评分由甲方人力资源部核定。\n③ 查验2020年3月服务费结算凭证(凭证号:FV20200315):所附明细清单按外包人员当月计薪天数×日工资标准核算费用。\n3.审计发现:基于审计记录的事实,提炼违反规定的具体问题性质。需明确界定违规行为的实质特征。同一性质问题应合并表述,避免分段罗列。一般采用定性句式:'上述行为实质构成……[问题性质],/ 形成……[违规形态]'。例如:\n审计发现:该单位通过签订名义上的《劳务外包合同》,实际由发包单位直接管理外包人员工作过程并控制费用结算标准,形成事实上的劳务派遣用工关系,构成'假外包、真派遣'行为。\n4.定性依据:违反的法律法规、政策规定及被审计单位内部管理制度等。\n选择优先级:法律法规>部门规章>地方政府规范性文件>被审计单位内部制度。\n引用规范:标明文件全称、文号及具体条款;引述条款内容须与问题直接对应;同时违反多层级规定的,按效力层级降序排列。例如:\n定性依据:\n①《劳务派遣暂行规定》(人社部令第22号)第三条:'用工单位只能在临时性、辅助性或者替代性的工作岗位上使用被派遣劳动者'。\n②被审计单位《XX管理办法》(XX集团〔2018〕35号)第X条:'……'。", + "①《中华人民共和国劳动合同法》及其实施条例;\n②《中华人民共和国民法典》" + ), + new AuditSubContent( + "2.检查发包单位是否实质上直接管理外包人员及其工作过程", + "①考勤记录(打卡截图、门禁刷卡数据)、OA系统工作安排(如能获取)、绩效目标确认文件、扣罚工资记录;\n②发包单位《员工手册》、奖惩记录;\n③工位证明、工卡(门禁卡或身份标识卡)发放或佩戴要求、设备领用记录。", + "①核实发包单位是否直接安排、记录和处罚外包人员考勤:查看考勤记录(如钉钉打卡截图、门禁刷卡数据)、绩效目标确认文件、OA系统工作安排记录、工资扣罚凭证(如'早退扣款'记录),若上述安排、记录和处罚由发包单位直接进行(而非外包公司执行),则表明发包单位存在实际考勤管理权,构成'实质派遣'。\n②核实发包单位的《员工手册》等规章制度是否明确适用于外包人员并被执行:审阅发包单位《员工手册》、奖惩通知(如警告、调岗通知)、工资条或相关记录,若实际操作中发包单位可直接对外包人员进行警告、调岗、扣款或奖励等管理动作,强有力地证明发包单位的实质性管理权限已延伸至外包人员,构成'实质派遣';\n③核实外包人员的工作环境和工作工具由谁提供和控制:查看外包人员在发包单位的工位安排记录、工卡发放记录、工作设备领用登记。若外包人员日常在发包单位固定场所工作,使用发包单位提供的专属工位、标识(如工卡)、电脑设备等,表明其工作环境高度受控于发包单位,构成'实质派遣'。", + "", + "①《中华人民共和国劳动合同法》及其实施条例;\n②《中华人民共和国民法典》" + ), + new AuditSubContent( + "3.核查劳务外包服务的费用结算依据是否符合外包法律特征", + "①结算相关的凭证:付款审批单,结算单据(如项目验收单、承揽书、成果清单及对应金额),发票;\n②访谈记录(文档或音频)", + "1.检查凭证,验证实际结算方式。\n检查付款审批流程中的结算依据,以及外包公司提供的结算材料,\n①如果结算材料表明该'外包'实际以'人员数量、岗位配置、服务时长或出勤天数(隐含'人头费'逻辑)'等指标结算费用,则构成'实质派遣'。\n②'劳务外包'结算需以项目成果为依据,形成合同→验收单→发票的完整凭证链。结算金额与成果量挂钩,结算单、请款函等文件需基于项目验收单、承揽书等成果凭证生成,以此构成'劳务外包'的合规流程。\n2.访谈财务及外包项目负责人,核实以下事项:\n①费用计算依据:若与外包人员数量及工时无关,则属于真实'劳务外包';反之,可能构成'劳务派遣';\n②结算调整机制:项目延期或增量时,真实外包应以成果变更调整结算,而非仅追加人员费用。", + "", + "①《中华人民共和国劳动合同法》及其实施条例;\n②《中华人民共和国民法典》" + ) + )); + + // 3. 检查人员经费的使用是否规范 + AUDIT_SUB_CONTENTS.put(AUDIT_CONTENTS[2], Arrays.asList( + new AuditSubContent( + "1.检查工资总额控制:工资性支出是否突破国资监管部门核定的年度总额上限,及超限额部分是否按规定完成审批报备", + "① 年度工资总额批复文件;\n② 年度工资汇总统计表;\n③ 超预算调整审批记录", + "核查实发工资总额与批复额度的一致性,确认超支部分是否履行相关决策程序(如职工代表大会审议、国资委备案等),并列出工资总额执行差异", + "生成审计取证单", + "①自治区国资委关于印发《自治区国资委履行出资人职责企业工资总额管理办法》的通知 - 政务公开 - 防城港市人民政府 -\n②企业内控制度\n③《中华人民共和国劳动合同法》第四条 职工代表大会" + ), + new AuditSubContent( + "2.检查福利费列支范围:福利费支出的合规性,有无违规发放补贴、变相薪酬行为", + "① 福利费明细账及原始凭证;\n② 职工福利制度文件;\n③ 补贴发放签收记录", + "对福利费支出项目进行抽查,依据制度文件审核合规性,发现违规支出的,列出超范围支出明细清单。", + "生成审计取证单", + "①财政部关于企业加强职工福利费财务管理的通知\n②企业内控制度" + ), + new AuditSubContent( + "3.检查劳务费真实性:是否存在虚构人员套取资金等虚假劳务支出行为", + "① 劳务合同;\n② 服务成果交付证明(如报告、验收单);\n③ 支付凭证(包括收款方信息及银行流水)", + "①通过天眼查或国家企业信用信息公示系统核查劳务提供方身份真实性;\n②对比服务成果与合同约定内容是否匹配;\n③对核查中发现的问题如实记录。", + "生成审计取证单", + "①《中华人民共和国会计法》第四十三条\n②《财政违法行为处罚处分条例》第七条" + ) + )); + + // 4. 检查借用人员管理规范性 + AUDIT_SUB_CONTENTS.put(AUDIT_CONTENTS[3], Arrays.asList( + new AuditSubContent( + "1.检查借用程序合规性", + "①借调相关材料(含沟通记录及正式文件),三方协议(如有)\n②实际在岗证明文件(考勤记录);\n③续借审批文件", + "①借用必要性审查:根据借调相关材料,核查借调事由是否合理,是否存在以工作专班、跟班学习或交流锻炼等名义变相借调的情况。\n②借用程序合规性审查:对照单位借用人员制度,核查借调审批手续是否齐全,以及是否经本单位党组(党委)审批并报同级党委组织部门备案。\n③借用期限审查:核查借调文件约定的首次借调期限是否超过6个月;结合实际在岗证明文件(考勤记录),若实际存在延期情形,是否已提前征得派出单位和本人同意。", + "合并生成一个审计取证单", + "①中共中央办公厅 国务院办公厅印发《整治形式主义为基层减负若干规定》————头条——中央纪委国家监委网站;\n②企业内控制度" + ), + new AuditSubContent( + "2.检查经费列支规范性:借用人员费用报销等是否存在重复列支或违规转嫁费用行为", + "①审计期间借用人员名单;\n②费用报销凭证及其明细账;\n③借用人员访谈记录", + "根据借用人员名单,在费用报销明细账中核查相关报销记录。依据借调文件或三方协议中明确的福利待遇等承担主体,结合对借用人员的访谈记录,审查是否存在同一借用人员的费用同时在借出单位与借入单位列支的情况。", + "", + "①中共中央办公厅 国务院办公厅印发《整治形式主义为基层减负若干规定》————头条——中央纪委国家监委网站;\n②企业内控制度" + ) + )); + + // 5. 绩效管理体系健全性、合规性 + AUDIT_SUB_CONTENTS.put(AUDIT_CONTENTS[4], Arrays.asList( + new AuditSubContent( + "1.确认绩效管理体系健全、制度流程符合法规要求", + "①所有内控制度\n②绩效考核制度发文记录、职工代表大会审议签字文件、制度修订记录等", + "①制度存在性审查:根据关键字,检索被审计单位所有制度,是否有员工绩效考核的制度规定。如有派遣工的,需检查是否有管派遣工的考核管理,并输出《制度清单》(含制度名称、文号、生效日期、具体条文等)。\n②纵向合规性比对:将被审计单位的考核办法与国家、自治区、上级单位比较,检查是否存在与上级制度相悖的情况,并标记冲突点。\n③横向一致性检查:与本单位的薪酬分配、干部管理、廉洁从业等其他内部控制制度比较,检查绩效考核的协同性,是否存在单位制度'左右脑互博'的情况,并标记冲突点。\n④确认是否绩效考核体系制度的设立是否已履行民主程序(应当经职工代表大会或全体职工讨论,协商确定);\n⑤根据以上检测出的问题,生成《绩效管理体系健全性、合规性审查审计取证单》,含客观事实描述、违规性质(是否需要?)、制度依据、审计建议等内容。", + "合并生成一个审计取证单", + "①《中华人民共和国劳动合同法》第四条;\n②《中央企业负责人经营业绩考核办法》;\n③国务院国资委《企业绩效评价标准值》(每年更新)\n⑤国资委回复:国有企业考核分配、工资总额相关的25个问题 http://www.sasac.gov.cn/n2588040/n2590387/n9854182/index.html\n⑥自治区国资委关于印发《关于进一步深化自治区国资委履行出资人职责企业劳动用工和收入分配制度改革的指导意见(试行)》的通知;\n⑦企业内控制度等" + ), + new AuditSubContent( + "2.绩效考核程序执行规范性", + "①考核表确认记录;\n②民主评议、领导评价记录;\n③绩效考核相关会议纪要、记录;\n④申诉处理记录(如有)等", + "①每个部门各抽查X份记录,检查考核表、民主评议、领导评价记录及其签字的完整性;\n②如有申述,检查申诉响应时效;\n③生成《绩效考核程序执行规范性审计取证单》", + "", + "企业内控制度" + ), + new AuditSubContent( + "3.绩效考核结果合规性", + "①工资计算表\n②职务任免文件", + "①检查工资计算与绩效考核结果是否呈正相关;\n②审核晋升人员绩效排名情况,是否存在低绩效仍获晋升的现象。", + "", + "企业内控制度" + ), + new AuditSubContent( + "4.验证系统数据准确性", + "①HR系统考核记录\n②纸质存档文件\n③工资发放明细", + "抽查样本,核验系统与纸质文件数据的一致性,并检查人员绩效等级是否存在差异", + "", + "企业内控制度" + ) + )); + + // 6. 检查机构编制合规性 + AUDIT_SUB_CONTENTS.put(AUDIT_CONTENTS[5], Arrays.asList( + new AuditSubContent( + "1.验证编制审批流程是否完整", + "机构设立批文、编制批文('三定'方案)", + "对比实际部门数量与编制文件;检查新增机构是否经上级编办审批", + "合并生成一个审计取证单", + "①《中国共产党机构编制工作条例》;\n②《'三定'规定制定和实施办法》559920f6ac788c5c8b2ee86842f36a96.pdf——行政事业单位适用;\n③《机构编制监督检查工作办法》;\n④机构编制违规违纪违法行为处理和问责规则(试行)" + ), + new AuditSubContent( + "2.验证是否按批复编制设置部门", + "被审计单位组织架构图、职能说明书", + "对比实际部门设置与编制文件是否一致;检查新增机构是否经上级编办审批,识别并标注是否存在未经批复的新增、撤销的临时机构。", + "", + "①《中国共产党机构编制工作条例》;\n②《'三定'规定制定和实施办法》559920f6ac788c5c8b2ee86842f36a96.pdf——行政事业单位适用;\n③《机构编制监督检查工作办法》;\n④机构编制违规违纪违法行为处理和问责规则(试行)" + ), + new AuditSubContent( + "3.被审计单位职数是否超标", + "党委、董事会成员名单、高管任职文件、员工花名册(含职务、职级等)", + "统计实际高管人数,并比对编制文件规定的领导职数阈值;", + "", + "①《中国共产党机构编制工作条例》;\n②《'三定'规定制定和实施办法》559920f6ac788c5c8b2ee86842f36a96.pdf——行政事业单位适用;\n③《机构编制监督检查工作办法》;\n④机构编制违规违纪违法行为处理和问责规则(试行)" + ), + new AuditSubContent( + "4.编制总量控制:岗位编制是否超核定标准", + "编制核定表、社保缴纳人数统计", + "抓取编制批文中机构名称、编制数量,与被审计单位实际部门清单、人力资源部门岗位数量自动比对。", + "", + "①《中国共产党机构编制工作条例》;\n②《'三定'规定制定和实施办法》559920f6ac788c5c8b2ee86842f36a96.pdf——行政事业单位适用;\n③《机构编制监督检查工作办法》;\n④机构编制违规违纪违法行为处理和问责规则(试行)" + ), + new AuditSubContent( + "5.编制调整是否履行审批", + "编制调整审批文件(可能包含OA系统日志)", + "需结合被审计单位、国资委或上级单位关于编制调整的审批流程判断。另检查编制调整流程是否在OA系统完整留痕(发起→审核→批复)。", + "", + "①《中国共产党机构编制工作条例》;\n②《'三定'规定制定和实施办法》559920f6ac788c5c8b2ee86842f36a96.pdf——行政事业单位适用;\n③《机构编制监督检查工作办法》;\n④机构编制违规违纪违法行为处理和问责规则(试行)" + ) + )); + + // 7. 预算编制与实际执行差异 + AUDIT_SUB_CONTENTS.put(AUDIT_CONTENTS[6], Arrays.asList( + new AuditSubContent( + "1.验证人员经费真实性,预算申报是否与实有人数匹配", + "工资预算表、工资发放明细表、考勤数据、每月社保缴纳明细等", + "比对预算人数与社保实缴人数,抽查离职人员工资停发时效,检查是否存在虚报人数、'吃空饷'情况,并列出涉及金额。", + "生成审计取证单", + "①中华人民共和国预算法_中国人大网;\n②《中华人民共和国预算法实施条例》;\n③企业内控制度" + ), + new AuditSubContent( + "2.检查职级成本是否合规", + "工资预算表、员工花名册(含职务、职级等)、个税申报记录等", + "识别'高职低编'薪酬倒挂人员,计算其薪酬超出编制标准部分", + "生成审计取证单", + "①中华人民共和国预算法_中国人大网;\n②《中华人民共和国预算法实施条例》;\n③企业内控制度" + ), + new AuditSubContent( + "3.检查项目经费合规性,是否违规使用项目经费支付超编人员成本", + "项目预算明细、费用报销凭证、人员分工表", + "分析项目支出中人工成本占比,核查超编人员参与项目合理性,并列出比例、金额。", + "生成审计取证单", + "①中华人民共和国预算法_中国人大网;\n②《中华人民共和国预算法实施条例》;\n③企业内控制度" + ) + )); + } + + // 审计子内容类 + public static class AuditSubContent { + private String auditTarget; + private String auditEvidence; + private String aiTestContent; + private String generationResult; + private String regulationBasis; + + public AuditSubContent(String auditTarget, String auditEvidence, String aiTestContent, + String generationResult, String regulationBasis) { + this.auditTarget = auditTarget; + this.auditEvidence = auditEvidence; + this.aiTestContent = aiTestContent; + this.generationResult = generationResult; + this.regulationBasis = regulationBasis; + } + + public String getAuditTarget() { return auditTarget; } + public String getAuditEvidence() { return auditEvidence; } + public String getAiTestContent() { return aiTestContent; } + public String getGenerationResult() { return generationResult; } + public String getRegulationBasis() { return regulationBasis; } + } + + // 关键词权重 + public static final Map KEYWORD_WEIGHTS = new HashMap<>(); + static { + KEYWORD_WEIGHTS.put("劳务派遣", 10); + KEYWORD_WEIGHTS.put("人员编制", 9); + KEYWORD_WEIGHTS.put("外包", 8); + KEYWORD_WEIGHTS.put("同工同酬", 9); + KEYWORD_WEIGHTS.put("三性标准", 8); + KEYWORD_WEIGHTS.put("工资总额", 8); + KEYWORD_WEIGHTS.put("福利费", 7); + KEYWORD_WEIGHTS.put("绩效考核", 8); + KEYWORD_WEIGHTS.put("机构编制", 9); + KEYWORD_WEIGHTS.put("预算编制", 7); + KEYWORD_WEIGHTS.put("假外包真派遣", 10); + KEYWORD_WEIGHTS.put("借用人员", 7); + KEYWORD_WEIGHTS.put("用工合规", 9); + KEYWORD_WEIGHTS.put("人员经费", 8); + } + + // 审计方法 + public static final List AUDIT_METHODS = Arrays.asList( + "文档审查", "数据分析", "访谈调查", "现场观察", "抽样测试", + "对比分析", "穿行测试", "合规性检查", "制度评价" + ); + + private AuditContent9PersonnelConstants() { + // 防止实例化 + } +} \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/controller/AuditContent9Controller.java b/src/main/java/com/gxwebsoft/ai/controller/AuditContent9Controller.java new file mode 100644 index 0000000..3b1e502 --- /dev/null +++ b/src/main/java/com/gxwebsoft/ai/controller/AuditContent9Controller.java @@ -0,0 +1,72 @@ +package com.gxwebsoft.ai.controller; + +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.ai.dto.AuditContentRequest; +import com.gxwebsoft.ai.dto.export.PersonnelExportEntity; +import com.gxwebsoft.ai.service.AuditContent9PersonnelService; +import com.gxwebsoft.common.core.web.ApiResult; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 审计内容9控制器 - 人员编制管理审计 + */ +@Slf4j +@Tag(name = "审计内容9-人员编制管理审计") +@RestController +@RequestMapping("/api/ai/auditContent9") +public class AuditContent9Controller extends BaseAuditContentController { + + @Autowired + private AuditContent9PersonnelService auditContent9PersonnelService; + + /** + * 生成人员编制管理审计表数据 + */ + @Operation(summary = "生成人员编制管理审计表") + @PostMapping("/generatePersonnelTable") + public ApiResult generatePersonnelTable(@RequestBody AuditContentRequest request, HttpServletRequest servletRequest) { + return generateTableData(request, servletRequest.getRequestURI(), + (params) -> auditContent9PersonnelService.generatePersonnelTableData( + params.knowledgeBaseId, params.libraryKbIds, params.projectLibrary, + params.username, params.history, params.suggestion + )); + } + + /** + * 导出人员编制管理审计表到Excel + */ + @Operation(summary = "导出人员编制管理审计表到Excel") + @PostMapping("/exportPersonnelTable") + public void exportPersonnelTable(@RequestBody Map request, HttpServletResponse response) { + exportToExcel(request, response, "人员编制管理审计表", + this::convertToPersonnelEntityList, PersonnelExportEntity.class); + } + + // ========== 数据转换方法 ========== + + private List convertToPersonnelEntityList(List> originalData) { + return originalData.stream().map(this::convertToPersonnelEntity).collect(Collectors.toList()); + } + + private PersonnelExportEntity convertToPersonnelEntity(Map item) { + PersonnelExportEntity entity = new PersonnelExportEntity(); + entity.setIndex(getStringValue(item, "index")); + entity.setAuditContent(getStringValue(item, "auditContent")); + entity.setAuditTarget(getStringValue(item, "auditTarget")); + entity.setAuditEvidence(getStringValue(item, "auditEvidence")); + entity.setGenerationResult(getStringValue(item, "generationResult")); + entity.setWorkPaperIndex(formatWorkPaperIndex(item.get("workPaperIndex"))); + return entity; + } +} \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/dto/export/PersonnelExportEntity.java b/src/main/java/com/gxwebsoft/ai/dto/export/PersonnelExportEntity.java new file mode 100644 index 0000000..1f65bb1 --- /dev/null +++ b/src/main/java/com/gxwebsoft/ai/dto/export/PersonnelExportEntity.java @@ -0,0 +1,40 @@ +// PersonnelExportEntity.java +package com.gxwebsoft.ai.dto.export; + +import lombok.Data; + +/** + * 人员编制管理审计导出实体 + */ +@Data +public class PersonnelExportEntity { + /** + * 序号 + */ + private String index; + + /** + * 审计内容 + */ + private String auditContent; + + /** + * 审计目标 + */ + private String auditTarget; + + /** + * 审计证据 + */ + private String auditEvidence; + + /** + * 生成结果 + */ + private String generationResult; + + /** + * 工作底稿索引 + */ + private String workPaperIndex; +} \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/service/AuditContent9PersonnelService.java b/src/main/java/com/gxwebsoft/ai/service/AuditContent9PersonnelService.java new file mode 100644 index 0000000..be489fd --- /dev/null +++ b/src/main/java/com/gxwebsoft/ai/service/AuditContent9PersonnelService.java @@ -0,0 +1,13 @@ +package com.gxwebsoft.ai.service; + +import com.alibaba.fastjson.JSONObject; + +public interface AuditContent9PersonnelService { + + /** + * 生成人员编制管理审计表数据 + */ + JSONObject generatePersonnelTableData( + String kbIds, String libraryKbIds, String projectLibrary, + String userName, String history, String suggestion); +} \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent9PersonnelServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent9PersonnelServiceImpl.java new file mode 100644 index 0000000..0d39ac3 --- /dev/null +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent9PersonnelServiceImpl.java @@ -0,0 +1,360 @@ +package com.gxwebsoft.ai.service.impl; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.ai.constants.AuditContent9PersonnelConstants; +import com.gxwebsoft.ai.service.AuditContent9PersonnelService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import cn.hutool.core.util.StrUtil; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class AuditContent9PersonnelServiceImpl extends AbstractAuditContentService implements AuditContent9PersonnelService { + + private static final String DIFY_WORKFLOW_TOKEN = "Bearer app-fmGhYITVQVAHaY3GJYonIGPA"; + + @Override + public JSONObject generatePersonnelTableData(String kbIds, String libraryKbIds, String projectLibrary, + String userName, String history, String suggestion) { + log.info("开始生成人员编制管理审计表数据"); + + long startTime = System.currentTimeMillis(); + + try { + // 异步并行处理每个审计内容(7个大项) + Map> futures = new HashMap<>(); + + for (String auditContent : AuditContent9PersonnelConstants.AUDIT_CONTENTS) { + futures.put(auditContent, CompletableFuture.supplyAsync(() -> + generateAuditContentData(auditContent, kbIds, libraryKbIds, projectLibrary, + userName, history, suggestion) + )); + } + + // 等待所有异步任务完成 + CompletableFuture.allOf(futures.values().toArray(new CompletableFuture[0])).join(); + + // 合并所有结果 + JSONArray allData = new JSONArray(); + int index = 1; + + for (String auditContent : AuditContent9PersonnelConstants.AUDIT_CONTENTS) { + JSONArray contentData = futures.get(auditContent).get(); + if (contentData != null) { + for (int i = 0; i < contentData.size(); i++) { + JSONObject item = contentData.getJSONObject(i); + item.put("index", index++); + allData.add(item); + } + } + } + + log.info("人员编制管理审计表生成完成 - 记录数: {}, 耗时: {}ms", + allData.size(), System.currentTimeMillis() - startTime); + + return buildSuccessResponse(allData, startTime, "personnel_establishment_audit"); + + } catch (Exception e) { + log.error("生成人员编制管理审计表失败", e); + return buildErrorResponse("生成失败: " + e.getMessage()); + } + } + + /** + * 生成单个审计内容(大项)下的所有子项数据 + */ + private JSONArray generateAuditContentData(String auditContent, String kbIds, String libraryKbIds, + String projectLibrary, String userName, + String history, String suggestion) { + + JSONArray results = new JSONArray(); + List subContents = + AuditContent9PersonnelConstants.AUDIT_SUB_CONTENTS.get(auditContent); + + if (subContents == null || subContents.isEmpty()) { + return results; + } + + // 为该审计内容检索相关知识 + Map> knowledgeSources = retrieveKnowledgeForAuditContent( + auditContent, subContents, kbIds, libraryKbIds, projectLibrary + ); + + // 处理每个子项 + for (AuditContent9PersonnelConstants.AuditSubContent subContent : subContents) { + try { + JSONArray subResult = generateSubItemData(auditContent, subContent, knowledgeSources, + userName, history, suggestion); + + if (subResult != null && !subResult.isEmpty()) { + results.addAll(subResult); + } + + } catch (Exception e) { + log.error("处理子项失败: {} - {}", auditContent, subContent.getAuditTarget(), e); + } + } + + return results; + } + + /** + * 为审计内容检索相关知识 + */ + private Map> retrieveKnowledgeForAuditContent( + String auditContent, List subContents, + String kbIds, String libraryKbIds, String projectLibrary) { + + Map> knowledgeSources = new HashMap<>(); + knowledgeSources.put("enterprise", new ArrayList<>()); + knowledgeSources.put("regulation", new ArrayList<>()); + knowledgeSources.put("auditCase", new ArrayList<>()); + + // 构建该审计内容的关键词 + List keywords = buildAuditContentKeywords(auditContent, subContents); + + // 检索企业知识库 + if (StrUtil.isNotBlank(kbIds)) { + String[] kbIdArray = kbIds.split(","); + for (String kbId : kbIdArray) { + if (StrUtil.isNotBlank(kbId)) { + knowledgeSources.get("enterprise").addAll( + queryKnowledgeBase(kbId.trim(), keywords, 80) + ); + } + } + } + + // 检索法规库 + if (StrUtil.isNotBlank(libraryKbIds)) { + String[] libIdArray = libraryKbIds.split(","); + for (String libId : libIdArray) { + if (StrUtil.isNotBlank(libId)) { + knowledgeSources.get("regulation").addAll( + queryKnowledgeBase(libId.trim(), keywords, 60) + ); + } + } + } + + // 检索案例库 + if (StrUtil.isNotBlank(projectLibrary)) { + knowledgeSources.get("auditCase").addAll( + queryKnowledgeBase(projectLibrary, keywords, 40) + ); + } + + // 去重和排序 + knowledgeSources.forEach((key, list) -> { + List processed = list.stream() + .distinct() + .sorted(this::keywordRelevanceComparator) + .limit(getLimitBySourceType(key)) + .collect(Collectors.toList()); + knowledgeSources.put(key, processed); + }); + + return knowledgeSources; + } + + /** + * 构建审计内容关键词 + */ + private List buildAuditContentKeywords(String auditContent, + List subContents) { + + List keywords = new ArrayList<>(); + keywords.add(auditContent); + + // 添加审计内容相关的关键词 + if (auditContent.contains("劳务派遣")) { + keywords.addAll(Arrays.asList("劳务派遣", "派遣工", "同工同酬", "三性标准")); + } else if (auditContent.contains("外包")) { + keywords.addAll(Arrays.asList("劳务外包", "外包合同", "假外包真派遣")); + } else if (auditContent.contains("人员经费")) { + keywords.addAll(Arrays.asList("工资总额", "福利费", "劳务费")); + } else if (auditContent.contains("借用人员")) { + keywords.addAll(Arrays.asList("借调", "借用人员", "借调程序")); + } else if (auditContent.contains("绩效管理")) { + keywords.addAll(Arrays.asList("绩效考核", "绩效管理", "绩效体系")); + } else if (auditContent.contains("机构编制")) { + keywords.addAll(Arrays.asList("机构编制", "三定方案", "编制审批", "领导职数")); + } else if (auditContent.contains("预算编制")) { + keywords.addAll(Arrays.asList("预算编制", "人员经费预算", "预算执行")); + } + + // 添加所有子项的审计目标作为关键词 + for (AuditContent9PersonnelConstants.AuditSubContent subContent : subContents) { + keywords.add(subContent.getAuditTarget()); + } + + return keywords.stream().distinct().collect(Collectors.toList()); + } + + /** + * 生成子项数据 + */ + private JSONArray generateSubItemData(String auditContent, + AuditContent9PersonnelConstants.AuditSubContent subContent, + Map> knowledgeSources, + String userName, String history, String suggestion) { + + try { + // 构建上下文 + String context = buildSubItemContext(auditContent, subContent, knowledgeSources, + history, suggestion); + + // 调用Dify工作流 - 使用正确的请求体格式 + JSONObject requestBody = buildWorkflowRequest(context, userName); + + JSONArray result = callWorkflow(DIFY_WORKFLOW_URL, DIFY_WORKFLOW_TOKEN, + requestBody, auditContent + "-" + subContent.getAuditTarget()); + + // 处理返回结果 + return processSubItemResult(result, auditContent, subContent); + + } catch (Exception e) { + log.error("生成子项数据失败: {} - {}", auditContent, subContent.getAuditTarget(), e); + return new JSONArray(); + } + } + + /** + * 构建子项上下文 + */ + private String buildSubItemContext(String auditContent, + AuditContent9PersonnelConstants.AuditSubContent subContent, + Map> knowledgeSources, + String history, String suggestion) { + + StringBuilder context = new StringBuilder(); + + context.append("## 审计任务\n"); + context.append("生成人员编制管理审计数据\n\n"); + + context.append("## 审计要求\n"); + context.append("1. 审计内容:").append(auditContent).append("\n"); + context.append("2. 审计目标:").append(subContent.getAuditTarget()).append("\n"); + context.append("3. 审计证据:").append(subContent.getAuditEvidence()).append("\n"); + context.append("4. 审计方法:").append(subContent.getAiTestContent()).append("\n"); + context.append("5. 制度依据:").append(subContent.getRegulationBasis()).append("\n\n"); + + context.append("## 生成结果要求\n"); + context.append(subContent.getGenerationResult()).append("\n\n"); + + context.append("## 重要要求\n"); + context.append("1. 必须使用具体单位名称,禁止使用'XX单位'等模糊词汇\n"); + context.append("2. 审计记录必须具体,包含文件名称、数据、人员等详细信息\n"); + context.append("3. 重点关注问题发现,提供具体证据和建议\n\n"); + + context.append("## 返回格式\n"); + context.append("返回JSON数组,每条记录包含以下字段:\n"); + context.append("- auditContent:固定为'").append(auditContent).append("'\n"); + context.append("- auditTarget:固定为'").append(subContent.getAuditTarget()).append("'\n"); + context.append("- auditEvidence:固定为'").append(subContent.getAuditEvidence()).append("'\n"); + context.append("- generationResult:审计发现和结论\n"); + context.append("- workPaperIndex:工作底稿索引,具体的文件名数组\n\n"); + + context.append("## generationResult格式\n"); + context.append("标题:在审计期间,[具体单位名称]存在[具体问题]\n\n"); + context.append("审计记录:\n经核查[具体文件],发现:[具体事实]\n\n"); + context.append("审计发现:\n上述行为构成[问题性质],违反了[相关规定]\n\n"); + context.append("定性依据:\n① [法规1];② [法规2]\n\n"); + context.append("处理建议:\n1. [建议1];2. [建议2]\n\n"); + context.append("附件:\n- [文件1]\n- [文件2]\n\n"); + + // 添加历史内容 + if (StrUtil.isNotBlank(history)) { + context.append("## 历史内容\n"); + context.append(history).append("\n\n"); + } + + // 添加用户建议 + if (StrUtil.isNotBlank(suggestion)) { + context.append("## 用户建议\n"); + context.append(suggestion).append("\n\n"); + } + + // 添加相关知识 + if (!knowledgeSources.get("enterprise").isEmpty()) { + context.append("## 企业信息\n"); + knowledgeSources.get("enterprise").forEach(info -> + context.append(info).append("\n")); + } + + if (!knowledgeSources.get("regulation").isEmpty()) { + context.append("## 法规信息\n"); + knowledgeSources.get("regulation").forEach(info -> + context.append(info).append("\n")); + } + + if (!knowledgeSources.get("auditCase").isEmpty()) { + context.append("## 案例信息\n"); + knowledgeSources.get("auditCase").forEach(info -> + context.append(info).append("\n")); + } + + return context.toString(); + } + + /** + * 处理子项返回结果 + */ + private JSONArray processSubItemResult(JSONArray result, String auditContent, + AuditContent9PersonnelConstants.AuditSubContent subContent) { + + if (result == null || result.isEmpty()) { + JSONArray defaultResult = new JSONArray(); + JSONObject defaultItem = new JSONObject(); + defaultItem.put("auditContent", auditContent); + defaultItem.put("auditTarget", subContent.getAuditTarget()); + defaultItem.put("auditEvidence", subContent.getAuditEvidence()); + defaultItem.put("generationResult", "审计数据待生成"); + defaultItem.put("workPaperIndex", new JSONArray()); + defaultResult.add(defaultItem); + return defaultResult; + } + + return result; + } + + /** + * 关键词相关性比较器 + */ + private int keywordRelevanceComparator(String content1, String content2) { + int score1 = calculateKeywordScore(content1); + int score2 = calculateKeywordScore(content2); + return Integer.compare(score2, score1); + } + + /** + * 计算关键词得分 + */ + private int calculateKeywordScore(String content) { + int score = 0; + for (Map.Entry entry : AuditContent9PersonnelConstants.KEYWORD_WEIGHTS.entrySet()) { + if (content.contains(entry.getKey())) { + score += entry.getValue(); + } + } + return score; + } + + /** + * 获取不同来源的限制条数 + */ + private int getLimitBySourceType(String sourceType) { + switch (sourceType) { + case "enterprise": return 80; + case "regulation": return 60; + case "auditCase": return 40; + default: return 30; + } + } +} \ No newline at end of file