$(selector).attr(attribute)

博客围绕$(selector).attr(attribute)展开,虽内容仅出现图片标签,但此为jQuery中用于获取元素属性的方法,在前端开发中可对元素属性进行操作,是前端开发的重要技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[img][/img]
Error building Player: CommandInvokationFailure: Unable to convert classes into dex format. See the Console for details. C:/Program Files/Java/jdk-1.8\bin\java.exe -Xmx2048M -Dcom.android.sdkmanager.toolsdir="D:/Android/sdk\tools" -Dfile.encoding=UTF8 -jar "D:\Unity\5.3.8f2\Editor\Data\PlaybackEngines\AndroidPlayer/Tools\sdktools.jar" - stderr[ warning: Ignoring InnerClasses attribute for an anonymous inner class (com.tencent.mm.sdk.b.b) that doesn't come with an associated EnclosingMethod attribute. This class was probably produced by a compiler that did not target the modern .class file format. The recommended solution is to recompile the class from source, using an up-to-date compiler and without specifying any "-target" type options. The consequence of ignoring this warning is that reflective operations on this class will incorrectly indicate that it is *not* an inner class. warning: Ignoring InnerClasses attribute for an anonymous inner class (com.testin.agent.a.b) that doesn't come with an associated EnclosingMethod attribute. This class was probably produced by a compiler that did not target the modern .class file format. The recommended solution is to recompile the class from source, using an up-to-date compiler and without specifying any "-target" type options. The consequence of ignoring this warning is that reflective operations on this class will incorrectly indicate that it is *not* an inner class. warning: Ignoring InnerClasses attribute for an anonymous inner class (com.testin.agent.a.e) that doesn't come with an associated EnclosingMethod attribute. This class was probably produced by a compiler that did not target the modern .class file format. The recommended solution is to recompile the class from source, using an up-to-date compiler and without specifying any "-target" type options. The consequence of ignoring this warning is that reflective operations on this class will incorrectly indicate that it is *not* an inner class. warning: Ignoring InnerClasses attribute for an anonymous inner class (com.testin.agent.a.f) that doesn't come with an associated EnclosingMethod attribute. This class was probably produced by a compiler that did not target the modern .class file format. The recommended solution is to recompile the class from source, using an up-to-date compiler and without specifying any "-target" type options. The consequence of ignoring this warning is that reflective operations on this class will incorrectly indicate that it is *not* an inner class. warning: Ignoring InnerClasses attribute for an anonymous inner class (com.testin.agent.a.i) that doesn't come with an associated EnclosingMethod attribute. This class was probably produced by a compiler that did not target the modern .class file format. The recommended solution is to recompile the class from source, using an up-to-date compiler and without specifying any "-target" type options. The consequence of ignoring this warning is that reflective operations on this class will incorrectly indicate that it is *not* an inner class. warning: Ignoring InnerClasses attribute for an anonymous inner class (com.testin.agent.a.m) that doesn't come with an associated EnclosingMethod attribute. This class was probably produced by a compiler that did not target the modern .class file format. The recommended solution is to recompile the class from source, using an up-to-date compiler and without specifying any "-target" type options. The consequence of ignoring this warning is that reflective operations on this class will incorrectly indicate that it is *not* an inner class. warning: Ignoring InnerClasses attribute for an anonymous inner class (com.testin.agent.d.b.c) that doesn't come with an associated EnclosingMethod attribute. This class was probably produced by a compiler that did not target the modern .class file format. The recommended solution is to recompile the class from source, using an up-to-date compiler and without specifying any "-target" type options. The consequence of ignoring this warning is that reflective operations on this class will incorrectly indicate that it is *not* an inner class. warning: Ignoring InnerClasses attribute for an anonymous inner class (com.testin.agent.d.b.b) that doesn't come with an associated EnclosingMethod attribute. This class was probably produced by a compiler that did not target the modern .class file format. The recommended solution is to recompile the class from source, using an up-to-date compiler and without specifying any "-target" type options. The consequence of ignoring this warning is that reflective operations on this class will incorrectly indicate that it is *not* an inner class. warning: Ignoring InnerClasses attribute for an anonymous inner class (com.testin.agent.e.h) that doesn't come with an associated EnclosingMethod attribute. This class was probably produced by a compiler that did not target the modern .class file format. The recommended solution is to recompile the class from source, using an up-to-date compiler and without specifying any "-target" type options. The consequence of ignoring this warning is that reflective operations on this class will incorrectly indicate that it is *not* an inner class. Uncaught translation error: java.lang.IllegalArgumentException: already added: Lbitter/jnibridge/JNIBridge; Uncaught translation error: java.lang.IllegalArgumentException: already added: Lbitter/jnibridge/JNIBridge$a; Uncaught translation error: java.lang.IllegalArgumentException: already added: Lcom/unity3d/player/NativeLoader; Uncaught translation error: java.lang.IllegalArgumentException: already added: Lcom/unity3d/player/ReflectionHelper; Uncaught translation error: java.lang.IllegalArgumentException: already added: Lcom/unity3d/player/ReflectionHelper$1; Uncaught translation error: java.lang.IllegalArgumentException: already added: Lcom/unity3d/player/ReflectionHelper$a; Uncaught translation error: java.lang.IllegalArgumentException: already added: Lcom/unity3d/player/UnityPlayer; Uncaught translation error: java.lang.IllegalArgumentException: already added: Lcom/unity3d/player/UnityPlayer$1; Uncaught translation error: java.lang.IllegalArgumentException: already added: Lcom/unity3d/player/UnityPlayer$10; UNEXPECTED TOP-LEVEL EXCEPTION: java.lang.RuntimeException: Translation has been interrupted at com.android.dx.command.dexer.Main.processAllFiles(Main.java:608) at com.android.dx.command.dexer.Main.runMonoDex(Main.java:311) at com.android.dx.command.dexer.Main.run(Main.java:277) at com.android.dx.command.dexer.Main.main(Main.java:245) at com.android.dx.command.Main.main(Main.java:106) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at SDKMain.main(SDKMain.java:129) Caused by: java.lang.InterruptedException: Too many errors at com.android.dx.command.dexer.Main.processAllFiles(Main.java:600) ... 9 more ] stdout[ processing bin\classes\.\com\dw\Dating\lua\R.class... processing bin\classes\.\com\dw\Dating\lua\R$attr.class... processing bin\classes\.\com\dw\Dating\lua\R$drawable.class... processing bin\classes\.\com\dw\Dating\lua\R$string.class... processing bin\classes\.\com\dw\Dating\lua\R$style.class... processing bin\classes\.\com\dw\Dating\lua\R$xml.class... processing archive bin\classes.jar... processing bitter/jnibridge/JNIBridge.class... processing bitter/jnibridge/JNIBridge$a.class... processing com/unity3d/player/NativeLoader.class... processing com/unity3d/player/ReflectionHelper.class... processing com/unity3d/player/ReflectionHelper$1.class... processing com/unity3d/player/ReflectionHelper$a.class... processing com/unity3d/player/UnityPlayer.class... processing com/unity3d/player/UnityPlayer$1.class... processing com/unity3d/player/UnityPlayer$10.class... processing com/unity3d/player/UnityPlayer$11.class... processing com/unity3d/player/UnityPlayer$12.class... processing com/unity3d/player/UnityPlayer$13.class... processing com/unity3d/player/UnityPlayer$14.class... processing com/unity3d/player/UnityPlayer$15.class... processing com/unity3d/player/UnityPlayer$15$1.class... processing com/unity3d/player/UnityPlayer$16.class... processing com/unity3d/player/UnityPlayer$17.class... processing com/unity3d/player/UnityPlayer$18.class... processing com/unity3d/player/UnityPlayer$19.class... processing com/unity3d/player/UnityPlayer$2.class... processing com/unity3d/player/UnityPlayer$20.class... processing com/unity3d/player/UnityPlayer$3.class... processing com/unity3d/player/UnityPlayer$4.class... processing com/unity3d/player/UnityPlayer$5.class... processing com/unity3d/player/UnityPlayer$6.class... processing com/unity3d/player/UnityPlayer$7.class... processing com/unity3d/player/UnityPlayer$8.class... processing com/unity3d/player/UnityPlayer$9.class... processing com/unity3d/player/UnityPlayer$a.class... processing com/unity3d/player/UnityPlayer$b.class... processing com/unity3d/player/UnityPlayer$c.class... processing com/unity3d/player/UnityPlayer$d.class... processing com/unity3d/player/UnityPlayerActivity.class... processing com/unity3d/player/UnityPlayerNativeActivity.class... processing com/unity3d/player/UnityPlayerProxyActivity.class... processing com/unity3d/player/UnityWebRequest.class... processing com/unity3d/player/WWW.class... processing com/unity3d/player/a.class... processing com/unity3d/player/a$1.class... processing com/unity3d/player/a$2.class... processing com/unity3d/player/a$a.class... processing com/unity3d/player/b.class... processing com/unity3d/player/b$1.class... processing com/unity3d/player/b$2.class... processing com/unity3d/player/c.class... processing com/unity3d/player/d.class... processing com/unity3d/player/d$1.class... processing com/unity3d/player/d$2.class... processing com/unity3d/player/e.class... processing com/unity3d/player/f.class... processing com/unity3d/player/g.class... processing com/unity3d/player/h.class... processing com/unity3d/player/i.class... processing com/unity3d/player/j.class... processing com/unity3d/player/k.class... processing com/unity3d/player/k$1.class... processing com/unity3d/player/k$2.class... processing com/unity3d/player/k$2$1.class... processing com/unity3d/player/k$2$1$1.class... processing com/unity3d/player/l.class... processing com/unity3d/player/l$1.class... processing com/unity3d/player/m.class... processing com/unity3d/player/n.class... processing com/unity3d/player/n$1.class... processing com/unity3d/player/o.class... processing com/unity3d/player/p.class... processing com/unity3d/player/p$1.class... processing com/unity3d/player/q.class... processing com/unity3d/player/r.class... processing com/unity3d/player/s.class... processing com/unity3d/player/s$1.class... processing com/unity3d/player/s$2.class... processing com/unity3d/player/s$3.class... processing com/unity3d/player/t.class... processing com/unity3d/player/u.class... processing com/unity3d/player/v.class... processing com/unity3d/player/w.class... processing com/unity3d/player/w$1.class... processing org/fmod/FMODAudioDevice.class... processing org/fmod/a.class... processing archive plugins\.\FanweiPlugin_v4.4.jar... processing android/app/ActivityThread.class... processing android/app/Instrumentation.class... processing android/app/Instrumentation$ActivityMonitor.class... processing android/app/Instrumentation$ActivityResult.class... processing android/app/LoadedApk.class... processing com/fanwei/bluearty/pluginmgr/BuildConfig.class... processing com/fanwei/bluearty/pluginmgr/DynamicActivity.class... processing com/fanwei/bluearty/pluginmgr/Globals.class... processing com/fanwei/bluearty/pluginmgr/PluginActivityLifeCycleCallback.class... processing com/fanwei/bluearty/pluginmgr/PluginManager.class... processing com/fanwei/bluearty/pluginmgr/delegate/DelegateActivityThread.class... processing com/fanwei/bluearty/pluginmgr/delegate/DelegateInstrumentation.class... processing com/fanwei/bluearty/pluginmgr/delegate/LayoutInflaterProxyContext.class... processing com/fanwei/bluearty/pluginmgr/environment/CreateActivityData.class... processing com/fanwei/bluearty/pluginmgr/environment/PlugInfo.class... processing com/fanwei/bluearty/pluginmgr/environment/PluginClassLoader.class... processing com/fanwei/bluearty/pluginmgr/environment/PluginContext.class... processing com/fanwei/bluearty/pluginmgr/environment/PluginInstrumentation.class... processing com/fanwei/bluearty/pluginmgr/reflect/NULL.class... processing com/fanwei/bluearty/pluginmgr/reflect/Reflect.class... processing com/fanwei/bluearty/pluginmgr/reflect/Reflect$1.class... processing com/fanwei/bluearty/pluginmgr/reflect/ReflectException.class... processing com/fanwei/bluearty/pluginmgr/selector/DefaultActivitySelector.class... processing com/fanwei/bluearty/pluginmgr/selector/DynamicActivitySelector.class... processing com/fanwei/bluearty/pluginmgr/utils/FileUtil.class... processing com/fanwei/bluearty/pluginmgr/utils/IntReader.class... processing com/fanwei/bluearty/pluginmgr/utils/NamespaceStack.class... processing com/fanwei/bluearty/pluginmgr/utils/PluginManifestUtil.class... processing com/fanwei/bluearty/pluginmgr/utils/StringBlock.class... processing com/fanwei/bluearty/pluginmgr/utils/Trace.class... processing com/fanwei/bluearty/pluginmgr/utils/XmlManifestReader.class... processing com/fanwei/bluearty/pluginmgr/utils/XmlResourceParser.class... processing com/fanwei/bluearty/pluginmgr/verify/PluginNotFoundException.class... processing com/fanwei/bluearty/pluginmgr/verify/PluginOverdueVerifier.class... processing com/fanwei/bluearty/pluginmgr/verify/SimpleLengthVerifier.class... processing com/fanwei/bluearty/pluginmgr/widget/LayoutInflaterWrapper.class... processing com/fanwei/bluearty/pluginmgr/widget/ViewStub.class... processing com/fanwei/bluearty/pluginmgr/widget/ViewStub$OnInflateListener.class... processing com/fanwei/bluearty/simplejson/BasicType.class... processing com/fanwei/bluearty/simplejson/BuildConfig.class... processing com/fanwei/bluearty/simplejson/SimpleJson.class... processing com/fanwei/bluearty/simplejson/SimpleJson$1.class... processing com/fanwei/bluearty/simplejson/annotation/CollectionCreateBy.class... processing com/fanwei/bluearty/simplejson/annotation/NickName.class... processing com/fanwei/bluearty/simplejson/annotation/NotConvert.class... processing com/fanwei/bluearty/simplejson/annotation/SerializeBy.class... processing com/fanwei/bluearty/simplejson/serializer/Serializer.class... processing com/fanwei/bluearty/tinyhttp/BuildConfig.class... processing com/fanwei/bluearty/tinyhttp/Const.class... processing com/fanwei/bluearty/tinyhttp/Request.class... processing com/fanwei/bluearty/tinyhttp/Request$Method.class... processing com/fanwei/bluearty/tinyhttp/Response.class... processing com/fanwei/bluearty/tinyhttp/RetryManager.class... processing com/fanwei/bluearty/tinyhttp/Webb.class... processing com/fanwei/bluearty/tinyhttp/Webb$1.class... processing com/fanwei/bluearty/tinyhttp/Webb$AutoDisconnectInputStream.class... processing com/fanwei/bluearty/tinyhttp/Webb$FWHostnameVerifier.class... processing com/fanwei/bluearty/tinyhttp/Webb$FWX509TrustManager.class... processing com/fanwei/bluearty/tinyhttp/WebbException.class... processing com/fanwei/bluearty/tinyhttp/WebbUtils.class... processing com/fanwei/jubaosdk/common/BuildConfig.class... processing com/fanwei/jubaosdk/common/core/AbstractCall.class... processing com/fanwei/jubaosdk/common/core/AbstractCall$Callback.class... processing com/fanwei/jubaosdk/common/core/AbstractCall$CallbackUI.class... processing com/fanwei/jubaosdk/common/core/AbstractCall$CallbackUI$UIHandler.class... processing com/fanwei/jubaosdk/common/core/Call.class... processing com/fanwei/jubaosdk/common/core/Dispatcher.class... processing com/fanwei/jubaosdk/common/core/OnPayResultListener.class... processing com/fanwei/jubaosdk/common/entity/Advertisement.class... processing com/fanwei/jubaosdk/common/entity/OrderEntity.class... processing com/fanwei/jubaosdk/common/entity/PayMethodResponse.class... processing com/fanwei/jubaos<message truncated>
最新发布
07-19
$(document).ready(function() { // 获取全局的DataManager实例 const dataManager = window.parent.dataManager; // 初始化页面元素 const $ dingdanSelect = $('#dingdanSelect'); const $ chanpinSelect = $('#chanpinSelect'); const $ zujianSelect = $('#zujianSelect'); const $ bancaiInfo = $('#bancaiInfo'); const $ orderQuantityInput = $('#orderQuantityInput'); const $ submitOrderBtn = $('#submitOrderBtn'); // 定义实体类型常量 const ENTITY_DINGDAN = 'dingdan'; const ENTITY_CHANPIN = 'chanpin'; const ENTITY_ZUJIAN = 'zujian'; const ENTITY_BANCAI = 'bancai'; const ENTITY_CAIZHI = 'caizhi'; const ENTITY_MUPI = 'mupi'; // 存储当前选中的实体ID(使用正确的层级关系) let currentDingdanId = null; // 订单ID let currentDingdanChanpinId = null; // 订单-产品关联ID let currentChanpinZujianId = null; // 产品-组件关联ID // 初始化页面 initPage(); // 初始化页面函数 async function initPage() { // 注册数据更新回调 dataManager.registerCallback('all', (operation, entity, data) => { if (operation === 'refresh' || operation === 'add' || operation === 'update' || operation === 'delete') { // 只刷新需要更新的部分 if (entity === ENTITY_DINGDAN) { refreshDingdanList(); } else if (entity === 'dingdan_chanpin') { if (currentDingdanId) { refreshChanpinList(currentDingdanId); } } else if (entity === 'chanpin_zujian') { if (currentDingdanChanpinId) { refreshZujianList(currentDingdanChanpinId); } } } }); // 填充订单下拉框 await refreshDingdanList(); // 初始化Select2下拉框 initSelect2Dropdowns(); // 绑定事件 bindEvents(); } // 初始化Select2下拉框 function initSelect2Dropdowns() { // 主页面下拉框 $('#dingdanSelect').select2({ theme: 'bootstrap', placeholder: '请选择订单', allowClear: true }); $('#chanpinSelect').select2({ theme: 'bootstrap', placeholder: '请选择产品', allowClear: true, disabled: true }); $('#zujianSelect').select2({ theme: 'bootstrap', placeholder: '请选择组件', allowClear: true, disabled: true }); } // 绑定事件处理函数 function bindEvents() { // 订单选择变化 $ dingdanSelect.on('change', async function() { currentDingdanId = $(this).val(); if (currentDingdanId) { await refreshChanpinList(currentDingdanId); $('#chanpinSelect').prop('disabled', false); $('#addChanpinBtn').prop('disabled', false); $('#chanpinSelect').select2('enable'); // 重置下级选择 $ zujianSelect.prop('disabled', true).empty(); $ zujianSelect.select2('destroy'); // 销毁旧的Select2实例 $ zujianSelect.select2({ theme: 'bootstrap', placeholder: '请选择组件', allowClear: true, disabled: true }); $ bancaiInfo.text(''); $ orderQuantityInput.val('').prop('disabled', true); $ submitOrderBtn.prop('disabled', true); $('#addZujianBtn').prop('disabled', true); currentDingdanChanpinId = null; currentChanpinZujianId = null; } else { $ chanpinSelect.prop('disabled', true).empty(); $ chanpinSelect.select2('enable', false); $ zujianSelect.prop('disabled', true).empty(); $ zujianSelect.select2('enable', false); $ bancaiInfo.text(''); $ orderQuantityInput.val('').prop('disabled', true); $ submitOrderBtn.prop('disabled', true); $('#addChanpinBtn').prop('disabled', true); $('#addZujianBtn').prop('disabled', true); currentDingdanChanpinId = null; currentChanpinZujianId = null; } }); // 产品选择变化(现在选择的是dingdan_chanpin的ID) $ chanpinSelect.on('change', async function() { currentDingdanChanpinId = $(this).val(); if (currentDingdanChanpinId) { await refreshZujianList(currentDingdanChanpinId); $ zujianSelect.prop('disabled', false); $('#addZujianBtn').prop('disabled', false); $ zujianSelect.select2('enable'); // 重置下级选择 $ bancaiInfo.text(''); $ orderQuantityInput.val('').prop('disabled', true); $ submitOrderBtn.prop('disabled', true); currentChanpinZujianId = null; } else { $ zujianSelect.prop('disabled', true).empty(); $ zujianSelect.select2('enable', false); $ bancaiInfo.text(''); $ orderQuantityInput.val('').prop('disabled', true); $ submitOrderBtn.prop('disabled', true); $('#addZujianBtn').prop('disabled', true); currentChanpinZujianId = null; } }); // 组件选择变化(现在选择的是chanpin_zujian的ID) $ zujianSelect.on('change', function() { currentChanpinZujianId = $(this).val(); if (currentChanpinZujianId) { displayBancaiInfo(currentChanpinZujianId); $ orderQuantityInput.prop('disabled', false); $ submitOrderBtn.prop('disabled', false); } else { $ bancaiInfo.text(''); $ orderQuantityInput.val('').prop('disabled', true); $ submitOrderBtn.prop('disabled', true); } }); // 新增订单按钮 $('#addDingdanBtn').on('click', function() { showEntityModal('新增订单', ENTITY_DINGDAN, null, { number: '', xiadan: new Date().toISOString().split('T')[0], jiaohuo: '' }); }); // 添加产品按钮 $('#addChanpinBtn').on('click', function() { if (!currentDingdanId) { alert('请先选择订单'); return; } // 确保产品数据已加载 if (!dataManager.data.chanpins || dataManager.data.chanpins.length === 0) { alert('产品数据未加载,请稍后再试'); return; } showEntityModal('添加产品', 'dingdan_chanpin', null, { dingdan: { id: parseInt(currentDingdanId) }, chanpin: { id: '' }, shuliang: 1 }); }); // 添加组件按钮 $('#addZujianBtn').on('click', function() { if (!currentDingdanChanpinId) { alert('请先选择产品'); return; } // 获取当前选中的产品ID const dingdanChanpin = dataManager.data.dingdan_chanpins.find( dc => dc.id == currentDingdanChanpinId ); if (!dingdanChanpin || !dingdanChanpin.chanpin) { alert('未找到产品信息'); return; } const chanpinId = dingdanChanpin.chanpin.id; showEntityModal('添加组件', 'chanpin_zujian', null, { chanpin: { id: parseInt(chanpinId) }, zujian: { id: '' }, bancai: { id: '' }, one_howmany: 1 }); }); // 提交订单按钮(修复后的逻辑) $ submitOrderBtn.on('click', async function() { const quantity = parseInt($ orderQuantityInput.val()); if (!quantity || quantity <= 0) { alert('请输入有效的订购数量'); return; } if (!currentDingdanId || !currentDingdanChanpinId || !currentChanpinZujianId) { alert('请完整选择订单、产品和组件'); return; } try { // 获取当前选中的产品组件关联 const chanpinZujian = dataManager.data.chanpin_zujians.find( cz => cz.id == currentChanpinZujianId ); if (!chanpinZujian) { throw new Error('未找到选中的产品组件关联'); } // 获取当前选中的产品关联 const dingdanChanpin = dataManager.data.dingdan_chanpins.find( dc => dc.id == currentDingdanChanpinId ); if (!dingdanChanpin || !dingdanChanpin.chanpin) { throw new Error('未找到选中的产品'); } // 实际的产品ID和组件ID const actualChanpinId = dingdanChanpin.chanpin.id; const actualZujianId = chanpinZujian.zujian.id; const actualBancaiId = chanpinZujian.bancai.id; // 检查是否已存在相同的订单组件订购记录 const existingOrder = dataManager.data.dingdan_bancais.find( dcz => dcz.dingdan.id == currentDingdanId && dcz.chanpin.id == currentChanpinId&& dcz.zujian==currentZujianId&& dcz.bancai==actualBancaiId ); //记录创建订购 if (existingOrder) { // 更新现有记录 await dataManager.updateEntity('dingdan_bancai', { id: existingOrder.id, shuliang: quantity }); } else { // 创建新记录 await dataManager.addEntity('dingdan_bancai', { dingdan: { id: parseInt(currentDingdanId) }, chanpin: { id: parseInt(currentChanpinId) }, zujian: { id: parseInt(currentzujianId) }, bancai: { id: parseInt(actualBancaiId) }, shuliang: quantity }); } // 检查是否已存在相同的订单组件订购记录 const existingban = dataManager.data.kucuns.find( dcz => dcz.bancai&&dcz.bancai.id == actualBancaiId ); if(existingban){ await dataManager.updateEntity('kucun', { id: existingban.id, shuliang: quantity+existingban.shuliang }); }else{ await dataManager.addEntity("kucun",{ bancai:{id:actualBancaiId}, shuliang:quantity }) } // 创建进货记录(使用正确的ID) await createJinhuo(actualChanpinId, actualZujianId, actualBancaiId, quantity); alert('订购成功!'); resetForm(); } catch (error) { console.error('订购失败:', error); alert(`订购失败: ${error.message}`); } }); // 模态框保存按钮 $('#saveEntityBtn').on('click', saveEntity); // 新建实体按钮(在创建实体模态框中) $('#saveNewEntityBtn').on('click', saveNewEntity); } // 创建进货记录函数(使用正确的ID)问:如何放到 //记录创建订购 回调里 async function createJinhuo(chanpinId, zujianId, bancaiId, quantity) { const jinhuoData = { dingdan: { id: parseInt(currentDingdanId) }, chanpin: { id: parseInt(chanpinId) }, zujian: { id: parseInt(zujianId) }, bancai: { id: parseInt(bancaiId) }, shuliang: quantity, date: new Date().toISOString(), user: { id: localStorage.getItem("userId") } }; await dataManager.addEntity('jinhuo', jinhuoData); } // 重置表单 function resetForm() { $ orderQuantityInput.val(''); $ submitOrderBtn.prop('disabled', true); } // 刷新订单列表 async function refreshDingdanList() { const currentValue = $ dingdanSelect.val(); $ dingdanSelect.empty().append('<option value="">请选择订单</option>'); // 获取所有订单 const dingdans = dataManager.data.dingdans || []; // 按下单日期降序排序 dingdans.sort((a, b) => new Date(b.xiadan) - new Date(a.xiadan)); // 填充下拉框 dingdans.forEach(dingdan => { const option = $('<option>') .val(dingdan.id) .text(`${dingdan.number} (${formatDate(dingdan.xiadan)})`); $ dingdanSelect.append(option); }); // 恢复之前的选择 if (currentValue) { $ dingdanSelect.val(currentValue); } // 刷新后重新初始化Select2 $ dingdanSelect.select2({ theme: 'bootstrap', placeholder: '请选择订单', allowClear: true }); } // 刷新产品列表(基于订单) async function refreshChanpinList(dingdanId) { const currentValue = $ chanpinSelect.val(); $ chanpinSelect.empty().append('<option value="">请选择产品</option>'); // 获取订单对应的产品(dingdan_chanpin) const dingdanChanpins = dataManager.data.dingdan_chanpins || []; const relatedChanpins = dingdanChanpins.filter(dc => dc.dingdan && dc.dingdan.id == dingdanId ); // 填充下拉框 relatedChanpins.forEach(dc => { if (dc.chanpin) { const option = $('<option>') .val(dc.id) // 使用dingdan_chanpin的ID .text(`${dc.chanpin.bianhao} (数量: ${dc.shuliang})`); $ chanpinSelect.append(option); } }); // 恢复之前的选择 if (currentValue) { $ chanpinSelect.val(currentValue); } // 刷新后重新初始化Select2 $ chanpinSelect.select2({ theme: 'bootstrap', placeholder: '请选择产品', allowClear: true }).prop('disabled', false); } // 刷新组件列表(基于产品)- 修复后的逻辑 async function refreshZujianList(dingdanChanpinId) { const currentValue = $ zujianSelect.val(); $ zujianSelect.empty().append('<option value="">请选择组件</option>'); // 获取当前选中的订单-产品关联 const dingdanChanpin = dataManager.data.dingdan_chanpins.find( dc => dc.id == dingdanChanpinId ); if (!dingdanChanpin || !dingdanChanpin.chanpin) { return; } const chanpinId = dingdanChanpin.chanpin.id; // 获取该产品的所有组件关联 const chanpinZujians = dataManager.data.chanpin_zujians.filter( cz => cz.chanpin && cz.chanpin.id == chanpinId ); // 填充下拉框 chanpinZujians.forEach(cz => { if (cz.zujian) { const option = $('<option>') .val(cz.id) // 使用chanpin_zujian的ID .text(`${cz.zujian.name} (产量: ${cz.one_howmany})`); $ zujianSelect.append(option); } }); // 恢复之前的选择 if (currentValue) { $ zujianSelect.val(currentValue); } // 刷新后重新初始化Select2 $ zujianSelect.select2({ theme: 'bootstrap', placeholder: '请选择组件', allowClear: true }).prop('disabled', false); } // 显示板材信息 - 修复后的逻辑 function displayBancaiInfo(chanpinZujianId) { // 获取产品组件关联 const chanpinZujian = dataManager.data.chanpin_zujians.find( cz => cz.id == chanpinZujianId ); if (!chanpinZujian || !chanpinZujian.bancai) { $ bancaiInfo.text('未找到板材信息'); return; } const bancai = chanpinZujian.bancai; let info = `厚度: ${bancai.houdu}mm, 材质: `; if (bancai.caizhi) { info += bancai.caizhi.name; } if (bancai.mupi1) { info += `, 木皮1: ${bancai.mupi1.name}${bancai.mupi1.you ? ' ()' : ''}`; } if (bancai.mupi2) { info += `, 木皮2: ${bancai.mupi2.name}${bancai.mupi2.you ? ' ()' : ''}`; } $ bancaiInfo.text(info); } // 显示实体模态框(添加产品/组件) function showEntityModal(title, entityType, entityId, initialData) { $('#modalTitle').text(title); const $ formFields = $('#formFields'); $ formFields.empty(); // 根据实体类型生成表单字段 switch (entityType) { case ENTITY_DINGDAN: $ formFields.append(` <div class="form-group"> <label>订单编号</label> <input type="text" class="form-control" name="number" value="${initialData.number || ''}" required> </div> <div class="form-group"> <label>下单日期</label> <input type="date" class="form-control" name="xiadan" value="${initialData.xiadan || ''}" required> </div> <div class="form-group"> <label>交货日期</label> <input type="date" class="form-control" name="jiaohuo" value="${initialData.jiaohuo || ''}"> </div> `); break; case 'dingdan_chanpin': // 订单产品 const chanpins = dataManager.data.chanpins || []; let chanpinOptions = '<option value="">选择产品</option>'; chanpinOptions += '<option value="new">+ 创建新产品</option>'; if (chanpins.length > 0) { chanpins.forEach(cp => { chanpinOptions += ` <option value="${cp.id}" ${initialData.chanpin.id == cp.id ? 'selected' : ''}> ${cp.bianhao} </option> `; }); } $ formFields.append(` <div class="form-group"> <label>产品</label> <div class="input-group"> <select class="form-control" name="chanpin" id="chanpinSelectModal" required> ${chanpinOptions} </select> <span class="input-group-btn"> <button class="btn btn-info" id="createChanpinBtn">新建</button> </span> </div> </div> <div class="form-group"> <label>数量</label> <input type="number" class="form-control" name="shuliang" value="${initialData.shuliang || 1}" min="1" required> </div> <input type="hidden" name="dingdan" value="${initialData.dingdan.id}"> `); // 添加新建产品按钮事件 $('#createChanpinBtn').on('click', function() { showCreateEntityModal('创建新产品', ENTITY_CHANPIN, null, { bianhao: '', name: '' }); }); // 产品选择变化 $('#chanpinSelectModal').on('change', function() { if ($(this).val() === 'new') { showCreateEntityModal('创建新产品', ENTITY_CHANPIN, null, { bianhao: '', }); $(this).val(''); // 重置选择 } }); break; case 'chanpin_zujian': // 产品组件 const zujians = dataManager.data.zujians || []; const bancais = dataManager.data.bancais || []; let zujianOptions = '<option value="">选择组件</option>'; zujianOptions += '<option value="new">+ 创建新组件</option>'; let bancaiOptions = '<option value="">选择板材</option>'; bancaiOptions += '<option value="new">+ 创建新板材</option>'; if (zujians.length > 0) { zujians.forEach(zj => { zujianOptions += ` <option value="${zj.id}" ${initialData.zujian.id == zj.id ? 'selected' : ''}> ${zj.name} </option> `; }); } if (bancais.length > 0) { bancais.forEach(bc => { let bcInfo = `厚度: ${bc.houdu}mm`; if (bc.caizhi) bcInfo += `, 材质: ${bc.caizhi.name}`; if (bc.mupi1) bcInfo += `, 木皮1: ${bc.mupi1.name}`; if (bc.mupi2) bcInfo += `, 木皮2: ${bc.mupi2.name}`; bancaiOptions += ` <option value="${bc.id}" ${initialData.bancai.id == bc.id ? 'selected' : ''}> ${bcInfo} </option> `; }); } $ formFields.append(` <div class="form-group"> <label>组件</label> <div class="input-group"> <select class="form-control" name="zujian" id="zujianSelectModal" required> ${zujianOptions} </select> <span class="input-group-btn"> <button class="btn btn-info" id="createZujianBtn">新建</button> </span> </div> </div> <div class="form-group"> <label>板材</label> <div class="input-group"> <select class="form-control" name="bancai" id="bancaiSelectModal" required> ${bancaiOptions} </select> <span class="input-group-btn"> <button class="btn btn-info" id="createBancaiBtn">新建</button> </span> </div> </div> <div class="form-group"> <label>一张板出多少组件</label> <input type="number" class="form-control" name="one_howmany" value="${initialData.one_howmany || 1}" min="0.01" step="0.01" required> </div> <input type="hidden" name="chanpin" value="${initialData.chanpin.id}"> `); // 添加新建按钮事件 $('#createZujianBtn').on('click', function() { showCreateEntityModal('创建新组件', ENTITY_ZUJIAN, null, { name: '' }); }); $('#createBancaiBtn').on('click', function() { showCreateEntityModal('创建新板材', ENTITY_BANCAI, null, { houdu: 0.0 }); }); // 组件选择变化 $('#zujianSelectModal').on('change', function() { if ($(this).val() === 'new') { showCreateEntityModal('创建新组件', ENTITY_ZUJIAN, null, { name: '' }); $(this).val(''); // 重置选择 } }); // 板材选择变化 $('#bancaiSelectModal').on('change', function() { if ($(this).val() === 'new') { showCreateEntityModal('创建新板材', ENTITY_BANCAI, null, { houdu: 0.0 }); $(this).val(''); // 重置选择 } }); break; } // 显示模态框 $('#entityModal').modal('show'); // 模态框显示后初始化Select2 $('#entityModal').on('shown.bs.modal', function() { // 产品模态框 if (entityType === 'dingdan_chanpin') { $('#chanpinSelectModal').select2({ theme: 'bootstrap', placeholder: '选择产品或创建新产品', allowClear: true, width: '100%' }); } // 组件模态框 if (entityType === 'chanpin_zujian') { $('#zujianSelectModal').select2({ theme: 'bootstrap', placeholder: '选择组件或创建新组件', allowClear: true, width: '100%' }); $('#bancaiSelectModal').select2({ theme: 'bootstrap', placeholder: '选择板材或创建新板材', allowClear: true, width: '100%' }); } }); // 模态框关闭时只销毁当前模态框内的Select2 $('#entityModal').on('hidden.bs.modal', function() { $(this).find('.select2-container').remove(); }); // 存储当前操作的实体信息 $('#entityModal').data('entity', { type: entityType, id: entityId }); } // 显示创建实体模态框(新产品/新组件/新板材) function showCreateEntityModal(title, entityType, entityId, initialData) { $('#createEntityModalTitle').text(title); const $ formFields = $('#createEntityFields'); $ formFields.empty(); // 根据实体类型生成表单字段 switch (entityType) { case ENTITY_CHANPIN: // 新产品 $ formFields.append(` <div class="form-group"> <label>产品编号</label> <input type="text" class="form-control" name="bianhao" value="${initialData.bianhao || ''}" required> </div> `); break; case ENTITY_ZUJIAN: // 新组件 $ formFields.append(` <div class="form-group"> <label>组件名称</label> <input type="text" class="form-control" name="name" value="${initialData.name || ''}" required> </div> `); break; case ENTITY_BANCAI: // 新板材 const caizhis = dataManager.data.caizhis || []; const mupis = dataManager.data.mupis || []; let caizhiOptions = '<option value="">选择材质</option>'; let mupi1Options = '<option value="">选择木皮1</option>'; let mupi2Options = '<option value="">选择木皮2</option>'; if (caizhis.length > 0) { caizhis.forEach(cz => { caizhiOptions += `<option value="${cz.id}">${cz.name}</option>`; }); } if (mupis.length > 0) { mupis.forEach(mp => { mupi1Options += `<option value="${mp.id}">${mp.name}${mp.you ? ' ()' : ''}</option>`; mupi2Options += `<option value="${mp.id}">${mp.name}${mp.you ? ' ()' : ''}</option>`; }); } $ formFields.append(` <div class="form-group"> <label>厚度(mm)</label> <input type="number" class="form-control" name="houdu" value="${initialData.houdu || 0.0}" step="0.1" min="0.1" required> </div> <div class="form-group"> <label>材质</label> <div class="input-group"> <select class="form-control" name="caizhi" required> ${caizhiOptions} </select> <span class="input-group-btn"> <button class="btn btn-default" id="createCaizhiBtn">新建</button> </span> </div> </div> <div class="form-group"> <label>木皮1</label> <div class="input-group"> <select class="form-control" name="mupi1"> ${mupi1Options} </select> <span class="input-group-btn"> <button class="btn btn-default" id="createMupiBtn">新建</button> </span> </div> </div> <div class="form-group"> <label>木皮2</label> <div class="input-group"> <select class="form-control" name="mupi2"> ${mupi2Options} </select> <span class="input-group-btn"> <button class="btn btn-default" id="createMupiBtn2">新建</button> </span> </div> </div> `); // 添加新建材质按钮事件 $('#createCaizhiBtn').on('click', function() { showCreateEntityModal('创建新材质', ENTITY_CAIZHI, null, { name: '' }); }); // 添加新建木皮按钮事件 $('#createMupiBtn, #createMupiBtn2').on('click', function() { showCreateEntityModal('创建新木皮', ENTITY_MUPI, null, { name: '', you: false }); }); break; case ENTITY_CAIZHI: // 新材质 $ formFields.append(` <div class="form-group"> <label>材质名称</label> <input type="text" class="form-control" name="name" value="${initialData.name || ''}" required> </div> `); break; case ENTITY_MUPI: // 新木皮 $ formFields.append(` <div class="form-group"> <label>木皮名称</label> <input type="text" class="form-control" name="name" value="${initialData.name || ''}" required> </div> <div class="form-group"> <label> <input type="checkbox" name="you" ${initialData.you ? 'checked' : ''}> 是否有油漆 </label> </div> `); break; } // 显示模态框 $('#createEntityModal').modal('show'); // 模态框显示后初始化Select2 $('#createEntityModal').on('shown.bs.modal', function() { if (entityType === ENTITY_BANCAI) { $('select[name="caizhi"], select[name="mupi1"], select[name="mupi2"]').select2({ theme: 'bootstrap', placeholder: '请选择', allowClear: true, width: '100%' }); } }); // 模态框关闭时只销毁当前模态框内的Select2 $('#entityModal').on('hidden.bs.modal', function() { $(this).find('.select2-container').remove(); }); // 存储当前操作的实体信息 $('#createEntityModal').data('entity', { type: entityType, id: entityId }); } // 保存实体(在添加产品/组件模态框中) async function saveEntity() { const $ saveBtn = $('#saveEntityBtn'); const originalText = $ saveBtn.text(); try { // 显示加载状态 $ saveBtn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> 保存中...'); const entityInfo = $('#entityModal').data('entity'); const formData = getFormData('#entityForm'); let result; if (entityInfo.id) { // 更新实体 result = await dataManager.updateEntity(entityInfo.type, { id: entityInfo.id, ...formData }); } else { // 新增实体 result = await dataManager.addEntity(entityInfo.type, formData); } if (result.status === 200) { $('#entityModal').modal('hide'); // 根据操作类型刷新对应的下拉列表 switch (entityInfo.type) { case ENTITY_DINGDAN: await refreshDingdanList(); break; case 'dingdan_chanpin': if (formData.dingdan && formData.dingdan.id) { await refreshChanpinList(formData.dingdan.id); } break; case 'chanpin_zujian': if (formData.chanpin && formData.chanpin.id) { await refreshZujianList(formData.chanpin.id); } break; } } else { alert(`保存失败: ${result.text}`); } } catch (error) { console.error('保存实体时出错:', error); alert(`保存失败: ${error.message}`); } finally { // 恢复按钮状态 $ saveBtn.prop('disabled', false).text(originalText); } } // 保存新实体(在创建实体模态框中) async function saveNewEntity() { const $ saveBtn = $('#saveNewEntityBtn'); const originalText = $ saveBtn.text(); try { // 显示加载状态 $ saveBtn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> 保存中...'); const entityInfo = $('#createEntityModal').data('entity'); const formData = getFormData('#createEntityForm'); // 新增实体 const result = await dataManager.addEntity(entityInfo.type, formData); if (result.status === 200) { $('#createEntityModal').modal('hide'); // 刷新父模态框中的下拉框 refreshParentDropdown(entityInfo.type, result.data.id); } else { alert(`创建失败: ${result.text}`); } } catch (error) { console.error('创建实体时出错:', error); alert(`创建失败: ${error.message}`); } finally { // 恢复按钮状态 $ saveBtn.prop('disabled', false).text(originalText); } } // 刷新父模态框中的下拉框 function refreshParentDropdown(entityType, newEntityId) { // 获取父模态框中的相关下拉框 const $ parentModal = $('#entityModal'); if (!$ parentModal.is(':visible')) return; const parentEntityType = $ parentModal.data('entity').type; // 根据实体类型刷新对应的下拉框 if (parentEntityType === 'dingdan_chanpin' && entityType === ENTITY_CHANPIN) { // 刷新产品下拉框 const $ select = $('#chanpinSelectModal'); $ select.append(`<option value="${newEntityId}" selected>新建产品</option>`); $ select.select2('destroy'); $ select.select2({ theme: 'bootstrap', placeholder: '选择产品或创建新产品', allowClear: true, width: '100%' }); } else if (parentEntityType === 'chanpin_zujian') { if (entityType === ENTITY_ZUJIAN) { // 刷新组件下拉框 const $ select = $('#zujianSelectModal'); $ select.append(`<option value="${newEntityId}" selected>新建组件</option>`); $ select.select2('destroy'); $ select.select2({ theme: 'bootstrap', placeholder: '选择组件或创建新组件', allowClear: true, width: '100%' }); } else if (entityType === ENTITY_BANCAI) { // 刷新板材下拉框 const $ select = $('#bancaiSelectModal'); $ select.append(`<option value="${newEntityId}" selected>新建板材</option>`); $ select.select2('destroy'); $ select.select2({ theme: 'bootstrap', placeholder: '选择板材或创建新板材', allowClear: true, width: '100%' }); } else if (entityType === ENTITY_CAIZHI) { // 刷新材质下拉框(在板材创建中) const $ select = $ parentModal.find('select[name="caizhi"]'); $ select.append(`<option value="${newEntityId}" selected>新建材质</option>`); $ select.select2('destroy'); $ select.select2({ theme: 'bootstrap', placeholder: '请选择', allowClear: true, width: '100%' }); } else if (entityType === ENTITY_MUPI) { // 刷新木皮下拉框(在板材创建中) const $ select = $ parentModal.find('select[name="mupi1"], select[name="mupi2"]'); $ select.append(`<option value="${newEntityId}" selected>新建木皮</option>`); $ select.select2('destroy'); $ select.select2({ theme: 'bootstrap', placeholder: '请选择', allowClear: true, width: '100%' }); } } } // 获取表单数据 function getFormData(selector) { const formData = {}; $(`${selector} :input`).each(function() { const $ input = $(this); const name = $ input.attr('name'); const type = $ input.attr('type'); if (name) { if (type === 'checkbox') { formData[name] = $ input.prop('checked'); } else if (type === 'radio') { if ($ input.prop('checked')) { formData[name] = $ input.val(); } } else { // 处理关联对象 if (name === 'chanpin' || name === 'zujian' || name === 'bancai' || name === 'dingdan' || name === 'caizhi' || name === 'mupi1' || name === 'mupi2') { formData[name] = { id: parseInt($ input.val()) }; } else if (name === 'one_howmany' || name === 'houdu') { formData[name] = parseFloat($ input.val()); } else if (name === 'shuliang') { formData[name] = parseInt($ input.val()); } else { formData[name] = $ input.val(); } } } }); return formData; } // 日期格式化辅助函数 function formatDate(dateString) { if (!dateString) return ''; const date = new Date(dateString); return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`; } }); 进货记录放在创建和更新订购计录的回调中中 function resolveDataReferences(data) { console.log(data) // 获取 data 对象的所有顶层键 const keys = Object.keys(data); // 遍历每个顶层键(如 users, posts 等) for (const key of keys) { const entities = data[key]; // 遍历该顶层键下的每个实体(如每个 user 或 post) for (const entity of entities) { // 遍历实体的每个属性 for (const attribute in entity) { if (entity?.hasOwnProperty(attribute)) { var trpe=attribute?.replace(/\d/g, ''); // 确保属性属于当前实体 if (Array.isArray(entity[attribute])) { if(data[trpe]==null){ trpe+="s" } // 如果属性是一个数组,则将数组中的每个 ID 替换为对应的实际对象 entity[attribute] = entity[attribute].map(item => data[trpe ]?.find(updateItem => updateItem.id === item.id) || item ); } else if (typeof entity[attribute] === "object" && entity[attribute] !== null) { // 如果属性是一个对象,则将其替换为对应的实际对象 entity[attribute] = data[trpe + "s"]?.find(updateItem => updateItem.id === entity[attribute].id); } } } } } return data; } /** * 数据管理器类,负责与后端API通信并管理数据 */ class DataManager { constructor(baseUrl) { this.baseUrl = baseUrl; this.data = { bancais: [], dingdans: [], mupis: [], chanpins: [], kucuns: [], dingdan_bancais:[], chanpin_zujians: [], zujians: [], caizhis: [], dingdan_chanpins: [], users: [], jinhuos: [] }; this.isSyncing = false; this.lastSync = null; this.callbacks = { all: [], bancais: [], dingdan: [], mupi: [], chanpin: [], kucun: [], chanpin_zujian: [], dingdan_bancai:[], zujian: [], caizhi: [], dingdan_chanpin: [], user: [], jinhuo: [] }; this.syncQueue = Promise.resolve(); } /** * 获取所有数据 * @returns {Promise<boolean>} 是否成功 */ async fetchAll() { console.log(this) 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'); console.log(result.data) const resolvedData = resolveDataReferences(result.data); // 更新本地数据 Object.keys(this.data).forEach(key => { if (resolvedData[key]) { this.data[key] = resolvedData[key]; } }); this.lastSync = new Date(); // 关键改进:数据更新后触发刷新回调 this.triggerCallbacks('refresh', 'all', this.data); return true; } catch (error) { console.error('Fetch error:', error); // 触发错误回调 this.triggerCallbacks('fetch_error', 'all', { 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.syncData(); // 触发操作成功的回调 this.triggerCallbacks(operation, entity, data); 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 - 要发送的数据 后端要求数据格式为{属性: "值", 关联对象: {id:0}, 关联对象集: [{id:0}]} * @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.syncQueue = this.syncQueue.then(async () => { await this.syncData(); // 同步完成后触发操作回调 this.triggerCallbacks(operation, entity, data); }); 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) { this.pendingSync = true; return; } this.isSyncing = true; try { await this.fetchAll(); } catch (error) { console.error('Sync failed:', error); } finally { this.isSyncing = false; // 处理等待中的同步请求 if (this.pendingSync) { this.pendingSync = false; setTimeout(() => this.syncData(), 1000); } } } /** * 添加实体 * @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}); } /** * 新增方法:手动触发数据刷新 */ async refreshData() { return this.syncQueue = this.syncQueue.then(() => this.syncData()); } /** * 获取订单的可用板材信息 * @param {number} dingdanId - 订单ID * @returns {Object} 可用板材信息 */ getAvailableBancaisForOrder(dingdanId) { const dingdan = this.data.dingdans.find(d => d.id == dingdanId); if (!dingdan) return {}; return dingdan.availableBancais || {}; } /** * 获取产品的组件列表 * @param {number} chanpinId - 产品ID * @returns {Array} 组件列表 */ getZujiansForChanpin(chanpinId) { const chanpin = this.data.chanpins.find(c => c.id == chanpinId); if (!chanpin) return []; return (chanpin.chanpin_zujian_list || []) .map(cz => cz.zujian) .filter(z => z); } /** * 获取组件的板材信息 * @param {number} zujianId - 组件ID * @returns {Array} 板材列表 */ getBancaisForZujian(zujianId) { return (this.data.chanpin_zujians || []) .filter(cz => cz.zujian && cz.zujian.id == zujianId) .map(cz => cz.bancai) .filter(b => b); } /** * 创建进货记录 在这里实现订购记录回调在创建进货记录 * @param {Object} jinhuoData - 进货数据 * @returns {Promise} 操作结果 */ async createJinhuo(jinhuoData) { return this.addEntity('jinhuo', jinhuoData); } /** * 获取订单列表 * @returns {Array} 订单列表 */ getDingdans() { return this.data.dingdans || []; } /** * 获取订单的产品列表 * @param {number} dingdanId - 订单ID * @returns {Array} 产品列表 */ getChanpinsForDingdan(dingdanId) { const dingdan = this.data.dingdans.find(d => d.id == dingdanId); if (!dingdan) return []; return (dingdan.dingdan_chanpin_list || []) .map(dc => dc.chanpin) .filter(c => c); } } 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);
06-24
//{ 实体类的关联和属性列表 // "entities": { // "Dingdan": { // "properties": { // "id": "Integer", // "number": "String", // "xiadan": "Date", // "jiaohuo": "Date", // "dingdan_chanpins": "List<Dingdan_chanpin> (OneToMany)", // "dingdan_chanpins_zujians": "List<Dingdan_chanpin_zujian> (OneToMany)" // }, // "relations": [ // "关联订单产品(Dingdan_chanpin)", // "关联订单组件(Dingdan_chanpin_zujian)" // ] // }, // "Dingdan_chanpin": { // "properties": { // "id": "Integer", // "shuliang": "Integer" // }, // "relations": [ // "多对一关联订单(Dingdan)", // "多对一关联产品(Chanpin)" // ] // }, // "Dingdan_chanpin_zujian": { // "properties": { // "id": "Integer", // "shuliang": "Integer" // }, // "relations": [ // "多对一关联订单(Dingdan)", // "多对一关联组件(Chanpin_zujian)", // "多对一关联板材(Bancai)" // ] // }, // "Jinhuo": { // "properties": { // "id": "Integer", // "shuliang": "Integer", // "date": "Date" // }, // "relations": [ // "多对一关联订单(Dingdan)", // "多对一关联产品(Chanpin)", // "多对一关联组件(Zujian)", // "多对一关联板材(Bancai)", // "多对一关联用户(User)" // ] // }, // "Kucun": { // "properties": { // "id": "Integer", // "shuliang": "Long" // }, // "relations": [ // "一对一关联板材(Bancai)" // ] // }, // "Mupi": { // "properties": { // "id": "Integer", // "name": "String", // "you": "Boolean" // }, // "relations": [ // "被板材关联(Bancai - mupi1/mupi2)" // ] // }, // "User": { // "properties": { // "id": "Integer", // "name": "String", // "andy": "String", // "pass": "String", // "role": "int" // } // }, // "Zujian": { // "properties": { // "id": "Integer", // "name": "String" // }, // "relations": [ // "一对多关联产品组件(Chanpin_zujian)" // ] // }, // "Bancai": { // "properties": { // "id": "Integer", // "houdu": "Double" // }, // "relations": [ // "多对一关联材质(Caizhi)", // "多对一关联木皮(Mupi - mupi1/mupi2)", // "一对一关联库存(Kucun)" // ] // }, // "Caizhi": { // "properties": { // "id": "Integer", // "name": "String" // }, // "relations": [ // "一对多关联板材(Bancai)" // ] // }, // "Chanpin": { // "properties": { // "id": "Integer", // "bianhao": "String" // }, // "relations": [ // "一对多关联订单产品(Dingdan_chanpin)", // "一对多关联产品组件(Chanpin_zujian)" // ] // }, // "Chanpin_zujian": { // "properties": { // "id": "Integer", // "one_howmany": "Double" // }, // "relations": [ // "多对一关联产品(Chanpin)", // "多对一关联组件(Zujian)", // "多对一关联板材(Bancai)" // ] // } // }, // "relationsSummary": [ // "订单(Dingdan) 1:N 订单产品(Dingdan_chanpin)", // "订单(Dingdan) 1:N 订单组件(Dingdan_chanpin_zujian)", // "产品(Chanpin) 1:N 产品组件(Chanpin_zujian)", // "组件(Zujian) 1:N 产品组件(Chanpin_zujian)", // "板材(Bancai) 1:1 库存(Kucun)", // "材质(Caizhi) 1:N 板材(Bancai)" // ] //} /** * 优化后的关联解析函数(解决空值问题) * @param {Object} data - 后端原始数据 * @returns {Object} 处理后的完整关联数据 */ function __resolveDataReferences(data) { // 创建ID映射表(带空值保护) const idMaps = {}; Object.keys(data).forEach(key => { if (Array.isArray(data[key])) { idMaps[key] = new Map(); data[key].forEach(item => item.id && idMaps[key].set(item.id, item)); } }); // 通用关联解析方法(带安全检测) const resolveRef = (sourceArray, sourceKey, targetKey, refProperty) => { if (!Array.isArray(sourceArray)) return; sourceArray.forEach(item => { const refObj = item[refProperty]; if (refObj && refObj.id && idMaps[targetKey]) { const target = idMaps[targetKey].get(refObj.id); if (target) { // 建立正向引用 item[refProperty] = target; // 建立反向引用(自动创建关联数组) const reverseProp = sourceKey.endsWith('s') ? sourceKey.slice(0, -1) + '_list' : sourceKey + '_list'; if (!target[reverseProp]) target[reverseProp] = []; if (!target[reverseProp].includes(item)) { target[reverseProp].push(item); } } } }); }; // 处理特定关联(使用新安全方法) // 订单 ↔ 订单产品 if (data.dingdans && data.dingdan_chanpins) { resolveRef(data.dingdan_chanpins, 'dingdans', 'dingdans', 'dingdan'); } // 订单 ↔ 订单组件 if (data.dingdans && data.dingdan_chanpin_zujians) { resolveRef(data.dingdan_chanpin_zujians, 'dingdans', 'dingdans', 'dingdan'); } // 产品 ↔ 产品组件 if (data.chanpins && data.chanpin_zujians) { resolveRef(data.chanpin_zujians, 'chanpins', 'chanpins', 'chanpin'); } // 组件 ↔ 产品组件 if (data.zujians && data.chanpin_zujians) { resolveRef(data.chanpin_zujians, 'zujians', 'zujians', 'zujian'); } // 材质 ↔ 板材 if (data.caizhis && data.bancais) { resolveRef(data.bancais, 'caizhis', 'caizhis', 'caizhi'); } // 板材 ↔ 库存(一对一) if (data.bancais && data.kucuns) { resolveRef(data.bancais, 'kucuns', 'kucuns', 'kucun'); resolveRef(data.kucuns, 'bancais', 'bancais', 'bancai'); // 反向引用 } // 板材 ↔ 木皮(mupi1/mupi2) if (data.bancais && data.mupis) { resolveRef(data.bancais, 'mupis', 'mupis', 'mupi1'); resolveRef(data.bancais, 'mupis', 'mupis', 'mupi2'); } // 订单产品 ↔ 产品 if (data.dingdan_chanpins && data.chanpins) { resolveRef(data.dingdan_chanpins, 'chanpins', 'chanpins', 'chanpin'); } // 订单组件 ↔ 产品组件 if (data.dingdan_chanpin_zujians && data.chanpin_zujians) { resolveRef(data.dingdan_chanpin_zujians, 'chanpin_zujians', 'chanpin_zujians', 'chanpin_zujian'); } // 订单组件 ↔ 板材 if (data.dingdan_chanpin_zujians && data.bancais) { resolveRef(data.dingdan_chanpin_zujians, 'bancais', 'bancais', 'bancai'); } // 进货 ↔ 相关实体 if (data.jinhuos) { ['dingdan', 'chanpin', 'zujian', 'bancai', 'user'].forEach(entity => { const plural = entity + 's'; if (data[plural]) { resolveRef(data.jinhuos, plural, plural, entity); } }); } return data; } function resolveDataReferences(data) { // 获取 data 对象的所有顶层键 const keys = Object.keys(data); // 遍历每个顶层键(如 users, posts 等) for (const key of keys) { const entities = data[key]; // 遍历该顶层键下的每个实体(如每个 user 或 post) for (const entity of entities) { // 遍历实体的每个属性 for (const attribute in entity) { if (entity.hasOwnProperty(attribute)) { var trpe=attribute.replace(/\d/g, ''); // 确保属性属于当前实体 if (Array.isArray(entity[attribute])) { if(data[trpe]==null){ trpe+="s" } // 如果属性是一个数组,则将数组中的每个 ID 替换为对应的实际对象 entity[attribute] = entity[attribute].map(item => data[trpe ]?.find(updateItem => updateItem.id === item.id) || item ); } else if (typeof entity[attribute] === "object" && entity[attribute] !== null) { // 如果属性是一个对象,则将其替换为对应的实际对象 entity[attribute] = data[trpe + "s"]?.find(updateItem => updateItem.id === entity[attribute].id); } } } } } console.log(data) return data; } /** * 数据管理器类,负责与后端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: [], // ...其他实体 }; this.syncQueue = Promise.resolve(); } /** * 获取所有数据 * @returns {Promise<boolean>} 是否成功 */ async fetchAll() { console.log(this) 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'); const resolvedData = resolveDataReferences(result.data); // 更新本地数据 Object.keys(this.data).forEach(key => { if (resolvedData[key]) { this.data[key] = resolvedData[key]; } }); this.lastSync = new Date(); // 关键改进:数据更新后触发刷新回调 this.triggerCallbacks('refresh', 'all', this.data); return true; } catch (error) { console.error('Fetch error:', error); // 触发错误回调 this.triggerCallbacks('fetch_error', 'all', { 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.syncData(); // 触发操作成功的回调 this.triggerCallbacks(operation, entity, data); 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 - 要发送的数据 后端要求数据格式为{属性: "值", 关联对象: {id:0}, 关联对象集: [{id:0}]} * @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.syncQueue = this.syncQueue.then(async () => { await this.syncData(); // 同步完成后触发操作回调 this.triggerCallbacks(operation, entity, data); }); 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) { this.pendingSync = true; return; } this.isSyncing = true; try { await this.fetchAll(); } catch (error) { console.error('Sync failed:', error); } finally { this.isSyncing = false; // 处理等待中的同步请求 if (this.pendingSync) { this.pendingSync = false; setTimeout(() => this.syncData(), 1000); } } } /** * 添加实体 * @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}); } /** * 新增方法:手动触发数据刷新 */ async refreshData() { return this.syncQueue = this.syncQueue.then(() => this.syncData()); } } 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);$(document).ready(function() { // 获取全局的DataManager实例 const dataManager = window.parent.dataManager; // 初始化页面元素 const $dingdanSelect = $('#dingdanSelect'); const $chanpinSelect = $('#chanpinSelect'); const $zujianSelect = $('#zujianSelect'); const $bancaiInfo = $('#bancaiInfo'); const $orderQuantityInput = $('#orderQuantityInput'); const $submitOrderBtn = $('#submitOrderBtn'); // 定义实体类型常量 const ENTITY_DINGDAN = 'dingdan'; const ENTITY_CHANPIN = 'chanpin'; const ENTITY_ZUJIAN = 'zujian'; const ENTITY_BANCAI = 'bancai'; const ENTITY_CAIZHI = 'caizhi'; const ENTITY_MUPI = 'mupi'; // 存储当前选中的实体ID let currentDingdanId = null; let currentChanpinId = null; let currentZujianId = null; // 初始化页面 initPage(); // 初始化页面函数 async function initPage() { // 注册数据更新回调 dataManager.registerCallback('all', (operation, entity, data) => { if (operation === 'refresh' || operation === 'add' || operation === 'update' || operation === 'delete') { // 只刷新需要更新的部分 if (entity === ENTITY_DINGDAN) { refreshDingdanList(); } else if (entity === 'dingdan_chanpin') { if (currentDingdanId) { refreshChanpinList(currentDingdanId); } } else if (entity === 'chanpin_zujian') { if (currentChanpinId) { refreshZujianList(currentChanpinId); } } } }); // 填充订单下拉框 await refreshDingdanList(); // 绑定事件 bindEvents(); } // 绑定事件处理函数 function bindEvents() { // 订单选择变化 $dingdanSelect.on('change', async function() { currentDingdanId = $(this).val(); if (currentDingdanId) { await refreshChanpinList(currentDingdanId); $('#chanpinSelect').prop('disabled', false); $('#addChanpinBtn').prop('disabled', false); // 重置下级选择 $zujianSelect.prop('disabled', true).empty(); $bancaiInfo.text(''); $orderQuantityInput.val('').prop('disabled', true); $submitOrderBtn.prop('disabled', true); $('#addZujianBtn').prop('disabled', true); currentChanpinId = null; currentZujianId = null; } else { $chanpinSelect.prop('disabled', true).empty(); $zujianSelect.prop('disabled', true).empty(); $bancaiInfo.text(''); $orderQuantityInput.val('').prop('disabled', true); $submitOrderBtn.prop('disabled', true); $('#addChanpinBtn').prop('disabled', true); $('#addZujianBtn').prop('disabled', true); currentChanpinId = null; currentZujianId = null; } }); // 产品选择变化 $chanpinSelect.on('change', async function() { currentChanpinId = $(this).val(); if (currentChanpinId) { await refreshZujianList(currentChanpinId); $zujianSelect.prop('disabled', false); $('#addZujianBtn').prop('disabled', false); // 重置下级选择 $bancaiInfo.text(''); $orderQuantityInput.val('').prop('disabled', true); $submitOrderBtn.prop('disabled', true); currentZujianId = null; } else { $zujianSelect.prop('disabled', true).empty(); $bancaiInfo.text(''); $orderQuantityInput.val('').prop('disabled', true); $submitOrderBtn.prop('disabled', true); $('#addZujianBtn').prop('disabled', true); currentZujianId = null; } }); // 组件选择变化 $zujianSelect.on('change', function() { currentZujianId = $(this).val(); if (currentZujianId) { displayBancaiInfo(currentZujianId); $orderQuantityInput.prop('disabled', false); $submitOrderBtn.prop('disabled', false); } else { $bancaiInfo.text(''); $orderQuantityInput.val('').prop('disabled', true); $submitOrderBtn.prop('disabled', true); } }); // 新增订单按钮 $('#addDingdanBtn').on('click', function() { showEntityModal('新增订单', ENTITY_DINGDAN, null, { number: '', xiadan: new Date().toISOString().split('T')[0], jiaohuo: '' }); }); // 添加产品按钮 $('#addChanpinBtn').on('click', function() { if (!currentDingdanId) { alert('请先选择订单'); return; } // 确保产品数据已加载 if (!dataManager.data.chanpins || dataManager.data.chanpins.length === 0) { alert('产品数据未加载,请稍后再试'); return; } showEntityModal('添加产品', 'dingdan_chanpin', null, { dingdan: { id: parseInt(currentDingdanId) }, chanpin: { id: '' }, shuliang: 1 }); }); // 添加组件按钮 $('#addZujianBtn').on('click', function() { if (!currentChanpinId) { alert('请先选择产品'); return; } // 确保组件数据已加载 if (!dataManager.data.zujians || dataManager.data.zujians.length === 0) { alert('组件数据未加载,请稍后再试'); return; } // 确保板材数据已加载 if (!dataManager.data.bancais || dataManager.data.bancais.length === 0) { alert('板材数据未加载,请稍后再试'); return; } showEntityModal('添加组件', 'chanpin_zujian', null, { chanpin: { id: parseInt(currentChanpinId) }, zujian: { id: '' }, bancai: { id: '' }, one_howmany: 1 }); }); // 提交订单按钮 $submitOrderBtn.on('click', async function() { const quantity = parseInt($orderQuantityInput.val()); if (!quantity || quantity <= 0) { alert('请输入有效的订购数量'); return; } if (!currentDingdanId || !currentZujianId) { alert('请完整选择订单、产品和组件'); return; } try { // 获取当前选中的产品组件关联 const chanpinZujian = dataManager.data.chanpin_zujians.find( cz => cz.id == currentZujianId ); if (!chanpinZujian) { throw new Error('未找到选中的产品组件关联'); } // 检查是否已存在相同的订单组件订购记录 var existingOrder if(dataManager.data.dingdan_chanpin_zujians.length>0){ existingOrder= dataManager.data.dingdan_chanpin_zujians.find( dcz => dcz.dingdan&& dcz.dingdan.id == currentDingdanId && dcz.chanpin_zujian.id == currentZujianId ); } if (existingOrder) { // 更新现有记录 await dataManager.updateEntity('dingdan_chanpin_zujian', { id: existingOrder.id, shuliang: quantity }); } else { // 创建新记录 - 直接关联chanpin_zujian await dataManager.addEntity('dingdan_chanpin_zujian', { dingdan: { id: parseInt(currentDingdanId) }, chanpin_zujian: { id: parseInt(currentZujianId) }, bancai:{id:parseInt(chanpinZujian.bancai.id)},// 直接关联 shuliang: quantity }); } // 创建进货记录 await createJinhuo(chanpinZujian, quantity); alert('订购成功!'); resetForm(); } catch (error) { console.error('订购失败:', error); alert(`订购失败: ${error.message}`); } }); // 模态框保存按钮 $('#saveEntityBtn').on('click', saveEntity); // 新建实体按钮(在创建实体模态框中) $('#saveNewEntityBtn').on('click', saveNewEntity); } // 修改createJinhuo函数 async function createJinhuo(chanpinZujian, quantity) { // 获取当前用户 // 确保获取正确的产品ID和组件ID const chanpinId = chanpinZujian.chanpin?.id; const zujianId = chanpinZujian.zujian?.id; const bancaiId = chanpinZujian.bancai?.id; if (!chanpinId || !zujianId || !bancaiId) { throw new Error('产品组件关联数据不完整'); } const jinhuoData = { dingdan: { id: parseInt(currentDingdanId) }, chanpin: { id: chanpinId }, // 使用实际产品ID zujian: { id: zujianId }, // 使用实际组件ID bancai: { id: bancaiId }, // 使用实际板材ID shuliang: quantity, date: new Date().toISOString(), user: { id: localStorage.getItem("userId") } }; await dataManager.addEntity('jinhuo', jinhuoData); } // 重置表单 function resetForm() { $orderQuantityInput.val(''); $submitOrderBtn.prop('disabled', true); } // 刷新订单列表 async function refreshDingdanList() { const currentValue = $dingdanSelect.val(); $dingdanSelect.empty().append('<option value="">请选择订单</option>'); // 获取所有订单 const dingdans = dataManager.data.dingdans || []; // 按下单日期降序排序 dingdans.sort((a, b) => new Date(b.xiadan) - new Date(a.xiadan)); // 填充下拉框 dingdans.forEach(dingdan => { const option = $('<option>') .val(dingdan.id) .text(`${dingdan.number} (${formatDate(dingdan.xiadan)})`); $dingdanSelect.append(option); }); // 恢复之前的选择 if (currentValue) { $dingdanSelect.val(currentValue); } } // 刷新产品列表(基于订单) async function refreshChanpinList(dingdanId) { const currentValue = $chanpinSelect.val(); $chanpinSelect.empty().append('<option value="">请选择产品</option>'); // 获取订单对应的产品 const dingdan = dataManager.data.dingdans.find(d => d.id == dingdanId); if (!dingdan || !dingdan.dingdan_chanpin) return; // 填充下拉框 dingdan.dingdan_chanpin.forEach(dc => { if (dc.chanpin) { const option = $('<option>') .val(dc.id) .text(`${dc.chanpin.bianhao} (数量: ${dc.shuliang})`); $chanpinSelect.append(option); } }); // 恢复之前的选择 if (currentValue) { $chanpinSelect.val(currentValue); } } // 刷新组件列表(基于产品) async function refreshZujianList(dingdanChanpinId) { const currentValue = $zujianSelect.val(); $zujianSelect.empty().append('<option value="">请选择组件</option>'); // 获取产品对应的组件 const chanpin = dataManager.data.chanpins.find( cp => cp.dingdan_chanpin?.some(dc => dc.id == dingdanChanpinId) ); if (!chanpin || !chanpin.chanpin_zujian) return; // 填充下拉框 chanpin.chanpin_zujian.forEach(cz => { if (cz.zujian) { const option = $('<option>') .val(cz.id) .text(`${cz.zujian.name} (产量: ${cz.one_howmany})`); $zujianSelect.append(option); } }); // 恢复之前的选择 if (currentValue) { $zujianSelect.val(currentValue); } } // 显示板材信息 function displayBancaiInfo(chanpinZujianId) { // 获取产品组件 const chanpinZujian = dataManager.data.chanpin_zujians.find( cz => cz.id == chanpinZujianId ); if (!chanpinZujian || !chanpinZujian.bancai) { $bancaiInfo.text('未找到板材信息'); return; } const bancai = chanpinZujian.bancai; let info = `厚度: ${bancai.houdu}mm, 材质: `; if (bancai.caizhi) { info += bancai.caizhi.name; } if (bancai.mupi1) { info += `, 木皮1: ${bancai.mupi1.name}${bancai.mupi1.you ? ' ()' : ''}`; } if (bancai.mupi2) { info += `, 木皮2: ${bancai.mupi2.name}${bancai.mupi2.you ? ' ()' : ''}`; } $bancaiInfo.text(info); } // 显示实体模态框(添加产品/组件) function showEntityModal(title, entityType, entityId, initialData) { $('#modalTitle').text(title); const $formFields = $('#formFields'); $formFields.empty(); // 根据实体类型生成表单字段 switch (entityType) { case ENTITY_DINGDAN: $formFields.append(` <div class="form-group"> <label>订单编号</label> <input type="text" class="form-control" name="number" value="${initialData.number || ''}" required> </div> <div class="form-group"> <label>下单日期</label> <input type="date" class="form-control" name="xiadan" value="${initialData.xiadan || ''}" required> </div> <div class="form-group"> <label>交货日期</label> <input type="date" class="form-control" name="jiaohuo" value="${initialData.jiaohuo || ''}"> </div> `); break; case 'dingdan_chanpin': // 订单产品 const chanpins = dataManager.data.chanpins || []; let chanpinOptions = '<option value="">选择产品</option>'; chanpinOptions += '<option value="new">+ 创建新产品</option>'; if (chanpins.length > 0) { chanpins.forEach(cp => { chanpinOptions += ` <option value="${cp.id}" ${initialData.chanpin.id == cp.id ? 'selected' : ''}> ${cp.bianhao} </option> `; }); } $formFields.append(` <div class="form-group"> <label>产品</label> <div class="input-group"> <select class="form-control" name="chanpin" id="chanpinSelectModal" required> ${chanpinOptions} </select> <span class="input-group-btn"> <button class="btn btn-info" id="createChanpinBtn">新建</button> </span> </div> </div> <div class="form-group"> <label>数量</label> <input type="number" class="form-control" name="shuliang" value="${initialData.shuliang || 1}" min="1" required> </div> <input type="hidden" name="dingdan" value="${initialData.dingdan.id}"> `); // 添加新建产品按钮事件 $('#createChanpinBtn').on('click', function() { showCreateEntityModal('创建新产品', ENTITY_CHANPIN, null, { bianhao: '', name: '' }); }); // 产品选择变化 $('#chanpinSelectModal').on('change', function() { if ($(this).val() === 'new') { showCreateEntityModal('创建新产品', ENTITY_CHANPIN, null, { bianhao: '', name: '' }); $(this).val(''); // 重置选择 } }); break; case 'chanpin_zujian': // 产品组件 const zujians = dataManager.data.zujians || []; const bancais = dataManager.data.bancais || []; let zujianOptions = '<option value="">选择组件</option>'; zujianOptions += '<option value="new">+ 创建新组件</option>'; let bancaiOptions = '<option value="">选择板材</option>'; bancaiOptions += '<option value="new">+ 创建新板材</option>'; if (zujians.length > 0) { zujians.forEach(zj => { zujianOptions += ` <option value="${zj.id}" ${initialData.zujian.id == zj.id ? 'selected' : ''}> ${zj.name} </option> `; }); } if (bancais.length > 0) { bancais.forEach(bc => { let bcInfo = `厚度: ${bc.houdu}mm`; if (bc.caizhi) bcInfo += `, 材质: ${bc.caizhi.name}`; if (bc.mupi1) bcInfo += `, 木皮1: ${bc.mupi1.name}`; if (bc.mupi2) bcInfo += `, 木皮2: ${bc.mupi2.name}`; bancaiOptions += ` <option value="${bc.id}" ${initialData.bancai.id == bc.id ? 'selected' : ''}> ${bcInfo} </option> `; }); } $formFields.append(` <div class="form-group"> <label>组件</label> <div class="input-group"> <select class="form-control" name="zujian" id="zujianSelectModal" required> ${zujianOptions} </select> <span class="input-group-btn"> <button class="btn btn-info" id="createZujianBtn">新建</button> </span> </div> </div> <div class="form-group"> <label>板材</label> <div class="input-group"> <select class="form-control" name="bancai" id="bancaiSelectModal" required> ${bancaiOptions} </select> <span class="input-group-btn"> <button class="btn btn-info" id="createBancaiBtn">新建</button> </span> </div> </div> <div class="form-group"> <label>一张板出多少组件</label> <input type="number" class="form-control" name="one_howmany" value="${initialData.one_howmany || 1}" min="0.01" step="0.01" required> </div> <input type="hidden" name="chanpin" value="${initialData.chanpin.id}"> `); // 添加新建按钮事件 $('#createZujianBtn').on('click', function() { showCreateEntityModal('创建新组件', ENTITY_ZUJIAN, null, { name: '' }); }); $('#createBancaiBtn').on('click', function() { showCreateEntityModal('创建新板材', ENTITY_BANCAI, null, { houdu: 0.0 }); }); // 组件选择变化 $('#zujianSelectModal').on('change', function() { if ($(this).val() === 'new') { showCreateEntityModal('创建新组件', ENTITY_ZUJIAN, null, { name: '' }); $(this).val(''); // 重置选择 } }); // 板材选择变化 $('#bancaiSelectModal').on('change', function() { if ($(this).val() === 'new') { showCreateEntityModal('创建新板材', ENTITY_BANCAI, null, { houdu: 0.0 }); $(this).val(''); // 重置选择 } }); break; } // 显示模态框 $('#entityModal').modal('show'); // 存储当前操作的实体信息 $('#entityModal').data('entity', { type: entityType, id: entityId }); } // 显示创建实体模态框(新产品/新组件/新板材) function showCreateEntityModal(title, entityType, entityId, initialData) { $('#createEntityModalTitle').text(title); const $formFields = $('#createEntityFields'); $formFields.empty(); // 根据实体类型生成表单字段 switch (entityType) { case ENTITY_CHANPIN: // 新产品 $formFields.append(` <div class="form-group"> <label>产品编号</label> <input type="text" class="form-control" name="bianhao" value="${initialData.bianhao || ''}" required> </div> `); break; case ENTITY_ZUJIAN: // 新组件 $formFields.append(` <div class="form-group"> <label>组件名称</label> <input type="text" class="form-control" name="name" value="${initialData.name || ''}" required> </div> `); break; case ENTITY_BANCAI: // 新板材 const caizhis = dataManager.data.caizhis || []; const mupis = dataManager.data.mupis || []; let caizhiOptions = '<option value="">选择材质</option>'; let mupi1Options = '<option value="">选择木皮1</option>'; let mupi2Options = '<option value="">选择木皮2</option>'; if (caizhis.length > 0) { caizhis.forEach(cz => { caizhiOptions += `<option value="${cz.id}">${cz.name}</option>`; }); } if (mupis.length > 0) { mupis.forEach(mp => { mupi1Options += `<option value="${mp.id}">${mp.name}${mp.you ? ' ()' : ''}</option>`; mupi2Options += `<option value="${mp.id}">${mp.name}${mp.you ? ' ()' : ''}</option>`; }); } $formFields.append(` <div class="form-group"> <label>厚度(mm)</label> <input type="number" class="form-control" name="houdu" value="${initialData.houdu || 0.0}" step="0.1" min="0.1" required> </div> <div class="form-group"> <label>材质</label> <div class="input-group"> <select class="form-control" name="caizhi" required> ${caizhiOptions} </select> <span class="input-group-btn"> <button class="btn btn-default" id="createCaizhiBtn">新建</button> </span> </div> </div> <div class="form-group"> <label>木皮1</label> <div class="input-group"> <select class="form-control" name="mupi1"> ${mupi1Options} </select> <span class="input-group-btn"> <button class="btn btn-default" id="createMupiBtn">新建</button> </span> </div> </div> <div class="form-group"> <label>木皮2</label> <div class="input-group"> <select class="form-control" name="mupi2"> ${mupi2Options} </select> <span class="input-group-btn"> <button class="btn btn-default" id="createMupiBtn2">新建</button> </span> </div> </div> `); // 添加新建材质按钮事件 $('#createCaizhiBtn').on('click', function() { showCreateEntityModal('创建新材质', ENTITY_CAIZHI, null, { name: '' }); }); // 添加新建木皮按钮事件 $('#createMupiBtn, #createMupiBtn2').on('click', function() { showCreateEntityModal('创建新木皮', ENTITY_MUPI, null, { name: '', you: false }); }); break; case ENTITY_CAIZHI: // 新材质 $formFields.append(` <div class="form-group"> <label>材质名称</label> <input type="text" class="form-control" name="name" value="${initialData.name || ''}" required> </div> `); break; case ENTITY_MUPI: // 新木皮 $formFields.append(` <div class="form-group"> <label>木皮名称</label> <input type="text" class="form-control" name="name" value="${initialData.name || ''}" required> </div> <div class="form-group"> <label> <input type="checkbox" name="you" ${initialData.you ? 'checked' : ''}> 是否有油漆 </label> </div> `); break; } // 显示模态框 $('#createEntityModal').modal('show'); // 存储当前操作的实体信息 $('#createEntityModal').data('entity', { type: entityType, id: entityId }); } // 保存实体(在添加产品/组件模态框中) async function saveEntity() { const $saveBtn = $('#saveEntityBtn'); const originalText = $saveBtn.text(); try { // 显示加载状态 $saveBtn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> 保存中...'); const entityInfo = $('#entityModal').data('entity'); const formData = getFormData('#entityForm'); let result; if (entityInfo.id) { // 更新实体 result = await dataManager.updateEntity(entityInfo.type, { id: entityInfo.id, ...formData }); } else { // 新增实体 result = await dataManager.addEntity(entityInfo.type, formData); } if (result.status === 200) { $('#entityModal').modal('hide'); // 根据操作类型刷新对应的下拉列表 switch (entityInfo.type) { case ENTITY_DINGDAN: await refreshDingdanList(); break; case 'dingdan_chanpin': if (formData.dingdan && formData.dingdan.id) { await refreshChanpinList(formData.dingdan.id); } break; case 'chanpin_zujian': if (formData.chanpin && formData.chanpin.id) { await refreshZujianList(formData.chanpin.id); } break; } } else { alert(`保存失败: ${result.text}`); } } catch (error) { console.error('保存实体时出错:', error); alert(`保存失败: ${error.message}`); } finally { // 恢复按钮状态 $saveBtn.prop('disabled', false).text(originalText); } } // 保存新实体(在创建实体模态框中) async function saveNewEntity() { const $saveBtn = $('#saveNewEntityBtn'); const originalText = $saveBtn.text(); try { // 显示加载状态 $saveBtn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> 保存中...'); const entityInfo = $('#createEntityModal').data('entity'); const formData = getFormData('#createEntityForm'); // 新增实体 const result = await dataManager.addEntity(entityInfo.type, formData); if (result.status === 200) { $('#createEntityModal').modal('hide'); // 刷新父模态框中的下拉框 refreshParentDropdown(entityInfo.type, result.data.id); } else { alert(`创建失败: ${result.text}`); } } catch (error) { console.error('创建实体时出错:', error); alert(`创建失败: ${error.message}`); } finally { // 恢复按钮状态 $saveBtn.prop('disabled', false).text(originalText); } } // 刷新父模态框中的下拉框 function refreshParentDropdown(entityType, newEntityId) { // 获取父模态框中的相关下拉框 const $parentModal = $('#entityModal'); if (!$parentModal.is(':visible')) return; const parentEntityType = $parentModal.data('entity').type; // 根据实体类型刷新对应的下拉框 if (parentEntityType === 'dingdan_chanpin' && entityType === ENTITY_CHANPIN) { // 刷新产品下拉框 const $select = $('#chanpinSelectModal'); $select.append(`<option value="${newEntityId}" selected>新建产品</option>`); } else if (parentEntityType === 'chanpin_zujian') { if (entityType === ENTITY_ZUJIAN) { // 刷新组件下拉框 const $select = $('#zujianSelectModal'); $select.append(`<option value="${newEntityId}" selected>新建组件</option>`); } else if (entityType === ENTITY_BANCAI) { // 刷新板材下拉框 const $select = $('#bancaiSelectModal'); $select.append(`<option value="${newEntityId}" selected>新建板材</option>`); } else if (entityType === ENTITY_CAIZHI) { // 刷新材质下拉框(在板材创建中) const $select = $parentModal.find('select[name="caizhi"]'); $select.append(`<option value="${newEntityId}" selected>新建材质</option>`); } else if (entityType === ENTITY_MUPI) { // 刷新木皮下拉框(在板材创建中) const $select = $parentModal.find('select[name="mupi1"], select[name="mupi2"]'); $select.append(`<option value="${newEntityId}" selected>新建木皮</option>`); } } } // 获取表单数据 function getFormData(selector) { const formData = {}; $(`${selector} :input`).each(function() { const $input = $(this); const name = $input.attr('name'); const type = $input.attr('type'); if (name) { if (type === 'checkbox') { formData[name] = $input.prop('checked'); } else if (type === 'radio') { if ($input.prop('checked')) { formData[name] = $input.val(); } } else { // 处理关联对象 if (name === 'chanpin' || name === 'zujian' || name === 'bancai' || name === 'dingdan' || name === 'caizhi' || name === 'mupi1' || name === 'mupi2') { formData[name] = { id: parseInt($input.val()) }; } else if (name === 'one_howmany' || name === 'houdu') { formData[name] = parseFloat($input.val()); } else if (name === 'shuliang') { formData[name] = parseInt($input.val()); } else { formData[name] = $input.val(); } } } }); return formData; } // 日期格式化辅助函数 function formatDate(dateString) { if (!dateString) return ''; const date = new Date(dateString); return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`; } }); 创建进货记录时,产品.id 搞错了
06-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值