const AUTOMATION_TYPES = { ACCEPT: "AUTO_ACCEPT", OPEN_RX: "AUTO_OPEN_RX", PASS_RX: "AUTO_PASS_RX", }; const DEFAULT_AUTOMATION_CONFIG = { autoAcceptOrder: false, autoOpenRx: false, autoPassRx: false, // Preserve the existing behaviour for institutions with no saved value. enableRationalDrug: true, autoAcceptDelayMinSeconds: 2, autoAcceptDelayMaxSeconds: 5, autoOpenRxDelayMinSeconds: 20, autoOpenRxDelayMaxSeconds: 40, autoPassRxDelayMinSeconds: 10, autoPassRxDelayMaxSeconds: 30, }; const TYPE_CONFIG = { [AUTOMATION_TYPES.ACCEPT]: { enabledKey: "autoAcceptOrder", minKey: "autoAcceptDelayMinSeconds", maxKey: "autoAcceptDelayMaxSeconds", }, [AUTOMATION_TYPES.OPEN_RX]: { enabledKey: "autoOpenRx", minKey: "autoOpenRxDelayMinSeconds", maxKey: "autoOpenRxDelayMaxSeconds", }, [AUTOMATION_TYPES.PASS_RX]: { enabledKey: "autoPassRx", minKey: "autoPassRxDelayMinSeconds", maxKey: "autoPassRxDelayMaxSeconds", }, }; const AUTOMATION_DELAY_KEYS = [ "autoAcceptDelayMinSeconds", "autoAcceptDelayMaxSeconds", "autoOpenRxDelayMinSeconds", "autoOpenRxDelayMaxSeconds", "autoPassRxDelayMinSeconds", "autoPassRxDelayMaxSeconds", ]; const AUTOMATION_DELAY_PAIRS = [ ["autoAcceptDelayMinSeconds", "autoAcceptDelayMaxSeconds"], ["autoOpenRxDelayMinSeconds", "autoOpenRxDelayMaxSeconds"], ["autoPassRxDelayMinSeconds", "autoPassRxDelayMaxSeconds"], ]; function normalizeNonNegativeInteger(value, fallback) { return Number.isInteger(value) && value >= 0 ? value : fallback; } function normalizeAutomationConfig(config = {}) { const result = { ...DEFAULT_AUTOMATION_CONFIG, ...config, }; Object.values(TYPE_CONFIG).forEach(({ minKey, maxKey }) => { const defaultMin = DEFAULT_AUTOMATION_CONFIG[minKey]; const defaultMax = DEFAULT_AUTOMATION_CONFIG[maxKey]; result[minKey] = normalizeNonNegativeInteger(config[minKey], defaultMin); result[maxKey] = normalizeNonNegativeInteger(config[maxKey], defaultMax); if (result[minKey] > result[maxKey]) { result[minKey] = defaultMin; result[maxKey] = defaultMax; } }); result.autoAcceptOrder = config.autoAcceptOrder === true; result.autoOpenRx = config.autoOpenRx === true; result.autoPassRx = config.autoPassRx === true; result.enableRationalDrug = config.enableRationalDrug !== false; return result; } function getTypeConfig(config, type) { const normalized = normalizeAutomationConfig(config); const mapping = TYPE_CONFIG[type]; if (!mapping) { throw new Error(`未知自动化任务类型: ${type}`); } return { enabled: normalized[mapping.enabledKey] === true, minSeconds: normalized[mapping.minKey], maxSeconds: normalized[mapping.maxKey], }; } function randomInteger(min, max, random = Math.random) { if (min === max) return min; return Math.floor(random() * (max - min + 1)) + min; } function validateAutomationDelayConfig(input = {}, current = {}) { const data = {}; for (const key of AUTOMATION_DELAY_KEYS) { if (key in input) { if (!Number.isInteger(input[key]) || input[key] < 0 || input[key] > 3600) { return { success: false, message: `${key}必须是0到3600之间的整数`, }; } data[key] = input[key]; } } const merged = { ...normalizeAutomationConfig(current), ...data, }; for (const [minKey, maxKey] of AUTOMATION_DELAY_PAIRS) { if (merged[minKey] > merged[maxKey]) { return { success: false, message: `${minKey}不能大于${maxKey}`, }; } } return { success: true, data }; } module.exports = { AUTOMATION_TYPES, DEFAULT_AUTOMATION_CONFIG, TYPE_CONFIG, AUTOMATION_DELAY_KEYS, AUTOMATION_DELAY_PAIRS, normalizeAutomationConfig, getTypeConfig, randomInteger, validateAutomationDelayConfig, };