feat: 新增通知管理功能,包括通知的创建、列表展示及相关路由配置;更新相关依赖
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
# backend service base url, prod environment
|
# backend service base url, prod environment
|
||||||
VITE_SERVICE_BASE_URL=http://192.168.1.6:9527
|
VITE_SERVICE_BASE_URL=http://192.168.1.7:9527
|
||||||
|
|
||||||
# other backend service base url, prod environment
|
# other backend service base url, prod environment
|
||||||
VITE_OTHER_SERVICE_BASE_URL= `{}`
|
VITE_OTHER_SERVICE_BASE_URL= `{}`
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# backend service base url, test environment
|
# backend service base url, test environment
|
||||||
VITE_SERVICE_BASE_URL=http://192.168.1.17:9528
|
VITE_SERVICE_BASE_URL=http://192.168.1.7:9528
|
||||||
|
|
||||||
# other backend service base url, test environment
|
# other backend service base url, test environment
|
||||||
VITE_OTHER_SERVICE_BASE_URL= `{}`
|
VITE_OTHER_SERVICE_BASE_URL= `{}`
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
"@better-scroll/core": "2.5.1",
|
"@better-scroll/core": "2.5.1",
|
||||||
"@elysiajs/eden": "^1.4.5",
|
"@elysiajs/eden": "^1.4.5",
|
||||||
"@iconify/vue": "5.0.0",
|
"@iconify/vue": "5.0.0",
|
||||||
"@riwa/api-types": "http://192.168.1.17:9527/api/riwa-eden-0.0.84.tgz",
|
"@riwa/api-types": "http://192.168.1.7:9527/api/riwa-eden-0.0.98.tgz",
|
||||||
"@sa/axios": "workspace:*",
|
"@sa/axios": "workspace:*",
|
||||||
"@sa/color": "workspace:*",
|
"@sa/color": "workspace:*",
|
||||||
"@sa/hooks": "workspace:*",
|
"@sa/hooks": "workspace:*",
|
||||||
|
|||||||
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@@ -18,8 +18,8 @@ importers:
|
|||||||
specifier: 5.0.0
|
specifier: 5.0.0
|
||||||
version: 5.0.0(vue@3.5.25(typescript@5.9.3))
|
version: 5.0.0(vue@3.5.25(typescript@5.9.3))
|
||||||
'@riwa/api-types':
|
'@riwa/api-types':
|
||||||
specifier: http://192.168.1.17:9527/api/riwa-eden-0.0.84.tgz
|
specifier: http://192.168.1.7:9527/api/riwa-eden-0.0.98.tgz
|
||||||
version: '@riwa/eden@http://192.168.1.17:9527/api/riwa-eden-0.0.84.tgz(@elysiajs/eden@1.4.5(elysia@1.4.19(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))'
|
version: '@riwa/eden@http://192.168.1.7:9527/api/riwa-eden-0.0.98.tgz(@elysiajs/eden@1.4.5(elysia@1.4.19(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))'
|
||||||
'@sa/axios':
|
'@sa/axios':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:packages/axios
|
version: link:packages/axios
|
||||||
@@ -1083,9 +1083,9 @@ packages:
|
|||||||
'@quansync/fs@0.1.6':
|
'@quansync/fs@0.1.6':
|
||||||
resolution: {integrity: sha512-zoA8SqQO11qH9H8FCBR7NIbowYARIPmBz3nKjgAaOUDi/xPAAu1uAgebtV7KXHTc6CDZJVRZ1u4wIGvY5CWYaw==}
|
resolution: {integrity: sha512-zoA8SqQO11qH9H8FCBR7NIbowYARIPmBz3nKjgAaOUDi/xPAAu1uAgebtV7KXHTc6CDZJVRZ1u4wIGvY5CWYaw==}
|
||||||
|
|
||||||
'@riwa/eden@http://192.168.1.17:9527/api/riwa-eden-0.0.84.tgz':
|
'@riwa/eden@http://192.168.1.7:9527/api/riwa-eden-0.0.98.tgz':
|
||||||
resolution: {tarball: http://192.168.1.17:9527/api/riwa-eden-0.0.84.tgz}
|
resolution: {tarball: http://192.168.1.7:9527/api/riwa-eden-0.0.98.tgz}
|
||||||
version: 0.0.84
|
version: 0.0.98
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@elysiajs/eden': ^1.4.5
|
'@elysiajs/eden': ^1.4.5
|
||||||
|
|
||||||
@@ -5080,7 +5080,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
quansync: 0.3.0
|
quansync: 0.3.0
|
||||||
|
|
||||||
'@riwa/eden@http://192.168.1.17:9527/api/riwa-eden-0.0.84.tgz(@elysiajs/eden@1.4.5(elysia@1.4.19(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))':
|
'@riwa/eden@http://192.168.1.7:9527/api/riwa-eden-0.0.98.tgz(@elysiajs/eden@1.4.5(elysia@1.4.19(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@elysiajs/eden': 1.4.5(elysia@1.4.19(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3))
|
'@elysiajs/eden': 1.4.5(elysia@1.4.19(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3))
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
|
|||||||
bank: () => import("@/views/bank/index.vue"),
|
bank: () => import("@/views/bank/index.vue"),
|
||||||
deposit_fiat: () => import("@/views/deposit/fiat/index.vue"),
|
deposit_fiat: () => import("@/views/deposit/fiat/index.vue"),
|
||||||
home: () => import("@/views/home/index.vue"),
|
home: () => import("@/views/home/index.vue"),
|
||||||
|
notification: () => import("@/views/notification/index.vue"),
|
||||||
rwa_product: () => import("@/views/rwa/product/index.vue"),
|
rwa_product: () => import("@/views/rwa/product/index.vue"),
|
||||||
rwa_producttype: () => import("@/views/rwa/productType/index.vue"),
|
rwa_producttype: () => import("@/views/rwa/productType/index.vue"),
|
||||||
rwa_subscribe: () => import("@/views/rwa/subscribe/index.vue"),
|
rwa_subscribe: () => import("@/views/rwa/subscribe/index.vue"),
|
||||||
@@ -32,7 +33,6 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
|
|||||||
transfer: () => import("@/views/transfer/index.vue"),
|
transfer: () => import("@/views/transfer/index.vue"),
|
||||||
user_bankcard: () => import("@/views/user/bankcard/index.vue"),
|
user_bankcard: () => import("@/views/user/bankcard/index.vue"),
|
||||||
user_list: () => import("@/views/user/list/index.vue"),
|
user_list: () => import("@/views/user/list/index.vue"),
|
||||||
user_transfer: () => import("@/views/user/transfer/index.vue"),
|
|
||||||
withdraw_approved: () => import("@/views/withdraw/approved/index.vue"),
|
withdraw_approved: () => import("@/views/withdraw/approved/index.vue"),
|
||||||
withdraw_fiat: () => import("@/views/withdraw/fiat/index.vue"),
|
withdraw_fiat: () => import("@/views/withdraw/fiat/index.vue"),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -116,6 +116,16 @@ export const generatedRoutes: GeneratedRoute[] = [
|
|||||||
hideInMenu: true
|
hideInMenu: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'notification',
|
||||||
|
path: '/notification',
|
||||||
|
component: 'layout.base$view.notification',
|
||||||
|
meta: {
|
||||||
|
title: 'notification',
|
||||||
|
i18nKey: 'route.notification',
|
||||||
|
order: 7
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'rwa',
|
name: 'rwa',
|
||||||
path: '/rwa',
|
path: '/rwa',
|
||||||
@@ -222,15 +232,6 @@ export const generatedRoutes: GeneratedRoute[] = [
|
|||||||
title: 'user_list',
|
title: 'user_list',
|
||||||
i18nKey: 'route.user_list'
|
i18nKey: 'route.user_list'
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'user_transfer',
|
|
||||||
path: '/user/transfer',
|
|
||||||
component: 'view.user_transfer',
|
|
||||||
meta: {
|
|
||||||
title: 'user_transfer',
|
|
||||||
i18nKey: 'route.user_transfer'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ const routeMap: RouteMap = {
|
|||||||
"home": "/home",
|
"home": "/home",
|
||||||
"iframe-page": "/iframe-page/:url",
|
"iframe-page": "/iframe-page/:url",
|
||||||
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?",
|
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?",
|
||||||
|
"notification": "/notification",
|
||||||
"rwa": "/rwa",
|
"rwa": "/rwa",
|
||||||
"rwa_product": "/rwa/product",
|
"rwa_product": "/rwa/product",
|
||||||
"rwa_producttype": "/rwa/producttype",
|
"rwa_producttype": "/rwa/producttype",
|
||||||
@@ -184,7 +185,6 @@ const routeMap: RouteMap = {
|
|||||||
"user": "/user",
|
"user": "/user",
|
||||||
"user_bankcard": "/user/bankcard",
|
"user_bankcard": "/user/bankcard",
|
||||||
"user_list": "/user/list",
|
"user_list": "/user/list",
|
||||||
"user_transfer": "/user/transfer",
|
|
||||||
"withdraw": "/withdraw",
|
"withdraw": "/withdraw",
|
||||||
"withdraw_approved": "/withdraw/approved",
|
"withdraw_approved": "/withdraw/approved",
|
||||||
"withdraw_fiat": "/withdraw/fiat"
|
"withdraw_fiat": "/withdraw/fiat"
|
||||||
|
|||||||
5
src/typings/elegant-router.d.ts
vendored
5
src/typings/elegant-router.d.ts
vendored
@@ -27,6 +27,7 @@ declare module "@elegant-router/types" {
|
|||||||
"home": "/home";
|
"home": "/home";
|
||||||
"iframe-page": "/iframe-page/:url";
|
"iframe-page": "/iframe-page/:url";
|
||||||
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?";
|
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?";
|
||||||
|
"notification": "/notification";
|
||||||
"rwa": "/rwa";
|
"rwa": "/rwa";
|
||||||
"rwa_product": "/rwa/product";
|
"rwa_product": "/rwa/product";
|
||||||
"rwa_producttype": "/rwa/producttype";
|
"rwa_producttype": "/rwa/producttype";
|
||||||
@@ -38,7 +39,6 @@ declare module "@elegant-router/types" {
|
|||||||
"user": "/user";
|
"user": "/user";
|
||||||
"user_bankcard": "/user/bankcard";
|
"user_bankcard": "/user/bankcard";
|
||||||
"user_list": "/user/list";
|
"user_list": "/user/list";
|
||||||
"user_transfer": "/user/transfer";
|
|
||||||
"withdraw": "/withdraw";
|
"withdraw": "/withdraw";
|
||||||
"withdraw_approved": "/withdraw/approved";
|
"withdraw_approved": "/withdraw/approved";
|
||||||
"withdraw_fiat": "/withdraw/fiat";
|
"withdraw_fiat": "/withdraw/fiat";
|
||||||
@@ -82,6 +82,7 @@ declare module "@elegant-router/types" {
|
|||||||
| "home"
|
| "home"
|
||||||
| "iframe-page"
|
| "iframe-page"
|
||||||
| "login"
|
| "login"
|
||||||
|
| "notification"
|
||||||
| "rwa"
|
| "rwa"
|
||||||
| "tokenization"
|
| "tokenization"
|
||||||
| "transfer"
|
| "transfer"
|
||||||
@@ -112,6 +113,7 @@ declare module "@elegant-router/types" {
|
|||||||
| "bank"
|
| "bank"
|
||||||
| "deposit_fiat"
|
| "deposit_fiat"
|
||||||
| "home"
|
| "home"
|
||||||
|
| "notification"
|
||||||
| "rwa_product"
|
| "rwa_product"
|
||||||
| "rwa_producttype"
|
| "rwa_producttype"
|
||||||
| "rwa_subscribe"
|
| "rwa_subscribe"
|
||||||
@@ -120,7 +122,6 @@ declare module "@elegant-router/types" {
|
|||||||
| "transfer"
|
| "transfer"
|
||||||
| "user_bankcard"
|
| "user_bankcard"
|
||||||
| "user_list"
|
| "user_list"
|
||||||
| "user_transfer"
|
|
||||||
| "withdraw_approved"
|
| "withdraw_approved"
|
||||||
| "withdraw_fiat"
|
| "withdraw_fiat"
|
||||||
>;
|
>;
|
||||||
|
|||||||
215
src/views/notification/components/add.vue
Normal file
215
src/views/notification/components/add.vue
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref, useTemplateRef } from 'vue';
|
||||||
|
import type { FormInst, FormRules } from 'naive-ui';
|
||||||
|
import { client, safeClient } from '@/service/api';
|
||||||
|
|
||||||
|
defineOptions({ name: 'AddNotification' });
|
||||||
|
|
||||||
|
type Body = CommonType.TreatyBody<typeof client.api.admin.notifications.post>;
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'close'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const formRef = useTemplateRef<FormInst | null>('formRef');
|
||||||
|
|
||||||
|
const form = ref<Body>({
|
||||||
|
title: '',
|
||||||
|
content: '',
|
||||||
|
category: 'GENERAL',
|
||||||
|
type: 'system',
|
||||||
|
isBroadcast: true,
|
||||||
|
priority: 'normal',
|
||||||
|
userIds: []
|
||||||
|
});
|
||||||
|
|
||||||
|
const categoryOptions = [
|
||||||
|
{ label: '通用', value: 'GENERAL' },
|
||||||
|
{ label: '系统', value: 'SYSTEM' },
|
||||||
|
{ label: '交易', value: 'TRADING' },
|
||||||
|
{ label: '安全', value: 'SECURITY' },
|
||||||
|
{ label: '营销', value: 'MARKETING' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const typeOptions = [
|
||||||
|
{ label: '系统通知', value: 'system' },
|
||||||
|
{ label: '安全通知', value: 'security' },
|
||||||
|
{ label: '交易通知', value: 'transaction' },
|
||||||
|
{ label: '活动通知', value: 'activity' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const priorityOptions = [
|
||||||
|
{ label: '低', value: 'low' },
|
||||||
|
{ label: '普通', value: 'normal' },
|
||||||
|
{ label: '高', value: 'high' },
|
||||||
|
{ label: '紧急', value: 'urgent' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 用户选择相关
|
||||||
|
const { data: users } = safeClient(() =>
|
||||||
|
client.api.admin.users.get({
|
||||||
|
query: {
|
||||||
|
pageIndex: 1,
|
||||||
|
pageSize: 100
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const userOptions = computed(
|
||||||
|
() =>
|
||||||
|
users.value?.data.map(user => ({
|
||||||
|
label: `${user.username} (${user.email})`,
|
||||||
|
value: user.id
|
||||||
|
})) || []
|
||||||
|
);
|
||||||
|
|
||||||
|
const showUserSelect = computed(() => !form.value.isBroadcast);
|
||||||
|
|
||||||
|
const rules: FormRules = {
|
||||||
|
title: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入通知标题',
|
||||||
|
trigger: ['blur', 'input']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
min: 1,
|
||||||
|
max: 200,
|
||||||
|
message: '标题长度应在1-200个字符之间',
|
||||||
|
trigger: ['blur', 'input']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入通知内容',
|
||||||
|
trigger: ['blur', 'input']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
min: 1,
|
||||||
|
message: '内容不能为空',
|
||||||
|
trigger: ['blur', 'input']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
category: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请选择通知分类',
|
||||||
|
trigger: 'change'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
type: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请选择通知类型',
|
||||||
|
trigger: 'change'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
priority: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请选择优先级',
|
||||||
|
trigger: 'change'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
userIds: [
|
||||||
|
{
|
||||||
|
type: 'array',
|
||||||
|
validator: (_rule, value: string[]) => {
|
||||||
|
if (!form.value.isBroadcast && (!value || value.length === 0)) {
|
||||||
|
return new Error('非广播通知必须选择接收用户');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
trigger: 'change'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleBroadcastChange(value: boolean) {
|
||||||
|
if (value) {
|
||||||
|
form.value.userIds = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSubmit() {
|
||||||
|
formRef.value?.validate(async errors => {
|
||||||
|
if (!errors) {
|
||||||
|
const { data } = await safeClient(() =>
|
||||||
|
client.api.admin.notifications.post({
|
||||||
|
...form.value
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if (data) {
|
||||||
|
window.$message?.success('通知创建成功');
|
||||||
|
emit('close');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NForm
|
||||||
|
ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
label-width="100px"
|
||||||
|
label-placement="left"
|
||||||
|
require-mark-placement="left"
|
||||||
|
>
|
||||||
|
<NFormItem label="通知标题" path="title">
|
||||||
|
<NInput v-model:value="form.title" placeholder="请输入通知标题" maxlength="200" show-count />
|
||||||
|
</NFormItem>
|
||||||
|
|
||||||
|
<NFormItem label="通知内容" path="content">
|
||||||
|
<NInput
|
||||||
|
v-model:value="form.content"
|
||||||
|
type="textarea"
|
||||||
|
placeholder="请输入通知内容"
|
||||||
|
:rows="5"
|
||||||
|
maxlength="2000"
|
||||||
|
show-count
|
||||||
|
/>
|
||||||
|
</NFormItem>
|
||||||
|
|
||||||
|
<NGrid :cols="2" :x-gap="16">
|
||||||
|
<NFormItemGi label="通知类型" path="type">
|
||||||
|
<NSelect v-model:value="form.type" :options="typeOptions" placeholder="请选择通知类型" />
|
||||||
|
</NFormItemGi>
|
||||||
|
|
||||||
|
<NFormItemGi label="通知分类" path="category">
|
||||||
|
<NSelect v-model:value="form.category" :options="categoryOptions" placeholder="请选择通知分类" />
|
||||||
|
</NFormItemGi>
|
||||||
|
|
||||||
|
<NFormItemGi label="优先级" path="priority">
|
||||||
|
<NSelect v-model:value="form.priority" :options="priorityOptions" placeholder="请选择优先级" />
|
||||||
|
</NFormItemGi>
|
||||||
|
|
||||||
|
<NFormItemGi label="广播通知" path="isBroadcast">
|
||||||
|
<NSwitch v-model:value="form.isBroadcast" @update:value="handleBroadcastChange">
|
||||||
|
<template #checked>是</template>
|
||||||
|
<template #unchecked>否</template>
|
||||||
|
</NSwitch>
|
||||||
|
</NFormItemGi>
|
||||||
|
</NGrid>
|
||||||
|
|
||||||
|
<NFormItem v-if="showUserSelect" label="接收用户" path="userIds">
|
||||||
|
<NSelect
|
||||||
|
v-model:value="form.userIds"
|
||||||
|
:options="userOptions"
|
||||||
|
placeholder="请选择接收用户"
|
||||||
|
multiple
|
||||||
|
filterable
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</NFormItem>
|
||||||
|
|
||||||
|
<NSpace justify="end" class="mt-4">
|
||||||
|
<NButton @click="$emit('close')">取消</NButton>
|
||||||
|
<NButton type="primary" @click="handleSubmit">创建通知</NButton>
|
||||||
|
</NSpace>
|
||||||
|
</NForm>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="css" scoped></style>
|
||||||
147
src/views/notification/index.vue
Normal file
147
src/views/notification/index.vue
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { h, useTemplateRef } from 'vue';
|
||||||
|
import { useDateFormat } from '@vueuse/core';
|
||||||
|
import { NTag, useDialog } from 'naive-ui';
|
||||||
|
import { client, safeClient } from '@/service/api';
|
||||||
|
import type { TableBaseColumns, TableFetchData, TableInst } from '@/components/table';
|
||||||
|
import Add from './components/add.vue';
|
||||||
|
|
||||||
|
const dialog = useDialog();
|
||||||
|
const tableInst = useTemplateRef<TableInst>('tableInst');
|
||||||
|
|
||||||
|
const fetchData: TableFetchData = ({ pagination, filter }) => {
|
||||||
|
return safeClient(() =>
|
||||||
|
client.api.admin.notifications.get({
|
||||||
|
query: {
|
||||||
|
...pagination,
|
||||||
|
...filter
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const typeMap: Record<string, { label: string; type: 'info' | 'success' | 'warning' | 'error' }> = {
|
||||||
|
system: { label: '系统', type: 'info' },
|
||||||
|
security: { label: '安全', type: 'error' },
|
||||||
|
transaction: { label: '交易', type: 'success' },
|
||||||
|
activity: { label: '活动', type: 'warning' }
|
||||||
|
};
|
||||||
|
|
||||||
|
const categoryMap: Record<string, string> = {
|
||||||
|
GENERAL: '通用',
|
||||||
|
SYSTEM: '系统',
|
||||||
|
TRADING: '交易',
|
||||||
|
SECURITY: '安全',
|
||||||
|
MARKETING: '营销'
|
||||||
|
};
|
||||||
|
|
||||||
|
const priorityMap: Record<string, { label: string; type: 'default' | 'info' | 'success' | 'warning' | 'error' }> = {
|
||||||
|
low: { label: '低', type: 'default' },
|
||||||
|
normal: { label: '普通', type: 'info' },
|
||||||
|
high: { label: '高', type: 'warning' },
|
||||||
|
urgent: { label: '紧急', type: 'error' }
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns: TableBaseColumns = [
|
||||||
|
{
|
||||||
|
key: 'selection',
|
||||||
|
title: '序号',
|
||||||
|
type: 'selection',
|
||||||
|
width: 60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '通知标题',
|
||||||
|
key: 'title',
|
||||||
|
width: 200,
|
||||||
|
ellipsis: { tooltip: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '通知类型',
|
||||||
|
key: 'type',
|
||||||
|
width: 100,
|
||||||
|
render: row => {
|
||||||
|
const type = typeMap[row.type as keyof typeof typeMap];
|
||||||
|
return h(NTag, { type: type?.type || 'default', size: 'small' }, { default: () => type?.label || row.type });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '分类',
|
||||||
|
key: 'category',
|
||||||
|
width: 100,
|
||||||
|
render: (row: any) => {
|
||||||
|
return categoryMap[row.category] || row.category;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '优先级',
|
||||||
|
key: 'priority',
|
||||||
|
width: 100,
|
||||||
|
render: row => {
|
||||||
|
const priority = priorityMap[row.priority as keyof typeof priorityMap];
|
||||||
|
return h(
|
||||||
|
NTag,
|
||||||
|
{ type: priority?.type || 'default', size: 'small' },
|
||||||
|
{ default: () => priority?.label || row.priority }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '广播',
|
||||||
|
key: 'isBroadcast',
|
||||||
|
width: 80,
|
||||||
|
render: row => (row.isBroadcast ? '是' : '否')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '通知内容',
|
||||||
|
key: 'content',
|
||||||
|
ellipsis: { tooltip: true },
|
||||||
|
width: 250
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
key: 'createdAt',
|
||||||
|
width: 180,
|
||||||
|
render: (row: any) => {
|
||||||
|
return useDateFormat(row.createdAt, 'YYYY-MM-DD HH:mm:ss').value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'operations',
|
||||||
|
fixed: 'right',
|
||||||
|
width: 120
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
function handleAdd() {
|
||||||
|
const dialogInstance = dialog.create({
|
||||||
|
title: '创建通知',
|
||||||
|
content: () =>
|
||||||
|
h(Add, {
|
||||||
|
onClose: () => {
|
||||||
|
dialogInstance.destroy();
|
||||||
|
tableInst.value?.reload();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
style: { width: '600px' },
|
||||||
|
showIcon: false,
|
||||||
|
onPositiveClick: () => {
|
||||||
|
window.$message?.success('创建通知成功');
|
||||||
|
tableInst.value?.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<TableBase
|
||||||
|
ref="tableInst"
|
||||||
|
show-header-operation
|
||||||
|
:columns="columns"
|
||||||
|
:fetch-data="fetchData"
|
||||||
|
:scroll-x="1000"
|
||||||
|
@add="handleAdd"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="css" scoped></style>
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { useTemplateRef } from 'vue';
|
|
||||||
import { NDatePicker, useDialog, useMessage } from 'naive-ui';
|
|
||||||
import { client, safeClient } from '@/service/api';
|
|
||||||
import type { TableBaseColumns, TableFetchData, TableInst } from '@/components/table';
|
|
||||||
|
|
||||||
const dialog = useDialog();
|
|
||||||
const message = useMessage();
|
|
||||||
const tableInst = useTemplateRef<TableInst>('tableInst');
|
|
||||||
|
|
||||||
const fetchData: TableFetchData = ({ pagination, filter }) => {
|
|
||||||
return safeClient(() =>
|
|
||||||
client.api.admin.transfer.get({
|
|
||||||
query: {
|
|
||||||
...pagination,
|
|
||||||
...filter
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const columns: TableBaseColumns = [
|
|
||||||
{
|
|
||||||
title: '订单ID',
|
|
||||||
key: 'id'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '订单号',
|
|
||||||
key: 'orderNo'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '转出用户ID',
|
|
||||||
key: 'fromUserId'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '转入用户ID',
|
|
||||||
key: 'toUserId'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '资产代码',
|
|
||||||
key: 'assetCode'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '转账金额',
|
|
||||||
key: 'amount'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '手续费',
|
|
||||||
key: 'fee'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '操作',
|
|
||||||
fixed: 'right',
|
|
||||||
key: 'operation',
|
|
||||||
width: 160,
|
|
||||||
operations: (row: any) => [
|
|
||||||
{
|
|
||||||
contentText: '编辑',
|
|
||||||
type: 'primary',
|
|
||||||
onClick: () => {
|
|
||||||
tableInst.value?.reload();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
contentText: '删除',
|
|
||||||
type: 'error',
|
|
||||||
ghost: true,
|
|
||||||
size: 'small',
|
|
||||||
onClick: async () => {
|
|
||||||
dialog.create({
|
|
||||||
title: '提示',
|
|
||||||
positiveText: '是',
|
|
||||||
negativeText: '否',
|
|
||||||
content: '确认删除该银行信息?',
|
|
||||||
onPositiveClick: async () => {
|
|
||||||
safeClient(() =>
|
|
||||||
client.api.admin.deposit.reject({ orderId: row.id as string }).post({
|
|
||||||
reviewNote: '管理员拒绝充值'
|
|
||||||
})
|
|
||||||
);
|
|
||||||
// tableInst.value?.reload();
|
|
||||||
message.success('删除成功');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const filterColumns: TableFilterColumns = [
|
|
||||||
{
|
|
||||||
title: '资产代码',
|
|
||||||
key: 'assetCode'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '转账金额',
|
|
||||||
key: 'amount',
|
|
||||||
component: NDatePicker
|
|
||||||
}
|
|
||||||
];
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<TableBase ref="tableInst" :columns="columns" :filter-columns="filterColumns" :fetch-data="fetchData" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="css" scoped></style>
|
|
||||||
Reference in New Issue
Block a user