main
Tomanage 2 months ago
parent 9c4bfe9b7b
commit 5e7a0bac1f

@ -0,0 +1,31 @@
/*
* Eslint config file
* Documentation: https://eslint.org/docs/user-guide/configuring/
* Install the Eslint extension before using this feature.
*/
module.exports = {
env: {
es6: true,
browser: true,
node: true,
},
ecmaFeatures: {
modules: true,
},
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
globals: {
wx: true,
App: true,
Page: true,
getCurrentPages: true,
getApp: true,
Component: true,
requirePlugin: true,
requireMiniProgram: true,
},
// extends: 'eslint:recommended',
rules: {},
}

14
前端/.gitignore vendored

@ -0,0 +1,14 @@
# Windows
[Dd]esktop.ini
Thumbs.db
$RECYCLE.BIN/
# macOS
.DS_Store
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
# Node.js
node_modules/

@ -0,0 +1,19 @@
// app.js
App({
onLaunch() {
// 展示本地存储能力
const logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)
// 登录
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
}
})
},
globalData: {
userInfo: null
}
})

@ -0,0 +1,22 @@
{
"pages": [
"pages/welcome/welcome",
"pages/call_roll/call_roll",
"pages/function/function",
"pages/class_manage/class_manage",
"pages/add_stu/add_stu",
"pages/class_message/class_message",
"pages/record/record",
"pages/index/index",
"pages/logs/logs"
],
"window": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "Weixin",
"navigationBarBackgroundColor": "#ffffff"
},
"style": "v2",
"componentFramework": "glass-easel",
"sitemapLocation": "sitemap.json",
"lazyCodeLoading": "requiredComponents"
}

@ -0,0 +1 @@
/**app.wxss**/

@ -0,0 +1,157 @@
// pages/addStudent/addStudent.js
Page({
data: {
className:"K班",
input: "",
students:[
]
},
onLoad: function(options) {
console.log(options);
// options 参数包含了从上一个页面传递过来的数据
const receivedClassName = options.className; // 获取传递过来的 className默认为空字符串
// 更新页面的数据
this.setData({
className: receivedClassName // 将接收到的 className 赋值给页面的 data 属性
});
console.log(this.data.className);
},
//获取输入框内容
onInput: function(e) {
console.log(e.detail.value)
this.setData({
input: e.detail.value//保存输入
});
},
// Excel文件导入
importExcel: function() {
const that = this;
wx.chooseMessageFile({
count: 1, // 默认为1设置选择文件的数量
type: 'file',
extension: ['xlsx'], // 指定文件的后缀名
success(res) {
const tempFiles = res.tempFiles; // 临时文件路径
const filePath = tempFiles[0].path; // 获取文件的路径
console.log(tempFiles);
that.readExcel(filePath); // 读取文件内容
},
fail(err) {
console.error('选择文件失败:', err);
}
});
},
// 读取Excel文件内容
readExcel(filePath) {
// 可以使用微信小程序的API或将文件上传到服务器解析
const that = this;
wx.uploadFile({
url: 'http://192.168.152.1:8090/excel/import', // 你的服务器上传地址
filePath: filePath,
name: 'file',
success: uploadRes => {
// 假设服务器返回解析后的 JSON 数据
const data = JSON.parse(uploadRes.data);
that.addStudents(data.students);
},
fail: uploadErr => {
console.error('文件上传失败:', uploadErr);
}
});
},
// 将解析后的学生数据添加到现有数组中
addStudents(newStudents) {
const currentStudents = this.data.students;
const allStudents = currentStudents.concat(newStudents); // 合并数组
this.setData({
students: allStudents
});
},
//点击输入框提示可以输入
focus: function(){
wx.showToast({
title: '可以开始输入了',
icon: 'none',
duration: 2000
});
},
cantNull: function(){
wx.showToast({
title: '输入框不可为空',
icon: 'none',
duration: 2000
});
},
addProcess: function(){
if(this.data.input != ""){
//分割字符串为数组
let firstArray = this.data.input.split("|");
console.log(firstArray);
let secondArray = firstArray.map(str => str.split(" "));
console.log(secondArray)
//遍历secondArray
secondArray.forEach(subArray => {
// 结构法从子数组中提取id和name
//等同于 const id = subArray[0]; const name = subArray[1];
const { [0]: id, [1]: name } = subArray;
// 创建一个新的对象来存储这些信息
const newStu = {
id: id,
name: name,
point: 10,
clazz: this.data.className,
};
const isDuplicate = this.data.students.some(stu => stu.id === id);
if(!isDuplicate){
// 将新对象发送到后端服务器
const classstu = newStu;
//classstu.className = this.data.className;//此时 classstu = {id:"102201",name:"Jhon", className:`${this.data.className}` }
wx.request({
url: 'http://192.168.152.1:8090/student/set',
method: 'POST', // 请求方法通常是POST用于发送数据
header: {
'Content-Type': 'application/json' // 设置请求头指定数据格式为JSON
},
data: newStu, // 要发送的数据这里直接传入对象wx.request会自动将其转换为JSON字符串后端接收json字符串
success: function(res) {
// 处理后端返回的响应
console.log('请求成功', res.data);
// 根据需要更新小程序页面的数据或执行其他操作
},
fail: function(err) {
// 处理请求失败的情况
console.error('请求失败', err);
// 可以向用户显示错误信息或执行其他错误处理操作
}
});
// 将新对象添加到data.stu数组中
this.setData({
['students[' + this.data.students.length + ']']: newStu //直接将新对象加在数组后面
});
} else {
console.log('id重复:${id}');
}
})
console.log(this.data.students);
} else {
this.cantNull();
}
},
goToclass_manage: function(){
wx.navigateTo({
url: '/pages/class_manage/class_manage'
});
}
});

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

@ -0,0 +1,12 @@
<view class="bg">
<image src="/pages/images/add_stu.png" mode="aspectFill"></image>
</view>
<view class="container">
<text class="header">添加学生</text>
<text class="tip">(添加学生学号 姓名用“|”隔开)</text>
<textarea class="stu_textarea" placeholder="如102201 Jhon|102202 kun" maxlength="100000000" bindinput="onInput" placeholder-style="color: black"
bindfocus="focus"/>
<button class="add" bindtap="addProcess">添加学生学号</button>
<button class="excel" bindtap="importExcel">Excel文件导入</button>
<button class="return" bindtap="goToclass_manage">返回</button>
</view>

@ -0,0 +1,111 @@
/* pages/add_stu/add_stu.wxss */
page{
width: 100%;
height: 100%;
}
.bg {
width: 100%;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: -1;
}
.bg image {
width: 100%;
height: 100%;
object-fit: cover;
}
.container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
padding: 0 0;
position: relative;
}
.header {
position: absolute;
top: 20rpx;
left: 20rpx;
font-size: 60rpx;
font-weight: bold;
color: rgb(0, 0, 0);
}
.tip {
position: absolute;
top:100rpx;
left: 20rpx;
font-size: 40rpx;
font-weight: bold;
color: rgb(0, 0, 0);
}
.stu_textarea {
position: absolute;
border: 5rpx solid rgb(252, 252, 252);
top: 180rpx;
left: 72rpx;
width: 80%;
box-sizing: border-box;
font-size: 40rpx;
height: 300rpx;
color: black;
}
.add {
position: absolute;
left: 200rpx;
top: 525rpx;
display: inline-block;
padding: 10rpx 50rpx; /* 调整内边距以改变按钮大小 */
font-size: 40rpx;
color: rgba(0, 0, 0, 1);
background-color: #ffae0060; /* 按钮背景色 */
border: none;
border-radius: 100rpx; /* 初始设置为圆角矩形 */
text-align: center;
text-decoration: none;
overflow: hidden; /* 隐藏超出按钮范围的内容 */
}
.add:before {
left: -10rpx; /* 圆形部分在按钮左侧的位置 */
}
.add:after {
right: -10px; /* 圆形部分在按钮右侧的位置 */
}
.add:hover {
background-color: #00b30f3d; /* 鼠标悬停时按钮的背景色 */
}
.add:hover:before,
.add:hover:after {
background-color: #00b31e5e; /* 鼠标悬停时圆形部分的背景色 */
}
.excel {
background-color: rgba(255, 166, 0, 0.486);
position: absolute;
padding: 0 0;
margin: 0 0;
width: 600rpx;
top: 800rpx;
left: 200rpx;
font-size: 60rpx;
}
.return {
position: absolute;
width: 200rpx;
height: 100rpx;
bottom: 100rpx;
right: 100rpx;
font-size: 60rpx;
background-color: rgba(255, 0, 0, 0.384);
}

@ -0,0 +1,179 @@
// pages/call_roll/call_roll.js
Page({
/**
* 页面的初始数据
*/
data: {
className: "",
students:[
{
id: "102201",
name: "Jhon",
point: 3
},
{
id: "102202",
name: "Kun",
point: 2
},
{
id: "102203",
name: "Tom",
point: 2
},
],
rolling: false, // 控制是否滚动
currentStudentIndex: 0, // 当前选中学生索引
currentStudentName: "开始点名", // 当前显示的学生名称
rollInterval: null, // 随机点名的定时器
point: 1, // 设置的积分
},
onLoad: function (options) {
clearInterval(this.data.rollInterval);//清除定时器,防止内存泄漏
console.log(options);
// options 参数包含了从上一个页面传递过来的数据
const receivedClassName = options.className; // 获取传递过来的 className默认为空字符串
// 更新页面的数据
this.setData({
className: receivedClassName // 将接收到的 className 赋值给页面的 data 属性
});
// const url = `https://your-backend-server.com/api/students?className=${this.data.className}`
//根据className向后端请求数据
wx.request({
url: `http://192.168.152.1:8090/student/${this.data.className}`,
method: 'GET',
success: function(res) {
// 后端返回的数据格式如下:
// {
// students: [
// { id: "102201", name: "Jhon", point: 3 },
// { id: "102202", name: "Kun", point: 2 },
// { id: "102203", name: "Tom", point: 1 }
// ]
// }
if (res.statusCode === 200 && Array.isArray(res.data)) {
// 使用setData方法更新data内的students数组
this.setData({
students: res.data
});
} else {
console.error('请求成功但数据格式不正确或数据不是数组');
}
}.bind(this), // 注意这里使用.bind(this)来确保this指向当前页面实例
fail: function(err) {
console.error('请求失败', err);
}
});
},
setPoint: function(e) {
const value = e.detail.value;
// 简单的正则表达式验证,允许负号和数字
if (/^-?\d+(\.\d+)?$/.test(value)) {
this.setData({
point: value //string类型
});
} else {
// 如果输入无效,可以重置输入框的内容或显示提示
wx.showToast({
title: '请输入有效的数字',
icon: 'none'
});
}
},
// 切换随机点名
toggleRoll: function() {
const { rolling, students, point } = this.data;
if (!rolling) {
this.setData({
currentStudentName: students[0].name, // 设置初始显示的学生名称
});
}
const newRolling = !rolling;
if (newRolling) {
this.startRoll();
} else {
console.log(this.data.currentStudentName)
clearInterval(this.data.rollInterval);
}
this.setData({
rolling: newRolling
});
},
// 开始随机点名
startRoll: function() {
const { students, point } = this.data;
let { currentStudentIndex } = this.data;
const rollInterval = setInterval(() => {
const totalPoints = students.reduce((acc, student) => acc + student.point, 0);
let randomPoint = Math.random() * totalPoints;
let sum = 0;
for (let i = 0; i < students.length; i++) {
sum += students[i].point;
if (randomPoint < sum) {
currentStudentIndex = i;
break;
}
}
this.setData({
currentStudentIndex,
currentStudentName: students[currentStudentIndex].name
});
}, 100); // 每100毫秒更新一次
this.setData({
rollInterval
});
},
confirmPoint: function() {
const Point = parseInt(this.data.point);
const id = this.data.students[this.data.currentStudentIndex].id;
let finalPoint = this.data.students[this.data.currentStudentIndex].point + Point;
if(finalPoint % 13 === 0){
finalPoint += 1; //积分等于13的整数倍加一分
wx.showToast({
title: '恭喜您触发彩蛋,积分额外+1',
icon: '/pages/images/eggs.png'
});
}
// this.data.students[this.data.currentStudentIndex].point += point; 不会重新渲染视图
this.setData({
['students[' + this.data.currentStudentIndex + '].point']: finalPoint //会重新更新并渲染视图
});
const newStu = this.data.students[this.data.currentStudentIndex];
//发送请求更新后端数据
console.log(newStu);
wx.request({
url: 'http://192.168.152.1:8090/student/update',
method: 'PUT',
data: {
point: newStu.point,
name: newStu.name //只发送修改对象
},
header: {
'Content-Type': 'application/json' // 设置请求头指定数据格式为JSON
},
success: function(res) {
// 处理后端返回的响应
console.log('发送成功', res.data);
// 根据需要更新小程序页面的数据或执行其他操作
},
fail: function(err) {
// 处理请求失败的情况
console.error('发送失败', err);
// 可以向用户显示错误信息或执行其他错误处理操作
}
});
},
goTofunction:function(){
wx.navigateTo({
url: '/pages/function/function',
});
},
})

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

@ -0,0 +1,17 @@
<!--pages/call_roll/call_roll.wxml-->
<view class="bg">
<image src="/pages/images/call_roll.png" mode="aspectFill"></image>
</view>
<view class="container">
<view class="student-name">{{currentStudentName}}</view>
<view class="student-list">
<block wx:for="{{students}}" wx:key="id">
<view class="student-item {{index === currentStudentIndex ? 'selected' : ''}}">{{name}}</view>
</block>
<button bindtap="toggleRoll" data-rolling="{{rolling}}">{{rolling ? '暂停' : '开始'}}随机点名</button>
</view>
<text class="tip">积分设置:</text>
<input class="number" input type="text" bindinput="setPoint" value="{{point}}"/>
<button class="confirmPoint" bindtap="confirmPoint">确认</button>
<button class="return" bindtap="goTofunction">返回</button>
</view>

@ -0,0 +1,113 @@
/* pages/call_roll/call_roll.wxss */
.bg {
width: 100%;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: -1;
}
.bg image {
width: 100%;
height: 100%;
object-fit: cover;
}
.container {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
padding: 0 0;
position: relative;
}
.student-list {
top: 400rpx;
left: 220rpx;
position: absolute;
display: flex;
flex-direction: column;
}
.student-list button{
position: absolute;
top: 100rpx;
background-color: rgba(234, 0, 255, 0.171);
}
.student-item {
margin-bottom: 20rpx;
opacity: 0.5; /* 默认透明度 */
}
.selected {
opacity: 1; /* 选中的透明度 */
font-weight: bold;
}
.student-name {
position: absolute;
top: 100rpx;
left: 220rpx;
font-size: 80rpx;
text-align: center;
margin: 20rpx 0;
font-weight: bold;
}
.tip {
font-size: 40rpx;
position: absolute;
top: 623rpx;
left: 200rpx;
}
.number {
height: 100rpx;
font-size: 40rpx;
position: absolute;
top: 600rpx;
left: 400rpx;
}
.confirmPoint {
position: absolute;
top: 700rpx;
left: 220rpx;
background-color: rgba(222, 184, 135, 0.699);
}
.return {
position: absolute;
right: 10rpx;
bottom: 40rpx;
display: inline-block;
padding: 10rpx 50rpx; /* 调整内边距以改变按钮大小 */
font-size: 40rpx;
color: rgba(0, 0, 0, 1);
background-color: #ffae00; /* 按钮背景色 */
border: none;
border-radius: 100rpx; /* 初始设置为圆角矩形 */
text-align: center;
text-decoration: none;
overflow: hidden; /* 隐藏超出按钮范围的内容 */
}
.return:before {
left: -10rpx; /* 圆形部分在按钮左侧的位置 */
}
.return:after {
right: -10px; /* 圆形部分在按钮右侧的位置 */
}
.return:hover {
background-color: #b30000; /* 鼠标悬停时按钮的背景色 */
}
.return:hover:before,
.return:hover:after {
background-color: #b30000; /* 鼠标悬停时圆形部分的背景色 */
}

@ -0,0 +1,37 @@
Component({
properties: {
visible: {
type: Boolean,
value: false
},
classList: {
type: Array,
value: []
}
},
data: {
selectedClassName: ''
},
methods: {
selectClass(e) {
this.setData({
selectedClassName: e.currentTarget.dataset.name
});
},
confirmSelection() {
if (this.data.selectedClassName) {
this.triggerEvent('confirm', { className: this.data.selectedClassName });
this.setData({ visible: false }); // 隐藏弹窗
} else {
wx.showToast({
title: '请选择班级',
icon: 'none'
});
}
},
cancelSelection() {
this.setData({ visible: false }); // 隐藏弹窗
this.triggerEvent('cancel'); // 可选:触发取消事件
}
}
});

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

@ -0,0 +1,13 @@
<view class="class-selector-overlay" wx:if="{{visible}}">
<view class="class-selector">
<view class="class-list">
<block wx:for="{{classList}}" wx:key="index">
<view class="class-item {{item.name === selectedClassName ? 'selected' : ''}}" bindtap="selectClass" data-name="{{item.name}}">{{item.name}}</view>
</block>
</view>
<view class="class-selector-buttons">
<button bindtap="confirmSelection">确定</button>
<button bindtap="cancelSelection">取消</button>
</view>
</view>
</view>

@ -0,0 +1,33 @@
/* 添加适当的样式来定位和美化弹窗 */
.class-selector-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
}
.class-selector {
background: white;
padding: 20px;
border-radius: 10px;
/* 其他样式 */
}
.class-item {
/* 班级项的默认样式 */
margin: 10rpx;
padding: 10rpx;
border-bottom: 1px solid rgb(21, 255, 0);
}
.class-item.selected {
/* 选中后的样式 */
background-color: #007aff; /* 例如,蓝色背景 */
color: white; /* 白色文字 */
}

@ -0,0 +1,266 @@
// pages/classManagement/classManagement.js
Page({
data: {
index: -1, //创建索引,知道此时选中哪个班级
showModal1: false, // 控制弹窗显示
showModal2: false,
showElement: false,
className: "", // 绑定输入框的值
classList: [
{ name: '班级1' ,id:1},
{ name: '班级2' ,id:2},
{ name: '班级3' ,id:3}
]
},
onLoad: function(options) {
// 发起网络请求以获取classList数据
wx.request({
url: 'http://192.168.152.1:8090/clazz/list', // 请替换为你的实际后端接口地址
method: 'GET', // 根据你的后端接口要求选择请求方法
success: (res) => {
// 请求成功的回调函数
if (res.statusCode === 200) {
try {
// 后端返回的数据格式{ "data": [{ "name": "" }, ...] }
// 小程序 SDK 会自动解析 JSON 字符串为对象,所以这里直接使用 res.data
const responseData = {
data:res.data
}
if (Array.isArray(responseData.data)) {
// 如果返回的数据中包含data数组则将其赋值给classList
this.setData({
classList: responseData.data
});
} else {
// 如果返回的数据格式不正确,则输出错误信息
console.error('返回的数据格式不正确期望包含data数组', responseData);
}
} catch (error) {
// 如果解析JSON时出错则输出错误信息
console.error('解析JSON数据时出错', error);
}
} else {
// 如果请求失败状态码不是200则输出错误信息
console.error('请求失败,状态码:', res.statusCode);
}
},
fail: (err) => {
// 请求失败的回调函数
console.error('请求出错', err);
}
});
},
showElement: function() {
this.setData({
showElement: !this.data.showElement // 切换showElement的值
});
},
// 显示弹窗
showModal1: function() {
this.setData({
showModal1: true
});
},
// 隐藏弹窗
hideModal1: function() {
this.setData({
showModal1: false
});
},
// 输入班级名称
inputChange: function(e) {
this.setData({
className: e.detail.value
});
},
// 添加班级
addClass: function() {
if (this.data.className.trim() === "") {
wx.showToast({
title: '班级名称不能为空',
icon: 'none'
});
return;
}
//将班级名称加入后端
wx.request({
url: 'http://192.168.152.1:8090/clazz/save',
method: 'POST',
data:{
name: this.data.className
},
success: function(res) {
// 处理后端返回的响应
console.log('添加成功', res.data);
// 根据需要更新小程序页面的数据或执行其他操作
},
fail: function(err) {
// 处理请求失败的情况
console.error('添加失败', err);
// 可以向用户显示错误信息或执行其他错误处理操作
}
})
// 将班级名称添加到页面的列表中
const newClassList = this.data.classList.concat({ name: this.data.className });
this.setData({
classList: newClassList, // 更新班级列表
className: "", // 清空输入框
showModal1: false // 隐藏弹窗
});
wx.showToast({
title: '班级添加成功',
icon: 'success'
});
},
goToadd_stu:function(){
const Name = this.data.classList[this.data.index].name
const queryString = `className=${Name}`;
wx.navigateTo({
url: `/pages/add_stu/add_stu?${queryString}`,//构造包含数据的url
success: function(res) {
// 跳转成功的回调
},
fail: function(err) {
// 跳转失败的回调
console.error('跳转失败', err);
}
});
},
goToclass_message:function(){
const Name = this.data.classList[this.data.index].name
const queryString = `className=${Name}`;
wx.navigateTo({
url: `/pages/class_message/class_message?${queryString}`,//构造包含数据的url
success: function(res) {
// 跳转成功的回调
},
fail: function(err) {
// 跳转失败的回调
console.error('跳转失败', err);
}
})
},
showAndGet: function(event) {
//显示元素
this.showElement();
// 从事件对象中获取data-index属性的值
const index = event.currentTarget.dataset.index;
// 成功获取console.log(index);
this.setData({
index: index
});
},
delete_class: function(){
//将删除班级传入后端
//取得要删除的班级名字
const className = this.data.classList[this.data.index];
const nameUsingDot = `${className.name}`;
console.log(nameUsingDot);
// const url = `https://your-backend-server.com/api/classes/className=${className}`;
wx.request({
url: `http://192.168.152.1:8090/clazz/${nameUsingDot}`,
method: 'DELETE', // 使用DELETE方法请求删除资源
header: {
'Content-Type': 'application/json', // 根据后端要求设置请求头
// 如果后端需要身份验证您可能还需要在这里添加Authorization头
},
success: function(res) {
// 处理后端返回的响应
if (res.statusCode === 200 || res.statusCode === 204) { // 200表示成功204表示成功且无内容返回
console.log('班级删除成功');
// 根据需要执行后续操作,如更新页面上的班级列表等
} else {
console.error('班级删除失败,状态码:', res.statusCode);
// 可以向用户显示错误信息或执行其他错误处理操作
}
},
fail: function(err) {
// 处理请求失败的情况
console.error('请求失败', err);
// 可以向用户显示错误信息或执行其他错误处理操作
}
});
//删除自己页面内的数据
// const newClassList = this.data.classList.splice(this.data.index, 1);
this.data.classList.splice(this.data.index, 1);
this.setData({
classList: this.data.classList, // 更新班级列表
className: "", // 清空输入框
showModal1: false, // 隐藏弹窗
showElement: false,
index: -1
});
console.log(this.data.classList);
},
change_name:function(){
if (this.data.className.trim() === "") {
wx.showToast({
title: '班级名称不能为空',
icon: 'none'
});
return;
}
//记录原名字
const id = this.data.classList[this.data.index].id
//记录要修改名字*
const name = this.data.className;
console.log(id);
console.log(name);
wx.request({
url: `http://192.168.152.1:8090/clazz/update`,
method: 'PUT',
data: {
id: id,
name: name
},
success(res) {
// 处理后端返回的成功响应
console.log('班级名字更新成功', res.data);
},
fail(err) {
// 处理请求失败的情况
console.error('更新班级名字失败', err);
}
})
// 班级名称修改页面的列表中
this.data.classList[this.data.index].name = this.data.className;
this.setData({
classList: this.data.classList, // 更新班级列表
className: "", // 清空输入框
showModal2: false // 隐藏弹窗
});
wx.showToast({
title: '班级修改成功',
icon: 'success'
});
},
showModal2: function() {
this.setData({
showModal2: true
});
},
// 隐藏弹窗
hideModal2: function() {
this.setData({
showModal2: false
});
},
});

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

@ -0,0 +1,31 @@
<!--pages/class_manage/class_manage.wxml-->
<view class="bg">
<image src="/pages/images/class_manage.png" mode="aspectFill"></image>
</view>
<view class="container">
<text class="class_list">班级列表</text>
<button class="add" bindtap="showModal1">添加班级</button>
<view class="list">
<view class="class_item" wx:for="{{classList}}" wx:key="index" bindtap="showAndGet" data-index="{{index}}">
<text>{{item.name}}</text>
<image class="arrow-icon" src="/pages/images/arrow_icon.png"/>
</view>
</view>
<modal hidden="{{!showModal1}}" title="添加班级" bindcancel="hideModal1" bindconfirm="addClass">
<view class="modal-input">
<input placeholder="输入班级名称" bindinput="inputChange" class="first_modal"/>
</view>
</modal>
<modal hidden="{{!showModal2}}" title="修改班级名称" bindcancel="hideModal2" bindconfirm="change_name">
<view class="modal-input">
<input placeholder="输入班级名称" bindinput="inputChange" class="first_modal"/>
</view>
</modal>
<view class="hide" wx:if="{{showElement}}">
<button class="hide_item" bindtap="goToadd_stu">添加学生</button>
<button class="hide_item" bindtap="goToclass_message">查看详情</button>
<button class="hide_item" bindtap="delete_class">删除班级</button>
<button class="hide_item" bindtap="showModal2">修改班级名称</button>
</view>
</view>

@ -0,0 +1,139 @@
/* pages/class_manage/class_manage.wxss */
/* page覆盖全页面 */
page{
width: 100%;
height: 100%;
}
.bg {
width: 100%;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: -1;
}
.bg image {
width: 100%;
height: 100%;
object-fit: cover;
}
.container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
padding: 0 0;
position: relative;
}
.class_list {
position: absolute;
top: 20rpx;
left: 10rpx;
font-size: 65rpx;
font-weight: bold;
}
.add {
position: absolute;
right: 10rpx;
top: 30rpx;
display: inline-block;
padding: 10rpx 50rpx; /* 调整内边距以改变按钮大小 */
font-size: 40rpx;
color: rgba(0, 0, 0, 1);
background-color: #ffae00; /* 按钮背景色 */
border: none;
border-radius: 100rpx; /* 初始设置为圆角矩形 */
text-align: center;
text-decoration: none;
overflow: hidden; /* 隐藏超出按钮范围的内容 */
}
.add:before {
left: -10rpx; /* 圆形部分在按钮左侧的位置 */
}
.add:after {
right: -10px; /* 圆形部分在按钮右侧的位置 */
}
.add:hover {
background-color: #b30000; /* 鼠标悬停时按钮的背景色 */
}
.add:hover:before,
.add:hover:after {
background-color: #b30000; /* 鼠标悬停时圆形部分的背景色 */
}
.modal-input {
margin: 50rpx;
}
.first_modal {
border: 1rpx solid #ccc;
padding: 0rpx;
border-radius: 5rpx;
width: 100%;
box-sizing: border-box;
height: 100rpx;
font-size: 40rpx;
}
.list {
width: 100%;
position: absolute;
top: 120rpx;
display: flex;
flex-direction: column;
}
.class_item {
width: 100%;
padding: 20rpx;
background-color: #ffffff34;
margin-bottom: 5rpx;
border-radius: 5rpx;
display: flex;
flex-direction: row;
}
.class_item text {
font-size: 50rpx;
font-weight: bold;
}
.class_item image {
width: 40rpx;
height: 40rpx;
object-fit: cover;
position: absolute;
right: 20rpx;
margin: 13rpx;
}
.hide {
width: 100%;
height: 500rpx;
position: absolute;
bottom: 40rpx;
display: flex;
flex-direction: column;
justify-content: center;
}
.hide_item {
width: 600rpx;
margin: 10rpx 0;
padding: 10rpx;
font-size: 55rpx;
/* transition: font-style 0.3s; */
background-color: transparent;
color: rgb(255, 255, 255);
}
.hide_item:hover {
font-style: italic;
}

@ -0,0 +1,66 @@
Page({
data:{
className: "",
students:[
]
},
onLoad: function(options) {
console.log(options);
// options 参数包含了从上一个页面传递过来的数据
const receivedClassName = options.className; // 获取传递过来的 className默认为空字符串
// 更新页面的数据
this.setData({
className: receivedClassName // 将接收到的 className 赋值给页面的 data 属性
});
// const url = `https://your-backend-server.com/api/students?className=${this.data.className}`
//根据className向后端请求数据
wx.request({
url: `http://192.168.152.1:8090/student/${this.data.className}`,
method: 'GET',
success: function(res) {
console.log(res.data)
// 后端返回的数据格式如下:
// {
// students: [
// { id: "102201", name: "Jhon" },
// { id: "102202", name: "Kun" },
// { id: "102203", name: "Tom" }
// ]
// }
// const formattedData = {
// students: res.data.map(data => ({
// id: data.id,
// name: data.name,
// point: data.point,
// clazz: data.clazz
// }))
// };
if (res.statusCode === 200) {
// 使用setData方法更新data内的students数组
// this.setData({
// students: formattedData
// });
this.setData({
students: res.data,
});
} else {
console.error('请求成功但数据格式不正确或数据不是数组');
}
}.bind(this), // 注意这里使用.bind(this)来确保this指向当前页面实例
fail: function(err) {
console.error('请求失败', err);
}
});
console.log(this.data.className);
},
});

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

@ -0,0 +1,10 @@
<!--pages/class_message/class_message.wxml-->
<view class="bg">
<image src="/pages/images/class_message.png" mode="aspectFill"></image>
</view>
<view class="container">
<view class="stu_list" wx:for="{{students}}" wx:for-item="item" wx:key="id">
<text class="id">{{item.id}}</text>
<text class="name">{{item.name}}</text>
</view>
</view>

@ -0,0 +1,38 @@
/* pages/class_message/class_message.wxss */
.bg {
width: 100%;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: -1;
}
.bg image {
width: 100%;
height: 100%;
object-fit: cover;
}
.container {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
padding: 0 0;
position: relative;
}
.stu_list {
font-size: 60rpx;
}
.stu_list .id {
position: relative;
left: 50rpx;
}
.stu_list .name {
position: relative;
left: 150rpx;
}

@ -0,0 +1,119 @@
// pages/function/function.js
Page({
data: {
classSelectorVisible1: false, //随机点名
classSelectorVisible2: false, //积分记录
classList: [
{ name: "班级一" },
{ name: "班级二" },
{ name: "班级三" },
],
// ... 其他数据
},
//加载页面classList(可以与class_manage的接口复用)
onLoad: function(options) {
// 发起网络请求以获取classList数据
wx.request({
url: 'http://192.168.152.1:8090/clazz/list', // 请替换为你的实际后端接口地址
method: 'GET', // 根据你的后端接口要求选择请求方法
success: (res) => {
// 请求成功的回调函数
if (res.statusCode === 200) {
try {
// 后端返回的数据格式{ "data": [{ "name": "" }, ...] }
// 小程序 SDK 会自动解析 JSON 字符串为对象,所以这里直接使用 res.data
const responseData = {
data:res.data
}
if (Array.isArray(responseData.data)) {
// 如果返回的数据中包含data数组则将其赋值给classList
this.setData({
classList: responseData.data
});
} else {
// 如果返回的数据格式不正确,则输出错误信息
console.error('返回的数据格式不正确期望包含data数组', responseData);
}
} catch (error) {
// 如果解析JSON时出错则输出错误信息
console.error('解析JSON数据时出错', error);
}
} else {
// 如果请求失败状态码不是200则输出错误信息
console.error('请求失败,状态码:', res.statusCode);
}
},
fail: (err) => {
// 请求失败的回调函数
console.error('请求出错', err);
}
});
},
// 班级管理
goToclass_manage: function() {
wx.navigateTo({
url: '/pages/class_manage/class_manage'
});
},
// 随机点名
goTocall_roll: function() {
this.setData({ classSelectorVisible1: true });
},
// 考勤管理
goTorecord: function() {
this.setData({ classSelectorVisible2: true });
},
//随机点名
handleClassConfirm1(e) {
const className = e.detail.className;
// 这里可以处理选择后的逻辑,比如跳转到录音页面并传递 className
console.log(className)
this.setData({ classSelectorVisible: false }); // 隐藏弹窗
const queryString = `className=${className}`;
wx.navigateTo({
url: `/pages/call_roll/call_roll?${queryString}`,//构造包含数据的url
success: function(res) {
// 跳转成功的回调
},
fail: function(err) {
// 跳转失败的回调
console.error('跳转失败', err);
}
})
},
handleClassCancel1() {
this.setData({ classSelectorVisible: false }); // 隐藏弹窗
// 可选:处理取消选择的逻辑
},
//积分记录
handleClassConfirm2(e) {
const className = e.detail.className;
// 这里可以处理选择后的逻辑,比如跳转到录音页面并传递 className
console.log(className)
this.setData({ classSelectorVisible: false }); // 隐藏弹窗
//传参给记录页面
const queryString = `className=${className}`;
wx.navigateTo({
url: `/pages/record/record?${queryString}`,//构造包含数据的url
success: function(res) {
// 跳转成功的回调
},
fail: function(err) {
// 跳转失败的回调
console.error('跳转失败', err);
}
})
},
handleClassCancel2() {
this.setData({ classSelectorVisible: false }); // 隐藏弹窗
// 可选:处理取消选择的逻辑
},
});

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {"class-selector" :"/pages/classSelector/classSelector"}
}

@ -0,0 +1,18 @@
<!-- pages/function/function.wxml -->
<view class="bg">
<image src="/pages/images/function.png" mode="aspectFill"></image>
</view>
<view class="container">
<view class="text">
<text class="title">首</text>
<text class="title">页</text>
</view>
<view class="menu">
<button class="menu-item" bindtap="goToclass_manage">班级管理</button>
<button class="menu-item" bindtap="goTocall_roll">随机点名</button>
<button class="menu-item" bindtap="goTorecord">考勤管理</button>
</view>
<class-selector visible="{{classSelectorVisible1}}" classList="{{classList}}" bind:confirm="handleClassConfirm1" bind:cancel="handleClassCancel1"></class-selector> <class-selector visible="{{classSelectorVisible2}}" classList="{{classList}}" bind:confirm="handleClassConfirm2" bind:cancel="handleClassCancel2"></class-selector>
</view>

@ -0,0 +1,70 @@
/* pages/function/function.wxss */
/* pages/function/function.wxss */
page{
width: 100%;
height: 100%;
}
.bg {
width: 100%;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: -1;
}
.bg image {
width: 100%;
height: 100%;
object-fit: cover;
}
.container {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
/* 把默认的padding: 200rpx 0;改掉 */
padding: 0 0;
position: relative;
}
.text {
display: flex;
flex-direction: column;
position: absolute;
top: 20rpx;
left: 40rpx;
}
.title {
/* 设置字体粗细 */
font-weight: bold;
padding: 10rpx 0;
font-size: 80rpx;
}
.menu {
width: 100%;
display: flex;
flex-direction: column;
position: absolute;
top: 300rpx;
}
.menu-item {
margin: 10rpx 0;
padding: 10rpx;
font-size: 65rpx;
/* transition: font-style 0.3s; */
background-color: transparent;
/* 相对定位 */
position: relative;
right: 210rpx;
}
.menu-item:hover {
font-style: italic;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

@ -0,0 +1,49 @@
// index.js
const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
Page({
data: {
motto: 'Hello World',
userInfo: {
avatarUrl: defaultAvatarUrl,
nickName: '',
},
hasUserInfo: false,
canIUseGetUserProfile: wx.canIUse('getUserProfile'),
canIUseNicknameComp: wx.canIUse('input.type.nickname'),
},
bindViewTap() {
wx.navigateTo({
url: '../logs/logs'
})
},
onChooseAvatar(e) {
const { avatarUrl } = e.detail
const { nickName } = this.data.userInfo
this.setData({
"userInfo.avatarUrl": avatarUrl,
hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl,
})
},
onInputChange(e) {
const nickName = e.detail.value
const { avatarUrl } = this.data.userInfo
this.setData({
"userInfo.nickName": nickName,
hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl,
})
},
getUserProfile(e) {
// 推荐使用wx.getUserProfile获取用户信息开发者每次通过该接口获取用户个人信息均需用户确认开发者妥善保管用户快速填写的头像昵称避免重复弹窗
wx.getUserProfile({
desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success: (res) => {
console.log(res)
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
})
},
})

@ -0,0 +1,4 @@
{
"usingComponents": {
}
}

@ -0,0 +1,27 @@
<!--index.wxml-->
<scroll-view class="scrollarea" scroll-y type="list">
<view class="container">
<view class="userinfo">
<block wx:if="{{canIUseNicknameComp && !hasUserInfo}}">
<button class="avatar-wrapper" open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
<image class="avatar" src="{{userInfo.avatarUrl}}"></image>
</button>
<view class="nickname-wrapper">
<text class="nickname-label">昵称</text>
<input type="nickname" class="nickname-input" placeholder="请输入昵称" bind:change="onInputChange" />
</view>
</block>
<block wx:elif="{{!hasUserInfo}}">
<button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 </button>
<view wx:else> 请使用2.10.4及以上版本基础库 </view>
</block>
<block wx:else>
<image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</block>
</view>
<view class="usermotto">
<text class="user-motto">{{motto}}</text>
</view>
</view>
</scroll-view>

@ -0,0 +1,62 @@
/**index.wxss**/
page {
height: 100vh;
display: flex;
flex-direction: column;
}
.scrollarea {
flex: 1;
overflow-y: hidden;
}
.userinfo {
display: flex;
flex-direction: column;
align-items: center;
color: #aaa;
width: 80%;
}
.userinfo-avatar {
overflow: hidden;
width: 128rpx;
height: 128rpx;
margin: 20rpx;
border-radius: 50%;
}
.usermotto {
margin-top: 200px;
}
.avatar-wrapper {
padding: 0;
width: 56px !important;
border-radius: 8px;
margin-top: 40px;
margin-bottom: 40px;
}
.avatar {
display: block;
width: 56px;
height: 56px;
}
.nickname-wrapper {
display: flex;
width: 100%;
padding: 16px;
box-sizing: border-box;
border-top: .5px solid rgba(0, 0, 0, 0.1);
border-bottom: .5px solid rgba(0, 0, 0, 0.1);
color: black;
}
.nickname-label {
width: 105px;
}
.nickname-input {
flex: 1;
}

@ -0,0 +1,18 @@
// logs.js
const util = require('../../utils/util.js')
Page({
data: {
logs: []
},
onLoad() {
this.setData({
logs: (wx.getStorageSync('logs') || []).map(log => {
return {
date: util.formatTime(new Date(log)),
timeStamp: log
}
})
})
}
})

@ -0,0 +1,4 @@
{
"usingComponents": {
}
}

@ -0,0 +1,6 @@
<!--logs.wxml-->
<scroll-view class="scrollarea" scroll-y type="list">
<block wx:for="{{logs}}" wx:key="timeStamp" wx:for-item="log">
<view class="log-item">{{index + 1}}. {{log.date}}</view>
</block>
</scroll-view>

@ -0,0 +1,16 @@
page {
height: 100vh;
display: flex;
flex-direction: column;
}
.scrollarea {
flex: 1;
overflow-y: hidden;
}
.log-item {
margin-top: 20rpx;
text-align: center;
}
.log-item:last-child {
padding-bottom: env(safe-area-inset-bottom);
}

@ -0,0 +1,66 @@
// pages/record/record.js
Page({
/**
* 页面的初始数据
*/
data: {
className: "K班",
students: [
{
id: "102201",
name: "Jhon",
point: 3
},
{
id: "102202",
name: "Kun",
point: 2
},
{
id: "102202",
name: "Tom",
point: 2
},
]
},
onLoad: function(options) {
console.log(options);
// options 参数包含了从上一个页面传递过来的数据
const receivedClassName = options.className; // 获取传递过来的 className默认为空字符串
// 更新页面的数据
this.setData({
className: receivedClassName // 将接收到的 className 赋值给页面的 data 属性
});
// const url = `https://your-backend-server.com/api/students?className=${this.data.className}`
//根据className向后端请求数据
wx.request({
url: `http://192.168.152.1:8090/student/${this.data.className}`,
method: 'GET',
success: function(res) {
// 后端返回的数据格式如下:
// {
// students: [
// { id: "102201", name: "Jhon", point: 3 },
// { id: "102202", name: "Kun", point: 2 },
// { id: "102203", name: "Tom", point: 1 }
// ]
// }
if (res.statusCode === 200 && Array.isArray(res.data)) {
// 使用setData方法更新data内的students数组
this.setData({
students: res.data
});
} else {
console.error('请求成功但数据格式不正确或数据不是数组');
}
}.bind(this), // 注意这里使用.bind(this)来确保this指向当前页面实例
fail: function(err) {
console.error('请求失败', err);
}
});
},
})

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

@ -0,0 +1,13 @@
<!--pages/record/record.wxml-->
<view class="bg">
<image src="/pages/images/record.png" mode="aspectFill"></image>
</view>
<view class="container">
<text class="title">出勤状况</text>
<view class="stu_list" wx:for="{{students}}" wx:for-item="item" wx:key="id">
<text class="id">{{item.id}}</text>
<text class="name">{{item.name}}</text>
<text class="point">积分数:{{item.point}}</text>
</view>
</view>

@ -0,0 +1,49 @@
/* pages/record/record.wxss */
.bg {
width: 100%;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: -1;
}
.bg image {
width: 100%;
height: 100%;
object-fit: cover;
}
.container {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
padding: 0 0;
position: relative;
}
.title {
font-size: 80rpx;
font-weight: bold;
margin: 80rpx;
}
.stu_list {
font-size: 40rpx;
}
.stu_list .id {
position: relative;
left: 50rpx;
}
.stu_list .name {
position: relative;
left: 120rpx;
}
.stu_list .point {
position: absolute;
left: 500rpx;
}

@ -0,0 +1,9 @@
// pages/welcome/welcome.js
Page({
// 跳转到功能页面的函数
goToFunction: function() {
wx.navigateTo({
url: '/pages/function/function' // 跳转function页面
});
}
});

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

@ -0,0 +1,5 @@
<!-- pages/index/index.wxml -->
<!-- view绑定触发函数 -->
<view class="page-container" bindtap="goToFunction">
<image src="/pages/images/welcome.png" mode="cover" class="background-image" />
</view>

@ -0,0 +1,21 @@
/* pages/index/index.wxss */
page{
width: 100%;
height: 100%;
}
.page-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%; /* 宽度100% */
height: 100%; /* 高度100% */
padding: 0;
margin: 0;
}
.background-image {
width: 100%; /* 宽度100% */
height: 100%; /* 高度100% */
}

@ -0,0 +1,28 @@
{
"compileType": "miniprogram",
"libVersion": "trial",
"packOptions": {
"ignore": [],
"include": []
},
"setting": {
"coverView": true,
"es6": true,
"postcss": true,
"minified": true,
"enhance": true,
"showShadowRootInWxmlPanel": true,
"packNpmRelationList": [],
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
}
},
"condition": {},
"editorSetting": {
"tabIndent": "auto",
"tabSize": 2
},
"appid": "wx008217ca2c2b30d3"
}

@ -0,0 +1,8 @@
{
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"projectname": "user",
"setting": {
"compileHotReLoad": true,
"urlCheck": false
}
}

@ -0,0 +1,7 @@
{
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
"rules": [{
"action": "allow",
"page": "*"
}]
}

@ -0,0 +1,19 @@
const formatTime = date => {
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
return `${[year, month, day].map(formatNumber).join('/')} ${[hour, minute, second].map(formatNumber).join(':')}`
}
const formatNumber = n => {
n = n.toString()
return n[1] ? n : `0${n}`
}
module.exports = {
formatTime
}

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>demo</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.6.13</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<!--easy excel依赖-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.18</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- excel 导出工具 -->
<!-- Apache POI的核心库用于处理HSSF格式的Excel.xls文件 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version> <!-- 选择合适的版本 -->
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version> <!-- 选择合适的版本 -->
</dependency>
<!-- Apache Commons IO for file handling (optional but useful) -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version> <!-- 选择合适的版本 -->
</dependency>
<!-- Apache POI的OOXML模式库通常与poi-ooxml一起使用提供了处理OOXML格式文件时所需的XML模式定义 -->
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.demo.DemoApplication</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,16 @@
package com.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.demo.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

@ -0,0 +1,40 @@
package com.demo.controller;
import com.demo.entity.Clazz;
import com.demo.entity.Student;
import com.demo.mapper.ClazzMapper;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Update;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/clazz")
public class ClazzController {
@Resource
ClazzMapper clazzMapper;
@PostMapping("/save")
public String addClazz(@RequestBody Clazz clazz){
clazzMapper.save(clazz);
return "success";
}
@GetMapping("/list")
public List<Clazz> getClazz(){
return clazzMapper.findAll();
}
@DeleteMapping("/{name}")
public String deleteClazz(@PathVariable("name") String name){
clazzMapper.deleteByname(name);
return "success";
}
@PutMapping("/update")
public String updateClazz(@RequestBody Clazz clazz){
clazzMapper.updateById(clazz);
return "success";
}
}

@ -0,0 +1,28 @@
package com.demo.controller;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.demo.entity.Student;
import com.demo.mapper.StudentMapper;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.InputStream;
import java.nio.channels.MulticastChannel;
import java.util.List;
@RestController
@RequestMapping("/excel")
@CrossOrigin(origins = "*")
public class ExcelController {
@Resource
private StudentMapper studentMapper;
@PostMapping("/import")
public void imp(@RequestBody MultipartFile file)throws Exception{
InputStream inputStream = file.getInputStream();
ExcelReader reader = ExcelUtil.getReader(inputStream);
List<Student> students = reader.readAll(Student.class);
studentMapper.batchInsert(students);
}
}

@ -0,0 +1,40 @@
package com.demo.controller;
import com.demo.entity.Clazz;
import com.demo.entity.Student;
import com.demo.mapper.StudentMapper;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/student")
public class StudentController {
@Resource
StudentMapper studentMapper;
@GetMapping
public List<Student> getStudent(){
return studentMapper.findAll();
}
@PostMapping("/set")
public String addStudent(@RequestBody Student student){
studentMapper.save(student);
return "success";
}
@GetMapping("/{clazz}")
public List<Student> getStudent1(@PathVariable("clazz") String clazz){
return studentMapper.findByclazz(clazz);
}
@PutMapping("/update")
public String updateStudent(@RequestBody Student student){
studentMapper.updateByname(student);
return "success";
}
}

@ -0,0 +1,9 @@
package com.demo.entity;
import lombok.Data;
@Data
public class Clazz {
private String name;
private int id;
}

@ -0,0 +1,16 @@
package com.demo.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private String id;
private String name;
private int point;
private String clazz;
}

@ -0,0 +1,25 @@
package com.demo.mapper;
import com.demo.entity.Clazz;
import com.demo.entity.Student;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
public interface ClazzMapper {
@Select("select * from classes")
List<Clazz> findAll();
@Insert("INSERT INTO classes (name) VALUES (#{name});")
@Transactional
void save(Clazz clazz);
@Delete("delete from classes where name = #{name}")
void deleteByname(String name);
@Update("update classes set name = #{name} where id = #{id}")
@Transactional
void updateById(Clazz clazz);
}

@ -0,0 +1,38 @@
package com.demo.mapper;
import com.demo.entity.Clazz;
import com.demo.entity.Student;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
public interface StudentMapper {
@Select("select * from students")
List<Student> findAll();
@Insert("INSERT INTO students (`id`, `name`, `point`, `clazz`) VALUES (#{id},#{name},#{point},#{clazz});")
@Transactional
void save(Student student);
@Select("select * from students where clazz = #{clazz}")
List<Student> findByclazz(String clazz);
@Update("update students set point = #{point} where name = #{name}")
@Transactional
void updateByname(Student student);
@Insert({
"<script>",
"INSERT INTO students (id, name, point, clazz) VALUES ",
"<foreach collection='list' item='student' separator=','>",
"(#{student.id}, #{student.name}, #{student.point}, #{student.clazz})",
"</foreach>",
"</script>"
})
void batchInsert(@Param("list") List<Student> list);
}

@ -0,0 +1,8 @@
server:
port: 8090
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
username: root
password: 123456

@ -0,0 +1,13 @@
package com.demo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DemoApplicationTests {
@Test
void contextLoads() {
}
}
Loading…
Cancel
Save