更新若干功能

This commit is contained in:
李琦
2026-08-14 17:54:06 +08:00
parent 89bc265f68
commit ce00c9d193
18 changed files with 779 additions and 158 deletions

View File

@@ -150,7 +150,7 @@ onUnmounted(()=>{clearTimeout(aiKeyTimer)})
<div v-else class="preview-notice"><Info/><div><b>{{t('fsAdminOnlyTitle')}}</b><small>{{t('fsAdminOnlyDesc')}}</small></div></div>
</section>
</template>
<template v-else><section class="panel database-panel"><div class="db-title"><h2><Database/>{{t('dbLocation')}}</h2><span class="db-connected"><CheckCircle2/>{{t('dbConnected')}}</span></div><div v-if="!native" class="preview-notice"><Info/><div><b>{{t('previewModeTitle')}}</b><small>{{t('previewModeDb')}}</small></div></div><div class="db-path"><span>{{t('dbCurrentLoc')}}</span><code :title="settings.databasePath">{{settings.databasePath||t('dbNoPath')}}</code><button :title="t('copyPathTitle')" :disabled="!settings.databasePath" @click="copyPath"><Copy/></button></div><p v-if="dbMessage" class="db-message">{{dbMessage}}</p><button class="btn secondary migrate" :disabled="!native" @click="migrate"><Upload/>{{t('migrateBtn')}}</button></section>
<template v-else><section class="panel database-panel"><div class="db-title"><h2><Database/>{{t('dbLocation')}}</h2><span class="db-connected"><CheckCircle2/>{{t('dbConnected')}}</span></div><div v-if="!native" class="preview-notice"><Info/><div><b>{{t('previewModeTitle')}}</b><small>{{t('previewModeDb')}}</small></div></div><div class="db-path"><span>{{t('dbCurrentLoc')}}</span><code :title="settings.databasePath">{{settings.databasePath||t('dbNoPath')}}</code><button :title="t('copyPathTitle')" :disabled="!settings.databasePath" @click="copyPath"><Copy/></button></div><p class="db-relocate-hint">{{t('dbRelocateHint')}}</p><p v-if="dbMessage" class="db-message">{{dbMessage}}</p><button class="btn secondary migrate" :disabled="!native" @click="migrate"><Upload/>{{t('migrateBtn')}}</button></section>
<section class="panel danger-zone"><h2><Trash2/>{{t('dangerZone')}}</h2><p>{{t('dangerDesc')}}</p><div><button @click="clear('stats')"><BarChart3/><span><b>{{t('clearStats')}}</b><small>{{t('clearStatsDesc')}}</small></span></button><button @click="clear('project')"><Folder/><span><b>{{t('clearProject')}}</b><small>{{t('clearProjectDesc')}}</small></span></button><button class="danger" @click="clear('all')"><Trash2/><span><b>{{t('clearAllData')}}</b><small>{{t('clearAllDesc')}}</small></span></button></div></section></template>
<AIScopeDrawer v-if="aiOpen" kind="config" :title="t('settings')" @close="aiOpen=false"/>
</div></template>

View File

@@ -1,8 +1,8 @@
<script setup>
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { NotebookPen, Send, BellRing, Sparkles, RefreshCw, Users, LogIn, WifiOff, Quote, Check, ChevronLeft, ChevronRight, UserRound } from 'lucide-vue-next'
import { call, isNative, on } from '../api'
import { NotebookPen, Send, BellRing, Sparkles, RefreshCw, Users, LogIn, WifiOff, Quote, Check, ChevronLeft, ChevronRight, UserRound, Copy } from 'lucide-vue-next'
import { call, isNative, on, copyText } from '../api'
import { useAppStore } from '../store'
import { teamsErr, currentTeam, isTeamAdmin, loadTeams, teamErrCode } from '../team'
import MarkdownView from '../components/MarkdownView.vue'
@@ -59,6 +59,14 @@ async function quoteDayReport() {
else store.showToast({ type: 'error', key: 'teamNoDayReport' })
} catch (e) { store.showToast({ type: 'error', text: errText(e) }) }
}
async function copyReport(text) {
try {
await copyText(text)
store.showToast({ type: 'success', key: 'copied' })
} catch {
store.showToast({ type: 'error', key: 'copyFailed' })
}
}
async function submit() {
if (!myDraft.value.trim() || busy.value) return
busy.value = 'submit'
@@ -135,6 +143,7 @@ onUnmounted(() => offDigest?.())
<textarea v-model="myDraft" class="team-report-editor" rows="6" :placeholder="t('teamReportPh')" />
<div class="team-report-ops">
<button v-if="isToday" class="btn secondary" :title="t('teamQuoteDayReportHint')" @click="quoteDayReport"><Quote />{{ t('teamQuoteDayReport') }}</button>
<button class="btn secondary" :disabled="!myDraft.trim()" :title="t('copyReport')" @click="copyReport(myDraft)"><Copy />{{ t('copyReport') }}</button>
<span class="spacer" />
<button class="btn primary" :disabled="!myDraft.trim() || !!busy" @click="submit"><Send />{{ myReport ? t('teamReportUpdateBtn') : t('teamReportSubmitBtn') }}</button>
</div>
@@ -146,6 +155,7 @@ onUnmounted(() => offDigest?.())
<span class="pc-badge ai"><Sparkles /></span>
<div><b>{{ t('teamDigest') }}</b><small>{{ board?.digest ? t('teamDigestAt', { at: fmtTime(board.digest.generatedAt), provider: board.digest.provider }) : t('teamDigestNone') }}</small></div>
<span class="spacer" />
<button v-if="board?.digest?.content" class="btn secondary" :title="t('copyDigest')" @click="copyReport(board.digest.content)"><Copy />{{ t('copyDigest') }}</button>
<button v-if="isTeamAdmin" class="btn secondary" :disabled="digestBusy" @click="generateDigest">
<component :is="digestBusy ? RefreshCw : Sparkles" :class="{ spin: digestBusy }" />{{ digestBusy ? t('generating') : (board?.digest ? t('teamDigestRegen') : t('teamDigestGen')) }}
</button>
@@ -156,7 +166,10 @@ onUnmounted(() => offDigest?.())
<!-- 成员提交状态 -->
<section class="team-report-grid">
<div v-for="r in otherReports" :key="r.userId" class="panel team-report-card ok">
<header><span class="trc-ava"><Check /></span><b>{{ r.user }}</b><time>{{ fmtTime(r.submittedAt) }}</time></header>
<header>
<span class="trc-ava"><Check /></span><b>{{ r.user }}</b><time>{{ fmtTime(r.submittedAt) }}</time>
<button v-if="r.content" class="icon-btn" :title="t('copyReport')" @click="copyReport(r.content)"><Copy /></button>
</header>
<MarkdownView v-if="r.content" class="md-body sm" :source="r.content" />
<p v-else class="team-none">{{ t('teamReportContentHidden') }}</p>
</div>