// 主脚本文件 - Scene Step 编辑器
function SceneStepEditor() {
this.fileManager = new FileManager();
this.codeGenerator = new CodeGenerator();
this.currentSteps = [];
this.stepFoldouts = [];
this.actionFoldouts = [];
this.initializeElements();
this.bindEvents();
this.loadInitialData();
}
// 初始化DOM元素引用
SceneStepEditor.prototype.initializeElements = function() {
this.fileSelect = document.getElementById('fileSelect');
this.newProcessBtn = document.getElementById('newProcessBtn');
this.stepsContainer = document.getElementById('stepsContainer');
this.saveBtn = document.getElementById('saveBtn');
this.generateCodeBtn = document.getElementById('generateCodeBtn');
// 模态框元素
this.newProcessModal = document.getElementById('newProcessModal');
this.newProcessName = document.getElementById('newProcessName');
this.confirmNewProcess = document.getElementById('confirmNewProcess');
this.cancelNewProcess = document.getElementById('cancelNewProcess');
this.confirmModal = document.getElementById('confirmModal');
this.confirmTitle = document.getElementById('confirmTitle');
this.confirmMessage = document.getElementById('confirmMessage');
this.confirmOk = document.getElementById('confirmOk');
this.confirmCancel = document.getElementById('confirmCancel');
this.codeModal = document.getElementById('codeModal');
this.generatedCode = document.getElementById('generatedCode');
this.copyCodeBtn = document.getElementById('copyCodeBtn');
this.closeCodeModal = document.getElementById('closeCodeModal');
}
// 绑定事件
bindEvents() {
// 文件选择
this.fileSelect.addEventListener('change', (e) => {
this.loadProcessFile(e.target.value);
});
// 新增流程
this.newProcessBtn.addEventListener('click', () => {
this.showNewProcessModal();
});
// 保存
this.saveBtn.addEventListener('click', () => {
this.saveConfiguration();
});
// 生成代码
this.generateCodeBtn.addEventListener('click', () => {
this.generateProcessEventsCode();
});
// 新增流程模态框
this.confirmNewProcess.addEventListener('click', () => {
this.createNewProcess();
});
this.cancelNewProcess.addEventListener('click', () => {
this.hideNewProcessModal();
});
// 确认模态框
this.confirmOk.addEventListener('click', () => {
this.hideConfirmModal();
if (this.confirmCallback) {
this.confirmCallback();
}
});
this.confirmCancel.addEventListener('click', () => {
this.hideConfirmModal();
});
// 代码模态框
this.copyCodeBtn.addEventListener('click', () => {
this.copyGeneratedCode();
});
this.closeCodeModal.addEventListener('click', () => {
this.hideCodeModal();
});
// 点击模态框背景关闭
window.addEventListener('click', (e) => {
if (e.target === this.newProcessModal) {
this.hideNewProcessModal();
}
if (e.target === this.confirmModal) {
this.hideConfirmModal();
}
if (e.target === this.codeModal) {
this.hideCodeModal();
}
});
// 键盘事件
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
this.hideNewProcessModal();
this.hideConfirmModal();
this.hideCodeModal();
}
});
}
// 加载初始数据
loadInitialData() {
// 尝试从localStorage加载
this.fileManager.loadFromLocalStorage();
// 更新文件下拉列表
this.updateFileDropdown();
// 加载默认文件
this.loadProcessFile(this.fileManager.getCurrentFileName());
}
// 更新文件下拉列表
updateFileDropdown() {
const fileNames = this.fileManager.getFileNames();
const currentFile = this.fileManager.getCurrentFileName();
this.fileSelect.innerHTML = '';
fileNames.forEach(fileName => {
const option = document.createElement('option');
option.value = fileName;
option.textContent = fileName;
if (fileName === currentFile) {
option.selected = true;
}
this.fileSelect.appendChild(option);
});
// 更新保存按钮文本
this.saveBtn.textContent = `保存到 ${currentFile}`;
}
// 加载流程文件
loadProcessFile(fileName) {
if (!fileName) return;
if (this.fileManager.setCurrentFile(fileName)) {
this.currentSteps = this.fileManager.loadProcessFile(fileName);
this.stepFoldouts = new Array(this.currentSteps.length).fill(true);
this.actionFoldouts = this.currentSteps.map(step =>
new Array(step.Actions.length).fill(true)
);
this.updateFileDropdown();
this.renderSteps();
}
}
// 渲染步骤列表
renderSteps() {
this.stepsContainer.innerHTML = '';
if (this.currentSteps.length === 0) {
this.renderEmptyState();
return;
}
this.currentSteps.forEach((step, stepIndex) => {
this.renderStep(step, stepIndex);
});
}
// 渲染空状态
renderEmptyState() {
const emptyDiv = document.createElement('div');
emptyDiv.className = 'empty-state';
emptyDiv.innerHTML = `
暂无步骤
`;
this.stepsContainer.appendChild(emptyDiv);
}
// HTML转义函数
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// 渲染单个步骤
renderStep(step, stepIndex) {
const stepDiv = document.createElement('div');
stepDiv.className = 'step-item';
// 确保折叠状态数组长度正确
this.ensureFoldoutLists(stepIndex);
const isExpanded = this.stepFoldouts[stepIndex];
stepDiv.innerHTML = `
`;
this.stepsContainer.appendChild(stepDiv);
// 渲染动作列表
if (isExpanded) {
this.renderActions(stepIndex);
}
}
// 确保折叠状态数组长度正确
ensureFoldoutLists(stepIndex) {
while (this.stepFoldouts.length <= stepIndex) {
this.stepFoldouts.push(true);
}
while (this.actionFoldouts.length <= stepIndex) {
this.actionFoldouts.push([]);
}
}
// 确保动作折叠状态数组长度正确
ensureActionFoldoutList(stepIndex, actionIndex) {
this.ensureFoldoutLists(stepIndex);
while (this.actionFoldouts[stepIndex].length <= actionIndex) {
this.actionFoldouts[stepIndex].push(true);
}
}
// 切换步骤折叠状态
toggleStepFoldout(stepIndex) {
this.stepFoldouts[stepIndex] = !this.stepFoldouts[stepIndex];
this.renderSteps();
}
// 切换动作折叠状态
toggleActionFoldout(stepIndex, actionIndex) {
this.actionFoldouts[stepIndex][actionIndex] = !this.actionFoldouts[stepIndex][actionIndex];
this.renderActions(stepIndex);
}
// 更新步骤描述
updateStepDescription(stepIndex, value) {
if (this.currentSteps[stepIndex]) {
this.currentSteps[stepIndex].StepDescription = value;
}
}
// 添加新步骤
addNewStep() {
const newStep = DataUtils.createNewStep();
this.currentSteps.push(newStep);
this.stepFoldouts.push(true);
this.actionFoldouts.push([]);
this.renderSteps();
}
// 删除步骤
removeStep(stepIndex) {
this.showConfirmModal(
"确认删除",
`确定要删除步骤 "${this.currentSteps[stepIndex].StepDescription}" 吗?`,
() => {
this.currentSteps.splice(stepIndex, 1);
this.stepFoldouts.splice(stepIndex, 1);
this.actionFoldouts.splice(stepIndex, 1);
this.renderSteps();
}
);
}
// 渲染动作列表
renderActions(stepIndex) {
const actionsContainer = document.getElementById(`actionsContainer_${stepIndex}`);
if (!actionsContainer) return;
const step = this.currentSteps[stepIndex];
actionsContainer.innerHTML = '';
if (step.Actions.length === 0) {
const emptyDiv = document.createElement('div');
emptyDiv.className = 'empty-state';
emptyDiv.innerHTML = `
暂无动作
`;
actionsContainer.appendChild(emptyDiv);
return;
}
step.Actions.forEach((action, actionIndex) => {
this.renderAction(stepIndex, action, actionIndex, actionsContainer);
});
}
// 渲染单个动作
renderAction(stepIndex, action, actionIndex, container) {
this.ensureActionFoldoutList(stepIndex, actionIndex);
const isExpanded = this.actionFoldouts[stepIndex][actionIndex];
const actionDiv = document.createElement('div');
actionDiv.className = 'action-item';
actionDiv.innerHTML = `
`;
container.appendChild(actionDiv);
// 渲染动作详情
if (isExpanded) {
this.renderActionDetails(stepIndex, actionIndex);
}
}
// 渲染动作详情
renderActionDetails(stepIndex, actionIndex) {
const actionContent = document.getElementById(`actionContent_${stepIndex}_${actionIndex}`);
if (!actionContent) return;
const action = this.currentSteps[stepIndex].Actions[actionIndex];
actionContent.innerHTML = `
`;
this.renderActionTypeContent(stepIndex, actionIndex);
}
// 根据动作类型渲染不同内容
renderActionTypeContent(stepIndex, actionIndex) {
const actionTypeContent = document.getElementById(`actionTypeContent_${stepIndex}_${actionIndex}`);
if (!actionTypeContent) return;
const action = this.currentSteps[stepIndex].Actions[actionIndex];
let content = '';
// 通用属性
content += `
`;
if (action.ActionType === ProcessActionType.DEFAULT) {
content += `
`;
} else if (action.ActionType === ProcessActionType.JUDGMENT) {
content += `
`;
} else if (action.ActionType === ProcessActionType.MULTIPLE_CHOICE) {
content += `
`;
}
actionTypeContent.innerHTML = content;
// 渲染具体内容
if (action.ActionType === ProcessActionType.DEFAULT) {
this.renderTargetObjects(stepIndex, actionIndex);
} else if (action.ActionType === ProcessActionType.JUDGMENT) {
this.renderJudgmentQuestions(stepIndex, actionIndex);
} else if (action.ActionType === ProcessActionType.MULTIPLE_CHOICE) {
this.renderMultipleChoiceQuestions(stepIndex, actionIndex);
}
}
// 更新动作属性
updateActionProperty(stepIndex, actionIndex, property, value) {
if (this.currentSteps[stepIndex] && this.currentSteps[stepIndex].Actions[actionIndex]) {
this.currentSteps[stepIndex].Actions[actionIndex][property] = value;
}
}
// 更新动作类型
updateActionType(stepIndex, actionIndex, newType) {
const action = this.currentSteps[stepIndex].Actions[actionIndex];
if (action.ActionType !== newType) {
action.ActionType = newType;
// 清理不相关的数据
if (newType === ProcessActionType.DEFAULT) {
action.JudgmentQuestions = [];
action.MultipleChoiceQuestions = [];
if (!action.TargetObjects) {
action.TargetObjects = [];
}
} else if (newType === ProcessActionType.JUDGMENT) {
action.TargetObjects = [];
action.MultipleChoiceQuestions = [];
action.IsSequential = false;
if (!action.JudgmentQuestions) {
action.JudgmentQuestions = [];
}
} else if (newType === ProcessActionType.MULTIPLE_CHOICE) {
action.TargetObjects = [];
action.JudgmentQuestions = [];
action.IsSequential = false;
if (!action.MultipleChoiceQuestions) {
action.MultipleChoiceQuestions = [];
}
}
this.renderActionTypeContent(stepIndex, actionIndex);
}
}
// 添加新动作
addNewAction(stepIndex) {
const newAction = DataUtils.createNewAction();
this.currentSteps[stepIndex].Actions.push(newAction);
this.actionFoldouts[stepIndex].push(true);
this.renderActions(stepIndex);
}
// 删除动作
removeAction(stepIndex, actionIndex) {
const action = this.currentSteps[stepIndex].Actions[actionIndex];
this.showConfirmModal(
"确认删除",
`确定要删除动作 "${action.Title}" 吗?`,
() => {
this.currentSteps[stepIndex].Actions.splice(actionIndex, 1);
this.actionFoldouts[stepIndex].splice(actionIndex, 1);
this.renderActions(stepIndex);
}
);
}
// 上移动作
moveActionUp(stepIndex, actionIndex) {
if (actionIndex > 0) {
const actions = this.currentSteps[stepIndex].Actions;
const foldouts = this.actionFoldouts[stepIndex];
// 交换动作
[actions[actionIndex], actions[actionIndex - 1]] = [actions[actionIndex - 1], actions[actionIndex]];
// 交换折叠状态
[foldouts[actionIndex], foldouts[actionIndex - 1]] = [foldouts[actionIndex - 1], foldouts[actionIndex]];
this.renderActions(stepIndex);
}
}
// 下移动作
moveActionDown(stepIndex, actionIndex) {
const actions = this.currentSteps[stepIndex].Actions;
if (actionIndex < actions.length - 1) {
const foldouts = this.actionFoldouts[stepIndex];
// 交换动作
[actions[actionIndex], actions[actionIndex + 1]] = [actions[actionIndex + 1], actions[actionIndex]];
// 交换折叠状态
[foldouts[actionIndex], foldouts[actionIndex + 1]] = [foldouts[actionIndex + 1], foldouts[actionIndex]];
this.renderActions(stepIndex);
}
}
// 渲染目标对象列表
renderTargetObjects(stepIndex, actionIndex) {
const container = document.getElementById(`targetObjectsContainer_${stepIndex}_${actionIndex}`);
if (!container) return;
const action = this.currentSteps[stepIndex].Actions[actionIndex];
let content = '目标对象列表
';
if (action.TargetObjects.length === 0) {
content += `
`;
} else {
action.TargetObjects.forEach((target, targetIndex) => {
content += `
`;
});
content += `
`;
}
container.innerHTML = content;
}
// 添加目标对象
addTargetObject(stepIndex, actionIndex) {
const newTarget = DataUtils.createNewTargetObject();
this.currentSteps[stepIndex].Actions[actionIndex].TargetObjects.push(newTarget);
this.renderTargetObjects(stepIndex, actionIndex);
}
// 删除目标对象
removeTargetObject(stepIndex, actionIndex, targetIndex) {
const target = this.currentSteps[stepIndex].Actions[actionIndex].TargetObjects[targetIndex];
this.showConfirmModal(
"确认删除",
`确定要删除目标对象 "${target.ObjectName}" 吗?`,
() => {
this.currentSteps[stepIndex].Actions[actionIndex].TargetObjects.splice(targetIndex, 1);
this.renderTargetObjects(stepIndex, actionIndex);
}
);
}
// 上移目标对象
moveTargetObjectUp(stepIndex, actionIndex, targetIndex) {
if (targetIndex > 0) {
const targets = this.currentSteps[stepIndex].Actions[actionIndex].TargetObjects;
[targets[targetIndex], targets[targetIndex - 1]] = [targets[targetIndex - 1], targets[targetIndex]];
this.renderTargetObjects(stepIndex, actionIndex);
}
}
// 下移目标对象
moveTargetObjectDown(stepIndex, actionIndex, targetIndex) {
const targets = this.currentSteps[stepIndex].Actions[actionIndex].TargetObjects;
if (targetIndex < targets.length - 1) {
[targets[targetIndex], targets[targetIndex + 1]] = [targets[targetIndex + 1], targets[targetIndex]];
this.renderTargetObjects(stepIndex, actionIndex);
}
}
// 更新目标对象属性
updateTargetObjectProperty(stepIndex, actionIndex, targetIndex, property, value) {
const target = this.currentSteps[stepIndex].Actions[actionIndex].TargetObjects[targetIndex];
if (target) {
target[property] = value;
}
}
// 渲染判断题列表
renderJudgmentQuestions(stepIndex, actionIndex) {
const container = document.getElementById(`judgmentQuestionsContainer_${stepIndex}_${actionIndex}`);
if (!container) return;
const action = this.currentSteps[stepIndex].Actions[actionIndex];
let content = '判断题配置
';
if (action.JudgmentQuestions.length === 0) {
content += `
`;
} else {
action.JudgmentQuestions.forEach((question, questionIndex) => {
content += `
`;
});
content += `
`;
}
container.innerHTML = content;
}
// 添加判断题
addJudgmentQuestion(stepIndex, actionIndex) {
const newQuestion = DataUtils.createNewJudgmentQuestion();
this.currentSteps[stepIndex].Actions[actionIndex].JudgmentQuestions.push(newQuestion);
this.renderJudgmentQuestions(stepIndex, actionIndex);
}
// 删除判断题
removeJudgmentQuestion(stepIndex, actionIndex, questionIndex) {
this.showConfirmModal(
"确认删除",
"确定要删除这个判断题吗?",
() => {
this.currentSteps[stepIndex].Actions[actionIndex].JudgmentQuestions.splice(questionIndex, 1);
this.renderJudgmentQuestions(stepIndex, actionIndex);
}
);
}
// 更新判断题属性
updateJudgmentQuestionProperty(stepIndex, actionIndex, questionIndex, property, value) {
const question = this.currentSteps[stepIndex].Actions[actionIndex].JudgmentQuestions[questionIndex];
if (question) {
question[property] = value;
}
}
// 渲染多选题列表
renderMultipleChoiceQuestions(stepIndex, actionIndex) {
const container = document.getElementById(`multipleChoiceContainer_${stepIndex}_${actionIndex}`);
if (!container) return;
const action = this.currentSteps[stepIndex].Actions[actionIndex];
let content = '多选题配置
';
if (action.MultipleChoiceQuestions.length === 0) {
content += `
`;
} else {
action.MultipleChoiceQuestions.forEach((question, questionIndex) => {
content += `
`;
});
content += `
`;
}
container.innerHTML = content;
// 渲染每个题目的选项
action.MultipleChoiceQuestions.forEach((question, questionIndex) => {
this.renderMultipleChoiceOptions(stepIndex, actionIndex, questionIndex);
});
}
// 渲染多选题选项
renderMultipleChoiceOptions(stepIndex, actionIndex, questionIndex) {
const container = document.getElementById(`optionsContainer_${stepIndex}_${actionIndex}_${questionIndex}`);
if (!container) return;
const question = this.currentSteps[stepIndex].Actions[actionIndex].MultipleChoiceQuestions[questionIndex];
let content = '';
question.Options.forEach((option, optionIndex) => {
const isCorrect = question.CorrectAnswers.includes(option);
content += `
`;
});
content += `
`;
container.innerHTML = content;
}
// 添加多选题
addMultipleChoiceQuestion(stepIndex, actionIndex) {
const newQuestion = DataUtils.createNewMultipleChoice();
this.currentSteps[stepIndex].Actions[actionIndex].MultipleChoiceQuestions.push(newQuestion);
this.renderMultipleChoiceQuestions(stepIndex, actionIndex);
}
// 删除多选题
removeMultipleChoiceQuestion(stepIndex, actionIndex, questionIndex) {
this.showConfirmModal(
"确认删除",
"确定要删除这个多选题吗?",
() => {
this.currentSteps[stepIndex].Actions[actionIndex].MultipleChoiceQuestions.splice(questionIndex, 1);
this.renderMultipleChoiceQuestions(stepIndex, actionIndex);
}
);
}
// 更新多选题属性
updateMultipleChoiceQuestionProperty(stepIndex, actionIndex, questionIndex, property, value) {
const question = this.currentSteps[stepIndex].Actions[actionIndex].MultipleChoiceQuestions[questionIndex];
if (question) {
question[property] = value;
}
}
// 添加多选题选项
addMultipleChoiceOption(stepIndex, actionIndex, questionIndex) {
const question = this.currentSteps[stepIndex].Actions[actionIndex].MultipleChoiceQuestions[questionIndex];
question.Options.push("");
this.renderMultipleChoiceOptions(stepIndex, actionIndex, questionIndex);
}
// 删除多选题选项
removeMultipleChoiceOption(stepIndex, actionIndex, questionIndex, optionIndex) {
const question = this.currentSteps[stepIndex].Actions[actionIndex].MultipleChoiceQuestions[questionIndex];
const option = question.Options[optionIndex];
// 从选项列表中删除
question.Options.splice(optionIndex, 1);
// 从正确答案列表中删除(如果存在)
const correctIndex = question.CorrectAnswers.indexOf(option);
if (correctIndex > -1) {
question.CorrectAnswers.splice(correctIndex, 1);
}
this.renderMultipleChoiceOptions(stepIndex, actionIndex, questionIndex);
}
// 更新多选题选项
updateMultipleChoiceOption(stepIndex, actionIndex, questionIndex, optionIndex, newValue) {
const question = this.currentSteps[stepIndex].Actions[actionIndex].MultipleChoiceQuestions[questionIndex];
const oldValue = question.Options[optionIndex];
// 更新选项值
question.Options[optionIndex] = newValue;
// 如果旧值在正确答案中,替换为新值
const correctIndex = question.CorrectAnswers.indexOf(oldValue);
if (correctIndex > -1) {
question.CorrectAnswers[correctIndex] = newValue;
}
}
// 切换正确答案状态
toggleCorrectAnswer(stepIndex, actionIndex, questionIndex, optionIndex, isCorrect) {
const question = this.currentSteps[stepIndex].Actions[actionIndex].MultipleChoiceQuestions[questionIndex];
const option = question.Options[optionIndex];
if (isCorrect) {
// 添加到正确答案列表
if (!question.CorrectAnswers.includes(option)) {
question.CorrectAnswers.push(option);
}
} else {
// 从正确答案列表中删除
const index = question.CorrectAnswers.indexOf(option);
if (index > -1) {
question.CorrectAnswers.splice(index, 1);
}
}
}
// 显示新增流程模态框
showNewProcessModal() {
this.newProcessName.value = "新流程";
this.newProcessModal.style.display = 'block';
this.newProcessName.focus();
this.newProcessName.select();
}
// 隐藏新增流程模态框
hideNewProcessModal() {
this.newProcessModal.style.display = 'none';
}
// 创建新流程
createNewProcess() {
const fileName = this.newProcessName.value.trim();
if (!fileName) {
alert("请输入流程名称");
return;
}
const result = this.fileManager.createNewProcessFile(fileName);
if (result.success) {
this.hideNewProcessModal();
this.updateFileDropdown();
this.loadProcessFile(result.fileName);
this.showAlert("新流程创建成功", `已创建新流程:${result.fileName}`);
} else {
alert(`创建失败:${result.error}`);
}
}
// 显示确认模态框
showConfirmModal(title, message, callback) {
this.confirmTitle.textContent = title;
this.confirmMessage.textContent = message;
this.confirmCallback = callback;
this.confirmModal.style.display = 'block';
}
// 隐藏确认模态框
hideConfirmModal() {
this.confirmModal.style.display = 'none';
this.confirmCallback = null;
}
// 显示代码模态框
showCodeModal(code) {
this.generatedCode.value = code;
this.codeModal.style.display = 'block';
}
// 隐藏代码模态框
hideCodeModal() {
this.codeModal.style.display = 'none';
}
// 复制生成的代码
copyGeneratedCode() {
this.generatedCode.select();
document.execCommand('copy');
this.showAlert("复制成功", "代码已复制到剪贴板");
}
// 显示提示信息
showAlert(title, message) {
// 简单的alert实现,可以后续改为更美观的提示框
alert(`${title}\n${message}`);
}
// 保存配置
saveConfiguration() {
const currentFileName = this.fileManager.getCurrentFileName();
this.showConfirmModal(
"确认保存",
`是否要保存当前配置到 ${currentFileName}?`,
() => {
const result = this.fileManager.saveProcessFile(currentFileName, this.currentSteps);
if (result.success) {
this.showAlert("保存成功", `配置已保存到 ${currentFileName}`);
} else {
alert(`保存失败:${result.error}`);
}
}
);
}
// 生成ProcessEvents代码
generateProcessEventsCode() {
try {
const currentFileName = this.fileManager.getCurrentFileName();
if (!this.currentSteps || this.currentSteps.length === 0) {
alert("当前流程文件为空,无法生成代码");
return;
}
const code = this.codeGenerator.generateProcessEventsCode(currentFileName, this.currentSteps);
this.showCodeModal(code);
} catch (error) {
alert(`生成代码失败:${error.message}`);
}
}
}
// 全局编辑器实例
let editor;
// 页面加载完成后初始化编辑器
document.addEventListener('DOMContentLoaded', function() {
editor = new SceneStepEditor();
});