mirror of
https://github.com/34892002/edgeKey.git
synced 2026-05-06 15:22:43 +08:00
feat: alert组件
This commit is contained in:
58
components/ConfirmDialog.vue
Normal file
58
components/ConfirmDialog.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<dialog ref="dialogRef" class="modal">
|
||||
<div class="modal-box">
|
||||
<h3 class="text-lg font-bold">{{ state.title }}</h3>
|
||||
<p class="py-4 text-base-content/80">{{ state.message }}</p>
|
||||
<div class="modal-action">
|
||||
<button class="btn" :class="state.danger ? 'btn-error' : 'btn-primary'" @click="resolve(true)">{{ state.confirmText ?? '确认' }}</button>
|
||||
<button v-if="!state.alertMode" class="btn btn-ghost" @click="resolve(false)">{{ state.cancelText ?? '取消' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<form method="dialog" class="modal-backdrop"><button @click="resolve(false)">close</button></form>
|
||||
</dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from "vue";
|
||||
|
||||
const dialogRef = ref<HTMLDialogElement>();
|
||||
|
||||
const state = reactive({
|
||||
title: "",
|
||||
message: "",
|
||||
confirmText: "确认",
|
||||
cancelText: "取消",
|
||||
danger: false,
|
||||
alertMode: false,
|
||||
});
|
||||
|
||||
let _resolve: ((v: boolean) => void) | null = null;
|
||||
|
||||
function resolve(value: boolean) {
|
||||
dialogRef.value?.close();
|
||||
_resolve?.(value);_resolve = null;
|
||||
}
|
||||
|
||||
function confirm(options: { title: string; message: string; confirmText?: string; cancelText?: string; danger?: boolean }): Promise<boolean> {
|
||||
state.title = options.title;
|
||||
state.message = options.message;
|
||||
state.confirmText = options.confirmText ?? "确认";
|
||||
state.cancelText = options.cancelText ?? "取消";
|
||||
state.danger = options.danger ?? false;
|
||||
state.alertMode = false;
|
||||
dialogRef.value?.showModal();
|
||||
return new Promise((res) => { _resolve = res; });
|
||||
}
|
||||
|
||||
function alert(options: { title: string; message: string; confirmText?: string }): Promise<void> {
|
||||
state.title = options.title;
|
||||
state.message = options.message;
|
||||
state.confirmText = options.confirmText ?? "知道了";
|
||||
state.alertMode = true;
|
||||
state.danger = false;
|
||||
dialogRef.value?.showModal();
|
||||
return new Promise((res) => { _resolve = () => res(); });
|
||||
}
|
||||
|
||||
defineExpose({ confirm, alert });
|
||||
</script>
|
||||
@@ -1,5 +1,49 @@
|
||||
# 公共组件文档
|
||||
|
||||
## ConfirmDialog
|
||||
|
||||
全局确认/提示弹窗组件,替代原生 `confirm()` 和 `alert()`,基于 daisyUI `<dialog>`。
|
||||
|
||||
### 暴露方法
|
||||
|
||||
| 方法 | 参数 | 返回 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `confirm(options)` | 见下表 | `Promise<boolean>` | 确认弹窗,有确认+取消按钮 |
|
||||
| `alert(options)` | `title`, `message`, `confirmText?` | `Promise<void>` | 提示弹窗,只有"知道了"按钮 |
|
||||
|
||||
#### confirm options
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `title` | `string` | — | 弹窗标题 |
|
||||
| `message` | `string` | — | 弹窗内容 |
|
||||
| `confirmText` | `string` | `"确认"` | 确认按钮文字 |
|
||||
| `cancelText` | `string` | `"取消"` | 取消按钮文字 |
|
||||
| `danger` | `boolean` | `false` | 确认按钮显示为红色(危险操作) |
|
||||
|
||||
### 基本用法
|
||||
|
||||
```components/ConfirmDialog.vue#L1-5
|
||||
<ConfirmDialog ref="confirmRef" />
|
||||
```
|
||||
|
||||
```components/ConfirmDialog.vue#L1-10
|
||||
const confirmRef = useTemplateRef<InstanceType<typeof ConfirmDialog>>("confirmRef");
|
||||
|
||||
// 确认弹窗(危险操作)
|
||||
const ok = await confirmRef.value?.confirm({
|
||||
title: "删除",
|
||||
message: "确认删除?此操作不可撤销。",
|
||||
confirmText: "删除",
|
||||
danger: true,
|
||||
});
|
||||
if (!ok) return;
|
||||
|
||||
// 提示弹窗
|
||||
await confirmRef.value?.alert({ title: "提示", message: "请先选择商品" });
|
||||
```
|
||||
|
||||
|
||||
## StatusTag
|
||||
|
||||
状态标签组件,用于展示订单状态、支付状态、发货状态等。
|
||||
|
||||
@@ -107,12 +107,15 @@
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<!-- 确认弹窗 -->
|
||||
<ConfirmDialog ref="confirmRef" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, useTemplateRef } from "vue";
|
||||
import { useData } from "vike-vue/useData";
|
||||
import { normalizeTelefuncError } from "../../../lib/app-error";
|
||||
import ConfirmDialog from "../../../components/ConfirmDialog.vue";
|
||||
import { onCreateCard } from "./createCard.telefunc";
|
||||
import { onDeleteUnusedCards } from "./deleteUnusedCards.telefunc";
|
||||
import { onImportCards } from "./importCards.telefunc";
|
||||
@@ -130,6 +133,7 @@ const cardPage = ref({ items: [...cards], total: cards.length });
|
||||
|
||||
const addModalRef = useTemplateRef<HTMLDialogElement>("addModalRef");
|
||||
const importModalRef = useTemplateRef<HTMLDialogElement>("importModalRef");
|
||||
const confirmRef = useTemplateRef<InstanceType<typeof ConfirmDialog>>("confirmRef");
|
||||
const message = ref("");
|
||||
const errorMessage = ref("");
|
||||
|
||||
@@ -231,7 +235,8 @@ async function handleImportCards() {
|
||||
}
|
||||
|
||||
async function handleDeleteCard(id: number) {
|
||||
if (!confirm(`确认删除卡密 #${id}?此操作不可撤销。`)) return;
|
||||
const ok = await confirmRef.value?.confirm({ title: "删除卡密", message: `确认删除卡密 #${id}?此操作不可撤销。`, confirmText: "删除", danger: true });
|
||||
if (!ok) return;
|
||||
message.value = "";
|
||||
errorMessage.value = "";
|
||||
try {
|
||||
@@ -245,11 +250,12 @@ async function handleDeleteCard(id: number) {
|
||||
|
||||
async function handleDeleteUnused() {
|
||||
if (!filter.productId) {
|
||||
alert("请先在筛选区选择商品");
|
||||
await confirmRef.value?.alert({ title: "提示", message: "请先在筛选区选择商品" });
|
||||
return;
|
||||
}
|
||||
const product = products.find(p => String(p.id) === filter.productId);
|
||||
if (!confirm(`确认清空「${product?.name ?? filter.productId}」所有未售卡密?此操作不可撤销。`)) return;
|
||||
const ok = await confirmRef.value?.confirm({ title: "清空未售库存", message: `确认清空「${product?.name ?? filter.productId}」所有未售卡密?此操作不可撤销。`, confirmText: "清空", danger: true });
|
||||
if (!ok) return;
|
||||
message.value = "";
|
||||
errorMessage.value = "";
|
||||
try {
|
||||
|
||||
@@ -84,11 +84,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<ConfirmDialog ref="confirmRef" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { normalizeTelefuncError } from "../../../lib/app-error";
|
||||
import { reactive, ref } from "vue";
|
||||
import { reactive, ref, useTemplateRef } from "vue";
|
||||
import ConfirmDialog from "../../../components/ConfirmDialog.vue";
|
||||
import { useData } from "vike-vue/useData";
|
||||
import StatusTag from "../../../components/StatusTag.vue";
|
||||
import { onDeleteCategory } from "./deleteCategory.telefunc";
|
||||
@@ -101,6 +103,7 @@ const { categories } = useData<Data>();
|
||||
const categoryList = ref([...categories]);
|
||||
const saving = ref(false);
|
||||
const errorMessage = ref("");
|
||||
const confirmRef = useTemplateRef<InstanceType<typeof ConfirmDialog>>("confirmRef");
|
||||
|
||||
const form = reactive({
|
||||
id: undefined as number | undefined,
|
||||
@@ -178,7 +181,7 @@ async function handleToggle(category: (typeof categories)[number]) {
|
||||
}
|
||||
|
||||
async function handleDelete(category: (typeof categories)[number]) {
|
||||
if (!window.confirm(`确认删除分类“${category.name}”吗?`)) {
|
||||
if (!await confirmRef.value?.confirm({ title: "删除分类", message: `确认删除分类"${category.name}"吗?`, confirmText: "删除", danger: true })) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -477,13 +477,15 @@
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<ConfirmDialog ref="confirmRef" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SecretInput from "../../../components/SecretInput.vue";
|
||||
import StatusTag from "../../../components/StatusTag.vue";
|
||||
import ConfirmDialog from "../../../components/ConfirmDialog.vue";
|
||||
import { normalizeTelefuncError } from "../../../lib/app-error";
|
||||
import { reactive, ref, computed } from "vue";
|
||||
import { reactive, ref, computed, useTemplateRef } from "vue";
|
||||
import { useData } from "vike-vue/useData";
|
||||
import { onSaveEmailConfig, onDeleteEmailConfig, onSaveEmailPushSettings, onActivateEmailProvider, onClearEmailLogs } from "./saveEmailConfig.telefunc";
|
||||
import { onSaveEmailTemplate } from "./saveEmailTemplate.telefunc";
|
||||
@@ -526,6 +528,7 @@ type MailboxItem = {
|
||||
const { configs, templates, logs: initialLogs, metrics, pushSettings: initialPushSettings } = useData<Data>();
|
||||
|
||||
const activeTab = ref<"stats" | "config" | "list" | "template">("stats");
|
||||
const confirmRef = useTemplateRef<InstanceType<typeof ConfirmDialog>>("confirmRef");
|
||||
|
||||
// ===================== Mailbox list =====================
|
||||
const logList = reactive([...initialLogs]);
|
||||
@@ -710,7 +713,7 @@ async function handleClearLogs() {
|
||||
logList.splice(0);
|
||||
showClearConfirm.value = false;
|
||||
} catch (error) {
|
||||
alert(normalizeTelefuncError(error, "清除失败"));
|
||||
await confirmRef.value?.alert({ title: "错误", message: normalizeTelefuncError(error, "清除失败") });
|
||||
} finally {
|
||||
clearingLogs.value = false;
|
||||
}
|
||||
@@ -827,7 +830,7 @@ async function handleActivate(item: MailboxItem) {
|
||||
m.isEnabled = m.id === item.id;
|
||||
}
|
||||
} catch (error) {
|
||||
alert(normalizeTelefuncError(error, "激活失败"));
|
||||
await confirmRef.value?.alert({ title: "错误", message: normalizeTelefuncError(error, "激活失败") });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,11 +52,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<ConfirmDialog ref="confirmRef" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { normalizeTelefuncError } from "../../../lib/app-error";
|
||||
import { ref } from "vue";
|
||||
import { ref, useTemplateRef } from "vue";
|
||||
import ConfirmDialog from "../../../components/ConfirmDialog.vue";
|
||||
import { useData } from "vike-vue/useData";
|
||||
import { formatCents } from "../../../lib/utils/money";
|
||||
import StatusTag from "../../../components/StatusTag.vue";
|
||||
@@ -65,9 +67,10 @@ import type { Data } from "./+data";
|
||||
|
||||
const { products } = useData<Data>();
|
||||
const productList = ref([...products]);
|
||||
const confirmRef = useTemplateRef<InstanceType<typeof ConfirmDialog>>("confirmRef");
|
||||
|
||||
async function handleDelete(product: (typeof products)[number]) {
|
||||
if (!window.confirm(`确认删除商品“${product.name}”吗?`)) {
|
||||
if (!await confirmRef.value?.confirm({ title: "删除商品", message: `确认删除商品"${product.name}"吗?`, confirmText: "删除", danger: true })) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -75,7 +78,7 @@ async function handleDelete(product: (typeof products)[number]) {
|
||||
await onDeleteProduct({ id: product.id });
|
||||
productList.value = productList.value.filter((item) => item.id !== product.id);
|
||||
} catch (error) {
|
||||
window.alert(normalizeTelefuncError(error, "删除失败"));
|
||||
await confirmRef.value?.alert({ title: "错误", message: normalizeTelefuncError(error, "删除失败") });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user