基于arkTS开发鸿蒙app应用案例——大学生签到系统

1.项目所用技术栈

  • arkTS

  • node.js express

  • mongoDB

2.效果图

3.源码

Index.ets(登录页)

登陆时让前端访问数据库中已经存好的账号密码,如果可以查询到数据库中的数据,则账号密码正确,登录成功,否则登录失败。

import  axios  from '@ohos/axios'
import router from '@ohos.router'
@Entry
@Component
struct Index {
  // 上传数据
  @State zhanghao: string = ''
  @State mima: string = ''
  @State zhanghao_find:string =''
  @State mima_find:string =''
  build() {
    Column() {
      Text('淼学签到系统')
        .margin({top:70})
        .fontWeight(FontWeight.Bold)
        .fontSize(30)
      Image('./components/img/appimg.jpg')
        .width(200)
        .height(200)
        .borderRadius(20)
        .margin({top:50,bottom:20})
      // 账号登录
      Row(){
        Image('./components/img/zhanghao.png')
          .width(20)
          .height(20)
        TextInput({placeholder:'账号(学号)'})
          .backgroundColor('#00FFFFFF')
          .width('75%')
          .onChange(value =>{
            console.log(value)
            this.zhanghao_find = value
          })
      }
      .borderRadius(12)
      .borderWidth(1)
      .borderColor('#E4DFDF')
      .padding(5)
      .margin({top:10})
      Row(){
        Image('./components/img/mima.png')
          .width(20)
          .height(20)
        TextInput({placeholder:'密码(学号后6位)'})
          .backgroundColor('#00FFFFFF')
          .width('75%')
          .onChange(value =>{
            console.log(value)
            this.mima_find = value
          })
      }
      .borderRadius(12)
      .borderWidth(1)
      .borderColor('#E4DFDF')
      .padding(5)
      .margin({top:10})

      Button('登录',{type:ButtonType.Normal,stateEffect:true})
        .borderRadius(10)
        .margin({top:40})
        .width(250)
        .height(55)
        .onClick(()=>{
          axios({
            method: "get",
            url: 'http://localhost:3000/users/find1/'+this.zhanghao_find+ '/' + this.mima_find,
          }).then(res => {
            console.info('result:' + JSON.stringify(res.data));
            // 获取data数组中的第一个元素
            const firstData = res.data.data[0];
            // 获取zhanghao字段的值
            const juese = firstData.juese;
            console.log('zhanghaoValue:', juese);
            const zhanghao = firstData.zhanghao;
            // 获取data数组中的第一个元素
            // 获取zhanghao字段的值
            router.pushUrl({
              url: 'pages/App_one',
              params: {
                juese,
                zhanghao
              }
            })
          }).catch(error => {
            console.error(error);
          })
        })
    }
    .width('100%')
    .height('100%')
  }
}

App_one.ets(具体功能页)

根据上一个登录页面的跳转,该页面拿到跳转传递过来的参数,根据与数据库中的“juese”字段相对比,如果角色为管理者,则功能页的内容切换为管理者的功能内容,如果角色为学生,则显示学生的页面内容。

import { Header } from '../components/Toubu'
import router from '@ohos.router'
import  axios  from '@ohos/axios'
@Entry
@Component

struct App_one {
  @State zhanghao_find:string =''
  @State Ondata: object = router.getParams()
  // 统计总共的学生数
  @State students:string = '0'
  // 统计已签到的学生数
  @State students_ok:string = '0'
  // 查询已经签到的信息
  @State items:Array<Object> = []

  // 判断登录的角色
  @State Switch:string = ''

  controller: TextClockController = new TextClockController();
  @State accumulateTime: number = 0

  aboutToAppear(){
    this.zhanghao_find = this.Ondata?.['zhanghao']
    console.log('qweqweqwe',JSON.stringify(this.zhanghao_find))
    if(this.Ondata?.['juese'] == 'Administrator'){
      //   查询学生总数
      axios({
        method: "get",
        url: 'http://localhost:3000/users/count/student',
      }).then(res=>{
        console.info('result:' + JSON.stringify(res.data.count));
        this.students = JSON.stringify(res.data.count)
        // 获取已签到的人数
        axios({
          method: "get",
          url: 'http://localhost:3000/qiandaos/count/student_ok',
        }).then(res=>{
          console.info('result:' + JSON.stringify(res.data.count));
          this.students_ok = JSON.stringify(res.data.count)
          // 查询所有签到者的账号
          axios({
            method: "get",
            url: 'http://localhost:3000/qiandaos/find_all',
          }).then(res=>{
            console.info('result:' + JSON.stringify(res.data.data));
            this.items = res.data.data
          })
        })
      })
    }
  }

  build() {
      Column() {
        Header()
          .margin(20)

        if(this.Ondata?.['juese'] == 'Administrator'){
          Text('管理员页面')
            .fontSize(20)
          Row(){
            Text('今日已签到人数:')
            Text(this.students_ok + '/' +this.students)
          }
          .borderRadius(5)
          .borderWidth(1)
          .borderColor('#E4DFDF')
          .padding(10)
          .margin({top:10})

          Scroll(){
            Column() {
              ForEach(this.items, (item) => {
                Row() {
                  Image($r('app.media.icon'))
                    .alt($r('app.media.icon')) // 使用alt,在网络图片加载成功前使用占位图
                    .width(30)
                    .height(30)
                  Text(item.zhanghao)
                    .fontWeight(800)
                    .margin({ left: 20 })
                  Text(item.date_times)
                    .fontWeight(800)
                    .margin({ left: 20 })
                }
                .margin({top:10})
              })
            }
          }
          .height(200)
          .scrollable(ScrollDirection.Vertical) // 滚动方向纵向
          .scrollBar(BarState.On) // 滚动条常驻显示
          .scrollBarColor(Color.Gray) // 滚动条颜色
          .scrollBarWidth(10) // 滚动条宽度
          .edgeEffect(EdgeEffect.Spring) // 滚动到边沿后回弹

        }else {
          Text('学生页面')
          TextClock({ timeZoneOffset: -8, controller: this.controller })
            .backgroundColor('#00FFFFFF')
            .borderRadius(12)
            .borderWidth(1)
            .borderColor('#E4DFDF')
            .padding(10)
            .margin({top:10})
            .format('yyyy/M/d/h/m/s')
            .onDateChange((value: number) => {
              this.accumulateTime = value
            })
            .margin(20)
            .fontSize(20)

          Button("马上签到")
            .borderRadius(10)
            .margin({top:40})
            .width(250)
            .height(55)
            .onClick(() => {
              axios({
                method: "get",
                url: 'http://localhost:3000/qiandaos/find/time/'+this.zhanghao_find,
              }).then(res=>{
                console.info('result:' + JSON.stringify(res.data.message));
                let zhanghao = res.data.message

                if (zhanghao == 'None' ){
                  // 停止文本时钟
                  this.controller.stop()
                  // 传递给后端
                  axios({
                    method: "post",
                    url: 'http://localhost:3000/qiandaos/time',
                    data:{
                      juese:'student',
                      zhanghao:this.Ondata?.['zhanghao']
                    }
                  }).then(res => {
                    console.info('result1111:');
                  }).catch(error => {
                    console.error(error);
                  })
                }else {
                    AlertDialog.show(
                      {
                        title: '今天已经签到,请勿多次签到',
                        message: '请勿多次签到',
                        autoCancel: true,
                        alignment: DialogAlignment.Bottom,
                        offset: { dx: 0, dy: -20 },
                        gridCount: 3,
                        confirm: {
                          value: 'OK',
                          action: () => {
                            console.info('Button-clicking callback')
                          }
                        },
                        cancel: () => {
                          console.info('Closed callbacks')
                        }
                      }
                    )
                }
              })
            })
        }

      }
      .width('100%')
  }
  onPageShow(){
    console.log(JSON.stringify(this.Ondata?.['zhanghao']))
  }
}

后端node.js文件架构

主要代码:

db.js


负责创建数据库中数据表的结构,并连接数据库,为数据表中的键值创建模型。

const mongoose = require('mongoose')

//连接mongodb数据库
mongoose.connect("mongodb://localhost:27017/DoList")
    .then(() => {
        console.log("数据库连接成功!")
    })
    .catch((err) => {
        console.log("数据库连接失败!", err)
    })

// 创建表用户表
const Users = new mongoose.Schema({
    zhanghao: {
        type: String,
    },
    mima: {
        type: String
    },
    //此处是为了测试vue动态路由
    juese:{
        type: String
    }
})
// 创建签到表
const Qiandao = new mongoose.Schema({
    zhanghao: {
        type: String,
    },
    date_times: {
        type: String
    },
    juese: {
        type: String
    }
})


const users = mongoose.model("Users", Users);
const qiandao = mongoose.model("Qiandao", Qiandao);
module.exports = {
    users,
    qiandao,
}

index.js

后端主入口程序,引用自定义组件进行进一步的模块封装。

// index.js
const express = require('express');
const cors = require('cors'); // 导入cors模块
const app = express();
const userApi = require('./user_ctrl/user_api');
const qiandaoApi = require('./qiandao_ctrl/qiandao_api');
const dingshi = require('./dingshi/dingshi'); // 引入定时任务文件

app.use(cors()); // 使用cors中间件处理跨域请求

app.use('/users', userApi);

app.use('/qiandaos', qiandaoApi);



app.listen(3000, () => {
    console.log('server running');
});

user_api.js

负责使用者用户登录的信息的判断。

// user_api.js
const express = require('express');
const router = express.Router();
const { users } = require('../db');

router.use(express.urlencoded({ extended: true }));
router.use(express.json());


// 账号登录
router.get("/find1/:zhanghao/:mima", async (req, res) => {
    try {
        const zhanghao = req.params.zhanghao;
        const mima = req.params.mima;

        // 使用 find 查询所有匹配指定 的数据记录
        const results = await users.find({ zhanghao, mima });

        if (results.length > 0) {
            // 如果找到匹配的记录,则返回所有匹配的记录
            res.json({ data: results, message: "登录成功!" });
        } else {
            res.status(404).json({ message: "未找到匹配的记录" });
        }
    } catch (error) {
        res.status(500).json({ message: "服务器内部错误" });
    }
});

router.get("/count/student", async (req, res) => {
    try {
        // 使用 countDocuments 查询 juese 字段为 "student" 的数据数量
        const count = await users.countDocuments({ juese: "student" });

        // 返回查询结果
        res.json({ count: count, message: "查询成功!" });
    } catch (error) {
        // 如果发生错误,返回500错误
        res.status(500).json({ message: "服务器内部错误" });
    }
});



module.exports = router;

qiandao_api.js

负责学生签到的时间查询、全部查询、账号查询等。

// user_api.js
const express = require('express');
const router = express.Router();
const { qiandao } = require('../db');

router.use(express.urlencoded({ extended: true }));
router.use(express.json());


router.get("/count/student_ok", async (req, res) => {
  try {
      // 使用 countDocuments 查询 juese 字段为 "student" 的数据数量
      const count = await qiandao.countDocuments({ juese: "student" });

      // 返回查询结果
      res.json({ count: count, message: "查询成功!" });
  } catch (error) {
      // 如果发生错误,返回500错误
      res.status(500).json({ message: "服务器内部错误" });
  }
});

// 全部查询
router.get("/find_all", async (req, res) => { // Corrected function signature
  try {
    const results = await qiandao.find();

    if (results.length > 0) {
      // 如果找到匹配的记录,则返回所有匹配的记录
      res.json({ data: results, message: "成功" });
    } else {
      res.status(404).json({ message: "未找到匹配的记录" });
    }
  } catch (error) {
    res.status(500).json({ message: "服务器内部错误" });
  }
});

// 签到时间
router.post("/time", async (req, res) => {
  try {
    const { zhanghao ,juese } = req.body;
    // if(date_time == true){
      await qiandao.create({
        juese,
        zhanghao,
        date_times:new Date().toLocaleString()
      }); 
    // }
    res.send("success"); 
  } catch (error) {
    res.send(error, "error");
}
});

router.get("/find/time/:zhanghao", async (req, res) => {
  try {
      const zhanghao = req.params.zhanghao;

      // 使用 find 查询所有匹配指定 name 的数据记录
      const results = await qiandao.find({ zhanghao });

      if (results.length > 0) {
          // 如果找到匹配的记录,则返回所有匹配的记录
          res.json({ data: results, message: "签到成功!" });
      } else {
        res.json({ data: results, message: "None" });
      }
  } catch (error) {
      res.status(500).json({ message: "服务器内部错误" });
  }
});




module.exports = router;

dingshi.js

定时器的作用负责每天凌晨0点,刷新diandaos数据表,确保第二天可以正常的使用。

// dingshi.js

const cron = require('node-cron');
const { qiandao } = require('../db'); // 导入数据库模型

// 每天凌晨0点0分执行任务
cron.schedule('0 0 * * *', async () => {
    try {
        // 清空签到表
        await qiandao.deleteMany({});
        console.log('签到表数据已清空');
    } catch (error) {
        console.error('清空数据表时出错:', error);
    }
}, {
    scheduled: true,
    timezone: "Asia/Shanghai" // 设置时区为上海时间
});

console.log('定时任务已启动');

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

淼学派对

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值