feat(export): 优化时间范围选择逻辑,限制跨度不超过1年
- 修改后端时间跨度验证逻辑,定义1年为从开始日期往后推1年 - 前端日期选择组件新增选择过程监听,记录首选日期以限制第二个日期范围 - 实现禁用时间函数,禁止选择超过1年跨度的时间范围 - 添加时间跨度变化检测,超出1年时清空选择并弹窗提示 - 前端导入中文语言包,支持ElementPlus中文本地化 - API模块统一业务错误码处理,非0码抛出带错误信息异常
This commit is contained in:
parent
c56c738992
commit
07eafb5684
|
|
@ -23,6 +23,7 @@ import (
|
|||
)
|
||||
|
||||
// validateTimeRange 验证时间范围不超过1年
|
||||
// 1年的定义:从开始日期往后推1年
|
||||
func validateTimeRange(startVal, endVal interface{}) error {
|
||||
var startStr, endStr string
|
||||
|
||||
|
|
@ -60,12 +61,14 @@ func validateTimeRange(startVal, endVal interface{}) error {
|
|||
return errors.New("结束时间必须晚于开始时间")
|
||||
}
|
||||
|
||||
// 计算时间跨度
|
||||
duration := endTime.Sub(startTime)
|
||||
oneYear := 365 * 24 * time.Hour
|
||||
// 计算开始日期往后推1年的时间点
|
||||
oneYearLater := startTime.AddDate(1, 0, 0)
|
||||
|
||||
if duration > oneYear {
|
||||
return fmt.Errorf("时间跨度超过1年限制,当前跨度为 %.1f 天,最多允许 365 天", duration.Hours()/24)
|
||||
// 如果结束时间超过这个时间点,则超过1年限制
|
||||
if endTime.After(oneYearLater) {
|
||||
duration := endTime.Sub(startTime)
|
||||
daysCount := duration.Hours() / 24
|
||||
return fmt.Errorf("时间跨度超过1年限制,当前跨度为 %.1f 天,最多允许 365 天", daysCount)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -235,12 +235,15 @@
|
|||
<el-date-picker
|
||||
v-model="exportForm.dateRange"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
:shortcuts="dateShortcuts"
|
||||
:default-time="dateDefaultTime"
|
||||
:disabled-date="disabledDate"
|
||||
@calendar-change="onCalendarChange"
|
||||
@change="onDateRangeChange"
|
||||
style="width:100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
|
@ -308,6 +311,7 @@
|
|||
<script src="./config.js"></script>
|
||||
<script src="./vendor/vue.global.prod.js"></script>
|
||||
<script src="./vendor/element-plus.full.min.js"></script>
|
||||
<script src="./vendor/element-plus-zh-cn.js"></script>
|
||||
<!-- 模块化架构 -->
|
||||
<script src="./modules/config.js"></script>
|
||||
<script src="./modules/utils.js"></script>
|
||||
|
|
|
|||
93
web/main.js
93
web/main.js
|
|
@ -190,34 +190,44 @@ const app = createApp({
|
|||
new Date(2000, 0, 1, 23, 59, 59),
|
||||
];
|
||||
|
||||
// 用于记录用户正在选择的第一个日期(用于限制第二个日期的可选范围)
|
||||
const pickerMinDate = Vue.ref(null);
|
||||
|
||||
/**
|
||||
* 日历面板变化事件 - 当用户点击日历时触发
|
||||
* 用于记录用户选择的第一个日期
|
||||
* @param {Array} dates - 已选日期数组
|
||||
*/
|
||||
const onCalendarChange = (dates) => {
|
||||
if (dates && dates.length === 1) {
|
||||
// 用户选择了第一个日期
|
||||
pickerMinDate.value = dates[0];
|
||||
} else {
|
||||
// 选择完成或清空
|
||||
pickerMinDate.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 禁用超过一年的日期
|
||||
* 当用户选择了第一个日期后,自动限制第二个日期的可选范围
|
||||
* @param {Date} date - 要检查的日期
|
||||
* @returns {boolean} 是否禁用
|
||||
*/
|
||||
const disabledDate = (date) => {
|
||||
if (!date) return false;
|
||||
|
||||
// 如果已经选择了开始时间,计算结束时间限制
|
||||
if (state.exportForm.dateRange && state.exportForm.dateRange[0]) {
|
||||
const startTime = new Date(state.exportForm.dateRange[0]);
|
||||
const oneYearLater = new Date(startTime);
|
||||
oneYearLater.setFullYear(startTime.getFullYear() + 1);
|
||||
oneYearLater.setDate(oneYearLater.getDate() - 1); // 减去一天以确保不超过一年
|
||||
// 如果用户正在选择第二个日期,限制范围不超过1年
|
||||
if (pickerMinDate.value) {
|
||||
const selectedDate = new Date(pickerMinDate.value);
|
||||
const oneYearMs = 365 * 24 * 60 * 60 * 1000;
|
||||
|
||||
// 只限制结束时间不能超过开始时间一年后
|
||||
if (date > oneYearLater) return true;
|
||||
}
|
||||
// 计算允许的日期范围
|
||||
const minAllowed = new Date(selectedDate.getTime() - oneYearMs);
|
||||
const maxAllowed = new Date(selectedDate.getTime() + oneYearMs);
|
||||
|
||||
// 如果已经选择了结束时间,计算开始时间限制
|
||||
if (state.exportForm.dateRange && state.exportForm.dateRange[1]) {
|
||||
const endTime = new Date(state.exportForm.dateRange[1]);
|
||||
const oneYearEarlier = new Date(endTime);
|
||||
oneYearEarlier.setFullYear(endTime.getFullYear() - 1);
|
||||
oneYearEarlier.setDate(oneYearEarlier.getDate() + 1); // 加上一天
|
||||
|
||||
// 只限制开始时间不能早于结束时间一年前
|
||||
if (date < oneYearEarlier) return true;
|
||||
// 禁用超出范围的日期
|
||||
return date < minAllowed || date > maxAllowed;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -288,6 +298,41 @@ const app = createApp({
|
|||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 验证时间跨度是否超过1年
|
||||
* 1年的定义:从开始日期往后推1年
|
||||
* @param {Array} dateRange - 时间范围 [开始时间, 结束时间]
|
||||
* @returns {boolean} 是否超过1年
|
||||
*/
|
||||
const isDateRangeExceedOneYear = (dateRange) => {
|
||||
if (!dateRange || dateRange.length !== 2 || !dateRange[0] || !dateRange[1]) {
|
||||
return false;
|
||||
}
|
||||
const start = new Date(dateRange[0]);
|
||||
const end = new Date(dateRange[1]);
|
||||
|
||||
// 计算开始日期往后推1年的时间点
|
||||
const oneYearLater = new Date(start);
|
||||
oneYearLater.setFullYear(start.getFullYear() + 1);
|
||||
|
||||
// 如果结束时间超过这个时间点,则超过1年
|
||||
return end > oneYearLater;
|
||||
};
|
||||
|
||||
/**
|
||||
* 时间范围变化处理函数
|
||||
* 如果时间跨度超过1年,清空并提示
|
||||
* @param {Array} val - 时间范围
|
||||
*/
|
||||
const onDateRangeChange = (val) => {
|
||||
if (isDateRangeExceedOneYear(val)) {
|
||||
// 清空时间范围
|
||||
state.exportForm.dateRange = null;
|
||||
// 显示提示
|
||||
showMessage('时间跨度不能超过1年(365天),请重新选择', 'warning');
|
||||
}
|
||||
};
|
||||
|
||||
// ==================== 表单引用 ====================
|
||||
const createFormRef = Vue.ref(null);
|
||||
const editFormRef = Vue.ref(null);
|
||||
|
|
@ -820,7 +865,11 @@ const app = createApp({
|
|||
showMessage('任务创建返回异常', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
showMessage(error.message || '导出失败', 'error');
|
||||
// 使用模态框显示错误信息
|
||||
ElementPlus.ElMessageBox.alert(error.message || '导出失败', '提示', {
|
||||
type: 'error',
|
||||
confirmButtonText: '确定'
|
||||
});
|
||||
} finally {
|
||||
state.exportSubmitting = false;
|
||||
}
|
||||
|
|
@ -1093,6 +1142,8 @@ const app = createApp({
|
|||
dateDefaultTime,
|
||||
dateShortcuts,
|
||||
disabledDate,
|
||||
onCalendarChange,
|
||||
onDateRangeChange,
|
||||
// 表单引用
|
||||
createFormRef,
|
||||
editFormRef,
|
||||
|
|
@ -1132,7 +1183,9 @@ const app = createApp({
|
|||
}
|
||||
});
|
||||
|
||||
app.use(ElementPlus);
|
||||
app.use(ElementPlus, {
|
||||
locale: window.ElementPlusLocaleZhCn
|
||||
});
|
||||
app.mount('#app');
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -157,7 +157,18 @@ const post = async (endpoint, body, options = {}) => {
|
|||
const errorText = await response.text();
|
||||
throw new Error(errorText || `请求失败: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
// 检查业务错误码
|
||||
if (result && result.code !== undefined && result.code !== 0) {
|
||||
const error = new Error(result.msg || '操作失败');
|
||||
error.code = result.code;
|
||||
error.data = result.data;
|
||||
throw error;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
/*! Element Plus v2.13.0 - Chinese (zh-cn) */
|
||||
(function(global) {
|
||||
var zhCn = {
|
||||
name: "zh-cn",
|
||||
el: {
|
||||
breadcrumb: { label: "面包屑" },
|
||||
colorpicker: {
|
||||
confirm: "确定",
|
||||
clear: "清空",
|
||||
defaultLabel: "颜色选择器",
|
||||
description: "当前颜色 {color},按 Enter 键选择新颜色"
|
||||
},
|
||||
datepicker: {
|
||||
now: "此刻",
|
||||
today: "今天",
|
||||
cancel: "取消",
|
||||
clear: "清空",
|
||||
confirm: "确定",
|
||||
dateTablePrompt: "使用方向键与 Enter 键可选择日期",
|
||||
monthTablePrompt: "使用方向键与 Enter 键可选择月份",
|
||||
yearTablePrompt: "使用方向键与 Enter 键可选择年份",
|
||||
selectedDate: "已选日期",
|
||||
selectDate: "选择日期",
|
||||
selectTime: "选择时间",
|
||||
startDate: "开始日期",
|
||||
startTime: "开始时间",
|
||||
endDate: "结束日期",
|
||||
endTime: "结束时间",
|
||||
prevYear: "前一年",
|
||||
nextYear: "后一年",
|
||||
prevMonth: "上个月",
|
||||
nextMonth: "下个月",
|
||||
year: "年",
|
||||
month1: "1 月",
|
||||
month2: "2 月",
|
||||
month3: "3 月",
|
||||
month4: "4 月",
|
||||
month5: "5 月",
|
||||
month6: "6 月",
|
||||
month7: "7 月",
|
||||
month8: "8 月",
|
||||
month9: "9 月",
|
||||
month10: "10 月",
|
||||
month11: "11 月",
|
||||
month12: "12 月",
|
||||
weeks: { sun: "日", mon: "一", tue: "二", wed: "三", thu: "四", fri: "五", sat: "六" },
|
||||
weeksFull: { sun: "星期日", mon: "星期一", tue: "星期二", wed: "星期三", thu: "星期四", fri: "星期五", sat: "星期六" },
|
||||
months: { jan: "一月", feb: "二月", mar: "三月", apr: "四月", may: "五月", jun: "六月", jul: "七月", aug: "八月", sep: "九月", oct: "十月", nov: "十一月", dec: "十二月" }
|
||||
},
|
||||
inputNumber: { decrease: "减少数值", increase: "增加数值" },
|
||||
select: { loading: "加载中", noMatch: "无匹配数据", noData: "无数据", placeholder: "请选择" },
|
||||
mention: { loading: "加载中" },
|
||||
dropdown: { toggleDropdown: "切换下拉选项" },
|
||||
cascader: { noMatch: "无匹配数据", loading: "加载中", placeholder: "请选择", noData: "暂无数据" },
|
||||
pagination: {
|
||||
goto: "前往",
|
||||
pagesize: "条/页",
|
||||
total: "共 {total} 条",
|
||||
pageClassifier: "页",
|
||||
page: "页",
|
||||
prev: "上一页",
|
||||
next: "下一页",
|
||||
currentPage: "第 {pager} 页",
|
||||
prevPages: "向前 {pager} 页",
|
||||
nextPages: "向后 {pager} 页"
|
||||
},
|
||||
dialog: { close: "关闭此对话框" },
|
||||
drawer: { close: "关闭此对话框" },
|
||||
messagebox: { title: "提示", confirm: "确定", cancel: "取消", error: "输入的数据不合法!", close: "关闭此对话框" },
|
||||
upload: { deleteTip: "按 Delete 键可删除", delete: "删除", preview: "查看图片", continue: "继续上传" },
|
||||
slider: { defaultLabel: "滑块介于 {min} 至 {max}", defaultRangeStartLabel: "选择起始值", defaultRangeEndLabel: "选择结束值" },
|
||||
table: { emptyText: "暂无数据", confirmFilter: "筛选", resetFilter: "重置", clearFilter: "全部", sumText: "合计" },
|
||||
tag: { close: "关闭此标签" },
|
||||
tour: { next: "下一步", previous: "上一步", finish: "结束导览", close: "关闭此对话框" },
|
||||
tree: { emptyText: "暂无数据" },
|
||||
transfer: { noMatch: "无匹配数据", noData: "无数据", titles: ["列表 1", "列表 2"], filterPlaceholder: "请输入搜索内容", noCheckedFormat: "共 {total} 项", hasCheckedFormat: "已选 {checked}/{total} 项" },
|
||||
image: { error: "加载失败" },
|
||||
pageHeader: { title: "返回" },
|
||||
popconfirm: { confirmButtonText: "确定", cancelButtonText: "取消" },
|
||||
carousel: { leftArrow: "上一张幻灯片", rightArrow: "下一张幻灯片", indicator: "幻灯片切换至索引 {index}" }
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露到全局
|
||||
global.ElementPlusLocaleZhCn = zhCn;
|
||||
})(typeof window !== 'undefined' ? window : this);
|
||||
Loading…
Reference in New Issue