FZU Meteorological Bureau —— EE308FZ_Fifth Assignment_Alpha Sprint_Sprint Essay 2

Assignment 5 Alpha Sprint
Course EE308FZ — Software Engineering
Class Link 2501_MU_SE_FZU
Requirements Fifth Assignment——Alpha Sprint
Team Name FZU Meteorological Bureau
Objective Sprint Essay 2_Day3-Day4 (12.14-12.15)
Other Reference 1. JavaScript Style guide 2. The Art of Construction 3. Vue Guide 4. Springboot Construction Guide

Catalog

I. Project Burn-up Chart
II. Latest Running Gif of the Project Module
1. The background management interface and air quality entry module are displayed
III. The Development Team Conducts Code Checks
2. The front end of the background management interface
3. Air quality Front-end management module
4. Air quality backend interface
IV. Evaluation of Teammates

I. Project Burn-up Chart

Burn-up Chart

II. Latest Running Gif of the Project Module

  • Our user interface design team and front-end development team have developed the air quality display component and some back-end management modules, including the design of the data visualization module and dynamic data presentation logic, which are consistent with the overall interface style of the system.
  • Our back-end development team has completed API integration and adaptation, including interface authentication, data format conversion, and handling of abnormal data (such as API timeouts and data return errors), reducing repeated API calls and improving data response speed.
  • Our test optimization team has completed the testing of the front-end management module and the air quality detection interface, but found that there are still problems with manual air quality entry. We hope to solve them throughout the Alpha sprint stage.

1. The background management interface and air quality entry module are displayed

  • Background management interface and air quality manual video entry

2025-12-14 18-42-22

  • Backend database field storage
/*Table structure for table `air_quality` */

DROP TABLE IF EXISTS `air_quality`;

CREATE TABLE `air_quality` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `city_name` varchar(50) NOT NULL COMMENT '城市名称',
  `province` varchar(50) NOT NULL COMMENT '省份',
  `aqi` int NOT NULL COMMENT 'AQI指数',
  `air_quality_level` varchar(20) NOT NULL COMMENT '空气质量等级(优/良/轻度污染/中度污染/重度污染/严重污染)',
  `primary_pollutant` varchar(50) NOT NULL COMMENT '首要污染物',
  `pm25` decimal(5,2) NOT NULL COMMENT 'PM2.5浓度(μg/m³)',
  `pm10` decimal(5,2) NOT NULL COMMENT 'PM10浓度(μg/m³)',
  `update_time` datetime NOT NULL COMMENT '更新时间',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `air_quality` */

insert  into `air_quality`(`id`,`city_name`,`province`,`aqi`,`air_quality_level`,`primary_pollutant`,`pm25`,`pm10`,`update_time`,`create_time`) values 
(1,'北京','北京市',45,'优','PM2.5',32.00,56.00,'2025-11-20 21:36:52','2025-11-04 14:55:54'),
(2,'上海','上海市',68,'良','PM10',48.00,72.00,'2025-11-20 21:36:52','2025-11-04 14:55:54'),
(3,'深圳','广东省',35,'优','O₃',22.00,38.00,'2025-11-20 21:36:52','2025-11-04 14:55:54'),
(4,'成都','四川省',85,'良','PM2.5',62.00,98.00,'2025-11-20 21:36:52','2025-11-04 14:55:54'),
(5,'杭州','浙江省',52,'良','PM2.5',36.00,58.00,'2025-11-20 21:36:52','2025-11-04 14:55:54'),
(6,'西安','陕西省',120,'轻度污染','PM10',88.00,135.00,'2025-11-20 21:36:52','2025-11-04 14:55:54'),
(7,'厦门','福建省',28,'优','O₃',18.00,32.00,'2025-11-20 21:36:52','2025-11-04 14:55:54'),
(8,'武汉','湖北省',78,'良','PM2.5',56.00,84.00,'2025-11-20 21:36:52','2025-11-04 14:55:54'),
(9,'1','1',1,'优','1',1.00,1.00,'2025-11-20 21:36:52','2025-11-20 21:14:28');
  • We found that the field still doesn’t show up on the frontend when the database already exists, which is an issue that needs to be addressed.
    前端界面

III. The Development Team Conducts Code Checks

图片1
图片2

2. The front end of the background management interface

code

<template>
  <div>

<!--  后台菜单管理-->
    <div style="margin: 10px 0">
      <el-input style="width: 200px" placeholder="请输入名称" suffix-icon="el-icon-search" v-model="name"></el-input>
<!--      <el-input style="width: 200px" placeholder="请输入邮箱" suffix-icon="el-icon-message" class="ml-5" v-model="email"></el-input>-->
<!--      <el-input style="width: 200px" placeholder="请输入地址" suffix-icon="el-icon-position" class="ml-5" v-model="address"></el-input>-->
      <el-button class="ml-5" type="primary" @click="load">搜索</el-button>
      <el-button type="warning" @click="reset">重置</el-button>
    </div>

    <div style="margin: 10px 0">
      <el-button type="primary" @click="handleAdd(null)">新增 <i class="el-icon-circle-plus-outline"></i></el-button>
      <el-popconfirm
          class="ml-5"
          confirm-button-text='确定'
          cancel-button-text='我再想想'
          icon="el-icon-info"
          icon-color="red"
          title="您确定批量删除这些数据吗?"
          @confirm="delBatch"
      >
        <el-button type="danger" slot="reference">批量删除 <i class="el-icon-remove-outline"></i></el-button>
      </el-popconfirm>
<!--      <el-upload action="http://localhost:9090/user/import" :show-file-list="false" accept="xlsx" :on-success="handleExcelImportSuccess" style="display: inline-block">-->
<!--        <el-button type="primary" class="ml-5">导入 <i class="el-icon-bottom"></i></el-button>-->
<!--      </el-upload>-->
<!--      <el-button type="primary" @click="exp" class="ml-5">导出 <i class="el-icon-top"></i></el-button>-->
    </div>

    <el-table :data="tableData" border stripe :header-cell-class-name="'headerBg'"
              row-key="id" default-expand-all @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55"></el-table-column>
      <el-table-column prop="id" label="ID" width="80"></el-table-column>
      <el-table-column prop="name" label="名称"></el-table-column>
      <el-table-column prop="path" label="路径"></el-table-column>
      <el-table-column prop="pagePath" label="页面路径"></el-table-column>
      <el-table-column label="图标" class-name="fontSize18" align="center" label-class-name="fontSize12">
        <template slot-scope="scope">
          <span :class="scope.row.icon" />
        </template>
      </el-table-column>
      <el-table-column prop="description" label="描述"></el-table-column>
      <el-table-column prop="sortNum" label="顺序"></el-table-column>
      <el-table-column label="操作"  width="300" align="center">
        <template slot-scope="scope">
          <el-button type="primary" @click="handleAdd(scope.row.id)" v-if="!scope.row.pid && !scope.row.path">新增子菜单 <i class="el-icon-plus"></i></el-button>
          <el-button type="success" @click="handleEdit(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
          <el-popconfirm
              class="ml-5"
              confirm-button-text='确定'
              cancel-button-text='我再想想'
              icon="el-icon-info"
              icon-color="red"
              title="您确定删除吗?"
              @confirm="del(scope.row.id)"
          >
            <el-button type="danger" slot="reference">删除 <i class="el-icon-remove-outline"></i></el-button>
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>

    <el-dialog title="菜单信息" :visible.sync="dialogFormVisible" width="30%" >
      <el-form label-width="80px" size="small">
        <el-form-item label="名称">
          <el-input v-model="form.name" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="路径">
          <el-input v-model="form.path" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="页面路径">
          <el-input v-model="form.pagePath" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="图标">
          <el-select clearable v-model="form.icon" placeholder="请选择" style="width: 100%">
            <el-option v-for="item in options" :key="item.name" :label="item.name" :value="item.value">
              <i :class="item.value" /> {{ item.name }}
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="顺序">
          <el-input v-model="form.sortNum" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="描述">
          <el-input v-model="form.description" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="save">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import {serverIp} from "../../public/config";

export default {
  name: "Menu",
  data() {
    return {
      tableData: [],
      total: 0,
      pageNum: 1,
      pageSize: 10,
      name: "",
      form: {},
      dialogFormVisible: false,
      multipleSelection: [],
      options: []
    }
  },
  created() {
    this.load()
  },
  methods: {
    load() {
      this.request.get("/menu", {
        params: {
          name: this.name,
        }
      }).then(res => {
        this.tableData = res.data
      })

      // 请求图标的数据
      this.request.get("/menu/icons").then(res => {
        this.options = res.data
      })
    },
    save() {
      this.request.post("/menu", this.form).then(res => {
        if (res.code === '200') {
          this.$message.success("保存成功")
          this.dialogFormVisible = false
          this.load()
        } else {
          this.$message.error("保存失败")
        }
      })
    },
    handleAdd(pid) {
      this.dialogFormVisible = true
      this.form = {}
      if (pid) {
        this.form.pid = pid
      }
    },
    handleEdit(row) {
      this.form = JSON.parse(JSON.stringify(row))
      this.dialogFormVisible = true
    },
    del(id) {
      this.request.delete("/menu/" + id).then(res => {
        if (res.code === '200') {
          this.$message.success("删除成功")
          this.load()
        } else {
          this.$message.error("删除失败")
        }
      })
    },
    handleSelectionChange(val) {
      console.log(val)
      this.multipleSelection = val
    },
    delBatch() {
      let ids = this.multipleSelection.map(v => v.id)  // [{}, {}, {}] => [1,2,3]
      this.request.post("/menu/del/batch", ids).then(res => {
        if (res.code === '200') {
          this.$message.success("批量删除成功")
          this.load()
        } else {
          this.$message.error("批量删除失败")
        }
      })
    },
    reset() {
      this.name = ""
      this.load()
    },
    handleSizeChange(pageSize) {
      console.log(pageSize)
      this.pageSize = pageSize
      this.load()
    },
    handleCurrentChange(pageNum) {
      console.log(pageNum)
      this.pageNum = pageNum
      this.load()
    },
    exp() {
      window.open(`http://${serverIp}:9090/role/export`)
    },
    handleExcelImportSuccess() {
      this.$message.success("导入成功")
      this.load()
    }
  }
}
</script>


<style scoped>
.headerBg {
  background: #eee!important;
}
.fontSize18{
  font-size: 18px;
}
.fontSize12{
  font-size: 12px;
}
</style>

3. Air quality Front-end management module

code

<template>
  <div>
    <!-- 搜索区域 -->
    <div style="margin: 10px 0">
      <el-input style="width: 200px" placeholder="请输入城市名称" suffix-icon="el-icon-search" v-model="searchForm.cityName"></el-input>
      <el-input style="width: 200px" placeholder="请输入省份" v-model="searchForm.province" class="ml-5"></el-input>
      <el-select style="width: 200px" placeholder="请选择质量等级" v-model="searchForm.airQualityLevel" class="ml-5" clearable>
        <el-option label="" value=""></el-option>
        <el-option label="" value=""></el-option>
        <el-option label="轻度污染" value="轻度污染"></el-option>
        <el-option label="中度污染" value="中度污染"></el-option>
        <el-option label="重度污染" value="重度污染"></el-option>
        <el-option label="严重污染" value="严重污染"></el-option>
      </el-select>
      <el-button class="ml-5" type="primary" @click="load">搜索</el-button>
      <el-button type="warning" @click="reset">重置</el-button>
    </div>

    <!-- 操作按钮区域 -->
    <div style="margin: 10px 0">
      <el-button type="primary" @click="handleAdd">新增 <i class="el-icon-circle-plus-outline"></i></el-button>
      <el-popconfirm
          class="ml-5"
          confirm-button-text='确定'
          cancel-button-text='我再想想'
          icon="el-icon-info"
          icon-color="red"
          title="您确定批量删除这些数据吗?"
          @confirm="delBatch"
      >
        <el-button type="danger" slot="reference">批量删除 <i class="el-icon-remove-outline"></i></el-button>
      </el-popconfirm>
    </div>

    <!-- 数据表格 -->
    <el-table :data="tableData" border stripe :header-cell-class-name="'headerBg'"  @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55"></el-table-column>
      <el-table-column prop="id" label="ID" width="80" sortable></el-table-column>
      <el-table-column prop="cityName" label="城市名称" width="120"></el-table-column>
      <el-table-column prop="province" label="省份" width="120"></el-table-column>
      <el-table-column prop="aqi" label="AQI指数" width="100" sortable></el-table-column>
      <el-table-column prop="airQualityLevel" label="质量等级" width="120">
        <template slot-scope="scope">
          <el-tag :type="getLevelType(scope.row.airQualityLevel)">{{ scope.row.airQualityLevel }}</el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="primaryPollutant" label="主要污染物" width="150"></el-table-column>
      <el-table-column prop="pm25" label="PM2.5" width="100" sortable></el-table-column>
      <el-table-column prop="pm10" label="PM10" width="100" sortable></el-table-column>
      <el-table-column prop="updateTime" label="更新时间" width="180"></el-table-column>

      <el-table-column label="操作" width="200" align="center">
        <template slot-scope="scope">
            <el-button type="success" @click="handleEdit(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
            <el-popconfirm
                class="ml-5"
                confirm-button-text='确定'
                cancel-button-text='我再想想'
                icon="el-icon-info"
                icon-color="red"
                title="您确定删除吗?"
                @confirm="del(scope.row.id)"
            >
                <el-button type="danger" slot="reference">删除 <i class="el-icon-remove-outline"></i></el-button>
            </el-popconfirm>
          </template>
      </el-table-column>
    </el-table>

    <!-- 分页组件 -->
    <div style="padding: 10px 0">
      <el-pagination
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page="pageNum"
          :page-sizes="[5, 10, 15, 20]"
          :page-size="pageSize"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total">
      </el-pagination>
    </div>

    <!-- 新增/编辑对话框 -->
    <el-dialog :title="dialogTitle" :visible.sync="dialogFormVisible" width="40%" :close-on-click-modal="false">
      <el-form label-width="120px" size="small" style="width: 85%;" :model="form" :rules="rules" ref="ruleForm">
        <el-form-item prop="cityName" label="城市名称">
          <el-input v-model="form.cityName" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item prop="province" label="省份">
          <el-input v-model="form.province" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item prop="aqi" label="AQI指数">
          <el-input-number v-model="form.aqi" :min="0" :max="500" controls-position="right" style="width: 100%"></el-input-number>
        </el-form-item>
        <el-form-item prop="airQualityLevel" label="质量等级">
          <el-select v-model="form.airQualityLevel" placeholder="请选择质量等级" style="width: 100%">
            <el-option label="" value=""></el-option>
            <el-option label="" value=""></el-option>
            <el-option label="轻度污染" value="轻度污染"></el-option>
            <el-option label="中度污染" value="中度污染"></el-option>
            <el-option label="重度污染" value="重度污染"></el-option>
            <el-option label="严重污染" value="严重污染"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item prop="primaryPollutant" label="主要污染物">
          <el-input v-model="form.primaryPollutant" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item prop="pm25" label="PM2.5浓度">
          <el-input-number v-model="form.pm25" :min="0" :max="500" :step="0.1" controls-position="right" style="width: 100%"></el-input-number>
        </el-form-item>
        <el-form-item prop="pm10" label="PM10浓度">
          <el-input-number v-model="form.pm10" :min="0" :max="600" :step="0.1" controls-position="right" style="width: 100%"></el-input-number>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="save">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  name: "AirQuality",
  data() {
    return {
      tableData: [],
      total: 0,
      pageNum: 1,
      pageSize: 10,
      searchForm: {
        cityName: "",
        province: "",
        airQualityLevel: ""
      },
      form: {},
      dialogFormVisible: false,
      multipleSelection: [],
      dialogTitle: "新增空气质量数据",
      rules: {
        cityName: [
          { required: true, message: '请输入城市名称', trigger: 'blur' }
        ],
        province: [
          { required: true, message: '请输入省份', trigger: 'blur' }
        ],
        aqi: [
          { required: true, message: '请输入AQI指数', trigger: 'blur' },
          { type: 'number', min: 0, max: 500, message: 'AQI指数应在0-500之间', trigger: 'blur' }
        ],
        airQualityLevel: [
          { required: true, message: '请选择空气质量等级', trigger: 'change' }
        ]
      }
    }
  },
  created() {
    this.load()
  },
  methods: {
    // 加载数据
    load() {
      this.request.get("/airQuality/page", {
        params: {
          pageNum: this.pageNum,
          pageSize: this.pageSize,
          cityName: this.searchForm.cityName,
          province: this.searchForm.province,
          airQualityLevel: this.searchForm.airQualityLevel
        }
      }).then(res => {
        this.tableData = res.data.records
        this.total = res.data.total
      })
    },
    
    // 保存数据(新增或编辑)
    save() {
      this.$refs['ruleForm'].validate((valid) => {
        if (valid) {
          // 根据是否有id判断是新增还是编辑
          const requestMethod = this.form.id ? this.request.put : this.request.post;
          const successMessage = this.form.id ? "更新成功" : "新增成功";
          
          requestMethod("/airQuality", this.form).then(res => {
            if (res.code === '200') {
              this.$message.success(successMessage)
              this.dialogFormVisible = false
              this.load()
            } else {
              this.$message.error(res.msg)
            }
          })
        }
      })
    },
    
    // 新增数据
    handleAdd() {
      this.dialogTitle = "新增空气质量数据"
      this.dialogFormVisible = true
      this.form = {}
    },
    
    // 编辑数据
    handleEdit(row) {
      this.dialogTitle = "编辑空气质量数据"
      this.form = JSON.parse(JSON.stringify(row))
      this.dialogFormVisible = true
    },
    
    // 删除单条数据
    del(id) {
      this.request.delete("/airQuality/" + id).then(res => {
        if (res.code === '200') {
          this.$message.success("删除成功")
          this.load()
        } else {
          this.$message.error("删除失败")
        }
      })
    },
    
    // 处理表格多选
    handleSelectionChange(val) {
      this.multipleSelection = val
    },
    
    // 批量删除
    delBatch() {
      if (!this.multipleSelection.length) {
        this.$message.error("请选择需要删除的数据")
        return
      }
      let ids = this.multipleSelection.map(v => v.id)
      this.request.post("/airQuality/del/batch", ids).then(res => {
        if (res.code === '200') {
          this.$message.success("批量删除成功")
          this.load()
        } else {
          this.$message.error("批量删除失败")
        }
      })
    },
    
    // 重置搜索条件
    reset() {
      this.searchForm = {
        cityName: "",
        province: "",
        airQualityLevel: ""
      }
      this.load()
    },
    
    // 分页大小改变
    handleSizeChange(pageSize) {
      this.pageSize = pageSize
      this.load()
    },
    
    // 当前页码改变
    handleCurrentChange(pageNum) {
      this.pageNum = pageNum
      this.load()
    },
    
    // 导出数据
    exp() {
      window.open("http://localhost:9090/airQuality/export")
    },
    
    // 根据空气质量等级返回对应的标签类型
    getLevelType(level) {
      switch(level) {
        case '优': return 'success'
        case '良': return 'primary'
        case '轻度污染': return 'warning'
        case '中度污染': return 'warning'
        case '重度污染': return 'danger'
        case '严重污染': return 'danger'
        default: return 'info'
      }
    }
  }
}
</script>

<style scoped>
.headerBg {
  background: #eee!important;
}
.ml-5 {
  margin-left: 5px;
}
</style>

4. Air quality detection module display code

  • Backend Controller layer (core: interface entrance)
package com.chen.springboot.controller;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chen.springboot.common.Result;
import com.chen.springboot.common.util.SensitivewordFilter;
import com.chen.springboot.entity.Activity;
import com.chen.springboot.entity.Follow;
import com.chen.springboot.service.IActivityService;
import com.chen.springboot.service.IFollowService;
import com.chen.springboot.utils.Date2Util;
import com.chen.springboot.utils.TokenUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author 
 * @since 2025-11-04
 */
@RestController
@RequestMapping("/activity")
public class
ActivityController {

    @Resource
    private IActivityService activityService;

    @Autowired
    private SensitivewordFilter sensitivewordFilter;

    @Resource
    private IFollowService followService;

    // 新增或者更新
    @PostMapping
    public Result save(@RequestBody Activity articles) {
        if (articles.getId() == null) { // 新增
            articles.setTime(DateUtil.now());  // new Date()
            articles.setUsername(TokenUtils.getCurrentUser().getUsername());//填入当前登录用户的昵称
            articles.setUserId(TokenUtils.getCurrentUser().getId());//填入当前登录用户的id
            articles.setUserAvatar(TokenUtils.getCurrentUser().getAvatarUrl()); //填入当前登录用户的头像
        }

        articles.setSurplusNum(articles.getActivityNum());

        String content = articles.getContent();
        String title = articles.getTitle();
        String wordsContent = sensitivewordFilter.filterSensitiveWords(content);
        articles.setContent(wordsContent);
        String wordsTitle = sensitivewordFilter.filterSensitiveWords(title);
        articles.setTitle(wordsTitle);
        articles.setSurplusNum(articles.getActivityNum());

        activityService.saveOrUpdate(articles);
        return Result.success();
    }
    //删除
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        activityService.removeById(id);
        return Result.success();
    }
    //批量删除
    @PostMapping("/del/batch")
    public Result deleteBatch(@RequestBody List<Integer> ids) {
        activityService.removeByIds(ids);
        return Result.success();
    }

    @GetMapping("/exame")
    public Result exame(
            @RequestParam Long id,
            @RequestParam Integer status) {
        Activity activity = new Activity();
        activity.setId(id);
        activity.setStatus(status);
        //验证时间,时间超过了报名时间就不能再审核了
        Activity activity1 = activityService.getById(id);

        String nowTime = DateUtil.now();

        String signEndTime = activity1.getSignEndTime();

        //报名时间超过了,也不能报名
        int compare = Date2Util.compareDate(nowTime, signEndTime);
        if(compare == 1){
            activity.setStatus(3);
        }

        activityService.updateById(activity);
        return Result.success();
    }

    //查询所有
    @GetMapping
    public Result findAll() {
        return Result.success(activityService.list());
    }

    //通过id查询
    @GetMapping("/{id}")
    public Result findOne(@PathVariable Integer id) {
        return Result.success(activityService.getById(id));
    }


    //后台:分页查询和按照文章名查询
    @GetMapping("/page")
    public Result findPage(@RequestParam (defaultValue = "") String title,
                           @RequestParam (defaultValue = "") String category,
                           @RequestParam Integer pageNum,
                           @RequestParam Integer pageSize) {
        QueryWrapper<Activity> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");  //按照id倒序排序

        if (StrUtil.isNotBlank(title)) {         // 标题模糊查询
            queryWrapper.like("title", title);
        }
        if (StrUtil.isNotBlank(category)) {         //分类模糊查询
            queryWrapper.like("category ", category);
        }
        //queryWrapper.eq("status",1);
        return Result.success(activityService.page(new Page<>(pageNum, pageSize), queryWrapper));
    }

    //首页:论坛,可以添加关注
    @GetMapping("/homepage")
    public Result findPage2(@RequestParam (defaultValue = "") String title,
                           @RequestParam (defaultValue = "") String category,
                           @RequestParam Integer pageNum,
                           @RequestParam Integer pageSize) {
        QueryWrapper<Activity> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");  //按照id倒序排序

        if (StrUtil.isNotBlank(title)) {         //标题模糊查询
            queryWrapper.like("title", title);
        }
        if (StrUtil.isNotBlank(category)) {         //分类模糊查询
            queryWrapper.like("category ", category);
        }
        queryWrapper.eq("status",1);
        Page<Activity> page = activityService.page(new Page<>(pageNum, pageSize), queryWrapper);


        return Result.success(page);
    }

    //我发布的帖子
    @GetMapping("/selfpage")
    public Result selfpage(@RequestParam (defaultValue = "") String title,
                           @RequestParam (defaultValue = "") String category,
                           @RequestParam Integer pageNum,
                           @RequestParam Integer pageSize) {

        String username = TokenUtils.getCurrentUser().getUsername();

        QueryWrapper<Activity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",username);
        queryWrapper.orderByDesc("id");  //按照id倒序排序

        if (StrUtil.isNotBlank(title)) {         // 标题模糊查询
            queryWrapper.like("title", title);
        }
        if (StrUtil.isNotBlank(category)) {         //分类模糊查询
            queryWrapper.like("category ", category);
        }
        return Result.success(activityService.page(new Page<>(pageNum, pageSize), queryWrapper));
    }

    //计算点赞数和阅读书
    @PutMapping ("/count")
    public Result count() {
        List<Activity> list = activityService.list();

        Map<String, List<Activity>> collect = list.stream().collect(Collectors.groupingBy(Activity::getUsername));

        Map<String, Integer> goodCount = new HashMap<>();  //点赞
        Map<String, Integer> readCount = new HashMap<>();   //阅读

        for (Map.Entry<String, List<Activity>> entry : collect.entrySet()) {

            int praiseSum = entry.getValue().stream().mapToInt(Activity::getGoodCount).sum();
            int readSum = entry.getValue().stream().mapToInt(Activity::getReadCount).sum();

            goodCount.put(entry.getKey(), praiseSum);
            readCount.put(entry.getKey(), readSum);
        }
        Map<String, Object> res = new HashMap<>();
        res.put("goodCount",goodCount);
        res.put("readCount", readCount);
        return Result.success(res);
    }

    //按照阅读数、点赞数、和时间 降序排序  分页进行查询
    @GetMapping("/read")
    public Result findReadPage(
                        @RequestParam Integer pageNum,
                       @RequestParam Integer pageSize) {
        QueryWrapper<Activity> queryWrapperRead = new QueryWrapper<>();
        queryWrapperRead.orderByDesc("read_count");  //按照阅读数倒序排序

        return Result.success(activityService.page(new Page<>(pageNum, pageSize), queryWrapperRead));
    }

    @GetMapping("/good")
    public Result findGoodPage(
            @RequestParam Integer pageNum,
            @RequestParam Integer pageSize) {
        QueryWrapper<Activity> queryWrapperGood = new QueryWrapper<>();
        queryWrapperGood.orderByDesc("good_count");  //按照点赞数倒序排序

        return Result.success(activityService.page(new Page<>(pageNum, pageSize), queryWrapperGood));
    }

    @GetMapping("/date")
    public Result findDatePage(
            @RequestParam Integer pageNum,
            @RequestParam Integer pageSize) {

        QueryWrapper<Activity> queryWrapperTime = new QueryWrapper<>();
        queryWrapperTime.orderByDesc("time");  //按照发布时间倒序排序

        return Result.success(activityService.page(new Page<>(pageNum, pageSize), queryWrapperTime));
    }


}


  • Service layer (core: business logic)
package com.chen.springboot.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.chen.springboot.entity.Activity;
import com.chen.springboot.entity.AirQuality;

/**
 * <p>
 *  服务类
 * </p>
 *
 * @author 
 * @since 2025-11-04
 */
public interface IAirQualityService extends IService<AirQuality> {

}

IV. Evaluation of Teammates

学号 姓名 职责 贡献
832301213 Chen Ye Responsible for the overall planning, schedule management and team coordination of the project; Lead the writing, integration and finalization of all project documents 10%
832301102 Wang Jiarui Responsible for front-end routing design and control logic implementation 8%
832301118 Li Yifei up the scaffolding and development environment for the Vue project 8%
832301208 Zhang Shimin Responsible for page component development and style implementation; Customize system themes and layouts; Complete user interaction features 8%
832301113 Sun Chenen Build a Spring Boot multi-module project architecture 8%
832301214 Chen Xueting Implement the user login authentication module to complete the permission menu management function 8%
832301205 Zhang Zhikai Complete the development of core CRUD functions in the business; Write unit test cases; Ensure code quality 8%
832301109 Liu Zhongbo Integrated Redis caching capabilities; Realize file upload and download services; Optimize thread pool configuration 8%
832301210 Chen Hongyu Execution functional test cases; track and validate bug fixes; Write test reports 8%
832301228 Lin Juntian Conduct system performance testing; organize user acceptance tests; Collect user feedback 8%
832301115 Li Yuxin Design database table structure; Maintain a data dictionary 8%
832301225 Lin Qixuan Optimize database index configuration; Build a master-slave replication architecture; Develop a data backup strategy 10%
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐