DataManager.js:68 Fetch error: TypeError: Cannot read properties of undefined (reading 'baseUrl')
at fetchAll (DataManager.js:52:44)
at initialize (bancai.js:36:19)
fetchAll @ DataManager.js:68
initialize @ bancai.js:36
await in initialize(异步)
(匿名) @ bancai.js:232
e @ jquery-3.6.0.min.js:2
t @ jquery-3.6.0.min.js:2
setTimeout(异步)
(匿名) @ jquery-3.6.0.min.js:2
c @ jquery-3.6.0.min.js:2
fireWith @ jquery-3.6.0.min.js:2
fire @ jquery-3.6.0.min.js:2
c @ jquery-3.6.0.min.js:2
fireWith @ jquery-3.6.0.min.js:2
ready @ jquery-3.6.0.min.js:2
B @ jquery-3.6.0.min.js:2
bancai.js:44 初始化失败: ReferenceError: data is not defined
at updateOptions (bancai.js:51:9)
at initialize (bancai.js:39:13) // bancai.js
$(document).ready(function () {
const modal = new bootstrap.Modal('#bancaiModal');
let currentMode = 'view';
let caizhiList = [];
let mupiList = [];
let currentSearchText = '';
// 从父窗口获取 DataManager
let dataManager = null;
// 等待父窗口的 DataManager 准备就绪
async function waitForDataManager() {
return new Promise((resolve, reject) => {
if (window.parent && window.parent.dataManager) {
resolve(window.parent.dataManager);
} else {
reject(new Error('无法从父窗口获取 DataManager'));
}
});
}
// 初始化函数
async function initialize() {
try {
dataManager = await waitForDataManager();
if (!dataManager || typeof dataManager.fetchAll !== 'function') {
throw new Error('无效的 DataManager 实例');
}
// 解构需要的方法和属性
const { data, addEntity, updateEntity, deleteEntity, fetchAll } = dataManager;
// 确保数据已加载
await fetchAll();
// 更新材质和木皮选项
updateOptions();
// 渲染板材表格
refreshTable();
} catch (error) {
console.error('初始化失败:', error);
alert('系统初始化失败,请刷新页面或联系管理员');
}
}
// 更新材质和木皮选项
function updateOptions() {
caizhiList = data.caizhis;
updateSelectOptions('#caizhiSelect', caizhiList);
mupiList = data.mupis.map(m => ({
...m,
name: m.you ? `${m.name}(油漆)` : m.name,
}));
updateSelectOptions('#mupi1Select', mupiList);
updateSelectOptions('#mupi2Select', mupiList);
}
// 更新下拉框选项
function updateSelectOptions(selector, data) {
$(selector).empty();
data.forEach(item => {
$(selector).append(`<option value="${item.id}">${item.name}</option>`);
});
}
// 刷新表格
function refreshTable() {
const filteredData = filterBancais(currentSearchText);
renderBancaiTable(filteredData);
}
// 搜索过滤
function filterBancais(searchText) {
if (!searchText) return data.bancais;
return data.bancais.filter(bancai => {
const caizhiName = bancai.caizhi?.name || '';
const mupi1Name = bancai.mupi1?.name || '';
const mupi2Name = bancai.mupi2?.name || '';
const houdu = bancai.houdu.toString();
return [
caizhiName.toLowerCase(),
mupi1Name.toLowerCase(),
mupi2Name.toLowerCase(),
houdu.toLowerCase(),
].some(field => field.includes(searchText.toLowerCase()));
});
}
// 渲染表格
function renderBancaiTable(bancais) {
const $tbody = $('#bancaiTable tbody');
$tbody.empty();
bancais.forEach(bancai => {
const caizhiName = bancai.caizhi?.name || '未知';
const mupi1Name = bancai.mupi1?.name || '未知';
const mupi2Name = bancai.mupi2?.name || '未知';
const row = `
<tr data-id="${bancai.id}">
<td>${bancai.id}</td>
<td>${caizhiName}</td>
<td>${mupi1Name} ${bancai.mupi1?.you ? '(油漆)' : ''}</td>
<td>${mupi2Name} ${bancai.mupi2?.you ? '(油漆)' : ''}</td>
<td>${bancai.houdu}</td>
<td>
<button class="btn btn-sm btn-info view-btn">查看</button>
<button class="btn btn-sm btn-warning edit-btn">编辑</button>
<button class="btn btn-sm btn-danger delete-btn">删除</button>
</td>
</tr>
`;
$tbody.append(row);
});
bindTableEvents();
}
// 绑定表格事件
function bindTableEvents() {
$('.view-btn').click(function () {
const id = $(this).closest('tr').data('id');
openModalForBancai(id, 'view');
});
$('.edit-btn').click(function () {
const id = $(this).closest('tr').data('id');
openModalForBancai(id, 'edit');
});
$('.delete-btn').click(function () {
const id = $(this).closest('tr').data('id');
deleteBancai(id);
});
}
// 添加按钮事件
$('#addBancaiBtn').click(function () {
$('#bancaiForm')[0].reset();
$('#modalTitle').text('添加新板材');
currentMode = 'add';
enableForm(true);
updateOptions();
modal.show();
});
// 搜索按钮事件
$('#searchBtn').click(function () {
currentSearchText = $('#searchInput').val();
refreshTable();
});
// 输入框实时搜索
$('#searchInput').on('input', function () {
currentSearchText = $(this).val();
refreshTable();
});
// 打开弹窗显示板材数据
function openModalForBancai(id, mode) {
const bancai = data.bancais.find(b => b.id === id);
if (!bancai) return;
currentMode = mode;
$('#bancaiId').val(bancai.id);
$('#caizhiSelect').val(bancai.caizhi.id);
$('#mupi1Select').val(bancai.mupi1.id);
$('#mupi2Select').val(bancai.mupi2.id);
$('#houdu').val(bancai.houdu);
$('#modalTitle').text(mode === 'view' ? '板材详情' : '编辑板材');
enableForm(mode === 'edit');
modal.show();
}
// 启用/禁用表单
function enableForm(enable) {
$('#caizhiSelect').prop('disabled', !enable);
$('#mupi1Select').prop('disabled', !enable);
$('#mupi2Select').prop('disabled', !enable);
$('#houdu').prop('disabled', !enable);
$('#saveBtn').toggle(enable);
}
// 保存按钮点击事件
$('#saveBtn').click(async function () {
const formData = {
id: $('#bancaiId').val(),
caizhiId: parseInt($('#caizhiSelect').val()),
mupi1Id: parseInt($('#mupi1Select').val()),
mupi2Id: parseInt($('#mupi2Select').val()),
houdu: parseFloat($('#houdu').val()),
};
try {
if (currentMode === 'add') {
await addEntity('bancais', formData);
} else {
await updateEntity('bancais', formData);
}
refreshTable();
modal.hide();
} catch (error) {
console.error('操作失败:', error);
alert('操作失败,请重试');
}
});
// 删除板材
async function deleteBancai(id) {
if (!confirm('确定要删除此板材吗?')) return;
try {
await deleteEntity('bancais', id);
refreshTable();
} catch (error) {
console.error('删除失败:', error);
alert('删除失败,请重试');
}
}
// 初始化应用
initialize();
});/**
* 数据管理器类,负责与后端API通信并管理数据
*/
class DataManager {
constructor(baseUrl) {
this.baseUrl = baseUrl;
this.data = {
bancais: [],
dingdans: [],
mupis: [],
chanpins: [],
kucuns: [],
dingdan_chanpin_zujians: [],
chanpin_zujians: [],
zujians: [],
caizhis: [],
dingdan_chanpins: [],
users: []
};
this.isSyncing = false;
this.lastSync = null;
// 回调注册表
this.callbacks = {
// 全局回调
all: [],
// 按实体类型分类的回调
bancais: [],
dingdan: [],
mupi: [],
chanpin: [],
kucun: [],
dingdan_chanpin_zujian: [],
chanpin_zujian: [],
zujian: [],
caizhi: [],
dingdan_chanpin: [],
user: []
// ...其他实体
};
}
/**
* 获取所有数据
* @returns {Promise<boolean>} 是否成功
*/
async fetchAll() {
try {
const response = await fetch(`${this.baseUrl}/app/all`);
if (!response.ok) throw new Error('Network response was not ok');
const result = await response.json();
if (result.status !== 200) throw new Error(result.text || 'API error');
// 更新本地数据
Object.keys(this.data).forEach(key => {
if (result.data[key]) {
this.data[key] = result.data[key];
}
});
this.lastSync = new Date();
return true;
} catch (error) {
console.error('Fetch error:', error);
return false;
}
}
/**
* 注册回调函数
* @param {string} entity - 实体类型(如'bancai')或'all'表示全局回调
* @param {Function} callback - 回调函数,参数为(operation, data)
*/
registerCallback(entity, callback) {
if (!this.callbacks[entity]) {
this.callbacks[entity] = [];
}
this.callbacks[entity].push(callback);
}
/**
* 移除回调函数
* @param {string} entity - 实体类型
* @param {Function} callback - 要移除的回调函数
*/
unregisterCallback(entity, callback) {
if (!this.callbacks[entity]) return;
const index = this.callbacks[entity].indexOf(callback);
if (index !== -1) {
this.callbacks[entity].splice(index, 1);
}
}
/**
* 触发回调
* @param {string} operation - 操作类型('add', 'update', 'delete')
* @param {string} entity - 实体类型
* @param {Object} data - 相关数据
*/
triggerCallbacks(operation, entity, data) {
// 触发全局回调
this.callbacks.all.forEach(cb => cb(operation, entity, data));
// 触发特定实体回调
if (this.callbacks[entity]) {
this.callbacks[entity].forEach(cb => cb(operation, data));
}
}
/**
* 执行CRUD操作并触发回调
*/
async crudOperation(operation, entity, data) {
try {
const response = await fetch(`${this.baseUrl}/app/${operation}/${entity}`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
});
if (!response.ok) throw new Error('Network response was not ok');
const result = await response.json();
if (result.status !== 200) throw new Error(result.text || 'API error');
// 触发操作成功的回调
this.triggerCallbacks(operation, entity, data);
// 自动同步数据
this.syncData();
return result;
} catch (error) {
console.error('CRUD error:', error);
// 触发操作失败的回调
this.triggerCallbacks(`${operation}_error`, entity, {
data,
error: error.message
});
throw error;
}
}
/**
* 执行CRUD操作
* @param {string} operation - 'add', 'delete', 'update'
* @param {string} entity - 实体名称(小写)
* @param {Object} data - 要发送的数据
* @returns {Promise<Object>} 响应结果
*/
async crudOperation(operation, entity, data) {
try {
const response = await fetch(`${this.baseUrl}/app/${operation}/${entity}`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
});
if (!response.ok) throw new Error('Network response was not ok');
const result = await response.json();
if (result.status !== 200) throw new Error(result.text || 'API error');
// 触发操作成功的回调
this.triggerCallbacks(operation, entity, data);
// 自动同步数据
this.syncData();
return result;
} catch (error) {
console.error('CRUD error:', error);
// 触发操作失败的回调
this.triggerCallbacks(`${operation}_error`, entity, {
data,
error: error.message
});
throw error;
}
}
/**
* 自动同步数据(防止频繁请求)
*/
async syncData() {
if (this.isSyncing) return;
// 距离上次同步超过5秒才执行新同步
if (this.lastSync && new Date() - this.lastSync < 5000) {
setTimeout(() => this.syncData(), 5000 - (new Date() - this.lastSync));
return;
}
this.isSyncing = true;
try {
await this.fetchAll();
} finally {
this.isSyncing = false;
}
}
/**
* 添加实体
* @param {string} entity - 实体名称
* @param {Object} data - 实体数据
*/
async addEntity(entity, data) {
return this.crudOperation('add', entity, data);
}
/**
* 更新实体
* @param {string} entity - 实体名称
* @param {Object} data - 实体数据(必须包含id)
*/
async updateEntity(entity, data) {
return this.crudOperation('update', entity, data);
}
/**
* 删除实体
* @param {string} entity - 实体名称
* @param {number} id - 实体ID
*/
async deleteEntity(entity, id) {
return this.crudOperation('delete', entity, {id});
}
}
export { DataManager };
// 创建单例实例
const dataManager = new DataManager('http://127.0.0.1:8080/KuCun2');
// 初始化时获取所有数据
dataManager.fetchAll().then(() => {
console.log('Initial data loaded');
});
// 导出数据对象,外部可以直接访问 data.bancais, data.dingdans 等
export const data = dataManager.data;
// 导出操作方法
export const addEntity = dataManager.addEntity.bind(dataManager);
export const updateEntity = dataManager.updateEntity.bind(dataManager);
export const deleteEntity = dataManager.deleteEntity.bind(dataManager);
export const fetchAll = dataManager.fetchAll.bind(dataManager);