The callee Property

本文介绍了一种使用JavaScript中的Arguments对象实现匿名函数递归调用的方法。通过Arguments对象的callee属性,即使函数未命名也能实现自我调用,文中提供了一个计算阶乘的示例。

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

In addition to its array elements, the Arguments object defines a callee property that refers to the
function that is currently being executed. This property is rarely useful, but it can be used to allow
unnamed functions to invoke themselves recursively. For instance, here is an unnamed function literal
that computes factorials:

function(x) {
   if (x <= 1) return 1;
   return x * arguments.callee(x-1);
}
 

 

你给的代码有好多错啊 10main.vue:189 [Element Warn][TableColumn]Comparing to render-header, scoped-slot header is easier to use. We recommend users to use scoped-slot header. setColumnRenders @ index.js:1 boundFn @ vue.esm.js:186 (匿名) @ index.js:1 (匿名) @ index.js:1 created @ index.js:1 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4476 VueComponent @ vue.esm.js:4646 createComponentInstanceForVnode @ vue.esm.js:4163 init @ vue.esm.js:3980 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 patch @ vue.esm.js:5879 (匿名) @ vue.esm.js:2562 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 Watcher @ vue.esm.js:3022 mountComponent @ vue.esm.js:2694 (匿名) @ vue.esm.js:8226 (匿名) @ vue.esm.js:10540 init @ vue.esm.js:3986 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 patch @ vue.esm.js:5879 (匿名) @ vue.esm.js:2562 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 Watcher @ vue.esm.js:3022 mountComponent @ vue.esm.js:2694 (匿名) @ vue.esm.js:8226 (匿名) @ vue.esm.js:10540 init @ vue.esm.js:3986 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 patch @ vue.esm.js:5879 (匿名) @ vue.esm.js:2562 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 Watcher @ vue.esm.js:3022 mountComponent @ vue.esm.js:2694 (匿名) @ vue.esm.js:8226 (匿名) @ vue.esm.js:10540 init @ vue.esm.js:3986 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 patch @ vue.esm.js:5879 (匿名) @ vue.esm.js:2562 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 Watcher @ vue.esm.js:3022 mountComponent @ vue.esm.js:2694 (匿名) @ vue.esm.js:8226 (匿名) @ vue.esm.js:10540 init @ vue.esm.js:3986 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 patch @ vue.esm.js:5879 (匿名) @ vue.esm.js:2562 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 Watcher @ vue.esm.js:3022 mountComponent @ vue.esm.js:2694 (匿名) @ vue.esm.js:8226 (匿名) @ vue.esm.js:10540 init @ vue.esm.js:3986 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 patch @ vue.esm.js:5879 (匿名) @ vue.esm.js:2562 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 Watcher @ vue.esm.js:3022 mountComponent @ vue.esm.js:2694 (匿名) @ vue.esm.js:8226 (匿名) @ vue.esm.js:10540 init @ vue.esm.js:3986 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 patch @ vue.esm.js:5879 (匿名) @ vue.esm.js:2562 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 Watcher @ vue.esm.js:3022 mountComponent @ vue.esm.js:2694 (匿名) @ vue.esm.js:8226 (匿名) @ vue.esm.js:10540 init @ vue.esm.js:3986 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 updateChildren @ vue.esm.js:5655 patchVnode @ vue.esm.js:5735 patch @ vue.esm.js:5884 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 proxySetter @ vue.esm.js:3225 (匿名) @ main.vue:189 Promise.then getUserInfo @ main.vue:184 boundFn @ vue.esm.js:187 created @ main.vue:93 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4476 VueComponent @ vue.esm.js:4646 createComponentInstanceForVnode @ vue.esm.js:4163 init @ vue.esm.js:3980 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 patch @ vue.esm.js:5915 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 (匿名) @ vue-router.esm.js:2508 (匿名) @ vue-router.esm.js:2507 updateRoute @ vue-router.esm.js:1997 (匿名) @ vue-router.esm.js:1875 (匿名) @ vue-router.esm.js:1984 step @ vue-router.esm.js:1714 step @ vue-router.esm.js:1721 step @ vue-router.esm.js:1721 runQueue @ vue-router.esm.js:1725 (匿名) @ vue-router.esm.js:1979 step @ vue-router.esm.js:1714 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ vue-router.esm.js:1792 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 step @ vue-router.esm.js:1721 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 beforeEnter @ index.js:47 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ index.js:64 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 replace @ vue-router.esm.js:2285 (匿名) @ vue-router.esm.js:1958 _callee$ @ index.js:78 tryCatch @ runtime.js:62 invoke @ runtime.js:296 (匿名) @ runtime.js:114 step @ asyncToGenerator.js:17 (匿名) @ asyncToGenerator.js:35 F @ _export.js:36 (匿名) @ asyncToGenerator.js:14 (匿名) @ index.js:66 Promise.then (匿名) @ index.js:70 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 init @ vue-router.esm.js:2499 beforeCreate @ vue-router.esm.js:540 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4472 Vue$3 @ vue.esm.js:4571 ./src/main.js @ main.js:109 webpack_require @ bootstrap c8219a0eed343174f276:677 fn @ bootstrap c8219a0eed343174f276:87 0 @ department-query-dialog.vue:46 webpack_require @ bootstrap c8219a0eed343174f276:677 (匿名) @ bootstrap c8219a0eed343174f276:723 (匿名) @ bootstrap c8219a0eed343174f276:723 main.vue:189 [Vue warn]: Invalid handler for event “close”: got undefined found in —> <EquipmentDetail> at src\views\modules\cmmsEquipmentInfo\cmmsEquipmentInfoDetail.vue <CmmsEquipmentInfo> at src\views\modules\cmmsEquipmentInfo\cmmsEquipmentInfo.vue <ElTabPane> at packages/tabs/src/tab-pane.vue <ElTabs> at packages/tabs/src/tabs.vue <MainContent> at src\views\main-content.vue <Main> at src\views\main.vue <App> at src\App.vue <Root> warn @ vue.esm.js:571 updateListeners @ vue.esm.js:1957 updateComponentListeners @ vue.esm.js:2348 initEvents @ vue.esm.js:2324 (匿名) @ vue.esm.js:4470 VueComponent @ vue.esm.js:4646 createComponentInstanceForVnode @ vue.esm.js:4163 init @ vue.esm.js:3980 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 patch @ vue.esm.js:5879 (匿名) @ vue.esm.js:2562 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 Watcher @ vue.esm.js:3022 mountComponent @ vue.esm.js:2694 (匿名) @ vue.esm.js:8226 (匿名) @ vue.esm.js:10540 init @ vue.esm.js:3986 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 patch @ vue.esm.js:5879 (匿名) @ vue.esm.js:2562 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 Watcher @ vue.esm.js:3022 mountComponent @ vue.esm.js:2694 (匿名) @ vue.esm.js:8226 (匿名) @ vue.esm.js:10540 init @ vue.esm.js:3986 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 patch @ vue.esm.js:5879 (匿名) @ vue.esm.js:2562 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 Watcher @ vue.esm.js:3022 mountComponent @ vue.esm.js:2694 (匿名) @ vue.esm.js:8226 (匿名) @ vue.esm.js:10540 init @ vue.esm.js:3986 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 patch @ vue.esm.js:5879 (匿名) @ vue.esm.js:2562 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 Watcher @ vue.esm.js:3022 mountComponent @ vue.esm.js:2694 (匿名) @ vue.esm.js:8226 (匿名) @ vue.esm.js:10540 init @ vue.esm.js:3986 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 patch @ vue.esm.js:5879 (匿名) @ vue.esm.js:2562 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 Watcher @ vue.esm.js:3022 mountComponent @ vue.esm.js:2694 (匿名) @ vue.esm.js:8226 (匿名) @ vue.esm.js:10540 init @ vue.esm.js:3986 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 createChildren @ vue.esm.js:5496 createElm @ vue.esm.js:5401 updateChildren @ vue.esm.js:5655 patchVnode @ vue.esm.js:5735 patch @ vue.esm.js:5884 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 proxySetter @ vue.esm.js:3225 (匿名) @ main.vue:189 Promise.then getUserInfo @ main.vue:184 boundFn @ vue.esm.js:187 created @ main.vue:93 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4476 VueComponent @ vue.esm.js:4646 createComponentInstanceForVnode @ vue.esm.js:4163 init @ vue.esm.js:3980 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 patch @ vue.esm.js:5915 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 (匿名) @ vue-router.esm.js:2508 (匿名) @ vue-router.esm.js:2507 updateRoute @ vue-router.esm.js:1997 (匿名) @ vue-router.esm.js:1875 (匿名) @ vue-router.esm.js:1984 step @ vue-router.esm.js:1714 step @ vue-router.esm.js:1721 step @ vue-router.esm.js:1721 runQueue @ vue-router.esm.js:1725 (匿名) @ vue-router.esm.js:1979 step @ vue-router.esm.js:1714 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ vue-router.esm.js:1792 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 step @ vue-router.esm.js:1721 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 beforeEnter @ index.js:47 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ index.js:64 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 replace @ vue-router.esm.js:2285 (匿名) @ vue-router.esm.js:1958 _callee$ @ index.js:78 tryCatch @ runtime.js:62 invoke @ runtime.js:296 (匿名) @ runtime.js:114 step @ asyncToGenerator.js:17 (匿名) @ asyncToGenerator.js:35 F @ _export.js:36 (匿名) @ asyncToGenerator.js:14 (匿名) @ index.js:66 Promise.then (匿名) @ index.js:70 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 init @ vue-router.esm.js:2499 beforeCreate @ vue-router.esm.js:540 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4472 Vue$3 @ vue.esm.js:4571 ./src/main.js @ main.js:109 webpack_require @ bootstrap c8219a0eed343174f276:677 fn @ bootstrap c8219a0eed343174f276:87 0 @ department-query-dialog.vue:46 webpack_require @ bootstrap c8219a0eed343174f276:677 (匿名) @ bootstrap c8219a0eed343174f276:723 (匿名) @ bootstrap c8219a0eed343174f276:723 dictionary.js:70 (7) [‘equipment_category’, ‘equipment_subcategory’, ‘accuracy_level’, ‘ownership_type’, ‘equipment_status’, ‘storage_status’, ‘inspection_status’] cmmsEquipmentInfo.vue:465 [Vue warn]: Property or method “closeDetail” is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties. found in —> <CmmsEquipmentInfo> at src\views\modules\cmmsEquipmentInfo\cmmsEquipmentInfo.vue <ElTabPane> at packages/tabs/src/tab-pane.vue <ElTabs> at packages/tabs/src/tabs.vue <MainContent> at src\views\main-content.vue <Main> at src\views\main.vue <App> at src\App.vue <Root> warn @ vue.esm.js:571 warnNonPresent @ vue.esm.js:1845 get @ vue.esm.js:1888 render @ cmmsEquipmentInfo.vue:465 (匿名) @ vue.esm.js:4390 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 proxySetter @ vue.esm.js:3225 (匿名) @ main.vue:189 Promise.then getUserInfo @ main.vue:184 boundFn @ vue.esm.js:187 created @ main.vue:93 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4476 VueComponent @ vue.esm.js:4646 createComponentInstanceForVnode @ vue.esm.js:4163 init @ vue.esm.js:3980 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 patch @ vue.esm.js:5915 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 (匿名) @ vue-router.esm.js:2508 (匿名) @ vue-router.esm.js:2507 updateRoute @ vue-router.esm.js:1997 (匿名) @ vue-router.esm.js:1875 (匿名) @ vue-router.esm.js:1984 step @ vue-router.esm.js:1714 step @ vue-router.esm.js:1721 step @ vue-router.esm.js:1721 runQueue @ vue-router.esm.js:1725 (匿名) @ vue-router.esm.js:1979 step @ vue-router.esm.js:1714 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ vue-router.esm.js:1792 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 step @ vue-router.esm.js:1721 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 beforeEnter @ index.js:47 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ index.js:64 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 replace @ vue-router.esm.js:2285 (匿名) @ vue-router.esm.js:1958 _callee$ @ index.js:78 tryCatch @ runtime.js:62 invoke @ runtime.js:296 (匿名) @ runtime.js:114 step @ asyncToGenerator.js:17 (匿名) @ asyncToGenerator.js:35 F @ _export.js:36 (匿名) @ asyncToGenerator.js:14 (匿名) @ index.js:66 Promise.then (匿名) @ index.js:70 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 init @ vue-router.esm.js:2499 beforeCreate @ vue-router.esm.js:540 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4472 Vue$3 @ vue.esm.js:4571 ./src/main.js @ main.js:109 webpack_require @ bootstrap c8219a0eed343174f276:677 fn @ bootstrap c8219a0eed343174f276:87 0 @ department-query-dialog.vue:46 webpack_require @ bootstrap c8219a0eed343174f276:677 (匿名) @ bootstrap c8219a0eed343174f276:723 (匿名) @ bootstrap c8219a0eed343174f276:723 main.vue:189 [Vue warn]: Invalid handler for event “close”: got undefined found in —> <EquipmentDetail> at src\views\modules\cmmsEquipmentInfo\cmmsEquipmentInfoDetail.vue <CmmsEquipmentInfo> at src\views\modules\cmmsEquipmentInfo\cmmsEquipmentInfo.vue <ElTabPane> at packages/tabs/src/tab-pane.vue <ElTabs> at packages/tabs/src/tabs.vue <MainContent> at src\views\main-content.vue <Main> at src\views\main.vue <App> at src\App.vue <Root> warn @ vue.esm.js:571 updateListeners @ vue.esm.js:1957 updateComponentListeners @ vue.esm.js:2348 updateChildComponent @ vue.esm.js:2758 prepatch @ vue.esm.js:3997 patchVnode @ vue.esm.js:5724 updateChildren @ vue.esm.js:5632 patchVnode @ vue.esm.js:5735 patch @ vue.esm.js:5884 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 proxySetter @ vue.esm.js:3225 (匿名) @ main.vue:189 Promise.then getUserInfo @ main.vue:184 boundFn @ vue.esm.js:187 created @ main.vue:93 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4476 VueComponent @ vue.esm.js:4646 createComponentInstanceForVnode @ vue.esm.js:4163 init @ vue.esm.js:3980 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 patch @ vue.esm.js:5915 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 (匿名) @ vue-router.esm.js:2508 (匿名) @ vue-router.esm.js:2507 updateRoute @ vue-router.esm.js:1997 (匿名) @ vue-router.esm.js:1875 (匿名) @ vue-router.esm.js:1984 step @ vue-router.esm.js:1714 step @ vue-router.esm.js:1721 step @ vue-router.esm.js:1721 runQueue @ vue-router.esm.js:1725 (匿名) @ vue-router.esm.js:1979 step @ vue-router.esm.js:1714 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ vue-router.esm.js:1792 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 step @ vue-router.esm.js:1721 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 beforeEnter @ index.js:47 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ index.js:64 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 replace @ vue-router.esm.js:2285 (匿名) @ vue-router.esm.js:1958 _callee$ @ index.js:78 tryCatch @ runtime.js:62 invoke @ runtime.js:296 (匿名) @ runtime.js:114 step @ asyncToGenerator.js:17 (匿名) @ asyncToGenerator.js:35 F @ _export.js:36 (匿名) @ asyncToGenerator.js:14 (匿名) @ index.js:66 Promise.then (匿名) @ index.js:70 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 init @ vue-router.esm.js:2499 beforeCreate @ vue-router.esm.js:540 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4472 Vue$3 @ vue.esm.js:4571 ./src/main.js @ main.js:109 webpack_require @ bootstrap c8219a0eed343174f276:677 fn @ bootstrap c8219a0eed343174f276:87 0 @ department-query-dialog.vue:46 webpack_require @ bootstrap c8219a0eed343174f276:677 (匿名) @ bootstrap c8219a0eed343174f276:723 (匿名) @ bootstrap c8219a0eed343174f276:723 cmmsEquipmentInfo.vue:465 [Vue warn]: Property or method “closeDetail” is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties. found in —> <CmmsEquipmentInfo> at src\views\modules\cmmsEquipmentInfo\cmmsEquipmentInfo.vue <ElTabPane> at packages/tabs/src/tab-pane.vue <ElTabs> at packages/tabs/src/tabs.vue <MainContent> at src\views\main-content.vue <Main> at src\views\main.vue <App> at src\App.vue <Root> warn @ vue.esm.js:571 warnNonPresent @ vue.esm.js:1845 get @ vue.esm.js:1888 render @ cmmsEquipmentInfo.vue:465 (匿名) @ vue.esm.js:4390 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 proxySetter @ vue.esm.js:3225 _callee$ @ cmmsEquipmentInfo.vue:339 tryCatch @ runtime.js:62 invoke @ runtime.js:296 (匿名) @ runtime.js:114 step @ asyncToGenerator.js:17 (匿名) @ asyncToGenerator.js:28 Promise.then step @ asyncToGenerator.js:27 (匿名) @ asyncToGenerator.js:35 F @ _export.js:36 (匿名) @ asyncToGenerator.js:14 getDataList @ cmmsEquipmentInfo.vue:346 boundFn @ vue.esm.js:187 activated @ cmmsEquipmentInfo.vue:316 callHook @ vue.esm.js:2817 activateChildComponent @ vue.esm.js:2792 insert @ vue.esm.js:4022 invokeInsertHook @ vue.esm.js:5759 patch @ vue.esm.js:5964 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 proxySetter @ vue.esm.js:3225 (匿名) @ main.vue:189 Promise.then getUserInfo @ main.vue:184 boundFn @ vue.esm.js:187 created @ main.vue:93 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4476 VueComponent @ vue.esm.js:4646 createComponentInstanceForVnode @ vue.esm.js:4163 init @ vue.esm.js:3980 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 patch @ vue.esm.js:5915 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 (匿名) @ vue-router.esm.js:2508 (匿名) @ vue-router.esm.js:2507 updateRoute @ vue-router.esm.js:1997 (匿名) @ vue-router.esm.js:1875 (匿名) @ vue-router.esm.js:1984 step @ vue-router.esm.js:1714 step @ vue-router.esm.js:1721 step @ vue-router.esm.js:1721 runQueue @ vue-router.esm.js:1725 (匿名) @ vue-router.esm.js:1979 step @ vue-router.esm.js:1714 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ vue-router.esm.js:1792 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 step @ vue-router.esm.js:1721 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 beforeEnter @ index.js:47 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ index.js:64 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 replace @ vue-router.esm.js:2285 (匿名) @ vue-router.esm.js:1958 _callee$ @ index.js:78 tryCatch @ runtime.js:62 invoke @ runtime.js:296 (匿名) @ runtime.js:114 step @ asyncToGenerator.js:17 (匿名) @ asyncToGenerator.js:35 F @ _export.js:36 (匿名) @ asyncToGenerator.js:14 (匿名) @ index.js:66 Promise.then (匿名) @ index.js:70 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 init @ vue-router.esm.js:2499 beforeCreate @ vue-router.esm.js:540 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4472 Vue$3 @ vue.esm.js:4571 ./src/main.js @ main.js:109 webpack_require @ bootstrap c8219a0eed343174f276:677 fn @ bootstrap c8219a0eed343174f276:87 0 @ department-query-dialog.vue:46 webpack_require @ bootstrap c8219a0eed343174f276:677 (匿名) @ bootstrap c8219a0eed343174f276:723 (匿名) @ bootstrap c8219a0eed343174f276:723 cmmsEquipmentInfo.vue:339 [Vue warn]: Invalid handler for event “close”: got undefined found in —> <EquipmentDetail> at src\views\modules\cmmsEquipmentInfo\cmmsEquipmentInfoDetail.vue <CmmsEquipmentInfo> at src\views\modules\cmmsEquipmentInfo\cmmsEquipmentInfo.vue <ElTabPane> at packages/tabs/src/tab-pane.vue <ElTabs> at packages/tabs/src/tabs.vue <MainContent> at src\views\main-content.vue <Main> at src\views\main.vue <App> at src\App.vue <Root> warn @ vue.esm.js:571 updateListeners @ vue.esm.js:1957 updateComponentListeners @ vue.esm.js:2348 updateChildComponent @ vue.esm.js:2758 prepatch @ vue.esm.js:3997 patchVnode @ vue.esm.js:5724 updateChildren @ vue.esm.js:5632 patchVnode @ vue.esm.js:5735 patch @ vue.esm.js:5884 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 proxySetter @ vue.esm.js:3225 _callee$ @ cmmsEquipmentInfo.vue:339 tryCatch @ runtime.js:62 invoke @ runtime.js:296 (匿名) @ runtime.js:114 step @ asyncToGenerator.js:17 (匿名) @ asyncToGenerator.js:28 Promise.then step @ asyncToGenerator.js:27 (匿名) @ asyncToGenerator.js:35 F @ _export.js:36 (匿名) @ asyncToGenerator.js:14 getDataList @ cmmsEquipmentInfo.vue:346 boundFn @ vue.esm.js:187 activated @ cmmsEquipmentInfo.vue:316 callHook @ vue.esm.js:2817 activateChildComponent @ vue.esm.js:2792 insert @ vue.esm.js:4022 invokeInsertHook @ vue.esm.js:5759 patch @ vue.esm.js:5964 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 proxySetter @ vue.esm.js:3225 (匿名) @ main.vue:189 Promise.then getUserInfo @ main.vue:184 boundFn @ vue.esm.js:187 created @ main.vue:93 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4476 VueComponent @ vue.esm.js:4646 createComponentInstanceForVnode @ vue.esm.js:4163 init @ vue.esm.js:3980 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 patch @ vue.esm.js:5915 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 (匿名) @ vue-router.esm.js:2508 (匿名) @ vue-router.esm.js:2507 updateRoute @ vue-router.esm.js:1997 (匿名) @ vue-router.esm.js:1875 (匿名) @ vue-router.esm.js:1984 step @ vue-router.esm.js:1714 step @ vue-router.esm.js:1721 step @ vue-router.esm.js:1721 runQueue @ vue-router.esm.js:1725 (匿名) @ vue-router.esm.js:1979 step @ vue-router.esm.js:1714 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ vue-router.esm.js:1792 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 step @ vue-router.esm.js:1721 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 beforeEnter @ index.js:47 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ index.js:64 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 replace @ vue-router.esm.js:2285 (匿名) @ vue-router.esm.js:1958 _callee$ @ index.js:78 tryCatch @ runtime.js:62 invoke @ runtime.js:296 (匿名) @ runtime.js:114 step @ asyncToGenerator.js:17 (匿名) @ asyncToGenerator.js:35 F @ _export.js:36 (匿名) @ asyncToGenerator.js:14 (匿名) @ index.js:66 Promise.then (匿名) @ index.js:70 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 init @ vue-router.esm.js:2499 beforeCreate @ vue-router.esm.js:540 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4472 Vue$3 @ vue.esm.js:4571 ./src/main.js @ main.js:109 webpack_require @ bootstrap c8219a0eed343174f276:677 fn @ bootstrap c8219a0eed343174f276:87 0 @ department-query-dialog.vue:46 webpack_require @ bootstrap c8219a0eed343174f276:677 (匿名) @ bootstrap c8219a0eed343174f276:723 (匿名) @ bootstrap c8219a0eed343174f276:723 cmmsEquipmentInfo.vue:465 [Vue warn]: Property or method “closeDetail” is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties. found in —> <CmmsEquipmentInfo> at src\views\modules\cmmsEquipmentInfo\cmmsEquipmentInfo.vue <ElTabPane> at packages/tabs/src/tab-pane.vue <ElTabs> at packages/tabs/src/tabs.vue <MainContent> at src\views\main-content.vue <Main> at src\views\main.vue <App> at src\App.vue <Root> warn @ vue.esm.js:571 warnNonPresent @ vue.esm.js:1845 get @ vue.esm.js:1888 render @ cmmsEquipmentInfo.vue:465 (匿名) @ vue.esm.js:4390 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 proxySetter @ vue.esm.js:3225 (匿名) @ cmmsEquipmentInfo.vue:383 Promise.then (匿名) @ cmmsEquipmentInfo.vue:382 F @ _export.js:36 getDictionaries @ cmmsEquipmentInfo.vue:372 boundFn @ vue.esm.js:187 activated @ cmmsEquipmentInfo.vue:317 callHook @ vue.esm.js:2817 activateChildComponent @ vue.esm.js:2792 insert @ vue.esm.js:4022 invokeInsertHook @ vue.esm.js:5759 patch @ vue.esm.js:5964 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 proxySetter @ vue.esm.js:3225 (匿名) @ main.vue:189 Promise.then getUserInfo @ main.vue:184 boundFn @ vue.esm.js:187 created @ main.vue:93 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4476 VueComponent @ vue.esm.js:4646 createComponentInstanceForVnode @ vue.esm.js:4163 init @ vue.esm.js:3980 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 patch @ vue.esm.js:5915 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 (匿名) @ vue-router.esm.js:2508 (匿名) @ vue-router.esm.js:2507 updateRoute @ vue-router.esm.js:1997 (匿名) @ vue-router.esm.js:1875 (匿名) @ vue-router.esm.js:1984 step @ vue-router.esm.js:1714 step @ vue-router.esm.js:1721 step @ vue-router.esm.js:1721 runQueue @ vue-router.esm.js:1725 (匿名) @ vue-router.esm.js:1979 step @ vue-router.esm.js:1714 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ vue-router.esm.js:1792 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 step @ vue-router.esm.js:1721 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 beforeEnter @ index.js:47 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ index.js:64 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 replace @ vue-router.esm.js:2285 (匿名) @ vue-router.esm.js:1958 _callee$ @ index.js:78 tryCatch @ runtime.js:62 invoke @ runtime.js:296 (匿名) @ runtime.js:114 step @ asyncToGenerator.js:17 (匿名) @ asyncToGenerator.js:35 F @ _export.js:36 (匿名) @ asyncToGenerator.js:14 (匿名) @ index.js:66 Promise.then (匿名) @ index.js:70 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 init @ vue-router.esm.js:2499 beforeCreate @ vue-router.esm.js:540 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4472 Vue$3 @ vue.esm.js:4571 ./src/main.js @ main.js:109 webpack_require @ bootstrap c8219a0eed343174f276:677 fn @ bootstrap c8219a0eed343174f276:87 0 @ department-query-dialog.vue:46 webpack_require @ bootstrap c8219a0eed343174f276:677 (匿名) @ bootstrap c8219a0eed343174f276:723 (匿名) @ bootstrap c8219a0eed343174f276:723 cmmsEquipmentInfo.vue:383 [Vue warn]: Invalid handler for event “close”: got undefined found in —> <EquipmentDetail> at src\views\modules\cmmsEquipmentInfo\cmmsEquipmentInfoDetail.vue <CmmsEquipmentInfo> at src\views\modules\cmmsEquipmentInfo\cmmsEquipmentInfo.vue <ElTabPane> at packages/tabs/src/tab-pane.vue <ElTabs> at packages/tabs/src/tabs.vue <MainContent> at src\views\main-content.vue <Main> at src\views\main.vue <App> at src\App.vue <Root> warn @ vue.esm.js:571 updateListeners @ vue.esm.js:1957 updateComponentListeners @ vue.esm.js:2348 updateChildComponent @ vue.esm.js:2758 prepatch @ vue.esm.js:3997 patchVnode @ vue.esm.js:5724 updateChildren @ vue.esm.js:5632 patchVnode @ vue.esm.js:5735 patch @ vue.esm.js:5884 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 proxySetter @ vue.esm.js:3225 (匿名) @ cmmsEquipmentInfo.vue:383 Promise.then (匿名) @ cmmsEquipmentInfo.vue:382 F @ _export.js:36 getDictionaries @ cmmsEquipmentInfo.vue:372 boundFn @ vue.esm.js:187 activated @ cmmsEquipmentInfo.vue:317 callHook @ vue.esm.js:2817 activateChildComponent @ vue.esm.js:2792 insert @ vue.esm.js:4022 invokeInsertHook @ vue.esm.js:5759 patch @ vue.esm.js:5964 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 proxySetter @ vue.esm.js:3225 (匿名) @ main.vue:189 Promise.then getUserInfo @ main.vue:184 boundFn @ vue.esm.js:187 created @ main.vue:93 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4476 VueComponent @ vue.esm.js:4646 createComponentInstanceForVnode @ vue.esm.js:4163 init @ vue.esm.js:3980 createComponent @ vue.esm.js:5425 createElm @ vue.esm.js:5361 patch @ vue.esm.js:5915 (匿名) @ vue.esm.js:2572 updateComponent @ vue.esm.js:2690 get @ vue.esm.js:3033 run @ vue.esm.js:3110 flushSchedulerQueue @ vue.esm.js:2876 (匿名) @ vue.esm.js:1783 flushCallbacks @ vue.esm.js:1704 Promise.then microTimerFunc @ vue.esm.js:1752 nextTick @ vue.esm.js:1796 queueWatcher @ vue.esm.js:2963 update @ vue.esm.js:3100 notify @ vue.esm.js:677 reactiveSetter @ vue.esm.js:994 (匿名) @ vue-router.esm.js:2508 (匿名) @ vue-router.esm.js:2507 updateRoute @ vue-router.esm.js:1997 (匿名) @ vue-router.esm.js:1875 (匿名) @ vue-router.esm.js:1984 step @ vue-router.esm.js:1714 step @ vue-router.esm.js:1721 step @ vue-router.esm.js:1721 runQueue @ vue-router.esm.js:1725 (匿名) @ vue-router.esm.js:1979 step @ vue-router.esm.js:1714 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ vue-router.esm.js:1792 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 step @ vue-router.esm.js:1721 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 beforeEnter @ index.js:47 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 (匿名) @ vue-router.esm.js:1718 (匿名) @ vue-router.esm.js:1964 (匿名) @ index.js:64 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 replace @ vue-router.esm.js:2285 (匿名) @ vue-router.esm.js:1958 _callee$ @ index.js:78 tryCatch @ runtime.js:62 invoke @ runtime.js:296 (匿名) @ runtime.js:114 step @ asyncToGenerator.js:17 (匿名) @ asyncToGenerator.js:35 F @ _export.js:36 (匿名) @ asyncToGenerator.js:14 (匿名) @ index.js:66 Promise.then (匿名) @ index.js:70 iterator @ vue-router.esm.js:1943 step @ vue-router.esm.js:1717 runQueue @ vue-router.esm.js:1725 confirmTransition @ vue-router.esm.js:1972 transitionTo @ vue-router.esm.js:1874 init @ vue-router.esm.js:2499 beforeCreate @ vue-router.esm.js:540 callHook @ vue.esm.js:2817 (匿名) @ vue.esm.js:4472 Vue$3 @ vue.esm.js:4571 ./src/main.js @ main.js:109 webpack_require @ bootstrap c8219a0eed343174f276:677 fn @ bootstrap c8219a0eed343174f276:87 0 @ department-query-dialog.vue:46 webpack_require @ bootstrap c8219a0eed343174f276:677 (匿名) @ bootstrap c8219a0eed343174f276:723 (匿名) @ bootstrap c8219a0eed343174f276:723
06-10
/* 文件路径: index.js */ /* 文件路径: pages/index/index.js */ // 首页逻辑文件 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, // 当前页数据 currentPageData: [], // 板材详情 showMaterialDetail: false, materialDetail: null }, onLoad: function() { console.log('index页面加载'); // 获取全局数据管理器 if (app.globalData && app.globalData.dataManager) { this.dataManager = app.globalData.dataManager; console.log('获取到dataManager实例'); // 注册数据更新回调 this.dataManager.registerCallback('all', () => { console.log('收到数据更新回调'); this.updatePageData(); }); // 初始化页面数据 this.updatePageData(); // 主动加载数据 this.dataManager.fetchAll().then(() => { console.log('数据加载成功'); }).catch(err => { console.error('数据加载失败:', err); wx.showToast({ title: '数据加载失败', icon: 'none' }); }); } else { console.error('DataManager not available'); wx.showToast({ title: '数据管理器未初始化', icon: 'none' }); // 尝试重新初始化 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; console.log('原始数据:', JSON.stringify(data, null, 2)); let results = []; // 直接遍历dingdan_bancai表获取数据 if (data.dingdan_bancais) { data.dingdan_bancais.forEach(db => { // 获取关联信息 const dingdan = db.dingdan || {}; const chanpin = db.chanpin || {}; const zujian = db.zujian || {}; const bancai = db.bancai || {}; // 获取库存数量 const kucun = data.kucuns?.find(k => k.bancai && k.bancai.id === bancai.id); const stockQuantity = kucun ? kucun.shuliang : 0; // 构建板材信息 const materialInfo = this.getMaterialInfo(bancai); // 构建结果项 results.push({ id: `${db.id}`, orderNumber: dingdan.number || '无', productInfo: chanpin.bianhao || '独立订购', productQuantity: db.shuliang, component: zujian.name || '独立板材', material: materialInfo, materialPerComponent: 1, // 直接订购时,每件用量为1 materialOrderQuantity: db.shuliang, stockQuantity: stockQuantity, raw: { orderNumber: 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}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 && item.orderNumber.toLowerCase().includes(search) ); } // 应用产品筛选 if (this.data.productSearch) { const search = this.data.productSearch.toLowerCase(); filtered = filtered.filter(item => item.productInfo && item.productInfo.toLowerCase().includes(search) ); } // 应用板材筛选 if (this.data.materialSearch) { const search = this.data.materialSearch.toLowerCase(); filtered = filtered.filter(item => item.material && item.material.toLowerCase().includes(search) ); } // 应用木皮筛选 if (this.data.woodSearch) { const search = this.data.woodSearch.toLowerCase(); filtered = filtered.filter(item => item.material && 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 }, () => { this.updateCurrentPageData(); }); }, // 排序处理 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 && 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 && db.bancai.id === bancai.id && db.dingdan) { orderMap.set(db.dingdan.id, db.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')}`; } }); ================================================================================ /* 文件路径: index.wxml */ <!-- 首页页面结构 --> <view class="container"> <!-- 标题部分 --> <view class="header-section"> <view class="title">板材库存管理系统</view> <view class="subtitle">查询订单、产品、板材及库存信息</view> </view> <!-- 统计卡片区域 --> <view class="stats-container"> <view class="stat-card"> <view class="stat-title">总订单数</view> <view class="stat-value">{{totalOrders}}</view> <view class="stat-icon"><icon type="success" size="20"/></view> </view> <view class="stat-card"> <view class="stat-title">产品总数</view> <view class="stat-value">{{totalProducts}}</view> <view class="stat-icon"><icon type="info" size="20"/></view> </view> <view class="stat-card"> <view class="stat-title">板材总数</view> <view class="stat-value">{{totalMaterials}}</view> <view class="stat-icon"><icon type="waiting" size="20"/></view> </view> </view> <!-- 搜索区域 --> <view class="search-section"> <view class="search-header"> <icon type="search" size="18"/> <text>高级搜索</text> </view> <view class="search-body"> <view class="search-row"> <!-- 订单搜索 --> <view class="search-item"> <view class="search-control"> <icon type="search" size="16"/> <input type="text" placeholder="搜索订单号..." bindinput="onOrderSearchInput"/> </view> </view> <!-- 产品搜索 --> <view class="search-item"> <view class="search-control"> <icon type="search" size="16"/> <input type="text" placeholder="搜索产品编号..." bindinput="onProductSearchInput"/> </view> </view> </view> <view class="search-row"> <!-- 板材搜索 --> <view class="search-item"> <view class="search-control"> <icon type="search" size="16"/> <input type="text" placeholder="搜索板材ID或材质..." bindinput="onMaterialSearchInput"/> </view> </view> <!-- 木皮搜索 --> <view class="search-item"> <view class="search-control"> <icon type="search" size="16"/> <input type="text" placeholder="搜索木皮名称..." bindinput="onWoodSearchInput"/> </view> </view> </view> <view class="search-row"> <!-- 厚度搜索 --> <view class="search-item"> <view class="search-control"> <icon type="search" size="16"/> <input type="digit" placeholder="厚度(mm)" bindinput="onThicknessSearchInput"/> </view> </view> <!-- 库存范围搜索 --> <view class="search-item"> <view class="stock-range"> <input type="number" placeholder="最小库存" bindinput="onMinStockInput"/> <input type="number" placeholder="最大库存" bindinput="onMaxStockInput"/> <button class="search-btn" bindtap="onStockSearch"><icon type="search" size="16"/></button> </view> </view> </view> <!-- 重置按钮 --> <view class="search-actions"> <button class="reset-btn" bindtap="resetFilters"> <icon type="cancel" size="16"/> 重置筛选 </button> </view> </view> </view> <!-- 结果区域 --> <view class="results-section"> <view class="results-header"> <view class="results-title"> <icon type="success" size="18"/> <text>查询结果</text> </view> <view class="results-info"> <text>{{resultCount}} 条记录</text> <text class="update-time">数据更新时间: {{lastUpdate}}</text> </view> </view> <view class="results-body"> <!-- 表格头部 --> <view class="table-header"> <view class="th" bindtap="sortBy" data-field="dingdan.number">订单号</view> <view class="th" bindtap="sortBy" data-field="chanpin.bianhao">产品信息</view> <view class="th" bindtap="sortBy" data-field="dingdan_chanpin.shuliang">产品数量</view> <view class="th" bindtap="sortBy" data-field="zujian.name">组件</view> <view class="th" bindtap="sortBy" data-field="bancai.id">板材</view> <view class="th" bindtap="sortBy" data-field="chanpin_zujian.one_howmany">单件用量</view> <view class="th" bindtap="sortBy" data-field="orderUsage">订单用量</view> <view class="th" bindtap="sortBy" data-field="kucun.shuliang">库存数量</view> <view class="th">操作</view> </view> <!-- 表格内容 --> <view class="table-body"> <block wx:if="{{loading}}"> <view class="loading-row"> <view class="loading-spinner"></view> <text>正在加载数据,请稍候...</text> </view> </block> <block wx:elif="{{results.length === 0}}"> <view class="no-results"> <icon type="info" size="40"/> <view class="no-results-text">没有找到匹配的记录</view> <view class="no-results-hint">请尝试调整您的搜索条件</view> </view> </block> <block wx:else> <!-- 调试信息 --> <view class="debug-info"> <text>currentPageData长度: {{currentPageData.length}}</text> <text>results长度: {{results.length}}</text> </view> <view class="table-row" wx:for="{{currentPageData}}" wx:key="uniqueId"> <view class="td">{{item.orderNumber}}</view> <view class="td">{{item.productInfo}}</view> <view class="td">{{item.productQuantity}}</view> <view class="td">{{item.component}}</view> <view class="td">{{item.material}}</view> <view class="td">{{item.materialPerComponent}}</view> <view class="td">{{item.materialOrderQuantity}}</view> <view class="td">{{item.stockQuantity}}</view> <view class="td"> <button class="detail-btn" bindtap="showMaterialDetail" data-id="{{item.bancaiId}}">详情</button> </view> </view> </block> </view> <!-- 分页控件 --> <view class="pagination" wx:if="{{!loading && results.length > 0}}"> <button class="page-btn" disabled="{{currentPage === 1}}" bindtap="prevPage">上一页</button> <view class="page-info">{{currentPage}}/{{totalPages}}</view> <button class="page-btn" disabled="{{currentPage === totalPages}}" bindtap="nextPage">下一页</button> </view> </view> </view> </view> <!-- 板材详情弹窗 --> <view class="material-modal {{showMaterialDetail ? 'show' : ''}}"> <view class="modal-content"> <view class="modal-header"> <text>板材详情</text> <icon type="cancel" size="20" bindtap="closeMaterialDetail"/> </view> <view class="modal-body"> <!-- 详情内容 --> <block wx:if="{{materialDetail}}"> <view class="detail-item"> <text class="detail-label">板材ID:</text> <text class="detail-value">{{materialDetail.id}}</text> </view> <view class="detail-item"> <text class="detail-label">材质:</text> <text class="detail-value">{{materialDetail.material}}</text> </view> <view class="detail-item"> <text class="detail-label">木皮:</text> <text class="detail-value">{{materialDetail.wood}}</text> </view> <view class="detail-item"> <text class="detail-label">厚度:</text> <text class="detail-value">{{materialDetail.thickness}}mm</text> </view> <view class="detail-item"> <text class="detail-label">库存:</text> <text class="detail-value">{{materialDetail.stock}}</text> </view> </block> </view> <view class="modal-footer"> <button bindtap="closeMaterialDetail">关闭</button> </view> </view> </view> ================================================================================ /* 文件路径: MiniProgramDataManager.js */ /** * 微信小程序数据管理器 * 基于DataManager.js的逻辑,但适配微信小程序环境 */ // 解析数据引用关系的辅助函数 /** * 解析数据中的引用关系 * * 该函数用于处理嵌套的数据结构,将数据中的引用关系解析为实际的对象引用。 * 它会遍历数据中的所有实体,查找属性名中包含的数字(如"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} 处理后的实体对象 * * 功能说明: * 1. 遍历实体对象的每个属性 * 2. 如果属性值是数组,则尝试在数据源中查找匹配项更新数组元素 * 3. 如果属性值是对象,则尝试在数据源中查找匹配项更新该对象 * 4. 自动处理单复数形式的数据源键名 */ 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.resolvedCache = new Map(); // 缓存已解析的实体 } /** * 创建实体代理 * @param {Object} entity 实体对象 * @param {string} entityType 实体类型 * @returns {Proxy} 返回代理后的实体 */ createProxy(entity, entityType) { const handler = { get: (target, prop) => { // 1. 处理特殊属性直接返回 if (prop.startsWith('_') || typeof target[prop] === 'function') { return target[prop]; } const value = target[prop]; // 2. 处理数组属性 if (Array.isArray(value)) { return value.map(item => this.resolveReference(item, prop) ); } // 3. 处理对象属性 if (typeof value === 'object' && value !== null) { return this.resolveReference(value, prop); } // 4. 返回普通属性值 return value; } }; return new Proxy(entity, handler); } /** * 解析引用关系(核心逻辑) * 根据resolveDataReference函数逻辑实现 */ resolveReference(ref, propName) { // 1. 检查缓存 const cacheKey = `${propName}_${ref.id}`; if (this.resolvedCache.has(cacheKey)) { return this.resolvedCache.get(cacheKey); } // 2. 确定引用类型(与resolveDataReference相同逻辑) let refType = propName.replace(/\d/g, ''); const rawData = this.dataManager._rawData; // 处理复数形式(与resolveDataReference相同) if (!rawData[refType] && rawData[`${refType}s`]) { refType = `${refType}s`; } // 3. 查找引用实体(与resolveDataReference相同) const refEntities = rawData[refType]; if (!refEntities) return ref; const resolved = refEntities.find(e => e.id === ref.id); if (!resolved) return ref; // 4. 创建代理并缓存 const proxy = this.createProxy(resolved, refType); this.resolvedCache.set(cacheKey, proxy); return proxy; } /** * 清除缓存(数据更新时调用) */ clearCache() { this.resolvedCache.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<boolean>} 是否获取成功 * @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.saveDataToStorage(); // 5. 触发数据更新回调 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; } } 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; [响应] http://192.168.1.4:8080/app/all {status: 200, data: {…}, headers: Proxy} index.js? [sm]:56 收到数据更新回调 index.js? [sm]:136 开始更新表格数据 MiniProgramDataManager.js? [sm]:359 Fetch error: TypeError: Converting circular structure to JSON --> starting at object with constructor 'Object' | property 'bancai' -> object with constructor 'Array' | index 0 -> object with constructor 'Object' --- property 'caizhi' closes the circle at JSON.stringify (<anonymous>) at li.updateTable (index.js? [sm]:138) at li.updatePageData (index.js? [sm]:109) at index.js? [sm]:57 at MiniProgramDataManager.js? [sm]:479 at Array.forEach (<anonymous>) at MiniProgramDataManager.triggerCallbacks (MiniProgramDataManager.js? [sm]:479) at MiniProgramDataManager._callee2$ (MiniProgramDataManager.js? [sm]:356) at s (regeneratorRuntime.js?forceSync=true:1) at Generator.<anonymous> (regeneratorRuntime.js?forceSync=true:1)(env: Windows,mp,1.06.2412050; lib: 3.8.10) _callee2$ @ MiniProgramDataManager.js? [sm]:359 s @ regeneratorRuntime.js?forceSync=true:1 (anonymous) @ regeneratorRuntime.js?forceSync=true:1 (anonymous) @ regeneratorRuntime.js?forceSync=true:1 asyncGeneratorStep @ asyncToGenerator.js?forceSync=true:1 c @ asyncToGenerator.js?forceSync=true:1 Promise.then (async) asyncGeneratorStep @ asyncToGenerator.js?forceSync=true:1 c @ asyncToGenerator.js?forceSync=true:1 (anonymous) @ asyncToGenerator.js?forceSync=true:1 (anonymous) @ asyncToGenerator.js?forceSync=true:1 fetchAll @ MiniProgramDataManager.js? [sm]:319 onLoad @ index.js? [sm]:64 index.js? [sm]:56 收到数据更新回调 index.js? [sm]:136 开始更新表格数据 index.js? [sm]:67 数据加载失败: TypeError: Converting circular structure to JSON --> starting at object with constructor 'Object' | property 'bancai' -> object with constructor 'Array' | index 0 -> object with constructor 'Object' --- property 'caizhi' closes the circle at JSON.stringify (<anonymous>) at li.updateTable (index.js? [sm]:138) at li.updatePageData (index.js? [sm]:109) at index.js? [sm]:57 at MiniProgramDataManager.js? [sm]:479 at Array.forEach (<anonymous>) at MiniProgramDataManager.triggerCallbacks (MiniProgramDataManager.js? [sm]:479) at MiniProgramDataManager._callee2$ (MiniProgramDataManager.js? [sm]:360) at s (regeneratorRuntime.js?forceSync=true:1) at Generator.<anonymous> (regeneratorRuntime.js?forceSync=true:1)(env: Windows,mp,1.06.2412050; lib: 3.8.10)
07-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值