feat(workspace): 新增配置待完成 Widget, 对接 config-check API

工作台新增 config-alert Widget(三栏栅格), 实时展示未完成配置项,
点击跳转对应配置页, 空状态显示「配置已完善」;
configCheck.json(10语)初始化分类文案, workspace.json 补 allComplete key。
This commit is contained in:
DaxPay Dev
2026-07-20 10:26:21 +08:00
parent 2a2f823303
commit d68ddfdccd
22 changed files with 163 additions and 50 deletions

View File

@@ -1,8 +1,4 @@
{
"payProduct": {
"title": "Payment Product",
"description": "Some payment products have not completed channel parameter configuration"
},
"platformWebsite": {
"title": "Site Information",
"description": "System name, logo, ICP filing and other site display info are not configured"

View File

@@ -71,6 +71,7 @@
},
"configAlert": {
"bannerTitle": "You have {n} configuration(s) pending",
"viewDetail": "View Details"
"viewDetail": "View Details",
"allComplete": "All configurations complete"
}
}

View File

@@ -1,8 +1,4 @@
{
"payProduct": {
"title": "Parameter Produk Pembayaran",
"description": "Beberapa produk pembayaran belum menyelesaikan konfigurasi parameter saluran"
},
"platformWebsite": {
"title": "Informasi Situs",
"description": "Nama sistem, logo, pendaftaran ICP dan info tampilan situs lainnya belum dikonfigurasi"

View File

@@ -71,6 +71,7 @@
},
"configAlert": {
"bannerTitle": "{n} konfigurasi tertunda",
"viewDetail": "Lihat Detail"
"viewDetail": "Lihat Detail",
"allComplete": "Semua konfigurasi selesai"
}
}

View File

@@ -1,8 +1,4 @@
{
"payProduct": {
"title": "決済商品パラメータ",
"description": "チャネルパラメータの設定が未完了の決済商品があります"
},
"platformWebsite": {
"title": "サイト情報",
"description": "システム名、ロゴ、ICP備案などのサイト表示情報が未設定です"

View File

@@ -71,6 +71,7 @@
},
"configAlert": {
"bannerTitle": "{n} 件の設定が未完了です",
"viewDetail": "詳細を表示"
"viewDetail": "詳細を表示",
"allComplete": "すべての設定が完了しています"
}
}

View File

@@ -1,8 +1,4 @@
{
"payProduct": {
"title": "결제 상품 매개변수",
"description": "채널 매개변수 설정이 완료되지 않은 결제 상품이 있습니다"
},
"platformWebsite": {
"title": "사이트 정보",
"description": "시스템 이름, 로고, ICP 신고 등 사이트 표시 정보가 설정되지 않았습니다"

View File

@@ -71,6 +71,7 @@
},
"configAlert": {
"bannerTitle": "{n}개의 설정이 미완료입니다",
"viewDetail": "상세 보기"
"viewDetail": "상세 보기",
"allComplete": "모든 설정이 완료되었습니다"
}
}

View File

@@ -1,8 +1,4 @@
{
"payProduct": {
"title": "Parameter Produk Pembayaran",
"description": "Sesetengah produk pembayaran belum melengkapkan konfigurasi parameter saluran"
},
"platformWebsite": {
"title": "Maklumat Tapak",
"description": "Nama sistem, logo, pendaftaran ICP dan maklumat paparan tapak lain belum dikonfigurasi"

View File

@@ -71,6 +71,7 @@
},
"configAlert": {
"bannerTitle": "{n} konfigurasi tertunggak",
"viewDetail": "Lihat Butiran"
"viewDetail": "Lihat Butiran",
"allComplete": "Semua konfigurasi selesai"
}
}

View File

@@ -1,8 +1,4 @@
{
"payProduct": {
"title": "พารามิเตอร์ผลิตภัณฑ์การชำระเงิน",
"description": "ผลิตภัณฑ์การชำระเงินบางรายการยังไม่ได้กำหนดค่าพารามิเตอร์ช่องทาง"
},
"platformWebsite": {
"title": "ข้อมูลเว็บไซต์",
"description": "ชื่อระบบ โลโก้ การจดทะเบียน ICP และข้อมูลการแสดงผลอื่นๆ ยังไม่ได้กำหนดค่า"

View File

@@ -71,6 +71,7 @@
},
"configAlert": {
"bannerTitle": "มีการกำหนดค้าง {n} รายการ",
"viewDetail": "ดูรายละเอียด"
"viewDetail": "ดูรายละเอียด",
"allComplete": "การกำหนดค่าเสร็จสมบูรณ์ทั้งหมด"
}
}

View File

@@ -1,8 +1,4 @@
{
"payProduct": {
"title": "Tham Số Sản Phẩm Thanh Toán",
"description": "Một số sản phẩm thanh toán chưa hoàn tất cấu hình tham số kênh"
},
"platformWebsite": {
"title": "Thông Tin Trang Web",
"description": "Tên hệ thống, logo, đăng ký ICP và thông tin hiển thị trang khác chưa được cấu hình"

View File

@@ -71,6 +71,7 @@
},
"configAlert": {
"bannerTitle": "Có {n} cấu hình chưa hoàn tất",
"viewDetail": "Xem chi tiết"
"viewDetail": "Xem chi tiết",
"allComplete": "Tất cả cấu hình đã hoàn tất"
}
}

View File

@@ -1,8 +1,4 @@
{
"payProduct": {
"title": "支付产品参数",
"description": "有支付产品尚未完成通道参数配置"
},
"platformWebsite": {
"title": "站点信息",
"description": "系统名称、Logo、ICP 备案等站点展示信息未配置"

View File

@@ -71,6 +71,7 @@
},
"configAlert": {
"bannerTitle": "您有 {n} 项配置待完成",
"viewDetail": "查看详情"
"viewDetail": "查看详情",
"allComplete": "配置已完善"
}
}

View File

@@ -1,8 +1,4 @@
{
"payProduct": {
"title": "支付產品參數",
"description": "有支付產品尚未完成通道參數配置"
},
"platformWebsite": {
"title": "站點資訊",
"description": "系統名稱、Logo、ICP 備案等站點展示資訊未配置"

View File

@@ -71,6 +71,7 @@
},
"configAlert": {
"bannerTitle": "您有 {n} 項配置待完成",
"viewDetail": "查看詳情"
"viewDetail": "查看詳情",
"allComplete": "配置已完善"
}
}

View File

@@ -1,8 +1,4 @@
{
"payProduct": {
"title": "支付產品參數",
"description": "有支付產品尚未完成通道參數配置"
},
"platformWebsite": {
"title": "站點資訊",
"description": "系統名稱、Logo、ICP 備案等站點展示資訊未配置"

View File

@@ -71,6 +71,7 @@
},
"configAlert": {
"bannerTitle": "您有 {n} 項配置待完成",
"viewDetail": "查看詳情"
"viewDetail": "查看詳情",
"allComplete": "配置已完善"
}
}

View File

@@ -1,5 +1,6 @@
import type { LayoutItem, WidgetMeta } from './types';
import ConfigAlertWidget from './widgets/config-alert.widget.vue';
import NoticeListWidget from './widgets/notice-list.widget.vue';
import PayTradeListWidget from './widgets/pay-trade-list.widget.vue';
import ProviderDistributionWidget from './widgets/provider-distribution.widget.vue';
@@ -33,6 +34,15 @@ export const WIDGET_REGISTRY: WidgetMeta[] = [
defaultSpan: 24,
defaultOrder: 1,
},
{
// 配置待完成: 提示未完成的平台级配置项, 点击跳转对应配置页
id: 'config-alert',
component: ConfigAlertWidget,
titleKey: 'dashboard.workspace.widget.configAlert',
icon: 'lucide:list-checks',
defaultSpan: 8,
defaultOrder: 2,
},
{
// 交易概览:左栏,三栏并排的第一栏
id: 'trade-overview',

View File

@@ -0,0 +1,133 @@
<script lang="ts" setup>
import type { DashboardData } from '../types';
import { computed, onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import { IconifyIcon } from '@vben/icons';
import { $t } from '@vben/locales';
import { ConfigCheckItem } from '#/api/payment/check/config-check.api';
import { ConfigCheckApi } from '#/api/payment/check/config-check.api';
interface Props {
data?: DashboardData;
}
defineOptions({ name: 'ConfigAlertWidget' });
withDefaults(defineProps<Props>(), {
data: undefined,
});
const router = useRouter();
const loading = ref(false);
const items = ref<ConfigCheckItem[]>([]);
const totalCount = ref(0);
// 分类图标映射(与后端 ConfigCheckCategoryEnum.code 对应)
const categoryIconMap: Record<string, string> = {
channelMerchant: 'lucide:store',
mchApp: 'lucide:app-window',
mchCredential: 'lucide:key-round',
mchNotify: 'lucide:bell-ring',
payProduct: 'lucide:credit-card',
payRoute: 'lucide:route',
platformOss: 'lucide:hard-drive',
platformUrl: 'lucide:link',
platformWebsite: 'lucide:globe',
socialLogin: 'lucide:log-in',
};
function categoryIcon(category: string): string {
return categoryIconMap[category] ?? 'lucide:alert-circle';
}
async function load() {
loading.value = true;
try {
const { data } = await ConfigCheckApi.items();
items.value = data?.items ?? [];
totalCount.value = data?.totalCount ?? 0;
} finally {
loading.value = false;
}
}
onMounted(load);
// 全部配置已完成
const isComplete = computed(() => totalCount.value === 0);
// routeName 字段实际存储的是前端路由 path, 直接 push
function navTo(routePath: string) {
router.push(routePath).catch(() => {});
}
</script>
<template>
<a-card variant="borderless" class="!h-full !bg-card">
<template #title>
<div class="flex items-center gap-2">
<IconifyIcon icon="lucide:list-checks" class="size-4 text-primary" />
<span>{{ $t('dashboard.workspace.widget.configAlert') }}</span>
<a-tag v-if="totalCount > 0" color="orange" class="!ml-1 !mr-0">
{{ totalCount }}
</a-tag>
</div>
</template>
<template #extra>
<a-button type="link" size="small" @click="load">
<IconifyIcon icon="lucide:refresh-cw" class="mr-1 size-3.5" />
<span>{{ $t('common.refresh') }}</span>
</a-button>
</template>
<a-skeleton v-if="loading" active :paragraph="{ rows: 4 }" />
<!-- 空状态: 全部已配置 -->
<div v-else-if="isComplete" class="flex flex-col items-center justify-center py-6">
<IconifyIcon icon="lucide:circle-check-big" class="mb-2 size-10 text-emerald-500" />
<span class="text-sm text-foreground/60">{{ $t('dashboard.workspace.configAlert.allComplete') }}</span>
</div>
<!-- 未配置列表 -->
<ul v-else class="alert-scroll flex max-h-[230px] flex-col gap-2 overflow-y-auto pr-1">
<li
v-for="item in items"
:key="item.itemKey"
class="flex cursor-pointer items-center gap-3 rounded-md p-2 transition-colors hover:bg-accent"
@click="navTo(item.routeName)"
>
<div class="flex size-8 shrink-0 items-center justify-center rounded-md bg-orange-50 text-orange-500">
<IconifyIcon :icon="categoryIcon(item.category)" class="size-4" />
</div>
<div class="min-w-0 flex-1">
<div class="truncate text-sm font-medium">
{{ $t(item.titleKey) }}
</div>
<div class="truncate text-xs text-foreground/50">
{{ $t(item.descriptionKey) }}
</div>
</div>
<a-tag v-if="item.count !== undefined && item.count > 0" color="orange" class="!m-0 shrink-0">
{{ item.count }}
</a-tag>
<IconifyIcon icon="lucide:chevron-right" class="size-4 shrink-0 text-foreground/30" />
</li>
</ul>
</a-card>
</template>
<style scoped>
.alert-scroll::-webkit-scrollbar {
width: 4px;
}
.alert-scroll::-webkit-scrollbar-thumb {
background-color: hsl(var(--border));
border-radius: 2px;
}
.alert-scroll::-webkit-scrollbar-track {
background: transparent;
}
</style>