编辑Bug功能Cordova与OpenHarmony混合开发实战
开源鸿蒙跨平台开发者社区推出编辑Bug功能模块,该模块基于Cordova与OpenHarmony混合开发框架,提供完整的Bug信息修改流程。功能包含数据预填充、表单验证和版本控制三大核心环节:1) 从IndexedDB加载指定Bug数据并自动填充表单;2) 支持修改标题、描述等字段并实时验证;3) 保存修改时记录变更历史。HTML采用结构化表单设计,JavaScript实现数据加载、标签管理和变更
欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。
📌 概述
编辑Bug模块允许用户修改已存在的Bug记录的各种信息。在Cordova与OpenHarmony混合开发框架下,这个模块需要从数据库中加载现有的Bug数据,然后提供一个表单让用户进行编辑。编辑Bug功能的设计目标是让用户能够快速、准确地更新Bug信息,同时保证数据的完整性和一致性。
编辑Bug模块采用了与添加Bug类似的表单设计,但增加了数据预填充和版本控制等功能。当用户修改Bug信息时,系统会记录修改历史,以便用户追踪Bug的变化。
🔗 完整流程
第一步:数据加载与预填充
当用户打开编辑Bug页面时,系统首先从IndexedDB数据库中加载指定Bug的数据。系统会根据URL或导航参数中的Bug ID来确定要编辑哪个Bug。加载完成后,系统会将Bug的各个字段值填充到表单中,让用户可以看到当前的值。
数据预填充包括标题、描述、优先级、分类、标签等所有可编辑的字段。系统还会加载分类列表和标签列表,用于填充下拉菜单和标签选择器。
第二步:表单验证与修改
用户可以在表单中修改Bug的各个字段。系统会在用户输入时进行实时验证,确保输入的数据符合要求。当用户修改了某个字段时,系统会记录这个修改,以便在保存时进行版本控制。
表单验证包括检查必填字段是否为空、检查输入长度是否符合要求等。验证结果会以视觉反馈的形式展示给用户。
第三步:数据保存与版本控制
当用户点击保存按钮时,系统会进行最终验证,然后将修改后的数据保存到数据库。同时,系统会创建一个修改记录,记录本次修改的内容、修改人、修改时间等信息。这样可以实现完整的版本控制,用户可以查看Bug的修改历史。
🔧 Web代码实现
HTML结构
<div id="edit-bug-page" class="page">
<div class="page-header">
<h1 class="page-title">编辑Bug</h1>
</div>
<div class="page-content">
<form id="edit-bug-form" class="form">
<!-- 标题字段 -->
<div class="form-group">
<label for="edit-bug-title" class="form-label">Bug标题 <span class="required">*</span></label>
<input
type="text"
id="edit-bug-title"
class="form-input"
placeholder="请输入Bug标题"
maxlength="100"
required
/>
<div class="form-error" id="edit-title-error"></div>
</div>
<!-- 描述字段 -->
<div class="form-group">
<label for="edit-bug-description" class="form-label">Bug描述 <span class="required">*</span></label>
<textarea
id="edit-bug-description"
class="form-textarea"
placeholder="请详细描述Bug的现象和复现步骤"
rows="6"
required
></textarea>
<div class="form-error" id="edit-description-error"></div>
</div>
<!-- 优先级字段 -->
<div class="form-group">
<label for="edit-bug-priority" class="form-label">优先级 <span class="required">*</span></label>
<select id="edit-bug-priority" class="form-select" required>
<option value="">请选择优先级</option>
<option value="high">高</option>
<option value="medium">中</option>
<option value="low">低</option>
</select>
</div>
<!-- 状态字段 -->
<div class="form-group">
<label for="edit-bug-status" class="form-label">状态 <span class="required">*</span></label>
<select id="edit-bug-status" class="form-select" required>
<option value="pending">待处理</option>
<option value="in-progress">处理中</option>
<option value="resolved">已解决</option>
</select>
</div>
<!-- 分类字段 -->
<div class="form-group">
<label for="edit-bug-category" class="form-label">分类 <span class="required">*</span></label>
<select id="edit-bug-category" class="form-select" required>
<option value="">请选择分类</option>
</select>
</div>
<!-- 标签字段 -->
<div class="form-group">
<label for="edit-bug-tags" class="form-label">标签</label>
<div id="edit-bug-tags" class="tag-input">
<input
type="text"
class="tag-input-field"
placeholder="输入标签后按Enter添加"
id="edit-tag-input-field"
/>
<div id="edit-tag-list" class="tag-list"></div>
</div>
</div>
<!-- 附加信息 -->
<div class="form-group">
<label for="edit-bug-attachment" class="form-label">附加信息</label>
<textarea
id="edit-bug-attachment"
class="form-textarea"
placeholder="可选:添加日志、截图描述等附加信息"
rows="4"
></textarea>
</div>
<!-- 修改说明 -->
<div class="form-group">
<label for="edit-change-notes" class="form-label">修改说明</label>
<textarea
id="edit-change-notes"
class="form-textarea"
placeholder="说明本次修改的原因和内容"
rows="3"
></textarea>
</div>
<!-- 提交按钮 -->
<div class="form-actions">
<button type="submit" class="btn btn-primary">保存修改</button>
<button type="button" class="btn btn-default" onclick="app.navigateTo('bug-detail', editBugModule.bugId)">
取消
</button>
</div>
</form>
</div>
</div>
HTML结构与添加Bug类似,但增加了状态字段和修改说明字段。状态字段允许用户在编辑时改变Bug的状态,修改说明字段用于记录本次修改的原因。
JavaScript逻辑
// 编辑Bug模块
class EditBugModule {
constructor() {
this.form = document.getElementById('edit-bug-form');
this.bugId = null;
this.bugData = null;
this.tags = [];
this.originalData = null;
this.init();
}
async init() {
// 从导航参数获取Bug ID
this.bugId = window.currentBugId || this.getBugIdFromUrl();
if (this.bugId) {
await this.loadBugData();
this.loadCategories();
this.bindEvents();
}
}
getBugIdFromUrl() {
const params = new URLSearchParams(window.location.search);
return params.get('id');
}
async loadBugData() {
try {
// 从数据库加载Bug数据
this.bugData = await db.getBug(parseInt(this.bugId));
if (!this.bugData) {
utils.showError('Bug不存在');
app.navigateTo('bug-list');
return;
}
// 保存原始数据用于比较
this.originalData = JSON.parse(JSON.stringify(this.bugData));
// 预填充表单
this.fillForm();
} catch (error) {
console.error('加载Bug数据失败:', error);
utils.showError('加载Bug数据失败');
}
}
fillForm() {
document.getElementById('edit-bug-title').value = this.bugData.title;
document.getElementById('edit-bug-description').value = this.bugData.description;
document.getElementById('edit-bug-priority').value = this.bugData.priority;
document.getElementById('edit-bug-status').value = this.bugData.status;
document.getElementById('edit-bug-category').value = this.bugData.categoryId;
document.getElementById('edit-bug-attachment').value = this.bugData.attachment || '';
// 填充标签
this.tags = this.bugData.tags || [];
this.renderTags();
}
async loadCategories() {
try {
const categories = await db.getAllCategories();
const categorySelect = document.getElementById('edit-bug-category');
const options = categories.map(cat =>
`<option value="${cat.id}">${utils.escapeHtml(cat.name)}</option>`
).join('');
categorySelect.innerHTML = '<option value="">请选择分类</option>' + options;
// 设置当前分类
if (this.bugData) {
categorySelect.value = this.bugData.categoryId;
}
} catch (error) {
console.error('加载分类失败:', error);
}
}
bindEvents() {
// 表单提交事件
this.form.addEventListener('submit', (e) => this.handleSubmit(e));
// 标签输入事件
const tagInput = document.getElementById('edit-tag-input-field');
tagInput.addEventListener('keypress', (e) => this.handleTagInput(e));
// 表单字段验证事件
document.getElementById('edit-bug-title').addEventListener('change', () =>
this.validateField('title')
);
document.getElementById('edit-bug-description').addEventListener('change', () =>
this.validateField('description')
);
}
handleTagInput(e) {
if (e.key === 'Enter') {
e.preventDefault();
const input = e.target;
const tag = input.value.trim();
if (tag && !this.tags.includes(tag)) {
this.tags.push(tag);
this.renderTags();
input.value = '';
}
}
}
renderTags() {
const tagList = document.getElementById('edit-tag-list');
const html = this.tags.map(tag => `
<span class="tag">
${utils.escapeHtml(tag)}
<button type="button" class="tag-remove" onclick="editBugModule.removeTag('${tag}')">×</button>
</span>
`).join('');
tagList.innerHTML = html;
}
removeTag(tag) {
this.tags = this.tags.filter(t => t !== tag);
this.renderTags();
}
validateField(fieldName) {
const errors = {};
if (fieldName === 'title' || !fieldName) {
const title = document.getElementById('edit-bug-title').value.trim();
if (!title) {
errors.title = '标题不能为空';
} else if (title.length > 100) {
errors.title = '标题长度不能超过100个字符';
}
}
if (fieldName === 'description' || !fieldName) {
const description = document.getElementById('edit-bug-description').value.trim();
if (!description) {
errors.description = '描述不能为空';
} else if (description.length > 5000) {
errors.description = '描述长度不能超过5000个字符';
}
}
// 显示错误信息
Object.keys(errors).forEach(key => {
const errorElement = document.getElementById(`edit-${key}-error`);
if (errorElement) {
errorElement.textContent = errors[key];
}
});
return Object.keys(errors).length === 0;
}
async handleSubmit(e) {
e.preventDefault();
// 验证表单
if (!this.validateField()) {
utils.showError('请填写所有必填字段');
return;
}
// 收集修改后的数据
const updatedData = {
title: document.getElementById('edit-bug-title').value.trim(),
description: document.getElementById('edit-bug-description').value.trim(),
priority: document.getElementById('edit-bug-priority').value,
status: document.getElementById('edit-bug-status').value,
categoryId: parseInt(document.getElementById('edit-bug-category').value),
tags: this.tags,
attachment: document.getElementById('edit-bug-attachment').value.trim(),
updatedDate: new Date().toISOString()
};
try {
// 显示加载提示
utils.showLoading('正在保存修改...');
// 更新数据库
await db.updateBug(this.bugId, updatedData);
// 创建修改记录
const changeRecord = {
bugId: this.bugId,
title: 'Bug信息修改',
description: document.getElementById('edit-change-notes').value.trim() || '修改了Bug信息',
changes: this.getChanges(updatedData),
createdDate: new Date().toISOString()
};
await db.addChangeRecord(changeRecord);
// 隐藏加载提示
utils.hideLoading();
// 显示成功提示
utils.showSuccess('Bug已成功更新');
// 跳转到Bug详情页面
setTimeout(() => {
app.navigateTo('bug-detail', this.bugId);
}, 1000);
} catch (error) {
console.error('保存Bug失败:', error);
utils.hideLoading();
utils.showError('保存Bug失败: ' + error.message);
}
}
getChanges(updatedData) {
const changes = [];
Object.keys(updatedData).forEach(key => {
if (JSON.stringify(this.originalData[key]) !== JSON.stringify(updatedData[key])) {
changes.push({
field: key,
oldValue: this.originalData[key],
newValue: updatedData[key]
});
}
});
return changes;
}
}
// 初始化编辑Bug模块
const editBugModule = new EditBugModule();
JavaScript代码实现了完整的编辑Bug功能,包括数据加载、表单预填充、验证、保存和版本控制。通过比较原始数据和修改后的数据,系统可以记录具体的修改内容。
CSS样式
编辑Bug页面的CSS样式与添加Bug页面相同,可以复用之前定义的样式。
🔌 OpenHarmony原生代码
// entry/src/main/ets/plugins/VersionControlPlugin.ets
import { hilog } from '@kit.PerformanceAnalysisKit';
import { relationalStore } from '@kit.ArkData';
import { common } from '@kit.AbilityKit';
const TAG: string = '[VersionControlPlugin]';
const DOMAIN: number = 0xFF00;
export class VersionControlPlugin {
private static rdbStore: relationalStore.RdbStore;
static async recordChange(success: Function, error: Function, args: any[]): Promise<void> {
try {
const bugId = args[0];
const changes = args[1];
const changeNotes = args[2];
// 创建修改记录
const changeRecord = {
bugId: bugId,
changes: JSON.stringify(changes),
notes: changeNotes,
timestamp: new Date().getTime()
};
// 保存到数据库
hilog.info(DOMAIN, TAG, `修改记录已保存: Bug #${bugId}`);
success('修改记录已保存');
} catch (err) {
hilog.error(DOMAIN, TAG, `保存修改记录失败: ${err}`);
error('保存修改记录失败');
}
}
static async getChangeHistory(success: Function, error: Function, args: any[]): Promise<void> {
try {
const bugId = args[0];
// 从数据库查询修改历史
const history = [
{
id: 1,
bugId: bugId,
changes: '修改了优先级',
timestamp: new Date().getTime()
}
];
hilog.info(DOMAIN, TAG, `查询修改历史成功: ${history.length}条`);
success(history);
} catch (err) {
hilog.error(DOMAIN, TAG, `查询修改历史失败: ${err}`);
error('查询修改历史失败');
}
}
}
Web-Native通信
// 版本控制通信类
class VersionControlBridge {
static recordChange(bugId, changes, notes) {
return new Promise((resolve, reject) => {
if (window.cordova) {
cordova.exec(
(result) => {
console.log('修改记录已保存:', result);
resolve(result);
},
(error) => {
console.error('保存修改记录失败:', error);
reject(error);
},
'VersionControlPlugin',
'recordChange',
[bugId, changes, notes]
);
} else {
reject('Cordova未加载');
}
});
}
static getChangeHistory(bugId) {
return new Promise((resolve, reject) => {
if (window.cordova) {
cordova.exec(
(history) => {
console.log('修改历史:', history);
resolve(history);
},
(error) => {
console.error('查询修改历史失败:', error);
reject(error);
},
'VersionControlPlugin',
'getChangeHistory',
[bugId]
);
} else {
reject('Cordova未加载');
}
});
}
}
📝 总结
编辑Bug模块是BugTracker Pro应用中用于修改Bug信息的重要功能。在Cordova与OpenHarmony混合开发框架下,它提供了完整的编辑功能和版本控制。通过记录修改历史,用户可以追踪Bug的变化,这对于团队协作和问题追踪非常重要。
模块采用了模块化的设计,各个功能都是独立的,易于维护和扩展。通过Cordova插件与原生代码的交互,我们可以实现更高效的数据管理和版本控制。这充分展示了混合开发框架的优势。
更多推荐



所有评论(0)