Przeglądaj źródła

修复邮件提醒与邮件相关错误

pm 2 miesięcy temu
rodzic
commit
6c30ce59ac

+ 10 - 6
src/api/emailTemplate/index.ts

@@ -65,20 +65,23 @@ export const emailTemplateApi = {
     return { list: [], total: 0 };
   },
 
-  // 查询邮件模版详情
+  // 查询邮件模版详情(兼容 { code, data } 与直接返回 data 两种格式)
   getMailTemplate: async (id: number): Promise<MailTemplateVO> => {
-    const response = await request.get({
-      url: `/system/mail-template/get?id=${id}`,
+    const response: any = await request.get({
+      url: '/system/mail-template/get',
+      params: { id },
     });
-    return response?.data || response;
+    const raw = response?.data ?? response;
+    return raw?.data ?? raw;
   },
 
-  // 新增邮件模版
+  // 新增邮件模版(不返回响应体,避免被误当作成功提示展示)
   createMailTemplate: async (data: MailTemplateVO): Promise<void> => {
     await request.post({
       url: '/system/mail-template/create',
       data,
     });
+    return;
   },
 
   // 修改邮件模版
@@ -92,7 +95,8 @@ export const emailTemplateApi = {
   // 删除邮件模版
   deleteMailTemplate: async (id: number): Promise<void> => {
     await request.delete({
-      url: `/system/mail-template/delete?id=${id}`,
+      url: '/system/mail-template/delete',
+      params: { id },
     });
   },
 

+ 10 - 6
src/api/mailNotifyConfig/index.ts

@@ -2,6 +2,7 @@ import { request } from '../../utils/axios';
 
 // 邮件提醒周期配置 VO 类型
 export interface MailNotifyConfigVO {
+  id?: number;
   configId?: number;
   configName?: string;
   configCode?: string;
@@ -61,21 +62,23 @@ export const mailNotifyConfigApi = {
     return { list: [], total: 0 };
   },
 
-  // 获取系统邮件提醒周期配置详细信息
+  // 获取系统邮件提醒周期配置详细信息(GET /admin-api/iscs/mail-notify-config/selectMailNotifyConfigById?id=4,兼容 { code, data } 与直接 data)
   getIsMailNotifyConfigById: async (id: number): Promise<MailNotifyConfigVO> => {
-    const response = await request.get({
+    const response: any = await request.get({
       url: '/iscs/mail-notify-config/selectMailNotifyConfigById',
       params: { id },
     });
-    return response?.data || response;
+    const raw = response?.data ?? response;
+    return raw?.data ?? raw;
   },
 
-  // 新增系统邮件提醒周期配置
+  // 新增系统邮件提醒周期配置(不返回响应体,避免被误当作成功提示内容展示)
   addIsMailNotifyConfig: async (data: MailNotifyConfigVO): Promise<void> => {
     await request.post({
       url: '/iscs/mail-notify-config/insertMailNotifyConfig',
       data,
     });
+    return;
   },
 
   // 修改系统邮件提醒周期配置
@@ -86,11 +89,12 @@ export const mailNotifyConfigApi = {
     });
   },
 
-  // 删除系统邮件提醒周期配置
+  // 删除系统邮件提醒周期配置(DELETE /admin-api/iscs/mail-notify-config/deleteMailNotifyConfigList?ids=7)
   deleteIsMailNotifyConfig: async (ids: number | number[]): Promise<void> => {
     const idStr = Array.isArray(ids) ? ids.join(',') : String(ids);
     await request.delete({
-      url: `/iscs/mail-notify-config/deleteMailNotifyConfigList?ids=${idStr}`,
+      url: '/iscs/mail-notify-config/deleteMailNotifyConfigList',
+      params: { ids: idStr },
     });
   },
 };

+ 22 - 12
src/components/mailTemplate/MailTemplateForm.tsx

@@ -28,25 +28,30 @@ const MailTemplateForm = forwardRef<MailTemplateFormRef, MailTemplateFormProps>(
     setFormType(type as 'create' | 'update');
     form.resetFields();
 
-    // 修改时,设置数据
+    // 修改时,拉取详情并回显
     if (id) {
       setFormLoading(true);
       try {
         const data = await emailTemplateApi.getMailTemplate(id);
+        if (!data) {
+          message.error(t('mailTemplate.detailFailed'));
+          return;
+        }
+        const status = data.status != null ? Number(data.status) : 1;
         form.setFieldsValue({
           id: data.id,
-          name: data.name,
-          code: data.code,
+          name: data.name ?? '',
+          code: data.code ?? '',
           accountId: data.accountId,
-          nickname: data.nickname,
-          title: data.title,
-          content: data.content,
-          params: data.params,
-          status: data.status,
-          remark: data.remark,
+          nickname: data.nickname ?? '',
+          title: data.title ?? '',
+          content: data.content ?? '',
+          params: data.params ?? '',
+          status,
+          remark: data.remark ?? '',
         });
       } catch (error: any) {
-        message.error(error.message || t('mailTemplate.detailFailed'));
+        message.error(error?.message || t('mailTemplate.detailFailed'));
       } finally {
         setFormLoading(false);
       }
@@ -75,10 +80,10 @@ const MailTemplateForm = forwardRef<MailTemplateFormRef, MailTemplateFormProps>(
 
         if (formType === 'create') {
           await emailTemplateApi.createMailTemplate(data);
-          message.success(t('common.createSuccess'));
+          message.success(t('mailTemplate.createSuccess') || '邮件模板创建成功');
         } else {
           await emailTemplateApi.updateMailTemplate(data);
-          message.success(t('common.updateSuccess'));
+          message.success(t('mailTemplate.updateSuccess') || '邮件模板更新成功');
         }
         setDialogVisible(false);
         onSuccess?.();
@@ -98,6 +103,8 @@ const MailTemplateForm = forwardRef<MailTemplateFormRef, MailTemplateFormProps>(
       open={dialogVisible}
       onCancel={() => setDialogVisible(false)}
       onOk={submitForm}
+      okText={t('common.save')}
+      cancelText={t('common.cancel')}
       confirmLoading={formLoading}
       width={1000}
       destroyOnClose
@@ -111,6 +118,9 @@ const MailTemplateForm = forwardRef<MailTemplateFormRef, MailTemplateFormProps>(
           status: 1,
         }}
       >
+        <Form.Item name="id" hidden>
+          <Input type="hidden" />
+        </Form.Item>
         <Row gutter={16}>
           <Col span={12}>
             <Form.Item

+ 43 - 26
src/components/mailTemplate/MailTemplateManagement.tsx

@@ -9,6 +9,7 @@ import { Button as UIButton } from '../ui/button';
 import type { ColumnsType } from 'antd/es/table';
 import MailTemplateForm, { MailTemplateFormRef } from './MailTemplateForm';
 import MailTemplateSendForm, { MailTemplateSendFormRef } from './MailTemplateSendForm';
+import { DICT_TYPE, getDictLabel } from '../../utils/dict';
 
 interface MailTemplateManagementProps {
   onBack?: () => void;
@@ -82,6 +83,18 @@ export default function MailTemplateManagement(props: MailTemplateManagementProp
     sendFormRef.current?.open(id);
   };
 
+  // 状态列:与角色管理一致,使用字典标签 + 徽章样式
+  const getStatusLabel = (status: number | undefined) => {
+    return status !== undefined && status !== null
+      ? (getDictLabel(DICT_TYPE.COMMON_STATUS, status) || (status === 1 ? t('mailTemplate.enable') : t('mailTemplate.disable')))
+      : '-';
+  };
+  const getStatusStyle = (status: number | undefined) => {
+    const label = getStatusLabel(status);
+    const isEnabled = label === '开启' || label === '启用' || label === '正常' || status === 1;
+    return isEnabled ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-700';
+  };
+
   // 删除
   const handleDelete = (id: number) => {
     Modal.confirm({
@@ -137,9 +150,11 @@ export default function MailTemplateManagement(props: MailTemplateManagementProp
       dataIndex: 'status',
       width: 100,
       align: 'center',
-      render: (status: number | undefined) => {
-        return status === 1 ? t('mailTemplate.enable') : t('mailTemplate.disable');
-      },
+      render: (status: number | undefined) => (
+        <span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${getStatusStyle(status)}`}>
+          {getStatusLabel(status)}
+        </span>
+      ),
     },
     {
       title: t('mailTemplate.remark'),
@@ -193,30 +208,32 @@ export default function MailTemplateManagement(props: MailTemplateManagementProp
     <div className="space-y-6">
       {/* 搜索栏 */}
       <div className="bg-white rounded-2xl border border-gray-200/50 shadow-sm p-6">
-        <div className="flex items-center gap-4 flex-wrap">
-          <div className="flex items-center gap-2 flex-1 min-w-[200px]">
-            <label className="text-sm text-gray-700 whitespace-nowrap">{t('mailTemplate.name')}:</label>
-            <Input
-              placeholder={t('mailTemplate.namePlaceholder')}
-              value={queryParams.name}
-              onChange={(e) => setQueryParams({ ...queryParams, name: e.target.value })}
-              onPressEnter={handleQuery}
-              className="flex-1 max-w-[240px]"
-              allowClear
-            />
-          </div>
-          <div className="flex items-center gap-2 flex-1 min-w-[200px]">
-            <label className="text-sm text-gray-700 whitespace-nowrap">{t('mailTemplate.code')}:</label>
-            <Input
-              placeholder={t('mailTemplate.codePlaceholder')}
-              value={queryParams.code}
-              onChange={(e) => setQueryParams({ ...queryParams, code: e.target.value })}
-              onPressEnter={handleQuery}
-              className="flex-1 max-w-[240px]"
-              allowClear
-            />
+        <div className="flex items-center justify-between gap-4 flex-wrap">
+          <div className="flex items-center gap-4 flex-wrap">
+            <div className="flex items-center gap-2">
+              <label className="text-sm text-gray-700 whitespace-nowrap">{t('mailTemplate.name')}:</label>
+              <Input
+                placeholder={t('mailTemplate.namePlaceholder')}
+                value={queryParams.name}
+                onChange={(e) => setQueryParams({ ...queryParams, name: e.target.value })}
+                onPressEnter={handleQuery}
+                className="w-[160px]"
+                allowClear
+              />
+            </div>
+            <div className="flex items-center gap-2">
+              <label className="text-sm text-gray-700 whitespace-nowrap">{t('mailTemplate.code')}:</label>
+              <Input
+                placeholder={t('mailTemplate.codePlaceholder')}
+                value={queryParams.code}
+                onChange={(e) => setQueryParams({ ...queryParams, code: e.target.value })}
+                onPressEnter={handleQuery}
+                className="w-[160px]"
+                allowClear
+              />
+            </div>
           </div>
-          <div className="flex items-center gap-2">
+          <div className="flex items-center gap-2 flex-shrink-0">
             <Button
               type="primary"
               icon={<Search className="w-4 h-4" />}

+ 46 - 22
src/components/notification/EmailNotifyForm.tsx

@@ -12,6 +12,12 @@ export interface EmailNotifyFormRef {
   open: (type: string, id?: number) => void;
 }
 
+// 提醒时长下拉选项:天 0-30,时 0-23,分 0-59,秒 0-59
+const DURATION_DAYS_OPTIONS = Array.from({ length: 31 }, (_, i) => i);
+const DURATION_HOURS_OPTIONS = Array.from({ length: 24 }, (_, i) => i);
+const DURATION_MINUTES_OPTIONS = Array.from({ length: 60 }, (_, i) => i);
+const DURATION_SECONDS_OPTIONS = Array.from({ length: 60 }, (_, i) => i);
+
 const EmailNotifyForm = forwardRef<EmailNotifyFormRef, EmailNotifyFormProps>(({ onSuccess }, ref) => {
   const { t } = useTranslation();
   const [dialogVisible, setDialogVisible] = useState(false);
@@ -21,12 +27,11 @@ const EmailNotifyForm = forwardRef<EmailNotifyFormRef, EmailNotifyFormProps>(({
   const [form] = Form.useForm();
   const [templateList, setTemplateList] = useState<Array<{ label: string; value: string }>>([]);
 
-  // 时间单位配置
   const timeUnits = [
-    { name: 'days', label: t('common.day'), options: Array.from({ length: 31 }, (_, i) => i) },
-    { name: 'hours', label: t('common.hour'), options: Array.from({ length: 24 }, (_, i) => i) },
-    { name: 'minutes', label: t('common.minute'), options: Array.from({ length: 60 }, (_, i) => i) },
-    { name: 'seconds', label: t('common.second'), options: Array.from({ length: 60 }, (_, i) => i) },
+    { name: 'days', label: t('common.day'), options: DURATION_DAYS_OPTIONS },
+    { name: 'hours', label: t('common.hour'), options: DURATION_HOURS_OPTIONS },
+    { name: 'minutes', label: t('common.minute'), options: DURATION_MINUTES_OPTIONS },
+    { name: 'seconds', label: t('common.second'), options: DURATION_SECONDS_OPTIONS },
   ];
 
   const [timeValues, setTimeValues] = useState({
@@ -44,37 +49,53 @@ const EmailNotifyForm = forwardRef<EmailNotifyFormRef, EmailNotifyFormProps>(({
     form.resetFields();
     setTimeValues({ days: 0, hours: 0, minutes: 0, seconds: 0 });
 
-    // 加载邮件模板列表
+    // 先加载邮件模板列表(编辑时回显模板依赖该列表)
+    let templates: Array<{ label: string; value: string }> = [];
     try {
       const response = await emailTemplateApi.getMailTemplatePage({
         pageNo: 1,
         pageSize: -1,
       });
-      setTemplateList(
-        response.list.map((item) => ({
-          label: item.name,
-          value: item.code,
-        }))
-      );
+      templates = (response.list || []).map((item) => ({
+        label: item.name,
+        value: item.code,
+      }));
+      setTemplateList(templates);
     } catch (error) {
       console.error(t('mailTemplate.fetchListFailed'), error);
       setTemplateList([]);
     }
 
-    // 修改时,设置数据
+    // 修改时,拉取详情并回显(调用 iscs/mail-notify-config/selectMailNotifyConfigById?id=xxx)
+    if (type === 'update' && (id == null || id === undefined)) {
+      message.warning(t('notificationManagement.getEmailListFailed') || '缺少记录 ID,无法加载详情');
+      return;
+    }
     if (id) {
       setFormLoading(true);
       try {
         const data = await mailNotifyConfigApi.getIsMailNotifyConfigById(id);
+        if (!data) {
+          message.error(t('notificationManagement.getEmailListFailed'));
+          return;
+        }
+        const recordId = (data as any).id ?? data.configId;
+        const name = data.name ?? data.configName ?? '';
+        let templateCode = data.templateCode ?? (data as any).templateCode ?? '';
+        if (!templateCode && (data as any).templateName && templates.length > 0) {
+          const byName = templates.find((t) => t.label === (data as any).templateName);
+          if (byName) templateCode = byName.value;
+        }
+        const status = data.status != null ? String(data.status) : '1';
+
         form.setFieldsValue({
-          configId: data.configId,
-          name: data.name || data.configName,
-          templateCode: data.templateCode,
-          status: data.status || '1',
+          id: recordId,
+          name,
+          templateCode,
+          status,
         });
 
-        // 转换时间
-        const totalSeconds = data.reminderTime || 0;
+        const totalSeconds = Number(data.reminderTime) || 0;
         setTimeValues({
           days: Math.floor(totalSeconds / (24 * 60 * 60)),
           hours: Math.floor((totalSeconds % (24 * 60 * 60)) / (60 * 60)),
@@ -82,7 +103,7 @@ const EmailNotifyForm = forwardRef<EmailNotifyFormRef, EmailNotifyFormProps>(({
           seconds: totalSeconds % 60,
         });
       } catch (error: any) {
-        message.error(error.message || t('notificationManagement.getEmailListFailed'));
+        message.error(error?.message || t('notificationManagement.getEmailListFailed'));
       } finally {
         setFormLoading(false);
       }
@@ -111,10 +132,10 @@ const EmailNotifyForm = forwardRef<EmailNotifyFormRef, EmailNotifyFormProps>(({
 
         if (formType === 'create') {
           await mailNotifyConfigApi.addIsMailNotifyConfig(data);
-          message.success(t('common.createSuccess'));
+          message.success(t('notificationManagement.addEmailNotifySuccess') || '邮件提醒新增成功');
         } else {
           await mailNotifyConfigApi.updateIsMailNotifyConfig(data);
-          message.success(t('common.updateSuccess'));
+          message.success(t('notificationManagement.updateEmailNotifySuccess') || '邮件提醒保存成功');
         }
         setDialogVisible(false);
         onSuccess?.();
@@ -148,6 +169,9 @@ const EmailNotifyForm = forwardRef<EmailNotifyFormRef, EmailNotifyFormProps>(({
           status: '1',
         }}
       >
+        <Form.Item name="id" hidden>
+          <Input type="hidden" />
+        </Form.Item>
         <Form.Item
           label={t('notificationManagement.reminderItem')}
           name="name"

+ 13 - 7
src/components/notification/EmailNotifyManagement.tsx

@@ -27,15 +27,18 @@ export default function EmailNotifyManagement() {
   // 子组件引用
   const formRef = useRef<EmailNotifyFormRef>(null);
 
-  // 获取列表
+  // 获取列表(归一化主键:后端可能返回 id 或 configId,统一保证有 id 供编辑/删除使用,传递 id 时不能使用 configId)
   const getList = async (params?: typeof queryParams) => {
     const currentParams = params || queryParams;
-    console.log('EmailNotifyManagement: 开始获取列表,参数:', currentParams);
     setLoading(true);
     try {
       const response = await mailNotifyConfigApi.listIsMailNotifyConfigPage(currentParams);
-      console.log('EmailNotifyManagement: API 响应:', response);
-      setList(response.list || []);
+      const rawList = response.list || [];
+      const listWithId = rawList.map((item: MailNotifyConfigVO) => ({
+        ...item,
+        id: (item as any).id ?? item.configId,
+      }));
+      setList(listWithId);
       setTotal(response.total || 0);
     } catch (error: any) {
       console.error('EmailNotifyManagement: 获取列表失败:', error);
@@ -188,7 +191,7 @@ export default function EmailNotifyManagement() {
             <UIButton
               variant="ghost"
               size="sm"
-              onClick={() => openForm('update', record.configId)}
+              onClick={() => openForm('update', (record as any).id ?? record.configId)}
               className="h-8 px-2 transition-colors hover:text-[#1677ff] hover:underline"
             >
               <Edit2 className="w-4 h-4" />
@@ -197,7 +200,10 @@ export default function EmailNotifyManagement() {
             <UIButton
               variant="ghost"
               size="sm"
-              onClick={() => handleDelete(record.configId!)}
+              onClick={() => {
+                const id = (record as any).id ?? record.configId;
+                if (id != null) handleDelete(id);
+              }}
               className="h-8 px-2 text-red-600 hover:text-[#1677ff] transition-colors hover:underline"
             >
               <Trash2 className="w-4 h-4" />
@@ -286,7 +292,7 @@ export default function EmailNotifyManagement() {
           <Table
             columns={columns}
             dataSource={list}
-            rowKey="configId"
+            rowKey="id"
             loading={loading}
             pagination={false}
             scroll={{ x: 'max-content' }}

+ 5 - 1
src/locales/en.json

@@ -91,6 +91,8 @@
     "reminderDuration": "Reminder Duration",
     "addEmailNotify": "Add Email Notification",
     "editEmailNotify": "Edit Email Notification",
+    "addEmailNotifySuccess": "Email reminder added successfully",
+    "updateEmailNotifySuccess": "Email reminder saved successfully",
     "getEmailListFailed": "Failed to load email reminder list",
     "deleteEmailConfirmContent": "Are you sure you want to delete this email reminder config?",
     "activateSuccess": "Activated successfully",
@@ -204,7 +206,9 @@
     "nicknamePlaceholder": "Enter nickname",
     "statusPlaceholder": "Select status",
     "enable": "Enabled",
-    "disable": "Disabled"
+    "disable": "Disabled",
+    "createSuccess": "Mail template created successfully",
+    "updateSuccess": "Mail template updated successfully"
   },
   "hardwareManagement": {
     "cabinet": "Cabinet",

+ 5 - 1
src/locales/zh.json

@@ -91,6 +91,8 @@
     "reminderDuration": "提醒时长",
     "addEmailNotify": "新增邮件提醒",
     "editEmailNotify": "编辑邮件提醒",
+    "addEmailNotifySuccess": "邮件提醒新增成功",
+    "updateEmailNotifySuccess": "邮件提醒保存成功",
     "getEmailListFailed": "获取邮件提醒列表失败",
     "deleteEmailConfirmContent": "确定要删除这条邮件提醒配置吗?",
     "activateSuccess": "激活成功",
@@ -204,7 +206,9 @@
     "nicknamePlaceholder": "请输入昵称",
     "statusPlaceholder": "请选择状态",
     "enable": "启用",
-    "disable": "禁用"
+    "disable": "禁用",
+    "createSuccess": "邮件模板创建成功",
+    "updateSuccess": "邮件模板更新成功"
   },
   "hardwareManagement": {
     "cabinet": "机柜",