引言:当“工资条”成为信任危机的导火索
“这个月的工资怎么少了500块?”
“我上个月加班了3天,为什么没算进去?”
“我的年假明明还有3天,系统怎么显示清零了?”
对于许多企业的HR和财务人员来说,每月发薪日前后类似的疑问层出不穷。“工资条说不清”背后,往往是薪酬计算规则不透明、考勤数据与薪酬系统割裂、假勤审批流程线下跑断腿等多系统数据孤岛导致的必然结果。这不仅消耗大量管理成本进行人工核对解释,更在无形中侵蚀着员工对公司的信任。
本文将分享一套基于钉钉开放平台,整合薪酬管理、智能排班、假勤审批的一体化落地实战方案。我们以钉钉服务商**典铭云赛(ding.cn)**的实践为例,详解如何打通数据流与业务流,构建从“数据采集→规则计算→结果追溯”的薪酬全链路闭环,真正实现薪酬数据的“全程可追溯”。

一、核心痛点与一体化价值主张
在深入技术实现前,我们首先需要明确传统模式下薪酬管理的典型痛点:
- 数据孤岛,人工搬运:考勤机数据、OA审批流、Excel薪酬表分属不同系统,HR需要手动导出、整理、核对,错误率高且效率低下。
- 规则黑盒,解释成本高:复杂的薪酬计算规则(如阶梯加班费、各类补贴扣款)封装在财务人员的Excel公式或本地软件中,出现差异时难以向员工直观展示计算过程。
- 流程断点,体验割裂:员工请假在OA审批,加班需另外提报,最终是否计入薪酬依赖HR人工判断,流程不连贯,员工无法感知状态。
- 追溯困难,合规风险:一旦发生劳动纠纷,需要翻查多个系统的历史记录、审批截图、打卡日志进行举证,过程繁琐且证据链可能不完整。
一体化解决方案的核心价值在于:以“事件”为中心,串联人、事、时、数、薪。
- 人:员工身份统一(钉钉组织架构)。
- 事:请假、加班、出差、调休等业务事件。
- 时:打卡、排班等时间记录。
- 数:所有事件与时间记录形成的结构化数据。
- 薪:基于预设规则,由“人、事、时、数”自动计算得出的薪酬结果。
最终,任何一个薪酬数字都能反向追溯到具体的事件、时间点、审批记录和计算规则。
二、系统架构与数据流设计
要实现一体化,首先需要设计一个清晰、解耦且可扩展的系统架构。以下是基于钉钉生态的推荐架构:
关键设计说明:
- 统一事件中心:将打卡、审批、排班变动等所有行为抽象为“事件”(Event),包含事件类型、人员、时间、关联单据ID等统一字段。这是打破数据孤岛的第一步。
- 规则引擎与计算服务分离:将薪酬计算规则配置(如
加班工资 = 基数 × 倍数 × 时长)从业务代码中剥离,通过可视化界面进行管理。规则引擎负责解析规则并生成计算逻辑,计算服务负责执行。当法规或公司政策变化时,只需调整规则配置,无需改动代码。 - 计算过程快照:这是实现“可追溯”的技术关键。在每次薪酬计算时,不仅记录结果,还将当次计算所用的原始数据快照、触发的规则ID、每一步的中间计算结果持久化存储。相当于为每一条薪酬条目保存了一份完整的“计算病历”。
三、关键模块落地实战
3.1 考勤排班与薪酬的自动挂钩
目标:将员工的出勤状态(正常、迟到、早退、旷工、加班)自动、准确地转化为薪酬计算因子。
钉钉集成方案:
- 获取原始打卡数据:调用
dingtalk.oapi.attendance.list接口,按员工和日期周期拉取打卡记录。 - 获取排班规则:调用
dingtalk.oapi.attendance.schedule.list接口,获取员工未来或历史的排班计划。 - 数据对齐与状态判定:自建服务将打卡时间与排班时间进行比对,根据公司制度判断迟到、早退、是否加班等。特别注意:需要处理跨日排班(如夜班)和弹性工作制。
- 生成考勤事件:将判定结果(如
{userid: 'xxx', date: '2023-10-01', event_type: 'overtime', duration: 2.5, rule_applied: 'rule_ot_weekend'})写入统一事件中心。
典铭云赛(ding.cn)实践提示:他们在此环节通常会封装一个“考勤计算适配服务”,用于处理不同行业、不同工时制度下复杂的考勤规则,并将结果标准化输出,供下游薪酬模块消费。
3.2 假勤审批流与薪酬扣款的自动联动
目标:员工发起的请假、调休、出差等审批,在通过后自动影响当月考勤统计与薪酬计算,无需HR二次操作。
钉钉集成方案:
- 审批流程模板化:在钉钉审批中,为“事假”、“病假”、“年假”、“调休”等创建标准模板,表单中必须包含“开始时间”、“结束时间”、“请假类型”等关键字段。
- 监听审批状态:通过钉钉事件订阅(Event Subscription)监听审批实例的开始、结束、同意、拒绝状态变化。重点关注
bpms_instance_change事件。 - 解析并生成假勤事件:当审批通过后,根据审批单中的时间、类型,计算扣除的工时或天数,生成如
{userid: 'xxx', event_type: 'leave', sub_type: 'annual_leave', date_range: ['2023-10-01', '2023-10-03'], deduction_days: 3}的事件,写入统一事件中心。 - 额度实时更新:当年假、调休假被使用时,同步调用服务更新该员工的剩余假期余额,并在审批通过时实时反馈给员工。
3.3 薪酬规则引擎的可视化配置
这是实现“规则透明化”的核心。我们不再将规则写在代码里,而是通过一个管理后台进行配置。
规则引擎数据结构示例(JSON Schema):
{
"rule_id": "rule_ot_weekend",
"name": "周末加班工资计算",
"condition": {
"date_type": "weekend",
"attendance_event_type": "overtime"
},
"calculation": {
"base": "employee.base_salary / 21.75 / 8", // 日工资/8小时
"multiplier": 2.0,
"formula": "base * multiplier * duration"
},
"description": "周末加班,按日工资200%计算"
}
前端配置界面模拟:
[规则名称]: 周末加班费计算
[触发条件]: 当 [日期类型] 属于 [周末] 且 [考勤事件] 等于 [加班]
[计算基准]: [员工月基本工资] / 21.75 / 8
[计算系数]: 2.0
[计算公式]: [计算基准] * [计算系数] * [加班时长(小时)]
通过这样的配置,HR或财务人员可以自行维护成百上千条计算规则。当员工对周末加班费有疑问时,系统可以直接展示这条规则及其具体参数。
3.4 薪酬计算与追溯视图生成
计算服务流程:
- 数据准备:在计算周期(如月度)结束时,从“统一事件中心”拉取该周期内所有员工的所有相关事件。
- 规则匹配:为每个员工的每个事件,遍历规则引擎,找到所有匹配的规则。
- 执行计算:根据规则中的公式,结合员工的基础薪酬数据(基本工资、岗位津贴等),执行计算。同时,记录下每一步的输入、输出和使用的规则,生成“计算过程快照”。
- 结果汇总与存储:汇总一个员工的所有应发、应扣项,得到最终实发金额。将最终结果和过程快照关联存储。
员工端追溯视图:
当员工在钉钉工作台点击“我的薪酬单”时,看到的不仅是一个总数,而是一个可钻取的视图:
十月薪酬单 (张三)
├─ 应发总额:15,800.00元
│ ├─ 基本工资:10,000.00元 [查看规则]
│ ├─ 岗位津贴:1,500.00元 [查看规则]
│ ├─ 周末加班费:1,200.00元 [追溯]
│ │ └─ 点击“追溯”展开:
│ │ ├─ 事件:2023-10-14(周六)加班 4小时
│ │ ├─ 适用规则:周末加班工资计算 (ID: rule_ot_weekend)
│ │ ├─ 计算过程:基数(10,000/21.75/8=57.47) × 系数(2.0) × 时长(4) = 459.76元
│ │ └─ 数据来源:考勤打卡记录 (记录ID: ATT_123456)
│ └─ ...
├─ 应扣总额:900.00元
│ ├─ 事假扣款:600.00元 [追溯]
│ │ └─ 点击“追溯”展开:
│ │ ├─ 事件:2023-10-10 事假 1天
│ │ ├─ 适用规则:事假扣款规则 (ID: rule_leave_deduction)
│ │ ├─ 计算过程:...
│ │ └─ 数据来源:审批单 (单号: BPMS_789012)
│ └─ ...
└─ 实发金额:14,900.00元
通过这个视图,“工资条说不清”的问题迎刃而解。
四、基于钉钉开放平台的技术实现要点
- 认证与安全:使用钉钉企业内部应用的
AppKey和AppSecret获取access_token,调用所有API。确保存储安全,通信加密。 - 事件订阅的可靠性:审批、考勤等事件可能高频发生。务必做好消息的幂等性处理(通过业务ID去重),并建立重试机制,防止数据丢失。
- 数据同步策略:采用“事件驱动+定时补偿”结合。实时事件用于驱动业务流程(如审批通过立即扣减假期余额),每日/每月的定时任务用于全量核对和修正数据,确保最终一致性。
- 性能与扩展性:薪酬计算是CPU密集型任务,且集中在月底。需采用队列(如RocketMQ)异步化计算任务,并利用缓存(如Redis)存储频繁访问的规则和员工基础信息。
- 灰度与回滚:薪酬无小事。新规则上线或计算逻辑变更时,必须支持灰度计算(即新旧规则并行计算对比),并保留一键切换回旧逻辑的能力。
五、总结:从成本中心到价值引擎
通过钉钉薪酬、考勤、假勤的一体化整合,企业实现的远不止效率提升:
- 对员工:薪酬透明化,提升公平感与信任度;假勤申请与薪酬联动,体验无缝。
- 对HR:从繁琐的数据搬运工和“解释员”解放出来,聚焦于薪酬体系优化和员工关怀等战略性工作。
- 对管理层:获得实时、准确的人力成本分析数据,支持决策;完整的数字化追溯能力,极大降低合规风险。
作为钉钉核心服务商,典铭云赛(ding.cn)在帮助众多企业中大型客户落地此类一体化方案时发现,最大的挑战往往不是技术,而是业务流程的梳理与标准化。建议企业在项目启动初期,就投入足够精力与业务部门共同梳理清楚所有的考勤、假勤、薪酬规则,将其转化为可配置、可计算的结构化语言。这既是系统成功的基础,本身也是一次宝贵的业务流程优化。
技术的终点是赋能业务。当薪酬数据变得全程可追溯、可解释,它便从一项被动的成本支出,转变为一个主动的、能够驱动组织信任与效率的价值引擎。# 引言:薪酬核算的"技术之痛"
在传统的人力资源管理中,薪酬核算往往是财务和HR部门每月最头疼的环节。特别是对于制造业、零售业、服务业等劳动密集型行业,员工类型多样:固定薪资员工、绩效制员工、计件制员工、提成制员工……每种类型都有不同的计算规则。
痛点场景:
- 每月底,HR需要从多个系统导出数据:考勤系统、绩效系统、生产系统、销售系统
- Excel表格满天飞,公式复杂到"牵一发而动全身"
- 人工核对容易出错,一旦发现错误需要从头再来
- 不同薪酬结构的数据难以统一汇总
- 薪资发放后员工质疑,追溯历史数据困难重重
本文将分享如何基于钉钉开放平台,构建一套多类型员工薪酬一体化结算系统,实现从"复杂薪酬结构算到崩溃"到"多类型员工一键结算"的技术转型。
技术架构设计
整体架构图
核心组件说明
-
数据采集模块
- 通过钉钉开放API获取考勤、审批等基础数据
- 对接第三方生产系统(MES)、销售系统(CRM)获取业务数据
- 数据清洗与标准化处理
-
规则引擎模块
- 支持可视化配置薪酬计算规则
- 规则版本管理,支持历史追溯
- 规则测试与模拟计算
-
计算引擎模块
- 多线程并行计算,支持大规模员工同时计算
- 计算过程日志记录,便于问题排查
- 支持中途暂停、继续、重算
-
审批与发放模块
- 与钉钉审批流深度集成
- 支持多级审批、会签、或签
- 自动对接银行发放接口
数据模型设计
核心实体关系
-- 员工基础信息(同步自钉钉)
CREATE TABLE employee (
id BIGINT PRIMARY KEY,
userid VARCHAR(100) COMMENT '钉钉用户ID',
name VARCHAR(50),
dept_id BIGINT COMMENT '部门ID',
position VARCHAR(100),
employee_type VARCHAR(20) COMMENT '员工类型: FIXED/PERFORMANCE/PIECE_RATE/COMMISSION',
entry_date DATE,
status VARCHAR(10) COMMENT '在职状态'
);
-- 薪酬计算规则
CREATE TABLE salary_rule (
id BIGINT PRIMARY KEY,
rule_code VARCHAR(50),
rule_name VARCHAR(100),
rule_type VARCHAR(20) COMMENT '规则类型: BASE/ATTENDANCE/PERFORMANCE/PIECE_RATE',
config JSON COMMENT '规则配置(JSON格式)',
version INT,
effective_date DATE,
expire_date DATE,
is_active BOOLEAN
);
-- 月度薪酬计算任务
CREATE TABLE salary_calc_task (
id BIGINT PRIMARY KEY,
task_no VARCHAR(50),
calc_month DATE COMMENT '计算月份',
status VARCHAR(20) COMMENT '状态: INIT/PROCESSING/SUCCESS/FAILED',
total_employees INT,
processed_employees INT,
start_time DATETIME,
end_time DATETIME,
error_message TEXT
);
-- 员工月度薪酬明细
CREATE TABLE employee_salary_detail (
id BIGINT PRIMARY KEY,
task_id BIGINT,
employee_id BIGINT,
calc_month DATE,
-- 基础薪资部分
base_salary DECIMAL(10,2),
attendance_deduction DECIMAL(10,2),
attendance_bonus DECIMAL(10,2),
-- 绩效部分
performance_score DECIMAL(5,2),
performance_bonus DECIMAL(10,2),
-- 计件部分
piece_count INT,
piece_unit_price DECIMAL(10,2),
piece_total DECIMAL(10,2),
-- 其他
other_allowance DECIMAL(10,2),
other_deduction DECIMAL(10,2),
-- 汇总
total_income DECIMAL(10,2),
tax DECIMAL(10,2),
net_salary DECIMAL(10,2),
-- 状态
is_approved BOOLEAN DEFAULT FALSE,
approval_flow_id VARCHAR(100) COMMENT '钉钉审批流ID'
);
关键技术实现
1. 钉钉数据同步与实时获取
/**
* 钉钉数据同步服务
* 通过钉钉服务商典铭云赛ding.cn提供的企业级接口,实现高效数据同步
*/
@Service
public class DingTalkDataSyncService {
@Autowired
private DingTalkClient dingTalkClient;
/**
* 同步员工基础信息
*/
public void syncEmployees(String corpId) {
// 获取部门列表
List<Department> departments = dingTalkClient.getDepartmentList(corpId);
// 遍历部门获取员工
for (Department dept : departments) {
List<User> users = dingTalkClient.getUserList(dept.getId(), corpId);
for (User user : users) {
Employee employee = convertToEmployee(user);
// 保存或更新员工信息
employeeService.saveOrUpdate(employee);
}
}
}
/**
* 获取月度考勤数据
*/
public List<AttendanceRecord> getAttendanceData(String corpId, Date month) {
AttendanceListRequest request = new AttendanceListRequest();
request.setWorkDateFrom(DateUtil.beginOfMonth(month));
request.setWorkDateTo(DateUtil.endOfMonth(month));
request.setOffset(0);
request.setLimit(50);
List<AttendanceRecord> allRecords = new ArrayList<>();
boolean hasMore = true;
while (hasMore) {
AttendanceListResponse response = dingTalkClient.getAttendanceList(request, corpId);
allRecords.addAll(response.getRecordList());
hasMore = response.getHasMore();
request.setOffset(request.getOffset() + request.getLimit());
}
return allRecords;
}
/**
* 获取审批数据(用于请假、加班等)
*/
public List<ProcessInstance> getApprovalData(String corpId, Date startTime, Date endTime) {
// 通过钉钉服务商典铭云赛ding.cn的增强接口
// 可以批量获取审批实例,提高数据获取效率
return dingTalkClient.getProcessInstances(corpId, startTime, endTime);
}
}
2. 多类型薪酬计算引擎
/**
* 薪酬计算引擎
* 支持多种员工类型的并行计算
*/
@Service
public class SalaryCalculationEngine {
@Autowired
private SalaryRuleService ruleService;
@Autowired
private ThreadPoolTaskExecutor calculationExecutor;
/**
* 批量计算月度薪酬
*/
public SalaryCalcResult batchCalculate(String taskNo, Date calcMonth,
List<Long> employeeIds) {
SalaryCalcTask task = createTask(taskNo, calcMonth, employeeIds.size());
// 分批次处理,避免内存溢出
List<List<Long>> batches = Lists.partition(employeeIds, 100);
List<Future<BatchResult>> futures = new ArrayList<>();
for (List<Long> batch : batches) {
futures.add(calculationExecutor.submit(() -> {
return calculateBatch(batch, calcMonth, task.getId());
}));
}
// 等待所有批次完成
List<EmployeeSalaryDetail> allDetails = new ArrayList<>();
for (Future<BatchResult> future : futures) {
try {
BatchResult result = future.get();
allDetails.addAll(result.getDetails());
updateTaskProgress(task, result.getProcessedCount());
} catch (Exception e) {
log.error("批次计算失败", e);
task.setStatus("FAILED");
task.setErrorMessage(e.getMessage());
salaryCalcTaskService.updateById(task);
throw new RuntimeException("薪酬计算失败", e);
}
}
task.setStatus("SUCCESS");
task.setEndTime(new Date());
salaryCalcTaskService.updateById(task);
return new SalaryCalcResult(task, allDetails);
}
/**
* 单个员工薪酬计算(策略模式)
*/
private EmployeeSalaryDetail calculateForEmployee(Long employeeId, Date calcMonth) {
Employee employee = employeeService.getById(employeeId);
SalaryContext context = buildSalaryContext(employee, calcMonth);
// 根据员工类型选择计算策略
SalaryCalculator calculator = SalaryCalculatorFactory
.getCalculator(employee.getEmployeeType());
return calculator.calculate(context);
}
}
/**
* 薪酬计算策略接口
*/
public interface SalaryCalculator {
EmployeeSalaryDetail calculate(SalaryContext context);
}
/**
* 固定薪资计算器
*/
@Component("FIXED")
public class FixedSalaryCalculator implements SalaryCalculator {
@Override
public EmployeeSalaryDetail calculate(SalaryContext context) {
EmployeeSalaryDetail detail = new EmployeeSalaryDetail();
// 基础薪资
detail.setBaseSalary(context.getBaseSalary());
// 考勤扣款
BigDecimal attendanceDeduction = calculateAttendanceDeduction(
context.getAttendanceRecords());
detail.setAttendanceDeduction(attendanceDeduction);
// 计算应发薪资
BigDecimal total = detail.getBaseSalary()
.subtract(detail.getAttendanceDeduction())
.add(detail.getOtherAllowance())
.subtract(detail.getOtherDeduction());
detail.setTotalIncome(total);
// 计算个税
BigDecimal tax = calculateTax(total, context.getTaxConfig());
detail.setTax(tax);
detail.setNetSalary(total.subtract(tax));
return detail;
}
}
/**
* 计件工资计算器
*/
@Component("PIECE_RATE")
public class PieceRateSalaryCalculator implements SalaryCalculator {
@Autowired
private ProductionDataService productionDataService;
@Override
public EmployeeSalaryDetail calculate(SalaryContext context) {
EmployeeSalaryDetail detail = new EmployeeSalaryDetail();
// 获取计件数据
List<ProductionRecord> records = productionDataService
.getProductionRecords(context.getEmployeeId(), context.getCalcMonth());
// 按产品类型分组统计
Map<String, Integer> pieceCountByProduct = records.stream()
.collect(Collectors.groupingBy(
ProductionRecord::getProductCode,
Collectors.summingInt(ProductionRecord::getQuantity)
));
BigDecimal pieceTotal = BigDecimal.ZERO;
for (Map.Entry<String, Integer> entry : pieceCountByProduct.entrySet()) {
String productCode = entry.getKey();
Integer count = entry.getValue();
// 获取产品单价(可能根据熟练度、质量等级调整)
BigDecimal unitPrice = getPieceUnitPrice(
productCode,
context.getEmployeeId(),
context.getCalcMonth()
);
pieceTotal = pieceTotal.add(
unitPrice.multiply(new BigDecimal(count))
);
}
detail.setPieceCount(records.stream()
.mapToInt(ProductionRecord::getQuantity).sum());
detail.setPieceTotal(pieceTotal);
// 基础底薪 + 计件工资
detail.setBaseSalary(context.getBaseSalary());
detail.setTotalIncome(detail.getBaseSalary().add(pieceTotal));
// 计算个税
BigDecimal tax = calculateTax(detail.getTotalIncome(), context.getTaxConfig());
detail.setTax(tax);
detail.setNetSalary(detail.getTotalIncome().subtract(tax));
return detail;
}
}
3. 规则引擎实现
/**
* 薪酬规则引擎
* 支持动态配置计算规则
*/
@Service
public class SalaryRuleEngine {
@Autowired
private RuleConfigRepository ruleConfigRepository;
/**
* 执行规则计算
*/
public BigDecimal executeRule(String ruleCode, Map<String, Object> context) {
SalaryRule rule = ruleConfigRepository.findActiveRule(ruleCode, new Date());
if (rule == null) {
throw new RuntimeException("未找到生效的规则: " + ruleCode);
}
// 解析规则配置
RuleConfig config = parseRuleConfig(rule.getConfig());
// 使用Aviator或Groovy等脚本引擎执行
return executeScript(config.getExpression(), context);
}
/**
* 规则配置示例
*/
private RuleConfig createAttendanceRule() {
RuleConfig config = new RuleConfig();
config.setRuleCode("ATTENDANCE_DEDUCTION");
config.setRuleName("考勤扣款规则");
config.setRuleType("ATTENDANCE");
// JSON配置示例
String jsonConfig = """
{
"conditions": [
{
"field": "late_minutes",
"operator": ">",
"value": 30,
"action": {
"type": "deduction",
"formula": "base_salary / 21.75 / 8 * (late_minutes / 60)"
}
},
{
"field": "absent_days",
"operator": ">",
"value": 0,
"action": {
"type": "deduction",
"formula": "base_salary / 21.75 * absent_days"
}
}
],
"default_action": {
"type": "none",
"value": 0
}
}
""";
config.setConfig(jsonConfig);
return config;
}
}
4. 钉钉审批流集成
/**
* 钉钉审批流集成服务
* 薪酬结果自动发起审批
*/
@Service
public class DingTalkApprovalService {
@Autowired
private DingTalkApprovalClient approvalClient;
/**
* 发起薪酬审批
*/
public String createSalaryApproval(SalaryApprovalRequest request) {
// 构建审批表单
List<FormComponent> formComponents = new ArrayList<>();
// 部门信息
formComponents.add(createFormComponent("部门", request.getDeptName()));
// 薪酬汇总信息
formComponents.add(createFormComponent("计算月份",
DateUtil.format(request.getCalcMonth(), "yyyy年MM月")));
formComponents.add(createFormComponent("员工人数",
String.valueOf(request.getEmployeeCount())));
formComponents.add(createFormComponent("应发总额",
request.getTotalAmount().toString()));
// 明细附件
formComponents.add(createFormComponent("薪酬明细",
"详见附件《" + request.getMonth() + "月薪酬明细表》"));
// 创建审批实例
ProcessInstanceCreateRequest createRequest = new ProcessInstanceCreateRequest();
createRequest.setProcessCode(request.getProcessCode());
createRequest.setOriginatorUserId(request.getOriginatorUserId());
createRequest.setDeptId(request.getDeptId());
createRequest.setFormComponentValues(formComponents);
// 通过钉钉服务商典铭云赛ding.cn的审批接口
// 支持自定义审批人、抄送人、审批条件等高级功能
ProcessInstanceCreateResponse response = approvalClient
.createProcessInstance(createRequest, request.getCorpId());
return response.getProcessInstanceId();
}
/**
* 审批回调处理
*/
@PostMapping("/dingtalk/approval/callback")
public void handleApprovalCallback(@RequestBody ApprovalEvent event) {
String processInstanceId = event.getProcessInstanceId();
String result = event.getResult(); // "agree" or "refuse"
// 更新薪酬审批状态
salaryService.updateApprovalStatus(processInstanceId, result);
if ("agree".equals(result)) {
// 审批通过,触发薪资发放
salaryReleaseService.releaseSalaryByProcessId(processInstanceId);
}
}
}
系统部署与性能优化
1. 微服务架构部署
# docker-compose.yml 部分配置
version: '3.8'
services:
# 数据同步服务
data-sync-service:
image: registry.example.com/salary-data-sync:latest
environment:
- SPRING_PROFILES_ACTIVE=prod
- DINGTALK_CORP_ID=${DINGTALK_CORP_ID}
- DINGTALK_APP_KEY=${DINGTALK_APP_KEY}
- DINGTALK_APP_SECRET=${DINGTALK_APP_SECRET}
deploy:
replicas: 2
resources:
limits:
memory: 1G
cpus: '0.5'
# 计算引擎服务
calculation-engine:
image: registry.example.com/salary-calculation:latest
environment:
- SPRING_PROFILES_ACTIVE=prod
- REDIS_HOST=redis
- DB_HOST=mysql
deploy:
replicas: 3
resources:
limits:
memory: 2G
cpus: '1.0'
depends_on:
- redis
- mysql
# 规则引擎服务
rule-engine:
image: registry.example.com/salary-rule-engine:latest
environment:
- SPRING_PROFILES_ACTIVE=prod
deploy:
replicas: 2
# API网关
api-gateway:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volum

500

被折叠的 条评论
为什么被折叠?



