当前位置: 首页 > article >正文

图表管理功能(前后端实现增删改查)

图表管理功能(前后端实现增删改查)

后端

  1. 库表设计

    create table chart
    (
        id         bigint auto_increment comment 'id'
            primary key,
        goal       text                               null comment '分析目标',
        chartData  text                               null comment '图表信息',
        chartType  varchar(256)                       null comment '图表类型',
        genChart   text                               null comment '生成的图表信息',
        genResult  text                               null,
        userId     bigint                             null comment '创建图标用户 id',
        createTime datetime default CURRENT_TIMESTAMP not null comment '创建时间',
        updateTime datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
        isDelete   tinyint  default 0                 not null comment '是否删除',
        name       varchar(128)                       null comment '图表名称'
    )
        comment '图表信息表' collate = utf8mb4_unicode_ci;
    
  2. 增删改查代码自动生成工具生成:

    使用Mybatis-Generator自动代码生成工具生成实体类,mapper接口和实现类。

  3. controller层增删改查询接口实现

    /**
     * 接口
     *
     */
    @RestController
    @RequestMapping("/chart")
    @Slf4j
    public class ChartController {
    
        @Resource
        private ChartService chartService;
    
        private final static Gson GSON = new Gson();
    
        // region 增删改查
    
        /**
         * 创建
         *
         * @param chartAddRequest
         * @param request
         * @return
         */
        @PostMapping("/add")
        public BaseResponse<Long> addChart(@RequestBody ChartAddRequest chartAddRequest, HttpServletRequest request) {
            if (chartAddRequest == null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR);
            }
            Chart chart = new Chart();
            BeanUtils.copyProperties(chartAddRequest, chart);
            User loginUser = userService.getLoginUser(request);
            chart.setUserId(loginUser.getId());
            boolean result = chartService.save(chart);
            ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
            long newChartId = chart.getId();
            return ResultUtils.success(newChartId);
        }
    
        /**
         * 删除
         *
         * @param deleteRequest
         * @param request
         * @return
         */
        @PostMapping("/delete")
        public BaseResponse<Boolean> deleteChart(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
            if (deleteRequest == null || deleteRequest.getId() <= 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR);
            }
            User user = userService.getLoginUser(request);
            long id = deleteRequest.getId();
            // 判断是否存在
            Chart oldChart = chartService.getById(id);
            ThrowUtils.throwIf(oldChart == null, ErrorCode.NOT_FOUND_ERROR);
            // 仅本人或管理员可删除
            if (!oldChart.getUserId().equals(user.getId()) && !userService.isAdmin(request)) {
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
            }
            boolean b = chartService.removeById(id);
            return ResultUtils.success(b);
        }
    
        /**
         * 更新(仅管理员)
         *
         * @param chartUpdateRequest
         * @return
         */
        @PostMapping("/update")
        @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
        public BaseResponse<Boolean> updateChart(@RequestBody ChartUpdateRequest chartUpdateRequest) {
            if (chartUpdateRequest == null || chartUpdateRequest.getId() <= 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR);
            }
            Chart chart = new Chart();
            BeanUtils.copyProperties(chartUpdateRequest, chart);
            long id = chartUpdateRequest.getId();
            // 判断是否存在
            Chart oldChart = chartService.getById(id);
            ThrowUtils.throwIf(oldChart == null, ErrorCode.NOT_FOUND_ERROR);
            boolean result = chartService.updateById(chart);
            return ResultUtils.success(result);
        }
    
        /**
         * 根据 id 获取
         *
         * @param id
         * @return
         */
        @GetMapping("/get")
        public BaseResponse<Chart> getChartById(long id, HttpServletRequest request) {
            if (id <= 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR);
            }
            Chart chart = chartService.getById(id);
            if (chart == null) {
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
            }
            return ResultUtils.success(chart);
        }
    
        /**
         * 分页获取列表
         *
         * @param chartQueryRequest
         * @param request
         * @return
         */
        @PostMapping("/list/page")
        public BaseResponse<Page<Chart>> listChartByPage(@RequestBody ChartQueryRequest chartQueryRequest,
                HttpServletRequest request) {
            long current = chartQueryRequest.getCurrent();
            long size = chartQueryRequest.getPageSize();
            // 限制爬虫
            ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
            Page<Chart> chartPage = chartService.page(new Page<>(current, size),
                    getQueryWrapper(chartQueryRequest));
            return ResultUtils.success(chartPage);
        }
    
        /**
         * 分页获取当前用户创建的资源列表
         *
         * @param chartQueryRequest
         * @param request
         * @return
         */
        @PostMapping("/my/list/page")
        public BaseResponse<Page<Chart>> listMyChartByPage(@RequestBody ChartQueryRequest chartQueryRequest,
                HttpServletRequest request) {
            if (chartQueryRequest == null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR);
            }
            User loginUser = userService.getLoginUser(request);
            chartQueryRequest.setUserId(loginUser.getId());
            long current = chartQueryRequest.getCurrent();
            long size = chartQueryRequest.getPageSize();
            // 限制爬虫
            ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
            Page<Chart> chartPage = chartService.page(new Page<>(current, size),
                    getQueryWrapper(chartQueryRequest));
            return ResultUtils.success(chartPage);
        }
    }
    
    

前端(antdesign组件库)

  1. 开发一个表展示页

    1. 新添加路由

        {
          path: '/my_chart',
          name: '我的图表',
          icon: 'pieChart',
          component: './MyChart',
        },
      
    2. 创建页面

    3. 填充内容

      1. 获取需要的数据

        • 定义一个获取数据的函数,调用接口(await把异步变成同步) listMyChartPageUsingPost和后端对应的查询接口由OpenApi工具根据Swagger接口自动生成,大幅提高开发效率。

          const loadData = async () => {
              try {
                const res = await listMyChartByPageUsingPost(searchParams);
                if (res.data) {
                  setChartList(res.data.records ?? []);
                }
              } catch (e: any) {
                message.error('获取图表失败', e.message);
              }
            };
          
      2. 首次页面加载时触发时加载数据(钩子函数:页面首次渲染时以及数组中的变量发生变化时执行钩子函数中的方法)

          //钩子函数:页面首次渲染时以及数组中的变量发生变化时执行钩子函数中的方法
          useEffect(() => {
            loadData();
          }, [searchParams]);//搜索参数改变就会触发加载数据方法
        
      3. 引入Ant Design的List组件,https://ant.design/components/list-cn,复制示例代码

      4. 调整 List 组件中的内容为自己的(注意,获取用户头像可以从初始化状态中获取)

        const { initialState } = useModel('@@initialState');
        const { currentUser } = initialState || {};
        
      5. 针对样式,对数据做一些处理,比如统一隐藏图表自身的 title

  2. 实现分页展示表

    逻辑:当用户点击切换页面的时候,组件触发onChange方法,改变搜索条件,当所搜条件改变的时候又会触发数据的加载,后端返回新的数据 。

    • 使用AntDesign组件库中的分页组件
  3. 添加按表名称搜索表功能

    • 添加搜索组件框组件,当用户的搜索条件(初始化)改变时,要添加到原始的搜索条件
  4. (附)前端展示图表,页面,搜索源码

//前端分页查询图表展示预页面(源码)
const MyChartPage: React.FC = () => {
  /**
   * 初始值
   */
  const initSearchParams = {
    current: 1,
    pageSize: 6,
  };

  const [searchParams, setSearchParams] = useState<API.ChartQueryRequest>({
    ...initSearchParams,
  });

  // const [selectedChartId, setSelectedChartId] = useState<number | undefined>(undefined);

  /**
   * 分页获取图表
   */
  const [chartList, setChartList] = useState<API.Chart[]>();
  const [chartTotal, setChartTotal] = useState<number>(0);
  const [loading, setLoading] = useState<boolean>(true);
  /**
   * 获取当前用户
   */
  const { initialState } = useModel('@@initialState');
  const { currentUser } = initialState || {};

  /**
   * 删除图表
   * @param chartId
   */
  const handleDelete = (chartId: any) => {
    Modal.confirm({
      title: '确认删除',
      icon: <ExclamationCircleOutlined />,
      content: '确定要删除这个图表吗?',
      okText: '确认',
      cancelText: '取消',
      onOk: async () => {
        try {
          const res = await deleteChartUsingPost({ id: chartId });
          // 后端返回 boolean值
          console.log('res:', res.data);
          if (res.data) {
            message.success('删除成功');
            // 删除成功后重新加载图表数据
            loadData();
          } else {
            message.error('删除失败');
          }
        } catch (e: any) {
          message.error('删除失败' + e.message);
        }
      },
    });
  };

  /**
   * 加载图表数据
   */
  const loadData = async () => {
    setLoading(loading);
    try {
      let res = await listMyChartByPageUsingPost(searchParams);
      if (res.data) {
        setChartList(res.data.records ?? []);
        setChartTotal(res.data.total ?? 0);
        // 隐藏title
        if (res.data.records) {
          res.data.records.forEach((data) => {
            const chartOption = JSON.parse(data.genChart ?? '{}');
            // 取出title并且设置为 undefined
            chartOption.title = undefined;
            data.genChart = JSON.stringify(chartOption);
          });
        }
      } else {
        message.error('获取我的图表失败');
      }
    } catch (e: any) {
      message.error('获取我的图表失败' + e.message);
    }
    setLoading(false);
  };
  /**
   * 变化时执行此处
   */
  useEffect(() => {
    loadData();
  }, [searchParams]);

  return (
    <div className="my-chart-page">
      <div className="margin-20">
        <Search
          placeholder="请输入图标名称搜索"
          loading={loading}
          enterButton
          onSearch={(value) => {
            setSearchParams({
              ...initSearchParams,
              chartName: value,
            });
          }}
        />
      </div>

      <List
        grid={{
          gutter: 16,
          xs: 1,
          sm: 1,
          md: 1,
          lg: 2,
          xl: 2,
          xxl: 2,
        }}
        pagination={{
          // 设置分页
          showTotal: () => `${chartTotal} 条记录`,
          showSizeChanger: true,
          showQuickJumper: true,
          pageSizeOptions: ['6', '10', '14', '20'],
          onChange: (page, pageSize) => {
            setSearchParams({
              ...searchParams,
              current: page,
              pageSize,
            });
          },
          current: searchParams.current, // 当前页
          pageSize: searchParams.pageSize, // 每页条数
          total: chartTotal, // 总数
        }}
        loading={loading}
        dataSource={chartList}
        renderItem={(item) => (
          <List.Item key={item.id}>
            <Card style={{ width: '100%' }}>
              <List.Item.Meta
                avatar={<Avatar src={currentUser?.userAvatar} />}
                title={currentUser?.userName}
              />
              <p
                style={{
                  textAlign: 'center',
                  fontWeight: 'bold',
                  color: 'black',
                  fontSize: '16px',
                }}
              >
                {'分析目标:' + item.goal}
              </p>
              <List.Item.Meta
                style={{ textAlign: 'right' }}
                description={item.chartType ? '图表类型:' + item.chartType : undefined}
              />
              <ReactECharts option={item.genChart && JSON.parse(item.genChart)} />
              <p
                style={{
                  textAlign: 'center',
                  fontWeight: 'bold',
                  color: '#e617ff',
                  fontSize: '16px',
                }}
              >
                {'图表名称:' + item.name}
              </p>
              <Divider style={{ fontWeight: 'bold', color: 'blue', fontSize: '16px' }}>
                智能分析结果
              </Divider>
              <p style={{ fontWeight: 'bold', color: '#0b93a1' }}>{item.getResult}</p>
              <Row justify="end">
                <Col>
                  <Button danger onClick={() => handleDelete(item.id)}>
                    删除
                  </Button>
                </Col>
              </Row>
            </Card>
          </List.Item>
        )}
      />
    </div>
  );
};
export default MyChartPage;

尚且不懂知识点记录

  1. react的数据状态:

    //定义了一个searchParams的变量
    const [searchParams,setSearchParams] = useState<Api.ChartQueryRequest>({
        ...initSearchParams, //初始值设置,每页12条,...initSearchParams把此对象展开成新的对象,不会由对象污染
      });
    
    //定义变量存前端展示的数据,从数据返回值中取得数据
    const [chartList, setChartList] = useState<API.Chart[]>();
    
    //定义变量存储数据总数
    const [total,setTotal] = useState<number>(0);
    
    
  2. idea快捷键:

    • 快速生成try-catch的快捷键:ctrl+alt+t
    • 格式化代码:ctrl+alt+l
  3. 原子化css

    通过className组合出一套组件


http://www.kler.cn/news/161707.html

相关文章:

  • webpack学习-3.管理输出
  • vue中对pdf文件和路径的处理
  • 采样率越高噪声越大?
  • GO设计模式——13、享元模式(结构型)
  • node.js出现version `GLIBC_2.27‘ not found的解决方案
  • oomall课堂笔记
  • 软考2018下午第六题改编逻辑(状态模式)
  • 【动手学深度学习】(十)PyTorch 神经网络基础+GPU
  • QT Windos平台下打包应用程序
  • CSM2433 一款集成2.4G+125K 和8位RISC 的SOC芯片
  • 临时或永久修改linux-kali虚拟机的主机名和遇见的错误解决方法(保姆级图文)【网络工程】
  • 流量分析1--菜刀666
  • [ES]ElasticSearch强转日期的时区问题
  • 备忘录怎么传到电脑?备忘录手机电脑互传方法
  • echarts图之 底部滚动横轴 缩放图形大小
  • 软件开发安全指南
  • IDEA 保存自动ESLint格式化
  • python 涉及opencv mediapipe知识,眨眼计数 供初学者参考
  • 【Linux】进程通信之命名管道mkfifo
  • 【设计模式-3.1】结构型——外观模式
  • GO设计模式——5、建造者模式(创建型)
  • 深眸科技以机器视觉高性能优势,为消费电子行业提供优质解决方案
  • vuepress路径问题,导致图片不显示
  • 十一.图像处理与光学之图像缩放方式
  • Course2-Week3-使用机器学习的建议
  • 【开源】基于Vue.js的二手车交易系统
  • 力扣102. 二叉树的层序遍历
  • GO设计模式——14、代理模式(结构型)
  • 【深度学习】迁移学习中的领域转移及迁移学习的分类
  • 2024山东健博会,第六届济南国际大健康产业博览会5月举办