重构消息通知弹窗
This commit is contained in:
parent
1af85b2940
commit
1a5786502a
@ -75,12 +75,11 @@ const DeploymentFormModal: React.FC<DeploymentFormModalProps> = ({
|
|||||||
// 通知信息(使用环境配置的通知设置)
|
// 通知信息(使用环境配置的通知设置)
|
||||||
notification: {
|
notification: {
|
||||||
notificationChannelId: environment.notificationConfig?.notificationChannelId,
|
notificationChannelId: environment.notificationConfig?.notificationChannelId,
|
||||||
deployNotificationEnabled: environment.notificationConfig?.deployNotificationEnabled,
|
preApprovalNotificationEnabled: environment.notificationConfig?.preApprovalNotificationEnabled,
|
||||||
deployNotificationTemplateId: environment.notificationConfig?.deployNotificationTemplateId,
|
preApprovalNotificationTemplateId: environment.notificationConfig?.preApprovalNotificationTemplateId,
|
||||||
buildNotificationEnabled: environment.notificationConfig?.buildNotificationEnabled,
|
buildNotificationEnabled: environment.notificationConfig?.buildNotificationEnabled,
|
||||||
buildNotificationTemplateId: environment.notificationConfig?.buildNotificationTemplateId,
|
buildNotificationTemplateId: environment.notificationConfig?.buildNotificationTemplateId,
|
||||||
buildFailureFileEnabled: environment.notificationConfig?.buildFailureFileEnabled,
|
buildFailureFileEnabled: environment.notificationConfig?.buildFailureFileEnabled,
|
||||||
buildFailureNotificationTemplateId: environment.notificationConfig?.buildFailureNotificationTemplateId,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}, [app, environment, teamId, currentUser]); // 只在这些依赖变化时重新生成
|
}, [app, environment, teamId, currentUser]); // 只在这些依赖变化时重新生成
|
||||||
|
|||||||
@ -60,12 +60,11 @@ export interface ApplicationConfig {
|
|||||||
|
|
||||||
export interface NotificationConfig {
|
export interface NotificationConfig {
|
||||||
notificationChannelId: number;
|
notificationChannelId: number;
|
||||||
deployNotificationEnabled: boolean;
|
preApprovalNotificationEnabled: boolean;
|
||||||
deployNotificationTemplateId: number;
|
preApprovalNotificationTemplateId: number;
|
||||||
buildNotificationEnabled: boolean;
|
buildNotificationEnabled: boolean;
|
||||||
buildNotificationTemplateId: number;
|
buildNotificationTemplateId: number;
|
||||||
buildFailureFileEnabled: boolean;
|
buildFailureFileEnabled: boolean;
|
||||||
buildFailureNotificationTemplateId: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DeployEnvironment {
|
export interface DeployEnvironment {
|
||||||
|
|||||||
@ -292,15 +292,15 @@ const ApplicationManageDialog: React.FC<ApplicationManageDialogProps> = ({
|
|||||||
|
|
||||||
{/* 表格 */}
|
{/* 表格 */}
|
||||||
<div className="border rounded-lg overflow-hidden">
|
<div className="border rounded-lg overflow-hidden">
|
||||||
<div className="max-h-[50vh] overflow-y-auto">
|
<div className="max-h-[50vh] overflow-auto">
|
||||||
<Table minWidth="690px">
|
<Table minWidth="750px">
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead width="100px">应用ID</TableHead>
|
<TableHead width="80px" className="whitespace-nowrap">应用ID</TableHead>
|
||||||
<TableHead width="150px">应用编码</TableHead>
|
<TableHead width="160px" className="whitespace-nowrap">应用编码</TableHead>
|
||||||
<TableHead width="200px">应用名称</TableHead>
|
<TableHead width="200px" className="whitespace-nowrap">应用名称</TableHead>
|
||||||
<TableHead width="160px">创建时间</TableHead>
|
<TableHead width="180px" className="whitespace-nowrap">创建时间</TableHead>
|
||||||
<TableHead width="80px" sticky>操作</TableHead>
|
<TableHead width="80px" sticky className="whitespace-nowrap">操作</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
@ -316,20 +316,20 @@ const ApplicationManageDialog: React.FC<ApplicationManageDialogProps> = ({
|
|||||||
) : data?.content && data.content.length > 0 ? (
|
) : data?.content && data.content.length > 0 ? (
|
||||||
data.content.map((record) => (
|
data.content.map((record) => (
|
||||||
<TableRow key={record.id}>
|
<TableRow key={record.id}>
|
||||||
<TableCell width="100px" className="font-medium">
|
<TableCell width="80px" className="font-medium whitespace-nowrap">
|
||||||
{record.applicationId}
|
{record.applicationId}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell width="150px">
|
<TableCell width="160px" className="whitespace-nowrap">
|
||||||
{record.applicationCode || '-'}
|
{record.applicationCode || '-'}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell width="200px">
|
<TableCell width="200px" className="whitespace-nowrap">
|
||||||
{record.applicationName || '-'}
|
{record.applicationName || '-'}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell width="160px">
|
<TableCell width="180px" className="whitespace-nowrap">
|
||||||
{record.createTime || '-'}
|
{record.createTime || '-'}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell width="80px" sticky>
|
<TableCell width="80px" sticky>
|
||||||
<div className="flex items-center justify-end gap-1">
|
<div className="flex items-center justify-end">
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|||||||
@ -37,10 +37,10 @@ const getChannelIcon = (channelType?: string) => {
|
|||||||
// 通知类型配置
|
// 通知类型配置
|
||||||
const notificationTypes = [
|
const notificationTypes = [
|
||||||
{
|
{
|
||||||
key: 'deployNotificationEnabled',
|
key: 'preApprovalNotificationEnabled',
|
||||||
label: '部署',
|
label: '审批前',
|
||||||
variant: 'success' as const,
|
variant: 'success' as const,
|
||||||
description: '部署状态变更时发送通知'
|
description: '提交部署申请进入审批时发送通知'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'buildNotificationEnabled',
|
key: 'buildNotificationEnabled',
|
||||||
@ -50,9 +50,9 @@ const notificationTypes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'buildFailureFileEnabled',
|
key: 'buildFailureFileEnabled',
|
||||||
label: '失败文件',
|
label: '失败日志',
|
||||||
variant: 'destructive' as const,
|
variant: 'destructive' as const,
|
||||||
description: '构建失败文件时发送通知'
|
description: '构建失败时发送日志文件'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -71,11 +71,9 @@ export const NotificationChannelCell: React.FC<NotificationChannelCellProps> = (
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
notificationChannelName,
|
notificationChannelName,
|
||||||
deployNotificationEnabled,
|
preApprovalNotificationEnabled,
|
||||||
buildNotificationEnabled,
|
buildNotificationEnabled,
|
||||||
buildFailureFileEnabled,
|
buildFailureFileEnabled,
|
||||||
updateTime,
|
|
||||||
updateBy
|
|
||||||
} = notificationConfig;
|
} = notificationConfig;
|
||||||
|
|
||||||
// 计算启用的通知类型
|
// 计算启用的通知类型
|
||||||
|
|||||||
@ -44,12 +44,11 @@ const formSchema = z
|
|||||||
.object({
|
.object({
|
||||||
id: z.number().optional(),
|
id: z.number().optional(),
|
||||||
notificationChannelId: z.number().nullish(),
|
notificationChannelId: z.number().nullish(),
|
||||||
deployNotificationEnabled: z.boolean().default(false),
|
preApprovalNotificationEnabled: z.boolean().default(false),
|
||||||
deployNotificationTemplateId: z.number().nullish(),
|
preApprovalNotificationTemplateId: z.number().nullish(),
|
||||||
buildNotificationEnabled: z.boolean().default(false),
|
buildNotificationEnabled: z.boolean().default(false),
|
||||||
buildNotificationTemplateId: z.number().nullish(),
|
buildNotificationTemplateId: z.number().nullish(),
|
||||||
buildFailureFileEnabled: z.boolean().default(false),
|
buildFailureFileEnabled: z.boolean().default(false),
|
||||||
buildFailureNotificationTemplateId: z.number().nullish(),
|
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
})
|
})
|
||||||
@ -57,7 +56,7 @@ const formSchema = z
|
|||||||
(data) => {
|
(data) => {
|
||||||
// 如果启用了任意通知类型,则通知渠道必填
|
// 如果启用了任意通知类型,则通知渠道必填
|
||||||
if (
|
if (
|
||||||
(data.notificationConfig?.deployNotificationEnabled ||
|
(data.notificationConfig?.preApprovalNotificationEnabled ||
|
||||||
data.notificationConfig?.buildNotificationEnabled ||
|
data.notificationConfig?.buildNotificationEnabled ||
|
||||||
data.notificationConfig?.buildFailureFileEnabled) &&
|
data.notificationConfig?.buildFailureFileEnabled) &&
|
||||||
!data.notificationConfig?.notificationChannelId
|
!data.notificationConfig?.notificationChannelId
|
||||||
@ -104,7 +103,7 @@ export const NotificationConfigDialog: React.FC<
|
|||||||
const [submitting, setSubmitting] = useState(false);
|
const [submitting, setSubmitting] = useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [configId, setConfigId] = useState<number | null>(null);
|
const [configId, setConfigId] = useState<number | null>(null);
|
||||||
const [currentConfig, setCurrentConfig] = useState<any>(null); // 存储完整的环境配置
|
const [currentConfig, setCurrentConfig] = useState<any>(null);
|
||||||
const [notificationChannels, setNotificationChannels] = useState<
|
const [notificationChannels, setNotificationChannels] = useState<
|
||||||
NotificationChannel[]
|
NotificationChannel[]
|
||||||
>([]);
|
>([]);
|
||||||
@ -119,12 +118,11 @@ export const NotificationConfigDialog: React.FC<
|
|||||||
defaultValues: {
|
defaultValues: {
|
||||||
notificationConfig: {
|
notificationConfig: {
|
||||||
notificationChannelId: undefined,
|
notificationChannelId: undefined,
|
||||||
deployNotificationEnabled: false,
|
preApprovalNotificationEnabled: false,
|
||||||
deployNotificationTemplateId: undefined,
|
preApprovalNotificationTemplateId: undefined,
|
||||||
buildNotificationEnabled: false,
|
buildNotificationEnabled: false,
|
||||||
buildNotificationTemplateId: undefined,
|
buildNotificationTemplateId: undefined,
|
||||||
buildFailureFileEnabled: false,
|
buildFailureFileEnabled: false,
|
||||||
buildFailureNotificationTemplateId: undefined,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -171,22 +169,20 @@ export const NotificationConfigDialog: React.FC<
|
|||||||
|
|
||||||
if (config) {
|
if (config) {
|
||||||
setConfigId(config.id);
|
setConfigId(config.id);
|
||||||
setCurrentConfig(config); // 保存完整配置
|
setCurrentConfig(config);
|
||||||
form.reset({
|
form.reset({
|
||||||
notificationConfig: config.notificationConfig || {
|
notificationConfig: config.notificationConfig || {
|
||||||
notificationChannelId: undefined,
|
notificationChannelId: undefined,
|
||||||
deployNotificationEnabled: false,
|
preApprovalNotificationEnabled: false,
|
||||||
deployNotificationTemplateId: undefined,
|
preApprovalNotificationTemplateId: undefined,
|
||||||
buildNotificationEnabled: false,
|
buildNotificationEnabled: false,
|
||||||
buildNotificationTemplateId: undefined,
|
buildNotificationTemplateId: undefined,
|
||||||
buildFailureFileEnabled: false,
|
buildFailureFileEnabled: false,
|
||||||
buildFailureNotificationTemplateId: undefined,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (error.response?.status === 404) {
|
if (error.response?.status === 404) {
|
||||||
// 配置不存在
|
|
||||||
toast({
|
toast({
|
||||||
title: '提示',
|
title: '提示',
|
||||||
description: '请先配置该环境的基本信息',
|
description: '请先配置该环境的基本信息',
|
||||||
@ -205,7 +201,6 @@ export const NotificationConfigDialog: React.FC<
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 对话框打开时初始化
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) {
|
if (open) {
|
||||||
loadNotificationChannels();
|
loadNotificationChannels();
|
||||||
@ -213,7 +208,6 @@ export const NotificationConfigDialog: React.FC<
|
|||||||
}
|
}
|
||||||
}, [open, teamId, environmentId]);
|
}, [open, teamId, environmentId]);
|
||||||
|
|
||||||
// 监听通知渠道变化,重新加载模板列表
|
|
||||||
const selectedChannelId = form.watch('notificationConfig.notificationChannelId');
|
const selectedChannelId = form.watch('notificationConfig.notificationChannelId');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -226,9 +220,6 @@ export const NotificationConfigDialog: React.FC<
|
|||||||
}, [selectedChannelId, notificationChannels, open]);
|
}, [selectedChannelId, notificationChannels, open]);
|
||||||
|
|
||||||
const handleSubmit = async (data: FormData) => {
|
const handleSubmit = async (data: FormData) => {
|
||||||
console.log('表单提交数据:', data);
|
|
||||||
console.log('当前配置:', currentConfig);
|
|
||||||
|
|
||||||
if (!configId || !currentConfig) {
|
if (!configId || !currentConfig) {
|
||||||
toast({
|
toast({
|
||||||
title: '错误',
|
title: '错误',
|
||||||
@ -240,22 +231,19 @@ export const NotificationConfigDialog: React.FC<
|
|||||||
|
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
try {
|
try {
|
||||||
// 构建通知配置对象
|
|
||||||
let notificationConfig = undefined;
|
let notificationConfig = undefined;
|
||||||
if (data.notificationConfig?.notificationChannelId) {
|
if (data.notificationConfig?.notificationChannelId) {
|
||||||
notificationConfig = {
|
notificationConfig = {
|
||||||
id: data.notificationConfig.id,
|
id: data.notificationConfig.id,
|
||||||
notificationChannelId: data.notificationConfig.notificationChannelId,
|
notificationChannelId: data.notificationConfig.notificationChannelId,
|
||||||
deployNotificationEnabled: data.notificationConfig.deployNotificationEnabled ?? false,
|
preApprovalNotificationEnabled: data.notificationConfig.preApprovalNotificationEnabled ?? false,
|
||||||
deployNotificationTemplateId: data.notificationConfig.deployNotificationTemplateId ?? undefined,
|
preApprovalNotificationTemplateId: data.notificationConfig.preApprovalNotificationTemplateId ?? undefined,
|
||||||
buildNotificationEnabled: data.notificationConfig.buildNotificationEnabled ?? false,
|
buildNotificationEnabled: data.notificationConfig.buildNotificationEnabled ?? false,
|
||||||
buildNotificationTemplateId: data.notificationConfig.buildNotificationTemplateId ?? undefined,
|
buildNotificationTemplateId: data.notificationConfig.buildNotificationTemplateId ?? undefined,
|
||||||
buildFailureFileEnabled: data.notificationConfig.buildFailureFileEnabled ?? false,
|
buildFailureFileEnabled: data.notificationConfig.buildFailureFileEnabled ?? false,
|
||||||
buildFailureNotificationTemplateId: data.notificationConfig.buildFailureNotificationTemplateId ?? undefined,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建完整的提交数据(保留原有配置,只更新通知部分)
|
|
||||||
const payload = {
|
const payload = {
|
||||||
teamId: currentConfig.teamId,
|
teamId: currentConfig.teamId,
|
||||||
environmentId: currentConfig.environmentId,
|
environmentId: currentConfig.environmentId,
|
||||||
@ -266,8 +254,6 @@ export const NotificationConfigDialog: React.FC<
|
|||||||
notificationConfig,
|
notificationConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('最终提交的 payload:', payload);
|
|
||||||
|
|
||||||
await updateTeamEnvironmentConfig(configId, payload);
|
await updateTeamEnvironmentConfig(configId, payload);
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
@ -308,7 +294,7 @@ export const NotificationConfigDialog: React.FC<
|
|||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form onSubmit={form.handleSubmit(handleSubmit)}>
|
<form onSubmit={form.handleSubmit(handleSubmit)}>
|
||||||
<DialogBody className="space-y-4">
|
<DialogBody className="space-y-4">
|
||||||
{/* 通知渠道选择 - 始终显示 */}
|
{/* 通知渠道选择 */}
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="notificationConfig.notificationChannelId"
|
name="notificationConfig.notificationChannelId"
|
||||||
@ -326,25 +312,16 @@ export const NotificationConfigDialog: React.FC<
|
|||||||
<SelectTrigger
|
<SelectTrigger
|
||||||
clearable
|
clearable
|
||||||
hasValue={!!field.value}
|
hasValue={!!field.value}
|
||||||
onClear={() => {
|
onClear={() => field.onChange(null)}
|
||||||
field.onChange(null);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<SelectValue
|
<SelectValue
|
||||||
placeholder={
|
placeholder={loadingChannels ? '加载中...' : '请选择通知渠道'}
|
||||||
loadingChannels
|
|
||||||
? '加载中...'
|
|
||||||
: '请选择通知渠道'
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{notificationChannels.map((channel) => (
|
{notificationChannels.map((channel) => (
|
||||||
<SelectItem
|
<SelectItem key={channel.id} value={channel.id.toString()}>
|
||||||
key={channel.id}
|
|
||||||
value={channel.id.toString()}
|
|
||||||
>
|
|
||||||
{channel.name} ({channel.channelType})
|
{channel.name} ({channel.channelType})
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
@ -358,65 +335,40 @@ export const NotificationConfigDialog: React.FC<
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 部署通知 */}
|
{/* 审批前提醒 */}
|
||||||
<div className="rounded-lg border p-4 space-y-2">
|
<div className="rounded-lg border p-4 space-y-2">
|
||||||
<div className="grid grid-cols-[1fr_auto_1fr] gap-4 items-center">
|
<div className="grid grid-cols-[1fr_auto_1fr] gap-4 items-center">
|
||||||
{/* 左侧:通知类型标题 */}
|
|
||||||
<div>
|
<div>
|
||||||
<FormLabel className="text-base">部署通知</FormLabel>
|
<FormLabel className="text-base">审批前提醒</FormLabel>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 中间:开关 */}
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="notificationConfig.deployNotificationEnabled"
|
name="notificationConfig.preApprovalNotificationEnabled"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="mb-0">
|
<FormItem className="mb-0">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Switch
|
<Switch checked={field.value} onCheckedChange={field.onChange} />
|
||||||
checked={field.value}
|
|
||||||
onCheckedChange={field.onChange}
|
|
||||||
/>
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 右侧:模板选择 */}
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="notificationConfig.deployNotificationTemplateId"
|
name="notificationConfig.preApprovalNotificationTemplateId"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="mb-0">
|
<FormItem className="mb-0">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<ClearableSelect
|
<ClearableSelect
|
||||||
value={field.value?.toString()}
|
value={field.value?.toString()}
|
||||||
onValueChange={(value) =>
|
onValueChange={(value) => field.onChange(value ? Number(value) : null)}
|
||||||
field.onChange(value ? Number(value) : null)
|
|
||||||
}
|
|
||||||
disabled={loadingTemplates}
|
disabled={loadingTemplates}
|
||||||
>
|
>
|
||||||
<SelectTrigger
|
<SelectTrigger clearable hasValue={!!field.value} onClear={() => field.onChange(null)}>
|
||||||
clearable
|
<SelectValue placeholder={loadingTemplates ? '加载中...' : '请选择通知模板(可选)'} />
|
||||||
hasValue={!!field.value}
|
|
||||||
onClear={() => {
|
|
||||||
field.onChange(null);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SelectValue
|
|
||||||
placeholder={
|
|
||||||
loadingTemplates
|
|
||||||
? '加载中...'
|
|
||||||
: '请选择通知模板(可选)'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{notificationTemplates.map((template) => (
|
{notificationTemplates.map((template) => (
|
||||||
<SelectItem
|
<SelectItem key={template.id} value={template.id.toString()}>
|
||||||
key={template.id}
|
|
||||||
value={template.id.toString()}
|
|
||||||
>
|
|
||||||
{template.name}
|
{template.name}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
@ -428,43 +380,30 @@ export const NotificationConfigDialog: React.FC<
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/* 描述文字行 */}
|
|
||||||
<div className="grid grid-cols-[1fr_auto_1fr] gap-4">
|
<div className="grid grid-cols-[1fr_auto_1fr] gap-4">
|
||||||
<div className="text-sm text-muted-foreground">
|
<div className="text-sm text-muted-foreground">提交部署申请进入审批时发送通知</div>
|
||||||
部署状态变更时发送通知
|
|
||||||
</div>
|
|
||||||
<div></div>
|
<div></div>
|
||||||
<div className="text-sm text-muted-foreground">
|
<div className="text-sm text-muted-foreground">审批前提醒模板</div>
|
||||||
部署通知模板
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 构建通知 */}
|
{/* 构建通知 */}
|
||||||
<div className="rounded-lg border p-4 space-y-2">
|
<div className="rounded-lg border p-4 space-y-2">
|
||||||
<div className="grid grid-cols-[1fr_auto_1fr] gap-4 items-center">
|
<div className="grid grid-cols-[1fr_auto_1fr] gap-4 items-center">
|
||||||
{/* 左侧:通知类型标题 */}
|
|
||||||
<div>
|
<div>
|
||||||
<FormLabel className="text-base">构建通知</FormLabel>
|
<FormLabel className="text-base">构建通知</FormLabel>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 中间:开关 */}
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="notificationConfig.buildNotificationEnabled"
|
name="notificationConfig.buildNotificationEnabled"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="mb-0">
|
<FormItem className="mb-0">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Switch
|
<Switch checked={field.value} onCheckedChange={field.onChange} />
|
||||||
checked={field.value}
|
|
||||||
onCheckedChange={field.onChange}
|
|
||||||
/>
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 右侧:模板选择 */}
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="notificationConfig.buildNotificationTemplateId"
|
name="notificationConfig.buildNotificationTemplateId"
|
||||||
@ -473,32 +412,15 @@ export const NotificationConfigDialog: React.FC<
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<ClearableSelect
|
<ClearableSelect
|
||||||
value={field.value?.toString()}
|
value={field.value?.toString()}
|
||||||
onValueChange={(value) =>
|
onValueChange={(value) => field.onChange(value ? Number(value) : null)}
|
||||||
field.onChange(value ? Number(value) : null)
|
|
||||||
}
|
|
||||||
disabled={loadingTemplates}
|
disabled={loadingTemplates}
|
||||||
>
|
>
|
||||||
<SelectTrigger
|
<SelectTrigger clearable hasValue={!!field.value} onClear={() => field.onChange(null)}>
|
||||||
clearable
|
<SelectValue placeholder={loadingTemplates ? '加载中...' : '请选择通知模板(可选)'} />
|
||||||
hasValue={!!field.value}
|
|
||||||
onClear={() => {
|
|
||||||
field.onChange(null);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SelectValue
|
|
||||||
placeholder={
|
|
||||||
loadingTemplates
|
|
||||||
? '加载中...'
|
|
||||||
: '请选择通知模板(可选)'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{notificationTemplates.map((template) => (
|
{notificationTemplates.map((template) => (
|
||||||
<SelectItem
|
<SelectItem key={template.id} value={template.id.toString()}>
|
||||||
key={template.id}
|
|
||||||
value={template.id.toString()}
|
|
||||||
>
|
|
||||||
{template.name}
|
{template.name}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
@ -510,114 +432,46 @@ export const NotificationConfigDialog: React.FC<
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/* 描述文字行 */}
|
|
||||||
<div className="grid grid-cols-[1fr_auto_1fr] gap-4">
|
<div className="grid grid-cols-[1fr_auto_1fr] gap-4">
|
||||||
<div className="text-sm text-muted-foreground">
|
<div className="text-sm text-muted-foreground">构建状态变更时发送通知</div>
|
||||||
构建状态变更时发送通知
|
|
||||||
</div>
|
|
||||||
<div></div>
|
<div></div>
|
||||||
<div className="text-sm text-muted-foreground">
|
<div className="text-sm text-muted-foreground">构建通知模板</div>
|
||||||
构建通知模板
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 失败日志 */}
|
{/* 失败日志 */}
|
||||||
<div className="rounded-lg border p-4 space-y-2">
|
<div className="rounded-lg border p-4 space-y-2">
|
||||||
<div className="grid grid-cols-[1fr_auto_1fr] gap-4 items-center">
|
<div className="grid grid-cols-[1fr_auto_1fr] gap-4 items-center">
|
||||||
{/* 左侧:通知类型标题 */}
|
|
||||||
<div>
|
<div>
|
||||||
<FormLabel className="text-base">失败日志</FormLabel>
|
<FormLabel className="text-base">失败日志</FormLabel>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 中间:开关 */}
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="notificationConfig.buildFailureFileEnabled"
|
name="notificationConfig.buildFailureFileEnabled"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="mb-0">
|
<FormItem className="mb-0">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Switch
|
<Switch checked={field.value} onCheckedChange={field.onChange} />
|
||||||
checked={field.value}
|
|
||||||
onCheckedChange={field.onChange}
|
|
||||||
/>
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 右侧:模板选择 */}
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="notificationConfig.buildFailureNotificationTemplateId"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="mb-0">
|
|
||||||
<FormControl>
|
|
||||||
<ClearableSelect
|
|
||||||
value={field.value?.toString()}
|
|
||||||
onValueChange={(value) =>
|
|
||||||
field.onChange(value ? Number(value) : null)
|
|
||||||
}
|
|
||||||
disabled={loadingTemplates}
|
|
||||||
>
|
|
||||||
<SelectTrigger
|
|
||||||
clearable
|
|
||||||
hasValue={!!field.value}
|
|
||||||
onClear={() => {
|
|
||||||
field.onChange(null);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SelectValue
|
|
||||||
placeholder={
|
|
||||||
loadingTemplates
|
|
||||||
? '加载中...'
|
|
||||||
: '请选择通知模板(可选)'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
{notificationTemplates.map((template) => (
|
|
||||||
<SelectItem
|
|
||||||
key={template.id}
|
|
||||||
value={template.id.toString()}
|
|
||||||
>
|
|
||||||
{template.name}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</ClearableSelect>
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/* 描述文字行 */}
|
|
||||||
<div className="grid grid-cols-[1fr_auto_1fr] gap-4">
|
|
||||||
<div className="text-sm text-muted-foreground">
|
|
||||||
构建失败时是否发送日志
|
|
||||||
</div>
|
|
||||||
<div></div>
|
<div></div>
|
||||||
<div className="text-sm text-muted-foreground">
|
|
||||||
失败日志通知模板
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="grid grid-cols-[1fr_auto_1fr] gap-4">
|
||||||
|
<div className="text-sm text-muted-foreground">构建失败时是否发送日志文件</div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</DialogBody>
|
</DialogBody>
|
||||||
|
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button
|
<Button type="button" variant="outline" onClick={() => onOpenChange(false)} disabled={submitting}>
|
||||||
type="button"
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => onOpenChange(false)}
|
|
||||||
disabled={submitting}
|
|
||||||
>
|
|
||||||
取消
|
取消
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" disabled={submitting}>
|
<Button type="submit" disabled={submitting}>
|
||||||
{submitting && (
|
{submitting && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
||||||
)}
|
|
||||||
保存
|
保存
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|||||||
@ -53,12 +53,11 @@ export interface NotificationConfig {
|
|||||||
teamId?: number;
|
teamId?: number;
|
||||||
environmentId?: number;
|
environmentId?: number;
|
||||||
notificationChannelId?: number;
|
notificationChannelId?: number;
|
||||||
deployNotificationEnabled?: boolean;
|
preApprovalNotificationEnabled?: boolean;
|
||||||
deployNotificationTemplateId?: number;
|
preApprovalNotificationTemplateId?: number;
|
||||||
buildNotificationEnabled?: boolean;
|
buildNotificationEnabled?: boolean;
|
||||||
buildNotificationTemplateId?: number;
|
buildNotificationTemplateId?: number;
|
||||||
buildFailureFileEnabled?: boolean;
|
buildFailureFileEnabled?: boolean;
|
||||||
buildFailureNotificationTemplateId?: number;
|
|
||||||
notificationChannelName?: string; // 关联数据
|
notificationChannelName?: string; // 关联数据
|
||||||
channelType?: string; // 渠道类型:WEWORK, EMAIL, DINGTALK等
|
channelType?: string; // 渠道类型:WEWORK, EMAIL, DINGTALK等
|
||||||
updateTime?: string; // 更新时间
|
updateTime?: string; // 更新时间
|
||||||
@ -96,12 +95,11 @@ export interface TeamEnvironmentConfigRequest {
|
|||||||
notificationConfig?: {
|
notificationConfig?: {
|
||||||
id?: number;
|
id?: number;
|
||||||
notificationChannelId?: number;
|
notificationChannelId?: number;
|
||||||
deployNotificationEnabled?: boolean;
|
preApprovalNotificationEnabled?: boolean;
|
||||||
deployNotificationTemplateId?: number;
|
preApprovalNotificationTemplateId?: number;
|
||||||
buildNotificationEnabled?: boolean;
|
buildNotificationEnabled?: boolean;
|
||||||
buildNotificationTemplateId?: number;
|
buildNotificationTemplateId?: number;
|
||||||
buildFailureFileEnabled?: boolean;
|
buildFailureFileEnabled?: boolean;
|
||||||
buildFailureNotificationTemplateId?: number;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -210,19 +210,19 @@ const OnlineUserList: React.FC = () => {
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="rounded-md border">
|
<div className="rounded-md border">
|
||||||
<Table>
|
<Table minWidth="1400px">
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead className="w-[120px]">用户名</TableHead>
|
<TableHead width="100px">用户名</TableHead>
|
||||||
<TableHead className="w-[120px]">昵称</TableHead>
|
<TableHead width="100px">昵称</TableHead>
|
||||||
<TableHead className="w-[150px]">部门</TableHead>
|
<TableHead width="120px">部门</TableHead>
|
||||||
<TableHead className="w-[180px]">登录时间</TableHead>
|
<TableHead width="160px">登录时间</TableHead>
|
||||||
<TableHead className="w-[120px]">在线时长</TableHead>
|
<TableHead width="100px">在线时长</TableHead>
|
||||||
<TableHead className="w-[180px]">最后活跃</TableHead>
|
<TableHead width="160px">最后活跃</TableHead>
|
||||||
<TableHead className="w-[140px]">IP地址</TableHead>
|
<TableHead width="130px">IP地址</TableHead>
|
||||||
<TableHead className="w-[120px]">浏览器</TableHead>
|
<TableHead width="110px">浏览器</TableHead>
|
||||||
<TableHead className="w-[120px]">操作系统</TableHead>
|
<TableHead width="120px">操作系统</TableHead>
|
||||||
<TableHead className="w-[100px] text-right">操作</TableHead>
|
<TableHead width="120px" sticky>操作</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
@ -235,16 +235,17 @@ const OnlineUserList: React.FC = () => {
|
|||||||
) : data?.content && data.content.length > 0 ? (
|
) : data?.content && data.content.length > 0 ? (
|
||||||
data.content.map((user) => (
|
data.content.map((user) => (
|
||||||
<TableRow key={user.userId}>
|
<TableRow key={user.userId}>
|
||||||
<TableCell className="font-medium">{user.username}</TableCell>
|
<TableCell width="100px" className="font-medium">{user.username}</TableCell>
|
||||||
<TableCell>{user.nickname}</TableCell>
|
<TableCell width="100px">{user.nickname}</TableCell>
|
||||||
<TableCell>{user.departmentName || '-'}</TableCell>
|
<TableCell width="120px">{user.departmentName || '-'}</TableCell>
|
||||||
<TableCell>{formatTime(user.loginTime)}</TableCell>
|
<TableCell width="160px">{formatTime(user.loginTime)}</TableCell>
|
||||||
<TableCell>{formatDuration(user.onlineDuration)}</TableCell>
|
<TableCell width="100px">{formatDuration(user.onlineDuration)}</TableCell>
|
||||||
<TableCell>{formatTime(user.lastActiveTime)}</TableCell>
|
<TableCell width="160px">{formatTime(user.lastActiveTime)}</TableCell>
|
||||||
<TableCell>{user.ipAddress || '-'}</TableCell>
|
<TableCell width="130px">{user.ipAddress || '-'}</TableCell>
|
||||||
<TableCell>{user.browser || '-'}</TableCell>
|
<TableCell width="110px">{user.browser || '-'}</TableCell>
|
||||||
<TableCell>{user.os || '-'}</TableCell>
|
<TableCell width="120px">{user.os || '-'}</TableCell>
|
||||||
<TableCell className="text-right">
|
<TableCell width="120px" sticky>
|
||||||
|
<div className="flex justify-end">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@ -255,6 +256,7 @@ const OnlineUserList: React.FC = () => {
|
|||||||
<LogOut className="h-4 w-4 mr-1" />
|
<LogOut className="h-4 w-4 mr-1" />
|
||||||
强制下线
|
强制下线
|
||||||
</Button>
|
</Button>
|
||||||
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))
|
))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user