产地管理模块 Cordova 与 OpenHarmony 混合开发实战
摘要:产地管理模块实现了茶叶产地的增删改查功能,支持数据加载、编辑和同步。前端界面包含产地列表、搜索框和编辑模态框,通过JavaScript实现数据渲染和交互逻辑。用户可添加、修改或删除产地信息,所有操作会同步更新至本地数据库,并支持按名称或地区搜索产地。

📌 概述
产地管理模块允许用户管理茶叶的产地信息。该模块集成了 Cordova 框架与 OpenHarmony 原生能力,提供了完整的产地数据管理功能。用户可以添加新产地、编辑产地信息、删除产地,以及查看每个产地的茶叶数量。模块支持产地搜索和分类,帮助用户快速管理产地信息。
🔗 完整流程
第一步:产地数据加载
当用户进入产地管理页面时,应用会从数据库中加载所有产地信息。应用会显示每个产地的名称、所在地区和该产地的茶叶数量。应用会显示加载动画直到数据加载完成。
第二步:产地展示与编辑
数据加载完成后,应用会将产地显示为列表形式。用户可以点击产地项进行编辑或删除。编辑时,应用会打开模态框,允许用户修改产地信息。用户也可以添加新的产地。
第三步:数据同步与更新
当用户添加、编辑或删除产地时,应用会立即更新 IndexedDB 数据库。同时,应用会通过 Cordova 调用原生插件,将数据同步到应用的关系型数据库中。
🔧 Web 代码实现
HTML 产地列表
<div id="tea-origins-page" class="page">
<div class="page-header">
<h1>产地管理</h1>
<button class="btn btn-primary" onclick="openAddOriginModal()">+ 添加产地</button>
</div>
<div class="origins-toolbar">
<input type="text" id="origin-search" class="search-box" placeholder="搜索产地...">
</div>
<div id="origins-list" class="origins-list">
<!-- 产地项动态生成 -->
</div>
<!-- 添加/编辑产地模态框 -->
<div id="origin-modal" class="modal" style="display: none;">
<div class="modal-content">
<div class="modal-header">
<h2 id="origin-modal-title">添加产地</h2>
<button class="btn-close" onclick="closeOriginModal()">×</button>
</div>
<form id="origin-form" class="form">
<div class="form-group">
<label for="origin-name">产地名称 *</label>
<input type="text" id="origin-name" name="name" required>
</div>
<div class="form-group">
<label for="origin-region">地区</label>
<input type="text" id="origin-region" name="region" placeholder="如:浙江省">
</div>
<div class="form-group">
<label for="origin-description">描述</label>
<textarea id="origin-description" name="description" rows="3"></textarea>
</div>
<div class="modal-actions">
<button type="submit" class="btn btn-primary">保存</button>
<button type="button" class="btn btn-secondary" onclick="closeOriginModal()">取消</button>
</div>
</form>
</div>
</div>
</div>
产地管理页面包含搜索功能和产地列表。模态框用于添加或编辑产地。
产地数据管理
let allOrigins = [];
let currentEditingOriginId = null;
async function renderOrigins() {
try {
// 加载产地数据
allOrigins = await db.getOrigins();
const listContainer = document.getElementById('origins-list');
listContainer.innerHTML = '';
if (allOrigins.length === 0) {
listContainer.innerHTML = '<div class="no-data"><p>暂无产地</p></div>';
return;
}
for (const origin of allOrigins) {
// 获取该产地的茶叶数量
const teaCount = await db.getTeaCountByOrigin(origin.id);
const originEl = document.createElement('div');
originEl.className = 'origin-item';
originEl.dataset.originId = origin.id;
originEl.innerHTML = `
<div class="origin-info">
<div class="origin-name">${origin.name}</div>
<div class="origin-region">${origin.region || '未指定'}</div>
<div class="origin-count">茶叶数: ${teaCount}</div>
${origin.description ? `<div class="origin-description">${origin.description}</div>` : ''}
</div>
<div class="origin-actions">
<button class="btn-icon" onclick="editOrigin(${origin.id})" title="编辑">✏️</button>
<button class="btn-icon" onclick="deleteOrigin(${origin.id})" title="删除">🗑️</button>
</div>
`;
listContainer.appendChild(originEl);
}
// 绑定搜索事件
document.getElementById('origin-search').addEventListener('input', function(e) {
const keyword = e.target.value.toLowerCase();
const filtered = allOrigins.filter(o =>
o.name.toLowerCase().includes(keyword) ||
(o.region && o.region.toLowerCase().includes(keyword))
);
renderOriginList(filtered);
});
document.getElementById('origin-form').addEventListener('submit', handleSaveOrigin);
} catch (error) {
console.error('Failed to render origins:', error);
showToast('加载产地失败', 'error');
}
}
function renderOriginList(origins) {
const listContainer = document.getElementById('origins-list');
listContainer.innerHTML = '';
if (origins.length === 0) {
listContainer.innerHTML = '<div class="no-data"><p>暂无产地</p></div>';
return;
}
origins.forEach(origin => {
const originEl = document.createElement('div');
originEl.className = 'origin-item';
originEl.dataset.originId = origin.id;
originEl.innerHTML = `
<div class="origin-info">
<div class="origin-name">${origin.name}</div>
<div class="origin-region">${origin.region || '未指定'}</div>
${origin.description ? `<div class="origin-description">${origin.description}</div>` : ''}
</div>
<div class="origin-actions">
<button class="btn-icon" onclick="editOrigin(${origin.id})" title="编辑">✏️</button>
<button class="btn-icon" onclick="deleteOrigin(${origin.id})" title="删除">🗑️</button>
</div>
`;
listContainer.appendChild(originEl);
});
}
function openAddOriginModal() {
currentEditingOriginId = null;
document.getElementById('origin-modal-title').textContent = '添加产地';
document.getElementById('origin-form').reset();
document.getElementById('origin-modal').style.display = 'flex';
}
async function editOrigin(originId) {
try {
const origin = await db.getOrigin(originId);
if (!origin) {
showToast('产地不存在', 'error');
return;
}
currentEditingOriginId = originId;
document.getElementById('origin-modal-title').textContent = '编辑产地';
// 填充表单
document.getElementById('origin-name').value = origin.name;
document.getElementById('origin-region').value = origin.region || '';
document.getElementById('origin-description').value = origin.description || '';
document.getElementById('origin-modal').style.display = 'flex';
} catch (error) {
console.error('Failed to edit origin:', error);
showToast('加载产地信息失败', 'error');
}
}
async function handleSaveOrigin(event) {
event.preventDefault();
const formData = new FormData(document.getElementById('origin-form'));
const originData = {
name: formData.get('name'),
region: formData.get('region'),
description: formData.get('description')
};
try {
if (currentEditingOriginId) {
await db.updateOrigin(currentEditingOriginId, originData);
if (window.cordova) {
cordova.exec(
null, null,
'TeaLogger',
'logEvent',
['origin_updated', { originId: currentEditingOriginId }]
);
}
showToast('产地已更新', 'success');
} else {
const originId = await db.addOrigin(originData);
if (window.cordova) {
cordova.exec(
null, null,
'TeaLogger',
'logEvent',
['origin_added', { originId: originId }]
);
}
showToast('产地已添加', 'success');
}
closeOriginModal();
renderOrigins();
} catch (error) {
console.error('Failed to save origin:', error);
showToast('保存失败,请重试', 'error');
}
}
async function deleteOrigin(originId) {
const teaCount = await db.getTeaCountByOrigin(originId);
if (teaCount > 0) {
showToast(`该产地有 ${teaCount} 种茶叶,无法删除`, 'warning');
return;
}
if (!confirm('确定要删除这个产地吗?')) {
return;
}
try {
await db.deleteOrigin(originId);
if (window.cordova) {
cordova.exec(
null, null,
'TeaLogger',
'logEvent',
['origin_deleted', { originId: originId }]
);
}
showToast('产地已删除', 'success');
renderOrigins();
} catch (error) {
console.error('Failed to delete origin:', error);
showToast('删除失败,请重试', 'error');
}
}
function closeOriginModal() {
document.getElementById('origin-modal').style.display = 'none';
currentEditingOriginId = null;
}
这段代码实现了完整的产地管理功能。renderOrigins() 加载并渲染产地列表。openAddOriginModal() 打开添加产地的模态框。editOrigin() 加载产地信息进行编辑。handleSaveOrigin() 保存新增或修改的产地。deleteOrigin() 删除产地,但会检查该产地下是否有茶叶。
🔌 OpenHarmony 原生代码
产地数据库操作
// entry/src/main/ets/plugins/OriginManager.ets
import { relationalStore } from '@kit.ArkData';
export class OriginManager {
private store: relationalStore.RdbStore;
async createOriginTable(): Promise<void> {
const createTableSql = `
CREATE TABLE IF NOT EXISTS tea_origins (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
region TEXT,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`;
await this.store.executeSql(createTableSql);
}
async addOrigin(origin: Origin): Promise<number> {
const values: relationalStore.ValuesBucket = {
name: origin.name,
region: origin.region,
description: origin.description,
created_at: new Date().toISOString()
};
return await this.store.insert('tea_origins', values);
}
async getTeaCountByOrigin(originId: number): Promise<number> {
const predicates = new relationalStore.RdbPredicates('tea_library');
predicates.equalTo('origin', originId);
const resultSet = await this.store.query(predicates);
const count = resultSet.getRowCount();
resultSet.close();
return count;
}
}
interface Origin {
id?: number;
name: string;
region?: string;
description?: string;
}
这个类提供了产地的数据库操作。createOriginTable() 创建产地表。addOrigin() 添加新产地。getTeaCountByOrigin() 获取该产地的茶叶数量。
📝 总结
产地管理模块展示了如何在 Cordova 框架中实现产地管理功能。通过 Web 层的用户界面和交互,结合原生层的数据库操作,为用户提供了高效的产地管理体验。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)