SCORM课程对接线上课程学习平台

SCORM课程对接线上课程学习平台

1,什么是SCORM课件?

SCORM是一种标准,是在线学习系统的一种内容标准,课件的内容主要由HTML、XML标签、JS代码组成。
其中,HTML 用于展现文字、图像、音视频等学习资源,XML标签用于组织课程结构,譬如章节目录,JS代码用于控制课程播放进度,或者制作一些效果。
在这里插入图片描述

2,SCORM课件有什么优点?

一、 SCORM课件可以对内容的重新组织和编排。
二、 SCORM课件可以定义学习资源的排序和浏览逻辑。
三、定制化的在线学习平台与课件具有交互能力,可以产生出很多效果。

那么如果制作好的SCORM课程如何对接到课程学习平台

(如果你这边是一个线上课程的学习平台,并和一个专门制作SCORM课程的公司合作,要把他们做好的SCORM课程放到自己线上的学习平台,并且记录学习等信息。那么应该如何对接好SCORM课程和线上学习平台)

SCORM主要的函数解析

一、函数
1、doLMSInitialize:初始化时调用的函数
2、doLMSCommit:提交数据时调用的函数
3、doLMSGetValue(name):获取SCORM数据模型某个值
4、doLMSSetValue(name,value):设置SCORM数据模型某个值
5、doLMSFinish:完成时调用的函数

二、数据模型(在项目中可通过window.API获取SCORM数据模型,格式内容如下)
获取数据模型中的某个值:doLMSGetValue(‘cmi.core.lesson_progress’)

{
	comments: "", // 存储评论数据
	comments_from_lms: "", // 存储LMS关于内容对象的评论数据
	core: {
		credit: "", // 学分
		entry: "", // 入口(进入内容对象)
		exit: "", // 退出途径
		lesson_location: "", // 记录上次离开sco时的位置
		lesson_mode: "normal", // 课的模式
		lesson_progress: "", // 记录课程学习进度
		lesson_status: "incomplete", // 记录课程的完成情况
		score: {
			max: "100", // 最高成绩
			min: "", // 最低成绩
			raw: "0", // 最后一次成绩
		},
		session_time: "00:00:00", // 本次学习时间
		student_id: "", // 学生学号
		student_name: "", // 学生姓名
		total_time: "", // 学习总时间
	},
	interactions: {
		childArray: [], // 返回集合中元素总数
	},
	launch_data: "", // 内容对象运行时所需的数据
	objectives: {
		childArray: [], // 返回所有属性
	},
	student_data: {
		mastery_score: "", // 掌握得分
		max_time_allowed: "", // 最大允许时间
		time_limit_action: "", // 限时反应
	},
	student_preference: {
		audio: "", // 音频
		language: "", // 语言
		speed: "", // 速度
		text: "", // 文本
	},
	suspend_data: "", // 暂存数据
},
SCORM课程制作端

首先他们制作端会在SCORM课程课程中加入 linkSCORM12.js 文件,这是执行调用SCORM标准的函数的必须文件(这是调用SCORM标准执行函数的js代码,下面是一段示例代码)

var _Debug = false;
var _NoError = 0;
var _ServerBusy = 102;
var _InvalidArgumentError = 201;
var _ElementCannotHaveChildren = 202;
var _ElementIsNotAnArray = 203;
var _NotInitialized = 301;
var _NotImplementedError = 401;
var _InvalidSetValue = 402;
var _ElementIsReadOnly = 403;
var _ElementIsWriteOnly = 404;
var _IncorrectDataType = 405;
var apiHandle = null;
var API = null;
var exitPageStatus;
var numTry = 0;
var isrenchuan = 0;
var startDate;
var lessonProgress = 0;
var dataStatus = "";
//alert("-------------SCORM--------------------001");
function runSeekStr(str, from, to) {
	//alert("--------------------SCORM------------002");
	var mystr = str;
	var str = str.toLowerCase();
	var from = from.toLowerCase();
	var to = to.toLowerCase();
	if (!(str.indexOf(from) + 1)) {
		return "";
	}
	var fromhere = str.indexOf(from) + from.length;
	var tostr = str.substr(fromhere, str.length - fromhere);
	mystr = mystr.substr(fromhere, str.length - fromhere);
	var tothere = tostr.length;
	if (to != "" && (tostr.indexOf(to) + 1)) {
		tothere = tostr.indexOf(to);
	}
	return mystr.substr(0, tothere);
}
function runFind(url) {
	//alert("--------------------SCORM------------003");
	try {
		isrenchuan = runSeekStr(url, "isrenchuan=", "&");
		if (isrenchuan.length) {
			return true;
		}
		else {
			return false;
		}
	}
	catch (e) {
		return false;
		//alert("读取参数时发生错误:\n\n" + e);
	}
}
function runURL(win) {
	//alert("--------------------SCORM------------004");
	try {
		if (runFind(win.document.location + "")) {
			return true;
		}
		else {
			numTry++;
			if (numTry > 1) {
				return false;
			}
			if (win.opener != null) {
				if (win == window.top) {
					return (runURL(win.opener));
				}
			}
			return (runURL(win.parent));
		}
	}
	catch (e) {
		//alert("读取参数时发生错误:\n\n" + e);
		return false;
	}
}
runURL(window);
function doLMSInitialize() {
	//alert("Lms init");
	//alert("--------------------SCORM------------005");
	var api = getAPIHandle();
	if (api == null) {
		return "false";
	}
	var result = api.LMSInitialize("");
	if (result.toString() != "true") {
		var err = ErrorHandler();
	}
	doLMSSetValue("cmi.core.score.raw", 0 + "")
	return result.toString();
}
function doLMSFinish() {
	//alert("--------------------SCORM------------006");
	var api = getAPIHandle();
	if (api == null) {
		return "false";
	}
	else {
		var result = api.LMSFinish("");
		if (result.toString() != "true") {
			var err = ErrorHandler();
		}
	}
	return result.toString();
}
function doLMSCommit(...data) {
	return new Promise(async (resolve, reject) => {
		//alert("Lms commit'");
		//alert("--------------------SCORM------------007");
		var api = getAPIHandle();
		if (api == null) {
			resolve("false");
		} else {
			var result = await api.LMSCommit(...data || "");
			if (result != "true") {
				var err = ErrorHandler();
			}
		}
		resolve(result);
	})
}
function doLMSGetValue(name) {
	//console.log("Lms read data '" + name +"'");
	//alert("--------------------SCORM------------008");
	//alert(name);
	var api = getAPIHandle();
	if (api == null) {
		return "";
	}
	else {
		var value = api.LMSGetValue(name);
		var errCode = api.LMSGetLastError().toString();
		if (errCode != _NoError) {
			var errDescription = api.LMSGetErrorString(errCode);
			return "";
		}
		else {
			if (parseInt(isrenchuan)) {
				//alert("doLMSGetValue: "+name+" = "+value.toString());
			}
			return value;
		}
	}
}
function doLMSSetValue(name, value) {
	//console.log("Lms write data '" + name +"' = " + value);
	//alert("--------------------SCORM------------009");
	//alert(name+":" +value);
	if (parseInt(isrenchuan)) {
		//alert("doLMSSetValue: "+name+" = "+value);
	}
	var api = getAPIHandle();
	if (api == null) {
		return;
	}
	else {
		var result = api.LMSSetValue(name, value);
		if (result.toString() != "true") {
			var err = ErrorHandler();
		}
	}
	if (name == "cmi.core.lesson_status") {
		computeTime();
		doLMSCommit();
		if (value == "completed") {
			//doLMSFinish();
		}
	}
	return;
}
function doLMSGetLastError() {
	//alert("--------------------SCORM------------010");
	var api = getAPIHandle();
	if (api == null) {
		return _GeneralError;
	}
	return api.LMSGetLastError().toString();
}
function doLMSGetErrorString(errorCode) {
	//alert("--------------------SCORM------------011");
	var api = getAPIHandle();
	if (api == null) {
		return "false";
	}
	return api.LMSGetErrorString(errorCode).toString();
}
function doLMSGetDiagnostic(errorCode) {
	//alert("--------------------SCORM------------012");
	var api = getAPIHandle();
	if (api == null) {
		return "false";
	}
	return api.LMSGetDiagnostic(errorCode).toString();
}
function LMSIsInitialized() {
	//alert("--------------------SCORM------------013");
	var api = getAPIHandle();
	if (api == null) {
		return "false";
	}
	else {
		var value = api.LMSGetValue("cmi.core.student_name");
		var errCode = api.LMSGetLastError().toString();
		if (errCode == _NotInitialized) {
			return false;
		}
		else {
			return true;
		}
	}
}
function ErrorHandler() {
	//alert("--------------------SCORM------------014");
	var api = getAPIHandle();
	if (api == null) {
		return "false";
	}
	var errCode = api.LMSGetLastError().toString();
	if (errCode != _NoError) {
		var errDescription = api.LMSGetErrorString(errCode);
		if (_Debug == true) {
			errDescription += "\n";
			errDescription += api.LMSGetDiagnostic(null);
		}
	}
	return errCode;
}
function getAPIHandle() {
	//alert("--------------------SCORM------------015");
	if (apiHandle == null) {
		var tries = 0;
		var win = window;
		while ((win.API == null)) {
			tries++;
			if (tries < 50) {
				if ((win.parent != null) && (win.parent != win)) {
					win = win.parent;
				}
				else if ((win.opener != null) && (typeof (win.opener) != "undefined")) {
					win = win.opener;
				}
				else {
					break;
				}
			}
			else {
				break;
			}
		}
		apiHandle = win.API;
	}
	return apiHandle;
}
function doSetSCOID(id) {
	//alert("--------------------SCORM------------016");
	var api = getAPIHandle();
	if (api == null) {
		return "false";
	}
	doTurnoff();
	api.setSCOID(id);
	doTurnon();
}
function doTurnon() {
	//console.log("doTurnon");
	//alert("--------------------SCORM------------017");
	startTimer();
	var result = doLMSInitialize();
	var status = doLMSGetValue("cmi.core.lesson_status");
	if (status == "not attempted") {
		doLMSSetValue("cmi.core.lesson_status", "incomplete");
	}
	//var mySCOstatusStr = doLMSGetValue("cmi.suspend_data");
	//var location = doLMSGetValue( "cmi.suspend_data" );
	//alert("mySCOstatusStr:" +mySCOstatusStr);
	//findSWF("main").SetVariable("jsCore",location);
	//findSWF("study").SetVariable("jsCore",mySCOstatusStr);
	exitPageStatus = false;
	if (parseInt(isrenchuan)) {
		//alert("jsCore = "+location);
	}
}
function startTimer() {
	//console.log("startTimer");
	//alert("--------------------SCORM------------018");
	startDate = new Date().getTime();
}
function computeTime() {
	//alert("--------------------SCORM------------019");
	if (startDate != 0 && startDate != undefined) {
		var currentDate = new Date().getTime();
		var elapsedSeconds = ((currentDate - startDate) / 1000);
		var formattedTime = convertTotalSeconds(elapsedSeconds);
	}
	else {
		formattedTime = "00:00:00.0";
	}
	doLMSSetValue("cmi.core.session_time", formattedTime);
}
function doBack() {
	//alert("--------------------SCORM------------020");
	computeTime();
	exitPageStatus = true;
	var result;
	//result = doLMSCommit();
	//result = doLMSFinish();
}
function doContinue(status) {
	//alert("--------------------SCORM------------021");
	// doLMSSetValue( "cmi.core.exit", "" );
	var mode = doLMSGetValue("cmi.core.lesson_mode");
	if (mode != "review" && mode != "browse") {
		doLMSSetValue("cmi.core.lesson_status", status);
	}
	exitPageStatus = true;
	var result;
	//result = doLMSCommit();
	//result = doLMSFinish();
}
function doQuit() {
	//alert("--------------------SCORM------------022");
	doLMSSetValue("cmi.core.exit", "suspend");
	computeTime();
	exitPageStatus = true;
	var result;
	//result = doLMSCommit();
	//result = doLMSFinish();
}
function unloadPage() {
	//alert("--------------------SCORM------------023");
	//alert("lessonProgress" + lessonProgress)
	if (lessonProgress >= 100) {
		scoFinished()
	}
	if (exitPageStatus != true) {
		//doQuit();
	}
}
function doTurnok() {
	//alert("--------------------SCORM------------024");
	var mode = doLMSGetValue("cmi.core.lesson_mode");
	if (mode != "review" && mode != "browse") {
		doLMSSetValue("cmi.core.lesson_status", "completed");
	}
	exitPageStatus = true;
	doLMSSetValue("cmi.core.exit", "");
	//doLMSCommit();
	//doLMSFinish();
}
function doTurnoff() {
	//alert("--------------------SCORM------------025");
	if (exitPageStatus != true) {
		exitPageStatus = true;
		computeTime();
		doLMSSetValue("cmi.core.exit", "");
		doLMSCommit();
		doLMSFinish();
	}
}
function getMYSCOstatus(len) {
	//alert("--------------------SCORM------------026");
	var mySCOstatusStr = doLMSGetValue("cmi.suspend_data");
	//alert("mySCOstatusStr:"+mySCOstatusStr);
	var arrmySCO = mySCOstatusStr.split("|");
	//alert("arrmySCO.length:"+arrmySCO.length);
	//alert("len:"+len);
	if (arrmySCO.length > len) {
		scoFinished();
	}
}
function scoFinished() {
	//alert("--------------------SCORM------------027");
	//alert("本章学习完毕,请点击章节目录继续学习!");
	doContinue('completed');
}
function SWFSetValue(type, val) {
	//alert("--------------------SCORM------------028");
	//alert("type:" + type);
	//alert("val:" + val);
	if (type == "cmi.core.lesson_progress") {
		lessonProgress = val
		//alert("lessonProgress:" + lessonProgress)
	}
	if (type == "cmi.suspend_data") {
		dataStatus = val
		//alert("dataStatus:" + dataStatus)
	}
	var error = doLMSSetValue(type, val);
	document.study.SCOReturnValue("ERROR", error);
	doLMSCommit()
}
function saveScos(i) {
	//alert("--------------------SCORM------------029");
	//alert("提交分数"+i+"分!");
	doLMSSetValue("cmi.core.score.raw", i + "")
}
if (window.attachEvent) {
	//alert("--------------------SCORM------------030");
	window.attachEvent('onunload', function () {
		doTurnoff();
	});
}
else if (window.addEventListener) {
	//alert("--------------------SCORM------------031");
	window.addEventListener('onunload', function () {
		doTurnoff();
	});
}
function convertTotalSeconds(ts) {
	//alert("--------------------SCORM------------032");
	var sec = (ts % 60);
	ts -= sec;
	var tmp = (ts % 3600);
	ts -= tmp;
	sec = Math.round(sec * 100) / 100;
	var strSec = new String(sec);
	var strWholeSec = strSec;
	var strFractionSec = "";
	if (strSec.indexOf(".") != -1) {
		strWholeSec = strSec.substring(0, strSec.indexOf("."));
		strFractionSec = strSec.substring(strSec.indexOf(".") + 1, strSec.length);
	}
	if (strWholeSec.length < 2) {
		strWholeSec = "0" + strWholeSec;
	}
	strSec = strWholeSec;
	if (strFractionSec.length) {
		strSec = strSec + "." + strFractionSec;
	}
	if ((ts % 3600) != 0)
		var hour = 0;
	else var hour = (ts / 3600);
	if ((tmp % 60) != 0)
		var min = 0;
	else var min = (tmp / 60);
	if ((new String(hour)).length < 2)
		hour = "0" + hour;
	if ((new String(min)).length < 2)
		min = "0" + min;
	var rtnVal = hour + ":" + min + ":" + strSec;
	return rtnVal;
}
线上课程学习平台

在SCORM课程中引入SCORMAPI12.js,这个js文件是对接了SCORM函数和设置了SCORM数据模型的接口,就是在window.API上挂载函数和数据,然后SCORM课程里面调用SCORM的函数来实现两端的对接,文件示例如下(可根据个人情况进行修改)

(function () {
    window.simplifyScorm = {};
    /**
     * 全局配置
     */
    window.simplifyScorm.constants = {
        SCORM_TRUE: "true",
        SCORM_FALSE: "false",
        STATE_NOT_INITIALIZED: 0,
        STATE_INITIALIZED: 1,
        STATE_TERMINATED: 2,
        LOG_LEVEL_DEBUG: 1,
        LOG_LEVEL_INFO: 2,
        LOG_LEVEL_WARNING: 3,
        LOG_LEVEL_ERROR: 4,
        LOG_LEVEL_NONE: 5
    };
    window.simplifyScorm.jsonFormatter = jsonFormatter;
    /**
     * jsonFormatter//转为json格式
     *
     * @returns {json}
     */
    function jsonFormatter() {
        this.jsonString = true;
        delete this.toJSON;
        var jsonValue = JSON.stringify(this);
        delete this.jsonString;
        this.toJSON = jsonFormatter;
        var returnObject = JSON.parse(jsonValue);
        delete returnObject.jsonString;
        for (var key in returnObject) {
            if (returnObject.hasOwnProperty(key) && key.indexOf("_") === 0) {
                delete returnObject[key];
            }
        }
        return returnObject;
    }
})();
/**
 * BaseAPI
 */
(function () {
    window.simplifyScorm.BaseAPI = BaseAPI;
    var constants = window.simplifyScorm.constants;
    function BaseAPI() {
        var _self = this;
        // Internal State
        _self.currentState = constants.STATE_NOT_INITIALIZED;
        _self.lastErrorCode = 0;
        // Utility Functions
        _self.apiLog = apiLog;
        _self.apiLogLevel = constants.LOG_LEVEL_ERROR;
        _self.clearSCORMError = clearSCORMError;
        _self.getLmsErrorMessageDetails = getLmsErrorMessageDetails;
        _self.isInitialized = isInitialized;
        _self.isNotInitialized = isNotInitialized;
        _self.isTerminated = isTerminated;
        _self.listenerArray = [];
        _self.on = onListener;
        _self.processListeners = processListeners;
        _self.throwSCORMError = throwSCORMError;
    }

    /**
     * Logging for all SCORM actions
     *
     * @param functionName
     * @param CMIElement
     * @param logMessage
     * @param messageLevel
     */
    function apiLog(functionName, CMIElement, logMessage, messageLevel) {
        logMessage = formatMessage(functionName, CMIElement, logMessage);
        if (messageLevel >= this.apiLogLevel) {
            switch (messageLevel) {
                case constants.LOG_LEVEL_ERROR:
                    console.error(logMessage);
                    break;
                case constants.LOG_LEVEL_WARNING:
                    console.warn(logMessage);
                    break;
                case constants.LOG_LEVEL_INFO:
                    console.info(logMessage);
                    break;
            }
        }
    }

    /**
     * Clears the last SCORM error code on success
     */
    function clearSCORMError(success) {
        if (success !== constants.SCORM_FALSE) {
            this.lastErrorCode = 0;
        }
    }

    /**
     * Formats the SCORM messages for easy reading
     *
     * @param functionName
     * @param CMIElement
     * @param message
     * @returns {string}
     */
    function formatMessage(functionName, CMIElement, message) {
        var baseLength = 20;
        var messageString = "";
        messageString += functionName;
        var fillChars = baseLength - messageString.length;
        for (var i = 0; i < fillChars; i++) {
            messageString += " ";
        }
        messageString += ": ";
        if (CMIElement) {
            var CMIElementBaseLength = 70;
            messageString += CMIElement;
            fillChars = CMIElementBaseLength - messageString.length;
            for (var j = 0; j < fillChars; j++) {
                messageString += " ";
            }
        }
        if (message) {
            messageString += message;
        }
        return messageString;
    }

    /**
     * Returns the message that corresponds to errrorNumber
     * APIs that inherit BaseAPI should override this function
     */
    function getLmsErrorMessageDetails(_errorNumber, _detail) {
        return "No error";
    }

    /**
     * Returns true if the API's current state is STATE_INITIALIZED
     */
    function isInitialized() {
        return this.currentState === constants.STATE_INITIALIZED;
    }

    /**
     * Returns true if the API's current state is STATE_NOT_INITIALIZED
     */
    function isNotInitialized() {
        return this.currentState === constants.STATE_NOT_INITIALIZED;
    }

    /**
     * Returns true if the API's current state is STATE_TERMINATED
     */
    function isTerminated() {
        return this.currentState === constants.STATE_TERMINATED;
    }

    /**
     * Provides a mechanism for attaching to a specific SCORM event
     *
     * @param listenerString
     * @param callback
     */
    function onListener(listenerString, callback) {
        if (!callback) return;
        var listenerFunctions = listenerString.split(" ");
        for (var i = 0; i < listenerFunctions.length; i++) {
            var listenerSplit = listenerFunctions[i].split(".");
            if (listenerSplit.length === 0) return;
            var functionName = listenerSplit[0];
            var CMIElement = null;
            if (listenerSplit.length > 1) {
                CMIElement = listenerString.replace(functionName + ".", "");
            }
            this.listenerArray.push({
                functionName: functionName,
                CMIElement: CMIElement,
                callback: callback
            });
        }
    }

    /**
     * Processes any 'on' listeners that have been created
     *
     * @param functionName
     * @param CMIElement
     * @param value
     */
    function processListeners(functionName, CMIElement, value) {
        for (var i = 0; i < this.listenerArray.length; i++) {
            var listener = this.listenerArray[i];
            console.log(11, listener)
            var functionsMatch = listener.functionName === functionName;
            var listenerHasCMIElement = !!listener.CMIElement;
            var CMIElementsMatch = listener.CMIElement === CMIElement;

            if (functionsMatch && (!listenerHasCMIElement || CMIElementsMatch)) {
                listener.callback(CMIElement, value);
            }
        }
    }

    /**
     * Throws a SCORM error
     *
     * @param errorNumber
     * @param message
     */
    function throwSCORMError(errorNumber, message) {
        if (!message) {
            message = this.getLmsErrorMessageDetails(errorNumber);
        }
        this.apiLog("throwSCORMError", null, errorNumber + ": " + message, constants.LOG_LEVEL_ERROR);
        this.lastErrorCode = String(errorNumber);
    }

})();
/**
 * ScormAPI
 */
(function () {
    window.simplifyScorm.ScormAPI = ScormAPI;
    var BaseAPI = window.simplifyScorm.BaseAPI;
    var constants = window.simplifyScorm.constants;
    var jsonFormatter = window.simplifyScorm.jsonFormatter;

    window.API = new ScormAPI();

    function ScormAPI() {
        var _self = this;
        BaseAPI.call(_self);
        // API Signature
        _self.LMSInitialize = LMSInitialize;
        _self.LMSFinish = LMSFinish;
        _self.LMSGetValue = LMSGetValue;
        _self.LMSSetValue = LMSSetValue;
        _self.LMSCommit = LMSCommit;
        _self.LMSGetLastError = LMSGetLastError;
        _self.LMSGetErrorString = LMSGetErrorString;
        _self.LMSGetDiagnostic = LMSGetDiagnostic;
        // Data Model
        _self.cmi = new CMI(_self);
        // Utility Functions
        _self.checkState = checkState;
        _self.getLmsErrorMessageDetails = getLmsErrorMessageDetails;
        _self.loadFromJSON = loadFromJSON;
        _self.replaceWithAnotherScormAPI = replaceWithAnotherScormAPI;

        /**
         * @returns {string} bool 初始化
         */
        function LMSInitialize() {
            var returnValue = constants.SCORM_FALSE;
            if (_self.isInitialized()) {
                _self.throwSCORMError(101, "LMS已经初始化!");
            } else if (_self.isTerminated()) {
                _self.throwSCORMError(101, "LMS已经完成!");
            } else {
                _self.currentState = constants.STATE_INITIALIZED;
                returnValue = constants.SCORM_TRUE;
                _self.processListeners("LMSInitialize");
            }
            _self.apiLog("LMSInitialize", null, "returned: " + returnValue, constants.LOG_LEVEL_INFO);
            _self.clearSCORMError(returnValue);
            return returnValue;
        }

        /**
         * @returns {string} bool
         */
        async function LMSFinish() {
            console.log('完成课程', window.API.cmi.toJSON())
            var returnValue = constants.SCORM_FALSE;
            if (_self.checkState()) {
                _self.currentState = constants.STATE_TERMINATED;
                returnValue = constants.SCORM_TRUE;
                _self.processListeners("LMSFinish");
            }
            _self.apiLog("LMSFinish", null, "returned: " + returnValue, constants.LOG_LEVEL_INFO);
            _self.clearSCORMError(returnValue);
            var ifSend = await updateCourseApi() //修改课程学习
            if (ifSend) {
                returnValue = constants.SCORM_TRUE
            } else {
                returnValue = constants.SCORM_FALSE
            }
            return returnValue;
        }

        /**
         * @param CMIElement
         * @returns {string}
         */
        function LMSGetValue(CMIElement) {
            var returnValue = "";
            if (_self.checkState()) {
                returnValue = getCMIValue(CMIElement);
                _self.processListeners("LMSGetValue", CMIElement);
            }
            _self.apiLog("LMSGetValue", CMIElement, ": returned: " + returnValue, constants.LOG_LEVEL_INFO);
            _self.clearSCORMError(returnValue);
            console.log('获取数据', CMIElement, returnValue)
            return returnValue;
        }

        /**
         * @param CMIElement
         * @param value
         * @returns {string}
         */
        function LMSSetValue(CMIElement, value) {
            console.log('设置数据', CMIElement, value)
            var returnValue = "";
            if (_self.checkState()) {
                returnValue = setCMIValue(CMIElement, value);
                _self.processListeners("LMSSetValue", CMIElement, value);
            }
            _self.apiLog("LMSSetValue", CMIElement, ": " + value + ": returned: " + returnValue, constants.LOG_LEVEL_INFO);
            _self.clearSCORMError(returnValue);
            return returnValue;
        }

        /**
         * Orders LMS to store all content parameters
         *
         * @returns {string} bool
         */
        async function LMSCommit(type, data) {
            console.log('提交数据', window.API.cmi.toJSON())
            var returnValue = constants.SCORM_FALSE;
            if (_self.checkState()) {
                returnValue = constants.SCORM_TRUE;
                _self.processListeners("LMSCommit");
            }
            _self.apiLog("LMSCommit", null, "returned: " + returnValue, constants.LOG_LEVEL_INFO);
            _self.clearSCORMError(returnValue);

            // 判断调用什么接口
            console.log('提交接口的参数----------', type, data)
            if (type == 'uploadImg') { //上传图片
                return await uploadImgFuc(data)
            } else if (type == 'getRank') { //排行榜
                return await getRankListFuc(data)
            } else if (type == 'getUser') { //用户信息
                return await getUserInfoFuc(data)
            } else if (type == 'setScore') { //设置分数
                return await updateUserScore()
            } else { //修改课程学习
                let ifSend = await updateCourseApi()
                if (ifSend) {
                    returnValue = constants.SCORM_TRUE
                } else {
                    returnValue = constants.SCORM_FALSE
                }
                return returnValue;
            }
        }

        /**
         * Returns last error code
         *
         * @returns {string}
         */
        function LMSGetLastError() {
            var returnValue = _self.lastErrorCode;
            _self.processListeners("LMSGetLastError");
            _self.apiLog("LMSGetLastError", null, "returned: " + returnValue, constants.LOG_LEVEL_INFO);
            return returnValue;
        }

        /**
         * Returns the errorNumber error description
         *
         * @param CMIErrorCode
         * @returns {string}
         */
        function LMSGetErrorString(CMIErrorCode) {
            var returnValue = "";
            if (CMIErrorCode !== null && CMIErrorCode !== "") {
                returnValue = _self.getLmsErrorMessageDetails(CMIErrorCode);
                _self.processListeners("LMSGetErrorString");
            }
            _self.apiLog("LMSGetErrorString", null, "returned: " + returnValue, constants.LOG_LEVEL_INFO);
            return returnValue;
        }

        /**
         * Returns a comprehensive description of the errorNumber error.
         *
         * @param CMIErrorCode
         * @returns {string}
         */
        function LMSGetDiagnostic(CMIErrorCode) {
            var returnValue = "";
            if (CMIErrorCode !== null && CMIErrorCode !== "") {
                returnValue = _self.getLmsErrorMessageDetails(CMIErrorCode, true);
                _self.processListeners("LMSGetDiagnostic");
            }
            _self.apiLog("LMSGetDiagnostic", null, "returned: " + returnValue, constants.LOG_LEVEL_INFO);
            return returnValue;
        }

        /**
         * Checks the LMS state and ensures it has been initialized
         */
        function checkState() {
            if (!this.isInitialized()) {
                this.throwSCORMError(301);
                return false;
            }
            return true;
        }

        /**
         * Sets a value on the CMI Object
         *
         * @param CMIElement
         * @param value
         * @returns {string}
         */
        function setCMIValue(CMIElement, value) {
            if (!CMIElement || CMIElement === "") {
                return constants.SCORM_FALSE;
            }
            var structure = CMIElement.split(".");
            var refObject = _self;
            var found = constants.SCORM_FALSE;
            for (var i = 0; i < structure.length; i++) {
                if (i === structure.length - 1) {
                    if (!refObject.hasOwnProperty(structure[i])) {
                        _self.throwSCORMError(101, "setCMIValue未找到以下项的元素:" + CMIElement);
                    } else {
                        refObject[structure[i]] = value;
                        found = constants.SCORM_TRUE;
                    }
                } else {
                    refObject = refObject[structure[i]];
                    if (!refObject) {
                        _self.throwSCORMError(101, "setCMIValue未找到以下项的元素:" + CMIElement);
                        break;
                    }
                    if (refObject.hasOwnProperty("childArray")) {
                        var index = parseInt(structure[i + 1], 10);
                        // SCO is trying to set an item on an array
                        if (!isNaN(index)) {
                            var item = refObject.childArray[index];
                            if (item) {
                                refObject = item;
                            } else {
                                var newChild;

                                if (CMIElement.indexOf("cmi.objectives") > -1) {
                                    newChild = new CMI_ObjectivesObject(_self);
                                } else if (CMIElement.indexOf(".correct_responses") > -1) {
                                    newChild = new CMI_InteractionsCorrectResponsesObject(_self);
                                } else if (CMIElement.indexOf(".objectives") > -1) {
                                    newChild = new CMI_InteractionsObjectivesObject(_self);
                                } else if (CMIElement.indexOf("cmi.interactions") > -1) {
                                    newChild = new CMI_InteractionsObject(_self);
                                }

                                if (!newChild) {
                                    _self.throwSCORMError(101, "无法创建新的子实体:" + CMIElement);
                                } else {
                                    refObject.childArray.push(newChild);
                                    refObject = newChild;
                                }
                            }

                            // Have to update i value to skip the array position
                            i++;
                        }
                    }
                }
            }
            if (found === constants.SCORM_FALSE) {
                _self.apiLog("LMSSetValue", null, "There was an error setting the value for: " + CMIElement + ", value of: " + value, constants.LOG_LEVEL_WARNING);
            }
            return found;
        }

        /**
         * Gets a value from the CMI Object
         *
         * @param CMIElement
         * @returns {*}
         */
        function getCMIValue(CMIElement) {
            if (!CMIElement || CMIElement === "") {
                return "";
            }
            var structure = CMIElement.split(".");
            var refObject = _self;
            var lastProperty = null;
            for (var i = 0; i < structure.length; i++) {
                lastProperty = structure[i];
                if (i === structure.length - 1) {
                    if (!refObject.hasOwnProperty(structure[i])) {
                        _self.throwSCORMError(101, "getCMIValue未找到以下项的值:" + CMIElement);
                    }
                }
                refObject = refObject[structure[i]];
            }
            if (refObject === null || refObject === undefined) {
                if (lastProperty === "_children") {
                    _self.throwSCORMError(202);
                } else if (lastProperty === "_count") {
                    _self.throwSCORMError(203);
                }
                return "";
            } else {
                return refObject;
            }
        }

        /**
         * Returns the message that corresponds to errrorNumber.
         */
        function getLmsErrorMessageDetails(errorNumber, detail) {
            var basicMessage = "";
            var detailMessage = "";
            // Set error number to string since inconsistent from modules if string or number
            errorNumber = String(errorNumber);
            switch (errorNumber) {
                case "101":
                    basicMessage = "General Exception";
                    detailMessage = "No specific error code exists to describe the error. Use LMSGetDiagnostic for more information";
                    break;
                case "201":
                    basicMessage = "Invalid argument error";
                    detailMessage = "Indicates that an argument represents an invalid data model element or is otherwise incorrect.";
                    break;
                case "202":
                    basicMessage = "Element cannot have children";
                    detailMessage = "Indicates that LMSGetValue was called with a data model element name that ends in \"_children\" for a data model element that does not support the \"_children\" suffix.";
                    break;
                case "203":
                    basicMessage = "Element not an array - cannot have count";
                    detailMessage = "Indicates that LMSGetValue was called with a data model element name that ends in \"_count\" for a data model element that does not support the \"_count\" suffix.";
                    break;
                case "301":
                    basicMessage = "Not initialized";
                    detailMessage = "Indicates that an API call was made before the call to LMSInitialize.";
                    break;
                case "401":
                    basicMessage = "Not implemented error";
                    detailMessage = "The data model element indicated in a call to LMSGetValue or LMSSetValue is valid, but was not implemented by this LMS. SCORM 1.2 defines a set of data model elements as being optional for an LMS to implement.";
                    break;
                case "402":
                    basicMessage = "Invalid set value, element is a keyword";
                    detailMessage = "Indicates that LMSSetValue was called on a data model element that represents a keyword (elements that end in \"_children\" and \"_count\").";
                    break;
                case "403":
                    basicMessage = "Element is read only";
                    detailMessage = "LMSSetValue was called with a data model element that can only be read.";
                    break;
                case "404":
                    basicMessage = "Element is write only";
                    detailMessage = "LMSGetValue was called on a data model element that can only be written to.";
                    break;
                case "405":
                    basicMessage = "Incorrect Data Type";
                    detailMessage = "LMSSetValue was called with a value that is not consistent with the data format of the supplied data model element.";
                    break;
                default:
                    basicMessage = "No Error";
                    detailMessage = "No Error";
                    break;
            }
            return detail ? detailMessage : basicMessage;
        }

        /**
         * Loads CMI data from a JSON object.
         */
        function loadFromJSON(json, CMIElement) {
            if (!_self.isNotInitialized()) {
                console.error("loadFromJSON can only be called before the call to LMSInitialize.");
                return;
            }
            CMIElement = CMIElement || "cmi";
            for (var key in json) {
                if (json.hasOwnProperty(key) && json[key]) {
                    var currentCMIElement = CMIElement + "." + key;
                    var value = json[key];
                    if (value["childArray"]) {
                        for (var i = 0; i < value["childArray"].length; i++) {
                            _self.loadFromJSON(value["childArray"][i], currentCMIElement + "." + i);
                        }
                    } else if (value.constructor === Object) {
                        _self.loadFromJSON(value, currentCMIElement);
                    } else {
                        setCMIValue(currentCMIElement, value);
                    }
                }
            }
        }

        /**
         * Replace the whole API with another
         */
        function replaceWithAnotherScormAPI(newAPI) {
            // API Signature
            _self.LMSInitialize = newAPI.LMSInitialize;
            _self.LMSFinish = newAPI.LMSFinish;
            _self.LMSGetValue = newAPI.LMSGetValue;
            _self.LMSSetValue = newAPI.LMSSetValue;
            _self.LMSCommit = newAPI.LMSCommit;
            _self.LMSGetLastError = newAPI.LMSGetLastError;
            _self.LMSGetErrorString = newAPI.LMSGetErrorString;
            _self.LMSGetDiagnostic = newAPI.LMSGetDiagnostic;
            // Data Model
            _self.cmi = newAPI.cmi;
            // Utility Functions
            _self.checkState = newAPI.checkState;
            _self.getLmsErrorMessageDetails = newAPI.getLmsErrorMessageDetails;
            _self.loadFromJSON = newAPI.loadFromJSON;
            _self.replaceWithAnotherScormAPI = newAPI.replaceWithAnotherScormAPI;
            // API itself
            _self = newAPI; // eslint-disable-line consistent-this
        }
        return _self;
    }

    /**
     * Scorm 1.2 Cmi data model 数据模型
     */
    function CMI(API) {
        return {
            _suspend_data: "",//暂存数据
            get suspend_data() { return this._suspend_data; },
            set suspend_data(suspend_data) { this._suspend_data = suspend_data; },

            _launch_data: "",//内容对象运行时所需的数据
            get launch_data() { return this._launch_data; },
            set launch_data(launch_data) { API.isNotInitialized() ? this._launch_data = launch_data : API.throwSCORMError(403); },

            _comments: "",//存储评论数据
            get comments() { return this._comments; },
            set comments(comments) { this._comments = comments; },

            _comments_from_lms: "",//存储LMS关于内容对象的评论数据
            get comments_from_lms() { return this._comments_from_lms; },
            set comments_from_lms(comments_from_lms) { API.isNotInitialized() ? this._comments_from_lms = comments_from_lms : API.throwSCORMError(403); },

            core: {
                __children: "student_id,student_name,lesson_location,credit,lesson_status,entry,score,total_time,lesson_mode,exit,session_time",
                get _children() { return this.__children; },
                set _children(_children) { API.throwSCORMError(402); },

                _student_id: "",//学生学号
                get student_id() { return this._student_id; },
                set student_id(student_id) { API.isNotInitialized() ? this._student_id = student_id : API.throwSCORMError(403); },

                _student_name: "",//学生姓名
                get student_name() { return this._student_name; },
                set student_name(student_name) { API.isNotInitialized() ? this._student_name = student_name : API.throwSCORMError(403); },

                _lesson_location: "", //记录上次离开sco时的位置
                get lesson_location() { return this._lesson_location; },
                set lesson_location(lesson_location) { this._lesson_location = lesson_location; },

                _lesson_progress: "", //记录课程学习进度
                get lesson_progress() { return this._lesson_progress; },
                set lesson_progress(lesson_progress) { this._lesson_progress = lesson_progress; },

                _credit: "",//是否有学分
                get credit() { return this._credit; },
                set credit(credit) { API.isNotInitialized() ? this._credit = credit : API.throwSCORMError(403); },

                _lesson_status: "not attempted",//记录sco的完成情况
                get lesson_status() { return this._lesson_status; },
                set lesson_status(lesson_status) { this._lesson_status = lesson_status; },

                _entry: "", //入口(进入内容对象)
                get entry() { return this._entry; },
                set entry(entry) { API.isNotInitialized() ? this._entry = entry : API.throwSCORMError(403); },

                _total_time: "",//学习总时间
                get total_time() { return this._total_time; },
                set total_time(total_time) { API.isNotInitialized() ? this._total_time = total_time : API.throwSCORMError(403); },

                _lesson_mode: "normal",//课的模式
                get lesson_mode() { return this._lesson_mode; },
                set lesson_mode(lesson_mode) { API.isNotInitialized() ? this._lesson_mode = lesson_mode : API.throwSCORMError(403); },

                _exit: "",//退出途径
                get exit() { return (!this.jsonString) ? API.throwSCORMError(404) : this._exit; },
                set exit(exit) { this._exit = exit; },

                _session_time: "", //本次学习时间
                get session_time() { return (!this.jsonString) ? API.throwSCORMError(404) : this._session_time; },
                set session_time(session_time) { this._session_time = session_time; },

                score: {
                    __children: "raw,min,max",
                    get _children() { return this.__children; },
                    set _children(_children) { API.throwSCORMError(402); },

                    _raw: "",//最后一次成绩
                    get raw() { return this._raw; },
                    set raw(raw) { this._raw = raw; },

                    _min: "",//最低成绩
                    get min() { return this._min; },
                    set min(min) { this._min = min; },

                    _max: "100",//最高成绩
                    get max() { return this._max; },
                    set max(max) { this._max = max; },

                    toJSON: jsonFormatter
                },

                toJSON: jsonFormatter
            },

            objectives: {
                __children: "id,score,status",
                get _children() { return this.__children; },
                set _children(_children) { API.throwSCORMError(402); },

                childArray: [],//返回所有属性
                get _count() { return this.childArray.length; },
                set _count(_count) { API.throwSCORMError(402); },

                toJSON: jsonFormatter
            },

            student_data: {
                __children: "mastery_score,max_time_allowed,time_limit_action",
                get _children() { return this.__children; },
                set _children(_children) { API.throwSCORMError(402); },

                _mastery_score: "",//掌握得分
                get mastery_score() { return this._mastery_score; },
                set mastery_score(mastery_score) { API.isNotInitialized() ? this._mastery_score = mastery_score : API.throwSCORMError(403); },

                _max_time_allowed: "", //最大允许时间
                get max_time_allowed() { return this._max_time_allowed; },
                set max_time_allowed(max_time_allowed) { API.isNotInitialized() ? this._max_time_allowed = max_time_allowed : API.throwSCORMError(403); },

                _time_limit_action: "", //限时反应
                get time_limit_action() { return this._time_limit_action; },
                set time_limit_action(time_limit_action) { API.isNotInitialized() ? this._time_limit_action = time_limit_action : API.throwSCORMError(403); },

                toJSON: jsonFormatter
            },

            student_preference: { //针对内容对象的用户偏好设置
                __children: "audio,language,speed,text",
                get _children() { return this.__children; },
                set _children(_children) { API.throwSCORMError(402); },

                _audio: "",//音频 
                get audio() { return this._audio; },
                set audio(audio) { this._audio = audio; },

                _language: "", //语言
                get language() { return this._language; },
                set language(language) { this._language = language; },

                _speed: "", //速度
                get speed() { return this._speed; },
                set speed(speed) { this._speed = speed; },

                _text: "", //文本
                get text() { return this._text; },
                set text(text) { this._text = text; },

                toJSON: jsonFormatter
            },

            interactions: {
                __children: "id,objectives,time,type,correct_responses,weighting,student_response,result,latency",
                get _children() { return this.__children; },
                set _children(_children) { API.throwSCORMError(402); },

                childArray: [],//	返回集合中元素总数
                get _count() { return this.childArray.length; },
                set _count(_count) { API.throwSCORMError(402); },

                toJSON: jsonFormatter
            },

            toJSON: jsonFormatter
        };
    }

    function CMI_InteractionsObject(API) {
        return {
            _id: "",//某一交互ID
            get id() { return (!this.jsonString) ? API.throwSCORMError(404) : this._id; },
            set id(id) { this._id = id; },

            _time: "",//交互完成时间
            get time() { return (!this.jsonString) ? API.throwSCORMError(404) : this._time; },
            set time(time) { this._time = time; },

            _type: "",//交互类型(true-false/choice/fill-in/matching/performance/sequencing/likert/numeric)
            get type() { return (!this.jsonString) ? API.throwSCORMError(404) : this._type; },
            set type(type) { this._type = type; },

            _weighting: "",//一个交互的权重
            get weighting() { return (!this.jsonString) ? API.throwSCORMError(404) : this._weighting; },
            set weighting(weighting) { this._weighting = weighting; },

            _student_response: "",//用户提供的答案
            get student_response() { return (!this.jsonString) ? API.throwSCORMError(404) : this._student_response; },
            set student_response(student_response) { this._student_response = student_response; },

            _result: "",//由用户答案计算的交互结果  (correct/wrong/unanticipated/neutral/x.x)
            get result() { return (!this.jsonString) ? API.throwSCORMError(404) : this._result; },
            set result(result) { this._result = result; },

            _latency: "",//	交互时间间隔
            get latency() { return (!this.jsonString) ? API.throwSCORMError(404) : this._latency; },
            set latency(latency) { this._latency = latency; },

            objectives: {//交互目标集合中总数
                childArray: [],
                get _count() { return this.childArray.length; },
                set _count(_count) { API.throwSCORMError(402); },

                toJSON: jsonFormatter
            },

            correct_responses: {//存储一个交互的答案数
                childArray: [],
                get _count() { return this.childArray.length; },
                set _count(_count) { API.throwSCORMError(402); },

                toJSON: jsonFormatter
            },

            toJSON: jsonFormatter
        };
    }

    function CMI_ObjectivesObject(API) {
        return {
            _id: "",//一个目标对象ID
            get id() { return this._id; },
            set id(id) { this._id = id; },

            _status: "",//目标完成状态(passed/completed/failed/incomplete/browsed/not attempted)
            get status() { return this._status; },
            set status(status) { this._status = status; },

            score: {
                __children: "raw,min,max",//获得score子属性
                get _children() { return this.__children; },
                set _children(children) { API.throwSCORMError(402); },

                _raw: "",//目标分数
                get raw() { return this._raw; },
                set raw(raw) { this._raw = raw; },

                _min: "",//目标分数最小值
                get min() { return this._min; },
                set min(min) { this._min = min; },

                _max: "",//目标分数最大值
                get max() { return this._max; },
                set max(max) { this._max = max; },

                toJSON: jsonFormatter
            },

            toJSON: jsonFormatter
        };
    }

    function CMI_InteractionsObjectivesObject(API) {
        return {
            _id: "", //交互的目标ID
            get id() { return (!this.jsonString) ? API.throwSCORMError(404) : this._id; },
            set id(id) { this._id = id; },

            toJSON: jsonFormatter
        };
    }

    function CMI_InteractionsCorrectResponsesObject(API) {
        return {
            _pattern: "",//存储一个交互的答案
            get pattern() { return (!this.jsonString) ? API.throwSCORMError(404) : this._pattern; },
            set pattern(pattern) { this._pattern = pattern; },

            toJSON: jsonFormatter
        };
    }
})();
总的来说SCORM就是一种格式规范,他把数据模型、函数命名固定命名,当不同的人来使用的时候,只需要根据他的格式就很容易实现对接。
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 20
    评论
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

锕舒

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

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

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

打赏作者

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

抵扣说明:

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

余额充值