优化
This commit is contained in:
1 parent
d9a50e23dd
commit
4f1acaa451
25 files changed
+1265
-335
No files matched your search
@@ -121,8 +121,138 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧 30%:通知公告 + 工作日程提醒 -->
|
||||
<!-- 右侧 30%:今日概览 + 通知公告 + 工作日程提醒 -->
|
||||
<div class="col-right">
|
||||
<!-- 今日概览卡片(顶部,与左侧 6 张指标卡区域等高) -->
|
||||
<div class="today-card">
|
||||
<div class="tc-greet">
|
||||
<div class="tc-hello">Hi,{{ displayName }}</div>
|
||||
<div class="tc-sub">
|
||||
{{ timeGreeting }},今天是 {{ todayWeekday }} {{ todayDay }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tc-tiles">
|
||||
<div class="tc-tile">
|
||||
<div class="tc-tile-head">
|
||||
<span class="tc-tile-label">天气</span>
|
||||
<el-icon
|
||||
class="tc-refresh"
|
||||
:class="{ spinning: weatherLoading }"
|
||||
@click="refreshWeather"
|
||||
>
|
||||
<Refresh />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="tc-weather" v-if="weather.available">
|
||||
<el-icon :size="26" class="tc-weather-icon">
|
||||
<component :is="weather.icon" />
|
||||
</el-icon>
|
||||
<div class="tc-weather-text">
|
||||
<div class="tc-weather-temp">{{ weather.temp }}°</div>
|
||||
<div class="tc-weather-desc">
|
||||
{{ weather.text }}<span v-if="weather.city"> · {{ weather.city }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tc-weather tc-weather-empty" v-else>
|
||||
<el-icon :size="22"><Cloudy /></el-icon>
|
||||
<span>暂未获取</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tc-tile">
|
||||
<div class="tc-tile-head">
|
||||
<span class="tc-tile-label">今日排班</span>
|
||||
</div>
|
||||
<div class="tc-shift" :class="todaySchedule.status">
|
||||
<span class="tc-shift-dot" />
|
||||
<span class="tc-shift-text">{{ todaySchedule.label }}</span>
|
||||
</div>
|
||||
<div class="tc-shift-meta">
|
||||
<span v-if="todaySchedule.shiftName">{{ todaySchedule.shiftName }}</span>
|
||||
<span v-if="todaySchedule.time">{{ todaySchedule.time }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tc-schedule">
|
||||
<div class="tc-schedule-head">
|
||||
<span class="tc-section-title">工作日程</span>
|
||||
<el-button link type="primary" @click="goSchedule">查看全部</el-button>
|
||||
</div>
|
||||
<el-tabs v-model="scheduleRange" class="schedule-tabs">
|
||||
<el-tab-pane
|
||||
v-for="tab in scheduleRanges"
|
||||
:key="tab.value"
|
||||
:name="tab.value"
|
||||
>
|
||||
<template #label>
|
||||
<span class="tab-label">{{ tab.label }}</span>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<div v-loading="scheduleLoading" class="schedule-list">
|
||||
<div
|
||||
v-for="item in filteredScheduleReminders"
|
||||
:key="item.id"
|
||||
class="schedule-item"
|
||||
:class="{ done: item.status === 1 }"
|
||||
:style="{ '--item-color': item.color }"
|
||||
@click="openScheduleDetail(item)"
|
||||
>
|
||||
<span
|
||||
class="item-status-dot"
|
||||
:class="{ done: item.status === 1 }"
|
||||
/>
|
||||
<div class="schedule-item-main">
|
||||
<div
|
||||
class="schedule-item-title"
|
||||
:class="{ done: item.status === 1 }"
|
||||
>
|
||||
<i v-if="hasImages(item)" class="fa-solid fa-image schedule-image-icon"></i>
|
||||
{{ item.title }}
|
||||
<el-tag
|
||||
v-if="item.priority > 0"
|
||||
:type="item.priority === 2 ? 'danger' : 'warning'"
|
||||
size="small"
|
||||
effect="light"
|
||||
>
|
||||
{{ item.priority === 2 ? "紧急" : "重要" }}
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-if="item.source_id > 0 && item.status === 0"
|
||||
type="warning"
|
||||
size="small"
|
||||
effect="plain"
|
||||
>
|
||||
延期第 {{ item.carry_count + 1 }} 天
|
||||
</el-tag>
|
||||
</div>
|
||||
<div
|
||||
class="schedule-item-time"
|
||||
:class="{ done: item.status === 1 }"
|
||||
>
|
||||
<span :class="{ overdue: isOverdueSchedule(item) }">{{
|
||||
scheduleDateTag(item)
|
||||
}}</span>
|
||||
<span>{{ scheduleTimeText(item) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty
|
||||
v-if="!filteredScheduleReminders.length && !scheduleLoading"
|
||||
:description="
|
||||
scheduleRange === 'today'
|
||||
? '今日暂无日程安排'
|
||||
: '该时间范围内暂无日程'
|
||||
"
|
||||
:image-size="60"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chart-card notice-card">
|
||||
<div class="chart-title notice-title">
|
||||
<span>通知公告</span>
|
||||
@@ -156,84 +286,6 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chart-card schedule-card">
|
||||
<div class="chart-title schedule-title">
|
||||
<span>工作日程提醒</span>
|
||||
<el-button link type="primary" @click="goSchedule"
|
||||
>查看全部</el-button
|
||||
>
|
||||
</div>
|
||||
<el-tabs v-model="scheduleRange" class="schedule-tabs">
|
||||
<el-tab-pane
|
||||
v-for="tab in scheduleRanges"
|
||||
:key="tab.value"
|
||||
:name="tab.value"
|
||||
>
|
||||
<template #label>
|
||||
<span class="tab-label">{{ tab.label }}</span>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<div v-loading="scheduleLoading" class="schedule-list">
|
||||
<div
|
||||
v-for="item in filteredScheduleReminders"
|
||||
:key="item.id"
|
||||
class="schedule-item"
|
||||
:class="{ done: item.status === 1 }"
|
||||
:style="{ '--item-color': item.color }"
|
||||
@click="openScheduleDetail(item)"
|
||||
>
|
||||
<span
|
||||
class="item-status-dot"
|
||||
:class="{ done: item.status === 1 }"
|
||||
/>
|
||||
<div class="schedule-item-main">
|
||||
<div
|
||||
class="schedule-item-title"
|
||||
:class="{ done: item.status === 1 }"
|
||||
>
|
||||
<i v-if="hasImages(item)" class="fa-solid fa-image schedule-image-icon"></i>
|
||||
{{ item.title }}
|
||||
<el-tag
|
||||
v-if="item.priority > 0"
|
||||
:type="item.priority === 2 ? 'danger' : 'warning'"
|
||||
size="small"
|
||||
effect="light"
|
||||
>
|
||||
{{ item.priority === 2 ? "紧急" : "重要" }}
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-if="item.source_id > 0 && item.status === 0"
|
||||
type="warning"
|
||||
size="small"
|
||||
effect="plain"
|
||||
>
|
||||
延期第 {{ item.carry_count + 1 }} 天
|
||||
</el-tag>
|
||||
</div>
|
||||
<div
|
||||
class="schedule-item-time"
|
||||
:class="{ done: item.status === 1 }"
|
||||
>
|
||||
<span :class="{ overdue: isOverdueSchedule(item) }">{{
|
||||
scheduleDateTag(item)
|
||||
}}</span>
|
||||
<span>{{ scheduleTimeText(item) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty
|
||||
v-if="!filteredScheduleReminders.length && !scheduleLoading"
|
||||
:description="
|
||||
scheduleRange === 'today'
|
||||
? '今日暂无日程安排'
|
||||
: '该时间范围内暂无日程'
|
||||
"
|
||||
:image-size="60"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -290,17 +342,35 @@ import { computed, onBeforeUnmount, onMounted, reactive, ref, watch } from "vue"
|
||||
import { useRouter } from "vue-router";
|
||||
import { ElMessage } from "element-plus";
|
||||
import * as echarts from "echarts";
|
||||
import { Refresh } from "@element-plus/icons-vue";
|
||||
import {
|
||||
Refresh,
|
||||
Sunny,
|
||||
Cloudy,
|
||||
PartlyCloudy,
|
||||
Moon,
|
||||
OfficeBuilding,
|
||||
Lightning,
|
||||
Pouring,
|
||||
Drizzling
|
||||
} from "@element-plus/icons-vue";
|
||||
import request from "@/utils/request";
|
||||
import { getReimbursementDashboard } from "@/api/reimburse";
|
||||
import {
|
||||
getNoticeDetail,
|
||||
getNoticePortal
|
||||
} from "@/api/oaNotice";
|
||||
import { finishSchedule, getScheduleList, getScheduleStats } from "@/api/oaSchedule";
|
||||
import { getMyScheduleBoard } from "@/api/oaScheduling";
|
||||
import ScheduleDetail from "../schedule/components/detail.vue";
|
||||
import SchedulePostpone from "../schedule/components/postponeDialog.vue";
|
||||
// 时间显示统一为:YYYY-MM-DD HH:mm:ss
|
||||
import { formatDateTime } from "@/utils/datetime";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
|
||||
const authStore = useAuthStore();
|
||||
const displayName = computed(
|
||||
() => authStore.user?.name || authStore.user?.account || "朋友"
|
||||
);
|
||||
|
||||
const emptyStat = () => ({ total: 0, paid: 0, unpaid: 0, count: 0 });
|
||||
const dashboard = reactive({
|
||||
@@ -318,6 +388,102 @@ const statCards = computed(() => [
|
||||
{ key: "year", label: "本年报销", data: dashboard.year },
|
||||
]);
|
||||
|
||||
// ---------- 今日概览 ----------
|
||||
const todayDate = new Date();
|
||||
const WEEKDAYS = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
|
||||
const todayWeekday = WEEKDAYS[todayDate.getDay()];
|
||||
const todayDay = `${todayDate.getMonth() + 1}月${todayDate.getDate()}日`;
|
||||
const timeGreeting = (() => {
|
||||
const h = new Date().getHours();
|
||||
if (h < 6) return "凌晨好";
|
||||
if (h < 9) return "早上好";
|
||||
if (h < 12) return "上午好";
|
||||
if (h < 14) return "中午好";
|
||||
if (h < 18) return "下午好";
|
||||
return "晚上好";
|
||||
})();
|
||||
const pad2 = (n) => String(n).padStart(2, "0");
|
||||
const todayStr = `${todayDate.getFullYear()}-${pad2(todayDate.getMonth() + 1)}-${pad2(todayDate.getDate())}`;
|
||||
|
||||
const todayScheduleEntry = ref(null);
|
||||
const todaySchedule = computed(() => {
|
||||
const entry = todayScheduleEntry.value;
|
||||
const isRest = !entry || !entry.shift_id || Number(entry.shift_id) === 0;
|
||||
const workStart = entry?.work_start || "";
|
||||
const workEnd = entry?.work_end || "";
|
||||
const time = workStart && workEnd ? `${workStart} - ${workEnd}` : "";
|
||||
return {
|
||||
status: isRest ? "rest" : "work",
|
||||
label: isRest ? "今日休息" : "今日上班",
|
||||
icon: isRest ? Moon : OfficeBuilding,
|
||||
time,
|
||||
shiftName: entry?.shift_name || "",
|
||||
};
|
||||
});
|
||||
|
||||
const weather = ref({
|
||||
available: false,
|
||||
temp: "",
|
||||
text: "",
|
||||
city: "",
|
||||
icon: PartlyCloudy,
|
||||
});
|
||||
// 天气图标:按中国天气网的天气现象文字(晴/多云/阴/小雨…)匹配
|
||||
const weatherIconOf = (desc) => {
|
||||
const s = String(desc || "");
|
||||
if (s.includes("雷")) return Lightning;
|
||||
if (s.includes("暴雨") || s.includes("大雨")) return Pouring;
|
||||
if (s.includes("雨")) return Drizzling;
|
||||
if (s.includes("雪")) return Cloudy;
|
||||
if (s.includes("阴")) return Cloudy;
|
||||
if (s.includes("云")) return PartlyCloudy;
|
||||
if (s.includes("晴")) return Sunny;
|
||||
return PartlyCloudy;
|
||||
};
|
||||
|
||||
const loadTodaySchedule = async () => {
|
||||
try {
|
||||
const res = await getMyScheduleBoard({ start_date: todayStr, end_date: todayStr });
|
||||
const list = res?.data?.list || [];
|
||||
todayScheduleEntry.value = list.length ? list[0] : null;
|
||||
} catch (e) {
|
||||
console.warn("加载今日排班失败:", e?.message, e);
|
||||
todayScheduleEntry.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
const WEATHER_CITY = "连云港";
|
||||
const weatherLoading = ref(false);
|
||||
const loadWeather = async () => {
|
||||
if (weatherLoading.value) return;
|
||||
weatherLoading.value = true;
|
||||
try {
|
||||
const res = await request.get("/backend/weather/now", {
|
||||
params: { city: WEATHER_CITY },
|
||||
});
|
||||
const d = res?.data || {};
|
||||
if (!d.temp && !d.text) throw new Error(res?.msg || "天气数据为空");
|
||||
weather.value = {
|
||||
available: true,
|
||||
temp: d.temp || "",
|
||||
text: d.text || "",
|
||||
city: d.city || WEATHER_CITY,
|
||||
icon: weatherIconOf(d.text),
|
||||
};
|
||||
} catch (e) {
|
||||
console.warn("加载天气失败:", e?.message);
|
||||
weather.value = { ...weather.value, available: false };
|
||||
} finally {
|
||||
weatherLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 手动刷新天气(点击卡片右上角刷新图标)
|
||||
const refreshWeather = async () => {
|
||||
await loadWeather();
|
||||
if (weather.value.available) ElMessage.success("天气已更新");
|
||||
};
|
||||
|
||||
// 趋势图
|
||||
const trendChartRef = ref(null);
|
||||
let trendChart = null;
|
||||
@@ -423,7 +589,6 @@ const scheduleRanges = [
|
||||
];
|
||||
const scheduleRange = ref("today");
|
||||
|
||||
const pad2 = (n) => String(n).padStart(2, "0");
|
||||
const fmtDate = (d) =>
|
||||
`${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
|
||||
|
||||
@@ -660,6 +825,11 @@ const loadScheduleStats = async () => {
|
||||
};
|
||||
|
||||
const loadDashboard = async () => {
|
||||
// 今日概览与经营看板并行拉取
|
||||
await Promise.allSettled([
|
||||
loadTodaySchedule(),
|
||||
loadWeather(),
|
||||
]);
|
||||
try {
|
||||
const data = responseData(await getReimbursementDashboard());
|
||||
dashboard.week = data.week || emptyStat();
|
||||
@@ -730,11 +900,8 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
|
||||
.stat-row {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.el-col {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
/* 行内换行/窄屏堆叠时的行间距;与下一张卡的间距由 .col-left 的 gap 统一控制 */
|
||||
row-gap: 16px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
@@ -782,7 +949,6 @@ onBeforeUnmount(() => {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.todo-stat-card {
|
||||
@@ -828,12 +994,12 @@ onBeforeUnmount(() => {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.col-left > .chart-card {
|
||||
margin-bottom: 16px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
/* 统一卡片间距:两栏内部全部用 16px 的 flex gap,卡片自身不再写 margin */
|
||||
.col-left,
|
||||
.col-right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.chart-card {
|
||||
@@ -869,13 +1035,182 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.type-card {
|
||||
margin-bottom: 0;
|
||||
/* 今日概览卡片:与左侧 6 张指标卡区域等高 */
|
||||
.today-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
padding: 18px;
|
||||
background: var(--el-bg-color);
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
|
||||
min-height: 250px;
|
||||
|
||||
/* 打招呼 */
|
||||
.tc-greet {
|
||||
.tc-hello {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 1.3;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.tc-sub {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
/* 天气 / 排班 两块信息 */
|
||||
.tc-tiles {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.tc-tile {
|
||||
min-width: 0;
|
||||
padding: 10px;
|
||||
background: var(--el-fill-color-light);
|
||||
border-radius: 8px;
|
||||
|
||||
.tc-tile-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 6px;
|
||||
margin-bottom: 6px;
|
||||
min-height: 16px;
|
||||
}
|
||||
|
||||
.tc-tile-label {
|
||||
font-size: 11px;
|
||||
color: var(--el-text-color-placeholder);
|
||||
}
|
||||
|
||||
.tc-refresh {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-placeholder);
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
&.spinning {
|
||||
animation: tc-spin 1s linear infinite;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tc-weather {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
|
||||
.tc-weather-icon {
|
||||
flex-shrink: 0;
|
||||
color: #f59e0b;
|
||||
}
|
||||
|
||||
.tc-weather-text {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.tc-weather-temp {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
line-height: 1.1;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.tc-weather-desc {
|
||||
margin-top: 2px;
|
||||
font-size: 11px;
|
||||
color: var(--el-text-color-secondary);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&.tc-weather-empty {
|
||||
gap: 6px;
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
.tc-shift {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
.tc-shift-dot {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 50%;
|
||||
background: var(--el-text-color-placeholder);
|
||||
}
|
||||
|
||||
.tc-shift-text {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
&.work {
|
||||
.tc-shift-dot {
|
||||
background: var(--el-color-success);
|
||||
}
|
||||
.tc-shift-text {
|
||||
color: var(--el-color-success);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tc-shift-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
margin-top: 4px;
|
||||
font-size: 11px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
/* 工作日程提醒(与今日概览合并展示) */
|
||||
.tc-schedule {
|
||||
margin-top: 2px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px dashed var(--el-border-color-lighter);
|
||||
|
||||
.tc-schedule-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.tc-section-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes tc-spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.notice-card {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.notice-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -957,43 +1292,9 @@ onBeforeUnmount(() => {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.schedule-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/*min-height: 340px; */
|
||||
height: 600px;
|
||||
|
||||
.schedule-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.schedule-tabs {
|
||||
margin-bottom: 20px;
|
||||
|
||||
:deep(.el-tabs__header) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__nav-wrap::after) {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__item) {
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
.schedule-list {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.schedule-tabs {
|
||||
:deep(.el-tabs__header) {
|
||||
margin: 0 0 10px;
|
||||
margin: 0 0 8px;
|
||||
}
|
||||
|
||||
/* 列表由下方 .schedule-list 承载,tabs 只作切换栏,隐藏空的面板容器 */
|
||||
@@ -1025,16 +1326,12 @@ onBeforeUnmount(() => {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.status-card {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.schedule-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
min-height: 120px;
|
||||
max-height: 520px;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@@ -1229,10 +1526,6 @@ onBeforeUnmount(() => {
|
||||
flex: 1 1 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.col-right {
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@@ -1261,6 +1554,12 @@ html.dark & {
|
||||
background: var(--el-bg-color-page);
|
||||
}
|
||||
|
||||
.today-card {
|
||||
background: var(--el-bg-color);
|
||||
border-color: var(--el-border-color);
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
.page-header {
|
||||
h2 {
|
||||
color: var(--el-text-color-primary);
|
||||
|
||||
Reference in new issue
Block a user