如何配置Redmine限制用户仅可记录过去3天的工时?
当然可以实现!针对你提到的Redmine限制用户仅能记录过去3天(含当天)工时的需求,我整理了几个实用的方案,你可以根据自己的技术能力和部署场景选择:
1. 插件方案(最省心的选择)
Redmine社区有不少专注于工时管理的插件,部分支持自定义日期范围限制。比如你可以找找类似redmine_time_limit这类插件(如果找不到完全匹配的,也可以基于Redmine的插件开发框架自行简单定制)。
这类插件的优势是:
- 自带前端验证:用户选择超出3天的日期时,会直接弹出友好提示,阻止提交
- 后端兜底校验:防止有人绕过前端限制提交不符合要求的记录
- 配置简单:下载插件放到Redmine的
plugins目录,执行bundle install和数据库迁移命令后,在Redmine后台设置里就能配置允许的日期范围(设为过去3天即可)
2. 数据库触发器方案(无需修改Redmine代码)
如果不想折腾插件,直接在数据库层面加触发器是个简单粗暴但有效的办法。以MySQL为例,Redmine的工时记录存在time_entries表,其中spent_on字段是工时对应的日期,我们可以创建两个触发器来拦截不符合要求的操作:
-- 拦截新增不符合日期要求的工时记录 DELIMITER // CREATE TRIGGER check_time_entry_insert BEFORE INSERT ON time_entries FOR EACH ROW BEGIN IF NEW.spent_on < DATE_SUB(CURDATE(), INTERVAL 3 DAY) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '仅允许记录过去3天(含当天)的工时'; END IF; END // DELIMITER ; -- 拦截修改为不符合日期要求的工时记录 DELIMITER // CREATE TRIGGER check_time_entry_update BEFORE UPDATE ON time_entries FOR EACH ROW BEGIN IF NEW.spent_on < DATE_SUB(CURDATE(), INTERVAL 3 DAY) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '仅允许记录过去3天(含当天)的工时'; END IF; END // DELIMITER ;
这个方案的好处是不需要修改Redmine的任何代码,不管用户通过前端还是API提交,数据库都会直接拒绝。唯一的小缺点是用户在前端不会得到友好提示,只会看到数据库报错,所以如果追求更好的体验,可以配合一点点前端的提示代码。
3. 自定义代码方案(最灵活,体验最佳)
如果你有一定的Ruby开发能力,直接修改Redmine代码可以实现最友好的限制效果:
前端校验
在工时录入页面的模板文件(比如app/views/time_entries/_form.html.erb)中添加一段JavaScript,监听日期选择框的变化:
document.getElementById('time_entry_spent_on').addEventListener('change', function() { const selectedDate = new Date(this.value); const threeDaysAgo = new Date(); threeDaysAgo.setDate(threeDaysAgo.getDate() - 3); // 只保留日期部分比较,忽略时间 const selectedDateOnly = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate()); const threeDaysAgoOnly = new Date(threeDaysAgo.getFullYear(), threeDaysAgo.getMonth(), threeDaysAgo.getDate()); const submitBtn = document.querySelector('input[type="submit"]'); const errorMsg = document.createElement('div'); errorMsg.className = 'error'; errorMsg.textContent = '仅允许记录过去3天(含当天)的工时'; if (selectedDateOnly < threeDaysAgoOnly) { submitBtn.disabled = true; // 移除已存在的提示,避免重复添加 const existingError = document.querySelector('.error'); if (existingError) existingError.remove(); this.parentNode.appendChild(errorMsg); } else { submitBtn.disabled = false; const existingError = document.querySelector('.error'); if (existingError) existingError.remove(); } });
后端校验
在app/models/time_entry.rb中添加自定义校验规则,作为前端校验的兜底:
validate :validate_spent_on_date_range private def validate_spent_on_date_range if spent_on.present? && spent_on < 3.days.ago.to_date errors.add(:spent_on, "仅允许记录过去3天(含当天)的工时") end end
这种方案的优势是用户能在前端得到即时的友好提示,后端也有严格的校验,体验最好,但需要维护自定义代码,Redmine版本升级时要注意兼容性。
以上三种方案各有优劣,你可以根据自己的实际情况来选择~
内容的提问来源于stack exchange,提问作者Darshan Faldu

