ORDER BY TO_NUMBER(S.STOCK_CODE) 当S.STOCK_CODE不是数字字符串时会报错的处理

本文介绍如何使用SQL的CASE WHEN语句来动态设置数据的显示顺序,通过to_number函数将字符串转换为数值进行排序,从而实现高效的数据展示策略。
"select case when S.INSTRUMENT_TYPE = 'INDX' then '0' else S.CODE end as DISPLAY_ORDER, s.*," +
....
" ORDER BY to_number(DISPLAY_ORDER)",
if OBJECT_ID('tempdb..#temp') is not null drop table #temp; declare @domain smallint; select @domain=domain from domain where current_flag=1; DECLARE @stone_places INT; SELECT @stone_places = CAST(value AS INT) FROM ops_default WHERE comp_code = 56 AND code = 6; DECLARE @total INT; CREATE TABLE #temp ( domain smallint, comp_code smallint, order_no int, sub_order_no smallint, job_order_no smallint, split_order_no smallint, dec_stock_type INT, batch_no int, dec_date DATETIME, qty INT, total_weight DECIMAL(18, 4), export_amount MONEY, total_labour MONEY, total_labour_USD MONEY, total_labour_CNY MONEY, receive_district SMALLINT, receive_district_desc NVARCHAR(50), ver_no SMALLINT, adding_labour_cost MONEY, adding_labour_cost_USD MONEY, adding_labour_cost_CNY MONEY, export_amount_HKD MONEY, export_amount_CNY MONEY, total int, aes_export_amount MONEY, aes_mark_good_value MONEY, other_accessory_export_amount MONEY, export_amount_sum MONEY, gold_export_amount MONEY, sync_flag int, last_sync_date datetime, last_sync_by varchar(10) ); insert into #temp(domain,comp_code , order_no , sub_order_no , job_order_no , split_order_no , dec_date,receive_district,ver_no, adding_labour_cost,total_labour,qty,dec_stock_type,batch_no,receive_district_desc,sync_flag,last_sync_date,last_sync_by,total_weight) select @domain,comp_code , order_no , sub_order_no , job_order_no , split_order_no , dec_date,rd.receive_district,ver_no, adding_labour_cost,total_labour,qty,dec_stock_type,batch_no,rd.description as receive_district_desc,sync_flag,last_sync_date,last_sync_by, ROUND(gold_weight + accessories_weight + other_accessories_weight, 2) from customs_master cm left join receive_district rd on cm.receive_district = rd.receive_district WHERE cm.info_number = '' and synchro_mid_flag = 1 and comp_code = 56 ; UPDATE t SET adding_labour_cost_USD = ROUND(adding_labour_cost * rate_value_us, 2), total_labour_USD = ROUND(total_labour * rate_value_us, 2) from #temp t inner join rate r on r.date_from <= t.dec_date AND r.date_to >= t.dec_date; UPDATE t SET adding_labour_cost_CNY = ROUND(adding_labour_cost_USD * rate_value_cn, 2), total_labour_CNY = ROUND(total_labour_USD * rate_value_cn, 2) from #temp t inner join rate r on r.date_from <= t.dec_date AND r.date_to >= t.dec_date; UPDATE #temp SET gold_export_amount =gold_result.gold_export_amount FROM #temp AS temp INNER JOIN ( select [domain],[comp_code],[order_no],[sub_order_no],[job_order_no],[split_order_no],[batch_no], sum(gold_export_amount) as gold_export_amount from (SELECT #temp.[domain], #temp.[comp_code], #temp.[order_no], #temp.[sub_order_no], #temp.[job_order_no], #temp.[split_order_no], #temp.[batch_no], dec_gold_accessories.dec_gold_no , ROUND( ROUND( SUM( CASE WHEN ISNULL(dec_stock_type_ref.gold_loss_rate, 0) = 1 THEN 0 ELSE dec_gold_accessories.gold_weight / (1 - ISNULL(dec_stock_type_ref.gold_loss_rate, 0)) END ), 4 )* dec_gold_accessories.dec_unit_price,2) AS gold_export_amount FROM #temp INNER JOIN dbo.dec_stock_type ON dec_stock_type.dec_stock_type = #temp.dec_stock_type INNER JOIN dbo.dec_hk_stock_type ON dec_hk_stock_type.dec_hk_stock_type = dec_stock_type.dec_hk_stock_type INNER JOIN dbo.dec_gold_accessories ON dec_gold_accessories.domain = #temp.domain AND dec_gold_accessories.comp_code = #temp.comp_code AND dec_gold_accessories.order_no = #temp.order_no AND dec_gold_accessories.sub_order_no = #temp.sub_order_no AND dec_gold_accessories.job_order_no = #temp.job_order_no AND dec_gold_accessories.split_order_no = #temp.split_order_no AND dec_gold_accessories.batch_no = #temp.batch_no LEFT JOIN dbo.product_gold_type ON dec_gold_accessories.dec_gold_no = product_gold_type.gold_type AND gold_group2 <> '0' LEFT JOIN dbo.dec_stock_type_ref ON dec_stock_type_ref.dec_stock_type = #temp.dec_stock_type AND dec_stock_type_ref.dec_gold_no = dec_gold_accessories.dec_gold_no GROUP BY #temp.[domain], #temp.[comp_code], #temp.[order_no], #temp.[sub_order_no], #temp.[job_order_no], #temp.[split_order_no], #temp.[batch_no], dec_gold_accessories.dec_gold_no,dec_gold_accessories.dec_unit_price ) AS gold_detail_result group by [domain],[comp_code],[order_no],[sub_order_no],[job_order_no],[split_order_no],[batch_no] ) AS gold_result ON temp.[domain] = gold_result.[domain] AND temp.[comp_code] = gold_result.[comp_code] AND temp.[order_no] = gold_result.[order_no] AND temp.[sub_order_no] = gold_result.[sub_order_no] AND temp.[job_order_no] = gold_result.[job_order_no] AND temp.[split_order_no] = gold_result.[split_order_no] AND temp.[batch_no] = gold_result.[batch_no]; IF OBJECT_ID('tempdb..#temp_accessories') IS NOT NULL DROP TABLE #temp_accessories; SELECT a.*, CAST(0 AS SMALLINT) AS dec_item_type, itm.item_type, single_wgt = ROUND( a.weight / (CASE (a.qty * a.packing_qty) WHEN 0 THEN 1 ELSE (a.qty * a.packing_qty) END ), @stone_places ) INTO #temp_accessories FROM #temp AS temp INNER JOIN dbo.accessories AS a ON temp.domain = a.domain AND temp.comp_code = a.comp_code AND temp.order_no = a.order_no AND temp.sub_order_no = a.sub_order_no AND temp.job_order_no = a.job_order_no AND temp.split_order_no = a.split_order_no AND a.cancel_flag = 0 LEFT JOIN item_code_master itm ON a.item_code = itm.item_code; UPDATE #temp_accessories SET dec_item_type = ditr.dec_item_type FROM #temp_accessories aes INNER JOIN dec_item_type_ref ditr ON aes.item_code = ditr.item_code WHERE aes.item_type <> 'A'; UPDATE #temp_accessories SET dec_item_type = ditr.dec_item_type FROM #temp_accessories aes INNER JOIN dec_item_type_ref ditr ON aes.item_code = ditr.item_code AND single_wgt <= ditr.max_wgt AND single_wgt >= ditr.min_wgt WHERE aes.item_type = 'A'; UPDATE #temp SET aes_mark_good_value = aes_result.aes_mark_good_value, aes_export_amount = round(aes_result.aes_export_amount,2) FROM #temp AS temp INNER JOIN (select [domain],[comp_code],[order_no],[sub_order_no],[job_order_no],[split_order_no],[batch_no], sum(aes_export_amount) as aes_export_amount,SUM(cost) AS aes_mark_good_value from (SELECT #temp.[domain], #temp.[comp_code], #temp.[order_no], #temp.[sub_order_no], #temp.[job_order_no], #temp.[split_order_no], #temp.[batch_no], dec_item_type_ref.dec_item_type, ROUND(ROUND(SUM(a.weight * convert_weight_times),4) * dec_item_type.dec_unit_price,2) AS aes_export_amount, SUM(cost) AS cost FROM #temp INNER JOIN dbo.dec_stock_type ON dec_stock_type.dec_stock_type = #temp.dec_stock_type INNER JOIN dbo.dec_hk_stock_type ON dec_hk_stock_type.dec_hk_stock_type = dec_stock_type.dec_hk_stock_type INNER JOIN #temp_accessories AS a ON #temp.domain = a.domain AND #temp.order_no = a.order_no AND #temp.sub_order_no = a.sub_order_no AND #temp.job_order_no = a.job_order_no AND #temp.split_order_no = a.split_order_no AND a.cancel_flag = 0 LEFT JOIN dbo.item_code_master AS icm ON icm.item_code = a.item_code LEFT JOIN dbo.dec_item_type_ref ON dec_item_type_ref.item_code = a.item_code and ( round(a.weight/(case (a.qty*a.packing_qty) when 0 then 1 else (a.qty*a.packing_qty) end ), icm.decimal_place) <= case when icm.item_type='A' then dec_item_type_ref.max_wgt end or dec_item_type_ref.max_wgt = case when icm.item_type <> 'A' then dec_item_type_ref.max_wgt end ) and ( round(a.weight/(case (a.qty*a.packing_qty) when 0 then 1 else (a.qty*a.packing_qty) end ), icm.decimal_place) >= case when icm.item_type='A' then dec_item_type_ref.min_wgt end or dec_item_type_ref.min_wgt = case when icm.item_type <> 'A' then dec_item_type_ref.min_wgt end ) LEFT JOIN dbo.dec_item_type ON dec_item_type.dec_item_type = dec_item_type_ref.dec_item_type GROUP BY #temp.[domain], #temp.[comp_code], #temp.[order_no], #temp.[sub_order_no], #temp.[job_order_no], #temp.[split_order_no], #temp.[batch_no], dec_item_type.dec_unit_price,dec_item_type_ref.dec_item_type )AS aes_Detail_Result group by [domain],[comp_code],[order_no],[sub_order_no],[job_order_no],[split_order_no],[batch_no] ) AS aes_result ON temp.[domain] = aes_result.[domain] AND temp.[comp_code] = aes_result.[comp_code] AND temp.[order_no] = aes_result.[order_no] AND temp.[sub_order_no] = aes_result.[sub_order_no] AND temp.[job_order_no] = aes_result.[job_order_no] AND temp.[split_order_no] = aes_result.[split_order_no] AND temp.[batch_no] = aes_result.[batch_no]; UPDATE #temp SET other_accessory_export_amount = other_accessory_result.other_accessory_export_amount FROM #temp AS temp INNER JOIN (select [domain],[comp_code],[order_no],[sub_order_no],[job_order_no],[split_order_no],[batch_no], sum(other_accessory_export_amount) as other_accessory_export_amount, sum(other_accessory_mark_good_value) as other_accessory_mark_good_value from ( SELECT #temp.[domain], #temp.[comp_code], #temp.[order_no], #temp.[sub_order_no], #temp.[job_order_no], #temp.[split_order_no], #temp.[batch_no], dec_other_accessory.other_type, ROUND(SUM(dec_other_accessory.weight * other_type.dec_unit_price), 2) AS other_accessory_export_amount, ROUND(SUM(dec_other_accessory.weight * other_type.dec_unit_price), 2) AS other_accessory_mark_good_value FROM #temp INNER JOIN dbo.dec_stock_type ON dec_stock_type.dec_stock_type = #temp.dec_stock_type INNER JOIN dbo.dec_hk_stock_type ON dec_hk_stock_type.dec_hk_stock_type = dec_stock_type.dec_hk_stock_type INNER JOIN dbo.dec_other_accessory ON dec_other_accessory.domain = #temp.domain AND dec_other_accessory.comp_code = #temp.comp_code AND dec_other_accessory.order_no = #temp.order_no AND dec_other_accessory.sub_order_no = #temp.sub_order_no AND dec_other_accessory.job_order_no = #temp.job_order_no AND dec_other_accessory.split_order_no = #temp.split_order_no AND dec_other_accessory.batch_no = #temp.batch_no LEFT JOIN dbo.other_type ON other_type.other_type = dec_other_accessory.other_type GROUP BY #temp.[domain], #temp.[comp_code], #temp.[order_no], #temp.[sub_order_no], #temp.[job_order_no], #temp.[split_order_no], #temp.[batch_no], dec_other_accessory.other_type )AS other_accessory_detail_result group by [domain],[comp_code],[order_no],[sub_order_no],[job_order_no],[split_order_no],[batch_no] ) AS other_accessory_result ON temp.[domain] = other_accessory_result.[domain] AND temp.[comp_code] = other_accessory_result.[comp_code] AND temp.[order_no] = other_accessory_result.[order_no] AND temp.[sub_order_no] = other_accessory_result.[sub_order_no] AND temp.[job_order_no] = other_accessory_result.[job_order_no] AND temp.[split_order_no] = other_accessory_result.[split_order_no] AND temp.[batch_no] = other_accessory_result.[batch_no]; UPDATE #temp SET export_amount_sum = t.export_amount_sum from #temp inner join ( select (SUM(total_labour_USD) + SUM(adding_labour_cost_USD) + SUM(gold_export_amount) + SUM(aes_export_amount) + SUM(other_accessory_export_amount)) as export_amount_sum, comp_code,order_no,sub_order_no,job_order_no,split_order_no,batch_no from #temp group by comp_code,order_no,sub_order_no,job_order_no,split_order_no,batch_no ) as t on #temp.comp_code = t.comp_code and #temp.order_no = t.order_no and #temp.sub_order_no = t.sub_order_no and #temp.job_order_no = t.job_order_no and #temp.split_order_no = t.split_order_no and #temp.batch_no = t.batch_no; WITH GroupedData AS ( select dec_date , ver_no , receive_district , receive_district_desc , rtrim(last_sync_by) AS last_sync_by, last_sync_date, fr.flag_desc_cn as syncFlagDesc, sum(qty) OVER(PARTITION BY dec_date, ver_no,receive_district) as qty , sum(adding_labour_cost) OVER(PARTITION BY dec_date, ver_no,receive_district) as adding_labour_cost , sum(total_labour) OVER(PARTITION BY dec_date, ver_no,receive_district) as total_labour , sum(total_weight) OVER(PARTITION BY dec_date, ver_no,receive_district) as total_weight , sum(total_labour_USD) OVER(PARTITION BY dec_date, ver_no,receive_district) as total_labour_USD , sum(total_labour_CNY) OVER(PARTITION BY dec_date, ver_no,receive_district) as total_labour_CNY , sum(adding_labour_cost_USD) OVER(PARTITION BY dec_date, ver_no,receive_district) as adding_labour_cost_USD , sum(adding_labour_cost_CNY) OVER(PARTITION BY dec_date, ver_no,receive_district) as adding_labour_cost_CNY , sum(export_amount_sum) OVER(PARTITION BY dec_date, ver_no,receive_district) as export_amount_sum , COUNT(*) OVER(PARTITION BY dec_date, ver_no,receive_district) AS total, min(sync_flag) OVER(PARTITION BY dec_date, ver_no,receive_district) as sync_flag, ROW_NUMBER() OVER( PARTITION BY dec_date, ver_no,receive_district ORDER BY last_sync_date DESC ) AS time_rank from #temp t inner join flag_reference fr on fr.flag_id = t.sync_flag and fr.flag_group = 'sync_flag' ) select dec_date , ver_no , receive_district , receive_district_desc , last_sync_by, syncFlagDesc, qty , adding_labour_cost , total_labour , total_weight , total_labour_USD , total_labour_CNY , adding_labour_cost_USD , adding_labour_cost_CNY , export_amount_sum , total, sync_flag, last_sync_date from GroupedData where time_rank = 1 OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY ; if OBJECT_ID('tempdb..#temp') is not null drop table #temp;sqlserver 会报什么错
最新发布
08-10
// 首页逻辑文件 const app = getApp(); Page({ data: { // 统计数据 totalOrders: 0, totalProducts: 0, totalMaterials: 0, totalStock: 0, // 搜索条件 orderSearch: '', productSearch: '', materialSearch: '', woodSearch: '', thicknessSearch: '', minStock: '', maxStock: '', // 结果数据 loading: true, results: [], filteredResults: [], resultCount: 0, lastUpdate: '--:--:--', // 排序 sortField: null, sortDirection: 'asc', // 分页 currentPage: 1, pageSize: 10, totalPages: 1, // 板材详情 showMaterialDetail: false, materialDetail: null }, onLoad: function() { console.log('index页面加载'); // 获取全局数据管理器 if (app.globalData && app.globalData.dataManager) { this.dataManager = app.globalData.dataManager; // 注册数据更新回调 this.dataManager.registerCallback('all', () => { console.log('收到数据更新回调'); this.updatePageData(); }); // 初始化页面数据 this.updatePageData(); // 尝试重新初始化 if (app.initDataManager) { app.initDataManager(); } } }, onShow: function() { console.log('首页显示'); // 检查是否需要登录 if (app.globalData && app.globalData.needLogin) { console.log('检测到需要登录'); // 延迟500ms确保页面渲染完成 setTimeout(() => { app.checkWechatLogin(); }, 500); } }, // 更新页面数据 updatePageData: function() { if (!this.dataManager || !this.dataManager.data) return; this.setData({ loading: true }); // 更新统计数据 this.updateStats(); // 更新表格数据 this.updateTable(); // 更新最后更新时间 const now = new Date(); const lastUpdate = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`; this.setData({ lastUpdate }); }, // 更新统计数据 updateStats: function() { const data = this.dataManager.data; const totalOrders = data.dingdans?.length || 0; const totalProducts = data.chanpins?.length || 0; const totalMaterials = data.bancais?.length || 0; const totalStock = data.kucuns?.reduce((sum, kucun) => sum + kucun.shuliang, 0) || 0; this.setData({ totalOrders, totalProducts, totalMaterials, totalStock }); }, // 更新表格数据 updateTable: function() { console.log('开始更新表格数据'); const data = this.dataManager.data; let results = []; // 处理订单产品数据 if (data.dingdan_chanpins) { console.log('处理dingdan_chanpins数据,数量:', data.dingdan_chanpins.length); // 深度处理嵌套数据 data.dingdan_chanpins.forEach(dc => { const order = data.dingdans.find(d => d.id === dc.dingdan?.id); const product = data.chanpins.find(c => c.id === dc.chanpin?.id); if (order && product) { results.push({ orderNumber: order.number, productInfo: `${product.bianhao} (${dc.shuliang}件)`, productQuantity: dc.shuliang, // 添加更多必要字段... _rawData: dc // 保留原始数据用于调试 }); } }); data.dingdan_chanpins.forEach(dc => { if (!dc.dingdan || !dc.chanpin) return; if (dc.chanpin.chanpin_zujians) { dc.chanpin.chanpin_zujians.forEach(cz => { if (!cz.zujian || !cz.bancai) return; const bancai = cz.bancai; const materialInfo = this.getMaterialInfo(bancai); // 查找该板材的库存 const kucun = data.kucuns?.find(k => k.bancai?.id === bancai.id); const stockQuantity = kucun ? kucun.shuliang : 0; results.push({ id: `${dc.dingdan.id}-${dc.chanpin.id}-${cz.zujian.id}-${bancai.id}`, orderNumber: dc.dingdan.number, productInfo: dc.chanpin.bianhao, productQuantity: dc.shuliang, component: cz.zujian.name, material: materialInfo, materialPerComponent: cz.one_howmany, materialOrderQuantity: dc.shuliang / cz.one_howmany, stockQuantity: stockQuantity, raw: { orderNumber: dc.dingdan.number, productQuantity: dc.shuliang, materialPerComponent: cz.one_howmany, materialOrderQuantity: dc.shuliang / cz.one_howmany, stockQuantity: stockQuantity, thickness: bancai.houdu || 0 }, bancaiId: bancai.id }); }); } }); } // 处理订单板材数据 (Dingdan_bancai) if (data.dingdan_bancais) { data.dingdan_bancais.forEach(db => { if (!db.dingdan || !db.bancai) return; const bancai = db.bancai; const materialInfo = this.getMaterialInfo(bancai); // 查找该板材的库存 const kucun = data.kucuns?.find(k => k.bancai?.id === bancai.id); const stockQuantity = kucun ? kucun.shuliang : 0; // 确定产品信息 let productInfo = '独立订购'; if (db.chanpin) { productInfo = db.chanpin.bianhao; } // 确定组件信息 let component = '独立板材'; if (db.zujian) { component = db.zujian.name; } else if (db.chanpin) { component = '产品板材'; } results.push({ id: `${db.dingdan.id}-direct-${bancai.id}`, orderNumber: db.dingdan.number, productInfo: productInfo, productQuantity: db.shuliang, // 直接订购的板材数量 component: component, material: materialInfo, materialPerComponent: 1, // 直接订购时,每件用量为1 materialOrderQuantity: db.shuliang, stockQuantity: stockQuantity, raw: { orderNumber: db.dingdan.number, productQuantity: db.shuliang, materialPerComponent: 1, materialOrderQuantity: db.shuliang, stockQuantity: stockQuantity, thickness: bancai.houdu || 0 }, bancaiId: bancai.id }); }); } // 应用排序 if (this.data.sortField !== null) { results = this.sortResults(results, this.data.sortField, this.data.sortDirection); } // 更新页面数据 this.setData({ results: results, filteredResults: results, resultCount: results.length, totalPages: Math.ceil(results.length / this.data.pageSize), currentPage: 1, loading: false }, () => { // 更新当前页数据 this.updateCurrentPageData(); }); // 应用筛选 this.applyFilters(); }, // 获取板材详细信息函数 getMaterialInfo: function(bancai) { if (!bancai) return '未知板材'; // 获取材质名称 const caizhiName = bancai.caizhi?.name || '未知材质'; // 获取木皮信息 const formatMupi = (mupi) => { if (!mupi) return null; return `${mupi.name}${mupi.you ? '()' : ''}`; }; const mupi1Str = formatMupi(bancai.mupi1) || '无'; const mupi2Str = formatMupi(bancai.mupi2) || '无'; const mupiInfo = mupi1Str + (mupi2Str !== '无' ? `/${mupi2Str}` : ''); // 厚度转换为字符串 const thickness = bancai.houdu ? `${bancai.houdu.toFixed(1)}mm` : '未知厚度'; return `${caizhiName}-${mupiInfo} (${thickness})`; }, // 搜索输入处理函数 onOrderSearchInput: function(e) { this.setData({ orderSearch: e.detail.value }); this.applyFilters(); }, onProductSearchInput: function(e) { this.setData({ productSearch: e.detail.value }); this.applyFilters(); }, onMaterialSearchInput: function(e) { this.setData({ materialSearch: e.detail.value }); this.applyFilters(); }, onWoodSearchInput: function(e) { this.setData({ woodSearch: e.detail.value }); // 支持中文和数字搜索 const searchTerm = e.detail.value.toLowerCase(); const searchKeywords = { '有油': '有油', '无油': '无油', 'you': '有油', 'wu': '无油', '1': '有油', '0': '无油', '()': '()' }; this.setData({ woodSearch: searchKeywords[searchTerm] || searchTerm }); this.applyFilters(); }, onThicknessSearchInput: function(e) { this.setData({ thicknessSearch: e.detail.value }); this.applyFilters(); }, onMinStockInput: function(e) { this.setData({ minStock: e.detail.value }); }, onMaxStockInput: function(e) { this.setData({ maxStock: e.detail.value }); }, // 库存范围搜索 onStockSearch: function() { this.applyFilters(); }, // 重置筛选 resetFilters: function() { this.setData({ orderSearch: '', productSearch: '', materialSearch: '', woodSearch: '', thicknessSearch: '', minStock: '', maxStock: '', sortField: null, sortDirection: 'asc', currentPage: 1 }); this.updateTable(); }, // 应用筛选条件 applyFilters: function() { let filtered = [...this.data.results]; // 应用订单号筛选 if (this.data.orderSearch) { const search = this.data.orderSearch.toLowerCase(); filtered = filtered.filter(item => item.orderNumber.toLowerCase().includes(search) ); } // 应用产品筛选 if (this.data.productSearch) { const search = this.data.productSearch.toLowerCase(); filtered = filtered.filter(item => item.productInfo.toLowerCase().includes(search) ); } // 应用板材筛选 if (this.data.materialSearch) { const search = this.data.materialSearch.toLowerCase(); filtered = filtered.filter(item => item.material.toLowerCase().includes(search) ); } // 应用木皮筛选 if (this.data.woodSearch) { const search = this.data.woodSearch.toLowerCase(); filtered = filtered.filter(item => item.material.toLowerCase().includes(search) ); } // 应用厚度筛选 if (this.data.thicknessSearch) { const thickness = parseFloat(this.data.thicknessSearch); if (!isNaN(thickness)) { filtered = filtered.filter(item => { // 提取厚度数字部分进行匹配 const thicknessMatch = item.material.match(/(\d+\.?\d*)/); if (thicknessMatch) { const thicknessValue = parseFloat(thicknessMatch[1]); // 允许小数点误差 return Math.abs(thicknessValue - thickness) < 0.5; } return false; }); } } // 应用库存范围筛选 if (this.data.minStock !== '' || this.data.maxStock !== '') { const min = this.data.minStock !== '' ? parseInt(this.data.minStock) : Number.MIN_SAFE_INTEGER; const max = this.data.maxStock !== '' ? parseInt(this.data.maxStock) : Number.MAX_SAFE_INTEGER; filtered = filtered.filter(item => item.stockQuantity >= min && item.stockQuantity <= max ); } // 更新筛选结果 this.setData({ filteredResults: filtered, resultCount: filtered.length, totalPages: Math.ceil(filtered.length / this.data.pageSize), currentPage: 1 }); }, // 排序处理 sortBy: function(e) { const field = e.currentTarget.dataset.field; // 如果点击的是当前排序字段,则切换排序方向 if (field === this.data.sortField) { this.setData({ sortDirection: this.data.sortDirection === 'asc' ? 'desc' : 'asc' }); } else { // 否则,设置新的排序字段,默认升序 this.setData({ sortField: field, sortDirection: 'asc' }); } // 应用排序 const sorted = this.sortResults(this.data.filteredResults, this.data.sortField, this.data.sortDirection); this.setData({ filteredResults: sorted }, () => { // 更新当前页数据 this.updateCurrentPageData(); }); }, // 排序结果 sortResults: function(results, field, direction) { if (!field) return results; return [...results].sort((a, b) => { let valueA, valueB; // 根据排序字段获取值 switch (field) { case 'dingdan.number': valueA = a.orderNumber; valueB = b.orderNumber; break; case 'chanpin.bianhao': valueA = a.productInfo; valueB = b.productInfo; break; case 'dingdan_chanpin.shuliang': valueA = a.productQuantity; valueB = b.productQuantity; break; case 'zujian.name': valueA = a.component; valueB = b.component; break; case 'bancai.id': // 特殊处理:按厚度排序 return this.sortByThickness(a, b, direction); case 'chanpin_zujian.one_howmany': valueA = a.materialPerComponent; valueB = b.materialPerComponent; break; case 'orderUsage': valueA = a.materialOrderQuantity; valueB = b.materialOrderQuantity; break; case 'kucun.shuliang': valueA = a.stockQuantity; valueB = b.stockQuantity; break; default: valueA = a.orderNumber; valueB = b.orderNumber; } // 数值比较 if (['productQuantity', 'materialPerComponent', 'materialOrderQuantity', 'stockQuantity'].includes(field)) { return this.sortNumeric(valueA, valueB, direction); } // 字符串比较 return this.sortString(valueA, valueB, direction); }); }, // 按厚度排序(特殊处理) sortByThickness: function(a, b, direction) { return this.sortNumeric(a.raw.thickness, b.raw.thickness, direction); }, // 数值排序辅助函数 sortNumeric: function(aVal, bVal, direction) { const aNum = parseFloat(aVal) || 0; const bNum = parseFloat(bVal) || 0; return direction === 'asc' ? aNum - bNum : bNum - aNum; }, // 字符串排序辅助函数 sortString: function(aVal, bVal, direction) { const aStr = String(aVal).toLowerCase(); const bStr = String(bVal).toLowerCase(); if (aStr < bStr) return direction === 'asc' ? -1 : 1; if (aStr > bStr) return direction === 'asc' ? 1 : -1; return 0; }, // 分页处理 prevPage: function() { if (this.data.currentPage > 1) { this.setData({ currentPage: this.data.currentPage - 1 }, () => { this.updateCurrentPageData(); }); } }, nextPage: function() { if (this.data.currentPage < this.data.totalPages) { this.setData({ currentPage: this.data.currentPage + 1 }, () => { this.updateCurrentPageData(); }); } }, // 更新当前页数据 updateCurrentPageData: function() { const startIndex = (this.data.currentPage - 1) * this.data.pageSize; const endIndex = startIndex + this.data.pageSize; const currentPageData = this.data.filteredResults.slice(startIndex, endIndex).map((item, index) => { // 为每个项目添加一个唯一的ID,使用索引确保唯一性 return { ...item, uniqueId: `item-${startIndex + index}` }; }); this.setData({ currentPageData }); }, // 显示板材详情 showMaterialDetail: function(e) { const materialId = e.currentTarget.dataset.id; // 查找板材详情 const bancai = this.dataManager.data.bancais.find(b => b.id === materialId); if (!bancai) { wx.showToast({ title: '未找到板材信息', icon: 'none' }); return; } // 获取库存信息 const kucun = this.dataManager.data.kucuns ? this.dataManager.data.kucuns.find(k => k.bancai?.id === materialId) : null; // 格式化木皮信息 const formatMupiDetail = (mupi) => { if (!mupi) return '无'; return `${mupi.name}${mupi.you ? '()' : ''}`; }; // 获取相关订单 const relatedOrders = this.getRelatedOrders(bancai); // 设置详情数据 this.setData({ materialDetail: { id: bancai.id, material: bancai.caizhi?.name || '未知', thickness: bancai.houdu ? bancai.houdu.toFixed(1) + 'mm' : '未知', stock: kucun ? kucun.shuliang : 0, mupi1: formatMupiDetail(bancai.mupi1), mupi2: formatMupiDetail(bancai.mupi2), relatedOrders: relatedOrders.map(order => ({ number: order.number, xiadan: order.xiadan ? this.formatDate(order.xiadan) : '-', jiaohuo: order.jiaohuo ? this.formatDate(order.jiaohuo) : '-' })) }, showMaterialDetail: true }); }, // 关闭板材详情 closeMaterialDetail: function() { this.setData({ showMaterialDetail: false }); }, // 获取板材相关订单 getRelatedOrders: function(bancai) { const data = this.dataManager.data; const orderMap = new Map(); // 使用Map进行订单去重 // 查找直接订单组件关联 const dingdan_bancais = data.dingdan_bancais || []; dingdan_bancais.forEach(db => { if (db.bancai?.id === bancai.id && db.dingdan) { orderMap.set(db.dingdan.id, db.dingdan); } }); // 查找产品组件关联 const chanpin_zujians = data.chanpin_zujians || []; chanpin_zujians.forEach(cz => { if (cz.bancai?.id === bancai.id) { const dingdan_chanpins = data.dingdan_chanpins || []; dingdan_chanpins.forEach(dc => { if (dc.chanpin?.id === cz.chanpin?.id && dc.dingdan) { orderMap.set(dc.dingdan.id, dc.dingdan); } }); } }); // 转换为数组并排序(按下单日期降序) return Array.from(orderMap.values()).sort((a, b) => { const dateA = a.xiadan ? new Date(a.xiadan) : new Date(0); const dateB = b.xiadan ? new Date(b.xiadan) : new Date(0); return dateB - dateA; // 最近的订单在前 }); }, // 格式化日期 formatDate: function(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')}`; } });@startuml !theme plain hide circle skinparam linetype ortho entity Bancai { + id: Integer <<PK>> -- houdu: Double -- + caizhi: Caizhi [1] + mupi1: Mupi [1] + mupi2: Mupi [1] + kucun: Kucun [1] } entity Caizhi { + id: Integer <<PK>> -- name: String -- *- bancai: Bancai [*] } entity Mupi { + id: Integer <<PK>> -- name: String you: Boolean -- *- bancai_mupi1: Bancai [*] *- bancai_mupi2: Bancai [*] } entity Kucun { + id: Integer <<PK>> -- shuliang: Integer -- + bancai: Bancai [1] } entity Chanpin { + id: Integer <<PK>> -- bianhao: String -- *- chanpin_zujian: Chanpin_zujian [*] *- dingdan_chanpin: Dingdan_chanpin [*] } entity Zujian { + id: Integer <<PK>> -- name: String -- *- chanpin_zujian: Chanpin_zujian [*] } entity Chanpin_zujian { + id: Integer <<PK>> -- one_howmany: Double zujianshu: Double -- + chanpin: Chanpin [1] + zujian: Zujian [1] + bancai: Bancai [1] } entity Dingdan { + id: Integer <<PK>> -- number: String xiadan: Date jiaohuo: Date -- *- dingdan_chanpin: Dingdan_chanpin [*] *- dingdan_bancai: Dingdan_bancai [*] } entity Dingdan_chanpin { + id: Integer <<PK>> -- shuliang: Integer -- + dingdan: Dingdan [1] + chanpin: Chanpin [1] } entity Dingdan_bancai { + id: Integer <<PK>> -- shuliang: Integer -- + dingdan: Dingdan [1] + chanpin: Chanpin [1] + zujian: Zujian [1] + bancai: Bancai [1] *- jinhuo: Jinhuo [*] } entity Jinhuo { + id: Integer <<PK>> -- shuliang: Integer date: Date text: String theTypeOfOperation: Integer -- + dingdan_bancai: Dingdan_bancai [1] + user: User [1] } entity User { + id: Integer <<PK>> -- name: String andy: String pass: String role: Integer incumbency: Integer -- *- jinhuo: Jinhuo [*] } ' 鏍稿績鍏崇郴瀹氫箟 Bancai }|--|| Kucun Bancai }o--o| Caizhi Bancai }o--o| Mupi : mupi1 Bancai }o--o| Mupi : mupi2 Chanpin_zujian }o--|| Chanpin Chanpin_zujian }o--|| Zujian Chanpin_zujian }o--|| Bancai Dingdan_chanpin }o--|| Dingdan Dingdan_chanpin }o--|| Chanpin Dingdan_bancai }o--|| Dingdan Dingdan_bancai }o--|| Chanpin Dingdan_bancai }o--|| Zujian Dingdan_bancai }o--|| Bancai Jinhuo }o--|| Dingdan_bancai Jinhuo }o--|| User ' 闆嗗悎鍏崇郴 Caizhi "1" *-- "many" Bancai : bancai Mupi "1" *-- "many" Bancai : bancai_mupi1 Mupi "1" *-- "many" Bancai : bancai_mupi2 Chanpin "1" *-- "many" Chanpin_zujian : chanpin_zujian Chanpin "1" *-- "many" Dingdan_chanpin : dingdan_chanpin Dingdan "1" *-- "many" Dingdan_chanpin : dingdan_chanpin Dingdan "1" *-- "many" Dingdan_bancai : dingdan_bancai Dingdan_bancai "1" *-- "many" Jinhuo : jinhuo User "1" *-- "many" Jinhuo : jinhuo Zujian "1" *-- "many" Chanpin_zujian : chanping_zujian @enduml // 解析数据引用关系的辅助函数 /** * 解析数据中的引用关系 * 该函数用于处理嵌套的数据结构,将数据中的引用关系解析为实际的对象引用。 * 它会遍历数据中的所有实体,查找属性名中包含的数字(如"item1"), * 并尝试将这些属性值替换为对应类型数据中的实际对象引用。 * @param {Object} data - 包含嵌套引用的原始数据对象 * @returns {Object} 处理后的数据对象,其中引用已被解析为实际对象 */ function resolveDataReferences(data) { const keys = Object.keys(data); for (const key of keys) { const entities = data[key]; for (const entity of entities) { for (const attribute in entity) { if (entity.hasOwnProperty(attribute)) { // 修复:统一使用复数形式查找引用类型 let refType = attribute.replace(/\d/g, ''); // 尝试直接查找复数形式 if (!data[refType] && data[`${refType}s`]) { refType = `${refType}s`; } if (Array.isArray(entity[attribute])) { entity[attribute] = entity[attribute].map(item => data[refType]?.find(updateItem => updateItem.id === item.id) || item ); } else if (typeof entity[attribute] === "object" && entity[attribute] !== null) { entity[attribute] = data[refType]?.find(updateItem => updateItem.id === entity[attribute].id) || entity[attribute]; } } } } } return data; } // 解析单个实体的数据引用 /** * 解析数据引用关系 * 该函数用于处理实体对象与数据源之间的引用关系,自动匹配并更新实体中的引用字段。 * @param {Object} entity - 需要处理的实体对象 * @param {Object} data - 包含引用数据的数据源对象 * @returns {Object} 处理后的实体对象 * 功能说明: * 遍历实体对象的每个属性 * 如果属性值是数组,则尝试在数据源中查找匹配项更新数组元素 * 如果属性值是对象,则尝试在数据源中查找匹配项更新该对象 * 自动处理单复数形式的数据源键名 */ function resolveDataReference(entity, data) { for (const attribute in entity) { if (entity.hasOwnProperty(attribute)) { // 修复:统一使用复数形式查找引用类型 let refType = attribute.replace(/\d/g, ''); // 尝试直接查找复数形式 if (!data[refType] && data[`${refType}s`]) { refType = `${refType}s`; } if (Array.isArray(entity[attribute])) { entity[attribute] = entity[attribute].map(item => data[refType]?.find(updateItem => updateItem.id === item.id) || item ); } else if (typeof entity[attribute] === "object" && entity[attribute] !== null) { entity[attribute] = data[refType]?.find(updateItem => updateItem.id === entity[attribute].id) || entity[attribute]; } } } return entity; } /** * 懒加载处理器 * 负责管理实体类之间的关联依赖,实现按需加载 */ class LazyLoader { constructor(dataManager) { this.dataManager = dataManager; this.cache = new Map(); this.entityTypeMap = { bancai: 'bancais', dingdan: 'dingdans', mupi: 'mupis', chanpin: 'chanpins', kucun: 'kucuns', dingdan_bancai: 'dingdan_bancais', chanpin_zujian: 'chanpin_zujians', zujian: 'zujians', caizhi: 'caizhis', dingdan_chanpin: 'dingdan_chanpins', user: 'users', jinhuo: 'jinhuos' }; } /** * 创建实体代理 * @param {Object} entity 实体对象 * @param {string} entityType 实体类型 * @returns {Proxy} 返回代理后的实体 */ createProxy(entity, entityType) { const handler = { get: (target, prop) => { // 如果是普通属性,直接返回 if (typeof target[prop] !== 'object' || target[prop] === null) { return target[prop]; } // 检查是否是引用属性 const refType = this.getReferenceType(prop); if (refType) { // 如果是数组引用 if (Array.isArray(target[prop])) { return this.loadReferences(target[prop], refType); } // 如果是对象引用 else { return this.loadReference(target[prop], refType); } } return target[prop]; } }; return new Proxy(entity, handler); } /** * 获取引用类型 * @param {string} prop 属性名 * @returns {string|null} 引用类型(复数形式) */ getReferenceType(prop) { // 去除数字后缀(如 "mupi1" -> "mupi") const baseProp = prop.replace(/\d/g, ''); // 尝试直接匹配实体类型 if (this.entityTypeMap[baseProp]) { return this.entityTypeMap[baseProp]; } // 尝试添加 's' 后缀匹配 const pluralProp = `${baseProp}s`; if (this.dataManager._rawData[pluralProp]) { return pluralProp; } return null; } /** * 加载单个关联引用 * @param {Object} ref 引用对象(包含id) * @param {string} refType 引用类型(复数形式) * @returns {Promise<Object>} 解析后的实体对象 */ async loadReference(ref, refType) { if (!ref || !ref.id) return null; const cacheKey = `${refType}_${ref.id}`; // 检查缓存 if (this.cache.has(cacheKey)) { return this.cache.get(cacheKey); } // 尝试从本地数据查找 const entities = this.dataManager._rawData[refType] || []; let entity = entities.find(e => e.id === ref.id); // 如果本地找不到,尝试同步数据 if (!entity) { await this.dataManager.syncData(); entity = (this.dataManager._rawData[refType] || []).find(e => e.id === ref.id); } if (entity) { // 递归解析嵌套引用 const resolvedEntity = resolveDataReference({...entity}, this.dataManager._rawData); // 创建代理并缓存 const proxy = this.createProxy(resolvedEntity, refType); this.cache.set(cacheKey, proxy); return proxy; } return ref; // 返回原始引用 } /** * 加载多个关联引用 * @param {Array} refs 引用对象数组 * @param {string} refType 引用类型(复数形式) * @returns {Promise<Array>} 解析后的实体对象数组 */ async loadReferences(refs, refType) { if (!Array.isArray(refs)) return []; return Promise.all( refs.map(ref => this.loadReference(ref, refType)) ); } /** * 清除缓存 */ clearCache() { this.cache.clear(); } } class MiniProgramDataManager { constructor(baseUrl) { this.baseUrl = baseUrl; this.debug = true; // 调试模式开关 this.requestCount = 0; // 请求计数器 // 数据结构定义 this._rawData = { bancais: [], dingdans: [], mupis: [], chanpins: [], kucuns: [], dingdan_bancais: [], chanpin_zujians: [], zujians: [], caizhis: [], dingdan_chanpins: [], users: [], jinhuos: [], _lastModified: null, _lastSync: null }; // 初始化网络状态 this.networkAvailable = false; this.checkNetwork().then(type => { this.networkAvailable = type !== 'none'; }); this.lazyLoader = new LazyLoader(this); this.loadDataFromStorage(); 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(); this.entiyeText = { bancai: '板材已存在', dingdan: '订单已存在', mupi: '木皮已存在', chanpin: '产品已存在', kucun: '已有库存记录', chanpin_zujian: '产品已有该组件', dingdan_bancai: '', zujian: '组件已定义过了', caizhi: '材质已定义过了', dingdan_chanpin: '订单下已有该产品', user: '' }; this.syncInterval = 5 * 60 * 1000; // 5分钟 this.storageKey = 'miniProgramData'; // 本地存储的键名 } get data() { // 创建数据代理 const handler = { get: (target, prop) => { // 处理特殊属性 if (prop.startsWith('_')) { return target[prop]; } // 处理数组类型的实体集合 if (Array.isArray(target[prop])) { return target[prop].map(item => this.lazyLoader.createProxy(item, prop.replace(/s$/, '')) ); } // 默认返回原始值 return target[prop]; }, // 保持其他操作不变 set: (target, prop, value) => { target[prop] = value; return true; } }; return new Proxy(this._rawData, handler); } // 添加显式初始化方法 async initialize() { // 启动自动同步 this.startAutoSync(); // 执行首次数据同步 await this.syncData(); } /** * 启动自动同步定时器 * 每隔syncInterval毫秒检查并执行数据同步 * 如果已有同步任务进行中则跳过 */ startAutoSync() { if (this.autoSyncTimer) clearInterval(this.autoSyncTimer); this.autoSyncTimer = setInterval(() => { if (!this.isSyncing) this.syncData(); }, this.syncInterval); } /** * 停止自动同步 */ stopAutoSync() { clearInterval(this.autoSyncTimer); } /** * 检查网络状态 */ checkNetwork() { return new Promise((resolve) => { wx.getNetworkType({ success: (res) => { resolve(res.networkType); }, fail: () => { resolve('unknown'); } }); }); } /** * 获取所有数据(全量或增量) * @async * @param {string} [since] - 增量获取的时间戳,不传则全量获取 * @returns {Promise} 是否获取成功 * @description * 根据since参数决定全量或增量获取数据 * 增量获取时会合并新数据到现有数据 * 全量获取会直接替换现有数据 * 成功后会更新同步时间并保存到本地存储 * 失败时会触发错误回调,若无历史数据则抛出错误 */ async fetchAll(since) { try { console.log(since ? `增量获取数据(自${since})...` : '全量获取数据...'); const params = since ? { since } : {}; const result = await this.request('/app/all', 'GET', params); const resolvedData = result; // 更新networkData Object.keys(this._rawData).forEach(key => { if (key.startsWith('_')) return; if (resolvedData[key]) { if (since) { // 增量更新: 合并新数据到现有数据 resolvedData[key].forEach(newItem => { const index = this._rawData[key].findIndex(item => item.id === newItem.id); if (index >= 0) { this._rawData[key][index] = newItem; } else { this._rawData[key].push(newItem); } }); } else { // 全量更新: 直接替换 this._rawData[key] = resolvedData[key]; } } }); // 更新同步时间 this.lastSync = new Date(); this._rawData._lastSync = this.lastSync.toISOString(); // 保存到本地存储 this.saveDataToStorage(); this.triggerCallbacks('refresh', 'all', this.data); return true; } catch (error) { console.error('Fetch error:', error); this.triggerCallbacks('fetch_error', 'all', { error }); // 失败时尝试使用本地数据 if (!this.lastSync) { throw new Error('初始化数据获取失败'); } return false; } } /** * 微信小程序API请求封装 */ request(url, method = 'GET', data = null, retryCount = 3) { return new Promise((resolve, reject) => { const makeRequest = (attempt) => { const fullUrl = `${this.baseUrl}${url}`; if (this.debug) { console.log(`[请求] ${method} ${fullUrl}`, { attempt, data, timestamp: new Date().toISOString() }); } wx.request({ url: fullUrl, method, data, header: { 'Content-Type': 'application/json' }, success: (res) => { if (this.debug) { console.log(`[响应] ${fullUrl}`, { status: res.statusCode, data: res.data, headers: res.header }); } // 修复:更灵活的响应格式处理 if (!res.data) { const err = new Error('空响应数据'); if (attempt < retryCount) { this.retryRequest(makeRequest, attempt, retryCount, err); } else { reject(err); } return; } // 修复:支持多种成功状态码和响应格式 const isSuccess = res.statusCode >= 200 && res.statusCode < 300; const hasData = res.data && (res.data.data !== undefined || typeof res.data === 'object'); if (isSuccess && hasData) { resolve(res.data.data || res.data); } else { const errMsg = res.data.message || res.data.text || 'API错误'; const err = new Error(errMsg); if (attempt < retryCount) { this.retryRequest(makeRequest, attempt, retryCount, err); } else { reject(err); } } }, fail: (err) => { if (this.debug) { console.error(`[失败] ${fullUrl}`, err); } const error = new Error(`网络请求失败: ${err.errMsg || '未知错误'}`); if (attempt < retryCount) { this.retryRequest(makeRequest, attempt, retryCount, error); } else { reject(error); } } }); }; makeRequest(1); }); } retryRequest(makeRequest, attempt, retryCount, error) { const delay = 1000 * attempt; console.warn(`请求失败 (${attempt}/${retryCount}), ${delay}ms后重试:`, error.message); setTimeout(() => makeRequest(attempt + 1), delay); } /** * 注册回调函数 */ registerCallback(entity, callback) { if (!this.callbacks[entity]) { this.callbacks[entity] = []; } this.callbacks[entity].push(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); } } /** * 触发回调函数 */ 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)); } } /** * 检查重复实体 */ checkDuplicate(entity, data) { // 修复:确保引用已解析 const resolvedData = resolveDataReference(data, this.data); switch (entity) { case 'bancai': return this.data.bancais.some(b => b.houdu === resolvedData.houdu && b.caizhi?.id === resolvedData.caizhi?.id && b.mupi1?.id === resolvedData.mupi1?.id && b.mupi2?.id === resolvedData.mupi2?.id ); case 'caizhi': return this.data.caizhis.some(c => c.name === resolvedData.name); case 'mupi': return this.data.mupis.some(m => m.name === resolvedData.name && m.you === resolvedData.you ); case 'chanpin': return this.data.chanpins.some(c => c.bianhao === resolvedData.bianhao); case 'zujian': return this.data.zujians.some(z => z.name === resolvedData.name); case 'dingdan': return this.data.dingdans.some(d => d.number === resolvedData.number); case 'chanpin_zujian': return this.data.chanpin_zujians.some(cz => cz.chanpin?.id === resolvedData.chanpin?.id && cz.zujian?.id === resolvedData.zujian?.id ); case 'dingdan_chanpin': return this.data.dingdan_chanpins.some(dc => dc.dingdan?.id === resolvedData.dingdan?.id && dc.chanpin?.id === resolvedData.chanpin?.id ); case 'dingdan_bancai': return this.data.dingdan_bancais.some(db => db.dingdan?.id === resolvedData.dingdan?.id && db.chanpin?.id === resolvedData.chanpin?.id && db.zujian?.id === resolvedData.zujian?.id && db.bancai?.id === resolvedData.bancai?.id ); case 'user': return this.data.users.some(u => u.name === resolvedData.name); default: return false; } } /** * CRUD操作通用方法 */ async crudOperation(operation, entity, data) { try { // 使用微信请求API替代fetch const result = await this.request(`/app/${operation}/${entity}`, 'POST', data); this.updateLocalData(operation, entity, result || data); this.triggerCallbacks(operation, entity, result || data); return result; } catch (error) { console.error('CRUD error:', error); this.triggerCallbacks(`${operation}_error`, entity, { data, error: error.message }); throw error; } } /** * 更新本地数据 * @param {string} operation - 操作类型: 'add' | 'update' | 'delete' * @param {string} entity - 实体名称 * @param {Object} newData - 新数据对象(包含id字段) * @description 根据操作类型对本地数据进行增删改操作 */ updateLocalData(operation, entity, newData) { const key = `${entity}s`; const entities = this._rawData[key]; // 确保新数据的引用已解析 const resolvedData = resolveDataReference(newData, this._rawData); switch (operation) { case 'add': entities.push(resolvedData); break; case 'update': const index = entities.findIndex(item => item.id === resolvedData.id); if (index !== -1) { // 修复:使用对象展开操作符确保属性完整覆盖 entities[index] = { ...entities[index], ...resolvedData }; } else { entities.push(resolvedData); } break; case 'delete': const deleteIndex = entities.findIndex(item => item.id === resolvedData.id); if (deleteIndex !== -1) { entities.splice(deleteIndex, 1); } break; } // 更新最后修改时间 this._rawData._lastModified = new Date().toISOString(); // 清除懒加载缓存 this.lazyLoader.clearCache(); // 保存修改后的数据到本地存储 this.saveDataToStorage(); } /** * 同步数据方法 * 该方法用于异步获取所有数据,并处理同步过程中的并发请求 * 如果同步正在进行中,会将请求标记为待处理(pendingSync) * 同步完成后会自动处理处理的请求 * @async * @throws {Error} 当获取数据失败时会抛出错误并记录日志 */ async syncData() { if (this.isSyncing) { this.pendingSync = true; return; } this.isSyncing = true; try { // 1. 先加载本地数据 this.loadDataFromStorage(); // 2. 获取最后同步时间,用于增量更新 const since = this._rawData._lastSync || null; // 3. 获取增量数据 await this.fetchAll(since); // 4. 清除懒加载缓存 this.lazyLoader.clearCache(); // 5. 保存更新后的数据到本地存储 this.saveDataToStorage(); // 6. 触发数据更新回调 this.triggerCallbacks('refresh', 'all', this.data); } catch (error) { console.error('Sync failed:', error); this.triggerCallbacks('sync_error', 'all', { error }); // 失败时尝试使用本地数据 if (!this._rawData._lastSync) { throw new Error('初始化数据同步失败'); } } finally { this.isSyncing = false; if (this.pendingSync) { this.pendingSync = false; this.syncData(); } } } /** * 从本地存储加载数据 * 使用微信小程序的同步存储API获取之前保存的数据 */ loadDataFromStorage() { try { const storedData = wx.getStorageSync(this.storageKey); if (storedData) { // 修复:加载到_rawData而非data代理对象 this._rawData = storedData; // 解析所有引用关系 // resolveDataReferences(this._rawData); } } catch (error) { console.error('加载本地存储数据失败:', error); // 提供默认空数据 this._rawData = { bancais: [], dingdans: [], mupis: [], chanpins: [], kucuns: [], dingdan_bancais: [], chanpin_zujians: [], zujians: [], caizhis: [], dingdan_chanpins: [], users: [], jinhuos: [], _lastModified: null, _lastSync: null }; } } /** * 保存数据到本地存储 * 使用微信小程序的同步存储API持久化当前数据 */ saveDataToStorage() { try { // 修复:保存_rawData而非localData wx.setStorageSync(this.storageKey, this._rawData); } catch (error) { console.error('保存数据到本地存储失败:', error); // 提示用户或执行降级策略 wx.showToast({ title: '数据保存失败,请稍后重试', icon: 'none' }); } } /** * 添加实体数据 * @async * @param {string} entity - 实体类型 * @param {Object} data - 要添加的实体数据 * @returns {Promise} 返回CRUD操作结果 * @throws {Error} 如果数据已存在则抛出错误 */ async addEntity(entity, data) { if (this.checkDuplicate(entity, data)) { const errorMsg = `${this.entiyeText[entity]}`; this.triggerCallbacks('duplicate_error', entity, { data, error: errorMsg }); throw new Error(errorMsg); } return this.crudOperation('add', entity, data); } /** * 更新实体 */ async updateEntity(entity, data) { return this.crudOperation('update', entity, data); } /** * 删除实体 */ async deleteEntity(entity, id) { return this.crudOperation('delete', entity, { id }); } getBancaisForZujian(zujianId) { const dingdan_bancais = this.data.dingdan_bancais.filter(db => db.zujian?.id == zujianId); return dingdan_bancais.map(db => db.bancai).filter(Boolean); } /** * 获取板材的库存信息 */ getKucunForBancai(bancaiId) { return this.data.kucuns.find(k => k.bancai?.id == bancaiId); } } // 导出模块 module.exports = MiniProgramDataManager;----------------------------------------页面数据显示不无安全,订单产品没有显示,index.js直接要以dingdan_bancai制定每行数据
07-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值