feat: 添加自动化部署方案(Docker + 远程服务器两套方案)

- 新增 deploy/docker/:Docker 本机模拟部署,含 Dockerfile、docker-compose、deploy.sh 一键脚本
- 新增 deploy/remote/:远程服务器部署,含 SSH 自动上传、重启、回滚脚本
- 新增 deploy/README.md:完整使用手册,含现状分析、落地调整工作清单、命令速查
- 新增 build.sh/start.sh:本地构建和启动脚本(含飞书通知)
- 新增前端 .env.docker 环境配置,API 指向测试服务器
- 前端 package.json 新增 build-docker 命令
- 更新 .gitignore:排除 IDE 配置、SQL 数据、Docker 敏感文件
- 前端 UI 样式优化(多个页面组件)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
xqzp2026
2026-04-15 18:41:15 +09:30
parent d27abbb529
commit 8373460096
71 changed files with 8003 additions and 350 deletions

View File

@@ -0,0 +1,281 @@
package xiaoqu.home.open.constant;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* 业务规则注册表.
*
* 所有核心业务规则在此集中定义,作为系统业务逻辑的"单一事实来源"。
*
* [PROTECTED] 此文件为红区文件AI 不可直接修改。
* 修改需审批人:项目经理 + 技术负责人。
*
* 使用方式:
* 1. 业务代码中引用此处常量,禁止硬编码业务规则值
* 2. 系统启动时调用 validateAll() 校验规则完整性
* 3. 新增业务规则须同步添加校验方法和单元测试
*
* @author SmartClean Team
* @since 2026-04-15
*/
public final class BusinessRules {
private BusinessRules() {
throw new UnsupportedOperationException("常量类不可实例化");
}
// =====================================================================
// 一、工资计算规则 (BR-SALARY)
// =====================================================================
/** BR-SALARY-001: 法定月计薪天数(劳动法规定) */
public static final BigDecimal MONTHLY_WORK_DAYS = new BigDecimal("21.75");
/** BR-SALARY-002: 平日加班费率1.5 倍) */
public static final BigDecimal WEEKDAY_OVERTIME_RATE = new BigDecimal("1.5");
/** BR-SALARY-003: 周末加班费率2.0 倍) */
public static final BigDecimal WEEKEND_OVERTIME_RATE = new BigDecimal("2.0");
/** BR-SALARY-004: 法定假日加班费率3.0 倍) */
public static final BigDecimal HOLIDAY_OVERTIME_RATE = new BigDecimal("3.0");
/** BR-SALARY-005: 标准日工作时长(小时) */
public static final BigDecimal STANDARD_DAILY_WORK_HOURS = new BigDecimal("8");
/** BR-SALARY-006: 工资金额计算精度(小数位数) */
public static final int SALARY_SCALE = 2;
/** BR-SALARY-007: 工资金额舍入模式(四舍五入) */
public static final RoundingMode SALARY_ROUNDING = RoundingMode.HALF_UP;
/** BR-SALARY-008: 最低工资标准(元/月),按当地政策设定,需定期更新 */
public static final BigDecimal MINIMUM_MONTHLY_WAGE = new BigDecimal("2690.00");
// =====================================================================
// 二、打卡考勤规则 (BR-ATTEND)
// =====================================================================
/** BR-ATTEND-001: 打卡地理围栏默认半径(米) */
public static final int DEFAULT_FENCE_RADIUS_METERS = 200;
/** BR-ATTEND-002: 防重复打卡时间窗口(分钟),同类型打卡在此时间内不可重复 */
public static final int DUPLICATE_PUNCH_WINDOW_MINUTES = 30;
/** BR-ATTEND-003: 迟到判定阈值(分钟),超过排班开始时间此值算迟到 */
public static final int LATE_THRESHOLD_MINUTES = 15;
/** BR-ATTEND-004: 早退判定阈值(分钟),早于排班结束时间此值算早退 */
public static final int EARLY_LEAVE_THRESHOLD_MINUTES = 15;
/** BR-ATTEND-005: 严重迟到阈值(分钟),超过此值算严重迟到 */
public static final int SEVERE_LATE_THRESHOLD_MINUTES = 60;
/** BR-ATTEND-006: 旷工判定阈值(分钟),超过此值未打卡算旷工 */
public static final int ABSENT_THRESHOLD_MINUTES = 120;
/** BR-ATTEND-007: GPS 定位超时时间(秒) */
public static final int GPS_TIMEOUT_SECONDS = 15;
/** BR-ATTEND-008: WiFi 辅助定位允许的最大偏差(米) */
public static final int WIFI_LOCATION_MAX_DEVIATION_METERS = 100;
/** BR-ATTEND-009: 只允许本人打卡,不可代打 */
public static final boolean SELF_PUNCH_ONLY = true;
/** BR-ATTEND-010: 打卡记录保留期限(天),超过此期限的记录可归档 */
public static final int PUNCH_RECORD_RETENTION_DAYS = 365;
// =====================================================================
// 三、排班规则 (BR-SCHED)
// =====================================================================
/** BR-SCHED-001: 单人单日最大排班时长(小时) */
public static final int MAX_DAILY_SCHEDULE_HOURS = 12;
/** BR-SCHED-002: 两个排班之间最小休息时间(小时) */
public static final int MIN_REST_HOURS_BETWEEN_SHIFTS = 8;
/** BR-SCHED-003: 排班交接重叠容差(分钟),此范围内不算冲突 */
public static final int SCHEDULE_HANDOVER_TOLERANCE_MINUTES = 0;
/** BR-SCHED-004: 排班提前发布天数,排班表至少提前此天数发布 */
public static final int SCHEDULE_PUBLISH_ADVANCE_DAYS = 3;
/** BR-SCHED-005: 单人单周最大排班天数 */
public static final int MAX_WEEKLY_SCHEDULE_DAYS = 6;
/** BR-SCHED-006: 夜班定义起始时间24 小时制) */
public static final int NIGHT_SHIFT_START_HOUR = 22;
/** BR-SCHED-007: 夜班定义结束时间24 小时制) */
public static final int NIGHT_SHIFT_END_HOUR = 6;
// =====================================================================
// 四、任务管理规则 (BR-TASK)
// =====================================================================
/** BR-TASK-001: 任务超时告警阈值(分钟),超过预计时长此值后触发告警 */
public static final int TASK_OVERTIME_ALERT_MINUTES = 30;
/** BR-TASK-002: 任务照片最少数量,完成任务时至少需上传此数量的照片 */
public static final int TASK_MIN_PHOTO_COUNT = 1;
/** BR-TASK-003: 任务照片最大数量 */
public static final int TASK_MAX_PHOTO_COUNT = 9;
/** BR-TASK-004: 任务评分满分 */
public static final int TASK_MAX_SCORE = 100;
/** BR-TASK-005: 任务合格分数线 */
public static final int TASK_PASS_SCORE = 60;
// =====================================================================
// 五、巡检规则 (BR-PATROL)
// =====================================================================
/** BR-PATROL-001: 巡检点最小停留时间(秒),少于此时间判定为无效巡检 */
public static final int PATROL_MIN_STAY_SECONDS = 30;
/** BR-PATROL-002: 巡检轨迹记录间隔(秒) */
public static final int PATROL_TRACK_INTERVAL_SECONDS = 10;
/** BR-PATROL-003: 巡检异常自动上报,发现异常时自动生成工单 */
public static final boolean PATROL_AUTO_REPORT_ANOMALY = true;
// =====================================================================
// 六、系统通用规则 (BR-SYS)
// =====================================================================
/** BR-SYS-001: 分页查询每页最大条数 */
public static final int MAX_PAGE_SIZE = 100;
/** BR-SYS-002: 分页查询默认每页条数 */
public static final int DEFAULT_PAGE_SIZE = 20;
/** BR-SYS-003: 数据删除方式 — 逻辑删除标记值0=未删除, 1=已删除) */
public static final int DELETED_FLAG = 1;
public static final int NOT_DELETED_FLAG = 0;
/** BR-SYS-004: 批量操作最大条数 */
public static final int MAX_BATCH_SIZE = 500;
/** BR-SYS-005: 导出 Excel 最大行数 */
public static final int MAX_EXPORT_ROWS = 10000;
/** BR-SYS-006: 文件上传最大大小MB */
public static final int MAX_UPLOAD_SIZE_MB = 20;
/** BR-SYS-007: 允许上传的图片格式 */
public static final Set<String> ALLOWED_IMAGE_FORMATS = Collections.unmodifiableSet(
new HashSet<>(Arrays.asList("jpg", "jpeg", "png", "bmp", "gif")));
// =====================================================================
// 七、龙虾助手/对话交互规则 (BR-CHAT)
// =====================================================================
/** BR-CHAT-001: 写操作需要二次确认 */
public static final boolean WRITE_OPERATION_REQUIRES_CONFIRM = true;
/** BR-CHAT-002: 闲聊不触发任何数据库操作 */
public static final boolean CHITCHAT_NO_DB_OPERATION = true;
/** BR-CHAT-003: 危险操作(删除/修改工资/修改权限)通过对话禁止执行 */
public static final boolean DANGEROUS_OPERATION_BLOCKED_VIA_CHAT = true;
// =====================================================================
// 规则校验方法
// =====================================================================
/**
* 校验所有业务规则完整性.
* 建议在系统启动时调用,确保核心常量未被篡改。
*
* @throws AssertionError 如果任何规则被篡改
*/
public static void validateAll() {
validateSalaryRules();
validateAttendanceRules();
validateScheduleRules();
validateSystemRules();
}
/**
* 校验工资计算规则.
*/
public static void validateSalaryRules() {
assertRule(MONTHLY_WORK_DAYS.compareTo(new BigDecimal("21.75")) == 0,
"BR-SALARY-001", "月计薪天数", "21.75", MONTHLY_WORK_DAYS.toString());
assertRule(WEEKDAY_OVERTIME_RATE.compareTo(new BigDecimal("1.5")) == 0,
"BR-SALARY-002", "平日加班费率", "1.5", WEEKDAY_OVERTIME_RATE.toString());
assertRule(WEEKEND_OVERTIME_RATE.compareTo(new BigDecimal("2.0")) == 0,
"BR-SALARY-003", "周末加班费率", "2.0", WEEKEND_OVERTIME_RATE.toString());
assertRule(HOLIDAY_OVERTIME_RATE.compareTo(new BigDecimal("3.0")) == 0,
"BR-SALARY-004", "法定假日加班费率", "3.0", HOLIDAY_OVERTIME_RATE.toString());
assertRule(STANDARD_DAILY_WORK_HOURS.compareTo(new BigDecimal("8")) == 0,
"BR-SALARY-005", "标准日工作时长", "8", STANDARD_DAILY_WORK_HOURS.toString());
assertRule(SALARY_SCALE == 2,
"BR-SALARY-006", "工资精度", "2", String.valueOf(SALARY_SCALE));
assertRule(SALARY_ROUNDING == RoundingMode.HALF_UP,
"BR-SALARY-007", "舍入模式", "HALF_UP", SALARY_ROUNDING.toString());
}
/**
* 校验打卡考勤规则.
*/
public static void validateAttendanceRules() {
assertRule(DEFAULT_FENCE_RADIUS_METERS == 200,
"BR-ATTEND-001", "围栏半径", "200", String.valueOf(DEFAULT_FENCE_RADIUS_METERS));
assertRule(DUPLICATE_PUNCH_WINDOW_MINUTES == 30,
"BR-ATTEND-002", "防重窗口", "30", String.valueOf(DUPLICATE_PUNCH_WINDOW_MINUTES));
assertRule(LATE_THRESHOLD_MINUTES == 15,
"BR-ATTEND-003", "迟到阈值", "15", String.valueOf(LATE_THRESHOLD_MINUTES));
assertRule(EARLY_LEAVE_THRESHOLD_MINUTES == 15,
"BR-ATTEND-004", "早退阈值", "15", String.valueOf(EARLY_LEAVE_THRESHOLD_MINUTES));
assertRule(SELF_PUNCH_ONLY,
"BR-ATTEND-009", "本人打卡", "true", String.valueOf(SELF_PUNCH_ONLY));
}
/**
* 校验排班规则.
*/
public static void validateScheduleRules() {
assertRule(MAX_DAILY_SCHEDULE_HOURS == 12,
"BR-SCHED-001", "单日最大排班时长", "12", String.valueOf(MAX_DAILY_SCHEDULE_HOURS));
assertRule(MIN_REST_HOURS_BETWEEN_SHIFTS == 8,
"BR-SCHED-002", "最小休息时间", "8", String.valueOf(MIN_REST_HOURS_BETWEEN_SHIFTS));
assertRule(MAX_WEEKLY_SCHEDULE_DAYS == 6,
"BR-SCHED-005", "单周最大排班天数", "6", String.valueOf(MAX_WEEKLY_SCHEDULE_DAYS));
}
/**
* 校验系统通用规则.
*/
public static void validateSystemRules() {
assertRule(MAX_PAGE_SIZE == 100,
"BR-SYS-001", "最大分页条数", "100", String.valueOf(MAX_PAGE_SIZE));
assertRule(DELETED_FLAG == 1,
"BR-SYS-003", "逻辑删除标记", "1", String.valueOf(DELETED_FLAG));
assertRule(NOT_DELETED_FLAG == 0,
"BR-SYS-003", "未删除标记", "0", String.valueOf(NOT_DELETED_FLAG));
assertRule(MAX_BATCH_SIZE == 500,
"BR-SYS-004", "批量操作上限", "500", String.valueOf(MAX_BATCH_SIZE));
}
/**
* 断言业务规则.
*/
private static void assertRule(boolean condition, String ruleId, String ruleName,
String expectedValue, String actualValue) {
if (!condition) {
throw new AssertionError(String.format(
"业务规则被篡改![%s] %s: 期望=%s, 实际=%s",
ruleId, ruleName, expectedValue, actualValue));
}
}
}