【Angular2】基于localStorage实现本地备份操作记录 - CSDN博客

项目中需要对用户的操作记录备份起来,如果后端出现任何问题,可以从前端把用户操作记录提取出来,然后后期把数据导入到数据库

功能

网络监测

1.监测每条记录的提交情况,分辨出是客户端和服务器问题;
2.呼吸灯动态显示当前整体提交状况;
3.监控中心可以查看每条记录的提交情况;
4.监控中心可以控制对每条记录的监控状态;
5.监控中心可以切换网络监测的开闭模式;

智能提交

1.监控中心每隔10秒监测一次提交情况,如果发现有没有提交成功的内容,会在监听到有提交成功的时刻,自动提交所有没有提交成功的记录;
2.监控中心可以切换智能提交的开闭模式;

自动备份

1.监控中心会在最后的时刻将所有用户的操作记录下载到本地;
2.监控中心可以切换自动备份的开闭模式;

关系图:

这里写图片描述
1.首先各个题型组件在调取服务之后,通过服务返回的值来判断提交情况,并记录操作,如果有问题则为服务端故障,同时更新网络状态;
2.如果调取服务出现任何异常导致无法获取返回值,则为客户端问题,记录操作并标记,同时更新网络状态;
3.呼吸灯实时监测网络状态,累计3次故障后客户端报警;
4..进入监控中心,读取所有操作记录及其标记,显示提交情况,同时根据具体情况选择性的关闭对应的记录的监测(否则会一直报警);
5.在操作的过程中,如果发现有没有提交成功的操作,同时监测到最近有提交成功,那么就把之前没有提交成功的操作重新自动提交;
6..监控中心如果出现很多问题或者关键性问题,可以开启备份操作下载功能,用户操作完成之后会把操作自动下载到本地;

代码说明:逻辑比较复杂

/* 向后台提交学生答案 */
  public updateStudentAnswerToBackend(answer: Answer) {
    let url: string = "examinationEvaluation-web/onlineExam/updatePaperRecordByRecord" + this.authGuardService.getTicket();
    let body: string = JSON.stringify(answer);
    this.exampapaerservice.post(url, body).subscribe(
      res => {
        if (res.json().code == "1111" || res.json().data != true) {
          this.backupAnswer(answer, 1); //备份答案
        } else {
          this.backupAnswer(answer, 0); //备份答案
        }
      }
    );
    console.log("学生提交答案-radio");
  }
/* 备份用户答案 */
  private backupAnswer(answer: Answer, status: number) {
    //备份答案记录
    console.log("answer-backup-log---"+ExamPaperService.userOperationAmount);
    ExamPaperService.userOperationAmount++; //操作序号递增
    localStorage.setItem("userOperationAmount", ExamPaperService.userOperationAmount.toString()); //记录操作序号
    localStorage.setItem(answer.studentId + ExamPaperService.userOperationAmount, JSON.stringify(answer) + status); //记录操作内容
    //记录提交情况
    let flag: boolean = true;
    let ns: string[] = JSON.parse(localStorage.getItem("NetWorkState"));
    for (var i = 0; i < ns.length; i++) {
      if (answer.questionMainId == ns[i]) { flag = false; }
    }
    if (status != 0 && flag) {
      ns[0] = (parseInt(ns[0]) + 1).toString();
      localStorage.setItem("NetWorkState",JSON.stringify(ns));
    }
  }

这块待优化的地方:

if (res.json().code == "1111" || res.json().data != true) {
          this.backupAnswer(answer, 1); //备份答案
        } else {
          this.backupAnswer(answer, 0); //备份答案
        }
将1/0 这个 成功提交答案与否 的标志 改为answer里面的一个属性字段来存储
后面还有2

公共服务ts

/* 处理  失败的提交 */
  public handleUpdateAnswerError(error: Response) {
    //保存用户答案到localStorage
    Let answer: Answer = <Answer>(JSON.parse(ExamPaperService.studentAnswer));
    this.backupAnswer(answer, 2);
    return Observable.throw(error.json().error || '网络问题:server error');
  }
/* 备份用户答案 */
  private backupAnswer(answer: Answer, status: number) {
    //备份答案记录
    console.log("answer-backup-log---" + ExamPaperService.userOperationAmount);
    ExamPaperService.userOperationAmount++; //操作序号递增
    localStorage.setItem("userOperationAmount", ExamPaperService.userOperationAmount.toString()); //记录操作序号
    localStorage.setItem(answer.studentId + ExamPaperService.userOperationAmount, JSON.stringify(answer) + status); //记录操作内容
    //记录提交情况
    let flag: boolean = true;
    let ns: string[] = JSON.parse(localStorage.getItem("NetWorkState"));
    for (var i = 0; i < ns.length; i++) {
      if (answer.questionMainId == ns[i]) { flag = false; }
    }
    if (status != 0 && flag) {
      ns[0] = (parseInt(ns[0]) + 1).toString();
      localStorage.setItem("NetWorkState", JSON.stringify(ns));
    }
  }

上面的1和0,这里的2是用来表示提交情况的。非0说明提交出现了问题,监控ts中会定时坚持这个标识位进而再次提交代码

监控中心ts
ngOnInit() {
    //获得当前操作数量
    this.getUserOperationAmount();
    //初始化网络状态
    let networkList: string[] = [];
    networkList.push("0");
    localStorage.setItem("NetWorkState", JSON.stringify(networkList));
    //初始化备份模式
    localStorage.setItem("NetWorkBackupPattern", "0");
    //开始监测
    this.startMonitorNetworkStatus();
  }
/* 开始监测网络状态 */
  startMonitorNetworkStatus() {
    this.timer = setInterval(() => {
      this.networkState = parseInt(JSON.parse(localStorage.getItem("NetWorkState"))[0]);
      let el: Element = document.getElementById("networkstate");
      if (this.networkState == 1) {
        el.setAttribute("class", "breathe-yellow-btn");
      } else if (this.networkState == 3) {
        el.setAttribute("class", "breathe-red-btn");
      } else if (this.networkState > 3) {
        this.display_error = true;
        let ns: string[] = JSON.parse(localStorage.getItem("NetWorkState"));
        ns[0] = "3";
        localStorage.setItem("NetWorkState", JSON.stringify(ns));
      }
    }, 1000);
  }
/* 刷新状态 */
  refreshStatus() {
    this.getAnswerStatus();
    this.getMonitorStatus();
  }
/* 清除缓存 */
  clearLocalStorage() {
    localStorage.clear();
  }
/* 获得题目提交状态 */
  getAnswerStatus() {
    console.log("Start-getAnswerStatus-------");
    for (var i = 0; i < parseInt(localStorage.getItem("userOperationAmount")); i++) {
      let answerLog: string = localStorage.getItem(localStorage.getItem("userId") + i);
      let answerStatus = answerLog.substring(answerLog.length - 1);
      let answer: Answer = JSON.parse(answerLog.substring(0, answerLog.length - 1));
if (answerStatus == "0") {
        let el = document.getElementById("network" + answer.questionMainId);
        if (el != null) {
          el.setAttribute("class", "badge badge-success badge_postion");
          el.innerHTML = "成功提交";
        }
      }
      if (answerStatus == "1") {
        let el = document.getElementById("network" + answer.questionMainId);
        if (el != null) {
          el.setAttribute("class", "badge badge-warning badge_postion");
          el.innerHTML = "客户端故障";
        }
      }
      if (answerStatus == "2") {
        let el = document.getElementById("network" + answer.questionMainId);
        if (el != null) {
          el.setAttribute("class", "badge badge-important badge_postion");
          el.innerHTML = "服务器故障";
        }
      }
    }
  }
/* 获得检测状态 */
  getMonitorStatus() {
    console.log("Start-getMonitorStatus-------");
    let idList: string[] = JSON.parse(localStorage.getItem("NetWorkState"));
    for (var i = 1; i < idList.length; i++) {
      let el = document.getElementById("monitor" + idList[i]);
      if (el != null) {
        el.setAttribute("class", "btn btn-danger btn-xs pull-right");
        el.innerHTML = "监测已停止";
      }
    }
  }
/* 获得操作记录数量 */
  getUserOperationAmount() {
    let amount: number = 1;
    while (localStorage.getItem("userId" + amount)!=null) {
      amount++;
    }
    localStorage.setItem("userOperationAmount",(amount-1).toString());
  }
/* 切换监测状态 */
  changeMonitorStatus(monitorId: string) {
    console.log("Start-changeMonitorStatus-------");
    let exitFlag: boolean = true;
    let questionId = monitorId.substring(7, monitorId.length);
    let idList: string[] = JSON.parse(localStorage.getItem("NetWorkState"));
    for (var i = 0; i < idList.length; i++) {
      if (questionId == idList[i]) {
        //切换为开始
        let el = document.getElementById("monitor" + idList[i]);
        if (el != null) {
          el.setAttribute("class", "btn btn-primary btn-xs pull-right");
          el.innerHTML = "正在监测中";
        }
        idList.splice(i, 1);
        localStorage.setItem("NetWorkState", JSON.stringify(idList));
        exitFlag = false;
      }
    }
    //切换为停止
    if (exitFlag) {
      let el = document.getElementById(monitorId);
      if (el != null) {
        el.setAttribute("class", "btn btn-danger btn-xs pull-right");
        el.innerHTML = "监测已停止";
      } 
      idList.push(questionId);
      localStorage.setItem("NetWorkState", JSON.stringify(idList));
    }
  }
private backupPatternStatus: boolean = false; //备份模式状态
/* 切换备份模式 */
  changeBackupPattern() {
    if (this.backupPatternStatus) {
      //切换为不备份
      let el = document.getElementById("networkbackuppattern");
      if (el != null) {
        el.setAttribute("class", "btn btn-info pull-left");
        el.innerHTML = "非备份模式";
        localStorage.setItem("NetWorkBackupPattern", "0");
        this.backupPatternStatus = false;
      }
    } else {
      //切换为开始备份
      let el = document.getElementById("networkbackuppattern");
      if (el != null) {
        el.setAttribute("class", "btn btn-warning pull-left");
        el.innerHTML = "备份模式中";
        localStorage.setItem("NetWorkBackupPattern", "1");
        this.backupPatternStatus = true;
      }
    }
  }
/* --------------------------------------------------------- */
private openNum: number = 0;//点击三次可以打开
/* 打开模态框 */
  openModal(modal: HTMLElement) {
    this.openNum++;
    if (this.openNum > 2) {
      this.refreshStatus();
      modal.style.visibility = 'visible';
      this.openNum = 0;
    }
  }
/* 关闭模态框 */
  close(modal: HTMLElement) {
    modal.style.visibility = 'hidden';
  }
/* 拖动模态框 */
  draggable() {
    $('.modal-dialog').draggable();
  }

网络、服务器出现了问题,上面我们开启了本地备份,怎么把备份的地方保存下来哪?下载拷贝:

/* 创建备份文本并下载 */
  createBackupText() {
    let userLog: string = "";
    for (var i = 0; i < parseInt(localStorage.getItem("userOperationAmount")); i++){
      userLog = userLog +localStorage.getItem(localStorage.getItem("userId")+i);
    }
    let data = new Blob([userLog], { type: 'application/json' })
    var link = document.createElement("a");
    link.setAttribute("href", window.URL.createObjectURL(data));
    link.setAttribute("download", localStorage.getItem("userId") + '.json');
    link.style.visibility = 'hidden';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    console.log("------ Start Create File And Download --------");
}

后语:
要针对不同的业务场景采取不同的解决方案,尽可能考虑全面

设置标识位,标记题的序号、标记提交情况,定时检测,抄过来,还是感觉我们组长强大的业务能力及代码能力!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值