v0.7.2 顶栏精简:移除常驻打卡与周记提示按钮,周记提醒改为周五至周日 toast 一次性提示
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
# v0.7.2 顶栏精简
|
||||||
|
|
||||||
|
## 优化
|
||||||
|
- 移除右上角常驻的「上班打卡」按钮:打卡在「详情」页当日面板与日历当日抽屉中操作,顶栏不再重复。
|
||||||
|
- 移除右上角常驻的「填写本周周记」提示按钮:改为周五至周日打开应用时 toast 提示一次,不占用常驻界面;设置页「周记提醒」开关继续有效。
|
||||||
|
- 顶栏仅保留页面标题与搜索,移动端搜索按钮右对齐。
|
||||||
|
- 清除相关死代码约 80 行(打卡三态、周记提示样式)。
|
||||||
+2
-2
@@ -1,2 +1,2 @@
|
|||||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./web-9h8A4HQx.js","./index-pe6VFzmc.js","./index-BiI44Vix.css"])))=>i.map(i=>d[i]);
|
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./web-Deo5OtIz.js","./index-ynPmf8i8.js","./index-COwenkhO.css"])))=>i.map(i=>d[i]);
|
||||||
import{r as s,_ as i}from"./index-pe6VFzmc.js";var t;(function(e){e.Documents="DOCUMENTS",e.Data="DATA",e.Library="LIBRARY",e.Cache="CACHE",e.External="EXTERNAL",e.ExternalStorage="EXTERNAL_STORAGE"})(t||(t={}));var a;(function(e){e.UTF8="utf8",e.ASCII="ascii",e.UTF16="utf16"})(a||(a={}));const E=s("Filesystem",{web:()=>i(()=>import("./web-9h8A4HQx.js"),__vite__mapDeps([0,1,2]),import.meta.url).then(e=>new e.FilesystemWeb)});export{t as Directory,a as Encoding,E as Filesystem};
|
import{r as s,_ as i}from"./index-ynPmf8i8.js";var t;(function(e){e.Documents="DOCUMENTS",e.Data="DATA",e.Library="LIBRARY",e.Cache="CACHE",e.External="EXTERNAL",e.ExternalStorage="EXTERNAL_STORAGE"})(t||(t={}));var a;(function(e){e.UTF8="utf8",e.ASCII="ascii",e.UTF16="utf16"})(a||(a={}));const E=s("Filesystem",{web:()=>i(()=>import("./web-Deo5OtIz.js"),__vite__mapDeps([0,1,2]),import.meta.url).then(e=>new e.FilesystemWeb)});export{t as Directory,a as Encoding,E as Filesystem};
|
||||||
+1
-1
File diff suppressed because one or more lines are too long
-27
File diff suppressed because one or more lines are too long
+27
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -8,8 +8,8 @@
|
|||||||
<link rel="icon" href="./icons/icon.svg" type="image/svg+xml" />
|
<link rel="icon" href="./icons/icon.svg" type="image/svg+xml" />
|
||||||
<link rel="apple-touch-icon" href="./icons/icon-192.png" />
|
<link rel="apple-touch-icon" href="./icons/icon-192.png" />
|
||||||
<title>实习工作日志</title>
|
<title>实习工作日志</title>
|
||||||
<script type="module" crossorigin src="./assets/index-pe6VFzmc.js"></script>
|
<script type="module" crossorigin src="./assets/index-ynPmf8i8.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="./assets/index-BiI44Vix.css">
|
<link rel="stylesheet" crossorigin href="./assets/index-COwenkhO.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "intern-log",
|
"name": "intern-log",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.7.1",
|
"version": "0.7.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
+19
-98
@@ -15,11 +15,11 @@ import UserAdminView from './views/UserAdminView.vue'
|
|||||||
import LoginView from './views/LoginView.vue'
|
import LoginView from './views/LoginView.vue'
|
||||||
import { getSession, logoutUser, openUserDatabase, type Session } from './db/auth'
|
import { getSession, logoutUser, openUserDatabase, type Session } from './db/auth'
|
||||||
import { autoSyncNow, enableRealtimeSync, ensureCloudBinding, stopRealtime } from './sync/engine'
|
import { autoSyncNow, enableRealtimeSync, ensureCloudBinding, stopRealtime } from './sync/engine'
|
||||||
import { clockIn, getAttendance, getWorkRule, getWeeklyNote, searchLogItems, searchMemos, smartClockOut, type WorkRule } from './db/repo'
|
import { getWorkRule, getWeeklyNote, searchLogItems, searchMemos } from './db/repo'
|
||||||
import { addDays, hhmm, todayStr, weekStart } from './lib/date'
|
import { todayStr, weekStart } from './lib/date'
|
||||||
import { showToast, useToasts } from './lib/toast'
|
import { showToast, useToasts } from './lib/toast'
|
||||||
import { attendanceChanged, focusDate, focusMemo, notifyAttendanceChanged } from './lib/bus'
|
import { focusDate, focusMemo } from './lib/bus'
|
||||||
import { categoryLabel, type Attendance, type LogItem, type Memo } from './db/schema'
|
import { categoryLabel, type LogItem, type Memo } from './db/schema'
|
||||||
|
|
||||||
const toasts = useToasts()
|
const toasts = useToasts()
|
||||||
|
|
||||||
@@ -30,8 +30,7 @@ async function onLogin(s: Session) {
|
|||||||
openUserDatabase(s.userId)
|
openUserDatabase(s.userId)
|
||||||
location.hash = '#/calendar'
|
location.hash = '#/calendar'
|
||||||
route.value = 'calendar'
|
route.value = 'calendar'
|
||||||
await refreshClock()
|
await checkWeeklyReminder()
|
||||||
await refreshTip()
|
|
||||||
startSyncTimer()
|
startSyncTimer()
|
||||||
try {
|
try {
|
||||||
await ensureCloudBinding()
|
await ensureCloudBinding()
|
||||||
@@ -161,72 +160,24 @@ function pickLog(item: LogItem & { date: string }) { openLog(item); mobileSearch
|
|||||||
function pickMemo(m: Memo) { openMemo(m); mobileSearch.value = false }
|
function pickMemo(m: Memo) { openMemo(m); mobileSearch.value = false }
|
||||||
|
|
||||||
|
|
||||||
// ---- 工具栏打卡 ----
|
// ---- 周记提醒:周五至周日打开应用时 toast 提示一次,不占用常驻界面 ----
|
||||||
const today = ref(todayStr())
|
async function checkWeeklyReminder() {
|
||||||
const att = ref<Attendance | undefined>(undefined)
|
try {
|
||||||
const yesterdayPending = ref(false)
|
const rule = await getWorkRule()
|
||||||
|
if (rule.remind_weekly === 'off') return
|
||||||
async function refreshClock() {
|
const wd = new Date().getDay()
|
||||||
att.value = await getAttendance(today.value)
|
if (wd !== 5 && wd !== 6 && wd !== 0) return
|
||||||
yesterdayPending.value = false
|
const note = await getWeeklyNote(weekStart(todayStr()))
|
||||||
const now = new Date()
|
if (note && (note.highlights || note.challenges || note.plan_next)) return
|
||||||
if (now.getHours() < 4) {
|
showToast('本周周记还没写,可在「总结」页填写')
|
||||||
const yRec = await getAttendance(addDays(today.value, -1))
|
} catch { /* 提醒检查失败不影响使用 */ }
|
||||||
yesterdayPending.value = !!(yRec && yRec.clock_in_at && !yRec.clock_out_at)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasActiveSession = computed(() => {
|
|
||||||
const a = att.value
|
|
||||||
if (a && a.clock_in_at && !a.clock_out_at) return true
|
|
||||||
return yesterdayPending.value && !(a && a.clock_in_at)
|
|
||||||
})
|
|
||||||
const clockDone = computed(() => {
|
|
||||||
const a = att.value
|
|
||||||
return !!(a && a.clock_in_at && a.clock_out_at)
|
|
||||||
})
|
|
||||||
const clockLabel = computed(() => {
|
|
||||||
const a = att.value
|
|
||||||
if (hasActiveSession.value) return '下班打卡'
|
|
||||||
if (clockDone.value) return '已打卡 ' + hhmm(a?.clock_in_at) + ' - ' + hhmm(a?.clock_out_at)
|
|
||||||
return '上班打卡'
|
|
||||||
})
|
|
||||||
|
|
||||||
async function doClock() {
|
|
||||||
if (hasActiveSession.value) {
|
|
||||||
try { await smartClockOut() } catch { /* 没有进行中的打卡 */ }
|
|
||||||
} else {
|
|
||||||
await clockIn(today.value)
|
|
||||||
}
|
|
||||||
await refreshClock()
|
|
||||||
notifyAttendanceChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 任何视图发生的考勤变更(含今日面板、日历抽屉)都实时同步到顶栏
|
|
||||||
watch(attendanceChanged, () => {
|
|
||||||
if (session.value) refreshClock()
|
|
||||||
})
|
|
||||||
|
|
||||||
// ---- 周记提醒 ----
|
|
||||||
const weekTip = ref(false)
|
|
||||||
async function refreshTip() {
|
|
||||||
const rule: WorkRule = await getWorkRule()
|
|
||||||
if (rule.remind_weekly === 'off') { weekTip.value = false; return }
|
|
||||||
const wd = new Date().getDay()
|
|
||||||
if (wd === 5 || wd === 6 || wd === 0) {
|
|
||||||
const note = await getWeeklyNote(weekStart(today.value))
|
|
||||||
weekTip.value = !note || (!note.highlights && !note.challenges && !note.plan_next)
|
|
||||||
} else {
|
|
||||||
weekTip.value = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
window.addEventListener('keydown', onGlobalKey)
|
window.addEventListener('keydown', onGlobalKey)
|
||||||
if (session.value) {
|
if (session.value) {
|
||||||
openUserDatabase(session.value.userId)
|
openUserDatabase(session.value.userId)
|
||||||
await refreshClock()
|
await checkWeeklyReminder()
|
||||||
await refreshTip()
|
|
||||||
startSyncTimer()
|
startSyncTimer()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -287,17 +238,7 @@ onMounted(async () => {
|
|||||||
<div v-else class="gs-empty muted">无匹配结果</div>
|
<div v-else class="gs-empty muted">无匹配结果</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span class="flex1"></span>
|
|
||||||
<div class="topbar-actions">
|
|
||||||
<button v-if="weekTip" class="week-tip" @click="nav('report')">
|
|
||||||
<span class="dot" style="background: var(--warn)"></span>
|
|
||||||
填写本周周记
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-primary" :disabled="clockDone" @click="doClock">
|
|
||||||
<Icon :name="clockDone ? 'check-circle' : 'clock'" :size="14" />
|
|
||||||
<span class="num">{{ clockLabel }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</header>
|
</header>
|
||||||
<main class="content">
|
<main class="content">
|
||||||
<div class="content-inner">
|
<div class="content-inner">
|
||||||
@@ -507,8 +448,6 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
.title { font-size: 15px; font-weight: 600; white-space: nowrap; }
|
.title { font-size: 15px; font-weight: 600; white-space: nowrap; }
|
||||||
|
|
||||||
.topbar-actions { display: flex; align-items: center; gap: 8px; }
|
|
||||||
|
|
||||||
.gsearch { position: relative; width: 320px; max-width: 38vw; }
|
.gsearch { position: relative; width: 320px; max-width: 38vw; }
|
||||||
.gs-icon { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); color: var(--text-3); }
|
.gs-icon { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); color: var(--text-3); }
|
||||||
.gs-input {
|
.gs-input {
|
||||||
@@ -554,21 +493,6 @@ onMounted(async () => {
|
|||||||
.gs-date { font-size: 12px; flex: none; }
|
.gs-date { font-size: 12px; flex: none; }
|
||||||
.gs-empty { padding: 10px; font-size: 12px; text-align: center; }
|
.gs-empty { padding: 10px; font-size: 12px; text-align: center; }
|
||||||
|
|
||||||
.week-tip {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
border: 1px solid var(--warn);
|
|
||||||
color: var(--warn);
|
|
||||||
background: var(--bg-page);
|
|
||||||
border-radius: 999px;
|
|
||||||
height: 28px;
|
|
||||||
padding: 0 10px;
|
|
||||||
font-size: 12px;
|
|
||||||
cursor: pointer;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.week-tip:hover { background: #FDF4EC; }
|
|
||||||
|
|
||||||
.content { flex: 1; overflow: auto; }
|
.content { flex: 1; overflow: auto; }
|
||||||
.content-inner { max-width: 1280px; margin: 0 auto; padding: 20px 24px 48px; }
|
.content-inner { max-width: 1280px; margin: 0 auto; padding: 20px 24px 48px; }
|
||||||
@@ -752,10 +676,7 @@ onMounted(async () => {
|
|||||||
.gsearch { display: none; }
|
.gsearch { display: none; }
|
||||||
.gsearch .gs-panel { display: none; }
|
.gsearch .gs-panel { display: none; }
|
||||||
.mob-search-btn { display: flex; }
|
.mob-search-btn { display: flex; }
|
||||||
.topbar-actions { margin-left: auto; gap: 6px; }
|
.mob-search-btn { margin-left: auto; }
|
||||||
.week-tip { height: 28px; max-width: 118px; padding: 0 8px; white-space: nowrap; overflow: hidden; }
|
|
||||||
.topbar-actions .btn { padding: 0 12px; height: 34px; }
|
|
||||||
.topbar-actions .btn .num { font-size: 12px; }
|
|
||||||
|
|
||||||
.tabbar { display: flex; }
|
.tabbar { display: flex; }
|
||||||
.tab-btn { height: 56px; font-size: 11px; }
|
.tab-btn { height: 56px; font-size: 11px; }
|
||||||
|
|||||||
Reference in New Issue
Block a user