longz
2026-08-11 2a3c3cdbf2398695d61633e072f98ee2757e9e27
frontend-admin/src/views/DashboardView.vue
@@ -44,8 +44,10 @@
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              value-format="YYYY-MM-DD"
              :disabled-date="disabledChartDate"
              :clearable="false"
              @change="loadAppointmentStats"
              @calendar-change="handleChartCalendarChange"
              @change="handleChartDateRangeChange"
            />
          </div>
        </div>
@@ -158,6 +160,8 @@
};
const ALL_DEPT_VALUE = "ALL" as const;
const DAY_MS = 24 * 60 * 60 * 1000;
const MAX_CHART_RANGE_DAYS = 31;
const deptOptions = ref<DeptTreeOption[]>([]);
const deptFilter = ref<number | typeof ALL_DEPT_VALUE>(ALL_DEPT_VALUE);
@@ -167,6 +171,8 @@
let lineChartInstance: ECharts | null = null;
const chartDateRange = ref<[string, string]>(getCurrentWeekRange());
const lastValidChartDateRange = ref<[string, string]>([...chartDateRange.value]);
const chartPickerBaseDate = ref<Date | null>(null);
const overview = ref<DashboardOverview>({
  startDate: "",
@@ -236,6 +242,53 @@
  return `${year}-${month}-${day}`;
}
function parseDateOnly(value?: string): Date | null {
  if (!value) {
    return null;
  }
  const parts = value.split("-").map(Number);
  if (parts.length !== 3 || parts.some(Number.isNaN)) {
    return null;
  }
  return new Date(parts[0], parts[1] - 1, parts[2]);
}
function daysBetween(start?: string, end?: string): number {
  const startDate = parseDateOnly(start);
  const endDate = parseDateOnly(end);
  if (!startDate || !endDate) {
    return 0;
  }
  return Math.floor(Math.abs(endDate.getTime() - startDate.getTime()) / DAY_MS) + 1;
}
function isChartDateRangeValid(range?: [string, string] | null): range is [string, string] {
  return Array.isArray(range) && range.length === 2 && daysBetween(range[0], range[1]) <= MAX_CHART_RANGE_DAYS;
}
function disabledChartDate(date: Date) {
  if (!chartPickerBaseDate.value) {
    return false;
  }
  const diffDays = Math.abs(date.getTime() - chartPickerBaseDate.value.getTime()) / DAY_MS;
  return diffDays > MAX_CHART_RANGE_DAYS - 1;
}
function handleChartCalendarChange(value: Date[]) {
  chartPickerBaseDate.value = value?.[0] || null;
}
function handleChartDateRangeChange(value: [string, string] | null) {
  chartPickerBaseDate.value = null;
  if (!isChartDateRangeValid(value)) {
    chartDateRange.value = [...lastValidChartDateRange.value];
    ElMessage.warning(`预约数据最多只能查询${MAX_CHART_RANGE_DAYS}天`);
    return;
  }
  lastValidChartDateRange.value = [...value];
  loadAppointmentStats();
}
function formatNumber(value: number | undefined): string {
  return new Intl.NumberFormat("zh-CN").format(Number(value) || 0);
}