feat: 添加确认模态框组件并在多个页面中实现删除和退出确认功能
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue";
|
||||
import { apiFetch, ensureMe, userRef } from "../lib/api";
|
||||
import BbModal from "../components/BbModal.vue";
|
||||
|
||||
const loadingUsers = ref(false);
|
||||
const usersError = ref("");
|
||||
@@ -22,6 +23,36 @@ const openFolderIds = ref(new Set());
|
||||
|
||||
const isAdmin = computed(() => userRef.value?.role === "admin");
|
||||
|
||||
const confirmOpen = ref(false);
|
||||
const confirmTitle = ref("请确认");
|
||||
const confirmMessage = ref("");
|
||||
const confirmOkText = ref("确定");
|
||||
const confirmDanger = ref(false);
|
||||
let confirmResolve = null;
|
||||
|
||||
function askConfirm(message, { title = "请确认", okText = "确定", danger = false } = {}) {
|
||||
confirmTitle.value = title;
|
||||
confirmMessage.value = message;
|
||||
confirmOkText.value = okText;
|
||||
confirmDanger.value = danger;
|
||||
confirmOpen.value = true;
|
||||
return new Promise((resolve) => {
|
||||
confirmResolve = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
function resolveConfirm(result) {
|
||||
const resolve = confirmResolve;
|
||||
confirmResolve = null;
|
||||
confirmOpen.value = false;
|
||||
if (resolve) resolve(Boolean(result));
|
||||
}
|
||||
|
||||
function onConfirmModalUpdate(v) {
|
||||
if (!v) resolveConfirm(false);
|
||||
else confirmOpen.value = true;
|
||||
}
|
||||
|
||||
async function loadUsers() {
|
||||
loadingUsers.value = true;
|
||||
usersError.value = "";
|
||||
@@ -62,6 +93,21 @@ async function loadBookmarks() {
|
||||
}
|
||||
}
|
||||
|
||||
let searchTimer = 0;
|
||||
watch(
|
||||
() => q.value,
|
||||
() => {
|
||||
window.clearTimeout(searchTimer);
|
||||
searchTimer = window.setTimeout(() => {
|
||||
loadBookmarks();
|
||||
}, 200);
|
||||
}
|
||||
);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.clearTimeout(searchTimer);
|
||||
});
|
||||
|
||||
function selectUser(id) {
|
||||
selectedUserId.value = id;
|
||||
q.value = "";
|
||||
@@ -152,7 +198,7 @@ function isFolderOpen(folderId) {
|
||||
|
||||
async function deleteBookmark(bookmarkId) {
|
||||
if (!selectedUserId.value) return;
|
||||
if (!confirm("确定删除该书签?")) return;
|
||||
if (!(await askConfirm("确定删除该书签?", { title: "删除书签", okText: "删除", danger: true }))) return;
|
||||
try {
|
||||
await apiFetch(`/admin/users/${selectedUserId.value}/bookmarks/${bookmarkId}`, { method: "DELETE" });
|
||||
await loadBookmarks();
|
||||
@@ -163,7 +209,7 @@ async function deleteBookmark(bookmarkId) {
|
||||
|
||||
async function deleteFolder(folderId) {
|
||||
if (!selectedUserId.value) return;
|
||||
if (!confirm("确定删除该文件夹?子文件夹会一起删除,文件夹内书签会变成未分组。")) return;
|
||||
if (!(await askConfirm("确定删除该文件夹?子文件夹会一起删除,文件夹内书签会变成未分组。", { title: "删除文件夹", okText: "删除", danger: true }))) return;
|
||||
try {
|
||||
await apiFetch(`/admin/users/${selectedUserId.value}/folders/${folderId}`, { method: "DELETE" });
|
||||
await loadFolders();
|
||||
@@ -240,8 +286,10 @@ onMounted(async () => {
|
||||
</div>
|
||||
|
||||
<div class="bb-row" style="gap: 8px;">
|
||||
<input v-model="q" class="bb-input bb-input--sm" placeholder="搜索标题/链接" @keyup.enter="loadBookmarks" />
|
||||
<button class="bb-btn bb-btn--secondary" :disabled="loadingBookmarks" @click="loadBookmarks">搜索</button>
|
||||
<div class="bb-searchWrap" style="min-width: 260px;">
|
||||
<input v-model="q" class="bb-input bb-input--sm bb-input--withClear" placeholder="搜索标题/链接" />
|
||||
<button v-if="q.trim()" class="bb-searchClear" type="button" aria-label="清空搜索" @click="q = ''">×</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -326,6 +374,14 @@ onMounted(async () => {
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<BbModal :model-value="confirmOpen" :title="confirmTitle" max-width="520px" @update:model-value="onConfirmModalUpdate">
|
||||
<div class="bb-muted" style="white-space: pre-wrap; line-height: 1.6;">{{ confirmMessage }}</div>
|
||||
<div class="bb-row" style="justify-content: flex-end; gap: 10px; margin-top: 14px;">
|
||||
<button class="bb-btn bb-btn--secondary" type="button" @click="resolveConfirm(false)">取消</button>
|
||||
<button class="bb-btn" :class="confirmDanger ? 'bb-btn--danger' : ''" type="button" @click="resolveConfirm(true)">{{ confirmOkText }}</button>
|
||||
</div>
|
||||
</BbModal>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user