人员岗位补负责人/线路维护,并同步后台人员、机器人回复与看板页改动。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -21,16 +21,13 @@ const COST_PLOT_TOP = 36;
|
||||
const COST_PLOT_BOTTOM = 186;
|
||||
|
||||
const now = new Date();
|
||||
const isoDay = now.toISOString().slice(0, 10);
|
||||
const dateDisplay = ref(`${isoDay}——${isoDay}`);
|
||||
const dateFrom = ref(isoDay);
|
||||
/** 用本地日期,避免 toISOString 因时区偏到前一天 */
|
||||
const pad2 = (n: number) => String(n).padStart(2, "0");
|
||||
const isoDay = `${now.getFullYear()}-${pad2(now.getMonth() + 1)}-${pad2(now.getDate())}`;
|
||||
/** 默认:当月 1 号 → 今天(不是当天到当天) */
|
||||
const isoMonthStart = `${now.getFullYear()}-${pad2(now.getMonth() + 1)}-01`;
|
||||
const dateFrom = ref(isoMonthStart);
|
||||
const dateTo = ref(isoDay);
|
||||
const dateFromMonth = ref(isoDay.slice(0, 7));
|
||||
const dateToMonth = ref(isoDay.slice(0, 7));
|
||||
const dateFromYear = ref(isoDay.slice(0, 4));
|
||||
const dateToYear = ref(isoDay.slice(0, 4));
|
||||
const pickerOpen = ref(false);
|
||||
const pickerMode = ref<"day" | "month" | "year">("day");
|
||||
const updatedTime = ref("00:00");
|
||||
const routeFilterOpen = ref(false);
|
||||
const selectedRoutes = ref<string[]>([]);
|
||||
@@ -60,18 +57,34 @@ const INQUIRY_PLOT_TOP = 36;
|
||||
const INQUIRY_PLOT_BOTTOM = 188;
|
||||
|
||||
function resolveRange(): string {
|
||||
if (pickerMode.value === "day") {
|
||||
const from = new Date(dateFrom.value);
|
||||
const to = new Date(dateTo.value);
|
||||
const days = Math.max(0, Math.round((to.getTime() - from.getTime()) / 86400000));
|
||||
if (days <= 0) return "today";
|
||||
if (days <= 6) return "7d";
|
||||
return "30d";
|
||||
}
|
||||
if (pickerMode.value === "month") return "30d";
|
||||
const from = new Date(dateFrom.value);
|
||||
const to = new Date(dateTo.value);
|
||||
const days = Math.max(0, Math.round((to.getTime() - from.getTime()) / 86400000));
|
||||
if (days <= 0) return "today";
|
||||
if (days <= 6) return "7d";
|
||||
return "30d";
|
||||
}
|
||||
|
||||
/**
|
||||
* 顶栏日期:与工单列表同一套 a-range-picker(双月历点选起止)。
|
||||
* 不再并排放「按日/月/年」切换,避免顶栏挤换行显得乱。
|
||||
*/
|
||||
const dateRange = computed({
|
||||
get(): [string, string] | undefined {
|
||||
if (!dateFrom.value && !dateTo.value) return undefined;
|
||||
return [dateFrom.value || "", dateTo.value || ""];
|
||||
},
|
||||
set(v: [string, string] | null | undefined) {
|
||||
dateFrom.value = v?.[0] ? String(v[0]) : isoMonthStart;
|
||||
dateTo.value = v?.[1] ? String(v[1]) : isoDay;
|
||||
},
|
||||
});
|
||||
|
||||
/** 选完起止日后立刻刷新看板 */
|
||||
function onDateRangeChange() {
|
||||
loadMetrics();
|
||||
}
|
||||
|
||||
async function loadMetrics() {
|
||||
loading.value = true;
|
||||
try {
|
||||
@@ -240,14 +253,6 @@ const costXs = computed(() => {
|
||||
return costDates.value.map((_, i) => (n === 1 ? 380 : 36 + (654 / (n - 1)) * i));
|
||||
});
|
||||
|
||||
function applyDateRange() {
|
||||
if (pickerMode.value === "day") dateDisplay.value = `${dateFrom.value}——${dateTo.value}`;
|
||||
else if (pickerMode.value === "month") dateDisplay.value = `${dateFromMonth.value}——${dateToMonth.value}`;
|
||||
else dateDisplay.value = `${dateFromYear.value}——${dateToYear.value}`;
|
||||
pickerOpen.value = false;
|
||||
loadMetrics();
|
||||
}
|
||||
|
||||
function refreshData() {
|
||||
loadMetrics().then(() => message.success("数据已更新"));
|
||||
}
|
||||
@@ -334,7 +339,6 @@ function exportRanking() {
|
||||
|
||||
function onDocClick(e: MouseEvent) {
|
||||
const t = e.target as HTMLElement;
|
||||
if (!t.closest(".month-range-picker")) pickerOpen.value = false;
|
||||
if (!t.closest(".ref-route-filter")) routeFilterOpen.value = false;
|
||||
}
|
||||
|
||||
@@ -353,33 +357,21 @@ onUnmounted(() => document.removeEventListener("click", onDocClick));
|
||||
<!-- defer:等布局挂好 #page-topbar-actions 再传送,避免顶栏工具丢失 -->
|
||||
<Teleport defer to="#page-topbar-actions">
|
||||
<div class="dash-topbar-tools">
|
||||
<div class="month-range-picker" @click.stop>
|
||||
<div class="month-range-input" @click="pickerOpen = !pickerOpen">
|
||||
<span>{{ dateDisplay }}</span>
|
||||
<ProtoIcon name="calendar" :size="14" style="color: #94a3b8" />
|
||||
</div>
|
||||
<div v-show="pickerOpen" class="month-range-dropdown dash-picker-dropdown">
|
||||
<div class="month-range-tabs">
|
||||
<button type="button" class="month-range-tab" :class="{ 'is-active': pickerMode === 'day' }" @click="pickerMode = 'day'">按日</button>
|
||||
<button type="button" class="month-range-tab" :class="{ 'is-active': pickerMode === 'month' }" @click="pickerMode = 'month'">按月</button>
|
||||
<button type="button" class="month-range-tab" :class="{ 'is-active': pickerMode === 'year' }" @click="pickerMode = 'year'">按年</button>
|
||||
</div>
|
||||
<div class="dash-picker-body">
|
||||
<template v-if="pickerMode === 'day'">
|
||||
<input v-model="dateFrom" type="date" class="dash-picker-input" />
|
||||
<input v-model="dateTo" type="date" class="dash-picker-input" />
|
||||
</template>
|
||||
<template v-else-if="pickerMode === 'month'">
|
||||
<input v-model="dateFromMonth" type="month" class="dash-picker-input" />
|
||||
<input v-model="dateToMonth" type="month" class="dash-picker-input" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<input v-model="dateFromYear" type="number" min="2020" max="2035" class="dash-picker-input" placeholder="起始年" />
|
||||
<input v-model="dateToYear" type="number" min="2020" max="2035" class="dash-picker-input" placeholder="结束年" />
|
||||
</template>
|
||||
<button type="button" class="btn btn-primary" style="width: 100%; min-height: 32px; height: 32px" @click="applyDateRange">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toolbar-date-range dash-toolbar-date" title="选择统计起止日期">
|
||||
<a-range-picker
|
||||
v-model:value="dateRange"
|
||||
class="toolbar-range-picker dash-range-picker"
|
||||
value-format="YYYY-MM-DD"
|
||||
separator="至"
|
||||
:placeholder="['开始日期', '结束日期']"
|
||||
:allow-clear="false"
|
||||
:input-read-only="true"
|
||||
@change="onDateRangeChange"
|
||||
>
|
||||
<template #suffixIcon>
|
||||
<ProtoIcon name="calendar" :size="14" />
|
||||
</template>
|
||||
</a-range-picker>
|
||||
</div>
|
||||
<div class="dashboard-data-note" aria-live="polite">
|
||||
<span class="dashboard-data-note__icon"><ProtoIcon name="clock" :size="13" /></span>
|
||||
@@ -634,38 +626,30 @@ onUnmounted(() => document.removeEventListener("click", onDocClick));
|
||||
<style scoped>
|
||||
.dash-topbar-tools {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.dash-picker-dropdown {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: calc(100% + 8px);
|
||||
width: 300px;
|
||||
z-index: 80;
|
||||
.dash-toolbar-date {
|
||||
height: 34px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.dash-picker-body {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.dash-picker-input {
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid #dfe5ee;
|
||||
border-radius: 7px;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
.dash-toolbar-date :deep(.ant-picker) {
|
||||
height: 34px !important;
|
||||
min-height: 34px !important;
|
||||
width: 260px !important;
|
||||
}
|
||||
|
||||
.dash-refresh-btn {
|
||||
height: 34px;
|
||||
min-height: 34px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.dashboard-data-note {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.dash-chart-title {
|
||||
|
||||
Reference in New Issue
Block a user