修改登录日志

788 阅读5分钟

1.我们在列表数据展现定义columns数组时,预留了修改和查看的操作列代码,代码如下:

{
      title: '操作',
      dataIndex: 'option',
      valueType: 'option',
      render: (_, record) => [
        <a
          key="config"
          onClick={() => {
            handleUpdateModalVisible(true);
            setCurrentRow(record);
          }}
        >
          修改
        </a>,
         <a
            onClick={() => {
              setCurrentRow(record);
              setShowDetail(true);
            }}
          >
          查看
          </a>

      ],
    },

这里点某一行数据的修改操作链接时会调用handleUpdateModalVisible(true)方法,从字面意义上看应该是有个UpdateModel组件,让其可见,然后调用setCurrentRow方法把当前行数据record存入state

  const [currentRow, setCurrentRow] = useState();

2.我们先找UpdateModel组件 image.png 发现有个UpdateForm,而且src/pages/loginfo/index.jsx中确实有UpdateForm组件,而 handleUpdateModalVisible(true)只是个useState的设置,来设置UpdateForm组件的可见性 image.png

 <UpdateForm
        onSubmit={async (value) => {
          const success = await handleUpdate(value, currentRow);

          if (success) {
            handleUpdateModalVisible(false);
            setCurrentRow(undefined);

            if (actionRef.current) {
              actionRef.current.reload();
            }
          }
        }}
        onCancel={() => {
          handleUpdateModalVisible(false);
          setCurrentRow(undefined);
        }}
        updateModalVisible={updateModalVisible}
        values={currentRow || {}}
      />
   updateModalVisible={updateModalVisible}

3.从以上代码我们可以分析出,修改模块的核心组件是UpdateForm,而UpdateForm是一个单独引入的JSX文件,文件位置在src/pages/loginfo/components/UpdateForm.jsx ​

4.我们打开UpdateForm.jsx,发现里面代码蛮多,而且还用了StepsForm image.png 我们的表单没有这么复杂,我们把UpdateForm.jsx,全替换掉,替换后的的代码如下

import React from 'react';
import { Modal } from 'antd';
import ProForm, { ModalForm, ProFormText, ProFormDateTimePicker } from '@ant-design/pro-form';

const UpdateForm = (props) => {

  return (
    <ModalForm
    layout="horizontal"
    labelCol={{ span: 4 }}

    title="修改登录日志"
    width="600px"
    visible={props.updateModalVisible}
    modalProps={{
      destroyOnClose: true,
      onCancel: () =>  props.onCancel(),
    }}

    onFinish={props.onSubmit}
    initialValues={{
      infoId: props.values.infoId,
      ipaddr: props.values.ipaddr,
      loginLocation: props.values.loginLocation,
      browser: props.values.browser,
      loginTime: props.values.loginTime,
      msg: props.values.msg,
    }}
  >

<ProFormText
      name="infoId"
      hidden="true"
    />
    <ProFormText
      rules={[
        {
          required: true,
          message: '登录IP地址不能为空',
        },
        {
          pattern: new RegExp(
            '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$',
            'g',
          ),
          message: '登录IP地址格式错误',
        },
      ]}
      width="md"
      name="ipaddr"
      label="登录IP地址"
      placeholder="请输入登录IP地址"

    />

    <ProFormText
      rules={[
        {
          required: true,
          message: '登录地点为必填项',
        },
      ]}
      width="md"
      label="登录地点"
      placeholder="请输入登录地点"
      name="loginLocation"
    />
    <ProFormText
      rules={[
        {
          required: true,
          message: '浏览器类型为必填项',
        },
      ]}
      width="md"
      label="浏览器类型"
      placeholder="请输入浏览器类型"
      name="browser"
    />

    <ProFormDateTimePicker
      name="loginTime"
      label="访问时间"
      rules={[
        {
          required: true,
          message: '访问时间为必填项',
        },
      ]}
    />
    <ProFormText
      rules={[
        {
          required: true,
          message: '提示消息为必填项',
        },
      ]}
      width="md"
      label="提示消息"
      placeholder="请输入提示消息"
      name="msg"
    />
  </ModalForm>
  );
};

export default UpdateForm;

这里的UpdateForm组件其实跟我们之前做新增时用的组件差不多,用的也是ModalForm,ModalForm里面用的组件和非空验证以及正则表达式验证也是一样的,其实之前在做新增登录日志时我们也说过,新增和修改其实可以共用一个jsx文件,有兴趣的朋友可以自行改造成共用一个jsx文件。 ​

5.UpdateForm表单中有几段代码稍作说明

  modalProps={{
      destroyOnClose: true,
      onCancel: () =>  props.onCancel(),
    }}

通过props公开onCancel方法 image.png

 onFinish={props.onSubmit}
     <UpdateForm
        onSubmit={async (value) => {
          const success = await handleUpdate(value, currentRow);

          if (success) {
            handleUpdateModalVisible(false);
            setCurrentRow(undefined);

            if (actionRef.current) {
              actionRef.current.reload();
            }
          }
        }}

通过props公开onSubmit方法,即更新表单后,点确定时会触发onSubmit方法,onSubmit中会调用handleUpdate更新数据,更新成功后会隐藏更新表单,然后重新加载表格。

    initialValues={{
      infoId: props.values.infoId,
      ipaddr: props.values.ipaddr,
      loginLocation: props.values.loginLocation,
      browser: props.values.browser,
      loginTime: props.values.loginTime,
      msg: props.values.msg,
    }}

initialValues设置编辑表单上各个组件的初始值,updateForm中有属性values,values的值即为当前行的数据对象,values会通过props传递给UpdateForm,我们可以在initialValues方法中拿到props.values,并且给各个组件设置初始值,如infoId:props.values.infoId, image.png

<ProFormText
      name="infoId"
      hidden="true"
    />

让主键字段infoId文本框隐藏,即实现input type='hidden'效果,这里踩了好久的坑,在Antd Pro官网的ProFormText并未找到如何实现隐藏域的效果,官网地址: procomponents.ant.design/components/…,在Antd 的Input组件属性中也未找到,官网地址: ant.design/components/…,最后自己反复猜测尝试,才发现可以用hidden="true"实现隐藏域效果 ​

6.保存UpdateForm.jsx后,等编译后,打开登录日志列表页面,选择我们刚才录入的哪条数据,发现数据可以正常显示在更新页面上,且主键字段值不会显示出来,如下图: image.png

7.下一步是写后台方法,之前在做新增时也说过,若依的登录日志的Contoller中是没有新增、修改的方法的,我们先加一下修改的后台方法,代码如下

  @PostMapping(value="edit")
    public AjaxResult edit(@Validated @RequestBody SysLogininfor sysLogininfor)
    {

        sysLogininfor.setUpdateBy(getUsername());
        sysLogininfor.setUserName(getUsername());
        sysLogininfor.setStatus("0");
        return toAjax(logininforService.updateSysLogininfor(sysLogininfor));

    }

这是一个Post接口,传入参数为一个sysLoginfor实体对象的JSON数据,接口调用的url地址为/api/monitor/logininfor/edit,这里有个问题,若依的servcie中连updateSysLogininfor方法也未提供,我们需要手动增加updateSysLogininfor方法,若依后台使用的是mybatis,我们需要先从mapper文件开始进行修改

8.我们先在mapper文件中增加更新logininfo的xml代码,找到ruoyi-system模块(若依是一个多模块的项目)下的resources/mapper/system/SysLogininforMapper.xml,找到insert代码 image.png

	<insert id="insertLogininfor" parameterType="SysLogininfor">
		insert into sys_logininfor (user_name, status, ipaddr, login_location, browser, os, msg, login_time)
		values (#{userName}, #{status}, #{ipaddr}, #{loginLocation}, #{browser}, #{os}, #{msg}, sysdate())
	</insert>

我们在insert后面增加update的mybatis xml代码如下:

	<update id="updateSysLogininfor" parameterType="SysLogininfor">
		update sys_logininfor
		<trim prefix="SET" suffixOverrides=",">
			<if test="userName != null">user_name = #{userName},</if>
			<if test="ipaddr != null">ipaddr = #{ipaddr},</if>
			<if test="loginLocation != null">login_location = #{loginLocation},</if>
			<if test="browser != null">browser = #{browser},</if>
			<if test="os != null">os = #{os},</if>
			<if test="status != null">status = #{status},</if>
			<if test="msg != null">msg = #{msg},</if>
			<if test="loginTime != null">login_time = #{loginTime},</if>
		</trim>
		where info_id = #{infoId}
	</update>

然后保存xml文件

9.找到ruoyi-system模块下的src/java/com/ruoyi/system/mapper/SysLogininforMapper.java,在 public void insertLogininfor(SysLogininfor logininfor);后面加一行更新方法的代码如下

    public int updateSysLogininfor(SysLogininfor sysLogininfor);

image.png

10.找到ruoyi-system模块下的src/java/com/ruoyi/system/service/ISysLogininforService.java,在 public void insertLogininfor(SysLogininfor logininfor);后面加一行更新方法的代码如下

  public int updateSysLogininfor(SysLogininfor sysLogininfor);

11.找到ruoyi-system模块下的src/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java,在

    @Override
    public void insertLogininfor(SysLogininfor logininfor)
    {
        logininforMapper.insertLogininfor(logininfor);
    }

后面加更新方法的代码如下

 @Override
    public int updateSysLogininfor(SysLogininfor sysLogininfor)
    {
        return logininforMapper.updateSysLogininfor(sysLogininfor);
    }

这一步做完后contoller中的edit部分的代码应该不会报错了,我们重新maven reload一下 image.png 然后Rebuild Project image.png 稍等几分钟,Rebuild 成功后,重启后台

12.后台方法写好后,我们就应该修改前台调用的接口了,找到src/pages/loginfo/service.js,找到updateRule方法,代码如下:

export async function updateRule(data, options) {
  return request('/api/rule', {
    data,
    method: 'PUT',
    ...(options || {}),
  });
}

修改为以下代码,主要修改了方法名和请求url地址,method改成后台对应的POST

export async function updateLoginfo(data, options) {
  return request('/api/monitor/logininfor/edit', {
    data,
    method: 'POST',
    ...(options || {}),
  });
}

13.回到src/pages/loginfo/index.jsx,修改引入service的代码

import { loginfo, addLoginfo, updateRule, removeRule } from './service';

将updateRule替换成updateLoginfo,替换后代码如下

import { loginfo, addLoginfo, updateLoginfo, removeRule } from './service';

14.找到handleUpdate方法,代码如下:

const handleUpdate = async (fields, currentRow) => {
  const hide = message.loading('正在配置');

  try {
    await updateRule({ ...currentRow, ...fields });
    hide();
    message.success('配置成功');
    return true;
  } catch (error) {
    hide();
    message.error('配置失败请重试!');
    return false;
  }
};

这是更新调用后台接口的主方法,查询表格里面已做好代码封装,我们只需将updateRule方法改为updateLoginfo即可,修改后代码如下:

const handleUpdate = async (fields, currentRow) => {
  const hide = message.loading('正在更新');

  try {
    await updateLoginfo({ ...currentRow, ...fields });
    hide();
    message.success('更新成功');
    return true;
  } catch (error) {
    hide();
    message.error('更新失败请重试!');
    return false;
  }
};
/**

15.保存前台代码,前台编译完成后,确保后台已启动,我们重新登录前台,打开登录日志,编辑我们之前录入的那条数据 image.png

修改成功后表格会刷新,会绑定更新后的数据,如下图所示 image.png

最近做了个小API应用,希望大家关注支持下: www.yuque.com/docs/share/…