dengjunjie
2 天以前 03dd618453fa57bd5b884c0249c4d98f5db60035
添加WMSPDA权限、PDA程序
已删除2个文件
已修改26个文件
已添加566个文件
86226 ■■■■■ 文件已修改
WMS/WIDESEA_WMSClient/src/router/viewGird.js 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSClient/src/views/system/PermissionPDA.vue 369 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/.vs/ProjectEvaluation/widesea_wmsserver.metadata.v9.bin 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/.vs/ProjectEvaluation/widesea_wmsserver.projects.v9.bin 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/DesignTimeBuild/.dtbcache.v2 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/FileContentIndex/5982a579-0600-4e48-a0b6-4c24286fa466.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/FileContentIndex/71ed4636-506d-4cb2-9b3e-484d7c67b28e.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/FileContentIndex/939e7db4-35c5-4fd0-9ad4-dfbe45b17c20.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/FileContentIndex/d6ecada3-a5d4-41fd-9590-39670f5b6543.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/FileContentIndex/f28f4da7-c4a5-4ea2-905b-0f53049bf3a6.vsidx 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v17/.futdcache.v2 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v17/.suo 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_IInboundRepository/IInboundOrderRepository.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_IInboundService/IInboundOrderDetailService.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_IInboundService/IInboundOrderService.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_ISystemRepository/ISys_MenuRepository.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_ISystemService/ISys_MenuService.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_ISystemService/ISys_RoleService.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_InboundRepository/InboundOrderRepository.cs 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_InboundService/Base/InboundOrderService.cs 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_InboundService/Service/InboundOrderDetailService.cs 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_SystemRepository/Sys_MenuRepository.cs 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_SystemService/Sys_MenuService.cs 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_SystemService/Sys_RoleService.cs 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Inbound/InboundOrderController.cs 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Inbound/InboundOrderDetailController.cs 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/PDAController.cs 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_DictionaryController.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_DictionaryListController.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_LogController.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_MenuController.cs 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_RoleAuthController.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_RoleController.cs 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/.eslintignore 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/.hbuilderx/launch.json 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/.vscode/launch.json 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/App.vue 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/LICENSE 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/common/config.js 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/common/http.interceptor.js 136 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/common/uni-ui.scss 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/components/uni-section/config.json 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/components/uni-section/readme.md 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/components/uni-section/uni-section.vue 136 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/main.js 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/manifest.json 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/package-lock.json 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/package.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages.json 196 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/home/home.vue 282 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/index/index.vue 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/login/login.vue 531 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/AGVFinish.vue 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/AGVTasks.vue 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/InEmpty.vue 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/InspectIn.vue 612 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/OutEmpty.vue 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/OutProOrder.vue 426 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/ProBack.vue 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/ProEmptyBack.vue 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/ProOutOrderView.vue 214 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/QueryData.vue 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/TakeStock.vue 437 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/TakeStockOrder.vue 209 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/boxing.vue 650 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/inboundorder.vue 216 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/index.vue 173 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/outboundorder.vue 177 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/outraworderboxing.vue 214 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/pickingMat.vue 471 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/raworderboxing.vue 558 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/receiveorder.vue 209 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/pages/stash/receiveorderoutbound.vue 760 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/BC.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/CK.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/CP.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/CPCK.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/CSJ.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/FL.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/GM.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/JX.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/KCCX.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/KCPD.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/RK.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/SH.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/WMSRK.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/YM.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/ZXRK.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/center-selected.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/center.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/fail.mp3 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/favicon.ico 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/iconfont.css 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/index-selected.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/index.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/login_bottom_bg.jpg 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/login_top2.jpg 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/login_top3.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/logo.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/pp.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/repeat.mp3 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/static/success.mp3 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/template.h5.html 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/README.md 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-action-sheet/tn-action-sheet.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-avatar-group/tn-avatar-group.vue 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-avatar/tn-avatar.vue 298 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-badge/tn-badge.vue 173 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-button/tn-button.vue 302 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-calendar/tn-calendar.vue 707 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-car-keyboard/tn-car-keyboard.vue 320 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-cascade-selection/tn-cascade-selection.vue 654 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-checkbox-group/tn-checkbox-group.vue 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-checkbox/tn-checkbox.vue 328 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-circle-progress/tn-circle-progress.vue 223 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-collapse-item/tn-collapse-item.vue 236 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-collapse/tn-collapse.vue 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-color-icon/tn-color-icon.vue 318 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-column-notice/tn-column-notice.vue 251 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-count-down/tn-count-down.vue 314 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-count-scroll/tn-count-scroll.vue 171 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-count-to/tn-count-to.vue 231 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-cropper/index.wxs 328 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-cropper/tn-cropper.vue 570 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-custom-swiper-item/index.wxs 288 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-custom-swiper-item/tn-custom-swiper-item.vue 277 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-custom-swiper/tn-custom-swiper.vue 535 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-drag/index.wxs 265 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-drag/tn-drag.vue 278 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-empty/tn-empty.vue 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-fab/tn-fab.vue 523 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-form-item/tn-form-item.vue 457 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-form/tn-form.vue 139 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-goods-nav/tn-goods-nav.vue 382 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-grid-item/tn-grid-item.vue 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-grid/tn-grid.vue 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-image-upload-drag/tn-image-upload-drag.vue 995 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-image-upload/tn-image-upload.vue 645 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-index-anchor/tn-index-anchor.vue 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-index-list/tn-index-list.vue 361 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-input/tn-input.vue 427 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-keyboard/tn-keyboard.vue 220 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-landscape/tn-landscape.vue 225 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-lazy-load/tn-lazy-load.vue 254 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-line-progress/tn-line-progress.vue 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-list-cell/tn-list-cell.vue 209 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-list-view/tn-list-view.vue 184 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-load-more/tn-load-more.vue 188 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-loading/tn-loading.vue 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-modal/tn-modal.vue 246 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-nav-bar/tn-nav-bar.vue 355 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-notice-bar/tn-notice-bar.vue 209 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-number-box/tn-number-box.vue 401 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-number-keyboard/tn-number-keyboard.vue 182 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-picker/tn-picker.vue 723 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-popup/tn-popup.vue 491 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-radio-group/tn-radio-group.vue 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-radio/tn-radio.vue 265 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-rate/tn-rate.vue 334 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-read-more/tn-read-more.vue 222 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-row-notice/tn-row-notice.vue 301 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-scroll-list/tn-scroll-list.vue 177 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-scroll-view/tn-scroll-view.vue 401 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-select/tn-select.vue 380 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-sign-board/tn-sign-board.vue 690 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-skeleton/tn-skeleton.vue 254 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-slider/tn-slider.vue 255 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-stack-swiper/index-h5.wxs 657 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-stack-swiper/index.wxs 657 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-stack-swiper/tn-stack-swiper.vue 284 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-steps/tn-steps.vue 346 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-sticky/tn-sticky.vue 186 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-subsection/tn-subsection.vue 410 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-swipe-action-item/index.wxs 230 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-swipe-action-item/tn-swipe-action-item.vue 236 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-swipe-action/tn-swipe-action.vue 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-swiper/tn-swiper.vue 364 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-switch/tn-switch.vue 241 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-tabbar/tn-tabbar.vue 576 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-table/tn-table.vue 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-tabs-swiper/tn-tabs-swiper.vue 444 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-tabs/tn-tabs.vue 340 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-tag/tn-tag.vue 223 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-td/tn-td.vue 307 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-time-line-item/tn-time-line-item.vue 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-time-line-item/tn-time-line-item.vue_bk 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-time-line/tn-time-line.vue 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-time-line/tn-time-line.vue_bk 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-tips/tn-tips.vue 240 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-toast/tn-toast.vue 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-tr/tn-tr.vue 210 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-tree-node/tn-tree-node.vue 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-tree-view/tn-tree-view.vue 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-verification-code-input/tn-verification-code-input.vue 324 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-verification-code/tn-verification-code.vue 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/components/tn-waterfall/tn-waterfall.vue 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/iconfont.css 1645 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/index.js 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/index.scss 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/config/color.js 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/config/zIndex.js 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/css/color.scss 563 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/css/main.scss 722 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/css/style.h5.scss 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/css/style.mp.scss 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/function/$parent.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/function/array.js 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/function/color.js 270 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/function/colorUtils.js 270 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/function/deepClone.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/function/message.js 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/function/messageUtils.js 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/function/number.js 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/function/string.js 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/function/test.js 232 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/function/updateCustomBarInfo.js 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/function/uuid.js 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/mixin/components_color.js 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/mixin/mixin.js 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/mixin/mpShare.js 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/mixin/touch.js 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/utils/area.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/utils/async-validator.js 1356 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/utils/calendar.js 546 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/utils/city.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/utils/emitter.js 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/libs/utils/province.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/tuniao-ui/theme.scss 183 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-badge/changelog.md 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-badge/components/uni-badge/uni-badge.vue 268 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-badge/package.json 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-badge/readme.md 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-card/changelog.md 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-card/components/uni-card/uni-card.vue 270 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-card/package.json 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-card/readme.md 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-combox/changelog.md 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-combox/components/uni-combox/uni-combox.vue 275 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-combox/package.json 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-combox/readme.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-data-checkbox/changelog.md 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue 821 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-data-checkbox/package.json 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-data-checkbox/readme.md 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-data-select/changelog.md 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue 449 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-data-select/package.json 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-data-select/readme.md 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-easyinput/changelog.md 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-easyinput/components/uni-easyinput/common.js 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue 639 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-easyinput/package.json 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-easyinput/readme.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-forms/changelog.md 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue 631 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-forms/components/uni-forms/uni-forms.vue 397 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-forms/components/uni-forms/utils.js 293 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-forms/components/uni-forms/validate.js 486 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-forms/package.json 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-forms/readme.md 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-group/changelog.md 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-group/components/uni-group/uni-group.vue 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-group/package.json 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-group/readme.md 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-icons/changelog.md 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-icons/components/uni-icons/icons.js 1169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-icons/components/uni-icons/uni-icons.vue 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-icons/components/uni-icons/uni.ttf 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-icons/components/uni-icons/uniicons.css 663 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-icons/components/uni-icons/uniicons.ttf 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-icons/package.json 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-icons/readme.md 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-id/changelog.md 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-id/package.json 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-id/readme.md 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/LICENSE.md 201 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/index.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package-lock.json 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package.json 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-list/changelog.md 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue 571 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue 530 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-list/components/uni-list/uni-list.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-list/components/uni-list/uni-refresh.vue 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-list/components/uni-list/uni-refresh.wxs 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-list/package.json 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-list/readme.md 346 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-load-more/changelog.md 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue 399 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-load-more/package.json 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-load-more/readme.md 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-nav-bar/changelog.md 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue 357 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-nav-bar/package.json 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-nav-bar/readme.md 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-popup/changelog.md 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue 275 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue 187 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-popup/components/uni-popup/i18n/en.json 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-popup/components/uni-popup/i18n/index.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-popup/components/uni-popup/keypress.js 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-popup/components/uni-popup/popup.js 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-popup/components/uni-popup/uni-popup.vue 473 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-popup/package.json 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-popup/readme.md 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-scss/changelog.md 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-scss/index.scss 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-scss/package.json 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-scss/readme.md 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-scss/styles/index.scss 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-scss/styles/setting/_border.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-scss/styles/setting/_color.scss 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-scss/styles/setting/_radius.scss 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-scss/styles/setting/_space.scss 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-scss/styles/setting/_styles.scss 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-scss/styles/setting/_text.scss 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-scss/styles/setting/_variables.scss 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-scss/styles/tools/functions.scss 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-scss/theme.scss 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-scss/variables.scss 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-search-bar/changelog.md 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-search-bar/components/uni-search-bar/i18n/en.json 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-search-bar/components/uni-search-bar/i18n/index.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hans.json 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hant.json 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-search-bar/components/uni-search-bar/uni-search-bar.vue 298 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-search-bar/package.json 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-search-bar/readme.md 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-segmented-control/changelog.md 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-segmented-control/package.json 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-segmented-control/readme.md 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-transition/changelog.md 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-transition/components/uni-transition/createAnimation.js 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-transition/components/uni-transition/uni-transition.vue 286 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-transition/package.json 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uni_modules/uni-transition/readme.md 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/apk/apkurl 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/apk/cmManifestCache.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/certdata 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/cloudcertificate/certini 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/.manifest/icon-android-hdpi.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/.manifest/icon-android-xhdpi.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/.manifest/icon-android-xxhdpi.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/.manifest/icon-android-xxxhdpi.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappchooselocation.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniapperror.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappes6.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappopenlocation.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniapppicker.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappquill.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappquillimageresize.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappscan.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappsuccess.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappview.html 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/app-config-service.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/app-config.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/app-service.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/app-view.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/manifest.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/BC.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/CK.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/CP.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/CPCK.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/CSJ.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/FL.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/GM.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/JX.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/KCCX.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/KCPD.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/RK.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/SH.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/WMSRK.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/YM.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/ZXRK.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/center-selected.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/center.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/fail.mp3 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/favicon.ico 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/iconfont.css 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/index-selected.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/index.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/login_bottom_bg.jpg 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/login_top2.jpg 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/login_top3.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/logo.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/pp.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/repeat.mp3 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/success.mp3 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/uni_modules/uni-icons/components/uni-icons/uniicons.ttf 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/view.css 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/view.umd.min.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/1024x1024.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/120x120.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/144x144.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/152x152.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/167x167.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/180x180.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/192x192.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/20241228155440.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/20x20.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/29x29.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/40x40.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/58x58.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/60x60.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/72x72.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/76x76.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/80x80.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/87x87.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/96x96.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/res/icons/logo.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappchooselocation.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniapperror.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappes6.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappopenlocation.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniapppicker.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappquill.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappquillimageresize.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappscan.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappsuccess.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappview.html 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/app-config-service.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/app-config.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/app-service.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/app-view.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/manifest.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/center-selected.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/center.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/favicon.ico 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/index-selected.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/index.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/login_bottom_bg.jpg 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/login_top2.jpg 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/login_top3.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/logo.png 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/uni_modules/uni-icons/components/uni-icons/uniicons.ttf 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/view.css 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/view.umd.min.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/LICENSE 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/README.md 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-action-sheet/u-action-sheet.vue 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-alert-tips/u-alert-tips.vue 256 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue 290 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-avatar-cropper/weCropper.js 1265 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-avatar/u-avatar.vue 244 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-back-top/u-back-top.vue 153 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-badge/u-badge.vue 216 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-button/u-button.vue 596 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-calendar/u-calendar.vue 639 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-car-keyboard/u-car-keyboard.vue 257 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-card/u-card.vue 299 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-cell-group/u-cell-group.vue 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-cell-item/u-cell-item.vue 316 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-checkbox-group/u-checkbox-group.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-checkbox/u-checkbox.vue 284 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-circle-progress/u-circle-progress.vue 220 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-col/u-col.vue 156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-collapse-item/u-collapse-item.vue 204 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-collapse/u-collapse.vue 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-column-notice/u-column-notice.vue 237 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-count-down/u-count-down.vue 318 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-count-to/u-count-to.vue 241 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-divider/u-divider.vue 153 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-dropdown-item/u-dropdown-item.vue 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-dropdown/u-dropdown.vue 298 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-empty/u-empty.vue 193 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-field/u-field.vue 384 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-form-item/u-form-item.vue 431 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-form/u-form.vue 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-full-screen/u-full-screen.vue 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-gap/u-gap.vue 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-grid-item/u-grid-item.vue 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-grid/u-grid.vue 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-icon/u-icon.vue 336 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-image/u-image.vue 266 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-index-anchor/u-index-anchor.vue 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-index-list/u-index-list.vue 315 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-input/u-input.vue 387 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-keyboard/u-keyboard.vue 217 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-lazy-load/u-lazy-load.vue 244 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-line-progress/u-line-progress.vue 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-line/u-line.vue 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-link/u-link.vue 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-loading-page/u-loading-page.vue 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-loading/u-loading.vue 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-loadmore/u-loadmore.vue 203 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-mask/u-mask.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-message-input/u-message-input.vue 311 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-modal/u-modal.vue 283 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-navbar/u-navbar.vue 315 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-no-network/u-no-network.vue 233 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-notice-bar/u-notice-bar.vue 272 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-number-box/u-number-box.vue 363 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-number-keyboard/u-number-keyboard.vue 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-parse/libs/CssHandler.js 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-parse/libs/MpHtmlParser.js 580 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-parse/libs/config.js 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-parse/libs/handler.wxs 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-parse/libs/trees.vue 505 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-parse/u-parse.vue 645 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-picker/u-picker.vue 676 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-popup/u-popup.vue 456 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-radio-group/u-radio-group.vue 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-radio/u-radio.vue 271 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-rate/u-rate.vue 275 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-read-more/u-read-more.vue 179 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-row-notice/u-row-notice.vue 269 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-row/u-row.vue 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-search/u-search.vue 342 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-section/u-section.vue 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-select/u-select.vue 417 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-skeleton/u-skeleton.vue 199 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-slider/u-slider.vue 257 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-steps/u-steps.vue 200 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-sticky/u-sticky.vue 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-subsection/u-subsection.vue 355 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-swipe-action/u-swipe-action.vue 255 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-swiper/u-swiper.vue 340 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-switch/u-switch.vue 163 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-tabbar/u-tabbar.vue 330 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-table/u-table.vue 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-tabs-swiper/u-tabs-swiper.vue 488 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-tabs/u-tabs.vue 368 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-tag/u-tag.vue 294 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-td/u-td.vue 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-th/u-th.vue 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-time-line-item/u-time-line-item.vue 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-time-line/u-time-line.vue 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-toast/u-toast.vue 220 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-top-tips/u-top-tips.vue 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-tr/u-tr.vue 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-upload/u-upload.vue 654 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-verification-code/u-verification-code.vue 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/components/u-waterfall/u-waterfall.vue 176 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/iconfont.css 910 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/index.js 141 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/index.scss 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/config/config.js 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/config/zIndex.js 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/css/color.scss 155 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/css/common.scss 176 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/css/style.components.scss 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/css/style.h5.scss 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/css/style.mp.scss 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/css/style.nvue.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/css/style.vue.scss 175 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/$parent.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/addUnit.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/bem.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/color.js 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/colorGradient.js 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/debounce.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/deepClone.js 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/deepMerge.js 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/getParent.js 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/guid.js 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/md5.js 385 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/queryParams.js 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/random.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/randomArray.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/route.js 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/sys.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/test.js 232 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/throttle.js 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/timeFormat.js 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/timeFrom.js 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/toast.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/trim.js 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/function/type2icon.js 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/mixin/mixin.js 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/mixin/mpShare.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/request/index.js 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/store/index.js 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/util/area.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/util/async-validator.js 1356 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/util/city.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/util/emitter.js 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/libs/util/province.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/package.json 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/uview-ui/theme.scss 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
吉安PDA/vue.config.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WMS/WIDESEA_WMSClient/src/router/viewGird.js
@@ -15,7 +15,11 @@
    name: 'permission',
    component: () => import('@/views/system/Permission.vue')
  },
  {
    path: '/permissionPDA',
    name: 'permissionPDA',
    component: () => import('@/views/system/PermissionPDA.vue')
  },
  {
    path: '/Sys_Dictionary',
    name: 'Sys_Dictionary',
@@ -45,7 +49,7 @@
    path: '/materielInfo',
    name: 'materielInfo',
    component: () => import('@/views/basic/materielInfo.vue')
  },
  },
  {
    path: '/cachePoint',
    name: 'cachePoint',
@@ -91,20 +95,20 @@
    path: '/task',
    name: 'task',
    component: () => import('@/views/taskinfo/task.vue')
  },
  },
  {
    path: '/task_hty',
    name: 'task_hty',
    component: () => import('@/views/taskinfo/task_hty.vue')
  },{
  }, {
    path: '/stockView',
    name: 'stockView',
    component: () => import('@/views/stock/stockView.vue')
  },{
  }, {
    path: '/StockQuantityChangeRecord',
    name: 'StockQuantityChangeRecord',
    component: () => import('@/views/record/stockQuantityChangeRecord.vue')
  },{
  }, {
    path: '/locationStatusChangeRecord',
    name: 'locationStatusChangeRecord',
    component: () => import('@/views/record/locationStatusChangeRecord.vue')
WMS/WIDESEA_WMSClient/src/views/system/PermissionPDA.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,369 @@
<template>
  <div class="role-container">
    <div class="role-tree-left flex-col">
      <div class="title"><i class="el-icon-user"></i>角色列表</div>
      <el-scrollbar class="el-role-list">
        <el-tree
          :data="tree"
          @node-click="nodeClick"
          node-key="id"
          :default-expanded-keys="openKeys"
          :expand-on-click-node="false"
          style="padding: 5px 0; margin-right: 2px"
        >
          <template #default="{ data }">
            <div class="action-group">
              <div class="action-text">
                {{ data.roleName }}
              </div>
            </div>
          </template>
        </el-tree>
      </el-scrollbar>
    </div>
    <div class="role-tree-right flex-col">
      <div class="title">
        <div><i class="el-icon-folder-opened"></i>PDA菜单权限</div>
        <el-button type="primary" @click="save">保存</el-button>
      </div>
      <el-scrollbar class="el-role-list">
        <el-tree
        ref="eltreerole"
          @check-change="leftCheckChange"
          @check="nodeCheck"
          :data="roleTree"
          :show-checkbox="false"
          style="padding: 15px"
          node-key="id"
          default-expand-all
          :expand-on-click-node="false"
        >
          <template #default="{ data }">
            <div class="action-group">
              <div
                class="action-text"
                :style="{ width: (4 - data.lv) * 18 + 150 + 'px' }"
              >
                <el-checkbox v-model="data.leftCk" @change="allChange(data)">{{
                  // data.text + (data.isApp ? "(app)" : "")
                  data.text
                }}</el-checkbox>
              </div>
              <div class="action-item">
                <el-checkbox
                  v-for="(item, index) in data.actions"
                  :key="index"
                  v-model="item.checked"
                  @change="actionChange(data, item.checked)"
                  >{{ item.text }}</el-checkbox
                >
              </div>
            </div>
          </template>
        </el-tree>
      </el-scrollbar>
    </div>
  </div>
</template>
<script>
import { defineComponent, ref, reactive, getCurrentInstance } from "vue";
import http from "@/../src/api/http.js";
export default defineComponent({
  setup() {
    const selectId = ref(-1);
    const checked = ref(false);
    const tree = reactive([]);
    const list = reactive([]);
    const roles = reactive([]);
    const roleList = reactive([]);
    const roleTree = reactive([]);
    const openKeys = reactive([]);
    const leftCheckChange = (node, selected) => {
      node.actions.forEach((x, index) => {
        x.checked = selected;
      });
    };
    const nodeCheck = (node, data) => {
      let rootData = roleList.find((x) => {
        return x.id === node.pid;
      });
      if (rootData && rootData.actions.length) {
        rootData.actions[0].checked =
          node.actions.some((x) => {
            return x.checked;
          }) ||
          data.halfCheckedNodes.some((x) => {
            return x.id === node.pid;
          });
      }
    };
    const allChange = (data) => {
      data.actions.forEach((item) => {
        item.checked = data.leftCk;
      });
      if (!data.children) {
        return;
      }
      setChildrenChecked(data, data.leftCk);
    };
    const setChildrenChecked = (data, ck) => {
      data.children.forEach((item) => {
        item.leftCk = ck;
        item.actions.forEach((c) => {
          c.checked = ck;
        });
        if (item.children) {
          setChildrenChecked(item, ck);
        }
      });
    };
    const actionChange = (data, ck) => {
      ck =
        data.actions.filter((x) => {
          return x.checked;
        }).length == data.actions.length;
      data.leftCk = ck;
    };
    const load = () => {
      const url = "api/Sys_Role/getUserChildRoles";
      http.post(url, {}, true).then((result) => {
        if (!result.status) return;
        list.splice(0);
        list.push(...result.data);
        list.forEach((x) => {
          if (x.parentId == 0) {
            x.lv = 1;
            x.children = [];
            tree.push(x);
            getTree(x.id, x);
          }
        });
        openKeys.push(tree[0].id);
        selectId.value = openKeys[0];
      });
    };
    const getTree = (id, data) => {
      list.forEach((x) => {
        if (x.parentId == id) {
          x.lv = data.lv + 1;
          if (!data.children) data.children = [];
          data.children.push(x);
          getTree(x.id, x);
        }
      });
    };
    const nodeClick = (node, selected) => {
      selectId.value = node.id;
      getUserRole(node);
    };
    const getUserRole = (item) => {
      selectId.value = item.id;
      roleList.forEach((x) => {
        x.actions.forEach((a) => {
          a.checked = false;
        });
      });
      let url = `/api/Sys_Role/getUserTreePermissionPDA?roleId=${item.id}`;
      http.post(url, {}, true).then((result) => {
        if (!result.status) return;
        result.data.forEach((item) => {
          if (item.actions.length == 0) return;
          let sourceItem = roleList.find((f) => f.id == item.id);
          if (!sourceItem) return;
          item.actions.forEach((actions) => {
            sourceItem.actions.forEach((soure) => {
              if (soure.value == actions.value) {
                soure.checked = true;
              }
            });
          });
        });
      });
    };
    const getRoleTree = (id, data, isRootId) => {
      roleList.forEach((x) => {
        if (x.pid == id) {
          x.lv = data.lv + 1;
          if (isRootId) {
            x.rootId = id;
          }
          if (!data.children) data.children = [];
          data.children.push(x);
          getRoleTree(x.id, x, isRootId);
        }
      });
    };
    const getCurrentTreePermission = () => {
      let url = "/api/Sys_Role/getCurrentTreePermissionPDA";
      http.post(url, {}, true).then((result) => {
        if (!result.status) return;
        roleList.splice(0);
        roles.splice(0);
        roleList.push(...result.data.tree);
        roles.push(...result.data.roles);
        roleList.forEach((x) => {
          if (x.pid == 0) {
            x.lv = 1;
            x.children = [];
            roleTree.push(x);
            getRoleTree(x.id, x);
          }
        });
      });
    };
    let $message =
      getCurrentInstance().appContext.config.globalProperties.$message;
    const save = () => {
      if (selectId.value <= 0) {
        return $message.error("请选择角色!");
      }
      // var keys = this.$refs.eltreerole.getCheckedKeys().concat(this.$refs.eltreerole.getHalfCheckedKeys());
      // console.log(keys)
      let userPermissions = [];
      // keys.forEach((x) => {
      //   userPermissions.push({
      //     id: x,
      //     actions: null,
      //     text: "PDA",
      //   });
      // });
      roleList.forEach((x) => {
        let checkedPermission = x.actions.filter((f) => {
          return f.checked;
        });
        if (checkedPermission.length > 0) {
          let actions = checkedPermission.map((m) => {
            return { text: m.text, value: m.value };
          });
          userPermissions.push({
            id: x.id,
            actions: actions,
          });
        }
      });
      let url = `api/Sys_Role/SavePermissionPDA?roleId=${selectId.value}`;
      http.post(url, userPermissions, true).then((result) => {
        $message[result.status ? "success" : "error"](result.message);
      });
    };
    load();
    getCurrentTreePermission();
    return {
      list,
      nodeClick,
      checked,
      tree,
      selectId,
      openKeys,
      getUserRole,
      roles,
      roleList,
      getCurrentTreePermission,
      leftCheckChange,
      nodeCheck,
      roleTree,
      allChange,
      actionChange,
      save,
    };
  },
});
</script>
<style lang="less" scoped>
.role-container {
  position: absolute;
  background: #f6f6f6;
  height: 100%;
  width: 100%;
  padding: 10px;
  display: flex;
  .flex-col {
    display: flex;
    flex-direction: column;
  }
  .role-tree-left {
    border: 1px solid #f2f2f2;
    background: #fff;
    width: 230px;
    margin-right: 10px;
    .title {
      i {
        margin-left: 10px;
      }
    }
  }
  .role-tree-right {
    background: #fff;
    border: 1px solid #f2f2f2;
    width: 0;
    flex: 1;
    .title {
      display: flex;
      i {
        margin-left: 10px;
      }
      div {
        flex: 1;
      }
    }
    .action-group {
      display: flex;
      // line-height: 32px;
      justify-content: center;
      align-items: center;
      label {
        float: left;
      }
      .action-text {
        line-height: 33px;
        label {
          margin-right: 5px;
        }
      }
    }
  }
  .title {
    padding: 10px;
    background: rgb(246 250 255);
    font-weight: bold;
    font-size: 14px;
    letter-spacing: 2px;
  }
  .el-role-list {
    flex: 1;
    height: 0;
    overflow-x: hidden;
  }
}
.role-tree-left ::v-deep(.el-tree-node__content) {
  cursor: pointer;
  height: auto;
  padding: 5px;
  margin: 2px 10px;
  font-size: 15px;
}
.role-tree-left ::v-deep(.el-tree-node__content:hover) {
  background: #f4f4f4;
  border-radius: 20px;
}
.role-tree-left ::v-deep(.is-current > .el-tree-node__content:first-child) {
  background: #f2f2f2;
  border-radius: 20px;
}
.role-tree-right ::v-deep(.el-tree-node__content) {
  margin-bottom: 5px;
  height: auto;
}
.role-tree-right ::v-deep(.el-checkbox__label) {
  position: relative;
  top: 2px;
}
</style>
WMS/WIDESEA_WMSServer/.vs/ProjectEvaluation/widesea_wmsserver.metadata.v9.bin
Binary files differ
WMS/WIDESEA_WMSServer/.vs/ProjectEvaluation/widesea_wmsserver.projects.v9.bin
Binary files differ
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/DesignTimeBuild/.dtbcache.v2
Binary files differ
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/FileContentIndex/5982a579-0600-4e48-a0b6-4c24286fa466.vsidx
Binary files differ
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/FileContentIndex/71ed4636-506d-4cb2-9b3e-484d7c67b28e.vsidx
Binary files differ
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/FileContentIndex/939e7db4-35c5-4fd0-9ad4-dfbe45b17c20.vsidx
Binary files differ
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/FileContentIndex/d6ecada3-a5d4-41fd-9590-39670f5b6543.vsidx
Binary files differ
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/FileContentIndex/f28f4da7-c4a5-4ea2-905b-0f53049bf3a6.vsidx
Binary files differ
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v17/.futdcache.v2
Binary files differ
WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v17/.suo
Binary files differ
WMS/WIDESEA_WMSServer/WIDESEA_IInboundRepository/IInboundOrderRepository.cs
@@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Model.Models;
@@ -10,5 +11,6 @@
{
    public interface IInboundOrderRepository : IRepository<Dt_InboundOrder>
    {
        WebResponseContent GetInboundOrders(SaveModel saveModel);
    }
}
WMS/WIDESEA_WMSServer/WIDESEA_IInboundService/IInboundOrderDetailService.cs
@@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Core;
using WIDESEA_Core.BaseServices;
using WIDESEA_IInboundRepository;
using WIDESEA_Model.Models;
@@ -13,6 +14,7 @@
    {
        IInboundOrderDetailRepository Repository { get; }
        WebResponseContent GetInboundOrderDetails(SaveModel saveModel);
        List<Dt_InboundOrderDetail> UpdateReceiptQuantity(List<Dt_InboundOrderDetail> inboundOrderDetails, decimal receiptQuantity);
    }
}
WMS/WIDESEA_WMSServer/WIDESEA_IInboundService/IInboundOrderService.cs
@@ -26,5 +26,6 @@
        WebResponseContent CancelIn(HouseCancelIn houseCancelIn);
        Dt_InboundOrder GetInboundOrder(string InboundOrderNo);
        WebResponseContent GetInboundOrders(SaveModel saveModel);
    }
}
WMS/WIDESEA_WMSServer/WIDESEA_ISystemRepository/ISys_MenuRepository.cs
@@ -23,5 +23,6 @@
        object GetMenu(List<int> menuIds);
        object GetTreeItem(int menuId);
        List<MenuDTO> GetAllMenuPDA();
    }
}
WMS/WIDESEA_WMSServer/WIDESEA_ISystemService/ISys_MenuService.cs
@@ -30,5 +30,7 @@
        WebResponseContent Save(Sys_Menu menu);
        WebResponseContent DelMenu(int menuId);
        List<MenuDTO> GetUserMenuListPDA(int roleId);
        object? GetTreeMenuPDAStash(int parentId);
    }
}
WMS/WIDESEA_WMSServer/WIDESEA_ISystemService/ISys_RoleService.cs
@@ -19,9 +19,10 @@
        List<RoleNodes> GetAllChildren(int roleId);
        WebResponseContent GetCurrentTreePermission();
        WebResponseContent GetCurrentTreePermissionPDA();
        WebResponseContent GetUserTreePermission(int role_Id);
        WebResponseContent GetUserTreePermissionPDA(int roleId);
        WebResponseContent SavePermission(List<UserPermissionDTO> userPermissions, int roleId);
        WebResponseContent SavePermissionPDA(List<UserPermissionDTO> userPermissions, int roleId);
    }
}
WMS/WIDESEA_WMSServer/WIDESEA_InboundRepository/InboundOrderRepository.cs
@@ -3,7 +3,10 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.Enums;
using WIDESEA_Core.Helper;
using WIDESEA_IInboundRepository;
using WIDESEA_Model.Models;
@@ -17,5 +20,32 @@
        {
            _unitOfWorkManage = unitOfWorkManage;
        }
        public WebResponseContent GetInboundOrders(SaveModel saveModel)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                int pageNo = saveModel.MainData["pageNo"].ObjToInt();
                string? orderNo = saveModel.MainData["orderNo"].ToString();
                int warehouseId = saveModel.MainData["warehouseId"].ObjToInt();
                List<Dt_InboundOrder> dt_ReceiveOrders = new List<Dt_InboundOrder>();
                if (string.IsNullOrEmpty(orderNo))
                {
                    dt_ReceiveOrders = Db.Queryable<Dt_InboundOrder>().Where(x => x.OrderStatus < InboundStatusEnum.入库完成.ObjToInt() && x.WarehouseId == warehouseId).Includes(x => x.Details).OrderByDescending(x => x.CreateDate).ToPageList(pageNo, 10);
                }
                else
                {
                    dt_ReceiveOrders = Db.Queryable<Dt_InboundOrder>().Where(x => (x.OrderNo.Contains(orderNo)) && x.OrderStatus < InboundStatusEnum.入库完成.ObjToInt() && x.WarehouseId == warehouseId).Includes(x => x.Details).OrderByDescending(x => x.CreateDate).ToPageList(pageNo, 10);
                }
                content.OK(data: dt_ReceiveOrders);
            }
            catch (Exception ex)
            {
                content.Error(ex.Message);
            }
            return content;
        }
    }
}
WMS/WIDESEA_WMSServer/WIDESEA_InboundService/Base/InboundOrderService.cs
@@ -313,6 +313,33 @@
            return content;
        }
        public WebResponseContent GetInboundOrders(SaveModel saveModel)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                int pageNo = saveModel.MainData["pageNo"].ObjToInt();
                string? orderNo = saveModel.MainData["orderNo"].ToString();
                int warehouseId = saveModel.MainData["warehouseId"].ObjToInt();
                List<Dt_InboundOrder> dt_ReceiveOrders = new List<Dt_InboundOrder>();
                if (string.IsNullOrEmpty(orderNo))
                {
                    dt_ReceiveOrders = Db.Queryable<Dt_InboundOrder>().Where(x => x.OrderStatus < InboundStatusEnum.入库完成.ObjToInt() && x.WarehouseId == warehouseId).Includes(x => x.Details).OrderByDescending(x => x.CreateDate).ToPageList(pageNo, 10);
                }
                else
                {
                    dt_ReceiveOrders = Db.Queryable<Dt_InboundOrder>().Where(x => (x.OrderNo.Contains(orderNo)) && x.OrderStatus < InboundStatusEnum.入库完成.ObjToInt() && x.WarehouseId == warehouseId).Includes(x => x.Details).OrderByDescending(x => x.CreateDate).ToPageList(pageNo, 10);
                }
                content.OK(data: dt_ReceiveOrders);
            }
            catch (Exception ex)
            {
                content.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
        /// éªŒè¯å•据添加DTO对象
        /// </summary>
WMS/WIDESEA_WMSServer/WIDESEA_InboundService/Service/InboundOrderDetailService.cs
@@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Core;
using WIDESEA_Core.BaseServices;
using WIDESEA_Core.Enums;
using WIDESEA_Core.Helper;
@@ -48,5 +49,21 @@
        {
        }
        public WebResponseContent GetInboundOrderDetails(SaveModel saveModel)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                string orderNo = saveModel.MainData["orderNo"].ToString();
                Dt_InboundOrder inboundOrder = Db.Queryable<Dt_InboundOrder>().Where(x => x.OrderNo == orderNo).Includes(x => x.Details).First();
                content.OK(data: inboundOrder.Details);
            }
            catch (Exception ex)
            {
                content.Error(ex.Message);
            }
            return content;
        }
    }
}
WMS/WIDESEA_WMSServer/WIDESEA_SystemRepository/Sys_MenuRepository.cs
@@ -201,5 +201,34 @@
                }).FirstOrDefault();
            return sysMenu;
        }
        public List<MenuDTO> GetAllMenuPDA()
        {
            if (App.User.IsRoleIdSuperAdmin(App.User.RoleId))
            {
                return GetAllPDAMenu();
            }
            List<int> menuIds = GetPermissions(App.User.RoleId).Select(x => x.MenuId).ToList();
            return GetAllPDAMenu().Where(x => menuIds.Contains(x.MenuId)).ToList();
        }
        public List<MenuDTO> GetAllPDAMenu()
        {
            List<Sys_Menu> menus = base.QueryData(x => (x.Enable == 1 || x.Enable == 2) && x.MenuType == 1).OrderByDescending(a => a.OrderNo).ThenByDescending(q => q.ParentId).ToList();
            List<MenuDTO> _menus = _mapper.Map<List<MenuDTO>>(menus);
            _menus.ForEach(x =>
            {
                if (!string.IsNullOrEmpty(x.Auth) && x.Auth.Length > 10)
                {
                    try
                    {
                        x.Actions = x.Auth.DeserializeObject<List<ActionDTO>>();
                    }
                    catch { }
                }
                x.Actions ??= new List<ActionDTO>();
            });
            string test = _menus.Serialize();
            return _menus;
        }
    }
}
WMS/WIDESEA_WMSServer/WIDESEA_SystemService/Sys_MenuService.cs
@@ -188,5 +188,21 @@
            return webResponse = WebResponseContent.Instance.OK("删除成功");
        }
        public List<MenuDTO> GetUserMenuListPDA(int roleId)
        {
            if (App.User.IsRoleIdSuperAdmin(roleId))
            {
                return BaseDal.GetAllMenuPDA();
            }
            List<int> menuIds = BaseDal.GetPermissions(roleId).Select(x => x.MenuId).ToList();
            return BaseDal.GetAllMenuPDA().Where(x => menuIds.Contains(x.MenuId)).ToList();
        }
        public object? GetTreeMenuPDAStash(int parentId)
        {
            List<MenuDTO> _menus = BaseDal.GetAllMenuPDA().Where(x => x.ParentId == parentId).ToList();
            return _menus;
        }
    }
}
WMS/WIDESEA_WMSServer/WIDESEA_SystemService/Sys_RoleService.cs
@@ -212,5 +212,136 @@
            return content;
        }
        public WebResponseContent GetCurrentTreePermissionPDA()
        {
            WebResponseContent content = GetCurrentUserTreePermissionPDA();
            int roleId = App.User.RoleId;
            return WebResponseContent.Instance.OK(null, new
            {
                tree = content.Data,
                roles = GetAllChildren(roleId)
            });
        }
        public WebResponseContent GetCurrentUserTreePermissionPDA()
        {
            return GetUserTreePermissionPDA(App.User.RoleId);
        }
        public WebResponseContent GetUserTreePermissionPDA(int roleId)
        {
            if (!App.User.IsRoleIdSuperAdmin(roleId) && App.User.RoleId != roleId)
            {
                if (!(GetAllChildren(App.User.RoleId)).Exists(x => x.Id == roleId))
                {
                    return WebResponseContent.Instance.Error("没有权限获取此角色的权限信息");
                }
            }
            //获取用户权限
            List<Permissions> permissions = _MenuRepository.GetPermissions(roleId);
            //权限用户权限查询所有的菜单信息
            List<MenuDTO> menus = _MenuService.GetUserMenuListPDA(roleId);
            //获取当前用户权限如:(Add,Search)对应的显示文本信息如:Add:添加,Search:查询
            var data = menus.Where(x => x.MenuType == 1).Select(x => new
            {
                Id = x.MenuId,
                Pid = x.ParentId,
                Text = x.MenuName,
                IsApp = x.MenuType == 1,
                Actions = _MenuService.GetActions(x.MenuId, x.Actions, permissions, roleId)
            });
            return WebResponseContent.Instance.OK(null, data);
        }
        /// <summary>
        /// ä¿å­˜è§’色权限
        /// </summary>
        /// <param name="userPermissions"></param>
        /// <param name="roleId"></param>
        /// <returns></returns>
        public WebResponseContent SavePermissionPDA(List<UserPermissionDTO> userPermissions, int roleId)
        {
            WebResponseContent content = new WebResponseContent();
            string message = "";
            try
            {
                if (!GetAllChildren(App.User.RoleId).Exists(x => x.Id == roleId))
                    return WebResponseContent.Instance.Error("没有权限修改此角色的权限信息");
                //当前用户的权限
                List<Permissions> permissions = _MenuRepository.GetPermissions(App.User.RoleId);
                List<int> originalMeunIds = new List<int>();
                List<int> menuIds = _MenuRepository.QueryData(x => x.MenuId, x => x.MenuType == 1);
                //被分配角色的权限
                List<Sys_RoleAuth> roleAuths = _RoleAuthRepository.QueryData(x => x.RoleId == roleId && menuIds.Contains(x.MenuId));
                List<Sys_RoleAuth> updateAuths = new List<Sys_RoleAuth>();
                foreach (UserPermissionDTO x in userPermissions)
                {
                    Permissions per = permissions.FirstOrDefault(p => p.MenuId == x.Id);
                    //不能分配超过当前用户的权限
                    if (per == null) continue;
                    //per.UserAuthArr.Contains(a.Value)校验权限范围
                    string[] arr = x.Actions == null || x.Actions.Count == 0
                      ? new string[0]
                      : x.Actions.Where(a => per.UserAuthArr.Contains(a.Value))
                      .Select(s => s.Value).ToArray();
                    //如果当前权限没有分配过,设置Auth_Id默认为0,表示新增的权限
                    var auth = roleAuths.Where(r => r.MenuId == x.Id).Select(s => new { s.AuthId, s.AuthValue, s.MenuId }).FirstOrDefault();
                    string newAuthValue = string.Join(",", arr);
                    //权限没有发生变化则不处理
                    if (auth == null || auth.AuthValue != newAuthValue)
                    {
                        updateAuths.Add(new Sys_RoleAuth()
                        {
                            RoleId = roleId,
                            MenuId = x.Id,
                            AuthValue = string.Join(",", arr),
                            AuthId = auth == null ? 0 : auth.AuthId,
                            ModifyDate = DateTime.Now,
                            Modifier = App.User.UserName,
                            CreateDate = DateTime.Now,
                            Creater = App.User.UserName
                        });
                    }
                    else
                    {
                        originalMeunIds.Add(auth.MenuId);
                    }
                }
                //更新权限
                _RoleAuthRepository.UpdateData(updateAuths);
                //新增的权限
                _RoleAuthRepository.AddData(updateAuths);
                //获取权限取消的权限
                int[] authIds = roleAuths.Where(x => userPermissions.Select(u => u.Id)
                 .ToList().Contains(x.MenuId) || originalMeunIds.Contains(x.MenuId))
                .Select(s => s.AuthId)
                .ToArray();
                List<Sys_RoleAuth> delAuths = roleAuths.Where(x => x.AuthValue != "" && !authIds.Contains(x.AuthId)).ToList();
                delAuths.ForEach(x =>
                {
                    x.AuthValue = "";
                });
                //将取消的权限设置为""
                _RoleAuthRepository.DeleteData(delAuths);
                int addCount = updateAuths.Where(x => x.AuthId <= 0).Count();
                int updateCount = updateAuths.Where(x => x.AuthId > 0).Count();
                string _version = DateTime.Now.ToString("yyyyMMddHHMMssfff");
                content.OK($"保存成功:新增加配菜单权限{addCount}条,更新菜单{updateCount}条,删除权限{delAuths.Count}条");
            }
            catch (Exception ex)
            {
                message = "异常信息:" + ex.Message + ex.StackTrace + ",";
            }
            return content;
        }
    }
}
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Inbound/InboundOrderController.cs
@@ -17,6 +17,16 @@
        public InboundOrderController(IInboundOrderService service) : base(service)
        {
        }
        /// <summary>
        /// æŸ¥è¯¢å…¥åº“单信息
        /// </summary>
        /// <returns></returns>
        [HttpPost, HttpGet, Route("GetInboundOrders")]
        public WebResponseContent GetInboundOrders([FromBody] SaveModel saveModel)
        {
            return Service.GetInboundOrders(saveModel);
        }
        /// <summary>
        /// WMS下发入库单据
        /// </summary>
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Inbound/InboundOrderDetailController.cs
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using WIDESEA_Core;
using WIDESEA_Core.BaseController;
using WIDESEA_IInboundService;
using WIDESEA_Model.Models;
@@ -13,5 +14,14 @@
        public InboundOrderDetailController(IInboundOrderDetailService service) : base(service)
        {
        }
        /// <summary>
        /// æŸ¥è¯¢å…¥åº“单详情
        /// </summary>
        /// <returns></returns>
        [HttpPost, HttpGet, Route("GetInboundOrderDetails")]
        public WebResponseContent GetInboundOrderDetails([FromBody] SaveModel saveModel)
        {
            return Service.GetInboundOrderDetails(saveModel);
        }
    }
}
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/PDAController.cs
@@ -3,6 +3,7 @@
using Microsoft.AspNetCore.Mvc;
using WIDESEA_Core;
using WIDESEA_Core.BaseController;
using WIDESEA_Core.Helper;
using WIDESEA_DTO.Inbound;
using WIDESEA_IInboundService;
using WIDESEA_IOutboundService;
@@ -49,5 +50,83 @@
        {
            return _inboundService.InbounOrderService.QueryOrderInfo(pageNo, orderNo);
        }
        /// <summary>
        /// ä¸‹è½½PDA
        /// </summary>
        /// <returns></returns>
        [HttpPost, HttpGet, Route("DownLoadApp"), AllowAnonymous]
        public virtual ActionResult DownLoadApp()
        {
            string path = $"{AppDomain.CurrentDomain.BaseDirectory}Upload/App/";
            if (!Directory.Exists(path)) Directory.CreateDirectory(path);
            path += "WMS-PDA.apk";
            if (System.IO.File.Exists(path))
            {
                byte[] fileBytes = System.IO.File.ReadAllBytes(path);
                return File(
                        fileBytes,
                        System.Net.Mime.MediaTypeNames.Application.Octet,
                        System.IO.Path.GetFileName(path)
                    );
            }
            else
            {
                return Json(WebResponseContent.Instance.Error($"未找到安装包"));
            }
        }
        /// <summary>
        /// ä¸Šä¼ PDA
        /// </summary>
        /// <param name="fileInput"></param>
        /// <returns></returns>
        [HttpPost, HttpGet, Route("UploadApp"), AllowAnonymous]
        [Consumes("multipart/form-data")]
        public WebResponseContent UploadApp(IEnumerable<IFormFile> fileInput)
        {
            try
            {
                List<IFormFile> files = fileInput.ToList();
                if (files == null || files.Count() == 0)
                    return new WebResponseContent { Status = true, Message = "请选择上传的文件" };
                IFormFile formFile = files[0];
                string dicPath = $"{AppDomain.CurrentDomain.BaseDirectory}Upload/App/";
                if (!Directory.Exists(dicPath)) Directory.CreateDirectory(dicPath);
                string path = $"{dicPath}WMS-PDA{DateTime.Now:yyyyMMddhhmmss}.apk";
                dicPath = $"{dicPath}WMS-PDA.apk";
                if (System.IO.File.Exists(dicPath))
                    System.IO.File.Move(dicPath, path);
                using (var stream = new FileStream(dicPath, FileMode.Create))
                {
                    formFile.CopyTo(stream);
                }
                return new WebResponseContent { Status = true, Message = "文件上传成功" };
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        [HttpPost, HttpGet, Route("GetPDAVersion"), AllowAnonymous]
        public WebResponseContent GetPDAVersion(string version)
        {
            try
            {
                string versionP = AppSettings.app("PDAVersion");
                if (Convert.ToInt32(versionP) > Convert.ToInt32(version))
                    return WebResponseContent.Instance.OK(data: true);
                else return WebResponseContent.Instance.OK(data: false);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
    }
}
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_DictionaryController.cs
@@ -7,7 +7,7 @@
using WIDESEA_Model.Models;
using WIDESEA_DTO.System;
namespace WIDESEA_WMSServer.Controllers.System
namespace WIDESEA_WMSServer.Controllers
{
    [Route("api/Sys_Dictionary")]
    [ApiController]
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_DictionaryListController.cs
@@ -3,7 +3,7 @@
using WIDESEA_ISystemService;
using WIDESEA_Model.Models;
namespace WIDESEA_WMSServer.Controllers.System
namespace WIDESEA_WMSServer.Controllers
{
    [Route("api/Sys_DictionaryList")]
    [ApiController]
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_LogController.cs
@@ -5,7 +5,7 @@
using WIDESEA_ISystemService;
using WIDESEA_Model.Models;
namespace WIDESEA_WMSServer.Controllers.System
namespace WIDESEA_WMSServer.Controllers
{
    [Route("api/Sys_Log")]
    [ApiController]
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_MenuController.cs
@@ -50,5 +50,15 @@
        {
            return Service.DelMenu(menuId);
        }
        /// <summary>
        /// èŽ·å–é¦–é¡µæ‰€æœ‰ä»“åº“æƒé™
        /// </summary>
        /// <returns></returns>
        [HttpGet, HttpPost, Route("GetTreeMenuPDAStash")]
        public IActionResult GetTreeMenuPDAStash(int ParentId)
        {
            return Json(Service.GetTreeMenuPDAStash(ParentId));
        }
    }
}
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_RoleAuthController.cs
@@ -4,7 +4,7 @@
using WIDESEA_ISystemService;
using WIDESEA_Model.Models;
namespace WIDESEA_WMSServer.Controllers.System
namespace WIDESEA_WMSServer.Controllers
{
    [Route("api/Sys_RoleAuth")]
    [ApiController]
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_RoleController.cs
@@ -9,7 +9,7 @@
using WIDESEA_Model.Models;
using WIDESEA_Model.Models.System;
namespace WIDESEA_WMSServer.Controllers.System
namespace WIDESEA_WMSServer.Controllers
{
    [Route("api/Sys_Role")]
    [ApiController]
@@ -60,5 +60,22 @@
        {
            return Json(Service.SavePermission(userPermissions, roleId));
        }
        [HttpPost, Route("getCurrentTreePermissionPDA")]
        public IActionResult GetCurrentTreePermissionPDA()
        {
            return Json(Service.GetCurrentTreePermissionPDA());
        }
        [HttpPost, Route("getUserTreePermissionPDA")]
        public IActionResult GetUserTreePermissionPDA(int roleId)
        {
            return Json(Service.GetUserTreePermissionPDA(roleId));
        }
        [HttpPost, Route("SavePermissionPDA")]
        public IActionResult SavePermissionPDA([FromBody] List<UserPermissionDTO> userPermissions, int roleId)
        {
            return Json(Service.SavePermissionPDA(userPermissions, roleId));
        }
    }
}
WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json
@@ -20,7 +20,7 @@
    "MainDB": "DB_WIDESEA", //当前项目的主库,所对应的连接字符串的Enabled必须为true
    //连接字符串
    //"ConnectionString": "HTI6FB1H05Krd07mNm9yBCNhofW6edA5zLs9TY~MNthRYW3kn0qKbMIsGp~3yyPDF1YZUCPBQx8U0Jfk4PH~ajNFXVIwlH85M3F~v_qKYQ3CeAz3q1mLVDn8O5uWt1~3Ut2V3KRkEwYHvW2oMDN~QIDXPxDgXN0R2oTIhc9dNu7QNaLEknblqmHhjaNSSpERdDVZIgHnMKejU_SL49tralBkZmDNi0hmkbL~837j1NWe37u9fJKmv91QPb~16JsuI9uu0EvNZ06g6PuZfOSAeFH9GMMIZiketdcJG3tHelo=",
    "ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWMS_JAMK;User ID=sa;Password=sa123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
    "ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWMS_JAMK;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
    //跨域
    "Cors": {
        "PolicyName": "CorsIpAccess", //策略名称
¼ª°²PDA/.eslintignore
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,3 @@
unpackage
node_modules
uview-ui
¼ª°²PDA/.hbuilderx/launch.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
{
    // launch.json é…ç½®äº†å¯åŠ¨è°ƒè¯•æ—¶ç›¸å…³è®¾ç½®ï¼Œconfigurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
    // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
    "version" : "0.0",
    "configurations" : [
        {
            "app-plus" : {
                "launchtype" : "local"
            },
            "default" : {
                "launchtype" : "local"
            },
            "type" : "uniCloud"
        },
        {
            "playground" : "standard",
            "type" : "uni-app:app-android"
        }
    ]
}
¼ª°²PDA/.vscode/launch.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
{
    // ä½¿ç”¨ IntelliSense äº†è§£ç›¸å…³å±žæ€§ã€‚
    // æ‚¬åœä»¥æŸ¥çœ‹çŽ°æœ‰å±žæ€§çš„æè¿°ã€‚
    // æ¬²äº†è§£æ›´å¤šä¿¡æ¯ï¼Œè¯·è®¿é—®: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "chrome",
            "request": "launch",
            "name": "针对 localhost å¯åЍ Chrome",
            "url": "http://localhost:8080",
            "webRoot": "${workspaceFolder}"
        }
    ]
}
¼ª°²PDA/App.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
<script>
    export default {
        onLaunch: function() {
            // console.log('App Launch')
        },
        onShow: function() {
            // this.interval = setInterval(function() {
            //     uni.hideKeyboard(); //隐藏软键盘
            // }, 50);
            // console.log('App Show')
        },
        onHide: function() {
            // console.log('App Hide')
        },
        onLoad() {
        },
    }
</script>
<style lang="scss">
    @import "./static/iconfont.css";
    @import './tuniao-ui/index.scss';
    @import './tuniao-ui/iconfont.css';
    @import "uview-ui/index.scss";
    /*每个页面公共css */
</style>
¼ª°²PDA/LICENSE
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 www.uviewui.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
¼ª°²PDA/common/config.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
let config = {
    baseUrl: 'http://127.0.0.1:9290',
    urls: [
        'http://10.30.4.92:9283',
        'http://10.30.4.92:9283'
    ]
}
export {
    config
}
export const ProOutStatus = [
    { label: '出货未开始', value: 0 },
    { label: '出货中待完成', value: 1 },
    { label: '出货完成', value: 2 }
]
export const ReceiveOrderStatus = [
    { label: '未开始', value: 0 },
    { label: '收货中', value: 1 }
]
export const InboundOrderStatus = [
    { label: '未开始', value: 0 },
    { label: '入库中', value: 1 }
]
export const TakeStockStatus = [
    { label: '未盘点', value: 0 },
    { label: '盘点中', value: 1 },
    { label: '盘点完成', value: 2 }
]
¼ª°²PDA/common/http.interceptor.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,136 @@
import { config } from "./config";
// let baseUrl = 'http://10.1.105.155:9995'
// let baseUrl = 'http://10.1.211.101:9004'
let baseUrl = '';
// let baseUrl = 'http://192.168.43.71:9995'
// let baseUrl = 'http://47.112.196.253:8881'
const install = (Vue, vm) => {
    baseUrl = config.baseUrl;
    // æ­¤ä¸ºè‡ªå®šä¹‰é…ç½®å‚数,具体参数见上方说明
    Vue.prototype.$u.http.setConfig({
        baseUrl: baseUrl,
        loadingText: '努力加载中~',
        loadingTime: 5000,
        originalData: true,
        // ......
    });
    // è¯·æ±‚拦截,配置Token等参数
    Vue.prototype.$u.http.interceptor.request = (config) => {
        // å¼•用token
        // æ–¹å¼ä¸€ï¼Œå­˜æ”¾åœ¨vuex的token,假设使用了uView封装的vuex方式
        // è§ï¼šhttps://uviewui.com/components/globalVariable.html
        // config.header.token = vm.token;
        // æ–¹å¼äºŒï¼Œå¦‚果没有使用uView封装的vuex方法,那么需要使用$store.state获取
        // config.header.token = vm.$store.state.token;
        // æ–¹å¼ä¸‰ï¼Œå¦‚æžœtoken放在了globalData,通过getApp().globalData获取
        // config.header.token = getApp().globalData.username;
        // æ–¹å¼å››ï¼Œå¦‚æžœtoken放在了Storage本地存储中,拦截是每次请求都执行的
        // æ‰€ä»¥å“ªæ€•您重新登录修改了Storage,下一次的请求将会是最新值
        // const token = uni.getStorageSync('token');
        // config.header.token = token;
        // debugger
        // var aaa = "Bearer " + uni.getStorageSync('jo_id_token');
        // var bbb = "a" + uni.getStorageSync('remAcc');
        // var ccc =  "a" + uni.getStorageSync('remPwd');
        // var ddd =  "a" + uni.getStorageSync('acc');
        // var eee =  "a" + uni.getStorageSync('pwd');
        config.header.Token = 'xxxxxx';
        config.header.Authorization = "Bearer " + uni.getStorageSync('jo_id_token');
        config.header.uniapp = '1';
        // å¯ä»¥å¯¹æŸä¸ªurl进行特别处理,此url参数为this.$u.get(url)中的url值
        if (config.url == '/api/User/login') config.header.noToken = true;
        // æœ€åŽéœ€è¦å°†config进行return
        return config;
        // å¦‚æžœreturn一个false值,则会取消本次请求
        // if(config.url == '/user/rest') return false; // å–消某次请求
    }
    // å“åº”拦截,判断状态码是否通过
    Vue.prototype.$u.http.interceptor.response = (res) => {
        if(!res.statusCode){
            if (res.errMsg) {
                vm.$u.toast("请求失败,请检查后台程序是否打开,错误信息:" + res.errMsg);
                return false;
            }
        }
        if (res.statusCode == 200) {
            // res为服务端返回值,可能有code,result等字段
            // è¿™é‡Œå¯¹res.result进行返回,将会在this.$u.post(url).then(res => {})的then回调中的res的到
            // å¦‚果配置了originalData为true,请留意这里的返回值
            return res.data;
        } else if (res.statusCode == 401) {
            // å‡è®¾201为token失效,这里跳转登录
            vm.$u.toast('验证失败,请重新登录');
            uni.reLaunch({
                url: '/pages/login/login'
            });
            return false;
        } else if (res.statusCode == 202) {
            // å¦‚果返回false,则会调用Promise的reject回调,
            // å¹¶å°†è¿›å…¥this.$u.post(url).then().catch(res=>{})的catch回调中,res为服务端的返回值
            vm.$u.post("/api/User/replaceToken").then(res => {
                if (x.data.status) {
                    vm.$u.vuex('vuex_token', x.data.data)
                    vm.$u.route({
                        type: "navigateBack",
                        delta: -1
                    })
                } else {
                    vm.$u.toast('验证过期,请重新登录');
                    uni.reLaunch({
                        url: '/pages/login/login'
                    });
                }
            }).catch(err => {
                uni.reLaunch({
                    url: '/pages/login/login'
                });
            })
            // uni.request({
            //     url: "http://192.168.12.245:8099/api/User/replaceToken",
            //     param: {},
            //     method: 'POST',
            //     responseType: "text",
            //     header: {
            //         Authorization: "Bearer " + vm.vuex_token
            //     },
            //     async: false,
            //     success: function(x) {
            //         if (x.data.status) {
            //             vm.$u.vuex('vuex_token',x.data.data)
            //             vm.$u.route({
            //                 type: "navigateBack",
            //                 delta: -1
            //             })
            //         } else {
            //             console.log(x.data.message);
            //             vm.$u.toast('验证过期,请重新登录');
            //             setTimeout(() => {
            //                 // æ­¤ä¸ºuView的方法,详见路由相关文档
            //                 vm.$u.route('/pages/user/login')
            //             }, 1500)
            //         }
            //     },
            //     errror: function(ex) {
            //         console.log(ex);
            //         uni.reLaunch({
            //             url: '/pages/user/login'
            //         });
            //     },
            // });
            return false;
        }
    }
}
export default {
    install,
    baseUrl
}
¼ª°²PDA/common/uni-ui.scss
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,120 @@
.uni-flex {
    display: flex;
}
.uni-flex-row {
    @extend .uni-flex;
    flex-direction: row;
    box-sizing: border-box;
}
.uni-flex-column {
    @extend .uni-flex;
    flex-direction: column;
}
.uni-color-gary {
    color: #3b4144;
}
/* æ ‡é¢˜ */
.uni-title {
    display: flex;
    margin-bottom: $uni-spacing-col-base;
    font-size: $uni-font-size-lg;
    font-weight: bold;
    color: #3b4144;
}
.uni-title-sub {
    display: flex;
    // margin-bottom: $uni-spacing-col-base;
    font-size: $uni-font-size-base;
    font-weight: 500;
    color: #3b4144;
}
/* æè¿° é¢å¤–文本 */
.uni-note {
    margin-top: 10px;
    color: #999;
    font-size: $uni-font-size-sm;
}
/* åˆ—表内容 */
.uni-list-box {
    @extend .uni-flex-row;
    flex: 1;
    margin-top: 10px;
}
/* ç•¥ç¼©å›¾ */
.uni-thumb {
    flex-shrink: 0;
    margin-right: $uni-spacing-row-base;
    width: 125px;
    height: 75px;
    border-radius: $uni-border-radius-lg;
    overflow: hidden;
    border: 1px #f5f5f5 solid;
    image {
        width: 100%;
        height: 100%;
    }
}
.uni-media-box {
    @extend .uni-flex-row;
    // margin-bottom: $uni-spacing-col-base;
    border-radius: $uni-border-radius-lg;
    overflow: hidden;
    .uni-thumb {
        margin: 0;
        margin-left: 4px;
        flex-shrink: 1;
        width: 33%;
        border-radius:0;
        &:first-child {
            margin: 0;
        }
    }
}
/* å†…容 */
.uni-content {
    @extend .uni-flex-column;
    justify-content: space-between;
}
/* åˆ—表footer */
.uni-footer {
    @extend .uni-flex-row;
    justify-content: space-between;
    margin-top: $uni-spacing-col-lg;
}
.uni-footer-text {
    font-size: $uni-font-size-sm;
    color: $uni-text-color-grey;
    margin-left: 5px;
}
/* æ ‡ç­¾ */
.uni-tag {
    flex-shrink: 0;
    padding: 0 5px;
    border: 1px $uni-border-color solid;
    margin-right: $uni-spacing-row-sm;
    border-radius: $uni-border-radius-base;
    background: $uni-bg-color-grey;
    color: $uni-text-color;
    font-size: $uni-font-size-sm;
}
/* é“¾æŽ¥ */
.uni-link {
    margin-left: 10px;
    color: $uni-text-color;
    text-decoration: underline;
}
¼ª°²PDA/components/uni-section/config.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
{
    "id": "99999",
    "name": "Section",
    "desc": "标题栏",
    "edition": "0.0.1",
    "url": "section",
    "type": "布局组件",
    "path": "https://ext.dcloud.net.cn/plugin?id=",
    "hidden": true,
    "test":true,
    "update_log": []
}
¼ª°²PDA/components/uni-section/readme.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
### Section æ ‡é¢˜æ 
标题栏,用于显示标题,组件名:``uni-section``,代码块: uSection。
### ä½¿ç”¨æ–¹å¼
在 ``script`` ä¸­å¼•用组件
```javascript
import uniSection from "@/components/uni-section/uni-section.vue"
export default {
    components: {uniSection}
}
```
在 ``template`` ä¸­ä½¿ç”¨ç»„ä»¶
```html
<uni-section title="只有主标题"></uni-section>
<uni-section title="竖线装饰" sub-title="副标题" type="line"></uni-section>
<uni-section title="圆形装饰" sub-title="副标题" type="circle"></uni-section>
```
### å±žæ€§è¯´æ˜Ž
|属性名        |类型    |默认值    |说明                                                |
|---        |----    |---    |---                                                |
|type        |String    |-        |标题装饰类型 ï¼Œå¯é€‰å€¼ï¼šline(竖线)、circle(圆形)|
|title        |String    |-        |主标题                                                |
|sub-title    |String    |-        |副标题                                                |
¼ª°²PDA/components/uni-section/uni-section.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,136 @@
<template>
    <view class="uni-section" nvue>
        <view v-if="type" class="uni-section__head">
            <view :class="type" class="uni-section__head-tag" />
        </view>
        <view class="uni-section__content">
            <text :class="{'distraction':!subTitle}" class="uni-section__content-title">{{ title }}</text>
            <text v-if="subTitle" class="uni-section__content-sub">{{ subTitle }}</text>
        </view>
        <slot />
    </view>
</template>
<script>
    /**
     * Section æ ‡é¢˜æ 
     * @description æ ‡é¢˜æ 
     * @property {String} type = [line|circle] æ ‡é¢˜è£…饰类型
     *     @value line ç«–线
     *     @value circle åœ†å½¢
     * @property {String} title ä¸»æ ‡é¢˜
     * @property {String} subTitle å‰¯æ ‡é¢˜
     */
    export default {
        name: 'UniSection',
        props: {
            type: {
                type: String,
                default: ''
            },
            title: {
                type: String,
                default: ''
            },
            subTitle: {
                type: String,
                default: ''
            }
        },
        data() {
            return {}
        },
        watch: {
            title(newVal) {
                if (uni.report && newVal !== '') {
                    uni.report('title', newVal)
                }
            }
        },
        methods: {
            onClick() {
                this.$emit('click')
            }
        }
    }
</script>
<style lang="scss" scoped>
    .uni-section {
        position: relative;
        /* #ifndef APP-NVUE */
        display: flex;
        /* #endif */
        margin-top: 10px;
        flex-direction: row;
        align-items: center;
        padding: 0 10px;
        height: 50px;
        background-color: $uni-bg-color-grey;
        /* #ifdef APP-NVUE */
        // border-bottom-color: $uni-border-color;
        // border-bottom-style: solid;
        // border-bottom-width: 0.5px;
        /* #endif */
        font-weight: normal;
    }
    /* #ifndef APP-NVUE */
    // .uni-section:after {
    //     position: absolute;
    //     bottom: 0;
    //     right: 0;
    //     left: 0;
    //     height: 1px;
    //     content: '';
    //     -webkit-transform: scaleY(.5);
    //     transform: scaleY(.5);
    //     background-color: $uni-border-color;
    // }
    /* #endif */
    .uni-section__head {
        flex-direction: row;
        justify-content: center;
        align-items: center;
        margin-right: 10px;
    }
    .line {
        height: 15px;
        background-color: $uni-text-color-disable;
        border-radius: 5px;
        width: 3px;
    }
    .circle {
        width: 8px;
        height: 8px;
        border-top-right-radius: 50px;
        border-top-left-radius: 50px;
        border-bottom-left-radius: 50px;
        border-bottom-right-radius: 50px;
        background-color: $uni-text-color-disable;
    }
    .uni-section__content {
        flex-direction: column;
        flex: 1;
        color: $uni-text-color;
    }
    .uni-section__content-title {
        font-size: $uni-font-size-base;
        color: $uni-text-color;
    }
    .distraction {
        flex-direction: row;
        align-items: center;
    }
    .uni-section__content-sub {
        font-size: $uni-font-size-sm;
        color: $uni-text-color-grey;
    }
</style>
¼ª°²PDA/main.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
App.mpType = 'app'
// å°è£…的展示消息提示的方法
uni.$showMsg = function (title = '数据加载失败!', duration = 1500) {
  uni.showToast({
    title,
    duration,
    icon: 'none',
  })
}
// å¼•入全局uView
import uView from 'uview-ui'
Vue.use(uView);
// å¼•入全局TuniaoUI
import TuniaoUI from 'tuniao-ui'
Vue.use(TuniaoUI)
// http拦截器,此为需要加入的内容,如果不是写在common目录,请自行修改引入路径
import httpInterceptor from '@/common/http.interceptor.js'
const app = new Vue({
    ...App
})
// è¿™é‡Œéœ€è¦å†™åœ¨æœ€åŽï¼Œæ˜¯ä¸ºäº†ç­‰Vue创建对象完成,引入"app"对象(也即页面的"this"实例)
Vue.use(httpInterceptor, app)
app.$mount()
¼ª°²PDA/manifest.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,127 @@
{
    "name" : "WMS-PDA",
    "appid" : "__UNI__4D0008D",
    "description" : "",
    "versionName" : "8",
    "versionCode" : 8,
    "transformPx" : false,
    /* 5+App特有相关 */
    "app-plus" : {
        "safearea" : {
            "bottom" : {
                "offset" : "none"
            }
        },
        "usingComponents" : true,
        "nvueCompiler" : "uni-app",
        "compilerVersion" : 3,
        "splashscreen" : {
            "alwaysShowBeforeRender" : true,
            "waiting" : true,
            "autoclose" : true,
            "delay" : 0
        },
        /* æ¨¡å—配置 */
        "modules" : {
            "Barcode" : {},
            "Bluetooth" : {}
        },
        /* åº”用发布信息 */
        "distribute" : {
            /* android打包配置 */
            "android" : {
                "permissions" : [
                    "<uses-feature android:name=\"android.hardware.camera\"/>",
                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
                    "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
                    "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
                    "<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
                ]
            },
            /* ios打包配置 */
            "ios" : {
                "dSYMs" : false
            },
            /* SDK配置 */
            "sdkConfigs" : {
                "ad" : {}
            },
            "icons" : {
                "android" : {
                    "hdpi" : "unpackage/res/icons/72x72.png",
                    "xhdpi" : "unpackage/res/icons/96x96.png",
                    "xxhdpi" : "unpackage/res/icons/144x144.png",
                    "xxxhdpi" : "unpackage/res/icons/192x192.png"
                },
                "ios" : {
                    "appstore" : "unpackage/res/icons/1024x1024.png",
                    "ipad" : {
                        "app" : "unpackage/res/icons/76x76.png",
                        "app@2x" : "unpackage/res/icons/152x152.png",
                        "notification" : "unpackage/res/icons/20x20.png",
                        "notification@2x" : "unpackage/res/icons/40x40.png",
                        "proapp@2x" : "unpackage/res/icons/167x167.png",
                        "settings" : "unpackage/res/icons/29x29.png",
                        "settings@2x" : "unpackage/res/icons/58x58.png",
                        "spotlight" : "unpackage/res/icons/40x40.png",
                        "spotlight@2x" : "unpackage/res/icons/80x80.png"
                    },
                    "iphone" : {
                        "app@2x" : "unpackage/res/icons/120x120.png",
                        "app@3x" : "unpackage/res/icons/180x180.png",
                        "notification@2x" : "unpackage/res/icons/40x40.png",
                        "notification@3x" : "unpackage/res/icons/60x60.png",
                        "settings@2x" : "unpackage/res/icons/58x58.png",
                        "settings@3x" : "unpackage/res/icons/87x87.png",
                        "spotlight@2x" : "unpackage/res/icons/80x80.png",
                        "spotlight@3x" : "unpackage/res/icons/120x120.png"
                    }
                }
            }
        }
    },
    /* å¿«åº”用特有相关 */
    "quickapp" : {},
    /* å°ç¨‹åºç‰¹æœ‰ç›¸å…³ */
    "mp-weixin" : {
        "appid" : "wxc256e348c4032ebd",
        "setting" : {
            "urlCheck" : false
        },
        "usingComponents" : true
    },
    "mp-alipay" : {
        "usingComponents" : true
    },
    "mp-baidu" : {
        "usingComponents" : true
    },
    "mp-toutiao" : {
        "usingComponents" : true
    },
    "h5" : {
        "template" : "template.h5.html",
        "router" : {
            "mode" : "history"
        }
    },
    "fallbackLocale" : "zh-Hans",
    "android" : {
        "hardwareAccelerated" : true,
        "keyboardHideMode" : "adjustPan"
    }
}
¼ª°²PDA/package-lock.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,70 @@
{
  "name": "PDA",
  "lockfileVersion": 2,
  "requires": true,
  "packages": {
    "": {
      "dependencies": {
        "vue-touch-keyboard": "^0.3.2"
      }
    },
    "node_modules/babel-runtime": {
      "version": "6.26.0",
      "resolved": "https://registry.npmmirror.com/babel-runtime/-/babel-runtime-6.26.0.tgz",
      "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==",
      "dependencies": {
        "core-js": "^2.4.0",
        "regenerator-runtime": "^0.11.0"
      }
    },
    "node_modules/core-js": {
      "version": "2.6.12",
      "resolved": "https://registry.npmmirror.com/core-js/-/core-js-2.6.12.tgz",
      "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
      "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
      "hasInstallScript": true
    },
    "node_modules/regenerator-runtime": {
      "version": "0.11.1",
      "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
      "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
    },
    "node_modules/vue-touch-keyboard": {
      "version": "0.3.2",
      "resolved": "https://registry.npmmirror.com/vue-touch-keyboard/-/vue-touch-keyboard-0.3.2.tgz",
      "integrity": "sha512-+GAZSMdiPfop2At9fhGLzs2Jodd6BQla4q4Mm+VkpQLUaxmFFU64NWsjxvkkYjncAgbv/oO5wi+rM1X4eVHCbg==",
      "dependencies": {
        "babel-runtime": "^6.26.0"
      }
    }
  },
  "dependencies": {
    "babel-runtime": {
      "version": "6.26.0",
      "resolved": "https://registry.npmmirror.com/babel-runtime/-/babel-runtime-6.26.0.tgz",
      "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==",
      "requires": {
        "core-js": "^2.4.0",
        "regenerator-runtime": "^0.11.0"
      }
    },
    "core-js": {
      "version": "2.6.12",
      "resolved": "https://registry.npmmirror.com/core-js/-/core-js-2.6.12.tgz",
      "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
    },
    "regenerator-runtime": {
      "version": "0.11.1",
      "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
      "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
    },
    "vue-touch-keyboard": {
      "version": "0.3.2",
      "resolved": "https://registry.npmmirror.com/vue-touch-keyboard/-/vue-touch-keyboard-0.3.2.tgz",
      "integrity": "sha512-+GAZSMdiPfop2At9fhGLzs2Jodd6BQla4q4Mm+VkpQLUaxmFFU64NWsjxvkkYjncAgbv/oO5wi+rM1X4eVHCbg==",
      "requires": {
        "babel-runtime": "^6.26.0"
      }
    }
  }
}
¼ª°²PDA/package.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,5 @@
{
  "dependencies": {
    "vue-touch-keyboard": "^0.3.2"
  }
}
¼ª°²PDA/pages.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,196 @@
{
    "easycom": {
        "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
    },
    "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
        {
            "path": "pages/index/index",
            "style": {
                "navigationBarTitleText": "首页"
            }
        },
        {
            "path": "pages/home/home",
            "style": {
                "navigationBarTitleText": "我的"
            }
        },
        {
            "path": "pages/login/login",
            "style": {
                "navigationBarTitleText": "登录"
            }
        },
        {
            "path": "pages/stash/index",
            "style": {
                "navigationBarTitleText": "功能",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/inboundorder",
            "style": {
                "navigationBarTitleText": "组盘",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/raworderboxing",
            "style": {
                "navigationBarTitleText": "组盘入库",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/outboundorder",
            "style": {
                "navigationBarTitleText": "出库单",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/outraworderboxing",
            "style": {
                "navigationBarTitleText": "平库出库",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/boxing",
            "style": {
                "navigationBarTitleText": "WMS入库",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/InspectIn",
            "style": {
                "navigationBarTitleText": "送检入库",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/AGVFinish",
            "style": {
                "navigationBarTitleText": "AGV完成",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/AGVTasks",
            "style": {
                "navigationBarTitleText": "AGV搬运任务",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/InEmpty",
            "style": {
                "navigationBarTitleText": "空箱入库",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/OutEmpty",
            "style": {
                "navigationBarTitleText": "空箱出库",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/pickingMat",
            "style": {
                "navigationBarTitleText": "拣选",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/TakeStock",
            "style": {
                "navigationBarTitleText": "盘点",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/TakeStockOrder",
            "style": {
                "navigationBarTitleText": "盘点单",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/QueryData",
            "style": {
                "navigationBarTitleText": "查询",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/receiveorder",
            "style": {
                "navigationBarTitleText": "收货",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/receiveorderoutbound",
            "style": {
                "navigationBarTitleText": "收货单",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/OutProOrder",
            "style": {
                "navigationBarTitleText": "出货",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/ProOutOrderView",
            "style": {
                "navigationBarTitleText": "成品出货",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/ProEmptyBack",
            "style": {
                "navigationBarTitleText": "空框回库",
                "enablePullDownRefresh": false
            }
        },
        {
            "path": "pages/stash/ProBack",
            "style": {
                "navigationBarTitleText": "余料退库",
                "enablePullDownRefresh": false
            }
        }
    ],
    "globalStyle": {
        "navigationBarTextStyle": "black",
        "navigationBarTitleText": "uView",
        "navigationBarBackgroundColor": "#F8F8F8",
        "backgroundColor": "#F8F8F8"
    },
    "tabBar": {
        "color": "#909399",
        "selectedColor": "#303133",
        "borderStyle": "black",
        "backgroundColor": "#ffffff",
        "list": [{
            "pagePath": "pages/index/index",
            "iconPath": "static/index.png",
            "selectedIconPath": "static/index-selected.png",
            "text": "首页"
        }, {
            "pagePath": "pages/home/home",
            "iconPath": "static/center.png",
            "selectedIconPath": "static/center-selected.png",
            "text": "我"
        }]
    }
}
¼ª°²PDA/pages/home/home.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,282 @@
<template>
    <view class="page">
        <view class="top">
            <view class="background"></view>
        </view>
        <view class="user-card">
            <view class="card">
                <view class="top">
                    <view class="userImage">
                        <!-- <open-data type="userAvatarUrl"></open-data> -->
                        <u-avatar :src="src" size="146"></u-avatar>
                    </view>
                </view>
                <view class="bottom" @tap.native="Login">
                    <view class="left">
                        <view class="user-text">
                            <!-- <open-data type="userNickName"></open-data> -->
                            <text style="text-align: center;">{{userNickName}}</text>
                        </view>
                        <!-- <view class="user-phone"> 171****4133 </view> -->
                    </view>
                    <view class="right flex-center">
                        <u-icon class="icon" name="arrow-right"></u-icon>
                    </view>
                </view>
                <!-- <view class="settings" @click="settings">
                    <view class="left">
                        <view class="settings-text">
                            <open-data type="userNickName"></open-data>
                            <text style="text-align: center;">设置</text>
                        </view>
                        <view class="user-phone"> 171****4133 </view>
                    </view>
                    <view class="right flex-center">
                        <u-icon class="icon" name="arrow-right"></u-icon>
                    </view>
                </view> -->
            </view>
        </view>
        <view class="list-card">
        </view>
        <view class="quit flex-center">
            <!-- <view class="btn flex-center" @click="LastLogin">
                æ›´æ–°ç¨‹åº
            </view> -->
            <view class="btn flex-center" @click="LastLogin">
                é€€å‡ºç™»å½•
            </view>
        </view>
    </view>
</template>
<style lang="scss" scoped>
    .top {
        height: 250rpx;
        position: relative;
        .background {
            background-color: #5199ff;
            border-bottom-left-radius: 22px;
            border-bottom-right-radius: 22px;
            position: absolute;
            height: 180rpx;
            width: 100%;
        }
    }
    .icon {
        color: #96a1ae;
        font-size: 20rpx;
    }
    .user-card {
        height: 170rpx;
        padding: 0 15px;
        .card {
            position: relative;
            bottom: 62px;
            height: 250rpx;
            background-color: white;
            border-radius: 5px;
            .top {
                height: 30%;
                position: relative;
                .userImage {
                    position: absolute;
                    bottom: 24%;
                    left: 10%;
                    width: 150rpx;
                    height: 150rpx;
                    overflow: hidden;
                    border-radius: 50%;
                    border: 2px solid white;
                }
            }
            .bottom {
                display: flex;
                height: 70%;
                .left {
                    width: 80%;
                    height: 100%;
                    position: relative;
                    .user-text {
                        width: 100%;
                        font-size: 1.6em;
                        padding-left: 80rpx;
                        height: 50%;
                    }
                    .user-phone {
                        width: 100%;
                        font-size: 1.3em;
                        padding-left: 80rpx;
                        height: 50%;
                    }
                }
                .right {
                    width: 20%;
                    height: 50%;
                }
                .right2 {
                    width: 10%;
                    height: 10%;
                }
            }
            .settings {
                display: flex;
                height: 70%;
                .left {
                    width: 80%;
                    height: 50%;
                    position: relative;
                    margin-left: 5%;
                    .settings-text {
                        width: 100%;
                        font-size: 1.2em;
                        padding-left: 80rpx;
                        height: 50%;
                        align-items: center;
                        padding-top: 10px;
                    }
                }
                .right {
                    width: 20%;
                    height: 50%;
                }
            }
        }
    }
    .list-card {
        padding: 0 15px;
        .card {
            border-radius: 5px;
            position: relative;
            background-color: white;
            border-radius: 5px;
            padding: 5px 30px;
            .item {
                display: flex;
                height: 120rpx;
                .left {
                    width: 15%;
                    image {
                        width: 70rpx;
                        height: 70rpx;
                    }
                }
                .center {
                    width: 65%;
                    display: flex;
                    justify-content: start;
                    align-items: center;
                    font-size: 1.1em;
                }
                .right {
                    width: 20%;
                    justify-content: flex-end;
                }
            }
        }
    }
    .item-bottom-solid {
        border-bottom: 1px solid #d4d6da;
    }
    .quit {
        height: 100rpx;
        margin-top: 50px;
        .btn {
            background-color: #4f99ff;
            border-radius: 30px;
            width: 80%;
            color: white;
            font-size: 1.2em;
            height: 100%;
        }
    }
    .flex-center {
        display: flex;
        justify-content: center;
        align-items: center;
    }
</style>
<script>
    //import {  } from "@/common/api/{$}.js";
    import httpInterceptor from '@/common/http.interceptor.js'
    export default {
        data() {
            return {
                src: "",
                userNickName: '请登录',
            };
        },
        //监听页面初始化,其参数同 onLoad å‚数,为上个页面传递的数据,参数类型为 Object(用于页面传参),触发时机早于 onLoad
        onInit() {},
        //监听页面加载,其参数为上个页面传递的数据,参数类型为 Object(用于页面传参)
        onLoad() {
            let isLogin = this.hasLogin();
            if (isLogin) {
                let haslogin = uni.getStorageSync('jo_user')
                this.userNickName = haslogin.userName;
                this.src = httpInterceptor.baseUrl + "/" + haslogin.img;
            }
        },
        //监听页面初次渲染完成。注意如果渲染速度快,会在页面进入动画完成前触发
        onReady() {},
        //监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面
        beforeDestroy() {},
        //页面滚动到底部的事件(不是scroll-view滚到底),常用于下拉下一页数据。
        onReachBottom() {},
        onShareAppMessage(res) {},
        created() {},
        methods: {
            hasLogin() {
                let haslogin = uni.getStorageSync('jo_user')
                if (haslogin == null || haslogin == "") {
                    return false
                } else {
                    return true
                }
            },
            LastLogin() {
                //uni.clearStorage();
                uni.removeStorageSync('jo_id_token');
                uni.removeStorageSync('jo_user');
                uni.removeStorageSync('jo_userImg');
                this.$u.route('/pages/login/login');
            },
            Login() {
                this.$u.route('/pages/login/login');
            },
            settings(){
                this.$u.route('/pages/index/settings');
            }
        },
    };
</script>
¼ª°²PDA/pages/index/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,169 @@
<template>
    <!-- <u-card :title="title" > -->
    <view class="" slot="body">
        <!-- <view v-for="(item,index) in tree" :key="item.id"> -->
        <u-grid :col="2">
            <u-grid-item @tap="clickCoupon(item.url,item.menuId,item.description,item.menuName)" v-for="(item) in tree"
                :key="item.menuId">
                <u-icon :name="item.icon" custom-prefix="custom-icon" size="50" color="#888888"> </u-icon>
                <view class="grid-text">{{item.menuName}}</view>
            </u-grid-item>
        </u-grid>
        <!-- </view> -->
        <u-toast ref="uToast" />
    </view>
    <!-- </u-card> -->
</template>
<script>
    import {
        config
    } from '../../common/config.js'
    export default {
        data() {
            return {
                // title: '操作功能'
                datas: [],
                tree: [],
                version: ""
            }
        },
        onShow() {
            console.log();
            uni.getSystemInfo({
                success: (res) => {
                    this.version = res.appWgtVersion;
                    // console.log(res);
                    //检测当前平台,如果是安卓则启动安卓更新
                    if (res.platform == "android") {
                        this.AndroidCheckUpdate();
                    }
                }
            });
        },
        onLoad() {
            this.getCurrentTree();
        },
        mounted() {
        },
        methods: {
            AndroidCheckUpdate: function() {
                var _this = this;
                uni.request({
                    url: this.$u.http.config.baseUrl + '/api/PDA/GetPDAVersion?version=' + this.version,
                    method: 'GET',
                    data: {},
                    success: res => {
                        if (res.data.data) {
                            uni.showToast({
                                title: '有新的版本发布,检测到您目前为Wifi连接,程序已启动自动更新。新版本下载完成后将自动弹出安装程序。',
                                mask: false,
                                duration: 5000,
                                icon: "none"
                            });
                            var dtask = plus.downloader.createDownload(
                                this.$u.http.config.baseUrl + "/api/PDA/DownLoadApp", {},
                                function(d, status) {
                                    // ä¸‹è½½å®Œæˆ
                                    if (status == 200) {
                                        plus.runtime.install(plus.io.convertLocalFileSystemURL(d
                                            .filename), {}, {}, function(error) {
                                            uni.showToast({
                                                title: '安装失败',
                                                mask: false,
                                                duration: 1500
                                            });
                                        })
                                    } else {
                                        uni.showToast({
                                            title: '更新失败',
                                            mask: false,
                                            duration: 1500
                                        });
                                    }
                                });
                            dtask.start();
                        }
                    },
                    fail: () => {
                        console.log('请求失败')
                    },
                    complete: () => {}
                });
            },
            getCurrentTree(ParentId) {
                this.$u.post('/api/Sys_Menu/GetTreeMenuPDAStash?ParentId=' + ParentId, {}).then(result => {
                    this.tree = result;
                })
            },
            getTree(id, data, isRootId) {
                this.datas.forEach((x) => {
                    if (x.pid == id) {
                        x.lv = data.lv + 1;
                        if (isRootId) {
                            x.rootId = id;
                        }
                        if (!data.children) data.children = [];
                        data.children.push(x);
                        this.getTree(x.id, x, isRootId);
                    }
                });
            },
            getPermission(text) {
                // return true;
                return this.datas.find(x => x.text == text);
            },
            clickCoupon(url, menuid, warehouseid, menuname) {
                // console.log("clickCoupon")
                if (this.hasLogin()) {
                    this.$u.route({
                        url: url,
                        params: {
                            menuId: menuid,
                            warehouseId: warehouseid,
                            menuName: menuname
                        }
                    })
                } else {
                    this.$t.message.loading('登录失效请重新登录')
                    uni.reLaunch({
                        url: '/pages/login/login'
                    });
                }
            },
            lock() {
                console.log("lock")
                if (this.hasLogin()) {
                    this.$u.route("pages/feeding/feeding")
                } else {
                    this.$t.message.loading('登录失效请重新登录')
                    uni.reLaunch({
                        url: '/pages/login/login'
                    });
                }
            },
            //判断是否登录
            hasLogin() {
                let haslogin = uni.getStorageSync('jo_user')
                if (haslogin == null || haslogin == "") {
                    return false
                } else {
                    return true
                }
            }
        }
    }
</script>
<style lang="scss" scoped>
    .grid-text {
        font-size: 28rpx;
        margin-top: 4rpx;
        color: $u-type-info;
    }
</style>
¼ª°²PDA/pages/login/login.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,531 @@
<template>
    <view class="template-login">
        <!-- é¡¶éƒ¨è‡ªå®šä¹‰å¯¼èˆª -->
        <!-- <tn-nav-bar fixed alpha customBack>
      <view slot="back" class='tn-custom-nav-bar__back'
        @click="goBack">
        <text class='icon tn-icon-left'></text>
        <text class='icon tn-icon-home-capsule-fill'></text>
      </view>
    </tn-nav-bar> -->
        <view class="login">
            <!-- é¡¶éƒ¨èƒŒæ™¯å›¾ç‰‡-->
            <view class="login__bg login__bg--top">
                <image class="bg" src="/static/login_top2.jpg" mode="widthFix"></image>
            </view>
            <view class="login__bg login__bg--top">
                <image class="rocket rocket-sussuspension" src="/static/login_top3.png" mode="widthFix"></image>
            </view>
            <view class="login__wrapper">
                <!-- è¾“入框内容-->
                <view class="login__info tn-flex tn-flex-direction-column tn-flex-col-center tn-flex-row-center">
                    <!-- ç™»å½• -->
                    <block v-if="currentModeIndex === 0">
                        <view
                            class="login__info__item__input tn-flex tn-flex-direction-row tn-flex-nowrap tn-flex-col-center tn-flex-row-left">
                            <view class="login__info__item__input__left-icon">
                                <view class="tn-icon-my"></view>
                            </view>
                            <view class="login__info__item__input__content">
                                <input maxlength="45" placeholder-class="input-placeholder" v-model="user"
                                    placeholder="请输入登录用户名称" />
                            </view>
                        </view>
                        <view
                            class="login__info__item__input tn-flex tn-flex-direction-row tn-flex-nowrap tn-flex-col-center tn-flex-row-left">
                            <view class="login__info__item__input__left-icon">
                                <view class="tn-icon-lock"></view>
                            </view>
                            <view class="login__info__item__input__content">
                                <input :password="!showPassword" placeholder-class="input-placeholder" v-model="pass"
                                    placeholder="请输入登录密码" />
                            </view>
                            <view class="login__info__item__input__right-icon" @click="showPassword = !showPassword">
                                <view :class="[showPassword ? 'tn-icon-eye' : 'tn-icon-eye-hide']"></view>
                            </view>
                        </view>
                        <view
                            class="login__info__item__input tn-flex tn-flex-direction-row tn-flex-nowrap tn-flex-col-center tn-flex-row-left">
                            <view class="login__info__item__input__left-icon">
                                <view class="tn-icon-my"></view>
                            </view>
                            <view class="login__info__item__input__content">
                                <input maxlength="45" placeholder-class="input-placeholder" v-model="code"
                                    placeholder="请输入验证码" />
                            </view>
                            <view class="login__info__item__input__right-icon u-border" style="width: 30%;"
                                @click="getVierificationCode">
                                <img v-show="codeImgSrc != ''" :src="codeImgSrc" />
                            </view>
                        </view>
                    </block>
                    <!-- æ³¨å†Œ -->
                    <view class="login__info__item__input__content" style="margin-top: 20px;">
                        <uni-data-checkbox multiple v-model="checkbox" :localdata="hobby"></uni-data-checkbox>
                    </view>
                    <view class="login__info__item__button tn-cool-bg-color-7--reverse"
                        @click="currentModeIndex === 0 ? login() : registra()" hover-class="tn-hover"
                        :hover-stay-time="150">{{ currentModeIndex === 0 ? '登录' : '注册'}}</view>
                    <!-- <view v-if="currentModeIndex === 0" class="login__info__item__tips">忘记密码?</view> -->
                </view>
            </view>
            <!-- <tn-tips ref="tips" position="top"></tn-tips> -->
            <!-- åº•部背景图片-->
            <view class="login__bg login__bg--bottom">
                <image src="/static/login_bottom_bg.jpg" mode="widthFix"></image>
            </view>
        </view>
    </view>
</template>
<script>
    var app = getApp();
    export default {
        name: 'login-demo-1',
        // mixins: [template_page_mixin],*
        data() {
            return {
                // å½“前选中的模式
                currentModeIndex: 0,
                // æ¨¡å¼é€‰ä¸­æ»‘块
                modeSliderStyle: {
                    left: 0
                },
                // æ˜¯å¦æ˜¾ç¤ºå¯†ç 
                showPassword: false,
                // å€’计时提示文字
                tips: '获取验证码',
                email: '',
                codeImgSrc: '',
                pass: '',
                code: '1234',
                user: '',
                isDetail: false,
                hobby: [{
                        text: '记住账号',
                        value: 1
                    },
                    {
                        text: '记住密码',
                        value: 2
                    }
                ],
                checkbox: []
            }
        },
        watch: {
            currentModeIndex(value) {
                const sliderWidth = uni.upx2px(476 / 2)
                this.modeSliderStyle.left = `${sliderWidth * value}px`
            }
        },
        onLoad(options) {
            this.getVierificationCode()
            if (options.id) {
                this.isDetail = true
            }
        },
        mounted() {
            var remAcc = uni.getStorageSync('remAcc');
            if (remAcc) {
                this.checkbox.push(1);
            }
            var remPwd = uni.getStorageSync('remPwd');
            if (remPwd) {
                this.checkbox.push(2);
            }
            var acc = uni.getStorageSync('acc');
            if (acc) {
                this.user = acc;;
            }
            var pwd = uni.getStorageSync('pwd');
            if (pwd) {
                this.pass = pwd;
            }
        },
        methods: {
            ///获取验证码
            getVierificationCode() {
                this.$u.get('/api/User/getVierificationCode', {}).then(res => {
                    if (res.img != null) {
                        this.codeImgSrc = "data:image/png;base64," + res.img;
                        this.email = res.uuid;
                    } else {
                        this.$refs.uToast.show({
                            title: '获取验证码失败请重新获取',
                            type: 'error',
                        })
                    }
                })
                // uni.request({
                //     url:"http://192.168.0.101:8098/api/User/getVierificationCode",
                //     success: (res) => {
                //     }
                // })
            },
            login() {
                if (this.pass == '') {
                    this.$t.message.toast('请输入密码')
                    return;
                } else if (this.user == '') {
                    this.$t.message.toast('请输入用户名')
                    return;
                } else if (this.pass.length < 6) {
                    this.$t.message.toast('密码应大于6位')
                    return;
                } else {
                    var userAcc = this.user;
                    var userPwd = this.pass;
                    var checkValues = this.checkbox;
                    var remAcc = this.checkbox.find(x => x == 1);
                    if (remAcc) {
                        uni.setStorage({
                            key: "remAcc",
                            data: "1",
                        })
                    } else {
                        if (uni.getStorageSync('remAcc')) {
                            uni.removeStorageSync('remAcc');
                        }
                    }
                    var remPwd = this.checkbox.find(x => x == 2);
                    if (remPwd) {
                        uni.setStorage({
                            key: "remPwd",
                            data: "2",
                        })
                    } else {
                        if (uni.getStorageSync('remPwd')) {
                            uni.removeStorageSync('remPwd');
                        }
                    }
                    this.$t.message.loading('正在登录')
                    let userInfo = this.userInfo;
                    let userifno = {
                        UUID: this.email,
                        passWord: this.pass,
                        userName: this.user,
                        verificationCode: this.code
                    }
                    this.$u.post('/api/User/login', {
                        UUID: this.email,
                        passWord: this.pass,
                        userName: this.user,
                        verificationCode: this.code
                    }).then(res => {
                        // this.$u.toast(res.message);
                        this.$t.message.toast(res.message)
                        this.$t.message.closeLoading()
                        uni.setStorage({
                            key: 'jo_id_token',
                            data: res.data.token,
                        });
                        uni.setStorage({
                            key: 'jo_user',
                            data: res.data,
                        });
                        uni.setStorage({
                            key: 'jo_userImg',
                            data: res.data.img,
                        });
                        var acc = checkValues.find(x => x == 1);
                        if (acc) {
                            uni.setStorage({
                                key: 'acc',
                                data: userAcc,
                            });
                        } else {
                            if (uni.getStorage({
                                    key: 'acc'
                                })) {
                                uni.removeStorage({
                                    key: 'acc'
                                });
                            }
                        }
                        var pwd = checkValues.find(x => x == 2);
                        if (pwd) {
                            uni.setStorage({
                                key: 'pwd',
                                data: userPwd,
                            });
                        } else {
                            if (uni.getStorage({
                                    key: 'pwd'
                                })) {
                                uni.removeStorage({
                                    key: 'pwd'
                                });
                            }
                        }
                        setTimeout(() => {
                            this.$u.route({
                                type: 'reLaunch',
                                url: 'pages/index/index'
                            })
                            // this.$Router.replace({name:"tabbar"})
                        }, 200)
                    }).catch(res=>{
                        this.getVierificationCode();
                    });
                }
            },
            codeInput: function(e) {
                this.code = e.detail.value;
            },
            passInput: function(e) {
                this.pass = e.detail.value;
            },
            userInput: function(e) {
                this.user = e.detail.value;
            },
        }
    }
</script>
<style lang="scss" scoped>
    // @import '@/static/css/templatePage/custom_nav_bar.scss';
    /* æ‚¬æµ® */
    .rocket-sussuspension {
        animation: suspension 3s ease-in-out infinite;
    }
    @keyframes suspension {
        0%,
        100% {
            transform: translate(0, 0);
        }
        50% {
            transform: translate(-0.8rem, 1rem);
        }
    }
    .login {
        position: relative;
        height: 100%;
        z-index: 1;
        /* èƒŒæ™¯å›¾ç‰‡ start */
        &__bg {
            z-index: -1;
            position: fixed;
            &--top {
                top: 0;
                left: 0;
                right: 0;
                width: 100%;
                .bg {
                    width: 750rpx;
                    will-change: transform;
                }
                .rocket {
                    margin: 50rpx 28%;
                    width: 400rpx;
                    will-change: transform;
                }
            }
            &--bottom {
                bottom: -10rpx;
                left: 0;
                right: 0;
                width: 100%;
                // height: 144px;
                margin-bottom: env(safe-area-inset-bottom);
                image {
                    width: 750rpx;
                    will-change: transform;
                }
            }
        }
        /* èƒŒæ™¯å›¾ç‰‡ end */
        /* å†…容 start */
        &__wrapper {
            margin-top: 250rpx;
            width: 100%;
        }
        /* åˆ‡æ¢ start */
        &__mode {
            position: relative;
            margin: 0 auto;
            width: 476rpx;
            height: 77rpx;
            background-color: #FFFFFF;
            box-shadow: 0rpx 10rpx 50rpx 0rpx rgba(0, 3, 72, 0.1);
            border-radius: 39rpx;
            &__item {
                height: 77rpx;
                width: 100%;
                line-height: 77rpx;
                text-align: center;
                font-size: 31rpx;
                color: #908f8f;
                letter-spacing: 1em;
                text-indent: 1em;
                z-index: 2;
                transition: all 0.4s;
                &--active {
                    font-weight: bold;
                    color: #FFFFFF;
                }
            }
            &__slider {
                position: absolute;
                height: inherit;
                width: calc(476rpx);
                border-radius: inherit;
                box-shadow: 0rpx 18rpx 72rpx 18rpx rgba(0, 195, 255, 0.1);
                z-index: 1;
                transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
            }
        }
        /* åˆ‡æ¢ end */
        /* ç™»å½•注册信息 start */
        &__info {
            margin: 0 30rpx;
            margin-top: 105rpx;
            padding: 30rpx 51rpx;
            padding-bottom: 0;
            border-radius: 20rpx;
            background-color: #ffff;
            box-shadow: 0rpx 10rpx 50rpx 0rpx rgba(0, 3, 72, 0.1);
            &__item {
                &__input {
                    margin-top: 59rpx;
                    width: 100%;
                    height: 77rpx;
                    border: 1rpx solid #E6E6E6;
                    border-radius: 39rpx;
                    &__left-icon {
                        width: 10%;
                        font-size: 44rpx;
                        margin-left: 20rpx;
                        color: #AAAAAA;
                    }
                    &__content {
                        width: 80%;
                        padding-left: 10rpx;
                        &--verify-code {
                            width: 56%;
                        }
                        input {
                            font-size: 24rpx;
                            // letter-spacing: 0.1em;
                        }
                    }
                    &__right-icon {
                        width: 10%;
                        font-size: 44rpx;
                        margin-right: 20rpx;
                        color: #AAAAAA;
                    }
                    &__right-verify-code {
                        width: 34%;
                        margin-right: 20rpx;
                    }
                }
                &__button {
                    margin-top: 75rpx;
                    margin-bottom: 39rpx;
                    width: 100%;
                    height: 77rpx;
                    text-align: center;
                    font-size: 31rpx;
                    font-weight: bold;
                    line-height: 77rpx;
                    letter-spacing: 1em;
                    text-indent: 1em;
                    border-radius: 39rpx;
                    box-shadow: 1rpx 10rpx 24rpx 0rpx rgba(60, 129, 254, 0.35);
                }
                &__tips {
                    margin: 30rpx 0;
                    color: #AAAAAA;
                }
            }
        }
        /* ç™»å½•注册信息 end */
        /* ç™»å½•方式切换 start */
        &__way {
            margin: 0 auto;
            margin-top: 110rpx;
            &__item {
                &--icon {
                    width: 77rpx;
                    height: 77rpx;
                    font-size: 50rpx;
                    border-radius: 100rpx;
                    margin-bottom: 18rpx;
                    position: relative;
                    z-index: 1;
                    &::after {
                        content: " ";
                        position: absolute;
                        z-index: -1;
                        width: 100%;
                        height: 100%;
                        left: 0;
                        bottom: 0;
                        border-radius: inherit;
                        opacity: 1;
                        transform: scale(1, 1);
                        background-size: 100% 100%;
                        background-image: url(https://tnuiimage.tnkjapp.com/cool_bg_image/icon_bg5.png);
                    }
                }
            }
        }
        /* ç™»å½•方式切换 end */
        /* å†…容 end */
    }
    /deep/.input-placeholder {
        font-size: 24rpx;
        color: #E6E6E6;
    }
</style>
¼ª°²PDA/pages/stash/AGVFinish.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,92 @@
<template>
    <view>
        <view class="itemstyle">
            <uni-forms label-width="180">
                <uni-forms-item label="托盘条码:">
                    <uni-easyinput type="text" placeholder="请扫描托盘条码" ref='midInput' :focus="!focus" v-model="barcode"
                        @input="barcodeInput" />
                </uni-forms-item>
                <uni-forms-item>
                    <button @click="AGVFinish" type="primary" size="default" style="margin-top: 2%;">确认完成</button>
                </uni-forms-item>
            </uni-forms>
        </view>
        <u-toast ref="uToast" />
    </view>
</template>
<script>
    const innerAudioContext = uni.createInnerAudioContext();
    export default {
        data() {
            return {
                focus: false,
                barcode: "",
            }
        },
        onShow() {},
        onLoad(res) {
            this.focus = false;
        },
        methods: {
            // voiceSpeech(src) {
            //     innerAudioContext.src = src; // '../../static/success.mp3';
            //     innerAudioContext.play();
            // },
            barcodeInput() {
                this.$nextTick(function(x) {
                    if (this.barcode.length > 0) {
                        this.focus = true;
                    }
                })
            },
            AGVFinish() {
                if (this.barcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘码",
                        type: 'error'
                    })
                    return;
                }
                this.$u.post('http://10.30.4.92:9291/api/CTU_AGV/AGVFinish?barcode=' + this.barcode).then(
                    res => {
                        if (res.status) {
                            this.$refs.uToast.show({
                                title: "完成成功",
                                type: "success"
                            })
                            this.barcode = "";
                        } else {
                            this.$refs.uToast.show({
                                title: res.message,
                                type: "error"
                            })
                        }
                    })
            },
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    .content {
        display: flex;
        height: 150px;
    }
    .content-text {
        font-size: 14px;
        color: #666;
    }
    .itemstyle {
        margin-top: 30px;
        margin-left: 5%;
    }
    .headerstyle {
        width: 90%;
    }
</style>
¼ª°²PDA/pages/stash/AGVTasks.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,113 @@
<template>
    <view>
        <view class="itemstyle">
            <uni-forms label-width="180">
                <uni-forms-item label="托盘条码:">
                    <uni-easyinput type="text" placeholder="请扫描托盘条码" ref='midInput' :focus="!focus" v-model="barcode"
                        @input="barcodeInput" />
                </uni-forms-item>
                <uni-forms-item label="地址码:">
                    <uni-easyinput type="text" placeholder="请扫描地址码" ref='midInput' :focus="!focus" v-model="address"
                        @input="barcodeInput" />
                </uni-forms-item>
                <uni-forms-item>
                    <button @click="AGVTasks" type="primary" size="default" style="margin-top: 2%;">确认完成</button>
                </uni-forms-item>
            </uni-forms>
        </view>
        <u-toast ref="uToast" />
    </view>
</template>
<script>
    const innerAudioContext = uni.createInnerAudioContext();
    export default {
        data() {
            return {
                focus: false,
                barcode: "",
                address: "",
                    warehouseId: "",
            }
        },
        onShow() {},
        onLoad(res) {
            this.focus = false;
            this.warehouseId=res.warehouseId;
        },
        methods: {
            // voiceSpeech(src) {
            //     innerAudioContext.src = src; // '../../static/success.mp3';
            //     innerAudioContext.play();
            // },
            barcodeInput() {
                this.$nextTick(function(x) {
                    if (this.barcode.length > 0) {
                        this.focus = true;
                    }
                })
            },
            AGVTasks() {
                if (this.barcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘码",
                        type: 'error'
                    })
                    return;
                }
                if (this.address == "") {
                    this.$refs.uToast.show({
                        title: "请扫描地址码",
                        type: 'error'
                    })
                    return;
                }
                var postDate = {
                    MainData: {
                        barcode: this.barcode,
                        address: this.address,
                        warehouseId:this.warehouseId,
                    }
                }
                this.$u.post('http://127.0.0.1:9293/api/Task/AGVTasks', postDate).then(
                    res => {
                        if (res.status) {
                            this.$refs.uToast.show({
                                title: "任务创建成功成功",
                                type: "success"
                            })
                            this.barcode = "";
                        } else {
                            this.$refs.uToast.show({
                                title: res.message,
                                type: "error"
                            })
                        }
                    })
            },
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    .content {
        display: flex;
        height: 150px;
    }
    .content-text {
        font-size: 14px;
        color: #666;
    }
    .itemstyle {
        margin-top: 30px;
        margin-left: 5%;
    }
    .headerstyle {
        width: 90%;
    }
</style>
¼ª°²PDA/pages/stash/InEmpty.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,99 @@
<template>
    <view>
        <view class="itemstyle">
            <uni-forms label-width="180">
                <uni-forms-item label="托盘条码:">
                    <uni-easyinput type="text" placeholder="请扫描托盘条码" ref='midInput' :focus="!focus" v-model="barcode"
                        @input="barcodeInput" />
                </uni-forms-item>
                <uni-forms-item>
                    <button @click="InEmpty" type="primary" size="default" style="margin-top: 2%;">空箱入库</button>
                </uni-forms-item>
            </uni-forms>
        </view>
        <u-toast ref="uToast" />
    </view>
</template>
<script>
    const innerAudioContext = uni.createInnerAudioContext();
    export default {
        data() {
            return {
                focus: false,
                barcode: "",
                address: "",
                WarehouseId: ""
            }
        },
        onShow() {},
        onLoad(res) {
            this.WarehouseId = res.warehouseId;
            this.focus = false;
            if (res.warehouseId == 5) {
                this.address = "8005";
            }
        },
        methods: {
            // voiceSpeech(src) {
            //     innerAudioContext.src = src; // '../../static/success.mp3';
            //     innerAudioContext.play();
            // },
            barcodeInput() {
                this.$nextTick(function(x) {
                    if (this.barcode.length > 0) {
                        this.focus = true;
                    }
                })
            },
            InEmpty() {
                if (this.barcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘码",
                        type: 'error'
                    })
                    return;
                }
                this.$u.post('/api/Task/InEmpty?barcode=' + this.barcode + '&address=' + this.address + '&WarehouseId=' +
                    this.WarehouseId).then(
                    res => {
                        if (res.status) {
                            this.$refs.uToast.show({
                                title: "成功",
                                type: "success"
                            })
                            this.barcode = "";
                        } else {
                            this.$refs.uToast.show({
                                title: res.message,
                                type: "error"
                            })
                        }
                    })
            }
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    .content {
        display: flex;
        height: 150px;
    }
    .content-text {
        font-size: 14px;
        color: #666;
    }
    .itemstyle {
        margin-top: 30px;
        margin-left: 5%;
    }
    .headerstyle {
        width: 90%;
    }
</style>
¼ª°²PDA/pages/stash/InspectIn.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,612 @@
<template>
    <view>
        <uni-segmented-control style="margin-top: 15rpx;" :current="current" :values="items" @clickItem="onClickItem">
        </uni-segmented-control>
        <view class="content">
            <!-- <view v-if="current === 0" class="headerstyle">
                <view class="itemstyle">
                    <uni-forms label-width="180">
                        <uni-forms-item label="托盘条码:">
                            <uni-easyinput type="text" placeholder="请扫描托盘条码" ref='midInput' :focus="!focus"
                                v-model="barcode" @input="barcodeInput" />
                        </uni-forms-item>
                        <uni-forms-item label="内箱标签:">
                            <uni-easyinput type="text" placeholder="请扫描内箱标签" ref='midInput' :focus="focus"
                                v-model="materSn" @input="snInput" />
                        </uni-forms-item>
                        <uni-forms-item :label="Testlabel" v-if="Test">
                            <uni-easyinput type="text" :placeholder="Testplaceholder" ref='midInput'
                                v-model="Initiallife" />
                        </uni-forms-item>
                        <uni-forms-item>
                            <button @click="submit" type="primary" size="default" style="margin-top: 2%;">组盘</button>
                        </uni-forms-item>
                    </uni-forms>
                    <uni-list>
                        <uni-list-item direction="column" v-for="(item,index) in matInfos" :key="index">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <uni-icons type="trash" size="22" style="position: absolute;right: 5%;"
                                        @click="deleteList(index)">
                                    </uni-icons>
                                    <view class="uni-content">
                                        <view class="uni-title-sub uni-ellipsis-2">采购单号:{{item.purchaseOrderNo}}</view>
                                        <view class="uni-note">物料编码:{{item.materielCode}}</view>
                                        <view class="uni-note">批次号:{{item.lotNo}}</view>
                                        <view class="uni-note">数量:{{item.quantity}}</view>
                                        <view class="uni-note">生产日期:{{item.productionDate}}</view>
                                        <view class="uni-note">有效期:{{item.effectiveDate}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item>
                    </uni-list>
                </view>
            </view> -->
            <view v-if="current === 0" class="headerstyle">
                <view class="itemstyle">
                    <uni-forms label-width="120">
                        <uni-forms-item label="托盘条码">
                            <uni-easyinput type="text" :focus="!addressFocus" v-model="inboundBarcode"
                                placeholder="请扫描托盘条码" ref='midInput' @confirm="inputChangebarcode" />
                        </uni-forms-item>
                        <uni-forms-item label="地址条码">
                            <uni-easyinput type="text" v-model="address" :disabled="addressdisabled"
                                placeholder="请扫描地址条码" ref='midInput' :focus="addressFocus" />
                        </uni-forms-item>
                        <uni-forms-item>
                            <button @click="inbound" type="primary" size="default" style="margin-top: 2%;">入库确认</button>
                        </uni-forms-item>
                    </uni-forms>
                </view>
                <view>
                    <view class="uni-content" v-if="checkStockInfo" style="width: 500rpx; margin: 0px auto;">
                        <view class="uni-title-sub uni-ellipsis-2" style="font-size: 16px;">物料编号:{{checkStockInfo.materielCode}}</view>
                        <view class="uni-note" style="font-size: 16px;">检验数量:{{checkStockInfo.receivedQuantity}}</view>
                        <view class="uni-note" style="font-size: 16px;">报废数量:{{checkStockInfo.scrappedQuantity}}</view>
                        <view class="uni-note" style="font-size: 16px;">特采数量:{{checkStockInfo.defectedQuantity}}</view>
                        <view class="uni-note" style="font-size: 16px;">合格数量:{{checkStockInfo.qualifiedQuantity}}</view>
                        <view class="uni-note" style="font-size: 16px;">库存数量:{{checkStockInfo.stockQuantity}}</view>
                    </view>
                </view>
            </view>
            <view v-if="current === 1" class="headerstyle">
                <view class="itemstyle">
                    <uni-forms label-width="180">
                        <uni-forms-item label="内箱标签:">
                            <uni-easyinput type="text" placeholder="请扫描内箱标签" ref='midInput' :focus="pkfocus"
                                v-model="pkmaterSn" @input="pksnInput" />
                        </uni-forms-item>
                        <uni-forms-item>
                            <button @click="pksubmit" type="primary" size="default" style="margin-top: 2%;">入平库</button>
                        </uni-forms-item>
                    </uni-forms>
                    <uni-list>
                        <uni-list-item direction="column" v-for="(item,index) in pkmatInfos" :key="index">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <uni-icons type="trash" size="22" style="position: absolute;right: 5%;"
                                        @click="pkdeleteList(index)">
                                    </uni-icons>
                                    <view class="uni-content">
                                        <view class="uni-title-sub uni-ellipsis-2">采购单号:{{item.purchaseOrderNo}}</view>
                                        <view class="uni-note">物料编码:{{item.materielCode}}</view>
                                        <view class="uni-note">批次号:{{item.lotNo}}</view>
                                        <view class="uni-note">数量:{{item.quantity}}</view>
                                        <view class="uni-note">生产日期:{{item.productionDate}}</view>
                                        <view class="uni-note">有效期:{{item.effectiveDate}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item>
                    </uni-list>
                </view>
            </view>
        </view>
        <u-toast ref="uToast" />
    </view>
</template>
<script>
    const innerAudioContext = uni.createInnerAudioContext();
    export default {
        data() {
            return {
                items: ['入库'], //, '单据信息', '解盘'
                current: 0,
                matTotal: [],
                matInfos: [],
                orderNo: "",
                label: "",
                orderInfo: [],
                focus: false,
                pkfocus: false,
                barcode: "",
                materSn: "",
                Initiallife: 1000,
                sns: [],
                sn: "",
                addressFocus: false,
                inboundBarcode: "",
                address: "",
                check: true,
                value: "",
                matInfo: [],
                value2: "",
                matTotals: [],
                warehouseId: "",
                Test: false,
                Testlabel: "",
                Testplaceholder: "",
                Testcheck: false,
                Summmary: 0,
                stockInfoDetail: [],
                addressdisabled: false,
                pksns: [],
                pkmaterSn: "",
                pkmatInfos: [],
                checkStockInfo:null
            }
        },
        onShow() {},
        onLoad(res) {
            this.focus = false;
            this.addressFocus = false;
            this.orderNo = res.orderNo;
            this.warehouseId = res.warehouseId;
            if (this.warehouseId == 6) { //测试架仓库区ID
                this.Test = true;
                this.Testlabel = "初始寿命:";
                this.Testplaceholder = "请输入初始寿命";
            } else if (this.warehouseId == 2) { //油墨仓库区ID
                this.Test = true;
                this.Testlabel = "数量:";
                this.Testplaceholder = "请输入数量";
                this.Initiallife = 16;
            } else if (this.warehouseId == 5) { //辅料仓库区ID
                this.address = "8005";
                this.items.push("入平库");
                this.items[1] = "入立库";
                this.address = "8005";
            } else if (this.warehouseId == 3) { //辅料仓库区ID
                this.address = "1011";
                this.addressdisabled = true;
            }
            this.label = "单据编号:" + this.orderNo;
            this.getData();
        },
        methods: {
            // voiceSpeech(src) {
            //     innerAudioContext.src = src; // '../../static/success.mp3';
            //     innerAudioContext.play();
            // },
            //wms入平库
            pksubmit() {
                if (this.pkmatInfos.length == 0) {
                    this.$refs.uToast.show({
                        title: "请扫描内箱标签",
                        type: 'error'
                    })
                    return;
                }
                this.$u.post('/api/InboundOrder/WMSInPinKu?warehouseId=' + this.warehouseId, this
                    .pksns).then(res => {
                    debugger
                    if (res.status) {
                        this.$refs.uToast.show({
                            title: "入库成功",
                            type: "success"
                        })
                        this.focus = false;
                        this.pkmatInfos = [];
                        this.pksns = [];
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                })
            },
            pksnInput() {
                this.$nextTick(() => {
                    if (this.pkmaterSn != "") {
                        this.focus = false;
                        var matSn = this.pkmaterSn;
                        setTimeout(() => {
                            this.pkmaterSn = "";
                        }, 10);
                        this.$u.post('/api/MaterielInfo/CodeAnalysis?serNum=' + matSn, {}).then((res) => {
                            if (res.status) {
                                this.pksns.push(res.data.serialNumber);
                                this.pkmatInfos.push(res.data);
                                if (!res.status) {
                                    this.$refs.uToast.show({
                                        title: res.message,
                                        type: "error"
                                    })
                                    // setTimeout(() => {
                                    //     this.voiceSpeech('../../static/fail.mp3');
                                    // }, 100);
                                    return;
                                }
                                // setTimeout(() => {
                                //     this.voiceSpeech('../../static/success.mp3');
                                // }, 100);
                                return;
                            } else {
                                this.$refs.uToast.show({
                                    title: res.message,
                                    type: "error"
                                })
                                // setTimeout(() => {
                                //     this.voiceSpeech('../../static/fail.mp3');
                                // }, 100);
                            }
                        })
                    }
                })
            },
            //解盘
            releasebox() {
                if (this.value.length == 0) {
                    this.$refs.uToast.show({
                        title: "请扫码",
                        type: "error"
                    })
                    return;
                }
                var param;
                var matInfo = this.value.split('|');
                if (matInfo.length == 7) {
                    param = {
                        MainData: {
                            "innerCode": this.value
                        }
                    }
                } else {
                    param = {
                        MainData: {
                            "barcode": this.value
                        }
                    }
                }
                this.$u.post('/api/StockOperate/ReleaseAllBox', param).then(resdt => {
                    if (resdt.status) {
                        uni.$showMsg('解盘成功!')
                        this.value = "";
                        this.matInfo = [];
                        this.matTotals = [];
                        this.value2 = "";
                    } else {
                        this.$refs.uToast.show({
                            title: resdt.message,
                            type: "error"
                        })
                    }
                })
            },
            releaseboxInput() {
                this.$nextTick(() => {
                    if (this.value.length == 0) {
                        return;
                    }
                    var matInfo = this.value.split('|');
                    this.matInfo = [];
                    if (matInfo.length == 7) {
                        this.$u.post('/api/StockOperate/GetStockInfoByInnerCode', {
                            MainData: {
                                "innerCode": this.value
                            }
                        }).then(res => {
                            if (res.status) {
                                this.matInfo = res.data.stockInfo;
                                this.matTotals = res.data.stockTotal;
                                this.value2 = res.data.barcode;
                            } else {
                                this.$refs.uToast.show({
                                    title: res.message,
                                    type: "error"
                                })
                            }
                        })
                    } else {
                        this.$u.post('/api/StockOperate/GetStockInfoByBarcode', {
                            MainData: {
                                "barcode": this.value
                            }
                        }).then(res => {
                            if (res.status) {
                                this.matInfo = res.data.stockInfo;
                                this.matTotals = res.data.stockTotal;
                                this.value2 = res.data.barcode;
                            } else {
                                this.$refs.uToast.show({
                                    title: res.message,
                                    type: "error"
                                })
                            }
                        })
                    }
                })
            },
            updateFocus() {
                debugger
                this.$nextTick(() => {
                    this.materSn = '';
                    if (!this.focus) {
                        this.focus = true;
                    }
                });
            },
            barcodeFocus() {
                debugger
                this.barcode = '';
                if (this.focus) {
                    this.focus = false;
                }
            },
            getData() {
                var postData = {
                    MainData: {
                        orderNo: this.orderNo
                    },
                }
                this.$u.post('/api/InboundOrderDetail/GetInboundOrderDetails', postData).then((res) => {
                    if (res.status) {
                        this.orderInfo = res.data;
                        if (this.orderInfo.length > 3) {
                            this.loadVisible = true;
                        }
                    }
                })
            },
            onClickItem(e) {
                this.focus = false;
                this.addressFocus = false;
                if (this.current !== e.currentIndex) {
                    this.current = e.currentIndex;
                    if (this.current == 2) {
                        this.getData();
                    }
                }
            },
            barcodeInput() {
                this.$nextTick(function(x) {
                    if (this.barcode.length > 0) {
                        // if (this.barcode.substring(0, 1) == 'A' || this.barcode.substring(0, 2) == 'TP') {
                        this.focus = true;
                        // } else {
                        //     this.$refs.uToast.show({
                        //         title: "扫码错误,请扫描托盘码",
                        //         type: "error"
                        //     })
                        // }
                    }
                })
            },
            snInput() {
                this.$nextTick(() => {
                    if (this.warehouseId == 6 || this.warehouseId == 2 || this.warehouseId == 3) {
                        if (this.sns.length > 0) {
                            this.sns = [];
                        }
                    }
                    if (this.materSn != "") {
                        this.focus = false;
                        if (this.warehouseId == 11) {
                            this.materSn = this.materSn.replace(/,SC.*/, '');
                        }
                        if (this.materSn.split(',').length != 6) {
                            this.materSn = "";
                            return;
                        }
                        var matSn = this.materSn;
                        //setTimeout(() => {
                        this.materSn = "";
                        //}, 10);
                        this.$u.post('/api/MaterielInfo/CodeAnalysis?serNum=' + matSn, {}).then((res) => {
                            this.Testcheck = false;
                            if (res.status) {
                                this.sns.push(res.data.serialNumber);
                                if (this.warehouseId == 6 || this.warehouseId == 2 || this.warehouseId ==
                                    3) {
                                    if (this.matInfos.length > 0) {
                                        this.matInfos = [];
                                    }
                                }
                                this.matInfos.push(res.data);
                                if (!res.status) {
                                    this.$refs.uToast.show({
                                        title: res.message,
                                        type: "error"
                                    })
                                    // setTimeout(() => {
                                    //     this.voiceSpeech('../../static/fail.mp3');
                                    // }, 100);
                                    return;
                                }
                                // setTimeout(() => {
                                //     this.voiceSpeech('../../static/success.mp3');
                                // }, 100);
                            } else {
                                this.$refs.uToast.show({
                                    title: res.message,
                                    type: "error"
                                })
                                // setTimeout(() => {
                                //     this.voiceSpeech('../../static/fail.mp3');
                                // }, 100);
                            }
                        })
                    }
                })
            },
            inbound() {
                if (this.inboundBarcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘条码",
                        type: "error"
                    })
                    return;
                }
                if (this.address == "") {
                    this.$refs.uToast.show({
                        title: "请扫描地址条码",
                        type: "error"
                    })
                    return;
                }
                var postData = {
                    MainData: {
                        "barcode": this.inboundBarcode,
                        "startPoint": this.address,
                        "warehouseId": this.warehouseId
                    }
                }
                this.$u.post('/api/Task/RequestInboundTask', postData).then(res => {
                    if (res.status) {
                        this.inboundBarcode = "";
                        if (this.warehouseId != 5 && this.warehouseId != 3) this.address = "";
                        this.checkStockInfo=null;
                        setTimeout(() => {
                            this.addressFocus = false;
                            this.$refs.uToast.show({
                                title: "成功",
                                type: "success"
                            })
                        }, 200);
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                }).catch(err => {
                    this.$refs.uToast.show({
                        title: err.message,
                        type: "error"
                    })
                })
            },
            inputChangebarcode() {
                this.addressFocus = false;
                this.$nextTick(function(x) {
                    if (this.inboundBarcode != '') {
                        this.addressFocus = true;
                    }
                })
                this.$nextTick(function(x) {
                    if (this.inboundBarcode != '') {
                        this.$u.post('/api/Task/InQualityConfirm?palletCode='+this.inboundBarcode, {}).then(res => {
                            // this.stockInfo = [];
                            this.checkStockInfo=null;
                            if (res.status) {
                                // this.stockInfo = res.data,
                                this.checkStockInfo = res.data;
                            } else {
                                this.inboundBarcode='';
                                this.$refs.uToast.show({
                                    // title: "未找到托盘信息",
                                    title: res.message,
                                    type: "error"
                                })
                            }
                        })
                    }
                })
            },
            deleteList(res) {
                this.matInfos.splice(res, 1);
                this.sns.splice(res, 1);
            },
            submit() {
                if (this.barcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘条码",
                        type: 'error'
                    })
                    return;
                }
                if (this.matInfos.length == 0) {
                    this.$refs.uToast.show({
                        title: "请扫描内箱标签",
                        type: 'error'
                    })
                    return;
                }
                if (this.Test) {
                    if (!this.Testcheck) {
                        this.Testcheck = true;
                        if (this.warehouseId == 2) {
                            this.$refs.uToast.show({
                                title: "请确认数量",
                                type: 'error'
                            })
                        } else if (this.warehouseId == 6) {
                            this.$refs.uToast.show({
                                title: "请确认初始寿命",
                                type: 'error'
                            })
                        }
                        return;
                    }
                }
                if (this.warehouseId == 2) { //油墨仓库区ID
                    this.sn = this.sns[0];
                    for (var i = 0; i < this.Initiallife - 1; i++) {
                        this.sns.push(this.sn);
                    }
                }
                let url = 'palletCode=' + this.barcode + '&initiallife=' + this.Initiallife + '&warehouseId=' + this
                    .warehouseId;
                this.$u.post('/api/InboundOrder/ManualMaterielGroup?' + url, this.sns).then(res => {
                    this.Testcheck = false;
                    if (res.status) {
                        this.$refs.uToast.show({
                            title: "组盘成功",
                            type: "success"
                        })
                        this.focus = false;
                        this.barcode = "";
                        this.matInfos = [];
                        this.sns = [];
                        this.matTotal = [];
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                })
            }
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    .content {
        display: flex;
        height: 150px;
    }
    .content-text {
        font-size: 14px;
        color: #666;
    }
    .itemstyle {
        margin-top: 30px;
        margin-left: 5%;
    }
    .headerstyle {
        width: 90%;
    }
</style>
¼ª°²PDA/pages/stash/OutEmpty.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,110 @@
<template>
    <view>
        <view class="itemstyle">
            <uni-forms label-width="180">
                <uni-forms-item label="数量:">
                    <uni-easyinput type="text" placeholder="请输入数量" ref='midInput' :focus="!focus" v-model="qty"
                        @input="barcodeInput" />
                </uni-forms-item>
                <uni-forms-item label="托盘条码:">
                    <uni-easyinput type="text" placeholder="请扫描托盘条码" ref='midInput' :focus="focus" v-model="barcode" />
                </uni-forms-item>
                <uni-forms-item>
                    <button @click="OutEmpty" type="primary" size="default" style="margin-top: 2%;">空箱出库</button>
                </uni-forms-item>
            </uni-forms>
        </view>
        <u-toast ref="uToast" />
    </view>
</template>
<script>
    const innerAudioContext = uni.createInnerAudioContext();
    export default {
        data() {
            return {
                focus: false,
                qty: "",
                address: "",
                barcode: "",
            }
        },
        onShow() {},
        onLoad(res) {
            this.WarehouseId = res.warehouseId;
            this.focus = false;
            this.qty = 1;
            if (res.warehouseId == 5) {
                this.address = "8001";
            }
        },
        methods: {
            // voiceSpeech(src) {
            //     innerAudioContext.src = src; // '../../static/success.mp3';
            //     innerAudioContext.play();
            // },
            barcodeInput() {
                // this.$nextTick(function(x) {
                //     if (this.barcode.length > 0) {
                //         this.focus = true;
                //     }
                // })
            },
            OutEmpty() {
                if (this.qty == "") {
                    this.$refs.uToast.show({
                        title: "请输入数量",
                        type: 'error'
                    })
                    return;
                }
                if (this.qty < 1) {
                    this.$refs.uToast.show({
                        title: "数量不能小于1",
                        type: 'error'
                    })
                    return;
                }
                this.$u.post('/api/Task/OutEmpty?qty=' + this.qty + '&address=' + this.address + '&WarehouseId=' +
                    this.WarehouseId + '&barcode=' + this.barcode).then(
                    res => {
                        if (res.status) {
                            this.$refs.uToast.show({
                                title: "成功",
                                type: "success"
                            })
                            this.qty = "";
                        } else {
                            this.$refs.uToast.show({
                                title: res.message,
                                type: "error"
                            })
                        }
                    })
            },
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    .content {
        display: flex;
        height: 150px;
    }
    .content-text {
        font-size: 14px;
        color: #666;
    }
    .itemstyle {
        margin-top: 30px;
        margin-left: 5%;
    }
    .headerstyle {
        width: 90%;
    }
</style>
¼ª°²PDA/pages/stash/OutProOrder.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,426 @@
<template>
    <view>
        <view class="itemstyle">
            <uni-forms label-width="180">
                <uni-forms-item label="外箱码:">
                    <uni-easyinput type="text" placeholder="请扫描外箱码" ref='midInput'  v-model="barcode" :focus="!focus"
                         class="search_box" :disabled="isDisable" @confirm="handleKeyPress"/>
                </uni-forms-item>
            </uni-forms>
        </view>
        <view style="padding: 0 0rpx 0rpx;">
            <!-- å½“前出库外包号 -->
            <view class="item_boxItem">
                <uni-list>
                    <uni-list-item direction="column" v-for="(item,index) in listShow" :key="index">
                        <template v-slot:body>
                            <view class="uni-list-box">
                                <uni-icons type="trash" size="22" style="position: absolute;right: 5%;"
                                    @click="deleteList(index)">
                                </uni-icons>
                                <view class="uni-content">
                                    <view class="uni-title-sub uni-ellipsis-2">外包:{{item.code}} &nbsp;&nbsp; æ•°é‡ï¼š{{item.qty}}</view>
                                </view>
                            </view>
                        </template>
                    </uni-list-item>
                </uni-list>
            </view>
        </view>
        <view style="padding: 0 14rpx 200rpx;">
            <!-- æ˜Žç»† -->
            <view v-for="i in list" :key="i.id" class="item_box">
                <view style="line-height: 17px;color: #596671;font-size: 14px;text-align: left;font-weight: bold;">订单明细行号:{{i.rowId}}
                </view>
                <view style="margin-top: 22rpx;height: 140rpx;display: flex;flex-direction: column;justify-content: space-around;">
                    <view style="color: #00070F;font-size: 12px;">客户代号:{{i.customer}}</view>
                    <view style="color: #00070F;font-size: 12px;">产品编号:{{i.pCode}}</view>
                    <view style="color: #00070F;font-size: 12px;">销售订单:{{i.saleOrder}}</view>
                    <view style="color: #f56c6c;font-size: 12px;">订单数量:{{i.qtyPcs}}</view>
                    <view style="color: #67c23a;font-size: 12px;">已出数量:{{i.overQtyPcs}}</view>
                </view>
                <view style="width: 100%;height: 1rpx;background-color: #00070F;margin-top: 28rpx;">
                </view>
            </view>
        </view>
        <view style="padding:20rpx;position: fixed;bottom: 0;left: 0;background-color:lightgray;width: 100%;z-index: 999;display: flex;justify-content: space-between;">
            <view style="margin-bottom: 22rpx;padding-left: 16rpx;line-height: 80rpx;">
                <view style="font-size: 24rpx;font-weight: bold;color: #f56c6c;">订单总数量:<text>{{orderQty}}</text></view>
                <view style="font-size: 24rpx;font-weight: bold;color: #67c23a;">已扫总数量:<text>{{total}}</text></view>
            </view>
            <view style="display: flex;height: 110rpx;margin-top: 40rpx;">
                <button @click="reset" type="default" size="default" style="margin-top: 2%;width: 160rpx;border: 1rpx solid #007aff;color: #007aff;margin-right: 30rpx;">重置</button>
                <button @click="InEmpty" type="primary" size="default" style="margin-top: 2%;width: 160rpx;">出货</button>
            </view>
        </view>
        <u-toast ref="uToast" />
    </view>
</template>
<script>
    const innerAudioContext = uni.createInnerAudioContext();
    export default {
        data() {
            return {
                focus: false,
                barcode: "",
                proOutNo: "",
                id: null,
                list:[],
                listOutBags:[],
                listShow:[],
                total:0,
                orderQty:0,
                isDisable:false
            }
        },
        onShow() {},
        onLoad(res) {
            this.proOutNo=res.proOutNo;
            this.GetDetail(res.id);
            this.id=res.id;
            uni.hideKeyboard(); //隐藏软键盘
        },
        methods: {
            handleKeyPress(e) {
                console.log(e);
                  // å›žè½¦ç¬¦ï¼ˆASCII 13)表示扫码结束
                  this.isDisable=true;
                  this.focus=true;
                  this.$nextTick(function(x) {
                      var values= this.barcode.split(',');
                      if(values.length==5){
                          // if (values.length != 5) {
                          //     this.$refs.uToast.show({
                          //         title: "扫描格式错误"+value,
                          //         type: 'error'
                          //     })
                          //     this.barcode="";
                          //     this.$refs.midInput.focus();
                          //     return;
                          // }
                          this.$u.post('/api/ProOutOrder/CheckCode?code='+this.barcode,{}).then(
                              res => {
                                  if (res.status) {
                                      //判断是否重复
                                      if (this.listShow.some(item => item.code === values[0])) {
                                          this.barcode="";
                                          setTimeout(() => {
                                              this.isDisable=false;
                                              this.focus=false;
                                          },200);
                                          this.$refs.uToast.show({
                                              title: "重复扫描"+values[0]+"已存在",
                                              type: 'error'
                                          })
                                          return;
                                      }
                                      if (this.list.some(item => item.pCode === values[1])) {
                                          var outCode=values[0];
                                          var outQty=parseInt(values[4]);
                                          //判断outQty为数字
                                          if (isNaN(outQty)) {
                                                  this.barcode="";
                                                  setTimeout(() => {
                                                      this.isDisable=false;
                                                      this.focus=false;
                                                  },200);
                                                  this.$refs.uToast.show({
                                                      title: "扫描格式错误"+values[4],
                                                      type: 'error'
                                                  })
                                                  return;
                                              }
                                          //判断outQty是否大于0
                                          if (outQty<=0) {
                                              this.barcode="";
                                              setTimeout(() => {
                                                  this.isDisable=false;
                                                  this.focus=false;
                                              },200);
                                              this.$refs.uToast.show({
                                                  title: "标签数必须大于0",
                                                  type: 'error'
                                              })
                                              return;
                                          }
                                          this.total+=outQty;
                                          if(this.orderQty<this.total){
                                              this.barcode="";
                                              setTimeout(() => {
                                                  this.isDisable=false;
                                                  this.focus=false;
                                              },200);
                                              this.$refs.uToast.show({
                                                  title: "订单数超出",
                                                  type: 'error'
                                              })
                                              return;
                                          }
                                          this.listShow.unshift({code:outCode,qty:outQty});
                                          console.log(this.listShow);
                                          //去除this.barcode的空格
                                          this.listOutBags.push(this.barcode.replace(/\s*/g, ""));
                                          this.barcode="";
                                          setTimeout(() => {
                                              this.isDisable=false;
                                              this.focus=false;
                                          },200);
                                      }else{
                                          this.barcode="";
                                          setTimeout(() => {
                                              this.isDisable=false;
                                              this.focus=false;
                                          },200);
                                          this.$refs.uToast.show({
                                              title: "扫描"+values[1]+"批号不在订单中",
                                              type: 'error'
                                          })
                                          return;
                                      }
                                  }
                              })
                      }
                  })
                },
            GetDetail(value) {
                this.$u.post('/api/ProOutOrder/GetOrderDetails?keyId='+value).then(
                    res => {
                        if (res.status) {
                            this.list=res.data.proOutOrderDetails;
                            this.orderQty=this.list.map(x=>{
                                return x.qtyPcs
                            }).reduce((a,b)=>{
                                return a+b
                            });
                        } else {
                            this.$refs.uToast.show({
                                title: res.message,
                                type: "error"
                            })
                        }
                    })
            },
            // voiceSpeech(src) {
            //     innerAudioContext.src = src; // '../../static/success.mp3';
            //     innerAudioContext.play();
            // },
            // barcodeInput(value) {
            //     this.isDisable=true;
            //     this.focus=true;
            //     setTimeout(x=>{
            //         this.$nextTick(function(x) {
            //             var values= this.barcode.split(',');
            //             if(values.length==5){
            //                 // if (values.length != 5) {
            //                 //     this.$refs.uToast.show({
            //                 //         title: "扫描格式错误"+value,
            //                 //         type: 'error'
            //                 //     })
            //                 //     this.barcode="";
            //                 //     this.$refs.midInput.focus();
            //                 //     return;
            //                 // }
            //                 this.$u.post('/api/ProOutOrder/CheckCode?code='+this.barcode,{}).then(
            //                     res => {
            //                         if (res.status) {
            //                             //判断是否重复
            //                             if (this.listShow.some(item => item.code === values[0])) {
            //                                 this.barcode="";
            //                                 setTimeout(() => {
            //                                     this.isDisable=false;
            //                                     this.focus=false;
            //                                 },200);
            //                                 this.$refs.uToast.show({
            //                                     title: "重复扫描"+values[0]+"已存在",
            //                                     type: 'error'
            //                                 })
            //                                 return;
            //                             }
            //                             if (this.list.some(item => item.pCode === values[1])) {
            //                                 var outCode=values[0];
            //                                 var outQty=parseInt(values[4]);
            //                                 //判断outQty为数字
            //                                 if (isNaN(outQty)) {
            //                                         this.barcode="";
            //                                         setTimeout(() => {
            //                                             this.isDisable=false;
            //                                             this.focus=false;
            //                                         },200);
            //                                         this.$refs.uToast.show({
            //                                             title: "扫描格式错误"+values[4],
            //                                             type: 'error'
            //                                         })
            //                                         return;
            //                                     }
            //                                 //判断outQty是否大于0
            //                                 if (outQty<=0) {
            //                                     this.barcode="";
            //                                     setTimeout(() => {
            //                                         this.isDisable=false;
            //                                         this.focus=false;
            //                                     },200);
            //                                     this.$refs.uToast.show({
            //                                         title: "标签数必须大于0",
            //                                         type: 'error'
            //                                     })
            //                                     return;
            //                                 }
            //                                 this.total+=outQty;
            //                                 if(this.orderQty<this.total){
            //                                     this.barcode="";
            //                                     setTimeout(() => {
            //                                         this.isDisable=false;
            //                                         this.focus=false;
            //                                     },200);
            //                                     this.$refs.uToast.show({
            //                                         title: "订单数超出",
            //                                         type: 'error'
            //                                     })
            //                                     return;
            //                                 }
            //                                 this.listShow.unshift({code:outCode,qty:outQty});
            //                                 console.log(this.listShow);
            //                                 //去除this.barcode的空格
            //                                 this.listOutBags.push(this.barcode.replace(/\s*/g, ""));
            //                                 this.barcode="";
            //                                 setTimeout(() => {
            //                                     this.isDisable=false;
            //                                     this.focus=false;
            //                                 },200);
            //                             }else{
            //                                 this.barcode="";
            //                                 setTimeout(() => {
            //                                     this.isDisable=false;
            //                                     this.focus=false;
            //                                 },200);
            //                                 this.$refs.uToast.show({
            //                                     title: "扫描"+values[1]+"批号不在订单中",
            //                                     type: 'error'
            //                                 })
            //                                 return;
            //                             }
            //                         }
            //                     })
            //             }
            //         })
            //     },200)
            // },
            deleteList(res) {
                let indexExist =-1;
                //查询this.listOutBags中是否有this.listShow[res].code
                this.listOutBags.forEach((item,index) => {
                    //item是否包含 this.listShow[res].code
                    if (item.includes(this.listShow[res].code)) {
                        indexExist=index;
                    }
                });
                console.log(indexExist);
                if (indexExist !=-1) { // å¦‚果找到了索引,则执行删除操作
                    this.total-=this.listShow[res].qty;
                    this.listOutBags.splice(indexExist, 1); // ä»Žç´¢å¼•位置开始删除一个元素
                    this.listShow.splice(res, 1);
                }
                setTimeout(() => {
                    this.isDisable=false;
                },200);
                this.barcode="";
            },
            reset(){
                this.listShow=[];
                this.total=0;
                this.listOutBags=[];
                this.focus=true;
                this.barcode="";
                setTimeout(() => {
                    this.barcode="";
                    this.isDisable=false;
                    this.focus=false;
                }, 200);
            },
            InEmpty() {
                // if (this.barcode == "") {
                //     this.$refs.uToast.show({
                //         title: "请扫描外箱码",
                //         type: 'error'
                //     })
                //     return;
                // }
                if(this.orderQty!==this.total){
                        this.$refs.uToast.show({
                            title: "请扫描"+this.orderQty+"数量",
                            type: 'error'
                        })
                        return;
                }
                var postData = {
                    MainData: {
                        "outProOrderNo":this.proOutNo
                    },
                    DelKeys:this.listOutBags
                }
                this.$u.post('/api/ProOutOrder/OutProScanCodeSync',postData).then(
                    res => {
                        if (res.status) {
                            this.$refs.uToast.show({
                                title: "成功",
                                type: "success"
                            })
                            this.reset();
                            this.GetDetail(this.id);
                        } else {
                            this.$refs.uToast.show({
                                title: res.message,
                                type: "error"
                            })
                        }
                    })
            }
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    .content {
        display: flex;
        height: 150px;
    }
    .content-text {
        font-size: 14px;
        color: #666;
    }
    .itemstyle {
        margin-top: 30px;
        margin-left: 5%;
    }
    .item_box {
        background-color: white;
        // height: 344rpx;
        border-radius: 12rpx;
        padding: 40rpx 38rpx 28rpx 34rpx;
        font-size: 24rpx;
        line-height: 34rpx;
        margin-top: 20rpx;
    }
    .item_boxItem {
        background-color: white;
        padding: 40rpx 38rpx 28rpx 34rpx;
        // height: 344rpx;
        border-radius: 12rpx;
        font-size: 24rpx;
        line-height: 17rpx;
    }
    .headerstyle {
        width: 90%;
    }
    .search_box {
        padding: 10rpx 20rpx 20rpx;
        background-color: white;
    }
</style>
¼ª°²PDA/pages/stash/ProBack.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,115 @@
<template>
    <view>
        <view class="itemstyle">
            <uni-forms label-width="180">
                <uni-forms-item label="托盘条码:">
                    <uni-easyinput type="text" placeholder="请扫描托盘条码" ref='midInput' :focus="!focus" v-model="barcode"
                        @input="barcodeInput" />
                </uni-forms-item>
                <uni-forms-item label="起点位置:">
                    <uni-easyinput type="text" placeholder="请扫描起点位置" ref='midInput' :focus="focusStart" v-model="address"
                        @input="addressInput" />
                </uni-forms-item>
                <uni-forms-item>
                    <button @click="InEmpty" type="primary" size="default" style="margin-top: 2%;">余料回库</button>
                </uni-forms-item>
            </uni-forms>
        </view>
        <u-toast ref="uToast" />
    </view>
</template>
<script>
    const innerAudioContext = uni.createInnerAudioContext();
    export default {
        data() {
            return {
                focus: false,
                focusStart:false,
                barcode: "",
                address: "",
                WarehouseId: ""
            }
        },
        onShow() {},
        onLoad(res) {
        },
        methods: {
            // voiceSpeech(src) {
            //     innerAudioContext.src = src; // '../../static/success.mp3';
            //     innerAudioContext.play();
            // },
            barcodeInput() {
                this.$nextTick(function(x) {
                    if (this.barcode.length > 0) {
                        this.focus = true;
                        this.focusStart=true;
                    }
                })
            },
            addressInput() {
                this.$nextTick(function(x) {
                    if (this.address.length > 0) {
                        this.focusStart = false;
                    }
                })
            },
            InEmpty() {
                if (this.barcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘码",
                        type: 'error'
                    })
                    return;
                }
                if (this.address == "") {
                    this.$refs.uToast.show({
                        title: "请扫描起点",
                        type: 'error'
                    })
                    return;
                }
                this.$u.post('/api/Task/BackProductTask?barcode=' + this.barcode + '&startPoint=' + this.address).then(
                    res => {
                        if (res.status) {
                            this.$refs.uToast.show({
                                title: "成功",
                                type: "success"
                            })
                            this.barcode = "";
                            this.address = "";
                        } else {
                            this.$refs.uToast.show({
                                title: res.message,
                                type: "error"
                            })
                        }
                    })
            }
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    .content {
        display: flex;
        height: 150px;
    }
    .content-text {
        font-size: 14px;
        color: #666;
    }
    .itemstyle {
        margin-top: 30px;
        margin-left: 5%;
    }
    .headerstyle {
        width: 90%;
    }
</style>
¼ª°²PDA/pages/stash/ProEmptyBack.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,115 @@
<template>
    <view>
        <view class="itemstyle">
            <uni-forms label-width="180">
                <uni-forms-item label="托盘条码:">
                    <uni-easyinput type="text" placeholder="请扫描托盘条码" ref='midInput' :focus="!focus" v-model="barcode"
                        @input="barcodeInput" />
                </uni-forms-item>
                <uni-forms-item label="起点位置:">
                    <uni-easyinput type="text" placeholder="请扫描起点位置" ref='midInput' :focus="focusStart" v-model="address"
                        @input="addressInput" />
                </uni-forms-item>
                <uni-forms-item>
                    <button @click="InEmpty" type="primary" size="default" style="margin-top: 2%;">空框回库</button>
                </uni-forms-item>
            </uni-forms>
        </view>
        <u-toast ref="uToast" />
    </view>
</template>
<script>
    const innerAudioContext = uni.createInnerAudioContext();
    export default {
        data() {
            return {
                focus: false,
                focusStart:false,
                barcode: "",
                address: "",
                WarehouseId: ""
            }
        },
        onShow() {},
        onLoad(res) {
        },
        methods: {
            // voiceSpeech(src) {
            //     innerAudioContext.src = src; // '../../static/success.mp3';
            //     innerAudioContext.play();
            // },
            barcodeInput() {
                this.$nextTick(function(x) {
                    if (this.barcode.length > 0) {
                        this.focus = true;
                        this.focusStart=true;
                    }
                })
            },
            addressInput() {
                this.$nextTick(function(x) {
                    if (this.address.length > 0) {
                        this.focusStart = false;
                    }
                })
            },
            InEmpty() {
                if (this.barcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘码",
                        type: 'error'
                    })
                    return;
                }
                if (this.address == "") {
                    this.$refs.uToast.show({
                        title: "请扫描起点",
                        type: 'error'
                    })
                    return;
                }
                this.$u.post('/api/Task/EmptyBackTask?barcode=' + this.barcode + '&startPoint=' + this.address).then(
                    res => {
                        if (res.status) {
                            this.$refs.uToast.show({
                                title: "成功",
                                type: "success"
                            })
                            this.barcode = "";
                            this.address = "";
                        } else {
                            this.$refs.uToast.show({
                                title: res.message,
                                type: "error"
                            })
                        }
                    })
            }
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    .content {
        display: flex;
        height: 150px;
    }
    .content-text {
        font-size: 14px;
        color: #666;
    }
    .itemstyle {
        margin-top: 30px;
        margin-left: 5%;
    }
    .headerstyle {
        width: 90%;
    }
</style>
¼ª°²PDA/pages/stash/ProOutOrderView.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,214 @@
<template>
    <view>
        <u-sticky>
            <view style="background-color: #ffffff;">
                <uni-search-bar @confirm="search" v-model="searchValue"></uni-search-bar>
            </view>
        </u-sticky>
        <uni-list :border="true">
            <uni-list-item direction="column" clickable @click="groupClick(item.proOutOrderNo)" link
                :to="page+item.proOutOrderNo+'&warehouseId='+warehouseId+'&id='+item.id" v-for="item in allReceivingOrders"
                :key="item.proOutOrderNo">
                <template v-slot:body>
                    <uni-group margin-top="20">
                        <view style="line-height: 17px;color: #596671;font-size: 14px;text-align: center;display: flex;justify-content: space-between;">
                            å‡ºè´§å•号&nbsp;&nbsp;{{item.proOutOrderNo}}
                        </view>
                        <view style="line-height: 17px;color: #596671;font-size: 14px;text-align: center;display: flex;justify-content: space-between;">
                            åˆ›å»ºæ—¶é—´&nbsp;&nbsp;{{item.createDate}}
                        </view>
                        <view
                            style="margin-top: 10rpx;display: flex;align-items: center; ">
                            <view style="text-align: center;line-height: 40rpx;border-radius: 8rpx; width: 238rpx;height: 40rpx;font-size: 22rpx;background-color:rgba(22,127,247,0.18);color: #1F63FF;">
                                è®¢å•状态&nbsp;&nbsp;{{item.ProOutStatus}}
                            </view>
                            <view style="text-align: center;line-height: 40rpx;border-radius: 8rpx; width: 158rpx;height: 40rpx;font-size: 22rpx;color: #F56C6C;">
                                æ€»æ•°é‡&nbsp;&nbsp;{{item.SumQty}}
                            </view>
                        </view>
                    </uni-group>
                </template>
            </uni-list-item>
        </uni-list>
        <uni-load-more :status="status" v-if="loadVisible"></uni-load-more>
        <u-back-top :scroll-top="scrollTop" top="400"></u-back-top>
    </view>
</template>
<script>
    import { ProOutStatus } from '../../common/config.js'
    export default {
        data() {
            return {
                page: "/pages/stash/OutProOrder?proOutNo=",
                loadVisible: false,
                searchValue: "",
                warehouseId: "",
                status: "more",
                allReceivingOrders: [],
                pageNo: 1,
                scrollTop: 0,
                isLoaded:false
            }
        },
        onLoad(res) {
            this.warehouseId = res.warehouseId;
            this.isLoaded = true;
            this.getData();
        },
        onPageScroll(e) {
            this.scrollTop = e.scrollTop;
        },
        onShow() {
            if (this.isLoaded) {
                // ä»Žå…¶ä»–页面返回时刷新
                this.getData();
            }
        },
        onReachBottom() {
            this.pageNo += 1;
            this.getData();
        },
        methods: {
            search(res) {
                this.pageNo = 1;
                this.getData();
            },
            groupClick() {
            },
            getData() {
                var postData = {
                    MainData: {
                        orderNo: this.searchValue,
                        pageNo: this.pageNo,
                        warehouseId: this.warehouseId,
                    },
                }
                this.$u.post('/api/ProOutOrder/GetProOutOrders', postData).then((res) => {
                    if (res.status) {
                        if (res.data.length > 0) {
                            if (this.searchValue == '') {
                                this.allReceivingOrders =res.data.map(i => ({
                                ...i,
                                ProOutStatus: ProOutStatus.find(item => item.value == i
                                    .proOrderStatus).label,
                                SumQty: i.details.map(item => item.qtyPcs).reduce((prev, next) => prev + next, 0)
                                }))
                                // this.allReceivingOrders = res.data;
                                if (this.allReceivingOrders.length > 3) {
                                    this.loadVisible = true;
                                } else {
                                    this.loadVisible = false;
                                }
                            } else {
                                // this.allReceivingOrders = res.data;
                                if (postData.MainData.pageNo == 1) {
                                    this.allReceivingOrders = [];
                                }
                                this.allReceivingOrders =res.data.map(i => ({
                                ...i,
                                ProOutStatus: ProOutStatus.find(item => item.value == i
                                    .proOrderStatus).label,
                                SumQty: i.details.map(item => item.qtyPcs).reduce((prev, next) => prev + next, 0)
                                }))
                                if (this.allReceivingOrders.length > 3) {
                                    this.loadVisible = true;
                                } else {
                                    this.loadVisible = false;
                                }
                            }
                        } else {
                            this.status = 'noMore';
                            //this.allReceivingOrders = [];
                            this.loadVisible = true;
                        }
                    }
                })
            }
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    page {
        display: flex;
        flex-direction: column;
        box-sizing: border-box;
        background-color: #efeff4;
        min-height: 100%;
        height: auto;
    }
    .tips {
        color: #67c23a;
        font-size: 14px;
        line-height: 40px;
        text-align: center;
        background-color: #f0f9eb;
        height: 0;
        opacity: 0;
        transform: translateY(-100%);
        transition: all 0.3s;
    }
    .tips-ani {
        transform: translateY(0);
        height: 40px;
        opacity: 1;
    }
    .content {
        width: 100%;
        display: flex;
    }
    .list-picture {
        width: 100%;
        height: 145px;
    }
    .thumb-image {
        width: 100%;
        height: 100%;
    }
    .ellipsis {
        display: flex;
        overflow: hidden;
    }
    .uni-ellipsis-1 {
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    }
    .uni-ellipsis-2 {
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }
    .customcss {
        display: flex;
        position: fixed;
        width: 100%;
        top: 10px;
        text-align: center;
        z-index: 999;
        left: 30px;
        height: 20%;
    }
    .footer {
        padding-top: 50%;
    }
</style>
¼ª°²PDA/pages/stash/QueryData.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,169 @@
<template>
    <view>
        <!-- <uni-forms ref="formData" :modelValue="formData" label-width="120"> -->
        <uni-forms class="customcss" label-width="120">
            <uni-forms-item label="托盘条码">
                <uni-easyinput type="text" :focus="!barcodefocus" v-model="barcode" placeholder="请扫描托盘条码" ref='midInput'
                    @input="locationNoinputChange()" />
            </uni-forms-item>
        </uni-forms>
        <uni-list>
            <uni-list-item direction="column" v-if="stockInfoBarcode">
                <template v-slot:body>
                    <view class="uni-list-box">
                        <view class="uni-content">
                            <view class="uni-title-sub uni-ellipsis-2">托盘号:{{stockInfoBarcode}}</view>
                            <view class="uni-title-sub uni-ellipsis-2">总数量:{{Summmary}}</view>
                        </view>
                    </view>
                </template>
            </uni-list-item>
            <uni-list-item direction="column" v-for="(item,index) in stockInfoDetail" :key="index">
                <template v-slot:body>
                    <view class="uni-list-box">
                        <view class="uni-content">
                            <view class="uni-title-sub uni-ellipsis-2">物料编号:{{item.materielCode}}</view>
                            <view class="uni-note">物料名称:{{item.materielName}}</view>
                            <view class="uni-note">物料批次:{{item.batchNo}}</view>
                            <view class="uni-note">库存数量:{{item.stockQuantity}}</view>
                            <view class="uni-note">出库数量:{{item.outboundQuantity}}</view>
                            <view class="uni-note">生产日期:{{item.productionDate}}</view>
                            <view class="uni-note">有 æ•ˆ æœŸï¼š{{item.effectiveDate}}</view>
                        </view>
                    </view>
                </template>
            </uni-list-item>
        </uni-list>
        <u-toast ref="uToast" />
    </view>
</template>
<script>
    export default {
        data() {
            return {
                // stockInfo: [],
                stockInfoDetail: [],
                barcode: '',
                Summmary: 0,
                barcodefocus: false,
                warehouseId: 0,
                stockInfoBarcode: '',
            }
        },
        onLoad(res) {
            this.warehouseId = res.warehouseId;
        },
        methods: {
            locationNoinputChange() {
                this.$nextTick(function(x) {
                    if (this.barcode != '') {
                        var postData = {
                            MainData: {
                                "barcode": this.barcode,
                                "warehouseId": this.warehouseId,
                            }
                        };
                        this.$u.post('/api/StockInfo/StockQueryData', postData).then(res => {
                            this.stockInfoBarcode = "";
                            // this.stockInfo = [];
                            this.stockInfoDetail = [];
                            if (res.status) {
                                this.stockInfoBarcode = res.data.palletCode,
                                    // this.stockInfo = res.data,
                                    this.stockInfoDetail = res.data.details
                                    //获取总数量
                                    this.stockInfoDetail.forEach(item => {
                                        this.Summmary+= item.stockQuantity;
                                    });
                            } else {
                                this.$refs.uToast.show({
                                    // title: "未找到托盘信息",
                                    title: res.message,
                                    type: "error"
                                })
                            }
                            this.barcode = "";
                        })
                    }
                })
            }
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    page {
        display: flex;
        flex-direction: column;
        box-sizing: border-box;
        background-color: #efeff4;
        min-height: 100%;
        height: auto;
    }
    .tips {
        color: #67c23a;
        font-size: 14px;
        line-height: 40px;
        text-align: center;
        background-color: #f0f9eb;
        height: 0;
        opacity: 0;
        transform: translateY(-100%);
        transition: all 0.3s;
    }
    .tips-ani {
        transform: translateY(0);
        height: 40px;
        opacity: 1;
    }
    .content {
        width: 100%;
        display: flex;
    }
    .list-picture {
        width: 100%;
        height: 145px;
    }
    .thumb-image {
        width: 100%;
        height: 100%;
    }
    .ellipsis {
        display: flex;
        overflow: hidden;
    }
    .uni-ellipsis-1 {
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    }
    .uni-ellipsis-2 {
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }
    .customcss {
        background-color: #fff;
        padding: 20rpx 40rpx;
        width: 100%;
    }
    .footer {
        // padding-top: 20%;
    }
</style>
¼ª°²PDA/pages/stash/TakeStock.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,437 @@
<template>
    <view>
        <uni-segmented-control :current="current" :values="items" @clickItem="onClickItem">
        </uni-segmented-control>
        <view class="content">
            <view v-if="current === 0" class="headerstyle">
                <view class="itemstyle">
                    <uni-forms label-width="120">
                        <uni-forms-item label="托盘条码">
                            <uni-easyinput type="text" :focus="!istrue" v-model="barcode" placeholder="请扫描托盘条码"
                                ref='midInput' @confirm="inputChangebarcode()" />
                        </uni-forms-item>
                        <uni-forms-item label="实盘数量">
                            <uni-easyinput type="number" v-model="num" placeholder="请输入实盘数量" ref='midInput' />
                        </uni-forms-item>
                        <uni-forms-item>
                            <button @click="picking" type="primary" style="margin-left: 0px;">盘点完成</button>
                        </uni-forms-item>
                    </uni-forms>
                    <view class="uni-content" v-if="takeStockObj">
                        <view class="uni-title-sub uni-ellipsis-2">盘点单号:{{orderNo}}</view>
                        <view class="uni-note">物料编码:{{takeStockObj.materielCode}}</view>
                        <view class="uni-note">物料批次:{{takeStockObj.batchNo}}</view>
                        <view class="uni-note">物料名称:{{takeStockObj.materielName}}</view>
                        <view class="uni-note">物料规格:{{takeStockObj.materielSpec}}</view>
                        <view class="uni-note">账面数量:{{takeStockObj.sysQty}}</view>
                    </view>
                </view>
            </view>
            <view v-if="current === 1" class="headerstyle">
                <view class="itemstyle">
                    <uni-forms label-width="120">
                        <uni-forms-item label="托盘条码">
                            <uni-easyinput type="text" :focus="!addressFocus" v-model="inboundBarcode"
                                placeholder="请扫描托盘条码" ref='midInput' @confirm="inputChangebarcode3" />
                        </uni-forms-item>
                        <uni-forms-item label="地址条码">
                            <uni-easyinput type="text" v-model="address" :disabled="addressdisabled" placeholder="请扫描地址条码" ref='midInput'
                                :focus="addressFocus" />
                        </uni-forms-item>
                        <uni-forms-item>
                            <button @click="inbound" type="primary" size="default" style="margin-top: 2%;">入库确认</button>
                        </uni-forms-item>
                    </uni-forms>
                </view>
                <view>
                    <uni-list>
                        <uni-list-item direction="column" v-if="inboundBarcode">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <view class="uni-content">
                                        <view class="uni-title-sub uni-ellipsis-2">组盘总数量:{{Summmary}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item>
                        <uni-list-item direction="column" v-for="(item,index) in stockInfoDetail" :key="index">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <view class="uni-content">
                                        <view class="uni-title-sub uni-ellipsis-2">物料编号:{{item.materielCode}}</view>
                                        <view class="uni-note">物料名称:{{item.materielName}}</view>
                                        <view class="uni-note">物料批次:{{item.batchNo}}</view>
                                        <view class="uni-note">组盘数量:{{item.stockQuantity}}</view>
                                        <view class="uni-note">生产日期:{{item.productionDate}}</view>
                                        <view class="uni-note">有 æ•ˆ æœŸï¼š{{item.effectiveDate}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item>
                    </uni-list>
                </view>
            </view>
        </view>
        <u-toast ref="uToast" />
    </view>
</template>
<script>
    // const SixUniTts = uni.requireNativePlugin("SmallSix-SixUniTts")
    export default {
        data() {
            return {
                items: ['盘点',  '入库'],//'拣选组盘',
                current: 0,
                isPicking: false,
                istrue: false,
                barcode: '',
                materialsns: "",
                boxBarcodes: [],
                sns: [],
                barcodefocus: true,
                totalNum: 0,
                pickNum: 0,
                num: null,
                orderTotalNum: 0,
                orderPickNum: 0,
                orderNo: "",
                matTotal: [],
                istrue2: false,
                barcode2: '',
                Summmary:0,
                innerboxcode: "",
                takeStockObj:null,
                sns2: [],
                barcodefocus: true,
                addressFocus: false,
                inboundBarcode: "",
                address: "",
                addressdisabled: false,
                warehouseId:"",
                stockInfoDetail:[]
            }
        },
        onLoad(res) {
            this.barcodefocus = false;
            this.istrue = false;
            this.warehouseId = res.warehouseId;
            this.orderNo=res.orderNo;
            if (this.warehouseId == 3) { //板料仓库区ID
                this.address = "1011";
                this.addressdisabled = true;
            }
        },
        methods: {
            onClickItem(e) {
                this.focus = false;
                this.addressFocus = false;
                if (this.current !== e.currentIndex) {
                    this.current = e.currentIndex;
                }
            },
            inbound() {
                var postData = {
                    MainData: {
                        "barcode": this.inboundBarcode,
                        "startPoint": this.address,
                        "warehouseId": this.warehouseId
                    }
                }
                this.$u.post('/api/Task/RequestInboundTask', postData).then(res => {
                    if (res.status) {
                        this.inboundBarcode = "";
                        if (this.warehouseId !== 3) //板料仓库区ID
                        {
                            this.address = "";
                        }
                        this.Summmary=0;
                        this.stockInfoDetail=[];
                        this.$refs.uToast.show({
                            title: "成功",
                            type: "success"
                        })
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                }).catch(err => {
                    this.$refs.uToast.show({
                        title: err.message,
                        type: "error"
                    })
                })
            },
            inputChangebarcode3() {
                this.addressFocus = false;
                this.$nextTick(function(x) {
                    if (this.inboundBarcode != '') {
                        this.addressFocus = true;
                    }
                })
                this.$nextTick(function(x) {
                                    if (this.inboundBarcode != '') {
                                        var postData = {
                                            MainData: {
                                                "barcode": this.inboundBarcode,
                                                "warehouseId": this.warehouseId,
                                            }
                                        };
                                        this.$u.post('/api/StockInfo/StockQueryData', postData).then(res => {
                                            // this.stockInfo = [];
                                            this.stockInfoDetail = [];
                                            this.Summmary=0;
                                            if (res.status) {
                                                // this.stockInfo = res.data,
                                                this.stockInfoDetail = res.data.details
                                                //获取总数量
                                                this.stockInfoDetail.forEach(item => {
                                                    this.Summmary += item.stockQuantity;
                                                });
                                            } else {
                                                this.$refs.uToast.show({
                                                    // title: "未找到托盘信息",
                                                    title: res.message,
                                                    type: "error"
                                                })
                                            }
                                        })
                                    }
                                })
            },
            picking() {
                if (this.barcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘条码",
                        type: "error"
                    })
                    return;
                }
                if(this.num==null || this.num==undefined){
                    this.$refs.uToast.show({
                        title: "盘点数量不能为空(可填0—有效数字值)",
                        type: "error"
                    })
                    return;
                }
                if(this.takeStockObj==null){
                    this.$refs.uToast.show({
                        title: "盘点信息为空",
                        type: "error"
                    })
                    return;
                }
                var params = {
                    MainData: {
                        "num": this.num,
                        "id": this.takeStockObj.id
                    }
                }
                this.$u.post('/api/TakeStockOrder/MatPicking', params).then(res => {
                    if (res.status) {
                        this.barcode="";
                        this.takeStockObj=null;
                        this.num=null;
                        this.$refs.uToast.show({
                            title: "盘点成功",
                            type: "success"
                        })
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                })
            },
            inputChange(e) {
                this.$nextTick(() => {
                    this.istrue = false;
                    var matInfo = this.materialsns.split('|');
                    if (matInfo.length == 7) {
                        var matObj = {
                            matCode: matInfo[1],
                            matProductionDate: matInfo[3],
                            matQty: matInfo[5],
                            orderNo: matInfo[6],
                            sn: this.materialsns,
                            isPicking: this.isPicking
                        }
                        var temp = this.boxBarcodes.find(x => x.orderNo == matObj.orderNo);
                        if (!temp) {
                            var tmp = this.matTotal.find(x => x.matCode == matObj.matCode);
                            if (!tmp) {
                                this.matTotal.push({
                                    matCode: matObj.matCode,
                                    matQuantity: parseInt(matObj.matQty)
                                })
                            } else {
                                tmp.matQuantity += parseInt(matObj.matQty);
                            }
                            this.sns.push({
                                innerboxcode: this.materialsns,
                                isSplit: this.isPicking
                            });
                            this.boxBarcodes.push(matObj);
                            this.isPicking = false;
                            setTimeout(this.updateFocus, 100);
                        } else {
                            this.$refs.uToast.show({
                                title: "扫码重复",
                                type: "error"
                            })
                            setTimeout(this.updateFocus, 100);
                        }
                    } else {
                        this.$refs.uToast.show({
                            title: "扫码错误,请扫描正确内箱码",
                            type: "error"
                        })
                        setTimeout(this.updateFocus, 100);
                    }
                })
            },
            checkedClick() {
                this.isPicking = !this.isPicking;
                this.istrue = false;
                this.$nextTick(function(x) {
                    if (this.barcode != '') {
                        this.istrue = true;
                    }
                })
            },
            updateFocus() {
                this.materialsns = '';
                if (!this.istrue) {
                    this.istrue = true;
                }
            },
            inputChangebarcode() {
                this.istrue = false;
                this.$nextTick(function(x) {
                    if (this.barcode != '') {
                        var postData = {
                            MainData: {
                                "orderNo": this.orderNo,
                                "takePalletCode": this.barcode
                            }
                        };
                        this.$u.post('/api/TakeStockOrder/GetTakeDetailInfo', postData).then(res => {
                            if (res.status) {
                                this.takeStockObj=null;
                                this.takeStockObj= res.data;
                            } else {
                                this.barcode="";
                                this.$refs.uToast.show({
                                    title: res.message,
                                    type: "error"
                                })
                            }
                        })
                        this.istrue = true;
                    }
                })
            },
            deleteList(res) {
                this.matTotal.map((item, index) => {
                    var temp = this.boxBarcodes.find(x => x.sn == res);
                    if (temp) {
                        if (item.matCode == temp.matCode) {
                            if (item.matQuantity - temp.matQty == 0) {
                                this.matTotal.splice(index, 1);
                            } else {
                                item.matQuantity -= temp.matQty;
                            }
                        }
                    }
                })
                this.sns.map((item, index) => {
                    if (item.innerboxcode == res) {
                        this.sns.splice(index, 1);
                    }
                })
                this.boxBarcodes.map((item, index) => {
                    if (item.sn == res) {
                        this.boxBarcodes.splice(index, 1);
                    }
                })
            },
            submit() {
                if (this.barcode2 == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘条码",
                        type: "error"
                    })
                    return;
                }
                if (this.innerboxcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描内箱标签",
                        type: "error"
                    })
                    return;
                }
                this.$u.post('/api/StockOperate/PickingBoxing', {
                    MainData: {
                        "barcode": this.barcode2,
                        "innerboxcode": this.innerboxcode
                    },
                    DelKeys: this.sns2
                }).then(res => {
                    if (res.status) {
                        uni.$showMsg('组盘成功!')
                        this.barcode2 = "";
                        this.innerboxcode = "";
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                }).catch(err => {
                    this.$refs.uToast.show({
                        title: err.message,
                        type: "error"
                    })
                })
            },
            inputChange2(e) {
            },
            inputChangebarcode2() {
                this.istrue2 = false;
                this.$nextTick(function(x) {
                    if (this.barcode2 != '') {
                        this.istrue2 = true;
                    }
                })
            },
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    .content {
        display: flex;
        height: 150px;
    }
    .content-text {
        font-size: 14px;
        color: #666;
    }
    .itemstyle {
        margin-top: 20px;
        margin-left: 5%;
    }
    .headerstyle {
        width: 90%;
    }
</style>
¼ª°²PDA/pages/stash/TakeStockOrder.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,209 @@
<template>
    <view>
        <u-sticky>
            <view style="background-color: #ffffff;">
                <uni-search-bar @confirm="search" v-model="searchValue"></uni-search-bar>
            </view>
        </u-sticky>
        <uni-list :border="true">
            <uni-list-item direction="column" clickable @click="groupClick(item.orderNo)" link
                :to="page+item.orderNo+'&warehouseId='+warehouseId+'&id='+item.id" v-for="item in allReceivingOrders"
                :key="item.orderNo">
                <template v-slot:body>
                    <uni-group margin-top="20">
                        <view style="line-height: 17px;color: #596671;font-size: 14px;text-align: center;display: flex;justify-content: space-between;">
                            ç›˜ç‚¹å•号&nbsp;&nbsp;{{item.orderNo}}
                        </view>
                        <view style="line-height: 17px;color: #596671;font-size: 14px;text-align: center;display: flex;justify-content: space-between;">
                            åˆ›å»ºæ—¶é—´&nbsp;&nbsp;{{item.createDate}}
                        </view>
                        <view
                            style="margin-top: 10rpx;display: flex;align-items: center; ">
                            <view style="text-align: center;line-height: 40rpx;border-radius: 8rpx; width: 238rpx;height: 40rpx;font-size: 22rpx;background-color:rgba(22,127,247,0.18);color: #1F63FF;">
                                ç›˜ç‚¹çŠ¶æ€&nbsp;&nbsp;{{item.takeStockStatus}}
                            </view>
                        </view>
                    </uni-group>
                </template>
            </uni-list-item>
        </uni-list>
        <uni-load-more :status="status" v-if="loadVisible"></uni-load-more>
        <u-back-top :scroll-top="scrollTop" top="400"></u-back-top>
    </view>
</template>
<script>
    import { TakeStockStatus } from '../../common/config.js'
    export default {
        data() {
            return {
                page: "/pages/stash/TakeStock?orderNo=",
                loadVisible: false,
                searchValue: "",
                warehouseId: "",
                status: "more",
                allReceivingOrders: [],
                pageNo: 1,
                scrollTop: 0,
                isLoaded:false
            }
        },
        onLoad(res) {
            this.warehouseId = res.warehouseId;
            this.isLoaded = true;
            this.getData();
        },
        onPageScroll(e) {
            this.scrollTop = e.scrollTop;
        },
        onShow() {
            if (this.isLoaded) {
                // ä»Žå…¶ä»–页面返回时刷新
                this.getData();
            }
        },
        onReachBottom() {
            this.pageNo += 1;
            this.getData();
        },
        methods: {
            search(res) {
                this.pageNo = 1;
                this.getData();
            },
            groupClick() {
            },
            getData() {
                var postData = {
                    MainData: {
                        orderNo: this.searchValue,
                        pageNo: this.pageNo,
                        warehouseId: this.warehouseId,
                    },
                }
                this.$u.post('/api/TakeStockOrder/GetTakeStockOrders', postData).then((res) => {
                    if (res.status) {
                        if (res.data.length > 0) {
                            if (this.searchValue == '') {
                                this.allReceivingOrders =res.data.map(i => ({
                                ...i,
                                takeStockStatus: TakeStockStatus.find(item => item.value == i
                                    .takeStockStatus).label
                                }))
                                // this.allReceivingOrders = res.data;
                                if (this.allReceivingOrders.length > 3) {
                                    this.loadVisible = true;
                                } else {
                                    this.loadVisible = false;
                                }
                            } else {
                                // this.allReceivingOrders = res.data;
                                if (postData.MainData.pageNo == 1) {
                                    this.allReceivingOrders = [];
                                }
                                this.allReceivingOrders =res.data.map(i => ({
                                ...i,
                                takeStockStatus: TakeStockStatus.find(item => item.value == i
                                    .takeStockStatus).label
                                }))
                                if (this.allReceivingOrders.length > 3) {
                                    this.loadVisible = true;
                                } else {
                                    this.loadVisible = false;
                                }
                            }
                        } else {
                            this.status = 'noMore';
                            //this.allReceivingOrders = [];
                            this.loadVisible = true;
                        }
                    }
                })
            }
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    page {
        display: flex;
        flex-direction: column;
        box-sizing: border-box;
        background-color: #efeff4;
        min-height: 100%;
        height: auto;
    }
    .tips {
        color: #67c23a;
        font-size: 14px;
        line-height: 40px;
        text-align: center;
        background-color: #f0f9eb;
        height: 0;
        opacity: 0;
        transform: translateY(-100%);
        transition: all 0.3s;
    }
    .tips-ani {
        transform: translateY(0);
        height: 40px;
        opacity: 1;
    }
    .content {
        width: 100%;
        display: flex;
    }
    .list-picture {
        width: 100%;
        height: 145px;
    }
    .thumb-image {
        width: 100%;
        height: 100%;
    }
    .ellipsis {
        display: flex;
        overflow: hidden;
    }
    .uni-ellipsis-1 {
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    }
    .uni-ellipsis-2 {
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }
    .customcss {
        display: flex;
        position: fixed;
        width: 100%;
        top: 10px;
        text-align: center;
        z-index: 999;
        left: 30px;
        height: 20%;
    }
    .footer {
        padding-top: 50%;
    }
</style>
¼ª°²PDA/pages/stash/boxing.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,650 @@
<template>
    <view>
        <uni-segmented-control :current="current" :values="items" @clickItem="onClickItem">
        </uni-segmented-control>
        <view class="content">
            <view v-if="current === 0" class="headerstyle">
                <view class="itemstyle">
                    <uni-forms label-width="180">
                        <uni-forms-item label="托盘条码:">
                            <uni-easyinput type="text" placeholder="请扫描托盘条码" ref='midInput' :focus="!focus"
                                v-model="barcode" @confirm="barcodeInput" />
                        </uni-forms-item>
                        <uni-forms-item label="内箱标签:">
                            <uni-easyinput type="text" placeholder="请扫描内箱标签" ref='midInput' :focus="focus"
                                v-model="materSn" @confirm="snInput" />
                        </uni-forms-item>
                        <uni-forms-item :label="Testlabel" v-if="Test">
                            <uni-easyinput type="text" :placeholder="Testplaceholder" ref='midInput'
                                v-model="Initiallife" />
                        </uni-forms-item>
                        <!-- <uni-forms-item>
                            <checkbox checked="check">是否满盘</checkbox>
                        </uni-forms-item> -->
                        <uni-forms-item>
                            <button @click="submit" type="primary" size="default" style="margin-top: 2%;">组盘</button>
                        </uni-forms-item>
                    </uni-forms>
                    <uni-list>
                        <!-- <uni-list-item direction="column" v-for="item in matTotal" :key="item.matCode">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <view class="uni-content">
                                        <view class="uni-title-sub uni-ellipsis-2">物料编码:{{item.matCode}}</view>
                                        <view class="uni-title-sub uni-ellipsis-2">数量:{{item.matQuantity}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item> -->
                        <uni-list-item direction="column" v-for="(item,index) in matInfos" :key="index">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <uni-icons type="trash" size="22" style="position: absolute;right: 5%;"
                                        @click="deleteList(index)">
                                    </uni-icons>
                                    <view class="uni-content">
                                        <view class="uni-title-sub uni-ellipsis-2">采购单号:{{item.purchaseOrderNo}}</view>
                                        <view class="uni-note">物料编码:{{item.materielCode}}</view>
                                        <view class="uni-note">批次号:{{item.lotNo}}</view>
                                        <view class="uni-note">数量:{{item.quantity}}</view>
                                        <view class="uni-note">生产日期:{{item.productionDate}}</view>
                                        <view class="uni-note">有效期:{{item.effectiveDate}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item>
                    </uni-list>
                </view>
            </view>
            <view v-if="current === 1" class="headerstyle">
                <view class="itemstyle">
                    <uni-forms label-width="120">
                        <uni-forms-item label="托盘条码">
                            <uni-easyinput type="text" :focus="!addressFocus" v-model="inboundBarcode"
                                placeholder="请扫描托盘条码" ref='midInput' @confirm="inputChangebarcode" />
                        </uni-forms-item>
                        <uni-forms-item label="地址条码">
                            <uni-easyinput type="text" v-model="address" :disabled="addressdisabled"
                                placeholder="请扫描地址条码" ref='midInput' :focus="addressFocus" />
                        </uni-forms-item>
                        <uni-forms-item>
                            <button @click="inbound" type="primary" size="default" style="margin-top: 2%;">入库确认</button>
                        </uni-forms-item>
                    </uni-forms>
                </view>
                <view>
                    <uni-list>
                        <uni-list-item direction="column" v-if="inboundBarcode">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <view class="uni-content">
                                        <view class="uni-title-sub uni-ellipsis-2">组盘总数量:{{Summmary}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item>
                        <uni-list-item direction="column" v-for="(item,index) in stockInfoDetail" :key="index">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <view class="uni-content">
                                        <view class="uni-title-sub uni-ellipsis-2">物料编号:{{item.materielCode}}</view>
                                        <view class="uni-note">物料名称:{{item.materielName}}</view>
                                        <view class="uni-note">物料批次:{{item.batchNo}}</view>
                                        <view class="uni-note">组盘数量:{{item.stockQuantity}}</view>
                                        <view class="uni-note">生产日期:{{item.productionDate}}</view>
                                        <view class="uni-note">有 æ•ˆ æœŸï¼š{{item.effectiveDate}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item>
                    </uni-list>
                </view>
            </view>
            <view v-if="current === 2" class="headerstyle">
                <view class="itemstyle">
                    <uni-forms label-width="180">
                        <uni-forms-item label="内箱标签:">
                            <uni-easyinput type="text" placeholder="请扫描内箱标签" ref='midInput' :focus="pkfocus"
                                v-model="pkmaterSn" @confirm="pksnInput" />
                        </uni-forms-item>
                        <uni-forms-item>
                            <button @click="pksubmit" type="primary" size="default" style="margin-top: 2%;">入平库</button>
                        </uni-forms-item>
                    </uni-forms>
                    <uni-list>
                        <uni-list-item direction="column" v-for="(item,index) in pkmatInfos" :key="index">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <uni-icons type="trash" size="22" style="position: absolute;right: 5%;"
                                        @click="pkdeleteList(index)">
                                    </uni-icons>
                                    <view class="uni-content">
                                        <view class="uni-title-sub uni-ellipsis-2">采购单号:{{item.purchaseOrderNo}}</view>
                                        <view class="uni-note">物料编码:{{item.materielCode}}</view>
                                        <view class="uni-note">批次号:{{item.lotNo}}</view>
                                        <view class="uni-note">数量:{{item.quantity}}</view>
                                        <view class="uni-note">生产日期:{{item.productionDate}}</view>
                                        <view class="uni-note">有效期:{{item.effectiveDate}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item>
                    </uni-list>
                </view>
            </view>
        </view>
        <u-toast ref="uToast" />
    </view>
</template>
<script>
    const innerAudioContext = uni.createInnerAudioContext();
    export default {
        data() {
            return {
                items: ['组盘', '入库'], //, '单据信息', '解盘'
                current: 0,
                matTotal: [],
                matInfos: [],
                orderNo: "",
                label: "",
                orderInfo: [],
                focus: false,
                pkfocus: false,
                barcode: "",
                materSn: "",
                Initiallife: 1000,
                sns: [],
                sn: "",
                addressFocus: false,
                inboundBarcode: "",
                address: "",
                check: true,
                value: "",
                matInfo: [],
                value2: "",
                matTotals: [],
                warehouseId: "",
                Test: false,
                Testlabel: "",
                Testplaceholder: "",
                Testcheck: false,
                Summmary: 0,
                stockInfoDetail: [],
                addressdisabled: false,
                pksns: [],
                pkmaterSn: "",
                pkmatInfos: []
            }
        },
        onShow() {},
        onLoad(res) {
            this.focus = false;
            this.addressFocus = false;
            this.orderNo = res.orderNo;
            this.warehouseId = res.warehouseId;
            if (this.warehouseId == 6) { //测试架仓库区ID
                this.Test = true;
                this.Testlabel = "初始寿命:";
                this.Testplaceholder = "请输入初始寿命";
            } else if (this.warehouseId == 2) { //油墨仓库区ID
                this.Test = true;
                this.Testlabel = "数量:";
                this.Testplaceholder = "请输入数量";
                this.Initiallife = 16;
            } else if (this.warehouseId == 5) { //辅料仓库区ID
                this.address = "8005";
                this.items.push("入平库");
                this.items[1] = "入立库";
                this.address = "8005";
            } else if (this.warehouseId == 3) { //辅料仓库区ID
                this.address = "1011";
                this.addressdisabled = true;
            }
            this.label = "单据编号:" + this.orderNo;
            this.getData();
        },
        methods: {
            // voiceSpeech(src) {
            //     innerAudioContext.src = src; // '../../static/success.mp3';
            //     innerAudioContext.play();
            // },
            //wms入平库
            pksubmit() {
                if (this.pkmatInfos.length == 0) {
                    this.$refs.uToast.show({
                        title: "请扫描内箱标签",
                        type: 'error'
                    })
                    return;
                }
                this.$u.post('/api/InboundOrder/WMSInPinKu?warehouseId=' + this.warehouseId, this
                    .pksns).then(res => {
                    debugger
                    if (res.status) {
                        this.$refs.uToast.show({
                            title: "入库成功",
                            type: "success"
                        })
                        this.focus = false;
                        this.pkmatInfos = [];
                        this.pksns = [];
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                })
            },
            pksnInput() {
                this.$nextTick(() => {
                    if (this.pkmaterSn != "") {
                        this.focus = false;
                        var matSn = this.pkmaterSn;
                        setTimeout(() => {
                            this.pkmaterSn = "";
                        }, 10);
                        this.$u.post('/api/MaterielInfo/CodeAnalysis?serNum=' + matSn, {}).then((res) => {
                            if (res.status) {
                                this.pksns.push(res.data.serialNumber);
                                this.pkmatInfos.push(res.data);
                                if (!res.status) {
                                    this.$refs.uToast.show({
                                        title: res.message,
                                        type: "error"
                                    })
                                    // setTimeout(() => {
                                    //     this.voiceSpeech('../../static/fail.mp3');
                                    // }, 100);
                                    return;
                                }
                                // setTimeout(() => {
                                //     this.voiceSpeech('../../static/success.mp3');
                                // }, 100);
                                return;
                            } else {
                                this.$refs.uToast.show({
                                    title: res.message,
                                    type: "error"
                                })
                                // setTimeout(() => {
                                //     this.voiceSpeech('../../static/fail.mp3');
                                // }, 100);
                            }
                        })
                    }
                })
            },
            //解盘
            releasebox() {
                if (this.value.length == 0) {
                    this.$refs.uToast.show({
                        title: "请扫码",
                        type: "error"
                    })
                    return;
                }
                var param;
                var matInfo = this.value.split('|');
                if (matInfo.length == 7) {
                    param = {
                        MainData: {
                            "innerCode": this.value
                        }
                    }
                } else {
                    param = {
                        MainData: {
                            "barcode": this.value
                        }
                    }
                }
                this.$u.post('/api/StockOperate/ReleaseAllBox', param).then(resdt => {
                    if (resdt.status) {
                        uni.$showMsg('解盘成功!')
                        this.value = "";
                        this.matInfo = [];
                        this.matTotals = [];
                        this.value2 = "";
                    } else {
                        this.$refs.uToast.show({
                            title: resdt.message,
                            type: "error"
                        })
                    }
                })
            },
            releaseboxInput() {
                this.$nextTick(() => {
                    if (this.value.length == 0) {
                        return;
                    }
                    var matInfo = this.value.split('|');
                    this.matInfo = [];
                    if (matInfo.length == 7) {
                        this.$u.post('/api/StockOperate/GetStockInfoByInnerCode', {
                            MainData: {
                                "innerCode": this.value
                            }
                        }).then(res => {
                            if (res.status) {
                                this.matInfo = res.data.stockInfo;
                                this.matTotals = res.data.stockTotal;
                                this.value2 = res.data.barcode;
                            } else {
                                this.$refs.uToast.show({
                                    title: res.message,
                                    type: "error"
                                })
                            }
                        })
                    } else {
                        this.$u.post('/api/StockOperate/GetStockInfoByBarcode', {
                            MainData: {
                                "barcode": this.value
                            }
                        }).then(res => {
                            if (res.status) {
                                this.matInfo = res.data.stockInfo;
                                this.matTotals = res.data.stockTotal;
                                this.value2 = res.data.barcode;
                            } else {
                                this.$refs.uToast.show({
                                    title: res.message,
                                    type: "error"
                                })
                            }
                        })
                    }
                })
            },
            updateFocus() {
                debugger
                this.$nextTick(() => {
                    this.materSn = '';
                    if (!this.focus) {
                        this.focus = true;
                    }
                });
            },
            barcodeFocus() {
                debugger
                this.barcode = '';
                if (this.focus) {
                    this.focus = false;
                }
            },
            getData() {
                var postData = {
                    MainData: {
                        orderNo: this.orderNo
                    },
                }
                this.$u.post('/api/InboundOrderDetail/GetInboundOrderDetails', postData).then((res) => {
                    if (res.status) {
                        this.orderInfo = res.data;
                        if (this.orderInfo.length > 3) {
                            this.loadVisible = true;
                        }
                    }
                })
            },
            onClickItem(e) {
                this.focus = false;
                this.addressFocus = false;
                if (this.current !== e.currentIndex) {
                    this.current = e.currentIndex;
                    if (this.current == 2) {
                        this.getData();
                    }
                }
            },
            barcodeInput() {
                this.$nextTick(function(x) {
                    if (this.barcode.length > 0) {
                        // if (this.barcode.substring(0, 1) == 'A' || this.barcode.substring(0, 2) == 'TP') {
                        this.focus = true;
                        // } else {
                        //     this.$refs.uToast.show({
                        //         title: "扫码错误,请扫描托盘码",
                        //         type: "error"
                        //     })
                        // }
                    }
                })
            },
            snInput() {
                this.$nextTick(() => {
                    if (this.warehouseId == 6 || this.warehouseId == 2 || this.warehouseId == 3) {
                        if (this.sns.length > 0) {
                            this.sns = [];
                        }
                    }
                    if (this.materSn != "") {
                        this.focus = false;
                        if(this.warehouseId==11){
                            this.materSn=this.materSn.replace(/,SC.*/, '');
                        }
                        if (this.materSn.split(',').length != 6) {
                            this.materSn = "";
                            return;
                        }
                        var matSn = this.materSn;
                        //setTimeout(() => {
                        this.materSn = "";
                        //}, 10);
                        this.$u.post('/api/MaterielInfo/CodeAnalysis?serNum=' + matSn, {}).then((res) => {
                            this.Testcheck = false;
                            if (res.status) {
                                this.sns.push(res.data.serialNumber);
                                if (this.warehouseId == 6 || this.warehouseId == 2 || this.warehouseId ==
                                    3) {
                                    if (this.matInfos.length > 0) {
                                        this.matInfos = [];
                                    }
                                }
                                this.matInfos.push(res.data);
                                if (!res.status) {
                                    this.$refs.uToast.show({
                                        title: res.message,
                                        type: "error"
                                    })
                                    // setTimeout(() => {
                                    //     this.voiceSpeech('../../static/fail.mp3');
                                    // }, 100);
                                    return;
                                }
                                // setTimeout(() => {
                                //     this.voiceSpeech('../../static/success.mp3');
                                // }, 100);
                            } else {
                                this.$refs.uToast.show({
                                    title: res.message,
                                    type: "error"
                                })
                                // setTimeout(() => {
                                //     this.voiceSpeech('../../static/fail.mp3');
                                // }, 100);
                            }
                        })
                    }
                })
            },
            inbound() {
                if (this.inboundBarcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘条码",
                        type: "error"
                    })
                    return;
                }
                if (this.address == "") {
                    this.$refs.uToast.show({
                        title: "请扫描地址条码",
                        type: "error"
                    })
                    return;
                }
                var postData = {
                    MainData: {
                        "barcode": this.inboundBarcode,
                        "startPoint": this.address,
                        "warehouseId": this.warehouseId
                    }
                }
                this.$u.post('/api/Task/RequestInboundTask', postData).then(res => {
                    if (res.status) {
                        this.inboundBarcode = "";
                        if (this.warehouseId != 5 && this.warehouseId != 3) this.address = "";
                        this.stockInfoDetail = [];
                        //获取总数量
                        this.Summmary = 0;
                        setTimeout(() => {
                            this.addressFocus = false;
                            this.$refs.uToast.show({
                                title: "成功",
                                type: "success"
                            })
                        }, 200);
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                }).catch(err => {
                    this.$refs.uToast.show({
                        title: err.message,
                        type: "error"
                    })
                })
            },
            inputChangebarcode() {
                this.addressFocus = false;
                this.$nextTick(function(x) {
                    if (this.inboundBarcode != '') {
                        this.addressFocus = true;
                    }
                })
                this.$nextTick(function(x) {
                    if (this.inboundBarcode != '') {
                        var postData = {
                            MainData: {
                                "barcode": this.inboundBarcode,
                                "warehouseId": this.warehouseId,
                            }
                        };
                        this.$u.post('/api/StockInfo/StockQueryData', postData).then(res => {
                            // this.stockInfo = [];
                            this.stockInfoDetail = [];
                            if (res.status) {
                                // this.stockInfo = res.data,
                                this.stockInfoDetail = res.data.details
                                //获取总数量
                                this.stockInfoDetail.forEach(item => {
                                    this.Summmary += item.stockQuantity;
                                });
                            } else {
                                this.$refs.uToast.show({
                                    // title: "未找到托盘信息",
                                    title: res.message,
                                    type: "error"
                                })
                            }
                        })
                    }
                })
            },
            deleteList(res) {
                this.matInfos.splice(res, 1);
                this.sns.splice(res, 1);
            },
            submit() {
                if (this.barcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘条码",
                        type: 'error'
                    })
                    return;
                }
                if (this.matInfos.length == 0) {
                    this.$refs.uToast.show({
                        title: "请扫描内箱标签",
                        type: 'error'
                    })
                    return;
                }
                if (this.Test) {
                    if (!this.Testcheck) {
                        this.Testcheck = true;
                        if (this.warehouseId == 2) {
                            this.$refs.uToast.show({
                                title: "请确认数量",
                                type: 'error'
                            })
                        } else if (this.warehouseId == 6) {
                            this.$refs.uToast.show({
                                title: "请确认初始寿命",
                                type: 'error'
                            })
                        }
                        return;
                    }
                }
                if (this.warehouseId == 2) { //油墨仓库区ID
                    this.sn = this.sns[0];
                    for (var i = 0; i < this.Initiallife - 1; i++) {
                        this.sns.push(this.sn);
                    }
                }
                let url = 'palletCode=' + this.barcode + '&initiallife=' + this.Initiallife + '&warehouseId=' + this
                    .warehouseId;
                this.$u.post('/api/InboundOrder/ManualMaterielGroup?' + url, this.sns).then(res => {
                    this.Testcheck = false;
                    if (res.status) {
                        this.$refs.uToast.show({
                            title: "组盘成功",
                            type: "success"
                        })
                        this.focus = false;
                        this.barcode = "";
                        this.matInfos = [];
                        this.sns = [];
                        this.matTotal = [];
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                })
            }
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    .content {
        display: flex;
        height: 150px;
    }
    .content-text {
        font-size: 14px;
        color: #666;
    }
    .itemstyle {
        margin-top: 30px;
        margin-left: 5%;
    }
    .headerstyle {
        width: 90%;
    }
</style>
¼ª°²PDA/pages/stash/inboundorder.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,216 @@
<template>
    <view>
        <u-sticky>
            <view style="background-color: #ffffff;">
                <uni-search-bar @confirm="search" v-model="searchValue"></uni-search-bar>
            </view>
        </u-sticky>
        <uni-list :border="true">
            <uni-list-item direction="column" clickable @click="groupClick(item.orderNo)" link
                :to="page+item.orderNo" v-for="item in allReceivingOrders" :key="item.orderNo">
                <template v-slot:body>
                    <uni-group margin-top="20">
                        <view style="line-height: 17px;color: #596671;font-size: 14px;text-align: center;display: flex;justify-content: space-between;">
                            å…¥åº“单号&nbsp;&nbsp;{{item.orderNo}}
                        </view>
                        <view style="margin-top: 10rpx;line-height: 17px;color: #596671;font-size: 14px;text-align: center;display: flex;justify-content: space-between;">
                            åˆ›å»ºäººå‘˜&nbsp;&nbsp;{{item.creater}}
                        </view>
                        <view style="margin-top: 10rpx;line-height: 17px;color: #596671;font-size: 14px;text-align: center;display: flex;justify-content: space-between;">
                            åˆ›å»ºæ—¥æœŸ&nbsp;&nbsp;{{item.createDate}}
                        </view>
                        <view
                            style="margin-top: 10rpx;display: flex;align-items: center; ">
                            <view style="text-align: center;line-height: 40rpx;border-radius: 8rpx; width: 238rpx;height: 40rpx;font-size: 22rpx;background-color:rgba(22,127,247,0.18);color: #1F63FF;">
                                è®¢å•状态&nbsp;&nbsp;{{item.InboundOrderStatus}}
                            </view>
                            <view style="text-align: center;line-height: 40rpx;border-radius: 8rpx; width: 158rpx;height: 40rpx;font-size: 22rpx;color: #F56C6C;">
                                æ€»é‡&nbsp;&nbsp;{{item.SumQty}}
                            </view>
                            <view style="text-align: center;line-height: 40rpx;border-radius: 8rpx; width: 158rpx;height: 40rpx;font-size: 22rpx;color: #F56C6C;">
                                å·²å…¥&nbsp;&nbsp;{{item.OverQty}}
                            </view>
                        </view>
                    </uni-group>
                </template>
            </uni-list-item>
        </uni-list>
        <uni-load-more :status="status" v-if="loadVisible"></uni-load-more>
        <u-back-top :scroll-top="scrollTop" top="400"></u-back-top>
    </view>
</template>
<script>
    import { InboundOrderStatus } from '../../common/config.js'
    export default {
        data() {
            return {
                page: "/pages/stash/raworderboxing?",
                loadVisible: false,
                searchValue: "",
                status: "more",
                allReceivingOrders: [],
                pageNo: 1,
                scrollTop: 0,
                warehouseId: "",
                isLoaded:false
            }
        },
        onLoad(res) {
            this.warehouseId = res.warehouseId;
            this.page = this.page + "warehouseId=" + this.warehouseId + "&orderNo=";
            this.getData();
        },
        onReachBottom() {
            this.pageNo += 1;
            this.getData();
            this.isLoaded=true;
        },
        onShow() {
            if (this.isLoaded) {
                // ä»Žå…¶ä»–页面返回时刷新
                this.getData();
            }
        },
        onPageScroll(e) {
            this.scrollTop = e.scrollTop;
        },
        methods: {
            search(res) {
                this.getData();
            },
            groupClick() {
            },
            getData() {
                var postData = {
                    MainData: {
                        warehouseId: this.warehouseId,
                        orderNo: this.searchValue,
                        pageNo: this.pageNo
                    },
                }
                this.$u.post('/api/InboundOrder/GetInboundOrders', postData).then((res) => {
                    if (res.status) {
                        if (res.data.length > 0) {
                            if (this.searchValue == '') {
                                this.allReceivingOrders = res.data.map(i => ({
                                    ...i,
                                    InboundOrderStatus: InboundOrderStatus.find(item => item.value == i
                                        .orderStatus).label,
                                    SumQty: i.details.map(item => item.orderQuantity).reduce((prev, next) => prev + next, 0),
                                    OverQty: i.details.map(item => item.overInQuantity).reduce((prev, next) => prev + next, 0)
                                }));
                                // this.allReceivingOrders = res.data;
                                if (this.allReceivingOrders.length > 3) {
                                    this.loadVisible = true;
                                } else {
                                    this.loadVisible = false;
                                }
                            } else {
                                this.allReceivingOrders = res.data.map(i => ({
                                    ...i,
                                    InboundOrderStatus: InboundOrderStatus.find(item => item.value == i
                                        .orderStatus).label,
                                    SumQty: i.details.map(item => item.orderQuantity).reduce((prev, next) => prev + next, 0),
                                    OverQty: i.details.map(item => item.overInQuantity).reduce((prev, next) => prev + next, 0)
                                }));
                                if (this.allReceivingOrders.length > 3) {
                                    this.loadVisible = true;
                                } else {
                                    this.loadVisible = false;
                                }
                            }
                        } else {
                            this.status = 'noMore';
                            //this.allReceivingOrders = [];
                            this.loadVisible = true;
                        }
                    }
                })
            }
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    page {
        display: flex;
        flex-direction: column;
        box-sizing: border-box;
        background-color: #efeff4;
        min-height: 100%;
        height: auto;
    }
    .tips {
        color: #67c23a;
        font-size: 14px;
        line-height: 40px;
        text-align: center;
        background-color: #f0f9eb;
        height: 0;
        opacity: 0;
        transform: translateY(-100%);
        transition: all 0.3s;
    }
    .tips-ani {
        transform: translateY(0);
        height: 40px;
        opacity: 1;
    }
    .content {
        width: 100%;
        display: flex;
    }
    .list-picture {
        width: 100%;
        height: 145px;
    }
    .thumb-image {
        width: 100%;
        height: 100%;
    }
    .ellipsis {
        display: flex;
        overflow: hidden;
    }
    .uni-ellipsis-1 {
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    }
    .uni-ellipsis-2 {
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }
    .customcss {
        display: flex;
        position: fixed;
        width: 100%;
        top: 10px;
        text-align: center;
        z-index: 999;
        left: 30px;
        height: 20%;
    }
    .footer {
        padding-top: 50%;
    }
</style>
¼ª°²PDA/pages/stash/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,173 @@
<template>
    <!-- <u-card :title="title" > -->
    <view class="" slot="body">
        <!-- <view v-for="(item,index) in tree" :key="item.id"> -->
        <u-grid :col="2">
            <u-grid-item @tap="clickCoupon(item.url)" v-for="(item) in tree" :key="item.menuId">
                <u-icon   :name="item.icon" custom-prefix="custom-icon" size="50"
                    color="#888888"></u-icon>
                <view class="grid-text">{{item.menuName}}</view>
            </u-grid-item>
        </u-grid>
        <!-- </view> -->
        <u-toast ref="uToast" />
    </view>
    <!-- </u-card> -->
</template>
<script>
    import {
        config
    } from '../../common/config.js'
    export default {
        data() {
            return {
                // title: '操作功能'
                datas: [],
                tree: [],
                warehouseId: "",
                version: ""
            }
        },
        onShow() {
            // uni.getSystemInfo({
            //     success: (res) => {
            //         this.version = res.appWgtVersion;
            //         // console.log(res);
            //         //检测当前平台,如果是安卓则启动安卓更新
            //         if (res.platform == "android") {
            //             this.AndroidCheckUpdate();
            //         }
            //     }
            // });
        },
        onLoad(res) {
            // var id = this.$mp.query.id;
            // this.warehouseId = this.$mp.query.warehouseId;
            this.warehouseId = res.warehouseId;
            uni.setNavigationBarTitle({
                title: res.menuName
            });
            this.getCurrentTree(res.menuId);
        },
        mounted() {
        },
        methods: {
            AndroidCheckUpdate: function() {
                var _this = this;
                uni.request({
                    url: 'http://10.1.211.101:9004/api/PDA/GetPDAVersion?version=' + this.version,
                    method: 'GET',
                    data: {},
                    success: res => {
                        if (res.data.data) {
                            uni.showToast({
                                title: '有新的版本发布,检测到您目前为Wifi连接,程序已启动自动更新。新版本下载完成后将自动弹出安装程序。',
                                mask: false,
                                duration: 5000,
                                icon: "none"
                            });
                            var dtask = plus.downloader.createDownload(
                                "http://10.1.211.101:9004/api/PDA/DownLoadApp", {},
                                function(d, status) {
                                    // ä¸‹è½½å®Œæˆ
                                    if (status == 200) {
                                        plus.runtime.install(plus.io.convertLocalFileSystemURL(d
                                            .filename), {}, {}, function(error) {
                                            uni.showToast({
                                                title: '安装失败',
                                                mask: false,
                                                duration: 1500
                                            });
                                        })
                                    } else {
                                        uni.showToast({
                                            title: '更新失败',
                                            mask: false,
                                            duration: 1500
                                        });
                                    }
                                });
                            dtask.start();
                        }
                    },
                    fail: () => {
                        console.log('请求失败')
                    },
                    complete: () => {}
                });
            },
            getCurrentTree(id) {
                this.$u.post('/api/Sys_Menu/GetTreeMenuPDAStash?ParentId=' + id, {}).then(result => {
                    this.tree = result;
                })
            },
            getTree(id, data, isRootId) {
                this.datas.forEach((x) => {
                    if (x.pid == id) {
                        x.lv = data.lv + 1;
                        if (isRootId) {
                            x.rootId = id;
                        }
                        if (!data.children) data.children = [];
                        data.children.push(x);
                        this.getTree(x.id, x, isRootId);
                    }
                });
            },
            getPermission(text) {
                // return true;
                return this.datas.find(x => x.text == text);
            },
            clickCoupon(url) {
                // console.log("clickCoupon")
                if (this.hasLogin()) {
                    // this.$u.route(url)
                    this.$u.route({
                        url: url,
                        params: {
                            warehouseId: this.warehouseId
                        }
                    })
                } else {
                    this.$t.message.loading('登录失效请重新登录')
                    uni.reLaunch({
                        url: '/pages/login/login'
                    });
                }
            },
            lock() {
                console.log("lock")
                if (this.hasLogin()) {
                    this.$u.route("pages/feeding/feeding")
                } else {
                    this.$t.message.loading('登录失效请重新登录')
                    uni.reLaunch({
                        url: '/pages/login/login'
                    });
                }
            },
            //判断是否登录
            hasLogin() {
                let haslogin = uni.getStorageSync('jo_user')
                if (haslogin == null || haslogin == "") {
                    return false
                } else {
                    return true
                }
            }
        }
    }
</script>
<style lang="scss" scoped>
    .grid-text {
        font-size: 28rpx;
        margin-top: 4rpx;
        color: $u-type-info;
    }
</style>
¼ª°²PDA/pages/stash/outboundorder.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,177 @@
<template>
    <view>
        <u-sticky>
            <view style="background-color: #ffffff;">
                <uni-search-bar @confirm="search" v-model="searchValue"></uni-search-bar>
            </view>
        </u-sticky>
        <uni-list :border="true">
            <uni-list-item direction="column" clickable @click="groupClick(item.orderNo)" link
                :to="page+item.orderNo" v-for="item in allReceivingOrders" :key="item.orderNo">
                <template v-slot:body>
                    <uni-group margin-top="20">
                        <view> å•号:{{item.orderNo}} </view>
                        <view> åˆ›å»ºäºº:{{item.creater}} </view>
                        <view> æ—¥æœŸ:{{item.createDate}} </view>
                    </uni-group>
                </template>
            </uni-list-item>
        </uni-list>
        <uni-load-more :status="status" v-if="loadVisible"></uni-load-more>
        <u-back-top :scroll-top="scrollTop" top="400"></u-back-top>
    </view>
</template>
<script>
    export default {
        data() {
            return {
                page: "/pages/stash/outraworderboxing?",
                loadVisible: false,
                searchValue: "",
                status: "more",
                allReceivingOrders: [],
                pageNo: 1,
                scrollTop: 0,
                warehouseId: ""
            }
        },
        onLoad(res) {
            this.warehouseId = res.warehouseId;
            this.page = this.page + "warehouseId=" + this.warehouseId + "&orderNo=";
            this.getData();
        },
        onReachBottom() {
            this.pageNo += 1;
            this.getData();
        },
        onPageScroll(e) {
            this.scrollTop = e.scrollTop;
        },
        methods: {
            search(res) {
                this.getData();
            },
            groupClick() {
            },
            getData() {
                var postData = {
                    MainData: {
                        warehouseId: this.warehouseId,
                        orderNo: this.searchValue,
                        pageNo: this.pageNo
                    },
                }
                this.$u.post('/api/OutboundOrder/GetOutboundOrders', postData).then((res) => {
                    if (res.status) {
                        if (res.data.length > 0) {
                            if (this.searchValue == '') {
                                this.allReceivingOrders = this.allReceivingOrders.concat(res.data);
                                // this.allReceivingOrders = res.data;
                                if (this.allReceivingOrders.length > 3) {
                                    this.loadVisible = true;
                                } else {
                                    this.loadVisible = false;
                                }
                            } else {
                                this.allReceivingOrders = res.data;
                                if (this.allReceivingOrders.length > 3) {
                                    this.loadVisible = true;
                                } else {
                                    this.loadVisible = false;
                                }
                            }
                        } else {
                            this.status = 'noMore';
                            //this.allReceivingOrders = [];
                            this.loadVisible = true;
                        }
                    }
                })
            }
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    page {
        display: flex;
        flex-direction: column;
        box-sizing: border-box;
        background-color: #efeff4;
        min-height: 100%;
        height: auto;
    }
    .tips {
        color: #67c23a;
        font-size: 14px;
        line-height: 40px;
        text-align: center;
        background-color: #f0f9eb;
        height: 0;
        opacity: 0;
        transform: translateY(-100%);
        transition: all 0.3s;
    }
    .tips-ani {
        transform: translateY(0);
        height: 40px;
        opacity: 1;
    }
    .content {
        width: 100%;
        display: flex;
    }
    .list-picture {
        width: 100%;
        height: 145px;
    }
    .thumb-image {
        width: 100%;
        height: 100%;
    }
    .ellipsis {
        display: flex;
        overflow: hidden;
    }
    .uni-ellipsis-1 {
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    }
    .uni-ellipsis-2 {
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }
    .customcss {
        display: flex;
        position: fixed;
        width: 100%;
        top: 10px;
        text-align: center;
        z-index: 999;
        left: 30px;
        height: 20%;
    }
    .footer {
        padding-top: 50%;
    }
</style>
¼ª°²PDA/pages/stash/outraworderboxing.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,214 @@
<template>
    <view>
        <uni-segmented-control :current="current" :values="items" @clickItem="onClickItem">
        </uni-segmented-control>
        <view class="content">
            <view v-if="current === 0" class="headerstyle">
                <view class="itemstyle">
                    <uni-forms style="margin-left: 2%;margin-top: 20px;" label-width="180">
                        <uni-forms-item :label="label" style="margin-top: -20px;"></uni-forms-item>
                        <uni-forms-item label="物料码:" style="margin-top: -20px;">
                            <uni-easyinput type="text" placeholder="请扫描物料码" ref='midInput' :focus="!focus"
                                v-model="materSn" @input="snInput" />
                        </uni-forms-item>
                        <uni-list>
                            <uni-list-item direction="column" v-for="(item,index) in matInfos" :key="index">
                                <template v-slot:body>
                                    <view class="uni-content">
                                        <!-- <view class="uni-title-sub uni-ellipsis-2">采购单号:{{item.purchaseOrderNo}}</view> -->
                                        <view>物料编码:{{item.materielCode}}</view>
                                        <view>批次号:{{item.lotNo}}</view>
                                        <view>数量:{{item.quantity}}</view>
                                        <!-- <view class="uni-note">生产日期:{{item.productionDate}}</view>
                                        <view class="uni-note">有效期:{{item.effectiveDate}}</view> -->
                                    </view>
                                </template>
                            </uni-list-item>
                        </uni-list>
                        </uni-forms-item>
                    </uni-forms>
                    <uni-forms-item>
                        <button @click="submit" type="primary" size="default" style="margin-top: 2%;">确认出库</button>
                    </uni-forms-item>
                </view>
            </view>
            <view v-if="current === 1" class="headerstyle">
                <view class="itemstyle">
                    <uni-list :border="true">
                        <uni-list-item direction="column" v-for="(item,index) in orderInfo" :key="index">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <view class="uni-content">
                                        <view>单据号:{{orderNo}}</view>
                                        <view>物料编码:{{item.materielCode}}</view>
                                        <view>物料名称:{{item.materielName}}</view>
                                        <view>数量:{{item.orderQuantity+item.unit}}</view>
                                        <view>出库数量:{{item.orderQuantity+item.unit}}</view>
                                        <view>已出数量:{{item.overOutQuantity+item.unit}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item>
                    </uni-list>
                </view>
            </view>
        </view>
        <u-toast ref="uToast" />
    </view>
</template>
<script>
    const innerAudioContext = uni.createInnerAudioContext();
    export default {
        data() {
            return {
                items: ['物料信息', '单据信息'],
                current: 0,
                matInfos: [],
                orderNo: "",
                label: "",
                orderInfo: [],
                focus: false,
                materSn: "",
                sn: "",
                warehouseId: "",
            }
        },
        onShow() {},
        onLoad(res) {
            this.focus = false;
            this.orderNo = res.orderNo;
            this.warehouseId = res.warehouseId;
            this.label = "单据编号:" + this.orderNo;
            this.getData();
        },
        methods: {
            // voiceSpeech(src) {
            //     innerAudioContext.src = src; // '../../static/success.mp3';
            //     innerAudioContext.play();
            // },
            getData() {
                var postData = {
                    MainData: {
                        orderNo: this.orderNo
                    },
                }
                this.$u.post('/api/OutboundOrderDetail/GetOutboundOrderDetails', postData).then((res) => {
                    if (res.status) {
                        this.orderInfo = res.data;
                        if (this.orderInfo.length > 3) {
                            this.loadVisible = true;
                        }
                    }
                })
            },
            onClickItem(e) {
                this.focus = false;
                if (this.current !== e.currentIndex) {
                    this.current = e.currentIndex;
                    if (this.current == 2) {
                        this.getData();
                    }
                }
            },
            //扫码
            snInput() {
                this.$nextTick(() => {
                    if (this.materSn != "") {
                        this.focus = true;
                        var matSn = this.materSn;
                        setTimeout(() => {
                            this.materSn = "";
                        }, 10);
                        this.$u.post('/api/MaterielInfo/CodeAnalysis?serNum=' + matSn, {}).then((res) => {
                            this.Testcheck = false;
                            if (res.status) {
                                this.matInfos = [];
                                this.sn = res.data.serialNumber;
                                this.matInfos.push(res.data);
                                if (!res.status) {
                                    this.$refs.uToast.show({
                                        title: res.message,
                                        type: "error"
                                    })
                                    // setTimeout(() => {
                                    //     this.voiceSpeech('../../static/fail.mp3');
                                    // }, 100);
                                    return;
                                }
                                // setTimeout(() => {
                                //     this.voiceSpeech('../../static/success.mp3');
                                // }, 100);
                            } else {
                                this.matInfos = [];
                                this.sns = [];
                                this.$refs.uToast.show({
                                    title: res.message,
                                    type: "error"
                                })
                                // setTimeout(() => {
                                //     this.voiceSpeech('../../static/fail.mp3');
                                // }, 100);
                            }
                        })
                    }
                })
            },
            submit() {
                if (this.sn == "") {
                    this.$refs.uToast.show({
                        title: "请扫描物料码",
                        type: 'error'
                    })
                    return;
                }
                debugger
                this.$u.post('/api/OutboundOrder/outpinku', {
                    MainData: {
                        "orderNo": this.orderNo,
                        "sn": this.sn,
                        "warehouseId": this.warehouseId
                    }
                }).then(res => {
                    if (res.status) {
                        this.$refs.uToast.show({
                            title: "出库成功",
                            type: "success"
                        })
                        this.focus = false;
                        this.matInfos = [];
                        this.sn = "";
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                })
            }
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    .content {
        display: flex;
        height: 150px;
    }
    .content-text {
        font-size: 14px;
        color: #666;
    }
    .itemstyle {
        margin-top: 30px;
        margin-left: 5%;
    }
    .headerstyle {
        width: 90%;
    }
</style>
¼ª°²PDA/pages/stash/pickingMat.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,471 @@
<template>
    <view>
        <uni-segmented-control :current="current" :values="items" @clickItem="onClickItem">
        </uni-segmented-control>
        <view class="content">
            <view v-if="current === 0" class="headerstyle">
                <view class="itemstyle">
                    <uni-forms label-width="120">
                        <uni-forms-item label="托盘条码">
                            <uni-easyinput type="text" :focus="!istrue" v-model="barcode" placeholder="请扫描托盘条码"
                                ref='midInput' @input="inputChangebarcode()" />
                        </uni-forms-item>
                        <uni-forms-item>
                            <button @click="picking" type="primary" style="margin-left: 0px;">拣选完成</button>
                        </uni-forms-item>
                    </uni-forms>
                    <uni-list>
                        <uni-list-item direction="column" v-for="item in matInfos" :key="item.palletCode">
                            <template v-slot:body>
                                    <!-- <uni-icons type="trash" size="22" style="position: absolute;right: 5%;"
                                        @click="deleteList(item.sn)">
                                    </uni-icons> -->
                                    <view class="uni-content">
                                        <view>单据编号:{{item.orderNo}}</view>
                                        <view>托盘编号:{{item.palletCode}}</view>
                                        <view>物料批次:{{item.batchNo}}</view>
                                        <view>物料编码:{{item.materielCode}}</view>
                                        <view>物料名称:{{item.materielName}}</view>
                                        <view>单据数量:{{item.orderQuantity}}</view>
                                        <view>原始库存:{{item.originalQuantity}}</view>
                                        <view>分配库存:{{item.assignQuantity}}</view>
                                        <view>剩余库存:{{item.originalQuantity-item.assignQuantity}}</view>
                                    </view>
                            </template>
                        </uni-list-item>
                    </uni-list>
                </view>
            </view>
            <view v-if="current === 2" class="headerstyle">
                <view class="itemstyle">
                    <uni-forms label-width="120">
                        <uni-forms-item label="托盘条码">
                            <uni-easyinput type="text" :focus="!istrue2" v-model="barcode2" placeholder="请扫描托盘条码"
                                ref='midInput' @input="inputChangebarcode2()" />
                        </uni-forms-item>
                        <uni-forms-item label="内箱标签">
                            <uni-easyinput type="text" @input="inputChange2()" v-model="innerboxcode"
                                placeholder="请扫描内箱标签" ref='midInput' :focus="istrue2" />
                        </uni-forms-item>
                        <uni-forms-item>
                            <button @click="submit" type="primary" size="default" style="margin-top: 2%;">组盘</button>
                        </uni-forms-item>
                    </uni-forms>
                </view>
            </view>
            <view v-if="current === 1" class="headerstyle">
                <view class="itemstyle">
                    <uni-forms label-width="120">
                        <uni-forms-item label="托盘条码">
                            <uni-easyinput type="text" :focus="!addressFocus" v-model="inboundBarcode"
                                placeholder="请扫描托盘条码" ref='midInput' @input="inputChangebarcode3" />
                        </uni-forms-item>
                        <uni-forms-item label="地址条码">
                            <uni-easyinput type="text" v-model="address" :disabled = "addressdisabled" placeholder="请扫描地址条码" ref='midInput'
                                :focus="addressFocus" />
                        </uni-forms-item>
                        <uni-forms-item>
                            <button @click="inbound" type="primary" size="default" style="margin-top: 2%;">入库确认</button>
                        </uni-forms-item>
                    </uni-forms>
                </view>
                <view>
                    <uni-list>
                        <uni-list-item direction="column" v-if="inboundBarcode">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <view class="uni-content">
                                        <view class="uni-title-sub uni-ellipsis-2">总数量:{{Summmary}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item>
                        <uni-list-item direction="column" v-for="(item,index) in stockInfoDetail" :key="index">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <view class="uni-content">
                                        <view class="uni-title-sub uni-ellipsis-2">物料编号:{{item.materielCode}}</view>
                                        <view class="uni-note">物料名称:{{item.materielName}}</view>
                                        <view class="uni-note">物料批次:{{item.batchNo}}</view>
                                        <view class="uni-note">库存数量:{{item.stockQuantity}}</view>
                                        <view class="uni-note">出库数量:{{item.outboundQuantity}}</view>
                                        <view class="uni-note">生产日期:{{item.productionDate}}</view>
                                        <view class="uni-note">有 æ•ˆ æœŸï¼š{{item.effectiveDate}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item>
                    </uni-list>
                </view>
            </view>
        </view>
        <u-toast ref="uToast" />
    </view>
</template>
<script>
    // const SixUniTts = uni.requireNativePlugin("SmallSix-SixUniTts")
    export default {
        data() {
            return {
                items: ['拣选', '入库'], //'拣选组盘',
                current: 0,
                isPicking: false,
                istrue: false,
                matInfos: [],
                barcode: '',
                materialsns: "",
                boxBarcodes: [],
                sns: [],
                barcodefocus: true,
                totalNum: 0,
                pickNum: 0,
                num: 0,
                orderTotalNum: 0,
                orderPickNum: 0,
                orderNo: "",
                matTotal: [],
                istrue2: false,
                barcode2: '',
                innerboxcode: "",
                sns2: [],
                barcodefocus: true,
                addressFocus: false,
                inboundBarcode: "",
                address: "",
                warehouseId: 0,
                Summmary: 0,
                stockInfoDetail: [],
                addressdisabled: false
            }
        },
        onLoad(res) {
            this.barcodefocus = false;
            this.warehouseId = res.warehouseId;
            if (this.warehouseId == 5) {
                this.address = "8005"
            }else if (this.warehouseId == 3) {
                this.address = "1011";
                this.addressdisabled = true;
            }
            this.istrue = false;
            this.addressFocus = false;
        },
        methods: {
            onClickItem(e) {
                this.barcodeFo = true;
                this.focus = false;
                this.addressFocus = false;
                if (this.current !== e.currentIndex) {
                    this.current = e.currentIndex;
                }
            },
            inbound() {
                if (this.inboundBarcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘条码",
                        type: "error"
                    })
                    return;
                }
                if (this.address == "") {
                    this.$refs.uToast.show({
                        title: "请扫描地址条码",
                        type: "error"
                    })
                    return;
                }
                var postData = {
                    MainData: {
                        "barcode": this.inboundBarcode,
                        "startPoint": this.address,
                        "warehouseId": this.warehouseId
                    }
                }
                this.$u.post('/api/Task/RequestInboundTask', postData).then(res => {
                    if (res.status) {
                        uni.$showMsg(res.message);
                        this.inboundBarcode = "";
                        setTimeout(() => {
                            this.addressFocus = false;
                        }, 200);
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                }).catch(err => {
                    this.$refs.uToast.show({
                        title: err.message,
                        type: "error"
                    })
                })
            },
            inputChangebarcode3() {
                this.addressFocus = false;
                this.$nextTick(function(x) {
                    if (this.inboundBarcode != '') {
                        this.addressFocus = true;
                    }
                })
                this.$nextTick(function(x) {
                    if (this.inboundBarcode != '') {
                        var postData = {
                            MainData: {
                                "barcode": this.inboundBarcode,
                                "warehouseId": this.warehouseId,
                            }
                        };
                        this.$u.post('/api/StockInfo/StockQueryData', postData).then(res => {
                            // this.stockInfo = [];
                            this.stockInfoDetail = [];
                            if (res.status) {
                                    // this.stockInfo = res.data,
                                    this.stockInfoDetail = res.data.details
                                    //获取总数量
                                    this.stockInfoDetail.forEach(item => {
                                        this.Summmary+= item.stockQuantity;
                                    });
                            } else {
                                this.$refs.uToast.show({
                                    // title: "未找到托盘信息",
                                    title: res.message,
                                    type: "error"
                                })
                            }
                        })
                    }
                })
            },
            picking() {
                if (this.barcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘条码",
                        type: "error"
                    })
                    return;
                }
                this.$u.post('/api/OutStockLockInfo/MaterialPick?palletCode=' + this.barcode, {}).then(res => {
                    if (res.status) {
                        // if(this.warehouseId==5){
                        //     this.Finish("8005");
                        // }
                        uni.$showMsg('拣选成功!')
                        this.barcode = "";
                        this.matInfos = [];
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                })
            },
            Finish(code) {
                this.$u.post('http://127.0.0.1:9291/api/CTU_AGV/PutFinish?&code=' + code).then(
                    res => {
                        if (res.status) {
                            // this.$refs.uToast.show({
                            //     title: "完成成功",
                            //     type: "success"
                            // })
                            // this.barcode = "";
                        } else {
                            // this.$refs.uToast.show({
                            //     title: res.message,
                            //     type: "error"
                            // })
                        }
                    })
            },
            inputChange(e) {
                this.$nextTick(() => {
                    this.istrue = false;
                    var matInfo = this.materialsns.split('|');
                    if (matInfo.length == 7) {
                        var matObj = {
                            matCode: matInfo[1],
                            matProductionDate: matInfo[3],
                            matQty: matInfo[5],
                            orderNo: matInfo[6],
                            sn: this.materialsns,
                            isPicking: this.isPicking
                        }
                        var temp = this.boxBarcodes.find(x => x.orderNo == matObj.orderNo);
                        if (!temp) {
                            var tmp = this.matTotal.find(x => x.matCode == matObj.matCode);
                            if (!tmp) {
                                this.matTotal.push({
                                    matCode: matObj.matCode,
                                    matQuantity: parseInt(matObj.matQty)
                                })
                            } else {
                                tmp.matQuantity += parseInt(matObj.matQty);
                            }
                            this.sns.push({
                                innerboxcode: this.materialsns,
                                isSplit: this.isPicking
                            });
                            this.boxBarcodes.push(matObj);
                            this.isPicking = false;
                            setTimeout(this.updateFocus, 100);
                        } else {
                            this.$refs.uToast.show({
                                title: "扫码重复",
                                type: "error"
                            })
                            setTimeout(this.updateFocus, 100);
                        }
                    } else {
                        this.$refs.uToast.show({
                            title: "扫码错误,请扫描正确内箱码",
                            type: "error"
                        })
                        setTimeout(this.updateFocus, 100);
                    }
                })
            },
            checkedClick() {
                this.isPicking = !this.isPicking;
                this.istrue = false;
                this.$nextTick(function(x) {
                    if (this.barcode != '') {
                        this.istrue = true;
                    }
                })
            },
            updateFocus() {
                this.materialsns = '';
                if (!this.istrue) {
                    this.istrue = true;
                }
            },
            inputChangebarcode() {
                this.boxBarcodes = [];
                this.istrue = false;
                this.$nextTick(function(x) {
                    if (this.barcode != '') {
                        var postData = {
                            MainData: {
                                "barcode": this.barcode,
                                "warehouseId": this.warehouseId,
                            }
                        };
                        this.$u.post('/api/OutStockLockInfo/GetStockOutboundOrder', postData).then(res => {
                            this.matInfos = [];
                            if (res != null) {
                                this.matInfos = res
                            } else {
                                this.$refs.uToast.show({
                                    title: "未找到拣选信息",
                                    type: "error"
                                })
                            }
                        })
                        this.istrue = true;
                    }
                })
            },
            deleteList(res) {
                this.matTotal.map((item, index) => {
                    var temp = this.boxBarcodes.find(x => x.sn == res);
                    if (temp) {
                        if (item.matCode == temp.matCode) {
                            if (item.matQuantity - temp.matQty == 0) {
                                this.matTotal.splice(index, 1);
                            } else {
                                item.matQuantity -= temp.matQty;
                            }
                        }
                    }
                })
                this.sns.map((item, index) => {
                    if (item.innerboxcode == res) {
                        this.sns.splice(index, 1);
                    }
                })
                this.boxBarcodes.map((item, index) => {
                    if (item.sn == res) {
                        this.boxBarcodes.splice(index, 1);
                    }
                })
            },
            submit() {
                if (this.barcode2 == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘条码",
                        type: "error"
                    })
                    return;
                }
                if (this.innerboxcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描内箱标签",
                        type: "error"
                    })
                    return;
                }
                this.$u.post('/api/StockOperate/PickingBoxing', {
                    MainData: {
                        "barcode": this.barcode2,
                        "innerboxcode": this.innerboxcode
                    },
                    DelKeys: this.sns2
                }).then(res => {
                    if (res.status) {
                        uni.$showMsg('组盘成功!')
                        this.barcode2 = "";
                        this.innerboxcode = "";
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                }).catch(err => {
                    this.$refs.uToast.show({
                        title: err.message,
                        type: "error"
                    })
                })
            },
            inputChange2(e) {
            },
            inputChangebarcode2() {
                this.istrue2 = false;
                this.$nextTick(function(x) {
                    if (this.barcode2 != '') {
                        this.istrue2 = true;
                    }
                })
            },
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    .content {
        display: flex;
        height: 150px;
    }
    .content-text {
        font-size: 14px;
        color: #666;
    }
    .itemstyle {
        margin-top: 20px;
        margin-left: 5%;
    }
    .headerstyle {
        width: 90%;
    }
</style>
¼ª°²PDA/pages/stash/raworderboxing.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,558 @@
<template>
    <view>
        <uni-segmented-control :current="current" :values="items" @clickItem="onClickItem">
        </uni-segmented-control>
        <view class="content">
            <view v-if="current === 0" class="headerstyle">
                <view class="itemstyle">
                    <uni-forms label-width="180">
                        <uni-forms-item :label="label">
                        </uni-forms-item>
                        <uni-forms-item label="托盘条码:">
                            <uni-easyinput type="text" placeholder="请扫描托盘条码" ref='midInput' :focus="!focus"
                                v-model="barcode" @confirm="barcodeInput" />
                        </uni-forms-item>
                        <uni-forms-item label="内箱标签:">
                            <uni-easyinput type="text" placeholder="请扫描内箱标签" ref='midInput' :focus="focus"
                                v-model="materSn" @confirm="snInput" />
                        </uni-forms-item>
                        <uni-forms-item :label="Testlabel" v-if="Test">
                            <uni-easyinput type="text" :placeholder="Testplaceholder" ref='midInput'
                                v-model="Initiallife" />
                        </uni-forms-item>
                        <!-- <uni-forms-item>
                            <checkbox checked="check">是否满盘</checkbox>
                        </uni-forms-item> -->
                        <uni-forms-item>
                            <view style="display: flex;justify-content: space-around;margin-top: 2%;">
                                <button @click="reset" type="default" size="default"
                                    style="width: 160rpx;border: 1rpx solid #007aff;color: #007aff;">重置</button>
                                <button @click="submit" type="primary" size="default" style="width: 160rpx;">组盘</button>
                            </view>
                        </uni-forms-item>
                    </uni-forms>
                    <uni-list>
                        <!-- <uni-list-item direction="column" v-for="item in matTotal" :key="item.matCode">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <view class="uni-content">
                                        <view class="uni-title-sub uni-ellipsis-2">物料编码:{{item.matCode}}</view>
                                        <view class="uni-title-sub uni-ellipsis-2">数量:{{item.matQuantity}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item> -->
                        <uni-list-item direction="column" v-for="(item,index) in matInfos" :key="index">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <uni-icons type="trash" size="22" style="position: absolute;right: 5%;"
                                        @click="deleteList(index)">
                                    </uni-icons>
                                    <view class="uni-content">
                                        <view class="uni-title-sub uni-ellipsis-2">采购单号:{{item.purchaseOrderNo}}</view>
                                        <view class="uni-note">物料编码:{{item.materielCode}}</view>
                                        <view class="uni-note">批次号:{{item.lotNo}}</view>
                                        <view class="uni-note">数量:{{item.quantity}}</view>
                                        <view class="uni-note">生产日期:{{item.productionDate}}</view>
                                        <view class="uni-note">有效期:{{item.effectiveDate}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item>
                    </uni-list>
                </view>
            </view>
            <view v-if="current === 1" class="headerstyle">
                <view class="itemstyle">
                    <uni-forms label-width="120">
                        <uni-forms-item label="托盘条码">
                            <uni-easyinput type="text" :focus="!addressFocus" v-model="inboundBarcode"
                                placeholder="请扫描托盘条码" ref='midInput' @confirm="inputChangebarcode" />
                        </uni-forms-item>
                        <uni-forms-item label="地址条码">
                            <uni-easyinput type="text" v-model="address" :disabled="addressdisabled"
                                placeholder="请扫描地址条码" ref='midInput' :focus="addressFocus" />
                        </uni-forms-item>
                        <uni-forms-item>
                            <button @click="inbound" type="primary" size="default" style="margin-top: 2%;">入库确认</button>
                        </uni-forms-item>
                    </uni-forms>
                </view>
            </view>
            <view v-if="current === 2" class="headerstyle">
                <view class="itemstyle">
                    <uni-list :border="true">
                        <uni-list-item direction="column" v-for="(item,index) in orderInfo" :key="index">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <view class="uni-content">
                                        <view style="font-size: 18px;">单据号:{{orderNo}}</view>
                                        <view style="font-size: 18px;">物料编码:{{item.materielCode}}</view>
                                        <view>物料名称:{{item.materielName}}</view>
                                        <!-- <view>物料规格:{{item.materielSpec}}</view> -->
                                        <!-- <view style="font-size: 18px;">物料名称:{{item.matName}}</view> -->
                                        <view style="font-size: 18px;">数量:{{item.orderQuantity}}</view>
                                        <view style="font-size: 18px;">组盘数量:{{item.receiptQuantity}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item>
                    </uni-list>
                </view>
            </view>
            <view v-if="current === 3" class="headerstyle">
                <view class="itemstyle">
                    <uni-forms label-width="180">
                        <uni-forms-item label="内箱标签:">
                            <uni-easyinput type="text" placeholder="请扫描内箱标签" ref='midInput' :focus="!pkfocus"
                                v-model="pkmaterSn" @confirm="pksnInput" />
                        </uni-forms-item>
                        <uni-forms-item>
                            <view style="display: flex;justify-content: space-around;margin-top: 2%;">
                                <button @click="resetInPk" type="default" size="default"
                                    style="width: 160rpx;border: 1rpx solid #007aff;color: #007aff;">重置</button>
                                <button @click="pksubmit" type="primary" size="default"
                                    style="margin-top: 2%;">入平库</button>
                            </view>
                        </uni-forms-item>
                    </uni-forms>
                    <uni-list>
                        <uni-list-item direction="column" v-for="(item,index) in pkmatInfos" :key="index">
                            <template v-slot:body>
                                <view class="uni-list-box">
                                    <uni-icons type="trash" size="22" style="position: absolute;right: 5%;"
                                        @click="pkdeleteList(index)">
                                    </uni-icons>
                                    <view class="uni-content">
                                        <view class="uni-title-sub uni-ellipsis-2">采购单号:{{item.purchaseOrderNo}}</view>
                                        <view class="uni-note">物料编码:{{item.materielCode}}</view>
                                        <view class="uni-note">批次号:{{item.lotNo}}</view>
                                        <view class="uni-note">数量:{{item.quantity}}</view>
                                        <view class="uni-note">生产日期:{{item.productionDate}}</view>
                                        <view class="uni-note">有效期:{{item.effectiveDate}}</view>
                                    </view>
                                </view>
                            </template>
                        </uni-list-item>
                    </uni-list>
                </view>
            </view>
        </view>
        <u-toast ref="uToast" />
    </view>
</template>
<script>
    const innerAudioContext = uni.createInnerAudioContext();
    export default {
        data() {
            return {
                items: ['组盘', '入库', '单据信息'], //, '解盘'
                current: 0,
                matTotal: [],
                matInfos: [],
                orderNo: "",
                label: "",
                orderInfo: [],
                focus: false,
                pkfocus: false,
                barcode: "",
                materSn: "",
                Initiallife: 1000,
                sns: [],
                pksns: [],
                addressFocus: false,
                inboundBarcode: "",
                address: "",
                check: true,
                value: "",
                matInfo: [],
                value2: "",
                matTotals: [],
                warehouseId: "",
                Test: false,
                Testlabel: "",
                Testplaceholder: "",
                Testcheck: false,
                pkmaterSn: "",
                pkmatInfos: [],
                addressdisabled: false
            }
        },
        onShow() {},
        onLoad(res) {
            this.focus = false;
            this.addressFocus = false;
            this.orderNo = res.orderNo;
            this.warehouseId = res.warehouseId;
            if (this.warehouseId == 6) { //测试架仓库区ID
                this.Test = true;
                this.Testlabel = "初始寿命:";
                this.Testplaceholder = "请输入初始寿命";
            } else if (this.warehouseId == 2) { //油墨仓库区ID
                this.Test = true;
                this.Testlabel = "数量:";
                this.Testplaceholder = "请输入数量";
                this.Initiallife = 16;
            } else if (this.warehouseId == 5) { //辅料
                this.items.push("入平库");
                this.items[1] = "入立库";
                this.address = "8005";
            } else if (this.warehouseId == 3) { //辅料
                this.address = "1011";
                this.addressdisabled = true;
            }
            this.label = "单据编号:" + this.orderNo;
            this.getData();
        },
        methods: {
            // voiceSpeech(src) {
            //     innerAudioContext.src = src; // '../../static/success.mp3';
            //     innerAudioContext.play();
            // },
            updateFocus() {
                debugger
                this.$nextTick(() => {
                    this.materSn = '';
                    if (!this.focus) {
                        this.focus = true;
                    }
                });
            },
            barcodeFocus() {
                debugger
                this.barcode = '';
                if (this.focus) {
                    this.focus = false;
                }
            },
            getData() {
                var postData = {
                    MainData: {
                        orderNo: this.orderNo
                    },
                }
                this.$u.post('/api/InboundOrderDetail/GetInboundOrderDetails', postData).then((res) => {
                    if (res.status) {
                        this.orderInfo = res.data;
                        if (this.orderInfo.length > 3) {
                            this.loadVisible = true;
                        }
                    }
                })
            },
            onClickItem(e) {
                this.focus = false;
                this.addressFocus = false;
                if (this.current !== e.currentIndex) {
                    this.current = e.currentIndex;
                    if (this.current == 2) {
                        this.getData();
                    }
                }
            },
            barcodeInput() {
                this.$nextTick(function(x) {
                    if (this.barcode.length > 0) {
                        // if (this.barcode.substring(0, 1) == 'A' || this.barcode.substring(0, 2) == 'TP') {
                        this.focus = true;
                        // } else {
                        //     this.$refs.uToast.show({
                        //         title: "扫码错误,请扫描托盘码",
                        //         type: "error"
                        //     })
                        // }
                    }
                })
            },
            snInput() {
                this.$nextTick(() => {
                    if (this.materSn != "") {
                        this.focus = false;
                        var matSn = this.materSn;
                        if (this.warehouseId == 11) {
                            matSn = matSn.replace(/,SC.*/, '');
                        }
                        //查询matSn是否存在字符
                        if(matSn.indexOf("POHA")>0){
                            this.$u.post('/api/MaterielInfo/CodeAnalysis?serNum=' + matSn, {}).then((res) => {
                                this.Testcheck = false;
                                if (res.status) {
                                    this.sns.push(res.data.serialNumber);
                                    this.matInfos.push(res.data);
                                    if (res.message) {
                                        this.$refs.uToast.show({
                                            title: res.message,
                                            type: "error"
                                        })
                                        // setTimeout(() => {
                                        //     this.voiceSpeech('../../static/fail.mp3');
                                        // }, 100);
                                        return;
                                    }
                                    // setTimeout(() => {
                                    //     this.voiceSpeech('../../static/success.mp3');
                                    // }, 100);
                                } else {
                                    this.$refs.uToast.show({
                                        title: res.message,
                                        type: "error"
                                    })
                                    // setTimeout(() => {
                                    //     this.voiceSpeech('../../static/fail.mp3');
                                    // }, 100);
                                }
                            })
                        }
                        setTimeout(() => {
                            this.materSn = "";
                        }, 100);
                    }
                })
            },
            pksnInput() {
                this.$nextTick(() => {
                    if (this.pkmaterSn != "") {
                        var matSn = this.pkmaterSn;
                        if(matSn.indexOf("POHA")>0){
                            this.$u.post('/api/MaterielInfo/CodeAnalysis?serNum=' + matSn, {}).then((res) => {
                                if (res.status) {
                                    this.pksns.push(res.data.serialNumber);
                                    this.pkmatInfos.push(res.data);
                                    if (!res.status) {
                                        this.$refs.uToast.show({
                                            title: res.message,
                                            type: "error"
                                        })
                                        // setTimeout(() => {
                                        //     this.voiceSpeech('../../static/fail.mp3');
                                        // }, 100);
                                        return;
                                    }
                                    // setTimeout(() => {
                                    //     this.voiceSpeech('../../static/success.mp3');
                                    // }, 100);
                                    return;
                                } else {
                                    this.$refs.uToast.show({
                                        title: res.message,
                                        type: "error"
                                    })
                                    // setTimeout(() => {
                                    //     this.voiceSpeech('../../static/fail.mp3');
                                    // }, 100);
                                }
                            })
                        }
                        setTimeout(() => {
                            this.pkmaterSn = "";
                        }, 100);
                    }
                })
            },
            inbound() {
                if (this.inboundBarcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘条码",
                        type: "error"
                    })
                    return;
                }
                if (this.address == "") {
                    this.$refs.uToast.show({
                        title: "请扫描地址条码",
                        type: "error"
                    })
                    return;
                }
                var postData = {
                    MainData: {
                        "barcode": this.inboundBarcode,
                        "startPoint": this.address,
                        "warehouseId": this.warehouseId
                    }
                }
                this.$u.post('/api/Task/RequestInboundTask', postData).then(res => {
                    if (res.status) {
                        this.inboundBarcode = "";
                        if (this.warehouseId != 5) this.address = "";
                        setTimeout(() => {
                            this.addressFocus = false;
                            this.$refs.uToast.show({
                                title: "成功",
                                type: "success"
                            })
                        }, 200);
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                }).catch(err => {
                    this.$refs.uToast.show({
                        title: err.message,
                        type: "error"
                    })
                })
            },
            inputChangebarcode() {
                this.addressFocus = false;
                this.$nextTick(function(x) {
                    if (this.inboundBarcode != '') {
                        this.addressFocus = true;
                    }
                })
            },
            deleteList(res) {
                this.matInfos.splice(res, 1);
                this.sns.splice(res, 1);
            },
            pkdeleteList(res) {
                this.pkmatInfos.splice(res, 1);
                this.pksns.splice(res, 1);
            },
            reset() {
                this.barcode = "";
                this.matInfos = [];
                this.sns = [];
                this.materSn = "";
                if (this.warehouseId = !6) {
                    this.Initiallife = 0;
                }
            },
            resetInPk() {
                this.pkmaterSn = "";
                this.pkfocus = false;
                this.pkmatInfos = [];
                this.pksns = [];
            },
            pksubmit() {
                if (this.pkmatInfos.length == 0) {
                    this.$refs.uToast.show({
                        title: "请扫描内箱标签",
                        type: 'error'
                    })
                    return;
                }
                this.$u.post('/api/InboundOrder/InPinKu?warehouseId=' + this.warehouseId + "&orderNo=" + this.orderNo, this
                    .pksns).then(res => {
                    if (res.status) {
                        this.$refs.uToast.show({
                            title: "入库成功",
                            type: "success"
                        })
                        this.pkfocus = false;
                        this.pkmatInfos = [];
                        this.pksns = [];
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                })
            },
            submit() {
                if (this.barcode == "") {
                    this.$refs.uToast.show({
                        title: "请扫描托盘条码",
                        type: 'error'
                    })
                    return;
                }
                if (this.matInfos.length == 0) {
                    this.$refs.uToast.show({
                        title: "请扫描内箱标签",
                        type: 'error'
                    })
                    return;
                }
                if (this.Test) {
                    if (!this.Testcheck) {
                        this.Testcheck = true;
                        if (this.warehouseId == 2) {
                            this.$refs.uToast.show({
                                title: "请确认数量",
                                type: 'error'
                            })
                        } else if (this.warehouseId == 6) {
                            this.$refs.uToast.show({
                                title: "请确认初始寿命",
                                type: 'error'
                            })
                        }
                        return;
                    }
                }
                if (this.warehouseId == 2) { //油墨仓库区ID
                    this.sn = this.sns[0];
                    for (var i = 0; i < this.Initiallife - 1; i++) {
                        this.sns.push(this.sn);
                    }
                }
                this.$u.post('/api/InboundOrder/MaterielGroup', {
                    MainData: {
                        "palletCode": this.barcode,
                        "orderNo": this.orderNo,
                        "initiallife": this.Initiallife,
                        // "isFull": this.check
                        "warehouseId": this.warehouseId
                    },
                    DelKeys: this.sns
                }).then(res => {
                    this.Testcheck = false;
                    if (res.status) {
                        this.$refs.uToast.show({
                            title: "组盘成功",
                            type: "success"
                        })
                        this.focus = false;
                        this.barcode = "";
                        this.matInfos = [];
                        this.sns = [];
                        this.matTotal = [];
                        if (this.warehouseId != 6) { //测试架仓库区ID
                            this.Initiallife = "";
                        }
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                })
            }
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    .content {
        display: flex;
        height: 150px;
    }
    .content-text {
        font-size: 14px;
        color: #666;
    }
    .itemstyle {
        margin-top: 30px;
        margin-left: 5%;
    }
    .headerstyle {
        width: 90%;
    }
</style>
¼ª°²PDA/pages/stash/receiveorder.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,209 @@
<template>
    <view>
        <u-sticky>
            <view style="background-color: #ffffff;">
                <uni-search-bar @confirm="search" v-model="searchValue"></uni-search-bar>
            </view>
        </u-sticky>
        <uni-list :border="true">
            <uni-list-item direction="column" clickable @click="groupClick(item.receiveOrderNo)" link
                :to="page+item.receiveOrderNo+'&receiveOrderId='+item.receiveOrderId+'&warehouseId='+warehouseId" v-for="item in allReceivingOrders"
                :key="item.receiveOrderNo">
                <template v-slot:body>
                    <uni-group margin-top="20">
                        <view style="line-height: 17px;color: #596671;font-size: 14px;text-align: center;display: flex;justify-content: space-between;">
                            æ”¶è´§å•号&nbsp;&nbsp;{{item.receiveOrderNo}}
                        </view>
                        <view style="margin-top: 10rpx;line-height: 17px;color: #596671;font-size: 14px;text-align: center;display: flex;justify-content: space-between;">
                            ä¾›åº”商代号&nbsp;&nbsp;{{item.suppliersId}}
                        </view>
                        <view
                            style="margin-top: 10rpx;display: flex;align-items: center; ">
                            <view style="text-align: center;line-height: 40rpx;border-radius: 8rpx; width: 238rpx;height: 40rpx;font-size: 22rpx;background-color:rgba(22,127,247,0.18);color: #1F63FF;">
                                è®¢å•状态&nbsp;&nbsp;{{item.ReceiveOrderStatus}}
                            </view>
                            <view style="text-align: center;line-height: 40rpx;border-radius: 8rpx; width: 158rpx;height: 40rpx;font-size: 22rpx;color: #F56C6C;">
                                å·²æ”¶æ•°é‡&nbsp;&nbsp;{{item.SumQty}}
                            </view>
                        </view>
                    </uni-group>
                </template>
            </uni-list-item>
        </uni-list>
        <uni-load-more :status="status" v-if="loadVisible"></uni-load-more>
        <u-back-top :scroll-top="scrollTop" top="400"></u-back-top>
    </view>
</template>
<script>
    import { ReceiveOrderStatus } from '../../common/config.js'
    export default {
        data() {
            return {
                page: "/pages/stash/receiveorderoutbound?orderNo=",
                loadVisible: false,
                searchValue: "",
                warehouseId: "",
                status: "more",
                allReceivingOrders: [],
                pageNo: 1,
                scrollTop: 0,
                isLoaded:false
            }
        },
        onLoad(res) {
            this.warehouseId = res.warehouseId;
            this.getData();
            this.isLoaded=true;
        },
        onShow() {
            if (this.isLoaded) {
                // ä»Žå…¶ä»–页面返回时刷新
                this.getData();
            }
        },
        onPageScroll(e) {
            this.scrollTop = e.scrollTop;
        },
        onReachBottom() {
            this.pageNo += 1;
            this.getData();
        },
        methods: {
            search(res) {
                this.pageNo = 1;
                this.getData();
            },
            groupClick() {
            },
            getData() {
                var postData = {
                    MainData: {
                        orderNo: this.searchValue,
                        pageNo: this.pageNo,
                        warehouseId: this.warehouseId,
                    },
                }
                this.$u.post('/api/ReceiveOrder/GetReceiveOrders', postData).then((res) => {
                    if (res.status) {
                        if (res.data.length > 0) {
                            if (this.searchValue == '') {
                                this.allReceivingOrders = res.data.map(i => ({
                                    ...i,
                                    ReceiveOrderStatus: ReceiveOrderStatus.find(item => item.value == i
                                        .receiveOrderStatus).label,
                                    SumQty: i.details.map(item => item.receivedQuantity).reduce((prev, next) => prev + next, 0)
                                }))
                                // this.allReceivingOrders = res.data;
                                if (this.allReceivingOrders.length > 3) {
                                    this.loadVisible = true;
                                } else {
                                    this.loadVisible = false;
                                }
                            } else {
                                // this.allReceivingOrders = res.data;
                                if (postData.MainData.pageNo == 1) {
                                    this.allReceivingOrders = [];
                                }
                                this.allReceivingOrders = this.allReceivingOrders.concat(res.data);
                                if (this.allReceivingOrders.length > 3) {
                                    this.loadVisible = true;
                                } else {
                                    this.loadVisible = false;
                                }
                            }
                        } else {
                            this.status = 'noMore';
                            //this.allReceivingOrders = [];
                            this.loadVisible = true;
                        }
                    }
                })
            }
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    page {
        display: flex;
        flex-direction: column;
        box-sizing: border-box;
        background-color: #efeff4;
        min-height: 100%;
        height: auto;
    }
    .tips {
        color: #67c23a;
        font-size: 14px;
        line-height: 40px;
        text-align: center;
        background-color: #f0f9eb;
        height: 0;
        opacity: 0;
        transform: translateY(-100%);
        transition: all 0.3s;
    }
    .tips-ani {
        transform: translateY(0);
        height: 40px;
        opacity: 1;
    }
    .content {
        width: 100%;
        display: flex;
    }
    .list-picture {
        width: 100%;
        height: 145px;
    }
    .thumb-image {
        width: 100%;
        height: 100%;
    }
    .ellipsis {
        display: flex;
        overflow: hidden;
    }
    .uni-ellipsis-1 {
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    }
    .uni-ellipsis-2 {
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }
    .customcss {
        display: flex;
        position: fixed;
        width: 100%;
        top: 10px;
        text-align: center;
        z-index: 999;
        left: 30px;
        height: 20%;
    }
    .footer {
        padding-top: 50%;
    }
</style>
¼ª°²PDA/pages/stash/receiveorderoutbound.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,760 @@
<template>
    <view>
        <uni-segmented-control :current="current" :values="items" @clickItem="onClickItem">
        </uni-segmented-control>
        <view v-if="current === 0" class="headerstyle">
            <view class="itemstyle">
                <uni-forms style="margin-left: 2%;margin-top: 20px;" label-width="180">
                    <uni-forms-item :label="label" style="margin-top: -20px;"></uni-forms-item>
                    <!-- <uni-forms-item label="单据类型:生产领料单" style="margin-top: -20px;"></uni-forms-item> -->
                    <uni-forms-item label="内箱码:" style="margin-top: -20px;">
                        <uni-easyinput type="text" placeholder="请扫描内箱码" ref='midInput' :focus="!focus"
                            v-model="innerCode" @confirm="innercodeInput" />
                    </uni-forms-item>
                    <uni-forms-item :label="PurchaseOrderNo" style="margin-top: -20px;"></uni-forms-item>
                    <uni-forms-item :label="matCode" style="margin-top: -20px;"></uni-forms-item>
                    <uni-forms-item :label="LotNo" style="margin-top: -20px;"></uni-forms-item>
                    <uni-forms-item :label="ProductionDate" style="margin-top: -20px;"></uni-forms-item>
                    <uni-forms-item :label="EffectiveDate" style="margin-top: -20px;"></uni-forms-item>
                    <uni-forms-item :label="orderQty" style="margin-top: -20px;"></uni-forms-item>
                    <uni-forms-item :label="remaindQty" style="margin-top: -20px;">
                        <uni-easyinput type="text" placeholder="请输入实际数量" v-model="Quantity" ref='midInput' />
                    </uni-forms-item>
                </uni-forms>
                <uni-forms-item>
                    <view class="uni-flex uni-row" style="justify-content: space-between;margin-top: 2%;height: 45px;width: 520rpx;margin: 0px auto;">
                        <view>
                            <button @click="resetReceive" type="default" size="default" style="width: 200rpx;border: 1rpx solid #007aff;color: #007aff;">重置</button>
                        </view>
                        <view>
                            <button @click="submit" type="primary" size="default" style="width: 220rpx;">确认收货</button>
                        </view>
                    </view>
                </uni-forms-item>
                <uni-forms-item>
                    <view style="margin-top: 2%;height: 45px;width: 520rpx;margin: 0px auto;">
                        <button @click="submit1" type="primary" size="default" style="margin-top: 2%;backgroundColor:#1AAD19;borderColor:#1AAD19">完成收货</button>
                    </view>
                </uni-forms-item>
            </view>
        </view>
        <view v-if="current === 1" class="headerstyle">
            <view class="itemstyle">
                <!-- <uni-forms label-width="180">
                    <uni-forms-item label="区域">
                        <uni-data-select v-if="show" v-model="value" :localdata="range"></uni-data-select>
                    </uni-forms-item>
                    <uni-forms-item label="楼层">
                        <uni-data-select v-if="show" v-model="floor" :localdata="floorrange"></uni-data-select>
                    </uni-forms-item>
                    <uni-forms-item label="出库区域">
                        <uni-data-select v-if="show" v-model="endType" :localdata="endTypeRange"></uni-data-select>
                    </uni-forms-item>
                </uni-forms> -->
                <uni-list :border="true">
                    <uni-list-item direction="column" v-for="item in orderinfoDetails" :key="item.id">
                        <template v-slot:body>
                                <view class="uni-content">
                                    <view>收货单号:{{orderNo}}</view>
                                    <view>采购单号:{{item.purchaseOrderNo}}</view>
                                    <view>物料编号:{{item.materielCode}}</view>
                                    <view>物料名称:{{item.materielName}}</view>
                                    <view>物料规格:{{item.materielSpec}}</view>
                                    <view>批次号:{{item.lotNo}}</view>
                                    <view>收货数量:{{item.receivedQuantity}}</view>
                                    <view>是否质检:{{item.ifInspection==1?"是":"否"}}</view>
                                </view>
                        </template>
                    </uni-list-item>
                </uni-list>
            </view>
            <view>
                <!-- è¾“入框示例 -->
                <uni-popup ref="inputDialog" type="dialog">
                    <uni-popup-dialog ref="inputClose" mode="input" title="输入内容" :value="outNum" placeholder="请输入内容"
                        @confirm="outbound"></uni-popup-dialog>
                </uni-popup>
            </view>
        </view>
        <view v-if="current === 2" class="headerstyle">
            <view class="itemstyle">
                <uni-forms label-width="120">
                    <uni-forms-item label="楼层">
                        <uni-data-select v-if="show" v-model="printfloor"
                            :localdata="printfloorrange"></uni-data-select>
                    </uni-forms-item>
                    <uni-forms-item label="内箱标签">
                        <uni-easyinput type="text" :focus="tagFocus" v-model="tag" placeholder="请扫描内箱标签" ref='midInput'
                            @input="tagInput" />
                    </uni-forms-item>
                    <uni-forms-item :label="tagmatCode"></uni-forms-item>
                    <uni-forms-item :label="tagmatName"></uni-forms-item>
                    <uni-forms-item :label="tagQty"></uni-forms-item>
                    <uni-forms-item label="拆分数量">
                        <uni-easyinput type="number" v-model="number" placeholder="请输入拆分数量" ref='midInput'
                            :focus="numberFocus" />
                    </uni-forms-item>
                    <uni-forms-item>
                        <button @click="printTag" type="primary" size="default" style="margin-top: 2%;">打印标签</button>
                    </uni-forms-item>
                </uni-forms>
            </view>
        </view>
        <view v-if="current === 3" class="headerstyle">
            <view class="itemstyle">
                <uni-forms label-width="120">
                    <uni-forms-item label="托盘条码">
                        <uni-easyinput type="text" :focus="!istrue" v-model="barcode" placeholder="请扫描托盘条码"
                            ref='midInput' @input="inputChangebarcode" />
                    </uni-forms-item>
                    <uni-forms-item label="地址条码">
                        <uni-easyinput type="text" v-model="address" placeholder="请扫描地址条码" ref='midInput'
                            :focus="istrue" />
                    </uni-forms-item>
                    <uni-forms-item>
                        <button @click="inbound" type="primary" size="default" style="margin-top: 2%;">入库</button>
                    </uni-forms-item>
                </uni-forms>
            </view>
        </view>
        <view v-if="current === 4" class="headerstyle">
            <view class="itemstyle">
                <uni-forms label-width="120">
                    <uni-forms-item>
                        <uni-easyinput type="text" @input="releaseboxInput" v-model="releasevalue" placeholder="请扫码"
                            ref='midInput' :focus="releasefocus" />
                    </uni-forms-item>
                    <uni-forms-item>
                        <button @click="releasebox" type="primary" size="default" style="margin-top: 2%;">解盘</button>
                    </uni-forms-item>
                </uni-forms>
                <uni-list>
                    <uni-list-item direction="column" v-if="value2">
                        <template v-slot:body>
                            <view class="uni-list-box">
                                <view class="uni-content">
                                    <view class="uni-title-sub uni-ellipsis-2">托盘号:{{value2}}</view>
                                </view>
                            </view>
                        </template>
                    </uni-list-item>
                    <uni-list-item direction="column" v-for="item in matTotals" :key="item.matCode">
                        <template v-slot:body>
                            <view class="uni-list-box">
                                <view class="uni-content">
                                    <view class="uni-title-sub uni-ellipsis-2">物料编码:{{item.matCode}}</view>
                                    <view class="uni-title-sub uni-ellipsis-2">数量:{{item.matQuantity}}</view>
                                </view>
                            </view>
                        </template>
                    </uni-list-item>
                    <uni-list-item direction="column" v-for="(item,index) in matInfo" :key="index">
                        <template v-slot:body>
                            <view class="uni-list-box">
                                <view class="uni-content">
                                    <view class="uni-title-sub uni-ellipsis-2" style="font-size: 1.1em;">
                                        ç‰©æ–™ç¼–码:{{item.matCode}}
                                    </view>
                                    <view class="uni-title-sub uni-ellipsis-2" style="font-size: 1.1em;">
                                        ç‰©æ–™åç§°ï¼š{{item.matName}}
                                    </view>
                                    <view class="uni-title-sub uni-ellipsis-2" style="font-size: 1.1em;">
                                        æ•°é‡ï¼š{{item.matQty}}
                                    </view>
                                </view>
                            </view>
                        </template>
                    </uni-list-item>
                </uni-list>
            </view>
        </view>
        <u-toast ref="uToast" />
    </view>
</template>
<script>
    import {
        config
    } from '../../common/config';
import message from '../../tuniao-ui/libs/function/message';
    const innerAudioContext = uni.createInnerAudioContext();
    export default {
        data() {
            return {
                show: true,
                items: ['扫描', '明细'], //, '拆分', '入库', '解盘'
                current: 0,
                orderNo: "",
                orderInfo: [],
                orderinfoDetails:[],
                label: "",
                innerCode: "",
                PurchaseOrderNo: "采购单号:",
                matCode: "物料编码:",
                LotNo: "物料批次:",
                orderQty: "订单数量:",
                Quantity: "",
                ProductionDate: "生产日期:",
                EffectiveDate: "有效日期:",
                matName: "物料名称:",
                currentQty: "已扫数量:",
                scanQty: "累计数量:",
                remaindQty: "实际数量:",
                tagFocus: true,
                numberFocus: false,
                focus: false,
                tag: "",
                number: "",
                tagmatCode: "物料编码:",
                tagmatName: "物料名称:",
                tagQty: "包装数量:",
                value: "",
                range: [],
                floor: "",
                floorrange: [],
                printfloor: "",
                printfloorrange: [],
                barcode: "",
                address: "",
                istrue: false,
                outNum: 0,
                itemCode: "",
                releasefocus: true,
                releasevalue: "",
                matInfo: [],
                matTotals: [],
                value2: "",
                searchValue: "",
                endType: "",
                endTypeRange: [],
                sns: "",
                receiveOrderId: 0,
                warehouseId:"",
                toastQueue: [], // æç¤ºé˜Ÿåˆ—
                isShowingToast: false
            }
        },
        onLoad(res) {
            this.range = config.warehouseRange;
            this.endTypeRange = config.outboundAreaRange;
            if (config.outboundArea) {
                this.endType = config.outboundArea;
            }
            if (config.warehouseArea) {
                this.value = config.warehouseArea;
            }
            this.orderNo = res.orderNo;
            this.receiveOrderId = res.receiveOrderId;
            this.label = "收货单号:" + this.orderNo;
            this.warehouseId=res.warehouseId;
            this.getData();
        },
        mounted() {
            this.printfloorrange = config.printFloorRange;
            this.floorrange = config.outboundFloorRange;
            if (config.outboundFloor) {
                this.floor = config.outboundFloor;
            }
            if (config.printFloor) {
                this.printfloor = config.printFloor;
            }
        },
        methods: {
            showToast(options) {
                        this.toastQueue.push(options);
                        this.processToastQueue();
                    },
                    // å¤„理提示队列
                    processToastQueue() {
                        // å¦‚果正在显示提示或队列为空,则不执行
                        if (this.isShowingToast || this.toastQueue.length === 0) return;
                        this.isShowingToast = true;
                        const toastOptions = this.toastQueue.shift();
                        // æ˜¾ç¤ºæç¤º
                        this.$refs.uToast.show({
                            ...toastOptions,
                            complete: () => {
                                // æç¤ºå…³é—­åŽå¤„理下一个
                                this.isShowingToast = false;
                                this.processToastQueue();
                            }
                        });
                    },
            inputDialogToggle(itemCode) {
                this.itemCode = itemCode;
                this.$refs.inputDialog.open()
            },
            // voiceSpeech(src) {
            //     innerAudioContext.src = src; // '../../static/success.mp3';
            //     innerAudioContext.play();
            // },
            search() {
                this.getData();
            },
            resetReceive(){
                this.PurchaseOrderNo="采购单号:";
                this.matCode="物料编码:";
                this.LotNo="物料批次:";
                this.orderQty="订单数量:";
                this.ProductionDate="生产日期:";
                this.EffectiveDate="有效日期:";
                this.Quantity="";
                setTimeout(() => {
                    this.innerCode="";
                    this.focus=false;
                }, 10);
            },
            releasebox() {
                if (this.releasevalue.length == 0) {
                    this.$refs.uToast.show({
                        title: "请扫码",
                        type: "error"
                    })
                    return;
                }
                var param;
                var matInfo = this.releasevalue.split('|');
                if (matInfo.length == 7) {
                    param = {
                        MainData: {
                            "innerCode": this.releasevalue
                        }
                    }
                } else {
                    param = {
                        MainData: {
                            "barcode": this.releasevalue
                        }
                    }
                }
                this.$u.post('/api/StockOperate/ReleaseAllBox', param).then(resdt => {
                    if (resdt.status) {
                        uni.$showMsg('解盘成功!')
                        this.releasevalue = "";
                        this.matInfo = [];
                        this.matTotals = [];
                        this.value2 = "";
                    } else {
                        this.$refs.uToast.show({
                            title: resdt.message,
                            type: "error"
                        })
                    }
                })
            },
            releaseboxInput() {
                this.$nextTick(() => {
                    if (this.releasevalue.length == 0) {
                        return;
                    }
                    var matInfo = this.releasevalue.split('|');
                    this.matInfo = [];
                    if (matInfo.length == 7) {
                        this.$u.post('/api/StockOperate/GetStockInfoByInnerCode', {
                            MainData: {
                                "innerCode": this.releasevalue
                            }
                        }).then(res => {
                            if (res.status) {
                                this.matInfo = res.data.stockInfo;
                                this.matTotals = res.data.stockTotal;
                                this.value2 = res.data.barcode;
                            } else {
                                this.$refs.uToast.show({
                                    title: res.message,
                                    type: "error"
                                })
                            }
                        })
                    } else {
                        this.$u.post('/api/StockOperate/GetStockInfoByBarcode', {
                            MainData: {
                                "barcode": this.releasevalue
                            }
                        }).then(res => {
                            if (res.status) {
                                this.matInfo = res.data.stockInfo;
                                this.matTotals = res.data.stockTotal;
                                this.value2 = res.data.barcode;
                            } else {
                                this.$refs.uToast.show({
                                    title: res.message,
                                    type: "error"
                                })
                            }
                        })
                    }
                })
            },
            updateFocus() {
                this.$nextTick(() => {
                    this.innerCode = '';
                    if (!this.focus) {
                        this.focus = true;
                    }
                });
            },
            submit() {
                // æå–生产日期(格式为"生产日期:YYYY-MM")
                const productionDateStr = this.ProductionDate.replace('生产日期:', '');
                if (!productionDateStr) {
                    this.showToast({
                        title: "未获取到生产日期",
                        type: 'error'
                    });
                    return;
                }
                // è§£æžç”Ÿäº§æ—¥æœŸçš„年月
                const [prodYear, prodMonth] = productionDateStr.split('-').map(Number);
                // èŽ·å–å½“å‰æ—¥æœŸçš„å¹´æœˆ
                const currentDate = new Date();
                const currentYear = currentDate.getFullYear();
                const currentMonth = currentDate.getMonth() + 1;
                // æ¯”较年月是否一致
                const isDateMismatch = prodYear !== currentYear || prodMonth !== currentMonth;
                if (isDateMismatch) {
                    this.showToast({
                        title: "该物料生产日期的年月与当前年月不一致",
                        type: 'warning',
                        duration: 1500
                    });
                }
                // åŽŸæœ‰çš„ç¡®è®¤æ”¶è´§é€»è¾‘
                if (this.sns == "") {
                    this.$refs.uToast.show({
                        title: "请扫描内箱标签",
                        type: 'error'
                    })
                    return;
                }
                if (this.Quantity == "") {
                    this.$refs.uToast.show({
                        title: "请输入实际数量",
                        type: 'error'
                    })
                    return;
                }
                if(this.warehouseId==2){
                    //替换指定两个字符间的字符
                    this.sns = this.sns.replace(/(Q:)([^,PO]+)(,PO)/, (match, p1, p2, p3) => {
                        return p1 + this.Quantity + p3;
                    });
                }
                const sendRequest = () => {
                    this.$u.post('/api/ReceiveOrderDetail/AddReceiveOrderDetail?serNum=' + this.sns + '&orderNo=' + this
                        .orderNo, {}).then(res => {
                        if (res.status) {
                            this.PurchaseOrderNo="采购单号:";
                            this.matCode="物料编码:";
                            this.LotNo="物料批次:";
                            this.orderQty="订单数量:";
                            this.ProductionDate="生产日期:";
                            this.EffectiveDate="有效日期:";
                            this.Quantity="";
                            setTimeout(() => {
                                this.innerCode="";
                                this.focus=false;
                            }, 100);
                            this.orderInfo=[];
                            this.sns = "";
                            this.$refs.uToast.show({
                                title:"确认收货成功",
                                type: "success"
                            })
                        } else {
                            this.$refs.uToast.show({
                                title: res.message,
                                type: "error"
                            })
                        }
                    })
                };
                // å¦‚果有日期不匹配提示,等待提示完成后发送请求
                if (isDateMismatch) {
                    setTimeout(sendRequest, 1500); // ç­‰å¾…1.5秒(与提示时长一致)
                } else {
                    sendRequest(); // æ²¡æœ‰æ—¥æœŸæç¤ºï¼Œç«‹å³å‘送请求
                }
            },
            submit1() {
                this.$u.post('/api/ReceiveOrder/FeedbackReceiveOrder?orderId=' + this
                    .receiveOrderId, {}).then(x => {
                    if (x.status) {
                        this.$refs.uToast.show({
                            title: "完成收货成功",
                            type: "success"
                        })
                        this.sns = "";
                    } else {
                        this.$refs.uToast.show({
                            title: x.message,
                            type: "error"
                        })
                    }
                })
            },
            inbound() {
                if (this.barcode.length == 0) {
                    this.$refs.uToast.show({
                        title: "请扫描托盘号",
                        type: "error"
                    })
                    return;
                }
                if (this.address.length == 0) {
                    this.$refs.uToast.show({
                        title: "请扫描地址条码",
                        type: "error"
                    })
                    return;
                }
                var postData = {
                    MainData: {
                        "barcode": this.barcode,
                        "startPoint": this.address
                    }
                }
                this.$u.post('/api/Inbound/RequestInbound', postData).then(res => {
                    if (res.status) {
                        uni.$showMsg(res.message);
                        this.barcode = "";
                        this.address = "";
                        this.istrue = false;
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                }).catch(err => {
                    this.$refs.uToast.show({
                        title: err.message,
                        type: "error"
                    })
                })
            },
            inputChangebarcode() {
                this.istrue = false;
                this.$nextTick(function(x) {
                    if (this.barcode != '') {
                        this.istrue = true;
                    }
                })
            },
            onClickItem(e) {
                console.log(1)
                this.focus = false;
                this.addressFocus = false;
                if (this.current !== e.currentIndex) {
                    this.current = e.currentIndex;
                    if (this.current == 1) {
                        this.getData();
                    }
                }
            },
            getData() {
                var postData = {
                    MainData: {
                        orderNo: this.orderNo,
                        searchValue: this.searchValue
                    },
                }
                this.$u.post('/api/ReceiveOrderDetail/GetReceiveOrderInfos', postData).then((res) => {
                    if (res.status) {
                        this.orderinfoDetails = res.data;
                        if (this.orderinfoDetails.length > 3) {
                            this.loadVisible = true;
                        }
                    }
                })
            },
            innercodeInput() {
                this.$nextTick(() => {
                    if (this.innerCode == "") {
                        return;
                    }
                    var innerCode = this.innerCode;
                    //将innerCode,SC后面的进行替换空
                    if(this.warehouseId==11){
                        innerCode=innerCode.replace(/,SC.*/, '');
                    }
                    if(innerCode.indexOf("POHA")>0){
                        this.$u.post('/api/MaterielInfo/CodeAnalysis?serNum=' + innerCode, {}).then((res) => {
                            if (res.status) {
                                this.sns = res.data.serialNumber;
                                // this.matInfos.splice(0, this.matInfos.length);
                                // this.matInfos.push(res.data);
                                this.matCode = "物料编码:" + res.data.materielCode;
                                this.LotNo = "物料批次:" + res.data.lotNo;
                                this.PurchaseOrderNo = "采购单号:" + res.data.purchaseOrderNo;
                                this.EffectiveDate = "有效日期:" + res.data.effectiveDate;
                                this.ProductionDate = "生产日期:" + res.data.productionDate;
                                this.orderQty = "订单数量:" + res.data.quantity;
                                this.Quantity = res.data.quantity;
                                // setTimeout(() => {
                                //     this.voiceSpeech('../../static/success.mp3');
                                // }, 100);
                            } else {
                                this.$refs.uToast.show({
                                    title: res.message,
                                    type: "error"
                                })
                                // setTimeout(() => {
                                //     this.voiceSpeech('../../static/fail.mp3');
                                // }, 100);
                            }
                        })
                    }
                    setTimeout(() => {
                        this.innerCode = "";
                        this.focus=true;
                    }, 100);
                })
            },
            tagInput() {
                this.$nextTick(() => {
                    var tagInfos = this.tag.split('|');
                    if (tagInfos.length == 7) {
                        this.tagmatCode = "物料编码:" + tagInfos[1];
                        this.tagQty = "物料数量:" + tagInfos[5];
                    } else {
                        this.$refs.uToast.show({
                            title: "内箱码扫描错误",
                            type: "error"
                        })
                    }
                    this.numberFocus = true;
                })
            },
            printTag() {
                if (this.tag == "") {
                    this.$refs.uToast.show({
                        title: "请扫描内箱标签",
                        type: "error"
                    })
                    return;
                }
                if (this.number <= 0) {
                    this.$refs.uToast.show({
                        title: "请输入数量",
                        type: "error"
                    })
                    return;
                }
                if (this.printfloor.length <= 0) {
                    this.$refs.uToast.show({
                        title: "请选择楼层",
                        type: "error"
                    })
                    return;
                }
                var postData = {
                    MainData: {
                        tag: this.tag,
                        number: this.number,
                        floor: this.printfloor
                    }
                }
                this.$u.post('/api/StockOperate/PrintTag', postData).then(res => {
                    if (res.status) {
                        this.$refs.uToast.show({
                            title: "打印成功",
                            type: "success"
                        })
                        this.tagmatCode = "物料编码:";
                        this.tagQty = "包装数量:";
                        this.tag = "";
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                })
            },
            outbound(val) {
                if (this.floor == "") {
                    this.$refs.uToast.show({
                        title: "请选择楼层",
                        type: "error"
                    })
                    return;
                }
                if (this.value == "") {
                    this.$refs.uToast.show({
                        title: "请选择区域",
                        type: "error"
                    })
                    return;
                }
                if (this.endType == "") {
                    this.$refs.uToast.show({
                        title: "请选择出库区域",
                        type: "error"
                    })
                    return;
                }
                var postData = {
                    MainData: {
                        matCode: this.itemCode,
                        orderNo: this.orderNo,
                        system: this.value,
                        floor: this.floor,
                        outNum: val,
                        endType: this.endType
                    }
                }
                this.$u.post('/api/ErpOrder/ReceiveOrderOutbound', postData).then(res => {
                    if (res.status) {
                        this.$refs.uToast.show({
                            title: "成功",
                            type: "success"
                        })
                        this.getData();
                    } else {
                        this.$refs.uToast.show({
                            title: res.message,
                            type: "error"
                        })
                    }
                })
            }
        }
    }
</script>
<style lang="scss">
    @import '@/common/uni-ui.scss';
    .content {
        display: flex;
        height: 150px;
    }
    .content-text {
        font-size: 14px;
        color: #666;
    }
    .itemstyle {
        margin-top: 20px;
        margin-left: 5%;
    }
    .headerstyle {
        width: 90%;
    }
</style>
¼ª°²PDA/static/BC.png
¼ª°²PDA/static/CK.png
¼ª°²PDA/static/CP.png
¼ª°²PDA/static/CPCK.png
¼ª°²PDA/static/CSJ.png
¼ª°²PDA/static/FL.png
¼ª°²PDA/static/GM.png
¼ª°²PDA/static/JX.png
¼ª°²PDA/static/KCCX.png
¼ª°²PDA/static/KCPD.png
¼ª°²PDA/static/RK.png
¼ª°²PDA/static/SH.png
¼ª°²PDA/static/WMSRK.png
¼ª°²PDA/static/YM.png
¼ª°²PDA/static/ZXRK.png
¼ª°²PDA/static/center-selected.png
¼ª°²PDA/static/center.png
¼ª°²PDA/static/fail.mp3
Binary files differ
¼ª°²PDA/static/favicon.ico
¼ª°²PDA/static/iconfont.css
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,82 @@
@font-face {
  font-family: "custom-icon";
  src:
       url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAABIYAAwAAAAAJkAAABHHAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIoMUIzYGYACBJAq9MK0dATYCJAOCfguBRAAEIAWCFAcgG5YcUZSSVnqyH4fpRiPfJMmbLUh2F/7neBlKafA0Zz9vs7GNbHY3QvAkFKgoZsElWGrAb6qCH6kr7VnFqahBlU/tuPOciOz/1kz1E5a8W9KMdjfAcCsd0zeQsGEh7DZAUxi1PGpvAtsFMlCA2YCWbLsPQVhdLFc2tb2VAkbsglh0sidNQVXzZLh/KdG/3iAy8FsBvfktEwapgjKdU7r6l0ygCwB0qTI9NU2KokrRlYG0uT6MOpBG2kM9xlzeXWuT4QCVcL6ib0S/BgEADoAWwCxkgQI8kDgp0EeFghQyP1EGhSIHA3WoNkICJcyQyMA3UYUArRpWSKFByFarRT+owCICPoUOdkjAIRUEPNJAQwCBHhQMIDCCwMTBC8zgDT7gC37gDwEQCBawgg2CoA8EQwiEQl/oDwNgIAyCwTAEhkEYhEMEREIUREMMxCpxkCCeGSdAjkTQSIIUdg+SIVVJhwKZgLMB58SQC/m5xVYWQhEuBiiBMuwAXM5wBTxbFQiqQeAEwXAQjAAwEjKMghKjYS3AgLA2mUncDvG15sXYH4JFsTWZxPbhYUFF8a/vRGRF0XVcPDxMMKJpE1kDKWjqTcoFIJ/fC3EhjIQBzic64cELCgvScRWBn7dK3KIbkLjhBkBwJzSlugAEAtSABIDeFwh301ijocTT+IIeyiPzsJ7+nsGeDE+JZ46nwTPP89fn7Ofhn7eKojZ7kjbX8+dLih/1EPN/5t/Mr80vzNfNZ8wbzOvNy80GM/Hq9dpozOBIqMEnuw7gbUAhAjF/ALgJYPT8zAiqaUigAGGCZKA+KSgQYCSBUnBKLxHFFFuAlZg5VxTTxx7IAC+hXiy3Ohv3aiw35CoflmhOSh1CePE8J5PTA7x1nsdngG/Q1ovlTFpW7aslpp+2TEer+eR8jtqFqPVqg7lf8BXRIDuE4GUmrY7nWUHtTS9odX0s/bUWi1YtU3t22g9JoyEa/6w+/qyeV+t4QWdezeDI0WC/g2K/rWEb9l+RDZSm9CkqMXb2SrRCRYgwAFxjHG3gPokKrcwRfoKZvDdm0qhjXsz1EQnn+cQN3EpXmKFOREFKHFUB7tkzZMSBs9//n3Vy1dVloZ4hQlmuMYzbIvFQKOm9Z0e7atOufigUyo9r6IyfhHGkAbghWM7WPwmZnszV3eYJ1Y0Ngv74kLDcpaZDl8uirX8fA/8uSWXaZ8xNhKVQ51dcnlP5t1shKKe7585H3KltMDeozkHuU1DKUuDWp30YU5iRO/PiI735px2JpdP9Z8s20XmFO6M3MJi3R/m/vyQd4nn3binpO9o09RUciy7Rg1cIObwbhuhkyTvi9/1gSpYKqTNMEUdFVJwZYa2rm5s0LAIvERdEyJiqc6b5TSKuI9dwdCMQFTRufOeUjNcIESX290sino/JknhURipduEsNeBVL+U4Bs+KMt5Yw3F5r2O/Ae3I91alFHE2WeVruyiDdWasypUDENMPWKAzcoVzjSKKH4DH7YWqOZNOA+d3WRdorM5YqBP06x3p2n30qS2V+g6fzVGYtV5WYyQXOLVY4802h57bAgdlJQ5MUwO2FKWM6X1qKsHlkTho4OVHh1ZOlJk7Cvbll6kz8yoeIC2ayJvqFfd1zMkYTBKC6MpPzto3u6mro7wX33nIwlVOLPblqI6xU3rYAHAfrFJVawP7sUmtmtT2r1p5RaTqWYi0U/lHhn2370OoZ1sKR02hA020GIG5voiY05jduMdEd70wLeNtv323oHM0pcSKojtoac6hE+WcOqDfqIBFL7SkkGIv23ngsFZR2dkZUkMnRHNZOi1kDyRHTaueAOFlPfesEjurmScf9R5I4i3RJSbW2c8BHGeMn0mh3clfi7IBNsbDNf6mUYKkS5KYmi5Pj+e7slIRKpnpmJOIJMS3lWBVxaSfdaAJLWQm1SdRg8LPT8FR2sZQxkMlBr/Wze8S0h+3n1pbXchoidpvu801ixfUJfzaehd9be2PiX+2XUeaocMUjtmMKm0RPf3HyHexjA33qc8twN3WkH1sOnI6rtyTWhB3l2FBT0SOSIJljW3pqvIsI5htuaxxRZ2j2LbCK7iel2pVxNNOr8lmDozCktNxo9nWvByBm1aAuzGI1PrO/Hu10Wg5nuCi8vmyMMjMq8zC8PUlTi2+lvB2xrzHMKz79YEohzWhOJSqUAzbkLKpKdIibMLgBFQfQdn97TgzRgy3RsFfzDAqvbwIMeKAPI9y91fu6NA5Clw6FEb6wjDGK7SHgcbd4r5wLbeLvOmMgEkf6RdArtkybfTOczn59uxRnxlLIgLi2+5nhjbPyPaBKI61m0rYdKUdDrZlvayZH/YKs9SQjE7XNkgbFjLG92ZJOUJ5Q/jFn88q6LJV+DWde5eptnduvbx2tucE3dj+U/YjMYeDBBvrNMYiNJe3No33wGsw4wi0DfUNib9IVQ3na+UiI0CD5sdd+b410vENgdxb8MMD5GRVk9SWM4W0xvMen0evUI/xu9OQMDOdnn5Iv4G0YzD2x8spHF3BsCLmZxsGvg9C3HeS3wfBd7LCZSh6Z4s5VJeBTHWccRi9PnRymjfbzdlsl3nAIGkzUahEUNldcFquutgH48TGBt1ZeiTx79Nluu6TObruJeFtqdN38C1Hcs4SonU0IL/UO3RmOuLrwyJ3j1DOlRKfOQ26qOzcNsEvs2WYOosNao1Ovg1LR/K1iS/2jUlPv5LbTIJ2k+Y1Jws/IDnOPcD/EW+r4mX96hM5OAYNi2IT8u1ej29qcf/YsrI3Bd9M6XErMVXYxbqZLyZsGrYSb6WRQcjmC835XphgMw+HC7HW/LPt5WK0t+6OcvPD0MNVtuGtJ/SC/W0QMjXTW6eTsszKniwDWr9T8WC5kofOUkd3EE0JJ8c7g0nS+J4Dv7OU0X1kj1+vCiMQClDn7Ml3ukt178ydubU9hupgBRVWTG7Wb2Uh2qS5ibMVGsUvYZkaODtcV68IuPOWaSN2SNUfuw0cj8kdtYWllZepR7WZtdATbgm06yi5GdSbTEDGW7rUDBn9iV0N90jW0bqodPy5k044YlY9DvNQF/PYZJj9x1vUj/K73+IAeIa108DuQUoQIG1nT7omzQ7j6KH41DCvA6Sp7xspl+EH1/76oagDTqyxZfMSZsPdUiruX6VvqBOFmLOiRYSw14bQu1fsDK6zd7G1/7K1LO5276lW3f3fAzVfX9/UpCPm5MDt37eQgtpsNmry3Ex9QMglD0dTHqh9U3UGKL8egYXT9YtO4d/eF1RZL1fW5ufWm+tNWi49OUovq4pKKLT9WVTIHqh9dobxMBdVejYwdgQ8DLadZuyyBXRjKnzB2Gl3GXqOFkbmM7xlXqfx83M6gIKd7vHfySg2ngfIWDa++yM2HRJNabVHP+ErDq7jrTS2l+QZftdUb53Rm5m70MW3Z9AMZX+XjW7UxfzFZuNHHa3O7SG2v8jVt2TXrQL1aheemYcxD5sRd9hw9/RXTxSh7mb+oV8l0of7umrjZQRVjh85ZGzvHNrYiGVFP7iX1+0in1ToCK1xkzLS6Me1XThB79S2o11VeLgC2kAbRP+xnOpntjH7hUPWiXWUn5XKKeyHQxbTwJy9Y6UPNWc2w/17LMMsYZuLCp+f05lfz/iVYBXo15mtas1rx9chRSxbFXbWraPKN6Z8xDrVltaF9sb3SRgu88HXlN7zA17Llqqwp2NB3NFrK0uXs+h9lsTt3u2i18BVQM58n4FJL1iR827dmweKsiCt+jteWoTLDe/vWaKyaU/HtJFYyZMLjPN73nkE21PJ66+jFXouhClSrs/C1Ee7Oxf6EhGdPt0CSo2mdIsnt6Mije3q0uRMCDL0GTx/J7vTM/ht89W+SsuQoFrYMBGcm/IQU/YFRI20XUj5CeuZW6PYIKbxd2D3cKewZLKTs0bGoHqzf4xyu362ieJiksFdMBRVVHZgdUmEo8R1bPVxYd9WpKrOzK1VAgy9q934jZFrcqJDszQiSSYUqfNCmyuIiqy3ZwRXGEp9KWsHOp5xmFR2KUx8bU+GM46uykTy/Wp1VVZWlvqOqLMNKldfOV/IDckWH/O6KOvUKe1GsQp5RId9WlZ1VpZKVGM+rU6w273HeaDivSbFZP/t5/Z/QrUjcOnDA1sQVOl1LwdYBA7cWtIC69NVZ7uww7to3Z8RL/20tUl796WoRqMGKr3oWFPvVae70EO76t2fQHcR9Pvn8Sj/Vga2nHnRNOvu22q/jrTP/n/R51r6v45p2F+7H/9ME+YwrpxqczvbdPWtt7dZzJ5fmOnPzTm496zm43Ypv/UOtRaOxaD/UWOG9cG3Z1BvVE+NzJ95wTD4x0RnvwtahOjKuJC24bo6mNHVI6tCSAjWkzl2SOqQ8uXxg7EdLHN6pqxxLnwQobb7tiIVd9/aEmPZZZXvWN5LubEbUiaa+7VuTEhPdpr1vU+O6vcuHqMWieJZh4k/nx7UJ16PiyPSyLrcVGXW5uPxVkmvKqr4cZ08yEU5SrHdSNBgjJ4QoHPUNDt7hUAbBGzfn5bryATw++MlnGeErlI5PPN8PHCCePC1Wixca+vXfcbz+Yiefp/zO+xkvYKh7Hsw85zP8aXoYH8VPbrD6eFvDbJG2J8+P/0EVrmJ6EGPlNhMoLyrLBI4bal47z5Um/70TR0+vSz/W6mIY1+R6l8E17P2/N+3erWlgOnHrgfKAUnFRMZfR4bvFtrabfkv8kanqB6KQWMZNTCvSUVA6Jky20hTRajPhvwQr1vIcl7zjQJbKcXyzdmBO/c2bjmk6CVRjb98K/8gyhGKLAkPW0P5L/GYWm61Wm8babDW2bjZNG2QLatxp++1YOf/rGL9TvkWRUXLFLjiXzPO2G1B4QBptU8vNDznmAHFZDKNXVtHOUDMLFsxawKjOeIE5EHN9u619lpRpy3zb5hu2G4gfhjtnWio22+iFG/4oWBL5rNQZXpoQUbD0iw2qMFvF5kkT76D5Is8FcYE5v4rDjJCmI5iFJAtxeApKa2pajKbKco54jGtLxbfwBkVclaaaiTIjYt6ceOf0neaWiWdu35mIo5YvVmU0rfoDhdIrv8Do0r4IQX4ZxG53tSnbX+4oF/c7EMvKREIkUZYOx+KjzNH2/Q6VAYCDX8KfipPbhqnO1J9v4OD5tNphwDsrOjq6qem8wPMXamq+W+dzM/+78yNdtF3otF3s2N/J8ZjTBEQXjOgfZ0+qPPrz4cTg3wMGPg0Q/J8OCuACBj31FwKeDgyYKeLLimE52XJjSHAa6ag2HFkDr53uZctuwUxQvOnp+a3JS6/3+q2xx2MG/fqOeeTq6cF/psmgN/3edFEw5AmZBNX+M7z0Bh1sP52eMnVaSnraoJra9pRpiGnpse40xFEhwam8UCjwJYXiMIIktEAw+gEI8R1rsIsmbV4CUZHohlwI1ChDAcgIT4vrUgDIcVA3lOY0CjwBhIw4KmOCOUvI2pjzEvOwSSho0VNAavh2//2eB3JfJYJRqrCValBp5JQ0irWAUNlaVOUmqGQOzexuOPSWv4fLxWuD3MY+DUE8DbINE8g6SRE5RfaJf5PvcZAkYkwbEiPFi39TVThItXjoxl6YIP5B/U7k6EZI/JoHGrIJl0FqDI7Be2b/O4qN/1UhoXGo+aT9zCAMEP8R0Scl7sHZqC5Y8Zv8uOlr4j//RJ/8Ddw0UqBZhPhfLOIhFS5AHk6swulTk0SxaCgNLLnl9LXq6J8Iak4k8bMlcaYZ9GUBldkcdKwpoEE+EiUGxDsY7IR8WhWB3yPxB9oVQRVHIoHtCS3XLaNPQjILqPvm8ASs4JxpLLJVbffbBx5ti5AERqBcJgdNjyUyfgIJ4E6yD0CDmAhYS4PiwekZdFItQK6oTGaqziNHqjNpkdIwCEPZIjwARchxARzjdBQfUjtg9vhqsA8KZEFmGU4OlKEAEhBa+S+XDbGTgnbOwUYJ4hG0kUYwRm+UwhuLsIxItqEOszETszAVkzEQ41EXPtgUlGAMxmI2JqEGMzAUgzDkqMShAIUMp+MAKp1s4HwABbILxOUSnrG1jdf0aG0IWnBIcLipeAL/S7EA') format('woff2');
}
.custom-icon {
  font-family: "custom-icon" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
.custom-icon-_WMS_rukuyewu:before {
  content: "\e70f";
}
.custom-icon-chuku:before {
  content: "\e602";
}
.custom-icon-ruku:before {
  content: "\e606";
}
.custom-icon-zhijin:before {
  content: "\e652";
}
.custom-icon-shouhuo:before {
  content: "\e60f";
}
.custom-icon-kucunpandian-:before {
  content: "\e646";
}
.custom-icon-ppt:before {
  content: "\e734";
}
.custom-icon-chengpinchuku:before {
  content: "\e62f";
}
.custom-icon-jianxuandan:before {
  content: "\e62b";
}
.custom-icon-kucunchaxun:before {
  content: "\e681";
}
.custom-icon-zhuangxiangruku1:before {
  content: "\e601";
}
.custom-icon-chanpin-youmotuliao:before {
  content: "\e682";
}
.custom-icon-bancaiwuliao:before {
  content: "\e676";
}
.custom-icon-ceshijiaguanli:before {
  content: "\e678";
}
.custom-icon-lingliaozupan:before {
  content: "\e77d";
}
.custom-icon-chengpincangku:before {
  content: "\e6f9";
}
.custom-icon-fuliaocangku:before {
  content: "\e6fa";
}
¼ª°²PDA/static/index-selected.png
¼ª°²PDA/static/index.png
¼ª°²PDA/static/login_bottom_bg.jpg
¼ª°²PDA/static/login_top2.jpg
¼ª°²PDA/static/login_top3.png
¼ª°²PDA/static/logo.png
¼ª°²PDA/static/pp.png
¼ª°²PDA/static/repeat.mp3
Binary files differ
¼ª°²PDA/static/success.mp3
Binary files differ
¼ª°²PDA/template.h5.html
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <link rel="shortcut icon" type="image/x-icon" href="static/favicon.ico">
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <title>
            <%= htmlWebpackPlugin.options.title %>
        </title>
        <script>
            document.addEventListener('DOMContentLoaded', function() {
                document.documentElement.style.fontSize = document.documentElement.clientWidth / 20 + 'px'
            })
        </script>
        <link rel="stylesheet" href="<%= BASE_URL %>static/index.css" />
    </head>
    <body>
        <noscript>
            <strong>本站点必须要开启JavaScript才能运行</strong>
        </noscript>
        <div id="app"></div>
    </body>
</html>
¼ª°²PDA/tuniao-ui/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,4 @@
TuniaoUi for uniApp v1.0.0 | by å›¾é¸Ÿ 2021-09-01
仅供开发,如作它用所承受的法律责任一概与作者无关
*使用TuniaoUi开发扩展与插件时,请注明基于tuniao字眼
¼ª°²PDA/tuniao-ui/components/tn-action-sheet/tn-action-sheet.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,202 @@
<template>
  <view v-if="value" class="tn-action-sheet-class tn-action-sheet">
    <tn-popup
      v-model="value"
      mode="bottom"
      length="auto"
      :popup="false"
      :borderRadius="borderRadius"
      :maskCloseable="maskCloseable"
      :safeAreaInsetBottom="safeAreaInsetBottom"
      :zIndex="elZIndex"
      @close="close"
    >
      <!-- æç¤ºä¿¡æ¯ -->
      <view
        v-if="tips.text"
        class="tn-action-sheet__tips tn-border-solid-bottom"
        :style="[tipsStyle]"
      >
        {{tips.text}}
      </view>
      <!-- æŒ‰é’®åˆ—表 -->
      <block v-for="(item, index) in list" :key="index">
        <view
          class="tn-action-sheet__item tn-text-ellipsis"
          :class="[ index < list.length - 1 ? 'tn-border-solid-bottom' : '']"
          :style="[itemStyle(index)]"
          hover-class="tn-hover-class"
          :hover-stay-time="150"
          @tap="itemClick(index)"
          @touchmove.stop.prevent
        >
          <text>{{item.text}}</text>
          <text v-if="item.subText" class="tn-action-sheet__item__subtext tn-text-ellipsis">{{item.subText}}</text>
        </view>
      </block>
      <!-- å–消按钮 -->
      <block v-if="cancelBtn">
        <view class="tn-action-sheet__cancel--gab"></view>
        <view
          class="tn-action-sheet__cancel tn-action-sheet__item"
          hover-class="tn-hover-class"
          :hover-stay-time="150"
          @tap="close"
        >{{cancelText}}</view>
      </block>
    </tn-popup>
  </view>
</template>
<script>
  export default {
    name: 'tn-action-sheet',
    props: {
      // é€šè¿‡v-model控制弹出和收起
      value: {
        type: Boolean,
        default: false
      },
      // æŒ‰é’®æ–‡å­—数组,可以自定义颜色和字体大小
      // return [{
      //     text: '确定',
      //  subText: '这是一个确定按钮',
      //     color: '',
      //     fontSize: '',
      //  disabled: true
      // }]
      list: {
        type: Array,
        default() {
          return []
        }
      },
      // é¡¶éƒ¨æç¤ºæ–‡å­—
      tips: {
        type: Object,
        default() {
          return {
            text: '',
            color: '',
            fontSize: 26
          }
        }
      },
      // å¼¹å‡ºçš„顶部圆角值
      borderRadius: {
        type: Number,
        default: 0
      },
      // ç‚¹å‡»é®ç½©å¯ä»¥å…³é—­
      maskCloseable: {
        type: Boolean,
        default: true
      },
      // åº•部取消按钮
      cancelBtn: {
        type: Boolean,
        default: true
      },
      // åº•部取消按钮的文字
      cancelText: {
        type: String,
        default: '取消'
      },
      // å¼€å¯åº•部安全区域
      // åœ¨iPhoneX机型底部添加一定的内边距
      safeAreaInsetBottom: {
        type: Boolean,
        default: false
      },
      // z-index值
      zIndex: {
        type: Number,
        default: 0
      }
    },
    computed: {
      // é¡¶éƒ¨æç¤ºæ ·å¼
      tipsStyle() {
        let style = {}
        if (this.tips.color) style.color = this.tips.color
        if (this.tips.fontSize) style.fontSize = this.tips.fontSize + 'rpx'
        return style
      },
      // æ“ä½œé¡¹ç›®çš„æ ·å¼
      itemStyle() {
        return (index) => {
          let style = {}
          if (this.list[index].color) style.color = this.list[index].color
          if (this.list[index].fontSize) style.fontSize = this.list[index].fontSize + 'rpx'
          // é€‰é¡¹è¢«ç¦ç”¨çš„æ ·å¼
          if (this.list[index].disabled) style.color = '#AAAAAA'
          return style
        }
      },
      elZIndex() {
        return this.zIndex ? this.zIndex : this.$t.zIndex.popup
      }
    },
    methods: {
      // ç‚¹å‡»å–消按钮
      close() {
        // å‘送input事件,并不会作用于父组件,而是要设置组件内部通过props传递的value参数
        this.popupClose();
        this.$emit('close');
      },
      // å…³é—­å¼¹çª—
      popupClose() {
        this.$emit('input', false)
      },
      // ç‚¹å‡»å¯¹åº”çš„item
      itemClick(index) {
        // å¦‚果是禁用项则不进行操作
        if (this.list[index].disabled) return
        this.$emit('click', index)
        this.popupClose()
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-action-sheet {
    &__tips {
      font-size: 26rpx;
      text-align: center;
      padding: 34rpx 0;
      line-height: 1;
      color: $tn-content-color;
    }
    &__item {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      font-size: 32rpx;
      padding: 34rpx 0;
      &__subtext {
        font-size: 24rpx;
        color: $tn-content-color;
        margin-top: 20rpx;
      }
    }
    &__cancel {
      color: $tn-font-color;
      &--gab {
        height: 12rpx;
        background-color: #eaeaec;
      }
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-avatar-group/tn-avatar-group.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,104 @@
<template>
  <view class="tn-avatar-group-class tn-avatar-group">
    <view v-for="(item, index) in lists" :key="index" class="tn-avatar-group__item" :style="[itemStyle(index)]">
      <tn-avatar
        :src="item.src || ''"
        :text="item.text || ''"
        :icon="item.icon || ''"
        :size="size"
        :shape="shape"
        :imgMode="imgMode"
        :border="true"
        backgroundColor="rgba(255, 255, 255, 0.4)"
        :borderSize="4"
      ></tn-avatar>
    </view>
  </view>
</template>
<script>
  export default {
    name: 'tn-avatar-group',
    props: {
      // å¤´åƒåˆ—表
      lists: {
        type: Array,
        default() {
          return []
        }
      },
      // å¤´åƒç±»åž‹
      // square å¸¦åœ†è§’正方形 circle åœ†å½¢
      shape: {
        type: String,
        default: 'circle'
      },
      // å¤§å°
      // sm å°å¤´åƒ lg å¤§å¤´åƒ xl åŠ å¤§å¤´åƒ
      // å¦‚果为其他则认为是直接设置大小
      size: {
        type: [Number, String],
        default: ''
      },
      // å½“设置为显示头像信息时,
      // å›¾ç‰‡çš„裁剪模式
      imgMode: {
        type: String,
        default: 'aspectFill'
      },
      // å¤´åƒä¹‹é—´çš„遮挡比例
      // 0.4 ä»£è¡¨ 40%
      gap: {
        type: Number,
        default: 0.4
      }
    },
    computed: {
      itemStyle() {
        return (index) => {
          let style = {}
          if (this._checkSizeIsInline()) {
            switch(this.size) {
              case 'sm':
                style.marginLeft = index != 0 ? `${-48 * this.gap}rpx` : ''
                break
              case 'lg':
                style.marginLeft = index != 0 ? `${-96 * this.gap}rpx` : ''
                break
              case 'xl':
                style.marginLeft = index != 0 ? `${-128 * this.gap}rpx` : ''
                break
            }
          } else {
            const size = Number(this.size.replace(/(px|rpx)/g, '')) || 64
            style.marginLeft = index != 0 ? `-${size * this.gap}rpx` : ''
          }
          return style
        }
      }
    },
    data() {
      return {
      }
    },
    methods: {
      // æ£€æŸ¥æ˜¯å¦ä½¿ç”¨å†…置的大小进行设置
      _checkSizeIsInline() {
        if (/(xs|sm|md|lg|xl|xxl)/.test(this.size)) return true
        else return false
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-avatar-group {
    display: flex;
    flex-direction: row;
    &__item {
      position: relative;
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-avatar/tn-avatar.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,298 @@
<template>
  <view
    class="tn-avatar-class tn-avatar"
    :class="[backgroundColorClass,avatarClass]"
    :style="[avatarStyle]"
    @tap="click"
  >
    <image
      v-if="showImg"
      class="tn-avatar__img"
      :class="[imgClass]"
      :src="src"
      :mode="imgMode || 'aspectFill'"
      @error="loadImageError"
    ></image>
    <view v-else class="tn-avatar__text" >
      <view v-if="text">{{ text }}</view>
      <view v-else :class="[`tn-icon-${icon}`]"></view>
    </view>
    <!-- è§’æ ‡ -->
    <tn-badge
      v-if="badge && (badgeIcon || badgeText)"
      :radius="badgeSize"
      :backgroundColor="badgeBgColor"
      :fontColor="badgeColor"
      :fontSize="badgeSize - 8"
      :absolute="true"
      :top="badgePosition[0]"
      :right="badgePosition[1]"
    >
      <view v-if="badgeIcon && badgeText === ''">
        <view :class="[`tn-icon-${badgeIcon}`]"></view>
      </view>
      <view v-else>
        {{ badgeText }}
      </view>
    </tn-badge>
  </view>
</template>
<script>
  import componentsColorMixin from '../../libs/mixin/components_color.js'
  export default {
    mixins: [componentsColorMixin],
    name: 'tn-avatar',
    props: {
      // åºå·
      index: {
        type: [Number, String],
        default: 0
      },
      // å¤´åƒç±»åž‹
      // square å¸¦åœ†è§’正方形 circle åœ†å½¢
      shape: {
        type: String,
        default: 'circle'
      },
      // å¤§å°
      // sm å°å¤´åƒ lg å¤§å¤´åƒ xl åŠ å¤§å¤´åƒ
      // å¦‚果为其他则认为是直接设置大小
      size: {
        type: [Number, String],
        default: ''
      },
      // æ˜¯å¦æ˜¾ç¤ºé˜´å½±
      shadow: {
        type: Boolean,
        default: false
      },
      // æ˜¯å¦æ˜¾ç¤ºè¾¹æ¡†
      border: {
        type: Boolean,
        default: false
      },
      // è¾¹æ¡†é¢œè‰²
      borderColor: {
        type: String,
        default: 'rgba(0, 0, 0, 0.1)'
      },
      // è¾¹æ¡†å¤§å°, rpx
      borderSize: {
        type: Number,
        default: 2
      },
      // å¤´åƒè·¯å¾„
      src: {
        type: String,
        default: ''
      },
      // æ–‡å­—
      text: {
        type: String,
        default: ''
      },
      // å›¾æ ‡
      icon: {
        type: String,
        default: ''
      },
      // å½“设置为显示头像信息时,
      // å›¾ç‰‡çš„裁剪模式
      imgMode: {
        type: String,
        default: 'aspectFill'
      },
      // æ˜¯å¦æ˜¾ç¤ºè§’æ ‡
      badge: {
        type: Boolean,
        default: false
      },
      // è®¾ç½®æ˜¾ç¤ºè§’标后,角标大小
      badgeSize: {
        type: Number,
        default: 0
      },
      // è§’标背景颜色
      badgeBgColor: {
        type: String,
        default: '#AAAAAA'
      },
      // è§’标字体颜色
      badgeColor: {
        type: String,
        default: '#FFFFFF'
      },
      // è§’标图标
      badgeIcon: {
        type: String,
        default: ''
      },
      // è§’标文字,优先级比icon高
      badgeText: {
        type: String,
        default: ''
      },
      // è§’标坐标
      // [top, right]
      badgePosition: {
        type: Array,
        default() {
          return [0, 0]
        }
      }
    },
    data() {
      return {
        // å›¾ç‰‡æ˜¾ç¤ºæ˜¯å¦å‘生错误
        imgLoadError: false
      }
    },
    computed: {
      showImg() {
        // å¦‚果设置了图片地址,则为显示图片,否则为显示文本
        return this.text === '' && this.icon === ''
      },
      avatarClass() {
        let clazz = ''
        clazz += ` tn-avatar--${this.shape}`
        if (this._checkSizeIsInline()) {
          clazz += ` tn-avatar--${this.size}`
        }
        if (this.shadow) {
          clazz += ' tn-avatar--shadow'
        }
        return clazz
      },
      avatarStyle() {
        let style = {}
        if (this.backgroundColorStyle) {
          style.background = this.backgroundColorStyle
        } else if (this.shadow && this.showImg) {
          style.backgroundImage = `url(${this.src})`
        }
        if (this.border) {
          style.border = `${this.borderSize}rpx solid ${this.borderColor}`
        }
        if (!this._checkSizeIsInline()) {
          style.width = this.size
          style.height = this.size
        }
        return style
      },
      imgClass() {
        let clazz = ''
        clazz += ` tn-avatar__img--${this.shape}`
        return clazz
      }
    },
    methods: {
      // åŠ è½½å›¾ç‰‡å¤±è´¥
      loadImageError() {
        this.imgLoadError = true
      },
      // ç‚¹å‡»äº‹ä»¶
      click() {
        this.$emit("click", this.index)
      },
      // æ£€æŸ¥æ˜¯å¦ä½¿ç”¨å†…置的大小进行设置
      _checkSizeIsInline() {
        if (/^(xs|sm|md|lg|xl|xxl)$/.test(this.size)) return true
        else return false
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-avatar {
    /* #ifndef APP-NVUE */
    display: inline-flex;
    /* #endif */
    margin: 0;
    padding: 0;
    text-align: center;
    align-items: center;
    justify-content: center;
    background-color: $tn-font-holder-color;
    // color: #FFFFFF;
    white-space: nowrap;
    position: relative;
    width: 64rpx;
    height: 64rpx;
    z-index: 1;
    &--sm {
      width: 48rpx;
      height: 48rpx;
    }
    &--lg {
      width: 96rpx;
      height: 96rpx;
    }
    &--xl {
      width: 128rpx;
      height: 128rpx;
    }
    &--square {
      border-radius: 10rpx;
    }
    &--circle {
      border-radius: 5000rpx;
    }
    &--shadow {
      position: relative;
      &::after {
        content: " ";
        display: block;
        background: inherit;
        filter: blur(10rpx);
        position: absolute;
        width: 100%;
        height: 100%;
        top: 10rpx;
        left: 10rpx;
        z-index: -1;
        opacity: 0.4;
        transform-origin: 0 0;
        border-radius: inherit;
        transform: scale(1, 1);
      }
    }
    &__img {
      width: 100%;
      height: 100%;
      &--square {
        border-radius: 10rpx;
      }
      &--circle {
        border-radius: 5000rpx;
      }
    }
    &__text {
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-badge/tn-badge.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,173 @@
<template>
  <view
    class="tn-badge-class tn-badge"
    :class="[
      backgroundColorClass,
      fontColorClass,
      badgeClass
    ]"
    :style="[badgeStyle]"
    @click="handleClick"
  >
    <slot v-if="!dot"></slot>
  </view>
</template>
<script>
  import componentsColorMixin from '../../libs/mixin/components_color.js'
  export default {
    mixins: [componentsColorMixin],
    name: 'tn-badge',
    props: {
      // åºå·
      index: {
        type: [Number, String],
        default: '0'
      },
      // å¾½ç« çš„大小 rpx
      radius: {
        type: Number,
        default: 0
      },
      // å†…边距
      padding: {
        type: String,
        default: ''
      },
      // å¤–边距
      margin: {
        type: String,
        default: ''
      },
      // æ˜¯å¦ä¸ºä¸€ä¸ªç‚¹
      dot: {
        type: Boolean,
        default: false
      },
      // æ˜¯å¦ä½¿ç”¨ç»å¯¹å®šä½
      absolute: {
        type: Boolean,
        default: false
      },
      // top
      top: {
        type: [String, Number],
        default: ''
      },
      // right
      right: {
        type: [String, Number],
        default: ''
      },
      // å±…中 å¯¹é½å³ä¸Šè§’
      translateCenter: {
        type: Boolean,
        default: true
      }
    },
    computed: {
      badgeClass() {
        let clazz = ''
        if (this.dot) {
          clazz += ' tn-badge--dot'
        }
        if (this.absolute) {
          clazz += ' tn-badge--absolute'
          if (this.translateCenter) {
            clazz += ' tn-badge--center-position'
          }
        }
        return clazz
      },
      badgeStyle() {
        let style = {}
        if (this.radius !== 0) {
          style.width = this.radius + 'rpx'
          style.height = this.radius + 'rpx'
          style.lineHeight = this.radius + 'rpx'
          // style.borderRadius = (this.radius * 8) + 'rpx'
        }
        if (this.padding) {
          style.padding = this.padding
        }
        if (this.margin) {
          style.margin = this.margin
        }
        if (this.fontColorStyle) {
          style.color = this.fontColorStyle
        }
        if (this.fontSize) {
          style.fontSize = this.fontSize + this.fontUnit
        }
        if (this.backgroundColorStyle) {
          style.backgroundColor = this.backgroundColorStyle
        }
        if (this.top) {
          style.top = this.$t.string.getLengthUnitValue(this.top)
        }
        if (this.right) {
          style.right = this.$t.string.getLengthUnitValue(this.right)
        }
        return style
      },
    },
    data() {
      return {
      }
    },
    methods: {
      // å¤„理点击事件
      handleClick() {
        this.$emit('click', {
          index: Number(this.index)
        })
        this.$emit('tap', {
          index: Number(this.index)
        })
      },
    }
  }
</script>
<style lang="scss" scoped>
  .tn-badge {
    width: auto;
    height: auto;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10;
    font-size: 20rpx;
    background-color: #FFFFFF;
    // color: #FFFFFF;
    border-radius: 100rpx;
    padding: 4rpx 8rpx;
    line-height: initial;
    &--dot {
      width: 8rpx;
      height: 8rpx;
      border-radius: 50%;
      padding: 0;
    }
    &--absolute {
      position: absolute;
      top: 0;
      right: 0;
    }
    &--center-position {
      transform: translate(50%, -50%);
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-button/tn-button.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,302 @@
<template>
  <button
    class="tn-btn-class tn-btn"
    :class="[
      buttonClass,
      backgroundColorClass,
      fontColorClass
    ]"
    :style="[buttonStyle]"
    hover-class="tn-hover"
    :loading="loading"
    :disabled="disabled"
    :form-type="formType"
    :open-type="openType"
    @getuserinfo="handleGetUserInfo"
    @getphonenumber="handleGetPhoneNumber"
    @contact="handleContact"
    @error="handleError"
    @tap="handleClick"
  >
    <slot></slot>
  </button>
</template>
<script>
  import componentsColorMixin from '../../libs/mixin/components_color.js'
  export default {
    mixins: [componentsColorMixin],
    name: "tn-button",
    // è§£å†³å†å¾®ä¿¡å°ç¨‹åºç§ï¼Œè‡ªå®šä¹‰æŒ‰é’®æ— æ³•触发bindsubmit
    behaviors: ['wx://form-field-button'],
    props: {
      // æŒ‰é’®ç´¢å¼•,用于区分多个按钮
      index: {
        type: [Number, String],
        default: 0
      },
      // æŒ‰é’®å½¢çж default é»˜è®¤ round åœ†è§’ icon å›¾æ ‡æŒ‰é’®
      shape: {
        type: String,
        default: 'default'
      },
      // æ˜¯å¦åŠ é˜´å½±
      shadow: {
        type: Boolean,
        default: false
      },
      // å®½åº¦ rpx或%
      width: {
        type: String,
        default: 'auto'
      },
      // é«˜åº¦ rpx或%
      height: {
        type: String,
        default: ''
      },
      // æŒ‰é’®çš„尺寸 sm lg
      size: {
        type: String,
        default: ''
      },
      // å­—体是否加粗
      fontBold: {
        type: Boolean,
        default: false
      },
      padding: {
        type: String,
        default: '0 30rpx'
      },
      // å¤–边距 ä¸Žcss的margin参数用法相同
      margin: {
        type: String,
        default: ''
      },
      // æ˜¯å¦é•‚空
      plain: {
        type: Boolean,
        default: false
      },
      // å½“plain=true时,是否显示边框
      border: {
        type: Boolean,
        default: true
      },
      // å½“plain=true时,是否加粗显示边框
      borderBold: {
        type: Boolean,
        default: false
      },
      // æ˜¯å¦ç¦ç”¨
      disabled: {
        type: Boolean,
        default: false
      },
      // æ˜¯å¦æ˜¾ç¤ºåŠ è½½å›¾æ ‡
      loading: {
        type: Boolean,
        default: false
      },
      // è§¦å‘form表单的事件类型
      formType: {
        type: String,
        default: ''
      },
      // å¼€æ”¾èƒ½åŠ›
      openType: {
        type: String,
        default: ''
      },
      // æ˜¯å¦é˜»æ­¢é‡å¤ç‚¹å‡»(默认间隔是200ms)
      blockRepeatClick: {
        type: Boolean,
        default: false
      }
    },
    computed: {
      // æ ¹æ®ä¸åŒçš„参数动态生成class
      buttonClass() {
        let clazz = ''
        // æŒ‰é’®å½¢çж
        switch (this.shape) {
          case 'icon':
          case 'round':
            clazz += ' tn-round'
            break
        }
        // é˜´å½±
        if (this.shadow) {
          if (this.backgroundColorClass !== '' && this.backgroundColorClass.indexOf('tn-bg') != -1) {
            const color = this.backgroundColor.slice(this.backgroundColor.lastIndexOf('-') + 1)
            clazz += ` tn-shadow-${color}`
          } else {
            clazz += ' tn-shadow-blur'
          }
        }
        // å­—体加粗
        if (this.fontBold) {
          clazz += ' tn-text-bold'
        }
        // è®¾ç½®ä¸ºé•‚空并且设置镂空便可才进行设置
        if (this.plain) {
          clazz += ' tn-btn--plain'
          if (this.border) {
            clazz += ' tn-border-solid'
            if (this.borderBold) {
              clazz += ' tn-bold-border'
            }
            if (this.backgroundColor !== '' && this.backgroundColor.includes('tn-bg')) {
              const color = this.backgroundColor.slice(this.backgroundColor.lastIndexOf('-') + 1)
              clazz += ` tn-border-${color}`
            }
          }
        }
        return clazz
      },
      // æŒ‰é’®çš„æ ·å¼
      buttonStyle() {
        let style = {}
        switch(this.size) {
          case 'sm':
            style.padding = '0 20rpx'
            style.fontSize = '22rpx'
            style.height = this.height || '48rpx'
            break
          case 'lg':
            style.padding = '0 40rpx'
            style.fontSize = '32rpx'
            style.height = this.height || '80rpx'
            break
          default :
            style.padding = '0 30rpx'
            style.fontSize = '28rpx'
            style.height = this.height || '64rpx'
        }
        // æ˜¯å¦æ‰‹åŠ¨è®¾ç½®äº†å†…è¾¹è·
        if (this.padding) {
          style.padding = this.padding
        }
        // æ˜¯å¦æ‰‹åŠ¨è®¾ç½®å¤–è¾¹è·
        if (this.margin) {
          style.margin = this.margin
        }
        // æ˜¯å¦æ‰‹åŠ¨è®¾ç½®äº†å­—ä½“å¤§å°
        if (this.fontSize) {
          style.fontSize = this.fontSize + this.fontUnit
        }
        style.width = this.shape === 'icon' ? style.height : this.width
        style.padding = this.shape === 'icon' ? '0' : style.padding
        if (this.fontColorStyle) {
          style.color = this.fontColorStyle
        }
        if (!this.backgroundColorClass) {
          if (this.plain) {
            style.borderColor = this.backgroundColorStyle || '#080808'
          } else {
            style.backgroundColor = this.backgroundColorStyle || '#FFFFFF'
          }
        }
        // è®¾ç½®é˜´å½±
        if (this.shadow && !this.backgroundColorClass) {
          if (this.backgroundColorStyle.indexOf('#') != -1) {
            style.boxShadow = `6rpx 6rpx 8rpx ${(this.backgroundColorStyle || '#000000')}10`
          } else if (this.backgroundColorStyle.indexOf('rgb') != -1 || this.backgroundColorStyle.indexOf('rgba') != -1 || !this.backgroundColorStyle) {
            style.boxShadow = `6rpx 6rpx 8rpx ${(this.backgroundColorStyle || 'rgba(0, 0, 0, 0.1)')}`
          }
        }
        return style
      },
    },
    data() {
      return {
        // ä¸Šæ¬¡ç‚¹å‡»çš„æ—¶é—´
        clickTime: 0,
        // ä¸¤æ¬¡ç‚¹å‡»é˜²æŠ–的间隔时间
        clickIntervalTime: 200
      }
    },
    methods: {
      // æŒ‰é’®ç‚¹å‡»äº‹ä»¶
      handleClick() {
        if (this.disabled) {
          return
        }
        if (this.blockRepeatClick) {
          const nowTime = new Date().getTime()
          if (nowTime - this.clickTime <= this.clickIntervalTime) {
            return
          }
          this.clickTime = nowTime
          setTimeout(() => {
            this.clickTime = 0
          }, this.clickIntervalTime)
        }
        this.$emit('click', {
          index: Number(this.index)
        })
        // å…¼å®¹tap事件
        this.$emit('tap', {
          index: Number(this.index)
        })
      },
      handleGetUserInfo({ detail = {} } = {}) {
          this.$emit('getuserinfo', detail);
      },
      handleContact({ detail = {} } = {}) {
          this.$emit('contact', detail);
      },
      handleGetPhoneNumber({ detail = {} } = {}) {
          this.$emit('getphonenumber', detail);
      },
      handleError({ detail = {} } = {}) {
          this.$emit('error', detail);
      },
    }
  }
</script>
<style lang="scss" scoped>
  .tn-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    line-height: 1;
    text-align: center;
    text-decoration: none;
    overflow: visible;
    transform: translate(0rpx, 0rpx);
    // background-color: $tn-mai
    border-radius: 12rpx;
    // color: $tn-font-color;
    margin: 0;
    &--plain {
      background-color: transparent !important;
      background-image: none;
      &.tn-round {
        border-radius: 1000rpx !important;
      }
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-calendar/tn-calendar.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,707 @@
<template>
  <tn-popup
    v-model="value"
    mode="bottom"
    :popup="false"
    length="auto"
    :borderRadius="borderRadius"
    :safeAreaInsetBottom="safeAreaInsetBottom"
    :maskCloseable="maskCloseable"
    :closeBtn="closeBtn"
    :zIndex="elIndex"
    @close="close"
  >
    <view class="tn-calendar-class tn-calendar">
      <!-- å¤´éƒ¨ -->
      <view class="tn-calendar__header">
        <view v-if="!$slots.tooltip || !$slots.$tooltip" class="tn-calendar__header__text">
          {{ toolTips }}
        </view>
        <view v-else>
          <slot name="tooltip"></slot>
        </view>
      </view>
      <!-- æ“ä½œæç¤ºä¿¡æ¯ -->
      <view class="tn-calendar__action">
        <view v-if="changeYear" class="tn-calendar__action__icon" :style="{backgroundColor: yearArrowColor}" @tap.stop="changeYearHandler(false)">
          <view><text class="tn-icon-left"></text></view>
        </view>
        <view v-if="changeMonth" class="tn-calendar__action__icon" :style="{backgroundColor: monthArrowColor}" @tap.stop="changeMonthHandler(false)">
          <view><text class="tn-icon-left"></text></view>
        </view>
        <view class="tn-calendar__action__text">{{ dateTitle }}</view>
        <view v-if="changeMonth" class="tn-calendar__action__icon" :style="{backgroundColor: monthArrowColor}" @tap.stop="changeMonthHandler(true)">
          <view><text class="tn-icon-right"></text></view>
        </view>
        <view v-if="changeYear" class="tn-calendar__action__icon" :style="{backgroundColor: yearArrowColor}" @tap.stop="changeYearHandler(true)">
          <view><text class="tn-icon-right"></text></view>
        </view>
      </view>
      <!-- æ˜ŸæœŸä¸­æ–‡æ ‡è¯† -->
      <view class="tn-calendar__week-day-zh">
        <view v-for="(item,index) in weekDayZh" :key="index" class="tn-calendar__week-day-zh__text">{{ item }}</view>
      </view>
      <!-- æ—¥åކ䏻体 -->
      <view class="tn-calendar__content">
        <!-- å‰ç½®ç©ºç™½éƒ¨åˆ† -->
        <block v-for="(item, index) in weekdayArr" :key="index">
          <view class="tn-calendar__content__item"></view>
        </block>
        <view
          v-for="(item, index) in daysArr"
          :key="index"
          class="tn-calendar__content__item"
          :class="{
            'tn-hover': disabledChoose(year, month, index + 1),
            'tn-calendar__content--start-date': (mode === 'range' && startDate == `${year}-${month}-${index+1}`) || mode === 'date',
            'tn-calendar__content--end-date': (mode === 'range' && endDate == `${year}-${month}-${index+1}`) || mode === 'date'
          }"
          :style="{
            backgroundColor: colorValue(index, 'bg')
          }"
          @tap.stop="dateClick(index)"
        >
          <view class="tn-calendar__content__item__text" :style="{color: colorValue(index, 'text')}">
            <view>{{ item.day }}</view>
          </view>
          <view class="tn-calendar__content__item__tips" :style="{color: item.color}">
            {{ item.bottomInfo }}
          </view>
        </view>
        <view class="tn-calendar__content__month--bg">{{ month }}</view>
      </view>
      <!-- åº•部 -->
      <view class="tn-calendar__bottom">
        <view class="tn-calendar__bottom__choose">
          <text>{{ mode === 'date' ? activeDate : startDate }}</text>
          <text v-if="endDate">至{{ endDate }}</text>
        </view>
        <view class="tn-calendar__bottom__btn" :style="{backgroundColor: btnColor}" @click="handleBtnClick(false)">
          <view class="tn-calendar__bottom__btn--text">确定</view>
        </view>
      </view>
    </view>
  </tn-popup>
</template>
<script>
  import Calendar from '../../libs/utils/calendar.js'
  export default {
    name: 'tn-calendar',
    props: {
      // åŒå‘绑定控制组件弹出与收起
      value: {
        type: Boolean,
        default: false
      },
      // æ¨¡å¼
      // date -> å•日期 range -> æ—¥æœŸèŒƒå›´
      mode: {
        type: String,
        default: 'date'
      },
      // æ˜¯å¦å…è®¸åˆ‡æ¢å¹´ä»½
      changeYear: {
        type: Boolean,
        default: true
      },
      // æ˜¯å¦å…è®¸åˆ‡æ¢æœˆä»½
      changeMonth: {
        type: Boolean,
        default: true
      },
      // å¯åˆ‡æ¢çš„æœ€å¤§å¹´ä»½
      maxYear: {
        type: [Number, String],
        default: 2100
      },
      // å¯åˆ‡æ¢çš„æœ€å°å¹´ä»½
      minYear: {
        type: [Number, String],
        default: 1970
      },
      // æœ€å°æ—¥æœŸ(不在范围被不允许选择)
      minDate: {
        type: String,
        default: '1970-01-01'
      },
      // æœ€å¤§æ—¥æœŸï¼Œå¦‚果为空则默认为今天
      maxDate: {
        type: String,
        default: ''
      },
      // åˆ‡æ¢æœˆä»½æŒ‰é’®çš„颜色
      monthArrowColor: {
        type: String,
        default: '#AAAAAA'
      },
      // åˆ‡æ¢å¹´ä»½æŒ‰é’®çš„颜色
      yearArrowColor: {
        type: String,
        default: '#C8C8C8'
      },
      // é»˜è®¤å­—体颜色
      color: {
        type: String,
        default: '#080808'
      },
      // é€‰ä¸­|起始结束日期背景颜色
      activeBgColor: {
        type: String,
        default: '#01BEFF'
      },
      // é€‰ä¸­|起始结束日期文字颜色
      activeColor: {
        type: String,
        default: '#FFFFFF'
      },
      // èŒƒå›´æ—¥æœŸå†…的背景颜色
      rangeBgColor: {
        type: String,
        default: '#E6E6E655'
      },
      // èŒƒå›´æ—¥æœŸå†…的文字颜色
      rangeColor: {
        type: String,
        default: '#01BEFF'
      },
      // èµ·å§‹æ—¥æœŸæ˜¾ç¤ºçš„æ–‡å­—,mode=range时生效
      startText: {
        type: String,
        default: '开始'
      },
      // ç»“束日期显示的文字,mode=range时生效
      endText: {
        type: String,
        default: '结束'
      },
      // æŒ‰é’®èƒŒæ™¯é¢œè‰²
      btnColor: {
        type: String,
        default: '#01BEFF'
      },
      // å†œåŽ†æ–‡å­—çš„é¢œè‰²
      lunarColor: {
        type: String,
        default: '#AAAAAA'
      },
      // é€‰ä¸­æ—¥æœŸæ˜¯å¦æœ‰é€‰ä¸­æ•ˆæžœ
      isActiveCurrent: {
        type: Boolean,
        default: true
      },
      // åˆ‡æ¢å¹´æœˆæ˜¯å¦è§¦å‘事件,mode=date时生效
      isChange: {
        type: Boolean,
        default: false
      },
      // æ˜¯å¦æ˜¾ç¤ºå†œåކ
      showLunar: {
        type: Boolean,
        default: true
      },
      // é¡¶éƒ¨æç¤ºæ–‡å­—
      toolTips: {
        type: String,
        default: '请选择日期'
      },
      // æ˜¾ç¤ºåœ†è§’的大小
      borderRadius: {
        type: Number,
        default: 8
      },
      // æ˜¯å¦å¼€å¯åº•部安全区适配,开启的话,会在iPhoneX机型底部添加一定的内边距
      safeAreaInsetBottom: {
          type: Boolean,
          default: false
      },
      // æ˜¯å¦å¯ä»¥é€šè¿‡ç‚¹å‡»é®ç½©è¿›è¡Œå…³é—­
      maskCloseable: {
          type: Boolean,
          default: true
      },
      // zIndex
      zIndex: {
        type: Number,
        default: 0
      },
      // æ˜¯å¦æ˜¾ç¤ºå…³é—­æŒ‰é’®
      closeBtn: {
        type: Boolean,
        default: false
      },
    },
    computed: {
      dateChange() {
        return `${this.mode}-${this.minDate}-${this.maxDate}`
      },
      elIndex() {
        return this.zIndex ? this.zIndex : this.$t.zIndex.popup
      },
      colorValue() {
        return (index, type) => {
          let color = type === 'bg' ? '' : this.color
          let day = index + 1
          let date = `${this.year}-${this.month}-${day}`
          let timestamp = new Date(date.replace(/\-/g,'/')).getTime()
          let start = this.startDate.replace(/\-/g,'/')
          let end = this.endDate.replace(/\-/g,'/')
          if ((this.mode === 'date' && this.isActiveCurrent && this.activeDate == date) || this.startDate == date || this.endDate == date) {
            color = type === 'bg' ? this.activeBgColor : this.activeColor
          } else if (this.endDate && timestamp > new Date(start).getTime() && timestamp < new Date(end).getTime()) {
            color = type === 'bg' ? this.rangeBgColor : this.rangeColor
          }
          return color
        }
      }
    },
    data() {
      return {
        // æ˜ŸæœŸå‡ ï¼Œ1-7
        weekday: 1,
        weekdayArr: [],
        // æ˜ŸæœŸå¯¹åº”的中文
        weekDayZh: ['日','一','二','三','四','五','六'],
        // å½“前月有多少天
        days: 0,
        daysArr: [],
        year: 2021,
        month: 0,
        day: 0,
        startYear: 0,
        startMonth: 0,
        startDay: 0,
        endYear: 0,
        endMonth: 0,
        endDay: 0,
        today: '',
        activeDate: '',
        startDate: '',
        endDate: '',
        min: null,
        max: null,
        // æ—¥æœŸæ ‡é¢˜
        dateTitle: '',
        // æ ‡è®°æ˜¯å¦å·²ç»é€‰æ‹©äº†å¼€å§‹æ—¥æœŸ
        chooseStart: false
      }
    },
    watch: {
      dateChange() {
        this.init()
      }
    },
    created() {
      this.init()
    },
    methods: {
      // åˆå§‹åŒ–
      init() {
        let now = new Date()
        this.year = now.getFullYear()
        this.month = now.getMonth() + 1
        this.day = now.getDate()
        this.today = `${this.year}-${this.month}-${this.day}`
        this.activeDate = this.today
        this.min = this.initDate(this.minDate)
        this.max = this.initDate(this.maxDate || this.today)
        this.startDate = ''
        this.startYear = 0
        this.startMonth = 0
        this.startDay = 0
        this.endDate = ''
        this.endYear = 0
        this.endMonth = 0
        this.endDay = 0
        this.chooseStart = false
        this.changeData()
      },
      // åˆ‡æ¢æœˆä»½
      changeMonthHandler(add) {
        if (add) {
          let month = this.month + 1
          let year = month > 12 ? this.year + 1 : this.year
          if (!this.checkRange(year)) {
            this.month = month > 12 ? 1 : month
            this.year = year
            this.changeData()
          }
        } else {
          let month = this.month - 1
          let year = month < 1 ? this.year - 1 : this.year
          if (!this.checkRange(year)) {
            this.month = month < 1 ? 12 : month
            this.year = year
            this.changeData()
          }
        }
      },
      // åˆ‡æ¢å¹´ä»½
      changeYearHandler(add) {
        let year = add ? this.year + 1 : this.year - 1
        if (!this.checkRange(year)) {
          this.year = year
          this.changeData()
        }
      },
      // æ—¥æœŸç‚¹å‡»äº‹ä»¶
      dateClick(day) {
        day += 1
        if (!this.disabledChoose(this.year, this.month, day)) {
          this.day = day
          let date = `${this.year}-${this.month}-${day}`
          if (this.mode === 'date') {
            this.activeDate = date
          } else {
            let startTimeCompare = new Date(date.replace(/\-/g,'/')).getTime() < new Date(this.startDate.replace(/\-/g,'/')).getTime()
            if (!this.chooseStart || startTimeCompare) {
              this.startDate = date
              this.startYear = this.year
              this.startMonth = this.month
              this.startDay = this.day
              this.endYear = 0
              this.endMonth = 0
              this.endDay = 0
              this.endDate = ''
              this.activeDate = ''
              this.chooseStart = true
            } else {
              this.endDate = date
              this.endYear = this.year
              this.endMonth = this.month
              this.endDay = this.day
              this.chooseStart = false
            }
          }
          this.daysArr = this.handleDaysArr()
        }
      },
      // ä¿®æ”¹æ—¥æœŸæ•°æ®
      changeData() {
        this.days = this.getMonthDay(this.year, this.month)
        this.daysArr = this.handleDaysArr()
        this.weekday = this.getMonthFirstWeekDay(this.year, this.month)
        this.weekdayArr = this.generateArray(1, this.weekday)
        this.dateTitle = `${this.year}å¹´${this.month}月`
        if (this.isChange && this.mode === 'date') {
          this.handleBtnClick(true)
        }
      },
      // å¤„理按钮点击
      handleBtnClick(show) {
        if (!show) {
          this.close()
        }
        if (this.mode === 'date') {
          let arr = this.activeDate.split('-')
          let year = this.isChange ? this.year : Number(arr[0])
          let month = this.isChange ? this.month : Number(arr[1])
          let day = this.isChange ? this.day : Number(arr[2])
          let days = this.getMonthDay(year, month)
          let result = `${year}-${this.formatNumber(month)}-${this.formatNumber(day)}`
          let weekText = this.getWeekText(result)
          let isToday = false
          if (`${year}-${month}-${day}` === this.today) {
            isToday = true
          }
          this.$emit('change', {
            year,
            month,
            day,
            days,
            week: weekText,
            isToday,
            date: result,
            // æ˜¯å¦ä¸ºåˆ‡æ¢å¹´æœˆæ“ä½œ
            switch: show
          })
        } else {
          if (!this.startDate || !this.endDate) return
          let startMonth = this.formatNumber(this.startMonth)
          let startDay = this.formatNumber(this.startDay)
          let startDate = `${this.startYear}-${startMonth}-${startDay}`
          let startWeek = this.getWeekText(startDate)
          let endMonth = this.formatNumber(this.endMonth)
          let endDay = this.formatNumber(this.endDay)
          let endDate = `${this.endYear}-${endMonth}-${endDay}`
          let endWeek = this.getWeekText(endDate)
          this.$emit('change', {
            startYear: this.startYear,
            startMonth: this.startMonth,
            startDay: this.startDay,
            startDate,
            startWeek,
            endYear: this.endYear,
            endMonth: this.endMonth,
            endDay: this.endDay,
            endDate,
            endWeek
          })
        }
      },
      // åˆ¤æ–­æ˜¯å¦å…è®¸é€‰æ‹©
      disabledChoose(year, month, day) {
        let flag = true
        let date = `${year}/${month}/${day}`
        let min = `${this.min.year}/${this.min.month}/${this.min.day}`
        let max = `${this.max.year}/${this.max.month}/${this.max.day}`
        let timestamp = new Date(date).getTime()
        if (timestamp >= new Date(min).getTime() && timestamp <= new Date(max).getTime()) {
          flag = false
        }
        return flag
      },
      // æ£€æŸ¥æ˜¯å¦åœ¨æ—¥æœŸèŒƒå›´å†…
      checkRange(year) {
        let overstep = false
        if (year < this.minYear || year > this.maxYear) {
          uni.showToast({
            title: '所选日期超出范围',
            icon: 'none'
          })
          overstep = true
        }
        return overstep
      },
      // å¤„理日期
      initDate(date) {
        let fdate = date.split('-')
        return {
          year: Number(fdate[0] || 1970),
          month: Number(fdate[1] || 1),
          day: Number(fdate[2] || 1)
        }
      },
      // å¤„理日期数组
      handleDaysArr() {
        let days = this.generateArray(1, this.days)
        let daysArr = days.map((item) => {
          let bottomInfo = this.showLunar ? Calendar.solar2lunar(this.year, this.month, item).IDayCn : ''
          let color = this.showLunar ? this.lunarColor : this.activeColor
          if (
            (this.mode === 'date' && this.day == item) ||
            (this.mode === 'range' && (this.startDay == item || this.endDay == item))
          ) {
            color = this.activeColor
          }
          if (this.mode === 'range') {
            if (this.startDay == item && this.startDay != this.endDay) {
              bottomInfo = this.startText
            }
            if (this.endDay == item) {
              bottomInfo = this.endText
            }
          }
          return {
            day: item,
            color: color,
            bottomInfo: bottomInfo
          }
        })
        return daysArr
      },
      // èŽ·å–å¯¹åº”æœˆæœ‰å¤šå°‘å¤©
      getMonthDay(year, month) {
        return new Date(year, month, 0).getDate()
      },
      // èŽ·å–å¯¹åº”æœˆçš„ç¬¬ä¸€å¤©æ—¶æ˜ŸæœŸå‡ 
      getMonthFirstWeekDay(year, month) {
        return new Date(`${year}/${month}/01 00:00:00`).getDay()
      },
      // èŽ·å–å¯¹åº”æ˜ŸæœŸçš„æ–‡æœ¬
      getWeekText(date) {
        date = new Date(`${date.replace(/\-/g, '/')} 00:00:00`)
        let week = date.getDay()
        return '星期' + this.weekDayZh[week]
      },
      // ç”Ÿæˆæ—¥æœŸå¤©æ•°æ•°ç»„
      generateArray(start, end) {
        return Array.from(new Array(end + 1).keys()).slice(start)
      },
      // æ ¼å¼åŒ–æ•°å­—
      formatNumber(num) {
        return num < 10 ? '0' + num : num + ''
      },
      // å…³é—­çª—口
      close() {
        this.$emit('input', false)
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-calendar {
    color: $tn-font-color;
    &__header {
      width: 100%;
      box-sizing: border-box;
      font-size: 30rpx;
      background-color: #FFFFFF;
      color: $tn-main-color;
      &__text {
        display: flex;
        flex-direction: row;
        align-items: center;
        justify-content: center;
        margin-top: 30rpx;
        padding: 0 60rpx;
      }
    }
    &__action {
      display: flex;
      flex-direction: row;
      justify-content: center;
      align-items: center;
      padding: 40rpx 0 40rpx 0;
      &__icon {
        display: flex;
        align-items: center;
        justify-content: center;
        margin: 0 16rpx;
        width: 32rpx;
        height: 32rpx;
        font-size: 20rpx;
        // line-height: 32rpx;
        border-radius: 50%;
        color: #FFFFFF;
      }
      &__text {
        padding: 0 16rpx;
        color: $tn-font-color;
        font-size: 32rpx;
        font-weight: bold;
      }
    }
    &__week-day-zh {
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;
      padding: 12rpx 0;
      overflow: hidden;
      box-shadow: 16rpx 6rpx 8rpx 0 #E6E6E6;
      margin-bottom: 2rpx;
      &__text {
        flex: 1;
        text-align: center;
      }
    }
    &__content {
      display: flex;
      flex-direction: row;
      flex-wrap: wrap;
      width: 100%;
      padding: 12rpx 0;
      box-sizing: border-box;
      background-color: #F7F7F7;
      position: relative;
      &__item {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        width: 14.2857%;
        padding: 12rpx 0;
        margin: 6rpx 0;
        overflow: hidden;
        position: relative;
        z-index: 2;
        // box-shadow: inset 0rpx 0rpx 22rpx 4rpx rgba(255,255,255, 0.52);
        &__text {
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          height: 80rpx;
          font-size: 32rpx;
          position: relative;
        }
        &__tips {
          position: absolute;
          width: 100%;
          line-height: 24rpx;
          left: 0;
          bottom: 8rpx;
          text-align: center;
          z-index: 2;
          transform-origin: center center;
          transform: scale(0.8);
        }
      }
      &--start-date {
        border-top-left-radius: 8rpx;
        border-bottom-left-radius: 8rpx;
      }
      &--end-date {
        border-top-right-radius: 8rpx;
        border-bottom-right-radius: 8rpx;
      }
      &__month {
        &--bg {
          position: absolute;
          font-size: 200rpx;
          line-height: 200rpx;
          left: 50%;
          top: 50%;
          transform: translate(-50%, -50%);
          color: $tn-font-holder-color;
          z-index: 1;
        }
      }
    }
    &__bottom {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      width: 100%;
      background-color: #F7F7F7;
      padding: 0 40rpx 30rpx;
      box-sizing: border-box;
      font-size: 24rpx;
      color: $tn-font-sub-color;
      &__choose {
        height: 50rpx;
      }
      &__btn {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 100%;
        height: 60rpx;
        border-radius: 40rpx;
        color: #FFFFFF;
        font-size: 28rpx;
      }
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-car-keyboard/tn-car-keyboard.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,320 @@
<template>
  <view class="tn-car-keyboard-class tn-car-keyboard" @touchmove.stop.prevent="() => {}">
    <view class="tn-car-keyboard__grids">
      <view
        v-for="(data, index) in inputCarNumber ? endKeyBoardList : areaList"
        :key="index"
        class="tn-car-keyboard__grids__item"
      >
        <view
          v-for="(sub_data, sub_index) in data"
          :key="sub_index"
          class="tn-car-keyboard__grids__btn"
          :class="{'tn-car-keyboard__grids__btn--disabled': sub_data === 'I'}"
          :hover-class="sub_data !== 'I' ? 'tn-car-keyboard--hover' : ''"
          :hover-stay-time="100"
          @tap="click(index, sub_index)"
        >
          {{ sub_data }}
        </view>
      </view>
      <view
        class="tn-car-keyboard__back"
        hover-class="tn-hover-class"
        :hover-stay-time="150"
        @touchstart.stop="backspaceClick"
        @touchend="clearTimer"
      >
        <view class="tn-icon-left-arrow tn-car-keyboard__back__icon"></view>
      </view>
      <view
        class="tn-car-keyboard__change"
        hover-class="tn-car-keyboard--hover"
        :hover-stay-time="150"
        @tap="changeMode"
      >
        <text class="tn-car-keyboard__mode--zh" :class="[`tn-car-keyboard__mode--${!inputCarNumber ? 'active' : 'inactive'}`]">中</text>
        /
        <text class="tn-car-keyboard__mode--en" :class="[`tn-car-keyboard__mode--${inputCarNumber ? 'active' : 'inactive'}`]">英</text>
      </view>
    </view>
  </view>
</template>
<script>
  export default {
    name: 'tn-car-keyboard',
    props: {
      // æ˜¯å¦æ‰“乱键盘顺序
      randomEnabled: {
        type: Boolean,
        default: false
      },
      // åˆ‡æ¢ä¸­è‹±æ–‡è¾“å…¥
      switchEnMode: {
        type: Boolean,
        default: false
      }
    },
    computed: {
      areaList() {
        let data = [
          '京',
          '沪',
          '粤',
          'æ´¥',
          '冀',
          '豫',
          '云',
          'è¾½',
          '黑',
          '湘',
          '皖',
          '鲁',
          '苏',
          '浙',
          'èµ£',
          '鄂',
          '桂',
          '甘',
          '晋',
          '陕',
          '蒙',
          '吉',
          '闽',
          'è´µ',
          '渝',
          '川',
          '青',
          '琼',
          '宁',
          '藏',
          '港',
          'æ¾³',
          '新',
          '使',
          'å­¦',
          '临',
          'è­¦'
        ]
        // æ‰“乱顺序
        if (this.randomEnabled) data = this.$t.array.random(data)
        // åˆ‡å‰²äºŒç»´æ•°ç»„
        let showData = []
        showData[0] = data.slice(0, 10)
        showData[1] = data.slice(10, 20)
        showData[2] = data.slice(20, 30)
        showData[3] = data.slice(30, 37)
        return showData
      },
      endKeyBoardList() {
        let data = [
          1,
          2,
          3,
          4,
          5,
          6,
          7,
          8,
          9,
          0,
          'Q',
          'W',
          'E',
          'R',
          'T',
          'Y',
          'U',
          'I',
          'O',
          'P',
          'A',
          'S',
          'D',
          'F',
          'G',
          'H',
          'J',
          'K',
          'L',
          'Z',
          'X',
          'C',
          'V',
          'B',
          'N',
          'M'
        ]
        // æ‰“乱顺序
        if (this.randomEnabled) data = this.$t.array.random(data)
        // åˆ‡å‰²äºŒç»´æ•°ç»„
        let showData = []
        showData[0] = data.slice(0, 10)
        showData[1] = data.slice(10, 20)
        showData[2] = data.slice(20, 29)
        showData[3] = data.slice(29, 36)
        return showData
      }
    },
    data() {
      return {
        // æ ‡è®°æ˜¯å¦è¾“入车牌号码
        inputCarNumber: false,
        // é•¿æŒ‰å¤šæ¬¡åˆ é™¤äº‹ä»¶ç›‘听
        longPressDeleteTimer: null
      }
    },
    watch:{
      switchEnMode: {
        handler(value) {
          if (value) {
            this.inputCarNumber = true
          } else {
            this.inputCarNumber = false
          }
        },
        immediate: true
      }
    },
    methods: {
      // ç‚¹å‡»é”®ç›˜æŒ‰é’®
      click(i, j) {
        let value = ''
        // æ ¹æ®ä¸åŒæ¨¡å¼èŽ·å–ä¸åŒæ•°ç»„çš„å€¼
        if (this.inputCarNumber) value = this.endKeyBoardList[i][j]
        else value = this.areaList[i][j]
        // è½¦ç‰Œé‡Œä¸åŒ…含I
        if (value === 'I') return
        this.$emit('change', value)
      },
      // ä¿®æ”¹è¾“入模式
      // ä¸­æ–‡/英文
      changeMode() {
        this.inputCarNumber = !this.inputCarNumber
      },
      // ç‚¹å‡»é€€æ ¼
      backspaceClick() {
        this.$emit('backspace')
        this.clearTimer()
        this.longPressDeleteTimer = setInterval(() => {
          this.$emit('backspace')
        }, 250)
      },
      // æ¸…空定时器
      clearTimer() {
        if (this.longPressDeleteTimer) {
          clearInterval(this.longPressDeleteTimer)
          this.longPressDeleteTimer = null
        }
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-car-keyboard {
    position: relative;
    padding: 24rpx 0;
    background-color: #E6E6E6;
    &__grids {
      &__item {
        display: flex;
        flex-direction: row;
        align-items: center;
        justify-content: center;
      }
      &__btn {
        display: inline-flex;
        justify-content: center;
        flex: 0 0 64rpx;
        width: 62rpx;
        height: 80rpx;
        font-size: 38rpx;
        line-height: 80rpx;
        font-weight: 500;
        text-decoration: none;
        text-align: center;
        background-color: #FFFFFF;
        margin: 8rpx 5rpx;
        border-radius: 8rpx;
        box-shadow: 0 2rpx 0rpx $tn-box-shadow-color;
        &--disabled {
          opacity: 0.6;
        }
      }
    }
    &__back {
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;
      position: absolute;
      width: 96rpx;
      height: 80rpx;
      right: 22rpx;
      bottom: 32rpx;
      background-color: #E6E6E6;
      border-radius: 8rpx;
      box-shadow: 0 2rpx 0rpx $tn-box-shadow-color;
    }
    &__change {
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;
      position: absolute;
      width: 96rpx;
      height: 80rpx;
      left: 22rpx;
      bottom: 32rpx;
      line-height: 1;
      background-color: #FFFFFF;
      border-radius: 8rpx;
      box-shadow: 0 2rpx 0rpx $tn-box-shadow-color;
    }
    &__mode {
      &--zh {
        transform: translateY(-10rpx);
      }
      &--en {
        transform: translateY(10rpx);
      }
      &--active {
        color: $tn-main-color;
        font-size: 30rpx;
      }
      &--inactive {
        &.tn-car-keyboard__mode--zh {
          transform: scale(0.85) translateY(-10rpx);
        }
      }
      &--inactive {
        &.tn-car-keyboard__mode--en {
          transform: scale(0.85) translateY(10rpx);
        }
      }
    }
    &--hover {
      background-color: #E6E6E6 !important;
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-cascade-selection/tn-cascade-selection.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,654 @@
<template>
  <view class="tn-cascade-selection tn-cascade-selection-class">
    <scroll-view
      class="selection__scroll-view"
      :class="[{'tn-border-solid-bottom': headerLine}]"
      :style="[scrollViewStyle]"
      scroll-x
      scroll-with-animation
      :scroll-into-view="scrollViewId"
    >
      <view class="selection__header" :class="[backgroundColorClass]" :style="[headerStyle]">
        <view
          v-for="(item, index) in selectedArr"
          :key="index"
          :id="`select__${index}`"
          class="selection__header__item"
          :class="[headerItemClass(index)]"
          :style="[headerItemStyle(index)]"
          @tap.stop="clickNav(index)"
        >
          {{ item.text }}
          <view
            v-if="index===currentTab && showActiveLine"
            class="selection__header__line"
            :style="{backgroundColor: activeLineColor}"
          ></view>
        </view>
      </view>
    </scroll-view>
    <swiper
      class="selection__list"
      :class="[backgroundColorClass]"
      :style="[listStyle]"
      :current="currentTab"
      :duration="300"
      @change="switchTab"
    >
      <swiper-item
        v-for="(item, index) in selectedArr"
        :key="index"
      >
        <scroll-view
          class="selection__list__item"
          :style="{height: selectionContainerHeight + 'rpx'}"
          scroll-y
          :scroll-into-view="item.scrollViewId"
        >
          <view class="selection__list__item--first"></view>
          <view
            v-for="(subItem, subIndex) in item.list"
            :key="subIndex"
            :id="`select__${subIndex}`"
            class="selection__list__item__cell"
            :style="[itemStyle]"
            @tap="change(index, subIndex, subItem)"
          >
            <view
              v-if="item.index === subIndex"
              class="selection__list__item__icon tn-icon-success"
              :style="[itemIconStyle]"
            ></view>
            <image
              v-if="subItem.src"
              class="selection__list__item__image"
              :style="[itemImageStyle]"
              :src="subItem.src"
            ></image>
            <view
              class="selection__list__item__title"
              :class="[{'tn-text-bold': item.index === subIndex && itemActiveBold}]"
              :style="[itemTitleStyle(index, subIndex)]"
            >
              {{ subItem.text }}
            </view>
            <view
              v-if="subItem.subText"
              class="selection__list__item__title--sub"
              :style="[itemSubTitleStyle]"
            >
              {{ subItem.subText }}
            </view>
          </view>
        </scroll-view>
      </swiper-item>
    </swiper>
  </view>
</template>
<script>
  import componentsColorMixin from '../../libs/mixin/components_color.js'
  export default {
    name: 'tn-cascade-selection',
    mixins: [ componentsColorMixin ],
    props: {
      // å¦‚果下一级是请求返回,则为第一级数据,否则为所有数据
      /* {
        text: '', // æ ‡é¢˜
        subText: '', // å­æ ‡é¢˜
        src: '', // å›¾ç‰‡åœ°å€
        value: 0, // é€‰ä¸­çš„值
        children: [
          {
            text: '',
            subText: '',
            value: 0,
            children: []
          }
        ]
      } */
      list: {
        type: Array,
        default() {
          return []
        }
      },
      // é»˜è®¤é€‰ä¸­å€¼
      // ['value1','value2','value3']
      defaultValue: {
        type: Array,
        default() {
          return []
        }
      },
      // å­é›†æ•°æ®é€šè¿‡è¯·æ±‚来获取
      request: {
        type: Boolean,
        default: false
      },
      // request为true时生效, èŽ·å–åˆ°çš„å­é›†æ•°æ®
      receiveData: {
        type: Array,
        default() {
          return []
        }
      },
      // æ˜¾ç¤ºheader底部细线
      headerLine: {
        type: Boolean,
        default: true
      },
      // header背景颜色
      headerBgColor: {
        type: String,
        default: ''
      },
      // é¡¶éƒ¨æ ‡ç­¾æ é«˜åº¦,单位rpx
      tabsHeight: {
        type: Number,
        default: 88
      },
      // é»˜è®¤æ˜¾ç¤ºæ–‡å­—
      text: {
        type: String,
        default: '请选择'
      },
      // é€‰ä¸­çš„颜色
      activeColor: {
        type: String,
        default: '#01BEFF'
      },
      // é€‰ä¸­åŽåŠ ç²—
      activeBold: {
        type: Boolean,
        default: true
      },
      // é€‰ä¸­æ˜¾ç¤ºåº•部线条
      showActiveLine: {
        type: Boolean,
        default: true
      },
      // çº¿æ¡é¢œè‰²
      activeLineColor: {
        type: String,
        default: '#01BEFF'
      },
      // icon大小,单位rpx
      activeIconSize: {
        type: Number,
        default: 0
      },
      // icon颜色
      activeIconColor: {
        type: String,
        default: '#01BEFF'
      },
      // item图片宽度, å•位rpx
      itemImgWidth: {
        type: Number,
        default: 0
      },
      // item图片高度, å•位rpx
      itemImgHeight: {
        type: Number,
        default: 0
      },
      // item图片圆角
      itemImgRadius: {
        type: String,
        default: '50%'
      },
      // item text颜色
      itemTextColor: {
        type: String,
        default: ''
      },
      // item text选中颜色
      itemActiveTextColor: {
        type: String,
        default: ''
      },
      // item text选中加粗
      itemActiveBold: {
        type: Boolean,
        default: true
      },
      // item text文字大小, å•位rpx
      itemTextSize: {
        type: Number,
        default: 0
      },
      // item subText颜色
      itemSubTextColor: {
        type: String,
        default: ''
      },
      // item subText字体大小, å•位rpx
      itemSubTextSize: {
        type: Number,
        default: 0
      },
      // item样式
      itemStyle: {
        type: Object,
        default() {
          return {}
        }
      },
      // selection选项容器高度, å•位rpx
      selectionContainerHeight: {
        type: Number,
        default: 300
      }
    },
    computed: {
      scrollViewStyle() {
        let style = {}
        if (this.headerBgColor) {
          style.backgroundColor = this.headerBgColor
        }
        return style
      },
      headerStyle() {
        let style = {}
        style.height = `${this.tabsHeight}rpx`
        if (this.backgroundColorStyle) {
          style.backgroundColor = this.backgroundColorStyle
        }
        return style
      },
      headerItemClass() {
        return (index) => {
          let clazz = ''
          if (index !== this.currentTab) {
            clazz += ` ${this.fontColorClass}`
          } else {
            if (this.activeBold) {
              clazz += ' tn-text-bold'
            }
          }
          return clazz
        }
      },
      headerItemStyle() {
        return (index) => {
          let style = {}
          style.color = index === this.currentTab ? this.activeColor : (this.fontColorStyle ? this.fontColorStyle : '')
          if (this.fontSizeStyle) {
            style.fontSize = this.fontSizeStyle
          }
          return style
        }
      },
      listStyle() {
        let style = {}
        style.height = `${this.selectionContainerHeight}rpx`
        if (this.backgroundColorStyle) {
          style.color = this.backgroundColorStyle
        }
        return style
      },
      itemIconStyle() {
        let style = {}
        if (this.activeIconColor) {
          style.color = this.activeIconColor
        }
        if (this.activeIconSize) {
          style.fontSize = this.activeIconSize + 'rpx'
        }
        return style
      },
      itemImageStyle() {
        let style = {}
        if (this.itemImgWidth) {
          style.width = this.itemImgWidth + 'rpx'
        }
        if (this.itemImgHeight) {
          style.height = this.itemImgHeight + 'rpx'
        }
        if (this.itemImgRadius) {
          style.borderRadius = this.itemImgRadius
        }
        return style
      },
      itemTitleStyle() {
        return (index, subIndex) => {
          let style = {}
          if (index === subIndex) {
            if (this.itemActiveTextColor) {
              style.color = this.itemActiveTextColor
            }
          } else {
            if (this.itemTextColor) {
              style.color = this.itemTextColor
            }
          }
          if (this.itemTextSize) {
            style.fontSize = this.itemTextSize + 'rpx'
          }
          return style
        }
      },
      itemSubTitleStyle() {
        let style = {}
        if (this.itemSubTextColor) {
          style.color = this.itemSubTextColor
        }
        if (this.itemSubTextSize) {
          style.fontSize = this.itemSubTextSize + 'rpx'
        }
        return {}
      }
    },
    watch: {
      list(val) {
        this.initData(val, -1)
      },
      defaultValue(val) {
        this.setDefaultValue(val)
      },
      receiveData(val) {
        this.addSubData(val, this.currentTab)
      },
    },
    data() {
      return {
        // å½“前选中的子集
        currentTab: 0,
        // tabs栏scrollView滚动的位置
        scrollViewId: 'select__0',
        // é€‰é¡¹æ•°ç»„
        selectedArr: []
      }
    },
    created() {
      this.setDefaultValue(this.defaultValue)
    },
    methods: {
      // åˆå§‹åŒ–数据
      initData(data, index) {
        if (!data || data.length === 0) return
        if (this.request) {
          // ç¬¬ä¸€çº§æ•°æ®
          this.addSubData(data, index)
        } else {
          this.addSubData(this.getItemList(index, -1), index)
        }
      },
      // é‡ç½®æ•°æ®
      reset() {
        this.initData(this.list, -1)
      },
      // æ»šåŠ¨åˆ‡æ¢
      switchTab(e) {
        this.currentTab = e.detail.current
        this.checkSelectPosition()
      },
      // ç‚¹å‡»æ ‡é¢˜åˆ‡æ¢
      clickNav(index) {
        if (this.currentTab !== index) {
          this.currentTab = index
        }
      },
      // åˆ—表数据发生改变
      change(index, subIndex, subItem) {
        let item = this.selectedArr[index]
        if (item.index === subIndex) return
        item.index = subIndex
        item.text = subItem.text
        item.subText = subItem.subText || ''
        item.value = subItem.value
        item.src = subItem.src || ''
        this.$emit('change', {
          index: index,
          subIndex: subIndex,
          ...subItem
        })
        // å¦‚果不是异步加载,则取出对应的数据
        if (!this.request) {
          let data = this.getItemList(index, subIndex)
          this.addSubData(data, index)
        }
      },
      // è®¾ç½®é»˜è®¤çš„æ•°æ®
      setDefaultValue(val) {
        let defaultValues = val || []
        if (defaultValues.length > 0) {
          this.selectedArr = this.getItemListWithValues(JSON.parse(JSON.stringify(this.list)), defaultValues)
          if (!this.selectedArr) return
          this.currentTab = this.selectedArr.length - 1
          this.$nextTick(() => {
            this.checkSelectPosition()
          })
          // defaultItemList.map((item) => {
          //   item.scrollViewId = `select__${item.index}`
          // })
          // this.selectedArr = defaultItemList
          // this.currentTab = defaultItemList.length - 1
          // this.$nextTick(() => {
          //   this.checkSelectPosition()
          // })
        } else {
          this.initData(this.list, -1)
        }
      },
      // èŽ·å–å¯¹åº”é€‰é¡¹çš„item数据
      getItemList(index, subIndex) {
        let list = []
        let arr = JSON.parse(JSON.stringify(this.list))
        // åˆå§‹åŒ–数据
        if (index === -1) {
          list = this.removeChildren(arr)
        } else {
          // åˆ¤æ–­ç¬¬ä¸€é¡¹æ˜¯å¦å·²ç»é€‰æ‹©
          let value = this.selectedArr[0].index
          value = value === -1 ? subIndex : value
          list = arr[value].children || []
          if (index > 0) {
            for (let i = 1; i < index + 1; i++) {
              // èŽ·å–å½“å‰æ•°æ®é€‰ä¸­çš„åºå·
              let val = index === i ? subIndex : this.selectedArr[i].index
              list = list[val].children || []
              if (list.length === 0) break
            }
          }
          list = this.removeChildren(list)
        }
        return list
      },
      // æ ¹æ®æ•°ç»„中的值获取对应的item数据
      getItemListWithValues(data, values) {
        const defaultValues = JSON.parse(JSON.stringify(values))
        if (!defaultValues || defaultValues.length === 0) return
        // å–出第一个值所对应的item
        const itemIndex = data.findIndex((item) => {
          return item.value === defaultValues[0]
        })
        if (itemIndex === -1) return
        const item = data[itemIndex]
        item.index = itemIndex
        item.scrollViewId = `select__${itemIndex}`
        item.list = this.removeChildren(JSON.parse(JSON.stringify(data)))
        // åˆ¤æ–­æ˜¯å¦åªæœ‰1个值
        if (defaultValues.length === 1 || (!item.hasOwnProperty('children') || item.children.length === 0)) {
          return this.removeChildren([item])
        } else {
          let selectItemList = []
          const children = item.children
          selectItemList.push(item)
          // ç§»é™¤å·²ç»èŽ·å–çš„å€¼
          defaultValues.splice(0, 1)
          const childrenValue = this.getItemListWithValues(children, defaultValues)
          selectItemList = selectItemList.concat(childrenValue)
          return this.removeChildren(selectItemList)
        }
      },
      // åˆ é™¤å­å…ƒç´ 
      removeChildren(data) {
        let list = data.map((item) => {
          if (item.hasOwnProperty('children')) {
            delete item['children']
          }
          return item
        })
        return list
      },
      // æ–°å¢žå­é›†æ•°æ®æ—¶å¤„理
      addSubData(data, index) {
        // åˆ¤æ–­æ˜¯å¦å·²ç»å®Œæˆé€‰æ‹©æ•°æ®æˆ–者为初始化数据
        if (!data || data.length === 0) {
          if (index == -1) return
          // å®Œæˆé€‰æ‹©
          let arr = this.selectedArr
          // å¦‚果当前选中项的序号比已选数据的长度小,则表示当前重新选择了数据
          if (index < arr.length - 1) {
            let newArr = arr.slice(0, index + 1)
            this.selectedArr = newArr
          }
          let result = JSON.parse(JSON.stringify(this.selectedArr))
          let lastItem = result[result.length - 1] || {}
          let text = ''
          result.map(item => {
            text += item.text
            delete item['list']
            delete item['scrollViewId']
            return item
          })
          this.$emit('complete', {
            result: result,
            value: lastItem.value,
            text: text,
            subText: lastItem.subText,
            src: lastItem.src
          })
        } else {
          // é‡ç½®æ•°æ®
          let item = [{
            text: this.text,
            subText: '',
            value: '',
            src: '',
            index: -1,
            scrollViewId: 'select__0',
            list: data
          }]
          // åˆå§‹åŒ–数据
          if (index === -1) {
            this.selectedArr = item
          } else {
            // æ‹¼æŽ¥æ–°æ—§æ•°æ®å¹¶ä¸”判断是否为重新选择了数据(如果为重新选择了数据则重置之后的选项数据)
            let retainArr = this.selectedArr.slice(0, index + 1)
            this.selectedArr = retainArr.concat(item)
          }
          this.$nextTick(() => {
            this.currentTab = this.selectedArr.length - 1
          })
        }
      },
      // æ£€æŸ¥å½“前选中项,并将选项设置位置信息
      checkSelectPosition() {
        let item = this.selectedArr[this.currentTab]
        item.scrollViewId = 'select__0'
        this.$nextTick(() => {
          setTimeout(() => {
            // è®¾ç½®å½“前数据滚动到的位置
            let val = item.index < 2 ? 0 : Number(item.index - 2)
            item.scrollViewId = `select__${val}`
          }, 10)
        })
        // è®¾ç½®é€‰é¡¹æ»šåŠ¨åˆ°æ‰€åœ¨çš„ä½ç½®
        if (this.currentTab > 1) {
          this.scrollViewId = `select__${this.currentTab - 1}`
        } else {
          this.scrollViewId = `select__0`
        }
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-cascade-selection {
    width: 100%;
  }
  .selection {
    &__scroll-view {
      background-color: #FFFFFF;
    }
    &__header {
      width: 100%;
      display: flex;
      align-items: center;
      position: relative;
      &__item {
        max-width: 240rpx;
        padding: 15rpx 30rpx;
        flex-shrink: 0;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
        position: relative;
      }
      &__line {
        width: 60rpx;
        height: 6rpx;
        border-radius: 4rpx;
        position: absolute;
        bottom: 0;
        right: 0;
        left: 50%;
        transform: translateX(-50%);
      }
    }
    &__list {
      background-color: #FFFFFF;
      &__item {
        &--first {
          width: 100%;
          height: 20rpx;
        }
        &__cell {
          width: 100%;
          display: flex;
          align-items: center;
          padding: 20rpx 30rpx;
        }
        &__icon {
          margin-right: 12rpx;
          font-size: 24rpx;
        }
        &__image {
          width: 40rpx;
          height: 40rpx;
          margin-right: 12rpx;
          flex-shrink: 0;
        }
        &__title {
          word-break: break-all;
          color: #333333;
          font-size: 28rpx;
          &--sub {
            margin-left: 20rpx;
            word-break: break-all;
            color: $tn-font-sub-color;
            font-size: 24rpx;
          }
        }
      }
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-checkbox-group/tn-checkbox-group.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,134 @@
<template>
  <view class="tn-checkbox-group-class tn-checkbox-group">
    <slot></slot>
  </view>
</template>
<script>
  import Emitter from '../../libs/utils/emitter.js'
  export default {
    mixins: [ Emitter ],
    name: 'tn-checkbox-group',
    props: {
      value: {
        type: Array,
        default() {
          return []
        }
      },
      // å¯ä»¥é€‰ä¸­å¤šå°‘个checkbox
      max: {
        type: Number,
        default: 999
      },
      // è¡¨å•提交时的标识符
      name: {
        type: String,
        default: ''
      },
      // ç¦ç”¨é€‰æ‹©
      disabled: {
        type: Boolean,
        default: false
      },
      // ç¦ç”¨ç‚¹å‡»æ ‡ç­¾è¿›è¡Œé€‰æ‹©
      disabledLabel: {
        type: Boolean,
        default: false
      },
      // é€‰æ‹©æ¡†çš„形状 square æ–¹å½¢ circle åœ†å½¢
      shape: {
        type: String,
        default: 'square'
      },
      // é€‰ä¸­æ—¶çš„颜色
      activeColor: {
        type: String,
        default: '#01BEFF'
      },
      // ç»„件大小
      size: {
        type: Number,
        default: 34
      },
      // æ¯ä¸ªcheckbox占的宽度
      width: {
        type: String,
        default: 'auto'
      },
      // æ˜¯å¦æ¢è¡Œ
      wrap: {
        type: Boolean,
        default: false
      },
      // å›¾æ ‡å¤§å°
      iconSize: {
        type: Number,
        default: 20
      }
    },
    computed: {
      // è¿™é‡Œcomputed的变量,都是子组件tn-checkbox需要用到的,由于头条小程序的兼容性差异,子组件无法实时监听父组件参数的变化
      // æ‰€ä»¥éœ€è¦æ‰‹åŠ¨é€šçŸ¥å­ç»„ä»¶ï¼Œè¿™é‡Œè¿”å›žä¸€ä¸ªparentData变量,供watch监听,在其中去通知每一个子组件重新从父组件(tn-checkbox-group)
      // æ‹‰å–父组件新的变化后的参数
      parentData() {
        return [this.value, this.disabled, this.disabledLabel, this.shape, this.activeColor, this.size, this.width, this.wrap, this.iconSize]
      }
    },
    data() {
      return {
      }
    },
    watch: {
      // å½“父组件中的子组件需要共享的参数发生了变化,手动通知子组件
      parentData() {
        if (this.children.length) {
          this.children.map(child => {
            // åˆ¤æ–­å­ç»„ä»¶(tn-checkbox)如果有updateParentData方法的话,子组件重新从父组件拉取了最新的值
            typeof(child.updateParentData) === 'function' && child.updateParentData()
          })
        }
      }
    },
    created() {
      this.children = []
    },
    methods: {
      initValue(values) {
        this.$emit('input', values)
      },
      // è§¦å‘事件
      emitEvent() {
        let values = []
        this.children.map(child => {
          if (child.checkValue) values.push(child.name)
        })
        this.$emit('change', values)
        this.$emit('input', values)
        // å‘出事件,用于在表单组件中嵌入checkbox的情况,进行验证
        // ç”±äºŽå¤´æ¡å°ç¨‹åºæ‰§è¡Œè¿Ÿé’ï¼Œæ•…需要用几十毫秒的延时
        setTimeout(() => {
            // å°†å½“前的值发送到 tn-form-item è¿›è¡Œæ ¡éªŒ
            this.dispatch('tn-form-item', 'on-form-change', values)
        }, 60)
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-checkbox-group {
    /* #ifndef MP || APP-NVUE */
    display: inline-flex;
    flex-wrap: wrap;
    /* #endif */
    &::after {
      content: " ";
      display: table;
      clear: both;
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-checkbox/tn-checkbox.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,328 @@
<template>
  <view class="tn-checkbox-class tn-checkbox" :style="[checkboxStyle]">
    <view
      class="tn-checkbox__icon-wrap"
      :class="[iconClass]"
      :style="[iconStyle]"
      @tap="toggle"
    >
      <view class="tn-checkbox__icon-wrap__icon" :class="[`tn-icon-${iconName}`]"></view>
    </view>
    <view
      class="tn-checkbox__label"
      :class="[labelClass]"
      :style="{
        fontSize: labelSize ? labelSize + 'rpx' : ''
      }"
      @tap="onClickLabel"
    >
      <slot></slot>
    </view>
  </view>
</template>
<script>
  export default {
    name: 'tn-checkbox',
    props: {
      // checkbox名称
      name: {
        type: [String, Number],
        default: ''
      },
      // æ˜¯å¦ä¸ºé€‰ä¸­çŠ¶æ€
      value: {
        type: Boolean,
        default: false
      },
      // ç¦ç”¨é€‰æ‹©
      disabled: {
        type: Boolean,
        default: false
      },
      // ç¦ç”¨ç‚¹å‡»æ ‡ç­¾è¿›è¡Œé€‰æ‹©
      disabledLabel: {
        type: Boolean,
        default: false
      },
      // é€‰æ‹©æ¡†çš„形状 square æ–¹å½¢ circle åœ†å½¢
      shape: {
        type: String,
        default: ''
      },
      // é€‰ä¸­æ—¶çš„颜色
      activeColor: {
        type: String,
        default: ''
      },
      // ç»„件大小
      size: {
        type: Number,
        default: 0
      },
      // å›¾æ ‡åç§°
      iconName: {
        type: String,
        default: 'success'
      },
      // å›¾æ ‡å¤§å°
      iconSize: {
        type: Number,
        default: 0
      },
      // label的字体大小
      labelSize: {
        type: Number,
        default: 0
      }
    },
    computed: {
      // æ˜¯å¦ç¦ç”¨é€‰ä¸­ï¼Œçˆ¶ç»„件的禁用会覆盖当前的禁用状态
      isDisabled() {
        return this.disabled ? this.disabled : (this.parent ? this.parentData.disabled : false)
      },
      // æ˜¯å¦ç¦ç”¨ç‚¹å‡»label选中,父组件的禁用会覆盖当前的禁用状态
      isDisabledLabel() {
        return this.disabledLabel ? this.disabledLabel : (this.parent ? this.parentData.disabledLabel : false)
      },
      // å°ºå¯¸
      checkboxSize() {
        return this.size ? this.size : (this.parent ? this.parentData.size : 34)
      },
      // æ¿€æ´»æ—¶çš„颜色
      elAvtiveColor() {
        return this.activeColor ? this.activeColor : (this.parent ? this.parentData.activeColor : '#01BEFF')
      },
      // å½¢çж
      elShape() {
        return this.shape ? this.shape : (this.parent ? this.parentData.shape : 'square')
      },
      iconClass() {
        let clazz = ''
        clazz += (' tn-checkbox__icon-wrap--' + this.elShape)
        if (this.checkValue) clazz += ' tn-checkbox__icon-wrap--checked'
        if (this.isDisabled) clazz += ' tn-checkbox__icon-wrap--disabled'
        if (this.value && this.isDisabled) clazz += ' tn-checkbox__icon-wrap--disabled--checked'
        return clazz
      },
      iconStyle() {
        let style = {}
        // åˆ¤æ–­æ˜¯å¦ç”¨æˆ·æ‰‹åŠ¨ç¦ç”¨å’Œä¼ é€’çš„å€¼
        if (this.elAvtiveColor && this.checkValue && !this.isDisabled) {
          style.borderColor = this.elAvtiveColor
          style.backgroundColor = this.elAvtiveColor
        }
        // checkbox内部的勾选图标,如果选中状态,为白色,否则为透明色即可
        style.color = this.checkValue ? '#FFFFFF' : 'transparent'
        style.width = this.checkboxSize + 'rpx'
        style.height = style.width
        style.fontSize = (this.iconSize ? this.iconSize : (this.parent ? this.parentData.iconSize : 20)) + 'rpx'
        return style
      },
      checkboxStyle() {
        let style = {}
        if (this.parent && this.parentData.width) {
          // #ifdef MP
          // å„家小程序因为它们特殊的编译结构,使用float布局
          style.float = 'left';
          // #endif
          // #ifndef MP
          // H5和APP使用flex布局
          style.flex = `0 0 ${this.parentData.width}`;
          // #endif
        }
        if(this.parent && this.parentData.wrap) {
            style.width = '100%';
            // #ifndef MP
            // H5和APP使用flex布局,将宽度设置100%,即可自动换行
            style.flex = '0 0 100%';
            // #endif
        }
        return style
      },
      labelClass() {
        let clazz = ''
        if (this.isDisabled) {
          clazz += ' tn-checkbox__label--disabled'
        }
        return clazz
      }
    },
    data() {
      return {
        // å½“前checkbox的value值
        checkValue: false,
        parentData: {
          value: null,
          max: null,
          disabled: null,
          disabledLabel: null,
          shape: null,
          activeColor: null,
          size: null,
          width: null,
          wrap: null,
          iconSize: null
        }
      }
    },
    watch: {
      value(val) {
        this.checkValue = val
      }
    },
    created() {
      // æ”¯ä»˜å®å°ç¨‹åºä¸æ”¯æŒprovide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环应用
      // this.parent = this.$t.$parent.call(this, 'tn-checkbox-group')
      // // å¦‚果存在u-checkbox-group,将本组件的this塞进父组件的children中
      // this.parent && this.parent.children.push(this)
      // // åˆå§‹åŒ–父组件的value值
      // this.parent && this.parent.emitEvent()
      this.updateParentData()
      this.parent && this.parent.children.push(this)
    },
    methods: {
      updateCheckValue() {
        // æ›´æ–°å½“前checkbox的选中状态
        this.checkValue = (this.parent && this.parentData.value.includes(this.name)) || this.value === true
        if (this.parent) {
          if (this.value && !this.parentData.value.includes(this.name)) {
            this.parentData.value.push(this.name)
            this.parent.initValue(this.parentData.value)
          }
        }
      },
      updateParentData() {
        this.getParentData('tn-checkbox-group')
        this.updateCheckValue()
      },
      onClickLabel() {
        if (!this.isDisabled && !this.isDisabledLabel) {
          this.setValue()
        }
      },
      toggle() {
        if (!this.isDisabled) {
          this.setValue()
        }
      },
      emitEvent() {
        this.$emit('change', {
          name: this.name,
          value: !this.checkValue
        })
        if (this.parent) {
          this.checkValue = !this.checkValue
          // æ‰§è¡Œçˆ¶ç»„ä»¶tn-checkbox-group的事件方法
          // ç­‰å¾…下一个周期再执行,因为this.$emit('input')作用于父组件,再反馈到子组件内部,需要时间
          setTimeout(() => {
            if(this.parent.emitEvent) this.parent.emitEvent();
          }, 80)
        }
      },
      // è®¾ç½®input的值,通过v-modal绑定组件的值
      setValue() {
        // åˆ¤æ–­æ˜¯å¦ä¸ºå¯é€‰é¡¹ç»„
        if (this.parent) {
          // åè½¬çŠ¶æ€
          if (this.checkValue === true) {
            this.emitEvent()
            // this.$emit('input', !this.checkValue)
          } else {
            // è¶…出最大可选项,弹出提示
            if (this.parentData.value.length >= this.parentData.max) {
              return this.$t.message.toast(`最多可选${this.parent.max}项`)
            }
            // å¦‚果原来为未选中状态,需要选中的数量少于父组件中设置的max值,才可以选中
            this.emitEvent();
            // this.$emit('input', !this.checkValue);
          }
        } else {
          // åªæœ‰ä¸€ä¸ªå¯é€‰é¡¹
          this.emitEvent()
          this.$emit('input', !this.checkValue)
        }
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-checkbox {
    /* #ifndef APP-NVUE */
    display: inline-flex;
    /* #endif */
    align-items: center;
    overflow: hidden;
    user-select: none;
    line-height: 1.8;
    &__icon-wrap {
      color: $tn-font-color;
      flex: none;
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;
      box-sizing: border-box;
      width: 42rpx;
      height: 42rpx;
      color: transparent;
      text-align: center;
      transition-property: color, border-color, background-color;
      border: 1px solid $tn-font-sub-color;
      transition-duration: 0.2s;
      /* #ifdef MP-TOUTIAO */
      // å¤´æ¡å°ç¨‹åºå…¼å®¹æ€§é—®é¢˜ï¼Œéœ€è¦è®¾ç½®è¡Œé«˜ä¸º0,否则图标偏下
      &__icon {
          line-height: 0;
      }
      /* #endif */
      &--circle {
        border-radius: 100%;
      }
      &--square {
        border-radius: 6rpx;
      }
      &--checked {
        color: #FFFFFF;
        background-color: $tn-main-color;
        border-color: $tn-main-color;
      }
      &--disabled {
        background-color: $tn-font-holder-color;
        border-color: $tn-font-sub-color;
      }
      &--disabled--checked {
        color: $tn-font-sub-color !important;
      }
    }
    &__label {
      word-wrap: break-word;
      margin-left: 10rpx;
      margin-right: 24rpx;
      color: $tn-font-color;
      font-size: 30rpx;
      &--disabled {
        color: $tn-font-sub-color;
      }
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-circle-progress/tn-circle-progress.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,223 @@
<template>
  <view
    class="tn-circle-progress-class tn-circle-progress"
    :style="{
      width: widthPx + 'px',
      height: widthPx + 'px'
    }"
  >
    <!-- æ”¯ä»˜å®å°ç¨‹åºä¸æ”¯æŒcanvas-id属性,必须用id属性 -->
    <!-- é»˜è®¤åœ†çޝ -->
    <canvas
      class="tn-circle-progress__canvas-bg"
      :canvas-id="elBgId"
      :id="elBgId"
      :style="{
        width: widthPx + 'px',
        height: widthPx + 'px'
      }"
    ></canvas>
    <!-- è¿›åº¦åœ†çޝ -->
    <canvas
      class="tn-circle-progress__canvas"
      :canvas-id="elId"
      :id="elId"
      :style="{
        width: widthPx + 'px',
        height: widthPx + 'px'
      }"
    ></canvas>
    <view class="tn-circle-progress__content">
      <slot v-if="$slots.default || $slots.$default"></slot>
      <view v-else-if="showPercent" class="tn-circle-progress__content__percent">{{ percent + '%' }}</view>
    </view>
  </view>
</template>
<script>
  export default {
    name: 'tn-circle-progress',
    props: {
      // è¿›åº¦ï¼ˆç™¾åˆ†æ¯”)
      percent: {
        type: Number,
        default: 0,
        validator: val => {
          return val >= 0 && val <= 100
        }
      },
      // åœ†çŽ¯çº¿å®½
      borderWidth: {
        type: Number,
        default: 14
      },
      // æ•´ä½“圆的宽度
      width: {
        type: Number,
        default: 200
      },
      // æ˜¯å¦æ˜¾ç¤ºæ¡çº¹
      striped: {
        type: Boolean,
        default: false
      },
      // æ¡çº¹æ˜¯å¦è¿åЍ
      stripedActive: {
        type: Boolean,
        default: true
      },
      // æ¿€æ´»éƒ¨åˆ†é¢œè‰²
      activeColor: {
        type: String,
        default: '#01BEFF'
      },
      // éžæ¿€æ´»éƒ¨åˆ†é¢œè‰²
      inactiveColor: {
        type: String,
        default: '#f0f0f0'
      },
      // æ˜¯å¦æ˜¾ç¤ºè¿›åº¦æ¡å†…部百分比值
      showPercent: {
        type: Boolean,
        default: false
      },
      // åœ†çŽ¯æ‰§è¡ŒåŠ¨ç”»çš„æ—¶é—´ï¼Œms
      duration: {
        type: Number,
        default: 1500
      }
    },
    data() {
      return {
        // å¾®ä¿¡å°ç¨‹åºä¸­ä¸èƒ½ä½¿ç”¨this.$t.uuid()形式动态生成id值,否则会报错
        // #ifdef MP-WEIXIN
        elBgId: 'tCircleProgressBgId',
        elId: 'tCircleProgressElId',
        // #endif
        // #ifndef MP-WEIXIN
        elBgId: this.$t.uuid(),
        elId: this.$t.uuid(),
        // #endif
        // æ´»åŠ¨åœ†ä¸Šä¸‹æ–‡
        progressContext: null,
        // è½¬æ¢æˆpx为单位的背景宽度
        widthPx: uni.upx2px(this.width || 200),
        // è½¬æ¢æˆpx为单位的圆环宽度
        borderWidthPx: uni.upx2px(this.borderWidth || 14),
        // canvas画圆的起始角度,默认为-90度,顺时针
        startAngle: -90 * Math.PI / 180,
        // åŠ¨æ€ä¿®æ”¹è¿›åº¦å€¼çš„æ—¶å€™ï¼Œä¿å­˜è¿›åº¦å€¼çš„å˜åŒ–å‰åŽå€¼
        newPercent: 0,
        oldPercent: 0
      }
    },
    watch: {
      percent(newVal, oldVal = 0) {
        if (newVal > 100) newVal = 100
        if (oldVal < 0) oldVal = 0
        this.newPercent = newVal
        this.oldPercent = oldVal
        setTimeout(() => {
            // æ— è®ºæ˜¯ç™¾åˆ†æ¯”值增加还是减少,需要操作还是原来的旧的百分比值
            // å°†æ­¤å€¼å‡å°‘或者新增到新的百分比值
            this.drawCircleByProgress(oldVal)
        }, 50)
      }
    },
    created() {
      // èµ‹å€¼ï¼Œç”¨äºŽåŠ è½½åŽç¬¬ä¸€ä¸ªç”»åœ†ä½¿ç”¨
      this.newPercent = this.percent;
      this.oldPercent = 0;
    },
    mounted() {
      setTimeout(() => {
          this.drawProgressBg()
          this.drawCircleByProgress(this.oldPercent)
      }, 50)
    },
    methods: {
      // ç»˜åˆ¶è¿›åº¦æ¡èƒŒæ™¯
      drawProgressBg() {
        let ctx = uni.createCanvasContext(this.elBgId, this)
        // è®¾ç½®çº¿å®½
        ctx.setLineWidth(this.borderWidthPx)
        // è®¾ç½®é¢œè‰²
        ctx.setStrokeStyle(this.inactiveColor)
        ctx.beginPath()
        let radius = this.widthPx / 2
        ctx.arc(radius, radius, radius - this.borderWidthPx, 0, 360 * Math.PI / 180, false)
        ctx.stroke()
        ctx.draw()
      },
      // ç»˜åˆ¶åœ†å¼§çš„进度
      drawCircleByProgress(progress) {
        // å¦‚果已经存在则拿来使用
        let ctx = this.progressContext
        if (!ctx) {
          ctx =uni.createCanvasContext(this.elId, this)
          this.progressContext = ctx
        }
        ctx.setLineCap('round')
        // è®¾ç½®çº¿æ¡å®½åº¦å’Œé¢œè‰²
        ctx.setLineWidth(this.borderWidthPx)
        ctx.setStrokeStyle(this.activeColor)
        // å°†æ€»è¿‡æ¸¡æ—¶é—´é™¤ä»¥100,得出每修改百分之一进度所需的时间
        let preSecondTime = Math.floor(this.duration / 100)
        // ç»“束角的计算依据为:将2π分为100份,乘以当前的进度值,得出终止点的弧度值,加起始角,为整个圆从默认的
        let endAngle = ((360 * Math.PI / 180) / 100) * progress + this.startAngle
        let radius = this.widthPx / 2
        ctx.beginPath()
        ctx.arc(radius, radius, radius - this.borderWidthPx, this.startAngle, endAngle, false)
        ctx.stroke()
        ctx.draw()
        // å¦‚果变更后新值大于旧值,意味着增大了百分比
        if (this.newPercent > this.oldPercent) {
          // æ¯æ¬¡é€’增百分之一
          progress++
          // å¦‚果新增后的值,大于需要设置的值百分比值,停止继续增加
          if (progress > this.newPercent) return
        } else {
          progress--
          if (progress < this.newPercent) return
        }
        setTimeout(() => {
          // å®šæ—¶å™¨ï¼Œæ¯æ¬¡æ“ä½œé—´éš”为time值,为了让进度条有动画效果
          this.drawCircleByProgress(progress)
        }, preSecondTime)
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-circle-progress {
    position: relative;
    /* #ifndef APP-NVUE */
    display: inline-flex;
    /* #endif */
    align-items: center;
    justify-content: center;
    background-color: transparent;
    &__canvas {
      position: absolute;
      &-bg {
        position: absolute;
      }
    }
    &__content {
      display: flex;
      align-items: center;
      justify-content: center;
      &__percent {
        font-size: 28rpx;
      }
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-collapse-item/tn-collapse-item.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,236 @@
<template>
  <view class="tn-collapse-item-class tn-collapse-item" :style="[itemStyle]">
    <!-- å¤´éƒ¨ -->
    <view
      class="tn-collapse-item__head"
      :style="[headStyle]"
      :hover-stay-time="200"
      :hover-class="hoverClass"
      @tap.stop="headClick"
    >
      <block v-if="!$slots['title-all'] || !$slots['$title-all']">
        <view
          v-if="!$slots.title || !$slots.$title"
          class="tn-collapse-item__head__title tn-text-ellipsis"
          :style="[
            { textAlign: align ? align : 'left'},
            isShow && activeStyle && !arrow ? activeStyle : ''
          ]"
        >{{ title }}</view>
        <view v-else>
          <slot name="title"></slot>
        </view>
        <view class="tn-collapse-item__head__icon__wrap">
          <view
            v-if="arrow"
            class="tn-icon-down tn-collapse-item__head__icon__arrow"
            :class="{'tn-collapse-item__head__icon__arrow--active': isShow}"
            :style="[arrowIconStyle]"
          ></view>
        </view>
      </block>
      <view v-else>
        <slot name="title-all"></slot>
      </view>
    </view>
    <!-- å†…容 -->
    <view
      class="tn-collapse-item__body"
      :style="[{
        height: isShow ? height + 'px' : '0'
      }]"
    >
      <view class="tn-collapse-item__body__content" :id="elId" :style="[bodyStyle]">
        <slot></slot>
      </view>
    </view>
  </view>
</template>
<script>
  export default {
    name: 'tn-collapse-item',
    props: {
      // å±•å¼€
      open: {
        type: Boolean,
        default: false
      },
      // å”¯ä¸€æ ‡è¯†
      name: {
        type: String,
        default: ''
      },
      // æ ‡é¢˜
      title: {
        type: String,
        default: ''
      },
      // æ ‡é¢˜å¯¹é½æ–¹å¼
      align: {
        type: String,
        default: 'left'
      },
      // ç‚¹å‡»ä¸æ”¶èµ·
      disabled: {
        type: Boolean,
        default: false
      },
      // æ´»åŠ¨æ—¶æ ·å¼
      activeStyle: {
        type: Object,
        default() {
          return {}
        }
      },
      // æ ‡è¯†
      index: {
        type: [Number, String],
        default: ''
      }
    },
    computed: {
      arrowIconStyle() {
        let style = {}
        if (this.arrowColor) {
          style.color = this.arrowColor
        }
        return style
      }
    },
    data() {
      return {
        isShow: false,
        elId: this.$t.uuid(),
        // body高度
        height: 0,
        // å¤´éƒ¨æ ·å¼
        headStyle: {},
        // ä¸»ä½“样式
        bodyStyle: {},
        // item样式
        itemStyle: {},
        // æ˜¾ç¤ºå³è¾¹ç®­å¤´
        arrow: true,
        // ç®­å¤´é¢œè‰²
        arrowColor: '',
        // ç‚¹å‡»å¤´éƒ¨æ—¶çš„æ•ˆæžœæ ·å¼
        hoverClass: ''
      }
    },
    watch: {
      open(value) {
        this.isShow = value
      }
    },
    created() {
      this.parent = false
      this.isShow = this.open
    },
    mounted() {
      this.init()
    },
    methods: {
      // å¼‚步获取内容或者修改了内容时重新获取内容的信息
      init() {
        this.parent = this.$t.$parent.call(this, 'tn-collapse')
        if (this.parent) {
          this.nameSync = this.name ? this.name : this.parent.childrens.length
          // ä¸å­˜åœ¨æ‰æ·»åŠ å¯¹åº”å®žä¾‹
          !this.parent.childrens.includes(this) && this.parent.childrens.push(this)
          this.headStyle = this.parent.headStyle
          this.bodyStyle = this.parent.bodyStyle
          this.itemStyle = this.parent.itemStyle
          this.arrow = this.parent.arrow
          this.arrowColor = this.parent.arrowColor
          this.hoverClass = this.parent.hoverClass
        }
        this.$nextTick(() => {
          this.queryRect()
        })
      },
      // ç‚¹å‡»å¤´éƒ¨
      headClick() {
        if (this.disabled) return
        if (this.parent && this.parent.accordion) {
          this.parent.childrens.map(child => {
            // å¦‚果是手风琴模式,将其他的item关闭
            if (this !== child) {
              child.isShow = false
            }
          })
        }
        this.isShow = !this.isShow
        // è§¦å‘修改事件
        this.$emit('change', {
          index: this.index,
          show: this.isShow
        })
        // åªæœ‰åœ¨æ‰“开时才触发父元素的change
        if (this.isShow) this.parent && this.parent.onChange()
        this.$forceUpdate()
      },
      // æŸ¥è¯¢å†…容高度
      queryRect() {
        this._tGetRect('#'+this.elId).then(res => {
          this.height = res.height
        })
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-collapse-item {
    &__head {
      position: relative;
      display: flex;
      flex-direction: row;
      justify-content: space-around;
      align-items: center;
      color: $tn-font-color;
      font-size: 30rpx;
      line-height: 1;
      padding: 24rpx 0;
      padding-left: 24rpx;
      text-align: left;
      background-color: #FFFFFF;
      &__title {
        flex: 1;
        overflow: hidden;
      }
      &__icon {
        &__arrow {
          transition: all 0.3s;
          margin-right: 20rpx;
          margin-left: 14rpx;
          font-size: inherit;
          &--active {
            transform: rotate(180deg);
            transform-origin: center center;
          }
        }
      }
    }
    &__body {
      transition: all 0.3s;
      overflow: hidden;
      &__content {
        overflow: hidden;
        font-size: 28rpx;
        color: $tn-font-color;
        text-align: left;
        background-color: #FFFFFF;
        padding-left: 24rpx;
      }
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-collapse/tn-collapse.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,98 @@
<template>
  <view class="tn-collapse-class tn-collapse">
    <slot></slot>
  </view>
</template>
<script>
  export default {
    name: 'tn-collapse',
    props: {
      // æ˜¯å¦ä¸ºæ‰‹é£Žç´
      accordion: {
        type: Boolean,
        default: true
      },
      // å¤´éƒ¨æ ·å¼
      headStyle: {
        type: Object,
        default() {
          return {}
        }
      },
      // ä¸»é¢˜æ ·å¼
      bodyStyle: {
        type: Object,
        default() {
          return {}
        }
      },
      // æ¯ä¸€ä¸ªitem的样式
      itemStyle: {
        type: Object,
        default() {
          return {}
        }
      },
      // æ˜¾ç¤ºç®­å¤´
      arrow: {
        type: Boolean,
        default: true
      },
      // ç®­å¤´é¢œè‰²
      arrowColor: {
        type: String,
        default: '#AAAAAA'
      },
      // ç‚¹å‡»æ ‡é¢˜æ æ—¶çš„æŒ‰åŽ‹æ ·å¼
      hoverClass: {
        type: String,
        default: 'tn-hover'
      }
    },
    computed: {
      parentData() {
        return [this.headStyle, this.bodyStyle, this.itemStyle, this.arrow, this.arrowColor, this.hoverClass]
      }
    },
    data() {
      return {
      }
    },
    watch: {
      parentData() {
        // å¦‚果父组件的参数发生变化重新初始化子组件的信息
        if (this.childrens.length > 0) {
          this.init()
        }
      }
    },
    created() {
      this.childrens = []
    },
    methods: {
      // é‡æ–°åˆå§‹åŒ–内部所有子元素计算高度,异步获取数据时重新渲染
      init() {
        this.childrens.forEach((child, index) => {
          child.init()
        })
      },
      // collapseItem被点击时由collapseItem调用父组件
      onChange() {
        let activeItem = []
        this.childrens.forEach((child, index) => {
          if (child.isShow) {
            activeItem.push(child.nameSync)
          }
        })
        // å¦‚果时手风琴模式,只有一个匹配结果,即activeItem长度为1
        if (this.accordion) activeItem = activeItem.join(',')
        this.$emit('change', activeItem)
      }
    }
  }
</script>
<style lang="scss" scoped>
</style>
¼ª°²PDA/tuniao-ui/components/tn-color-icon/tn-color-icon.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,318 @@
<template>
  <text
    class="tn-color-icon-class tn-color-icon"
    :class="[
      'tn-color-icon-' + name
    ]"
    :style="{
      fontSize: size + unit,
      margin: margin
    }"
    @tap="handleClick"
  ></text>
</template>
<script>
  export default {
    name: 'tn-color-icon',
    props: {
      // ç´¢å¼•
      index: {
        type: [Number, String],
        default: '0'
      },
      // å›¾æ ‡åç§°
      name: {
        type: String,
        default: ''
      },
      // å›¾æ ‡å¤§å°
      size: {
        type: Number,
        default:32
      },
      // å¤§å°å•位
      unit: {
        type: String,
        default: 'px'
      },
      // å¤–边距
      margin: {
        type: String,
        default: '0'
      }
    },
    computed: {
    },
    data() {
      return {
      }
    },
    methods: {
      // å¤„理点击事件
      handleClick() {
        this.$emit("click", {
          index: Number(this.index)
        })
        this.$emit("tap", {
          index: Number(this.index)
        })
      }
    }
  }
</script>
<style scoped>
  @charset "UTF-8";
  @font-face {
    font-family: "tuniaoColorFont"; /* Project id 2445412 */
    /* Color fonts */
    src: url('iconfont.woff2?t=1632654518618') format('woff2');
  }
  .tn-color-icon {
    font-family: "tuniaoColorFont" !important;
    font-size: 16px;
    font-style: normal;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    text-decoration: none;
  }
  .tn-color-icon-logo-github:before {
    content: "\e601";
  }
  .tn-color-icon-logo-qq:before {
    content: "\e602";
  }
  .tn-color-icon-logo-weixin:before {
    content: "\e603";
  }
  .tn-color-icon-logo-alipay:before {
    content: "\e604";
  }
  .tn-color-icon-logo-weibo:before {
    content: "\e605";
  }
  .tn-color-icon-logo-dingtalk:before {
    content: "\e606";
  }
  .tn-color-icon-safe:before {
    content: "\e607";
  }
  .tn-color-icon-wifi:before {
    content: "\e608";
  }
  .tn-color-icon-help:before {
    content: "\e609";
  }
  .tn-color-icon-tag:before {
    content: "\e60a";
  }
  .tn-color-icon-play:before {
    content: "\e60b";
  }
  .tn-color-icon-stopwatch:before {
    content: "\e60c";
  }
  .tn-color-icon-home:before {
    content: "\e60d";
  }
  .tn-color-icon-map:before {
    content: "\e60e";
  }
  .tn-color-icon-book:before {
    content: "\e60f";
  }
  .tn-color-icon-qrcode:before {
    content: "\e610";
  }
  .tn-color-icon-discover:before {
    content: "\e611";
  }
  .tn-color-icon-visitor:before {
    content: "\e612";
  }
  .tn-color-icon-menu:before {
    content: "\e613";
  }
  .tn-color-icon-renew:before {
    content: "\e614";
  }
  .tn-color-icon-business:before {
    content: "\e615";
  }
  .tn-color-icon-telephone:before {
    content: "\e616";
  }
  .tn-color-icon-medicine:before {
    content: "\e617";
  }
  .tn-color-icon-chicken:before {
    content: "\e618";
  }
  .tn-color-icon-clock:before {
    content: "\e619";
  }
  .tn-color-icon-download:before {
    content: "\e61a";
  }
  .tn-color-icon-lamp:before {
    content: "\e61b";
  }
  .tn-color-icon-hourglass:before {
    content: "\e61c";
  }
  .tn-color-icon-calendar:before {
    content: "\e61d";
  }
  .tn-color-icon-bluetooth:before {
    content: "\e61e";
  }
  .tn-color-icon-fish:before {
    content: "\e61f";
  }
  .tn-color-icon-seal:before {
    content: "\e620";
  }
  .tn-color-icon-remind:before {
    content: "\e621";
  }
  .tn-color-icon-music:before {
    content: "\e622";
  }
  .tn-color-icon-email:before {
    content: "\e623";
  }
  .tn-color-icon-medal:before {
    content: "\e624";
  }
  .tn-color-icon-image:before {
    content: "\e625";
  }
  .tn-color-icon-network:before {
    content: "\e626";
  }
  .tn-color-icon-wallet:before {
    content: "\e627";
  }
  .tn-color-icon-program:before {
    content: "\e628";
  }
  .tn-color-icon-shrimp:before {
    content: "\e629";
  }
  .tn-color-icon-collect:before {
    content: "\e62a";
  }
  .tn-color-icon-screw:before {
    content: "\e62b";
  }
  .tn-color-icon-set:before {
    content: "\e62c";
  }
  .tn-color-icon-userfavorite:before {
    content: "\e62d";
  }
  .tn-color-icon-useradd:before {
    content: "\e62e";
  }
  .tn-color-icon-honor:before {
    content: "\e62f";
  }
  .tn-color-icon-shop:before {
    content: "\e630";
  }
  .tn-color-icon-usercard:before {
    content: "\e631";
  }
  .tn-color-icon-school:before {
    content: "\e632";
  }
  .tn-color-icon-user:before {
    content: "\e633";
  }
  .tn-color-icon-internet:before {
    content: "\e634";
  }
  .tn-color-icon-time:before {
    content: "\e635";
  }
  .tn-color-icon-topic:before {
    content: "\e636";
  }
  .tn-color-icon-phone:before {
    content: "\e637";
  }
  .tn-color-icon-usertable:before {
    content: "\e638";
  }
  .tn-color-icon-userset:before {
    content: "\e639";
  }
  .tn-color-icon-game:before {
    content: "\e63a";
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-column-notice/tn-column-notice.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,251 @@
<template>
  <view
    class="tn-column-notice-class tn-column-notice"
    :class="[backgroundColorClass]"
    :style="[noticeStyle]"
  >
    <!-- å·¦å›¾æ ‡ -->
    <view class="tn-column-notice__icon">
      <view
        v-if="leftIcon"
        class="tn-column-notice__icon--left"
        :class="[`tn-icon-${leftIconName}`,fontColorClass]"
        :style="[fontStyle('leftIcon')]"
        @tap="clickLeftIcon"></view>
    </view>
    <!-- æ»šåŠ¨æ˜¾ç¤ºå†…å®¹ -->
    <swiper class="tn-column-notice__swiper" :style="[swiperStyle]" :vertical="vertical" circular :autoplay="autoplay && playStatus === 'play'" :interval="duration" @change="change">
      <swiper-item v-for="(item, index) in list" :key="index" class="tn-column-notice__swiper--item">
        <view
          class="tn-column-notice__swiper--content tn-text-ellipsis"
          :class="[fontColorClass]"
          :style="[fontStyle()]"
          @tap="click(index)"
        >{{ item }}</view>
      </swiper-item>
    </swiper>
    <!-- å³å›¾æ ‡ -->
    <view class="tn-column-notice__icon">
      <view
        v-if="rightIcon"
        class="tn-column-notice__icon--right"
        :class="[`tn-icon-${rightIconName}`,fontColorClass]"
        :style="[fontStyle('rightIcon')]"
        @tap="clickRightIcon"></view>
      <view
        v-if="closeBtn"
        class="tn-column-notice__icon--right"
        :class="[`tn-icon-close`,fontColorClass]"
        :style="[fontStyle('close')]"
        @tap="close"></view>
    </view>
  </view>
</template>
<script>
  import componentsColorMixin from '../../libs/mixin/components_color.js'
  export default {
    name: 'tn-column-notice',
    mixins: [componentsColorMixin],
    props: {
      // æ˜¾ç¤ºçš„内容
      list: {
        type: Array,
        default() {
          return []
        }
      },
      // æ˜¯å¦æ˜¾ç¤º
      show: {
        type: Boolean,
        default: true
      },
      // æ’­æ”¾çŠ¶æ€
      // play -> æ’­æ”¾ paused -> æš‚停
      playStatus: {
        type: String,
        default: 'play'
      },
      // æ»šåŠ¨æ–¹å‘
      // horizontal -> æ°´å¹³æ»šåЍ vertical -> åž‚直滚动
      mode: {
        type: String,
        default: 'horizontal'
      },
      // æ˜¯å¦æ˜¾ç¤ºå·¦è¾¹å›¾æ ‡
      leftIcon: {
        type: Boolean,
        default: true
      },
      // å·¦è¾¹å›¾æ ‡çš„名称
      leftIconName: {
        type: String,
        default: 'sound'
      },
      // å·¦è¾¹å›¾æ ‡çš„大小
      leftIconSize: {
        type: Number,
        default: 34
      },
      // æ˜¯å¦æ˜¾ç¤ºå³è¾¹çš„图标
      rightIcon: {
        type: Boolean,
        default: false
      },
      // å³è¾¹å›¾æ ‡çš„名称
      rightIconName: {
        type: String,
        default: 'right'
      },
      // å³è¾¹å›¾æ ‡çš„大小
      rightIconSize: {
        type: Number,
        default: 26
      },
      // æ˜¯å¦æ˜¾ç¤ºå…³é—­æŒ‰é’®
      closeBtn: {
        type: Boolean,
        default: false
      },
      // åœ†è§’
      radius: {
        type: Number,
        default: 0
      },
      // å†…边距
      padding: {
        type: String,
        default: '18rpx 24rpx'
      },
      // è‡ªåŠ¨æ’­æ”¾
      autoplay: {
        type: Boolean,
        default: true
      },
      // æ»šåŠ¨å‘¨æœŸ
      duration: {
        type: Number,
        default: 2000
      }
    },
    computed: {
      fontStyle() {
        return (type) => {
          let style = {}
          style.color = this.fontColorStyle ? this.fontColorStyle : ''
          style.fontSize = this.fontSizeStyle ? this.fontSizeStyle : ''
          if (type === 'leftIcon' && this.leftIconSize) {
            style.fontSize = this.leftIconSize + 'rpx'
          }
          if (type === 'rightIcon' && this.rightIconSize) {
            style.fontSize = this.rightIconSize + 'rpx'
          }
          if (type === 'close') {
            style.fontSize = '24rpx'
          }
          return style
        }
      },
      noticeStyle() {
        let style = {}
        style.backgroundColor = this.backgroundColorStyle ? this.backgroundColorStyle : 'transparent'
        if (this.padding) style.padding = this.padding
        return style
      },
      swiperStyle() {
        let style = {}
        style.height = this.fontSize ? this.fontSize + 6 + this.fontUnit : '32rpx'
        style.lineHeight = style.height
        return style
      },
      // æ ‡è®°æ˜¯å¦ä¸ºåž‚ç›´
      vertical() {
        if (this.mode === 'horizontal') return false
        else return true
      }
    },
    data() {
      return {
      }
    },
    watch: {
    },
    methods: {
      // ç‚¹å‡»äº†é€šçŸ¥æ 
      click(index) {
        this.$emit('click', index)
      },
      // ç‚¹å‡»äº†å…³é—­æŒ‰é’®
      close() {
        this.$emit('close')
      },
      // ç‚¹å‡»äº†å·¦è¾¹å›¾æ ‡
      clickLeftIcon() {
        this.$emit('clickLeft')
      },
      // ç‚¹å‡»äº†å³è¾¹å›¾æ ‡
      clickRightIcon() {
        this.$emit('clickRight')
      },
      // åˆ‡æ¢æ¶ˆæ¯æ—¶é—´
      change(event) {
        let index = event.detail.current
        if (index === this.list.length - 1) {
          this.$emit('end')
        }
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-column-notice {
    width: 100%;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    flex-wrap: nowrap;
    overflow: hidden;
    &__swiper {
      height: auto;
      flex: 1;
      display: flex;
      flex-direction: row;
      align-items: center;
      margin-left: 12rpx;
      &--item {
        display: flex;
        flex-direction: row;
        align-items: center;
        overflow: hidden;
      }
      &--content {
        overflow: hidden;
      }
    }
    &__icon {
      &--left {
        display: inline-flex;
        align-items: center;
      }
      &--right {
        margin-left: 12rpx;
        display: inline-flex;
        align-items: center;
      }
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-count-down/tn-count-down.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,314 @@
<template>
  <view class="tn-countdown-class tn-countdown">
    <view
      v-if="showDays && (hideZeroDay || (!hideZeroDay && d != '00'))"
      class="tn-countdown__item"
      :class="[backgroundColorClass]"
      :style="[itemStyle]"
    >
      <view class="tn-countdown__item__time" :class="[fontColorClass]" :style="[letterStyle]">
        {{ d }}
      </view>
    </view>
    <view
      v-if="showHours && (hideZeroDay || (!hideZeroDay && d != '00'))"
      class="tn-countdown__separator"
      :style="{
        fontSize: separatorSize + 'rpx',
        color: separatorColor,
        paddingBottom: separator === 'en' ? '4rpx' : 0
      }"
    >
      {{ separator === 'en' ? ':' : '天'}}
    </view>
    <view
      v-if="showHours"
      class="tn-countdown__item"
      :class="[backgroundColorClass]"
      :style="[itemStyle]"
    >
      <view class="tn-countdown__item__time" :class="[fontColorClass]" :style="[letterStyle]">
        {{ h }}
      </view>
    </view>
    <view
      v-if="showMinutes"
      class="tn-countdown__separator"
      :style="{
        fontSize: separatorSize + 'rpx',
        color: separatorColor,
        paddingBottom: separator === 'en' ? '4rpx' : 0
      }"
    >
      {{ separator === 'en' ? ':' : '时'}}
    </view>
    <view
      v-if="showMinutes"
      class="tn-countdown__item"
      :class="[backgroundColorClass]"
      :style="[itemStyle]"
    >
      <view class="tn-countdown__item__time" :class="[fontColorClass]" :style="[letterStyle]">
        {{ m }}
      </view>
    </view>
    <view
      v-if="showSeconds"
      class="tn-countdown__separator"
      :style="{
        fontSize: separatorSize + 'rpx',
        color: separatorColor,
        paddingBottom: separator === 'en' ? '4rpx' : 0
      }"
    >
      {{ separator === 'en' ? ':' : '分'}}
    </view>
    <view
      v-if="showSeconds"
      class="tn-countdown__item"
      :class="[backgroundColorClass]"
      :style="[itemStyle]"
    >
      <view class="tn-countdown__item__time" :class="[fontColorClass]" :style="[letterStyle]">
        {{ s }}
      </view>
    </view>
    <view
      v-if="showSeconds && separator === 'cn'"
      class="tn-countdown__separator"
      :style="{
        fontSize: separatorSize + 'rpx',
        color: separatorColor,
        paddingBottom: separator === 'en' ? '4rpx' : 0
      }"
    >
      ç§’
    </view>
  </view>
</template>
<script>
  import componentsColorMixin from '../../libs/mixin/components_color.js'
  export default {
    name: 'tn-count-down',
    mixins: [componentsColorMixin],
    props: {
      // å€’计时时间,秒作为单位
      timestamp: {
        type: Number,
        default: 0
      },
      // æ˜¯å¦è‡ªåЍ开始
      autoplay: {
        type: Boolean,
        default: true
      },
      // æ•°å­—框高度
      height: {
        type: [String, Number],
        default: 'auto'
      },
      // åˆ†éš”符类型
      // en -> ä½¿ç”¨è‹±æ–‡çš„冒号 cn -> ä½¿ç”¨ä¸­æ–‡è¿›è¡Œåˆ†å‰²
      separator: {
        type: String,
        default: 'en'
      },
      // åˆ†å‰²ç¬¦å¤§å°
      separatorSize: {
        type: Number,
        default: 30
      },
      // åˆ†éš”符颜色
      separatorColor: {
        type: String,
        default: '#080808'
      },
      // æ˜¯å¦æ˜¾ç¤ºè¾¹æ¡†
      showBorder: {
        type: Boolean,
        default: false
      },
      // è¾¹æ¡†é¢œè‰²
      borderColor: {
        type: String,
        default: '#080808'
      },
      // æ˜¯å¦æ˜¾ç¤ºç§’
      showSeconds: {
        type: Boolean,
        default: true
      },
      // æ˜¯å¦æ˜¾ç¤ºåˆ†
      showMinutes: {
        type: Boolean,
        default: true
      },
      // æ˜¯å¦æ˜¾ç¤ºæ—¶
      showHours: {
        type: Boolean,
        default: true
      },
      // æ˜¯å¦æ˜¾ç¤ºå¤©
      showDays: {
        type: Boolean,
        default: true
      },
      // å¦‚果当天的部分为0时,是否隐藏不显示
      hideZeroDay: {
        type: Boolean,
        default: false
      }
    },
    computed: {
      // å€’计时item的样式
      itemStyle() {
        let style = {}
        if (this.height) {
          style.height = this.$t.string.getLengthUnitValue(this.height)
          style.width = style.height
        }
        if (this.showBorder) {
          style.borderStyle = 'solid'
          style.borderColor = this.borderColor
          style.borderWidth = '1rpx'
        }
        style.backgroundColor = this.backgroundColorStyle || '#FFFFFF'
        return style
      },
      // å€’计时数字样式
      letterStyle() {
        let style = {}
        style.fontSize = this.fontSizeStyle || '30rpx'
        style.color = this.fontColorStyle || '#080808'
        return style
      }
    },
    data() {
      return {
        d: '00',
        h: '00',
        m: '00',
        s: '00',
        // å®šæ—¶å™¨
        timer: null,
        // è®°å½•倒计过程中变化的秒数
        seconds: 0
      }
    },
    watch: {
      // ç›‘听时间戳变化
      timestamp(value) {
        this.clearTimer()
        this.start()
      }
    },
    mounted() {
      // å¦‚果时自动倒计时,加载完成开始计时
      this.autoplay && this.timestamp && this.start()
    },
    beforeDestroy() {
      this.clearTimer()
    },
    methods: {
      // å¼€å§‹å€’计时
      start() {
        // é¿å…å¯èƒ½å‡ºçŽ°çš„å€’è®¡æ—¶é‡å æƒ…å†µ
        this.clearTimer()
        if (this.timestamp <= 0) return
        this.seconds = Number(this.timestamp)
        this.formatTime(this.seconds)
        this.timer = setInterval(() => {
          this.seconds--
          // å‘出change事件
          this.$emit('change', this.seconds)
          if (this.seconds < 0) {
            return this.end()
          }
          this.formatTime(this.seconds)
        }, 1000)
      },
      // æ ¼å¼åŒ–æ—¶é—´
      formatTime(seconds) {
        // å°äºŽç­‰äºŽ0的话,结束倒计时
        seconds <= 0 && this.end()
        let [day, hour, minute, second] = [0, 0, 0, 0]
        day = Math.floor(seconds / (60 * 60 * 24))
        // å¦‚果不显示天,则将天对应的小时计入到小时中
        // å…ˆæŠŠå½“前的hour计算出来供分和秒使用
        hour = Math.floor(seconds / (60 * 60)) - (day * 24)
        let showHour = null
        if (this.showDays) {
          showHour = hour
        } else {
          // å°†å¤©æ•°å¯¹åº”的小时加入到时中进行显示
          showHour = Math.floor(seconds / (60 * 60))
        }
        minute = Math.floor(seconds / 60) - (hour * 60) - (day * 24 * 60)
        second = Math.floor(seconds) - (minute * 60) - (hour * 60 * 60) - (day * 24 * 60 * 60)
        // å¦‚果小于0在前面进行补0操作
        showHour = this.$t.number.formatNumberAddZero(showHour)
        minute = this.$t.number.formatNumberAddZero(minute)
        second = this.$t.number.formatNumberAddZero(second)
        day = this.$t.number.formatNumberAddZero(day)
        this.d = day
        this.h = showHour
        this.m = minute
        this.s = second
      },
      // å€’计时结束
      end() {
        this.clearTimer()
        this.$emit('end')
      },
      // æ¸…除倒计时
      clearTimer() {
        if (this.timer !== null) {
          clearInterval(this.timer)
          this.timer = null
        }
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-countdown {
    /* #ifndef APP-NVUE */
    display: inline-flex;
    /* #endif */
    align-items: center;
    &__item {
      box-sizing: content-box;
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;
      padding: 2rpx;
      border-radius: 6rpx;
      white-space: nowrap;
      transform: translateZ(0);
      &__time {
        margin: 0;
        padding: 0;
        line-height: 1;
      }
    }
    &__separator {
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;
      padding: 0 5rpx;
      line-height: 1;
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-count-scroll/tn-count-scroll.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,171 @@
<template>
  <view class="tn-count-scroll-class tn-count-scroll">
    <view
      v-for="(item, index) in columns"
      :key="index"
      class="tn-count-scroll__box"
      :style="{
        width: $t.string.getLengthUnitValue(width),
        height: heightPxValue + 'px'
      }"
    >
      <view
        class="tn-count-scroll__column"
        :style="{
          transform: `translate3d(0, -${keys[index] * heightPxValue}px, 0)`,
          transitionDuration: `${duration}s`
        }"
      >
        <view
          v-for="(value, value_index) in item"
          :key="value_index"
          class="tn-count-scroll__column__item"
          :class="[fontColorClass]"
          :style="{
            height: heightPxValue + 'px',
            lineHeight: heightPxValue + 'px',
            fontSize: fontSizeStyle || '32rpx',
            fontWeight: bold ? 'bold': 'normal',
            color: fontColorStyle || '#080808'
          }"
        >
          {{ value }}
        </view>
      </view>
    </view>
  </view>
</template>
<script>
  import componentsColorMixin from '../../libs/mixin/components_color.js'
  export default {
    name: 'tn-count-scroll',
    mixins: [componentsColorMixin],
    props: {
      value: {
        type: Number,
        default: 0
      },
      // è¡Œé«˜
      height: {
        type: Number,
        default: 32
      },
      // å•个字的宽度
      width: {
        type: [String, Number],
        default: 'auto'
      },
      // æ˜¯å¦åŠ ç²—
      bold: {
        type: Boolean,
        default: false
      },
      // æŒç»­æ—¶é—´
      duration: {
        type: Number,
        default: 1.2
      },
      // ååˆ†ä½åˆ†å‰²ç¬¦
      decimalSeparator: {
        type: String,
        default: '.'
      },
      // åƒåˆ†ä½åˆ†å‰²ç¬¦
      thousandthsSeparator: {
        type: String,
        default: ''
      }
    },
    computed: {
      heightPxValue() {
        return uni.upx2px(this.height || 0)
      }
    },
    data() {
      return {
        // æ¯åˆ—的数据
        columns: [],
        // æ¯åˆ—对应值所在的滚动位置
        keys: []
      }
    },
    watch: {
      value(val) {
        this.initColumn(val)
      }
    },
    created() {
      // ä¸ºäº†è¾¾åˆ°ä¸€è¿›å…¥å°±æœ‰æ»šåŠ¨æ•ˆæžœï¼Œå»¶è¿Ÿæ‰§è¡Œåˆå§‹åŒ–
      this.initColumn()
      setTimeout(() => {
        this.initColumn(this.value)
      }, 20)
    },
    methods: {
      // åˆå§‹åŒ–每一列的数据
      initColumn(val) {
        val = val + ''
        let digit = val.length,
            columnArray = [],
            rows = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
        for (let i = 0; i < digit; i++) {
          if (val[i] === this.decimalSeparator || val[i] === this.thousandthsSeparator) {
            columnArray.push(val[i])
          } else {
            columnArray.push(rows)
          }
        }
        this.columns = columnArray
        this.roll(val)
      },
      // æ»šåŠ¨å¤„ç†
      roll(value) {
        let valueArray = value.toString().split(''),
            lengths = this.columns.length,
            indexs = [];
        while (valueArray.length) {
          let figure = valueArray.pop()
          if (figure === this.decimalSeparator || figure === this.thousandthsSeparator) {
            indexs.unshift(0)
          } else {
            indexs.unshift(Number(figure))
          }
        }
        while(indexs.length < lengths) {
          indexs.unshift(0)
        }
        this.keys = indexs
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-count-scroll {
    display: inline-flex;
    align-items: center;
    justify-content: space-between;
    &__box {
      overflow: hidden;
    }
    &__column {
      transform: translate3d(0, 0, 0);
      display: flex;
      align-items: center;
      justify-content: center;
      flex-direction: column;
      transition-timing-function: cubic-bezier(0, 1, 0, 1);
      &__item {
        display: flex;
        align-items: center;
        justify-content: center;
      }
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-count-to/tn-count-to.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,231 @@
<template>
  <view
    class="tn-count-num-class tn-count-num"
    :class="[fontColorClass]"
    :style="{
      fontSize: fontSizeStyle || '50rpx',
      fontWeight: bold ? 'bold' : 'normal',
      color: fontColorStyle || '#080808'
    }"
  >
    {{ displayValue }}
  </view>
</template>
<script>
  import componentsColorMixin from '../../libs/mixin/components_color.js'
  export default {
    name: 'tn-count-to',
    mixins: [componentsColorMixin],
    props: {
      // å¼€å§‹çš„æ•°å€¼ï¼Œé»˜è®¤ä¸º0
      startVal: {
        type: Number,
        default: 0
      },
      // ç»“束目标数值
      endVal: {
        type: Number,
        default: 0,
        required: true
      },
      // æ˜¯å¦è‡ªåЍ开始
      autoplay: {
        type: Boolean,
        default: true
      },
      // æ»šåŠ¨åˆ°ç›®æ ‡å€¼çš„æŒç»­æ—¶é—´ï¼Œå•ä½ä¸ºæ¯«ç§’
      duration: {
        type: Number,
        default: 2000
      },
      // æ˜¯å¦åœ¨å³å°†ç»“束的时候使用缓慢滚动的效果
      useEasing: {
        type: Boolean,
        default: true
      },
      // æ˜¾ç¤ºçš„小数位数
      decimals: {
        type: Number,
        default: 0
      },
      // åè¿›åˆ¶çš„分割符
      decimalSeparator: {
        type: String,
        default: '.'
      },
      // åƒåˆ†ä½çš„分隔符
      // ç±»ä¼¼é‡‘额的分割(ï¿¥23,321.05中的",")
      thousandthsSeparator: {
        type: String,
        default: ''
      },
      // æ˜¯å¦æ˜¾ç¤ºåŠ ç²—å­—ä½“
      bold: {
        type: Boolean,
        default: false
      }
    },
    computed: {
      countDown() {
        return this.startVal > this.endVal
      }
    },
    data() {
      return {
        localStartVal: this.startVal,
        localDuration: this.duration,
        // æ˜¾ç¤ºçš„æ•°å€¼
        displayValue: this.formatNumber(this.startVal),
        // æ‰“印的数值
        printValue: null,
        // æ˜¯å¦æš‚停
        paused: false,
        // å¼€å§‹æ—¶é—´æˆ³
        startTime: null,
        // åœç•™æ—¶é—´æˆ³
        remainingTime: null,
        // å½“前时间戳
        timestamp: null,
        // ä¸Šä¸€æ¬¡çš„æ—¶é—´æˆ³
        lastTime: 0,
        rAF: null
      }
    },
    watch: {
      startVal() {
        this.autoplay && this.start()
      },
      endVal() {
        this.autoplay && this.start()
      }
    },
    mounted() {
      this.autoplay && this.start()
    },
    methods: {
      // å¼€å§‹æ»šåЍ
      start() {
        this.localStartVal = this.startVal
        this.startTime = null
        this.localDuration = this.duration
        this.paused = false
        this.rAF = this.requestAnimationFrame(this.count)
      },
      // é‡æ–°å¼€å§‹
      reStart() {
        if (this.paused) {
          this.resume()
          this.paused = false
        } else {
          this.stop()
          this.paused = true
        }
      },
      // åœæ­¢
      stop() {
        this.cancelAnimationFrame(this.rAF)
      },
      // æ¢å¤
      resume() {
        this.startTime = null
        this.localDuration = this.remainingTime
        this.localStartVal = this.printValue
        this.requestAnimationFrame(this.count)
      },
      // é‡ç½®
      reset() {
        this.startTime = null
        this.cnacelAnimationFrame(this.rAF)
        this.displayValue = this.formatNumber(this.startVal)
      },
      // é”€æ¯ç»„ä»¶
      destroyed() {
        this.cancelAnimationFrame(this.rAF)
      },
      // ç´¯åŠ æ—¶é—´
      count(timestamp) {
        if (!this.startTime) this.startTime = timestamp
        this.timestamp = timestamp
        const progress = timestamp - this.startTime
        this.remainingTime = this.localDuration - progress
        if (this.useEasing) {
          if (this.countDown) {
            this.printValue = this.localStartVal - this.easingFn(progress, 0, this.localStartVal - this.endVal, this.localDuration)
          } {
            this.printValue = this.easingFn(progress, this.localStartVal, this.endVal - this.localStartVal, this.localDuration)
          }
        } else {
          if (this.countDown) {
            this.printValue = this.localStartVal - (this.localStartVal - this.endVal) * (progress / this.localDuration)
          } else {
            this.printValue = this.localStartVal + (this.endVal - this.localStartVal) * (progress / this.localDuration)
          }
        }
        if (this.countDown) {
          this.printValue = this.printValue < this.endVal ? this.endVal : this.printValue
        } else {
          this.printValue = this.printValue > this.endVal ? this.endVal : this.printValue
        }
        this.displayValue = this.formatNumber(this.printValue)
        if (progress < this.localDuration) {
          this.rAF = this.requestAnimationFrame(this.count)
        } else {
          this.$emit('end')
        }
      },
      // ç¼“动时间计算
      easingFn(t, b, c, d) {
        return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b
      },
      // è¯·æ±‚帧动画
      requestAnimationFrame(cb) {
        const currentTime = new Date().getTime()
        // ä¸ºäº†ä½¿setTimteout的尽可能的接近每秒60帧的效果
        const timeToCall = Math.max(0, 16 - (currentTime - this.lastTime))
        const timerId = setTimeout(() => {
          cb && cb(currentTime + timeToCall)
        }, timeToCall)
        this.lastTime = currentTime + timeToCall
        return timerId
      },
      // æ¸…除帧动画
      clearAnimationFrame(timerId) {
        clearTimeout(timerId)
      },
      // æ ¼å¼åŒ–数值
      formatNumber(number) {
        const reg = /(\d+)(\d{3})/
        number = Number(number)
        number = number.toFixed(Number(this.decimals))
        number += ''
        const numberArray = number.split('.')
        let num1 = numberArray[0]
        const num2 = numberArray.length > 1 ? this.decimalSeparator + numberArray[1] : ''
        if (this.thousandthsSeparator && !this.isNumber(this.thousandthsSeparator)) {
          while(reg.test(num1)) {
            num1 = num1.replace(reg, '$1' + this.thousandthsSeparator + '$2')
          }
        }
        return num1 + num2
      },
      // åˆ¤æ–­æ˜¯å¦ä¸ºæ•°å­—
      isNumber(val) {
        return !isNaN(parseFloat(val))
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-count-num {
    /* #ifndef APP-NVUE */
    display: inline-flex;
    /* #endif */
    text-align: center;
    line-height: 1;
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-cropper/index.wxs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,328 @@
var cropper = {
  // ç”»å¸ƒx轴起点
  cutX: 0,
  // ç”»å¸ƒy轴起点
  cutY: 0,
  // è§¦æ‘¸ç‚¹ä¿¡æ¯(手指与图片中心点的相对位置)
  touchRelactive: [{
    x: 0,
    y: 0
  }],
  // åŒæŒ‡è§¦æ‘¸æ—¶æ–œè¾¹çš„长度
  hypotenuseLength:0,
  // æ˜¯å¦ç»“束触摸
  touchEndFlag: false,
  // ç”»å¸ƒå®½é«˜
  canvasWidth: 0,
  canvasHeight: 0,
  // å›¾ç‰‡å®½é«˜
  imgWidth: 0,
  imgHeight: 0,
  // å›¾ç‰‡ç¼©æ”¾æ¯”例
  scale: 1,
  // å›¾ç‰‡æ—‹è½¬è§’度
  angle: 0,
  // å›¾ç‰‡ä¸Šè¾¹è·
  imgTop: 0,
  // å›¾ç‰‡å·¦è¾¹è·
  imgLeft: 0,
  // çª—口宽高
  windowWidth: 0,
  windowHeight: 0,
  init: true
}
function bool(str) {
  return str === 'true' || str === true
}
function propsChange(prop, oldProp, ownerInstance, instance) {
  if (prop && prop !== 'null') {
    var params = prop.split(',')
    var type = +params[0]
    var dataset = instance.getDataset()
    if (cropper.init || type == 4) {
      cropper.canvasWidth = +dataset.width
      cropper.canvasHeight = +dataset.height
      cropper.imgTop = +dataset.windowheight / 2
      cropper.imgLeft = +dataset.windowwidth / 2
      cropper.imgWidth = +dataset.imgwidth
      cropper.imgHeight = +dataset.imgheight
      cropper.windowHeight = +dataset.windowheight
      cropper.windowWidth = +dataset.windowwidth
      cropper.init = false
    } else if (type == 2 || type == 3) {
      cropper.imgWidth = +dataset.imgwidth
      cropper.imgHeight = +dataset.imgheight
    }
    cropper.angle = +dataset.angle
    if (type == 3) {
      imgTransform(ownerInstance)
    }
    switch(type) {
      case 1:
        setCutCenter(ownerInstance)
        // è®¾ç½®è£å‰ªæ¡†å¤§å°
        computeCutSize(ownerInstance)
        // æ£€æŸ¥è£å‰ªæ¡†æ˜¯å¦åœ¨èŒƒå›´å†…
        cutDetectionPosition(ownerInstance)
        break
      case 2:
        setCutCenter(ownerInstance)
        break
      case 3:
        imgMarginDetectionScale(ownerInstance)
        break
      case 4:
        imageReset(ownerInstance)
        break
      case 5:
        setCutCenter(ownerInstance)
        break
      default:
        break
    }
  }
}
function touchStart(event, ownerInstance) {
  var touch = event.touches || event.changedTouches
  cropper.touchEndFlag = false
  if (touch.length === 1) {
    cropper.touchRelactive[0] = {
      x: touch[0].pageX - cropper.imgLeft,
      y: touch[0].pageY - cropper.imgTop
    }
  } else {
    var width = Math.abs(touch[0].pageX - touch[1].pageX)
    var height = Math.abs(touch[0].pageY - touch[1].pageY)
    cropper.touchRelactive = [{
      x: touch[0].pageX - cropper.imgLeft,
      y: touch[0].pageY - cropper.imgTop
    },{
      x: touch[1].pageX - cropper.imgLeft,
      y: touch[1].pageY - cropper.imgTop
    }]
    cropper.hypotenuseLength = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2))
  }
}
function touchMove(event, ownerInstance) {
  var touch = event.touches || event.changedTouches
  if (cropper.touchEndFlag) return
  moveDuring(ownerInstance)
  if (event.touches.length === 1) {
    var left = touch[0].pageX - cropper.touchRelactive[0].x,
      top = touch[0].pageY - cropper.touchRelactive[0].y;
    cropper.imgLeft = left
    cropper.imgTop = top
    imgTransform(ownerInstance)
    imgMarginDetectionPosition(ownerInstance)
  } else {
    var dataset = event.instance.getDataset()
    var minScale = +dataset.minscale
    var maxScale = +dataset.maxscale
    var width = Math.abs(touch[0].pageX - touch[1].pageX),
      height = Math.abs(touch[0].pageY - touch[1].pageY),
      hypotenuse = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)),
      scale = cropper.scale * (hypotenuse / cropper.hypotenuseLength),
      current_deg = 0;
    scale = scale <= minScale ? minScale : scale
    scale = scale >= maxScale ? maxScale : scale
    cropper.scale = scale
    imgMarginDetectionScale(ownerInstance, true)
    var touchRelative = [{
      x: touch[0].pageX - cropper.imgLeft,
      y: touch[0].pageY - cropper.imgTop
    }, {
      x: touch[1].pageX - cropper.imgLeft,
      y: touch[1].pageY - cropper.imgTop
    }]
    cropper.touchRelactive = touchRelative
    cropper.hypotenuseLength = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2))
    // æ›´æ–°è§†å›¾
    cropper.angle = cropper.angle + current_deg
    imgTransform(ownerInstance)
  }
}
function touchEnd(event, ownerInstance) {
  cropper.touchEndFlag = true
  moveStop(ownerInstance)
  updateData(ownerInstance)
}
function moveDuring(ownerInstance) {
  if (!ownerInstance) return
  ownerInstance.callMethod('moveDuring')
}
function moveStop(ownerInstance) {
  if (!ownerInstance) return
  ownerInstance.callMethod('moveStop')
}
function setCutCenter(ownerInstance) {
  var cutX = (cropper.windowWidth - cropper.canvasWidth) * 0.5
  var cutY = (cropper.windowHeight - cropper.canvasHeight) * 0.5
  cropper.imgTop = cropper.imgTop - cropper.cutY + cutY
  cropper.cutY = cutY
  cropper.imgLeft = cropper.imgLeft - cropper.cutX + cutX
  cropper.cutX = cutX
  cutDetectionPosition(ownerInstance)
  imgTransform(ownerInstance)
  updateData(ownerInstance)
}
// æ£€æµ‹å‰ªè£æ¡†ä½ç½®æ˜¯å¦åœ¨å…è®¸çš„范围内(屏幕内)
function cutDetectionPosition(ownerInstance) {
  var windowHeight = cropper.windowHeight,
    windowWidth = cropper.windowWidth;
  // æ£€æµ‹ä¸Šè¾¹è·æ˜¯å¦åœ¨èŒƒå›´å†…
  var cutDetectionPositionTop = function() {
    if (cropper.cutY < 0) {
      cropper.cutY = 0
    }
    if (cropper.cutY > windowHeight - cropper.canvasHeight) {
      cropper.cutY = windowHeight - cropper.canvasHeight
    }
  }
  // æ£€æµ‹å·¦è¾¹è·æ˜¯å¦åœ¨èŒƒå›´å†…
  var cutDetectionPositionLeft = function() {
    if (cropper.cutX < 0) {
      cropper.cutX = 0
    }
    if (cropper.cutX > windowWidth - cropper.canvasWidth) {
      cropper.cutX = windowWidth - cropper.canvasWidth
    }
  }
  // è£å‰ªæ¡†åæ ‡å¤„理(如果只写一个参数则另一个默认为0,都不写默认为居中)
  if (cropper.cutX === null && cropper.cutY === null) {
    var cutX = (windowWidth - cropper.canvasWidth) * 0.5,
      cutY = (windowHeight - cropper.canvasHeight) * 0.5;
    cropper.cutX = cutX
    cropper.cutY = cutY
  } else if (cropper.cutX !== null && cropper.cutX !== null) {
    cutDetectionPositionTop()
    cutDetectionPositionLeft()
  } else if (cropper.cutX !== null && cropper.cutY === null) {
    cutDetectionPositionLeft()
    cropper.cutY = (windowHeight - cropper.canvasHeight) / 2
  } else if (cropper.cutX === null && cropper.cutY !== null) {
    cutDetectionPositionTop()
    cropper.cutX = (windowWidth - cropper.canvasWidth) / 2
  }
}
// å›¾ç‰‡è¾¹ç¼˜æ£€æµ‹-缩放
function imgMarginDetectionScale(ownerInstance, delay) {
  var scale = cropper.scale,
    imgWidth = cropper.imgWidth,
    imgHeight = cropper.imgHeight;
  if ((cropper.angle / 90) % 2) {
    imgWidth = cropper.imgHeight
    imgHeight = cropper.imgWidth
  }
  if (imgWidth * scale < cropper.canvasWidth) {
    scale = cropper.canvasWidth / imgWidth
  }
  if (imgHeight * scale < cropper.canvasHeight) {
    scale = Math.max(scale, cropper.canvasHeight / imgHeight)
  }
  imgMarginDetectionPosition(ownerInstance, scale, delay)
}
// å›¾ç‰‡è¾¹ç¼˜æ£€æµ‹-位置
function imgMarginDetectionPosition(ownerInstance, scale, delay) {
  var left = cropper.imgLeft,
    top = cropper.imgTop,
    imgWidth = cropper.imgWidth,
    imgHeight = cropper.imgHeight;
  scale = scale || cropper.scale
  if ((cropper.angle / 90) % 2) {
    imgWidth = cropper.imgHeight
    imgHeight = cropper.imgWidth
  }
  left = cropper.cutX + (imgWidth * scale) / 2 >= left ? left : cropper.cutX + (imgWidth * scale) / 2
  left = cropper.cutX + cropper.canvasWidth - (imgWidth * scale) / 2 <= left ? left : cropper.cutX + cropper.canvasWidth - (imgWidth * scale) / 2
  top = cropper.cutY + (imgHeight * scale) / 2 >= top ? top : cropper.cutY + (imgHeight * scale) / 2
  top = cropper.cutY + cropper.canvasHeight - (imgHeight * scale) / 2 <= top ? top : cropper.cutY + cropper.canvasHeight - (imgHeight * scale) / 2
  cropper.imgLeft = left
  cropper.imgTop = top
  cropper.scale = scale
  if (!delay || delay === 'null') {
    imgTransform(ownerInstance)
  }
}
// æ”¹å˜æˆªå–值大小
function computeCutSize(ownerInstance) {
  if (cropper.canvasWidth > cropper.windowWidth) {
    cropper.canvasWidth = cropper.windowWidth
  } else if (cropper.canvasWidth + cropper.cutX > cropper.windowWidth) {
    cropper.cutX = cropper.windowWidth - cropper.cutX
  }
  if (cropper.canvasHeight > cropper.windowHeight) {
    cropper.canvasHeight = cropper.windowHeight
  } else if (cropper.canvasHeight + cropper.cutY > cropper.windowHeight) {
    cropper.cutY = cropper.windowHeight - cropper.cutY
  }
}
// å›¾ç‰‡åŠ¨ç”»
function imgTransform(ownerInstance) {
  var image = ownerInstance.selectComponent('.tn-cropper__image')
  if (!image) return
  var x = cropper.imgLeft - cropper.imgWidth / 2,
    y = cropper.imgTop - cropper.imgHeight / 2;
  image.setStyle({
    'transform': 'translate3d('+ x + 'px,' + y + 'px,0) scale(' + cropper.scale +') rotate(' + cropper.angle + 'deg)'
  })
}
// å›¾ç‰‡é‡ç½®
function imageReset(ownerInstance) {
  cropper.scale = 1
  cropper.angle = 0
  imgTransform(ownerInstance)
}
// é«˜åº¦å˜åŒ–
function canvasHeight(ownerInstance) {
  if (!ownerInstance) return
  computeCutSize(ownerInstance)
}
// å®½åº¦å˜åŒ–
function canvasWidth(ownerInstance) {
  if (!ownerInstance) return
  computeCutSize(ownerInstance)
}
// æ›´æ–°æ•°æ®
function updateData(ownerInstance) {
  if (!ownerInstance) return
  ownerInstance.callMethod('change', {
    cutX: cropper.cutX,
    cutY: cropper.cutY,
    imgWidth: cropper.imgWidth,
    imgHeight: cropper.imgHeight,
    scale: cropper.scale,
    angle: cropper.angle,
    imgTop: cropper.imgTop,
    imgLeft: cropper.imgLeft
  })
}
module.exports = {
  touchStart: touchStart,
  touchMove: touchMove,
  touchEnd: touchEnd,
  propsChange: propsChange
}
¼ª°²PDA/tuniao-ui/components/tn-cropper/tn-cropper.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,570 @@
<template>
  <view class="tn-cropper-class tn-cropper" @touchmove.stop.prevent="stop">
    <image
      v-if="imageUrl"
      :src="imageUrl"
      class="tn-cropper__image"
      :style="{
        width: (imgWidth ? imgWidth : width) + 'px',
        height: (imgHeight ? imgHeight : height) + 'px',
        transitionDuration: (animation ? 0.3 : 0) + 's'
      }"
      mode="widthFix"
      :data-minScale="minScale"
      :data-maxScale="maxScale"
      @load="imageLoad"
      @error="imageLoad"
      @touchstart="wxs.touchStart"
      @touchmove="wxs.touchMove"
      @touchend="wxs.touchEnd"
    ></image>
    <view
      class="tn-cropper__wrapper"
      :style="{
        width: width + 'px',
        height: height + 'px',
        borderRadius: isRound ? '50%' : '0'
      }"
    >
      <view
        class="tn-cropper__border"
        :style="{
          border: borderStyle,
          borderRadius: isRound ? '50%' : '0',
        }"
        :prop="props"
        :change:prop="wxs.propsChange"
        :data-width="width"
        :data-height="height"
        :data-windowHeight="systemInfo.windowHeight || 600"
        :data-windowWidth="systemInfo.windowWidth || 400"
        :data-imgTop="imgTop"
        :data-imgWidth="imgWidth"
        :data-imgHeight="imgHeight"
        :data-angle="angle"
      ></view>
    </view>
    <canvas
      class="tn-cropper__canvas"
      :style="{
        width: width * scaleRatio + 'px',
        height: height * scaleRatio + 'px'
      }"
      :canvas-id="CANVAS_ID"
      :id="CANVAS_ID"
      :disable-scroll="true"
    ></canvas>
    <view
      v-if="!custom"
      class="tn-cropper__tabbar"
    >
      <view class="tn-cropper__tabbar__btn tn-cropper__tabber__cancel" @tap.stop="back">取消</view>
      <view class="tn-cropper__tabbar__rotate" :class="[`tn-icon-${rotateIcon}`]" @tap.stop="setAngle"></view>
      <view class="tn-cropper__tabbar__btn tn-cropper__tabber__confirm" @tap.stop="getCutImage">完成</view>
    </view>
  </view>
</template>
<script src="./index.wxs" lang="wxs" module="wxs"></script>
<script>
  export default {
    name: 'tn-cropper',
    props: {
      // å›¾ç‰‡è·¯å¾„
      imageUrl: {
        type: String,
        default: ''
      },
      // è£å‰ªæ¡†é«˜åº¦ px
      height: {
        type: Number,
        default: 280
      },
      // è£å‰ªæ¡†çš„宽度 px
      width: {
        type: Number,
        default: 280
      },
      // æ˜¯å¦ä¸ºåœ†å½¢è£å‰ªæ¡†
      isRound: {
        type: Boolean,
        default: false
      },
      // è£å‰ªæ¡†è¾¹æ¡†æ ·å¼
      borderStyle: {
        type: String,
        default: '1rpx solid #FFF'
      },
      // ç”Ÿæˆçš„图片尺寸相对于裁剪框的比例
      scaleRatio: {
        type: Number,
        default: 1
      },
      // è£å‰ªåŽçš„图片质量
      // å–值范围为:(0, 1]
      quality: {
        type: Number,
        default: 0.8
      },
      // æ˜¯å¦è¿”回base64(H5默认为base64)
      returnBase64: {
        type: Boolean,
        default: false
      },
      // å›¾ç‰‡æ—‹è½¬è§’度
      rotateAngle: {
        type: Number,
        default: 0
      },
      // å›¾ç‰‡æœ€å°ç¼©æ”¾æ¯”
      minScale: {
        type: Number,
        default: 0.5
      },
      // å›¾ç‰‡æœ€å¤§ç¼©æ”¾æ¯”
      maxScale: {
        type: Number,
        default: 2
      },
      // è‡ªå®šä¹‰æ“ä½œæ (设置后会隐藏默认的底部操作栏)
      custom: {
        type: Boolean,
        default: false
      },
      // æ˜¯å¦åœ¨å€¼å‘生改变的时候开始裁剪
      // custom为true时生效
      startCutting: {
        type: Boolean,
        default: false
      },
      // è£å‰ªæ—¶æ˜¯å¦æ˜¾ç¤ºloading
      loading: {
        type: Boolean,
        default: true
      },
      // æ—‹è½¬å›¾ç‰‡å›¾æ ‡
      rotateIcon: {
        type: String,
        default: 'circle-arrow'
      }
    },
    data() {
      return {
        // canvas容器id
        CANVAS_ID: 'tn-cropper-canvas',
        // ç§»åŠ¨è£å‰ªè¶…æ—¶æ—¶é—´å®šæ—¶å™¨
        TIME_CUT_CENTER: null,
        // canvas容器
        ctx: null,
        // ç”»å¸ƒx轴起点
        cutX: 0,
        // ç”»å¸ƒy轴起点
        cutY: 0,
        // å›¾ç‰‡å®½åº¦
        imgWidth: 0,
        // å›¾ç‰‡é«˜åº¦
        imgHeight: 0,
        // å›¾ç‰‡åº•部位置
        imgTop: 0,
        // å›¾ç‰‡å·¦è¾¹ä½ç½®
        imgLeft: 0,
        // å›¾ç‰‡ç¼©æ”¾æ¯”
        scale: 1,
        // å›¾ç‰‡æ—‹è½¬è§’度
        angle: 0,
        // å¼€å¯åŠ¨ç”»è¿‡æ¸¡æ•ˆæžœ
        animation: false,
        // åŠ¨ç”»å®šæ—¶å™¨
        animationTime: null,
        // ç³»ç»Ÿä¿¡æ¯
        systemInfo: {},
        // ä¼ é€’的参数
        props: '',
        // æ ‡è®°æ˜¯å¦å‘生改变
        sizeChange: 0,
        angleChange: 0,
        resetChange: 0,
        centerChange: 0
      }
    },
    watch: {
      imageUrl(val) {
        this.imageReset()
        this.showLoading()
        uni.getImageInfo({
          src: val,
          success: (res) => {
            // è®¡ç®—图片尺寸
            this.imgComputeSize(res.width, res.height)
            this.angleChange++
            this.props = `3,${this.angleChange}`
          },
          fail: (err) => {
            console.log(err);
            this.imgComputeSize()
            this.angleChange++
            this.props = `3,${this.angleChange}`
          }
        })
      },
      rotateAngle(val) {
        this.animation = true
        this.angle = val
        this.angleChanged(val)
      },
      animation(val) {
        clearTimeout(this.animationTime)
        if (val) {
          this.animationTime = setTimeout(() => {
            this.animation = false
          }, 200)
        }
      },
      startCutting(val) {
        if (this.custom && val) {
          this.getCutImage()
        }
      }
    },
    mounted() {
      this.systemInfo = uni.getSystemInfoSync()
      this.imgTop = this.systemInfo.windowHeight / 2
      this.imgLeft = this.systemInfo.windowWidth / 2
      this.ctx = uni.createCanvasContext(this.CANVAS_ID, this)
      // åˆå§‹åŒ–
      this.$nextTick(() => {
        this.props = '1,1'
      })
      setTimeout(() => {
        this.$emit('ready', {})
      }, 200)
    },
    methods: {
      // å°†ç½‘络图片转换为本地图片【同步执行】
      async getLocalImage(url) {
        return await new Promise((resolve, reject) => {
          uni.downloadFile({
            url: url,
            success: (res) => {
              resolve(res.tempFilePath)
            },
            fail: (err) => {
              reject(false)
            }
          })
        })
      },
      // è¿”回裁剪后的图片信息
      getCutImage() {
        if (!this.imageUrl) {
          uni.showToast({
            title: '请选择图片',
            icon: 'none'
          })
          return
        }
        this.loading && this.showLoading()
        const draw = async () => {
          // å›¾ç‰‡å®žé™…大小
          let imgWidth = this.imgWidth * this.scale * this.scaleRatio
          let imgHeight = this.imgHeight * this.scale * this.scaleRatio
          // canvas和图片的相对距离
          let xpos = this.imgLeft - this.cutX
          let ypos = this.imgTop - this.cutY
          let imgUrl = this.imageUrl
          // #ifdef APP-PLUS || MP-WEIXIN
          if (~this.imageUrl.indexOf('https:')) {
            imgUrl = await this.getLocalImage(this.imageUrl)
          }
          // #endif
          // æ—‹è½¬ç”»å¸ƒ
          this.ctx.translate(xpos * this.scaleRatio, ypos * this.scaleRatio)
          // å¦‚果时圆形则截取圆形
          if (this.isRound) {
            const r = this.width > this.height ? Math.floor(this.height / 2) : Math.floor(this.width / 2)
            let translateX = Math.floor(this.width / 2)
            let translateY = Math.floor(this.height / 2)
            this.ctx.beginPath()
            this.ctx.arc(translateX - (xpos * this.scaleRatio), translateY - (ypos * this.scaleRatio), r, 0, (360 * Math.PI) / 180)
            this.ctx.closePath()
            this.ctx.stroke()
            this.ctx.clip()
          }
          this.ctx.rotate((this.angle * Math.PI) / 180)
          this.ctx.drawImage(imgUrl, -imgWidth / 2, -imgHeight / 2, imgWidth, imgHeight)
          // æ¸…空后再继续绘制
          this.ctx.draw(false, () => {
            let params = {
              width: this.width * this.scaleRatio,
              height: Math.round(this.height * this.scaleRatio),
              destWidth: this.width * this.scaleRatio,
              destHeight: Math.round(this.height) * this.scaleRatio,
              fileType: 'png',
              quality: this.quality
            }
            let data = {
              url: '',
              base64: '',
              width: this.width * this.scaleRatio,
              height: this.height * this.scaleRatio
            }
            // #ifdef MP-ALIPAY
            if (this.returnBase64) {
              this.ctx.toDataURL(params).then((urlData) => {
                data.base64 = urlData
                this.loading && uni.hideLoading()
                this.$emit('cropper', data)
              })
            } else {
              this.ctx.toTempFilePath({
                ...params,
                success: (res) => {
                  data.url = res.apFilePath
                  this.loading && uni.hideLoading()
                  this.$emit('cropper', data)
                }
              })
            }
            // #endif
            let base64Flag = this.returnBase64
            // #ifndef MP-ALIPAY
            // #ifdef MP-BAIDU || MP-TOUTIAO || H5
            base64Flag = false
            // #endif
            if (base64Flag) {
              uni.canvasGetImageData({
                canvasId: this.CANVAS_ID,
                x: 0,
                y: 0,
                width: this.width * this.scaleRatio,
                height: Math.round(this.height * this.scaleRatio),
                success: (res) => {
                  const arrayBuffer = new Uint8Array(res.data)
                  const base64 = uni.arrayBufferToBase64(arrayBuffer)
                  data.base64 = base64
                  this.loading && uni.hideLoading()
                  this.$emit('cropper', data)
                }
              }, this)
            } else {
              uni.canvasToTempFilePath({
                ...params,
                canvasId: this.CANVAS_ID,
                success: (res) => {
                  data.url = res.tempFilePath
                  // #ifdef H5
                  data.base64 = res.tempFilePath
                  // #endif
                  this.loading && uni.hideLoading()
                  this.$emit('cropper', data)
                }
              }, this)
            }
            // #endif
          })
        }
        draw()
      },
      // ä¿®æ”¹å›¾ç‰‡åŽè§¦å‘的函数
      change(e) {
        this.cutX = e.cutX || 0
        this.cutY = e.cutY || 0
        this.imgWidth = e.imgWidth || this.imgWidth
        this.imgHeight = e.imgHeight || this.imgHeight
        this.scale = e.scale || 1
        this.angle = e.angle || 0
        this.imgTop = e.imgTop || 0
        this.imgLeft = e.imgLeft || 0
      },
      // é‡ç½®å›¾ç‰‡
      imageReset() {
        this.scale = 1
        this.angle = 0
        let systemInfo = this.systemInfo.windowHeight ? this.systemInfo : uni.getSystemInfoSync()
        this.imgTop = systemInfo.windowHeight / 2
        this.imgLeft = systemInfo.windowWidth / 2
        this.resetChange++
        this.props = `4,${this.resetChange}`
        // åˆå§‹æ—‹è½¬è§’度
        this.$emit('initAngle', {})
      },
      // å›¾ç‰‡çš„生成的尺寸
      imgComputeSize(width, height) {
        // é»˜è®¤æŒ‰å›¾ç‰‡çš„æœ€å°è¾¹ = å¯¹åº”的裁剪框尺寸
        let imgWidth = width,
          imgHeight = height;
        if (imgWidth && imgHeight) {
          if (imgWidth / imgHeight > this.width / this.height) {
            imgHeight = this.height
            imgWidth = (width / height) * imgHeight
          } else {
            imgWidth = this.width
            imgHeight = (height / width) * imgWidth
          }
        } else {
          let systemInfo = this.systemInfo.windowHeight ? this.systemInfo : uni.getSystemInfoSync()
          imgWidth = systemInfo.windowWidth
          imgHeight = 0
        }
        this.imgWidth = imgWidth
        this.imgHeight = imgHeight
        this.sizeChange++
        this.props = `2,${this.sizeChange}`
      },
      // å›¾ç‰‡åŠ è½½å®Œæ¯•
      imageLoad(e) {
        this.imageReset()
        uni.hideLoading()
        this.$emit('imageLoad', {})
      },
      // ç§»åŠ¨ç»“æŸ
      moveStop() {
        clearTimeout(this.TIME_CUT_CENTER)
        this.TIME_CUT_CENTER = setTimeout(() => {
          this.centerChange++
          this.props = `5,${this.centerChange}`
        }, 688)
      },
      // ç§»åЍ䏭
      moveDuring() {
        clearTimeout(this.TIME_CUT_CENTER)
      },
      // æ˜¾ç¤ºåŠ è½½æ¡†
      showLoading() {
        uni.showLoading({
          title: '请稍等......',
          mask: true
        })
      },
      // åœæ­¢
      stop() {},
      // å–消/返回
      back() {
        uni.navigateBack()
      },
      // è§’度改变
      angleChanged(val) {
        this.moveStop()
        if (val % 90) {
          this.angle = Math.round(val / 90) * 90
        }
        this.angleChange++
        this.props = `3,${this.angleChange}`
      },
      // è®¾ç½®è§’度
      setAngle() {
        this.animation = true
        this.angle = this.angle + 90
        this.angleChanged(this.angle)
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-cropper {
    width: 100vw;
    height: 100vh;
    background: linear-gradient(-120deg, #F15BB5, #9A5CE5, #01BEFF, #00F5D4);
    // background: linear-gradient(-120deg,  #9A5CE5, #01BEFF, #00F5D4, #43e97b);
    // background: linear-gradient(-120deg,#c471f5, #ec008c, #ff4e50,#f9d423);
    // background: linear-gradient(-120deg, #0976ea, #c471f5, #f956b6, #ea7e0a);
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1;
    &__image {
      width: 100%;
      border-style: none;
      position: absolute;
      top: 0;
      left: 0;
      z-index: 2;
      -webkit-backface-visibility: hidden;
      backface-visibility: hidden;
      transform-origin: center;
    }
    &__canvas {
      position: fixed;
      z-index: 10;
      left: -2000px;
      top: -2000px;
      pointer-events: none;
    }
    &__wrapper {
      position: fixed;
      z-index: 4;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      border: 3000px solid rgba(0, 0, 0, 0.55);
      pointer-events: none;
      box-sizing: content-box;
    }
    &__border {
      position: absolute;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      box-sizing: border-box;
      pointer-events: none;
    }
    &__tabbar {
      width: 100%;
      height: 120rpx;
      padding: 0 40rpx;
      box-sizing: border-box;
      position: fixed;
      left: 0;
      bottom: 0;
      z-index: 99;
      display: flex;
      align-items: center;
      justify-content: space-between;
      color: #FFFFFF;
      font-size: 32rpx;
      &::after {
        content: '';
        position: absolute;
        top: 0;
        right: 0;
        left: 0;
        border-top: 1rpx solid rgba(255, 255, 255, 0.2);
        -webkit-transform: scaleY(0.5) translateZ(0);
        transform: scaleY(0.5) translateZ(0);
        transform-origin: 0 100%;
      }
      &__btn {
        height: 80rpx;
        display: flex;
        align-items: center;
      }
      &__rotate {
        width: 44rpx;
        height: 44rpx;
        font-size: 40rpx;
        text-align: center;
      }
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-custom-swiper-item/index.wxs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,288 @@
function setTimeout(instance, cb, time) {
  if (time > 0) {
    var s = getDate().getTime()
    var fn = function () {
        if (getDate().getTime() - s > time) {
            cb && cb()
        } else
            instance.requestAnimationFrame(fn)
    }
    fn()
  }
  else
    cb && cb()
}
// åˆ¤æ–­è§¦æ‘¸çš„移动方向
function decideSwiperDirection(startTouches, currentTouches, vertical) {
  // éœ‡åŠ¨åç§»å®¹å·®
  var toleranceShake = 150
  // ç§»åЍ容差
  var toleranceTranslate = 10
  if (!vertical) {
    // æ°´å¹³æ–¹å‘移动
    if (Math.abs(currentTouches.y - startTouches.y) <= toleranceShake) {
      // console.log(currentTouches.x, startTouches.x);
      if (Math.abs(currentTouches.x - startTouches.x) > toleranceTranslate) {
        if (currentTouches.x - startTouches.x > 0) {
          return 'right'
        } else if (currentTouches.x - startTouches.x < 0) {
          return 'left'
        }
      }
    }
  } else {
    // åž‚直方向移动
    if (Math.abs(currentTouches.x - startTouches.x) <= toleranceShake) {
      // console.log(currentTouches.x, startTouches.x);
      if (Math.abs(currentTouches.y - startTouches.y) > toleranceTranslate) {
        if (currentTouches.y - startTouches.y > 0) {
          return 'down'
        } else if (currentTouches.y - startTouches.y < 0) {
          return 'up'
        }
      }
    }
  }
  return ''
}
// swiperItem参数数据更新
var itemDataObserver = function(newVal, oldVal, ownerInstance, instance) {
  if (!newVal || newVal === 'undefined') return
  var state = ownerInstance.getState()
  state.itemData = newVal
}
// swiperIndex数据更新
var currentIndexObserver = function(newVal, oldVal, ownerInstance, instance) {
  if ((!newVal && newVal != 0) || newVal === 'undefined') return
  var state = ownerInstance.getState()
  state.currentIndex = newVal
}
// containerData数据更新
var containerDataObserver = function(newVal, oldVal, ownerInstance, instance) {
  if (!newVal || newVal === 'undefined') return
  var state = ownerInstance.getState()
  state.containerData = newVal
}
// å¼€å§‹è§¦æ‘¸
var touchStart = function(event, ownerInstance) {
  console.log('touchStart');
  var instance = event.instance
  var dataset = instance.getDataset()
  var state = ownerInstance.getState()
  var itemData = state.itemData
  var containerData = state.containerData
  // ç”±äºŽå½“前SwiperIndex初始为0,可能会导致swiperIndex数据没有更新
  if (!state.currentIndex || state.currentIndex === 'undefined') {
    state.currentIndex = 0
  }
  if (!containerData || containerData.circular === 'undefined') {
    containerData.circular = false
  }
  state.containerData = containerData
  // å¦‚果当前切换动画还没执行结束,再次触摸会重新加载对应的swiperContainer的信息
  // console.log(containerData.animationFinish);
  if (!containerData.animationFinish) {
    ownerInstance.callMethod('changeParentSwiperContainerStyleStatus',{
      status: 'reload'
    })
  }
  // åˆ¤æ–­æ˜¯å¦ä¸ºä¸ºå½“前显示的SwiperItem
  if (itemData.index != state.currentIndex) return
  var touches = event.changedTouches[0]
  if (!touches) return
  // æ ‡è®°æ»‘动开始时间
  state.touchStartTime = getDate().getTime()
  // è®°å½•当前滑动开始的x,y坐标
  state.touchRelactive = {
    x: touches.pageX,
    y: touches.pageY
  }
  // è®°å½•触摸id,用于处理多指的情况
  state.touchId = touches.identifier
  // æ ‡è®°å¼€å§‹è§¦æ‘¸
  state.touching = true
  ownerInstance.callMethod('updateTouchingStatus', {
    status: true
  })
}
// æ­£åœ¨ç§»åЍ
var touchMove = function(event, ownerInstance) {
  console.log('touchMove');
  var instance = event.instance
  var dataset = instance.getDataset()
  var state = ownerInstance.getState()
  var itemData = state.itemData
  var containerData = state.containerData
  // åˆ¤æ–­æ˜¯å¦ä¸ºä¸ºå½“前显示的SwiperItem
  if (itemData.index != state.currentIndex) return
  // åˆ¤æ–­æ˜¯å¦å¼€å§‹è§¦æ‘¸
  if (!state.touching) return
  var touches = event.changedTouches[0]
  if (!touches) return
  // åˆ¤æ–­æ˜¯å¦ä¸ºåŒä¸€ä¸ªè§¦æ‘¸ç‚¹
  if (state.touchId != touches.identifier) return
  var currentTouchRelactive = {
    x: touches.pageX,
    y: touches.pageY
  }
  // è®¡ç®—相对位移比例
  if (containerData.vertical) {
    var touchDistance = currentTouchRelactive.y - state.touchRelactive.y
    var itemHeight = itemData.itemHeight
    var distanceRate = touchDistance / itemHeight
    // console.log(currentTouchRelactive.y, touchDistance, itemHeight, distanceRate);
    // åˆ¤æ–­æ˜¯å¦ä¸ºè¡”接轮播,如果不是衔接轮播,如果当前为第一个swiperItem并且向下滑、当前为最后一个swiperItem并且向上滑时不进行操作
    if (!containerData.circular &&
      ((state.currentIndex === 0 && touchDistance > 0) || (state.currentIndex === containerData.swiperItemLength - 1 && touchDistance < 0))
    ) {
      return
    }
    // å¦‚果超出了距离则不进行操作
    if((Math.abs(touchDistance) > (itemData.itemTop + itemData.itemHeight))) {
      ownerInstance.callMethod('updateParentSwiperContainerStyle', {
        value: distanceRate < 0 ? -1 : 1
      })
      return
    }
  } else {
    var touchDistance = currentTouchRelactive.x - state.touchRelactive.x
    var itemWidth = itemData.itemWidth
    var distanceRate = touchDistance / itemWidth
    // console.log(currentTouchRelactive.x, touchDistance, itemWidth, distanceRate);
    // åˆ¤æ–­æ˜¯å¦ä¸ºè¡”接轮播,如果不是衔接轮播,如果当前为第一个swiperItem并且向右滑、当前为最后一个swiperItem并且向左滑时不进行操作
    if (!containerData.circular &&
      ((state.currentIndex === 0 && touchDistance > 0) || (state.currentIndex === containerData.swiperItemLength - 1 && touchDistance < 0))
    ) {
      return
    }
    // å¦‚果超出了距离则不进行操作
    if((Math.abs(touchDistance) > (itemData.itemLeft + itemData.itemWidth))) {
      ownerInstance.callMethod('updateParentSwiperContainerStyle', {
        value: distanceRate < 0 ? -1 : 1
      })
      return
    }
  }
  ownerInstance.callMethod('updateParentSwiperContainerStyle', {
    value: distanceRate
  })
}
// ç§»åŠ¨ç»“æŸ
var touchEnd = function(event, ownerInstance) {
  console.log('touchEnd');
  var instance = event.instance
  var dataset = instance.getDataset()
  var state = ownerInstance.getState()
  var itemData = state.itemData
  var containerData = state.containerData
  // åˆ¤æ–­æ˜¯å¦ä¸ºä¸ºå½“前显示的SwiperItem
  if (itemData.index != state.currentIndex) return
  // åˆ¤æ–­æ˜¯å¦å¼€å§‹è§¦æ‘¸
  if (!state.touching) return
  var touches = event.changedTouches[0]
  if (!touches) return
  // åˆ¤æ–­æ˜¯å¦ä¸ºåŒä¸€ä¸ªè§¦æ‘¸ç‚¹
  if (state.touchId != touches.identifier) return
  var currentTime = getDate().getTime()
  var currentTouchRelactive = {
    x: touches.pageX,
    y: touches.pageY
  }
  if (containerData.vertical) {
    // åˆ¤æ–­è§¦æ‘¸ç§»åŠ¨æ–¹å‘
    var direction = decideSwiperDirection(state.touchRelactive, currentTouchRelactive, true)
    // åˆ¤æ–­æ˜¯å¦ä¸ºè¡”接轮播,如果不是衔接轮播,如果当前为第一个swiperItem并且向下滑、当前为最后一个swiperItem并且向上滑时不进行操作
    if (containerData.circular ||
      !((state.currentIndex === 0 && direction === 'down') || (state.currentIndex === containerData.swiperItemLength - 1 && direction === 'up'))
    ) {
      // åˆ¤æ–­è§¦æ‘¸çš„æ—¶é—´å’Œç§»åŠ¨çš„è·ç¦»æ˜¯å¦è¶…è¿‡äº†å½“å‰itemHeight的一半,如果是则执行切换操作
      // console.log(currentTime - state.touchStartTime, Math.abs(currentTouchRelactive.y - state.touchRelactive.y));
      if ((currentTime - state.touchStartTime) > 200 && Math.abs(currentTouchRelactive.y - state.touchRelactive.y) < itemData.itemHeight / 2) {
        ownerInstance.callMethod('changeParentSwiperContainerStyleStatus',{
          status: 'reset'
        })
      } else {
        // console.log(direction, state.touchRelactive.y, currentTouchRelactive.y);
        ownerInstance.callMethod('updateParentSwiperContainerStyleWithDirection', {
          direction: direction
        })
      }
    }
  } else {
    // åˆ¤æ–­è§¦æ‘¸ç§»åŠ¨æ–¹å‘
    var direction = decideSwiperDirection(state.touchRelactive, currentTouchRelactive, false)
    // åˆ¤æ–­æ˜¯å¦ä¸ºè¡”接轮播,如果不是衔接轮播,如果当前为第一个swiperItem并且向右滑、当前为最后一个swiperItem并且向左滑时不进行操作
    if (containerData.circular ||
      !((state.currentIndex === 0 && direction === 'right') || (state.currentIndex === containerData.swiperItemLength - 1 && direction === 'left'))
    ) {
      // åˆ¤æ–­è§¦æ‘¸çš„æ—¶é—´å’Œç§»åŠ¨çš„è·ç¦»æ˜¯å¦è¶…è¿‡äº†å½“å‰itemWidth的一半,如果是则执行切换操作
      // console.log(currentTime - state.touchStartTime, Math.abs(currentTouchRelactive.x - state.touchRelactive.x));
      if ((currentTime - state.touchStartTime) > 200 && Math.abs(currentTouchRelactive.x - state.touchRelactive.x) < itemData.itemWidth / 2) {
        ownerInstance.callMethod('changeParentSwiperContainerStyleStatus',{
          status: 'reset'
        })
      } else {
        // console.log(direction, state.touchRelactive.x, currentTouchRelactive.x);
        ownerInstance.callMethod('updateParentSwiperContainerStyleWithDirection', {
          direction: direction
        })
      }
    }
  }
  // æ¸…除标记
  state.touchId = null
  state.touchRelactive = null
  state.touchStartTime = 0
  // æ ‡è®°åœæ­¢è§¦æ‘¸
  state.touching = true
  ownerInstance.callMethod('updateTouchingStatus', {
    status: false
  })
}
module.exports = {
  itemDataObserver: itemDataObserver,
  currentIndexObserver: currentIndexObserver,
  containerDataObserver: containerDataObserver,
  touchStart: touchStart,
  touchMove: touchMove,
  touchEnd: touchEnd
}
¼ª°²PDA/tuniao-ui/components/tn-custom-swiper-item/tn-custom-swiper-item.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,277 @@
<template>
  <!-- #ifdef MP-WEIXIN -->
  <view
    class="tn-c-swiper-item"
    :style="[swiperStyle]"
    :itemData="itemData"
    :currentIndex="currentIndex"
    :containerData="containerData"
    :change:itemData="wxs.itemDataObserver"
    :change:currentIndex="wxs.currentIndexObserver"
    :change:containerData="wxs.containerDataObserver"
    @touchstart="wxs.touchStart"
    :catch:touchmove="touching?wxs.touchMove:''"
    :catch:touchend="touching?wxs.touchEnd:''"
  >
    <view class="item__container tn-c-swiper-item__container" :style="[containerStyle]">
      <slot></slot>
    </view>
  </view>
  <!-- #endif -->
  <!-- #ifndef MP-WEIXIN -->
  <view
    class="tn-c-swiper-item"
    :style="[swiperStyle]"
    :itemData="itemData"
    :currentIndex="currentIndex"
    :containerData="containerData"
    :change:itemData="wxs.itemDataObserver"
    :change:currentIndex="wxs.currentIndexObserver"
    :change:containerData="wxs.containerDataObserver"
    @touchstart="wxs.touchStart"
    @touchmove="wxs.touchMove"
    @touchend="wxs.touchEnd"
  >
    <view class="item__container tn-c-swiper-item__container" :style="[containerStyle]">
      <slot></slot>
    </view>
  </view>
  <!-- #endif -->
</template>
<script src="./index.wxs" lang="wxs" module="wxs"></script>
<script>
  export default {
    name: 'tn-custom-swiper-item',
    props: {
    },
    computed: {
      // swiperItem公共数据
      itemData() {
        return {
          index: this.index,
          itemWidth: this.itemWidth,
          itemHeight: this.itemHeight,
          itemTop: this.itemTop,
          itemLeft: this.itemLeft
        }
      },
      currentIndex() {
        return this.parentData.currentIndex
      },
      containerData() {
        return {
          duration: this.parentData.duration,
          animationFinish: this.parentData.swiperContainerAnimationFinish,
          circular: this.parentData.circular,
          swiperItemLength: this.swiperItemLength,
          vertical: this.parentData.vertical
        }
      },
      swiperStyle() {
        let style = {}
        style.transform = `translate3d(${this.translateX}%, ${this.translateY}%, 0px)`
        return style
      },
      containerStyle() {
        let style = {}
        if (this.parentData.customSwiperStyle && Object.keys(this.parentData.customSwiperStyle).length > 0) {
          style = this.parentData.customSwiperStyle
        }
        if ((this.currentIndex === 0 && this.index === this.swiperItemLength - 1) || (this.index === this.currentIndex - 1) &&
          (this.parentData.prevSwiperStyle && Object.keys(this.parentData.prevSwiperStyle).length > 0)
        ) {
          // å‰ä¸€ä¸ªswiperItem
          const copyStyle = JSON.parse(JSON.stringify(style))
          style = Object.assign(copyStyle, this.parentData.prevSwiperStyle)
        }
        if ((this.currentIndex === this.swiperItemLength - 1 && this.index === 0) || (this.index === this.currentIndex + 1) &&
          (this.parentData.nextSwiperStyle && Object.keys(this.parentData.nextSwiperStyle).length > 0)
        ) {
          // åŽä¸€ä¸ªswiperItem
          const copyStyle = JSON.parse(JSON.stringify(style))
          style = Object.assign(copyStyle, this.parentData.nextSwiperStyle)
        }
        return style
      }
    },
    data() {
      return {
        // çˆ¶ç»„件参数
        parentData: {
          duration: 500,
          currentIndex: 0,
          swiperContainerAnimationFinish: false,
          circular: false,
          vertical: false,
          prevSwiperStyle: {},
          customSwiperStyle: {},
          nextSwiperStyle: {}
        },
        // æ ‡è®°å½“前是否正在触摸
        touching: true,
        // å½“前swiperItem的偏移位置
        translateX: 0,
        translateY: 0,
        // å½“前swiperItem的宽高
        itemWidth: 0,
        itemHeight: 0,
        // å½“前swiperItem的位置信息
        itemTop: 0,
        itemLeft: 0,
        // å½“前swiperItem的状态 prev current next
        status: 'current',
        // å½“前swiperItem的index序号
        index: 0,
        // swiperItem的的数量
        swiperItemLength: 0
      }
    },
    created() {
      this.parent = false
      this.updateParentData()
      // èŽ·å–å½“å‰çˆ¶ç»„ä»¶children的数量作为当前swiperItem的序号
      this.index = this.parent.children.length
      this.parent && this.parent.children.push(this)
    },
    mounted() {
      this.$nextTick(() => {
        this.initSwiperItem()
      })
    },
    methods: {
      // åˆå§‹åŒ–swiperItem
      initSwiperItem() {
        this.getSwiperItemRect(() => {
          this.parent.updateAllSwiperItemStyle()
          this.parentData.swiperContainerAnimationFinish = true
        })
      },
      // èŽ·å–swiperItem的信息
      async getSwiperItemRect(callback) {
        const swiperItemRes = await this._tGetRect('.tn-c-swiper-item')
        if (!swiperItemRes.height || !swiperItemRes.width) {
          setTimeout(() => {
            this.getSwiperItemRect()
          }, 30)
          return
        }
        this.itemWidth = swiperItemRes.width
        this.itemHeight = swiperItemRes.height
        this.itemTop = swiperItemRes.top
        this.itemLeft = swiperItemRes.left
        callback && callback()
      },
      // æ›´æ–°swiperItem样式
      updateSwiperItemStyle(swiperItemLength, currentIndex = undefined) {
        currentIndex = currentIndex != undefined ? currentIndex : this.parentData.currentIndex
        this.swiperItemLength = swiperItemLength
        // æ ¹æ®å½“前swiperItem的序号设置偏移位置
        // åˆ¤æ–­å½“前swiperItem是否为第一个,如果是则将最后的swiperItem移动到当前的前一个位置(即最前面)
        if (currentIndex === 0 && this.index === swiperItemLength - 1) {
          if (this.parentData.vertical) {
            this.translateX = 0
            this.translateY = -100
          } else {
            this.translateX = -100
            this.translateY = 0
          }
        }
        // åˆ¤æ–­å½“前swiperItem是否为最后一个,如果是则将最前的swiperItem移动到当前的后一个位置(即最后面)
        else if (currentIndex === swiperItemLength - 1 && this.index === 0) {
          if (this.parentData.vertical) {
            this.translateX = 0
            this.translateY = swiperItemLength * 100
          } else {
            this.translateX = swiperItemLength * 100
            this.translateY = 0
          }
        }
        // æ­£å¸¸æƒ…况
        else {
          if (this.parentData.vertical) {
            this.translateX = 0
            this.translateY = this.index * 100
          } else {
            this.translateX = this.index * 100
            this.translateY = 0
          }
        }
      },
      // æ›´æ–°çˆ¶ç»„件的偏移位置信息
      updateParentSwiperContainerStyle(e) {
        this.parent.updateSwiperContainerStyleWithValue(e.value)
      },
      // æ ¹æ®æ–¹å‘更新父组件的偏移位置信息
      updateParentSwiperContainerStyleWithDirection(e) {
        this.parent.updateSwiperContainerStyleWithDirection(e.direction)
      },
      // ä¿®æ”¹çˆ¶ç»„件的偏移位置的状态
      changeParentSwiperContainerStyleStatus(e) {
        // reset -> é‡ç½® reload -> é‡è½½
        this.parent.updateSwiperContainerStyleWithDirection(e.status)
      },
      // æ›´æ–°çˆ¶ç»„件信息
      updateParentData() {
        this.getParentData('tn-custom-swiper')
      },
      // æ›´æ–°è§¦æ‘¸çŠ¶æ€
      updateTouchingStatus(e) {
        this.touching = e.status
        if (e.status) {
          this.parent.stopAutoPlay()
        } else {
          this.parent.startAutoPlay()
        }
      },
      // æå–对应用户自定义样式
      extractCustomStyle(customStyle) {
        let data = {
          transform: {},
          style: {}
        }
        if (!customStyle) return data
        // å…è®¸è®¾ç½®çš„transform参数
        const allowTransformProps = ['scale','scaleX','scaleY','scaleZ','rotate','rotateX','rotateY','rotateZ']
        for (let prop in customStyle) {
          if (prop.startsWith('transformProp')) {
            // transform里面的样式
            let transformProp = prop.substring('transformProp'.length)
            const index = allowTransformProps.findIndex((item) => {
              return item.toLowerCase() === transformProp.toLowerCase()
            })
            if (index !== -1) {
              transformProp = allowTransformProps[index]
              data.transform[transformProp] = customStyle[prop]
            }
          } else {
            // æ™®é€šæ ·å¼
            data.style[prop] = customStyle[prop]
          }
        }
        return data
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-c-swiper-item {
    width: 100%;
    height: 100%;
    position: absolute;
    display: block;
    will-change: transform;
    cursor: none;
    transform: translate3d(0px, 0px, 0px);
    .item__container {
      width: 100%;
      height: 100%;
      display: block;
      position: absolute;
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-custom-swiper/tn-custom-swiper.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,535 @@
<template>
  <view
    class="tn-c-swiper-class tn-c-swiper"
  >
    <!-- è½®æ’­item容器-->
    <view class="tn-swiper__container" :style="[swiperContainerStyle]" :animation="containerAnimation">
      <slot></slot>
    </view>
    <!-- è½®æ’­æŒ‡ç¤ºå™¨-->
    <view v-if="indicator" class="tn-swiper__indicator" :class="[`tn-swiper__indicator--${vertical ? 'vertical' : 'horizontal'}`]" :style="[indicatorStyle]">
      <!-- æ–¹å½¢ -->
      <block v-if="indicatorType === 'rect'">
        <view
          v-for="(item, index) in children.length"
          :key="index"
          class="tn-swiper__indicator__rect"
          :class="[
            `tn-swiper__indicator__rect--${vertical ? 'vertical' : 'horizontal'}`,
            currentIndex === index ? `tn-swiper__indicator__rect--active tn-swiper__indicator__rect--active--${vertical ? 'vertical' : 'horizontal'}` : ''
          ]"
          :style="[indicatorPointStyle(index)]"
        ></view>
      </block>
      <!-- ç‚¹ -->
      <block v-if="indicatorType === 'dot'">
        <view
          v-for="(item, index) in children.length"
          :key="index"
          class="tn-swiper__indicator__dot"
          :class="[
            `tn-swiper__indicator__dot--${vertical ? 'vertical' : 'horizontal'}`,
            currentIndex === index ? `tn-swiper__indicator__dot--active tn-swiper__indicator__dot--active--${vertical ? 'vertical' : 'horizontal'}` : ''
          ]"
          :style="[indicatorPointStyle(index)]"
        ></view>
      </block>
      <!-- åœ†è§’方形 -->
      <block v-if="indicatorType === 'round'">
        <view
          v-for="(item, index) in children.length"
          :key="index"
          class="tn-swiper__indicator__round"
          :class="[
            `tn-swiper__indicator__round--${vertical ? 'vertical' : 'horizontal'}`,
            currentIndex === index ? `tn-swiper__indicator__round--active tn-swiper__indicator__round--active--${vertical ? 'vertical' : 'horizontal'}` : ''
          ]"
          :style="[indicatorPointStyle(index)]"
        ></view>
      </block>
      <!-- åºå· -->
      <block v-if="indicatorType === 'number' && !vertical">
        <view class="tn-swiper__indicator__number">{{ currentIndex + 1 }}/{{ children.length }}</view>
      </block>
    </view>
  </view>
</template>
<script>
  export default {
    name: 'tn-custom-swiper',
    props: {
      // å½“前所在的轮播位置
      current: {
        type: Number,
        default: 0
      },
      // è‡ªåŠ¨åˆ‡æ¢
      autoplay: {
        type: Boolean,
        default: false
      },
      // è‡ªåŠ¨åˆ‡æ¢æ—¶é—´é—´éš”
      interval: {
        type: Number,
        default: 5000
      },
      // æ»‘动动画时长
      duration: {
        type: Number,
        default: 500
      },
      // æ˜¯å¦é‡‡ç”¨è¡”接滑动
      circular: {
        type: Boolean,
        default: false
      },
      // æ»‘动方向为纵向
      vertical: {
        type: Boolean,
        default: false
      },
      // æ˜¾ç¤ºæŒ‡ç¤ºç‚¹
      indicator: {
        type: Boolean,
        default: false
      },
      // æŒ‡ç¤ºç‚¹ç±»åž‹
      // rect -> æ–¹å½¢ round -> åœ†è§’方形 dot -> ç‚¹ number -> è½®æ’­å›¾ä¸‹æ ‡
      indicatorType: {
        type: String,
        default: 'dot'
      },
      // æŒ‡ç¤ºç‚¹çš„位置
      // topLeft \ topCenter \ topRight \ bottomLeft \ bottomCenter \ bottomRight
      indicatorPosition: {
        type: String,
        default: 'bottomCenter'
      },
      // æŒ‡ç¤ºç‚¹æ¿€æ´»æ—¶é¢œè‰²
      indicatorActiveColor: {
        type: String,
        default: ''
      },
      // æŒ‡ç¤ºç‚¹æœªæ¿€æ´»æ—¶é¢œè‰²
      indicatorInactiveColor: {
        type: String,
        default: ''
      },
      // å‰ä¸€ä¸ªè½®æ’­çš„自定义样式
      prevSwiperStyle: {
        type: Object,
        default() {
          return {}
        }
      },
      // å½“前轮播的自定义样式
      customSwiperStyle: {
        type: Object,
        default() {
          return {}
        }
      },
      // åŽä¸€ä¸ªè½®æ’­çš„自定义样式
      nextSwiperStyle: {
        type: Object,
        default() {
          return {}
        }
      }
    },
    computed: {
      parentData() {
        return [
          this.duration,
          this.currentIndex,
          this.swiperContainerAnimationFinish,
          this.circular,
          this.vertical,
          this.prevSwiperStyle,
          this.customSwiperStyle,
          this.nextSwiperStyle
        ]
      },
      indicatorStyle() {
        let style = {}
        if (this.vertical) {
          if (this.indicatorPosition === 'topLeft' || this.indicatorPosition === 'bottomLeft') style.justifyContent = 'flex-start'
          if (this.indicatorPosition === 'topCenter' || this.indicatorPosition === 'bottomCenter') style.justifyContent =  'center'
          if (this.indicatorPosition === 'topRight' || this.indicatorPosition === 'bottomRight') style.justifyContent =  'flex-end'
          if (['topLeft','topCenter','topRight'].indexOf(this.indicatorPosition) >= 0) {
            if (this.vertical) {
              style.right = '12rpx'
              style.left = 'auto'
            } else {
              style.top = '12rpx'
              style.bottom = 'auto'
            }
          } else {
            if (this.vertical) {
              style.right = 'auto'
              style.left = '12rpx'
            } else {
              style.top = 'auto'
              style.bottom = '12rpx'
            }
          }
        } else {
          if (this.indicatorPosition === 'topLeft' || this.indicatorPosition === 'bottomLeft') style.justifyContent = 'flex-start'
          if (this.indicatorPosition === 'topCenter' || this.indicatorPosition === 'bottomCenter') style.justifyContent =  'center'
          if (this.indicatorPosition === 'topRight' || this.indicatorPosition === 'bottomRight') style.justifyContent =  'flex-end'
          if (['topLeft','topCenter','topRight'].indexOf(this.indicatorPosition) >= 0) {
            style.top = '12rpx'
            style.bottom = 'auto'
          } else {
            style.top = 'auto'
            style.bottom = '12rpx'
          }
        }
        return style
      },
      indicatorPointStyle() {
        return (index) => {
          let style = {}
          if (index === this.currentIndex && this.indicatorActiveColor !== '') {
            style.backgroundColor = this.indicatorActiveColor
          } else if (this.indicatorInactiveColor !== '') {
            style.backgroundColor = this.indicatorInactiveColor
          }
          return style
        }
      }
    },
    watch: {
      parentData() {
        if (this.children.length) {
          this.children.forEach((item) => {
            // åˆ¤æ–­å­ç»„件如果有updateParentData方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
            typeof(item.updateParentData) === 'function' && item.updateParentData()
          })
        }
      },
      current(nVal, oVal) {
        if (this.currentIndex === nVal) return
        this.currentIndex = nVal > this.children.length ? this.children.length - 1 : nVal
        this.swiperContainerAnimationFinish = false
        // è®¾ç½®åŠ¨ç”»è¿‡æ¸¡æ—¶é—´
        this.swiperContainerStyle.transitionDuration = `${this.duration + 90}ms`
        this.updateSwiperContainerItem(oVal)
      }
    },
    data() {
      return {
        // æ¸…除动画定时器
        clearAnimationTimer: null,
        // å‰åŽè¡”接执行定时器
        convergeTimer: null,
        // è‡ªåŠ¨è½®æ’­Timer
        autoPlayTimer: null,
        // å½“前选中的轮播
        currentIndex: this.current,
        // swiperContainer样式
        swiperContainerStyle: {
          transform: 'translate3d(0px, 0px, 0px)',
          transitionDuration: '0ms'
        },
        // swiperContainer动画
        containerAnimation: {},
        // æ»‘动动画结束标记
        swiperContainerAnimationFinish: false
      }
    },
    created() {
      this.children = []
    },
    mounted() {
      this.$nextTick(() => {
        const index = this.currentIndex > this.children.length ? this.children.length - 1 : this.currentIndex
        this.updateSwiperContainerStyle(index)
        this.startAutoPlay()
      })
    },
    methods: {
      // æ›´æ–°å…¨éƒ¨swiperItem的样式
      updateAllSwiperItemStyle() {
        this.children.forEach((item, index) => {
          typeof(item.updateSwiperItemStyle) === 'function' && item.updateSwiperItemStyle(this.children.length)
        })
      },
      // æ ¹æ®swiperIndex更新swiperItemContainer的样式
      updateSwiperContainerStyle(index) {
        if (this.vertical) {
          this.swiperContainerStyle.transform = `translate3d(0px, ${-index * 100}%, 0px)`
        } else {
          this.swiperContainerStyle.transform = `translate3d(${-index * 100}%, 0px, 0px)`
        }
      },
      // æ ¹æ®ä¼ é€’的值更新swiperItemContainer的位置
      updateSwiperContainerStyleWithValue(value) {
        if (this.vertical) {
          this.swiperContainerStyle.transform = `translate3d(0px, ${(-this.currentIndex * 100) + value * 100}%, 0px)`
        } else {
          this.swiperContainerStyle.transform = `translate3d(${(-this.currentIndex * 100) + value * 100}%, 0px, 0px)`
        }
      },
      // æ ¹æ®ä¼ é€’的方向更新swiperItemContainer的位置
      updateSwiperContainerStyleWithDirection(direction) {
        const oldCurrent = this.currentIndex
        const childrenLength = this.children.length
        const lastSwiperItemIndex = childrenLength - 1
        this.swiperContainerAnimationFinish = false
        // å‘后切换一个SwiperItem
        if (direction === 'reset') {
          // è®¾ç½®åŠ¨ç”»è¿‡æ¸¡æ—¶é—´
          this.swiperContainerStyle.transitionDuration = `${this.duration}ms`
          this.updateSwiperContainerStyle(this.currentIndex)
          this.clearAnimationTimer = setTimeout(() => {
            this.clearSwiperContainerAnimation()
          }, this.duration)
        } else if (direction === 'reload') {
          this.clearConvergeSwiperItemTimer()
          this.clearSwiperContainerAnimation()
          this.updateSwiperItemStyle(0)
          this.updateSwiperItemStyle(lastSwiperItemIndex)
        } else {
          if (direction === 'left' || direction === 'up') {
            if (oldCurrent === childrenLength - 1 && !this.circular) {
              this.clearSwiperContainerAnimation()
              this.clearConvergeSwiperItemTimer()
              return
            }
            this.currentIndex = oldCurrent + 1 >= childrenLength ? 0 : oldCurrent + 1
          } else if (direction === 'right' || direction === 'down') {
            if (oldCurrent === 0 && !this.circular) {
              this.clearSwiperContainerAnimation()
              this.clearConvergeSwiperItemTimer()
              return
            }
            this.currentIndex = oldCurrent - 1 < 0 ? childrenLength - 1 : oldCurrent - 1
          }
          // è®¾ç½®åŠ¨ç”»è¿‡æ¸¡æ—¶é—´
          this.swiperContainerStyle.transitionDuration = `${this.duration + 90}ms`
          // this.updateSwiperItemContainerRect(this.currentIndex)
        }
        // console.log(direction, oldCurrent, this.currentIndex);
        this.updateSwiperContainerItem(oldCurrent)
        // åˆ‡æ¢è½®æ’­æ—¶è§¦å‘事件
        this.$emit('change', {
          current: this.currentIndex
        })
      },
      // è®¾ç½®è‡ªåŠ¨è½®æ’­
      startAutoPlay() {
        if (this.autoplay && !this.autoPlayTimer && this.circular) {
          this.autoPlayTimer = setInterval(() => {
            this.updateSwiperContainerStyleWithDirection('left')
          }, this.interval)
        }
      },
      // åœæ­¢è‡ªåŠ¨è½®æ’­
      stopAutoPlay() {
        if (this.autoPlayTimer) {
          clearInterval(this.autoPlayTimer)
          this.autoPlayTimer = null
        }
      },
      // æ›´æ–°swiperContainer和swiperItem相关联信息
      updateSwiperContainerItem(oldCurrent) {
        const childrenLength = this.children.length
        const lastSwiperItemIndex = childrenLength - 1
        // åˆ¤æ–­å½“前是否为头尾,如果是更新对应的头尾SwiperItem样式
        // æ›´æ–°swiperItemContainer的样式
        if (oldCurrent === 0 && this.currentIndex === lastSwiperItemIndex) {
          // å…ˆç§»åŠ¨åˆ°æœ€å·¦è¾¹ç„¶åŽå†åŽ»é™¤åŠ¨ç”»åç§»åˆ°æ­£å¸¸çš„ä½ç½®
          // this.swiperContainerStyle.transform = `translate3d(100%, 0px, 0px)`
          this.updateSwiperContainerStyle(-1)
          this.clearSwiperContainerAnimationTimer()
          this.clearAnimationTimer = setTimeout(() => {
            this.convergeSwiperItem()
          }, this.duration)
        } else if (oldCurrent === lastSwiperItemIndex && this.currentIndex === 0) {
          // å…ˆç§»åŠ¨åˆ°æœ€å³è¾¹ç„¶åŽå†åŽ»é™¤åŠ¨ç”»åç§»åˆ°æ­£å¸¸çš„ä½ç½®
          // this.swiperContainerStyle.transform = `translate3d(${-childrenLength * 100}%, 0px, 0px)`
          this.updateSwiperContainerStyle(childrenLength)
          this.clearSwiperContainerAnimationTimer()
          this.clearAnimationTimer = setTimeout(() => {
            this.convergeSwiperItem()
          }, this.duration)
        } else {
          this.updateSwiperContainerStyle(this.currentIndex)
          this.updateSwiperItemStyle(0)
          this.updateSwiperItemStyle(lastSwiperItemIndex)
          this.clearAnimationTimer = setTimeout(() => {
            this.clearSwiperContainerAnimation()
          }, this.duration)
        }
      },
      // æ›´æ–°å¯¹åº”swiperItem的信息
      updateSwiperItemStyle(index) {
        const childrenLength = this.children.length
        if (index < 0) index = 0
        if (index > childrenLength - 1) index = childrenLength - 1
        typeof(this.children[index].updateSwiperItemStyle) === 'function' && this.children[index].updateSwiperItemStyle(childrenLength, this.currentIndex)
      },
      // æ›´æ–°å¯¹åº”swiperItem的容器信息
      updateSwiperItemContainerRect(index) {
        const childrenLength = this.children.length
        if (index < 0) index = 0
        if (index > childrenLength - 1) index = childrenLength - 1
        typeof(this.children[index].getSwiperItemRect) === 'function' && this.children[index].getSwiperItemRect()
      },
      // æ‰§è¡Œå‰åŽè¡”接
      convergeSwiperItem() {
        const lastSwiperItemIndex = this.children.length - 1
        this.clearSwiperContainerAnimation()
        this.clearConvergeSwiperItemTimer()
        this.convergeTimer = setTimeout(() => {
          this.updateSwiperItemStyle(0)
          this.updateSwiperItemStyle(lastSwiperItemIndex)
          this.updateSwiperContainerStyle(this.currentIndex)
          this.clearConvergeSwiperItemTimer()
        }, 30)
      },
      // åœæ­¢/清除切换动画
      clearSwiperContainerAnimation() {
        this.swiperContainerStyle.transitionDuration = `0ms`
        this.swiperContainerAnimationFinish = true
        this.clearSwiperContainerAnimationTimer()
      },
      // åœæ­¢/清除执行前后衔接定时器
      clearConvergeSwiperItemTimer() {
        if (this.convergeTimer) {
          clearTimeout(this.convergeTimer)
          this.convergeTimer = null
        }
      },
      // åœæ­¢/清除切换动画定时器
      clearSwiperContainerAnimationTimer() {
        if (this.clearAnimationTimer) {
          clearTimeout(this.clearAnimationTimer)
          this.clearAnimationTimer = null
        }
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-c-swiper {
    position: relative;
    overflow: hidden;
    width: 100%;
    height: 100%;
    .tn-swiper {
      &__container {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
        will-change: transform;
        transition-property: all;
        transition-timing-function: ease-out;
      }
      &__indicator {
        position: absolute;
        display: flex;
        z-index: 1;
        &--horizontal {
          padding: 0 24rpx;
          flex-direction: row;
          width: 100%;
        }
        &--vertical {
          padding: 24rpx 0;
          flex-direction: column;
          height: 100%;
        }
        &__rect {
          background-color: rgba(0, 0, 0, 0.3);
          transition: all 0.5s;
          &--horizontal {
            width: 26rpx;
            height: 8rpx;
          }
          &--vertical {
            width: 8rpx;
            height: 26rpx;
          }
          &--active {
            background-color: rgba(255, 255, 255, 0.8);
          }
        }
        &__dot {
          width: 14rpx;
          height: 14rpx;
          border-radius: 20rpx;
          background-color: rgba(0, 0, 0, 0.3);
          transition: all 0.5s;
          &--horizontal {
            margin: 0 6rpx;
          }
          &--vertical {
            margin: 6rpx 0;
          }
          &--active {
            background-color: rgba(255, 255, 255, 0.8);
          }
        }
        &__round {
          width: 14rpx;
          height: 14rpx;
          border-radius: 20rpx;
          background-color: rgba(0, 0, 0, 0.3);
          transition: all 0.5s;
          &--horizontal {
            margin: 0 6rpx;
          }
          &--vertical {
            margin: 6rpx 0;
          }
          &--active {
            background-color: rgba(255, 255, 255, 0.8);
            &--horizontal {
              width: 34rpx;
            }
            &--vertical {
              height: 34rpx;
            }
          }
        }
        &__number {
          padding: 6rpx 16rpx;
          line-height: 1;
          background-color: rgba(0, 0, 0, 0.3);
          color: rgba(255, 255, 255, 0.8);
          border-radius: 100rpx;
          font-size: 26rpx;
        }
      }
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-drag/index.wxs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,265 @@
// åˆ¤æ–­æ˜¯å¦å‡ºç•Œ
var isOutRange = function(x1, y1, x2, y2, x3, y3) {
  return x1 < 0 || x1 >= y1 || x2 < 0 || x2 >= y2 || x3 < 0 || x3 >= y3
}
var edit = false
function bool(str) {
  return str === 'true' || str === true
}
/**
 * æŽ’序核心
 * @param {Object} startKey å¼€å§‹æ—¶ä½ç½®
 * @param {Object} endKey ç»“束时位置
 * @param {Object} instance wxs内的局部变量快照
 */
var sortCore = function(startKey, endKey, state) {
  var basedata = state.basedata
  var excludeFix = function(sortKey, type) {
    // fixed å…ƒç´ ä½ç½®ä¸ä¼šå˜åŒ–, è¿™é‡Œç›´æŽ¥ç”¨ sortKey èŽ·å–ï¼Œæ›´åŠ ä¾¿æ·
    if (state.list[sortKey].fixed) {
      var _sortKey = type ? --sortKey : ++sortKey
      return excludeFix(sortKey, type)
    }
    return sortKey
  }
  // å…ˆèŽ·å–åˆ° endKey å¯¹åº”çš„ realKey, é˜²æ­¢ä¸‹é¢æŽ’序过程中该 realKey è¢«ä¿®æ”¹
  var endRealKey = -1
  state.list.forEach(function(item) {
    if (item.sortKey === endKey) endRealKey = item.realKey
  })
  return state.list.map(function(item) {
    if (item.fixed) return item
    var sortKey = item.sortKey
    var realKey = item.realKey
    if (startKey < endKey) {
      // æ­£åºæ‹–动
      if (sortKey > startKey && sortKey <= endKey) {
        --realKey
        sortKey =  excludeFix(--sortKey, true)
      } else if (sortKey === startKey) {
        realKey = endRealKey
        sortKey = endKey
      }
    } else if (startKey > endKey) {
      // å€’序拖动
      if (sortKey >= endKey && sortKey < startKey) {
        ++realKey
        sortKey = excludeFix(++sortKey, false)
      } else if (sortKey === startKey) {
        realKey = endRealKey
        sortKey = endKey
      }
    }
    if (item.sortKey != sortKey) {
      item.translateX = (sortKey % basedata.columns) * 100 + '%'
      item.translateY = Math.floor(sortKey / basedata.columns) * 100 + '%'
      item.sortKey = sortKey
      item.realKey = realKey
    }
    return item
  })
}
var triggerCustomEvent = function(list, type, instance) {
  if (!instance) return
  var _list = [],
    listData = [];
  list.forEach(function(item) {
    _list[item.sortKey] = item
  })
  _list.forEach(function(item) {
    listData.push(item.data)
  })
  // ç¼–译到小程序 funcName作为参数传递导致事件不执行
  switch(type) {
    case 'change':
      instance.callMethod('change', {data: listData})
      break
    case 'sortEnd':
      instance.callMethod('sortEnd', {data: listData})
      break
  }
}
var listObserver = function(newVal, oldVal, ownerInstance, instance) {
  var state = ownerInstance.getState()
  state.itemsInstance = ownerInstance.selectAllComponents('.tn-drag__item')
  state.list = newVal || []
  state.list.forEach(function(item, index) {
    var itemInstance = state.itemsInstance[index]
    if (item && itemInstance) {
      itemInstance.setStyle({
        'transform': 'translate3d('+ item.translateX + ',' + item.translateY +', 0)'
      })
      if (item.fixed) itemInstance.addClass('tn-drag__fixed')
    }
  })
}
var baseDataObserver = function(newVal, oldVal, ownerInstance, instance) {
  var state = ownerInstance.getState()
  state.basedata = newVal
}
var longPress = function(event, ownerInstance) {
  var instance = event.instance
  var dataset = instance.getDataset()
  var state = ownerInstance.getState()
  edit = bool(dataset.edit)
  if (!edit) return
  if (!state.basedata || state.basedata === 'undefined') {
    state.basedata = JSON.parse(dataset.basedata)
  }
  var basedata = state.basedata
  var touches = event.changedTouches[0]
  if (!touches) return
  state.current = +dataset.index
  // åˆå§‹é¡¹æ˜¯å›ºå®šé¡¹åˆ™è¿”回
  var item = state.list[state.current]
  if (item && item.fixed) return
  // å¦‚果已经在 drag ä¸­åˆ™è¿”回, é˜²æ­¢å¤šæŒ‡è§¦å‘ drag åŠ¨ä½œ, touchstart äº‹ä»¶ä¸­æœ‰æ•ˆæžœ
  if (state.dragging) return
  ownerInstance.callMethod("drag", {
    dragging: true
  })
  // è®¡ç®—X, Y轴初始位移,使item中心移动到点击处,单列的时候X轴初始不做位移
  state.translateX = basedata.columns === 1 ? 0 : touches.pageX - (basedata.itemWidth / 2 + basedata.left)
  state.translateY = touches.pageY - (basedata.itemHeight / 2 + basedata.top)
  state.touchId = touches.identifier
  instance.setStyle({
    'transform': 'translate3d(' + state.translateX + 'px,' + state.translateY +'px, 0)'
  })
  state.itemsInstance.forEach(function(item, index) {
    item.removeClass("tn-drag__transition").removeClass("tn-drag__current")
    item.addClass(index === state.current ? "tn-drag__current" : "tn-drag__transition")
  })
  ownerInstance.callMethod("vibrate")
  state.dragging = true
}
var touchStart = function(event, ownerInstance) {
  var instance = event.instance
  var dataset = instance.getDataset()
  edit = bool(dataset.edit)
}
var touchMove = function(event, ownerInstance) {
  var instance = event.instance
  var dataset = instance.getDataset()
  var state = ownerInstance.getState()
  var basedata = state.basedata
  if (!state.dragging || !edit) return
  var touches = event.changedTouches[0]
  if (!touches) return
  // å¦‚果不是同一个触发点则返回
  if (state.touchId !== touches.identifier) return
  // è®¡ç®—X,Y轴位移, å•列时候X轴初始不做位移
  var translateX = basedata.columns === 1 ? 0 : touches.pageX - (basedata.itemWidth / 2 + basedata.left)
  var translateY = touches.pageY - (basedata.itemHeight / 2 + basedata.top)
  // åˆ°é¡¶åˆ°ä½Žè‡ªåŠ¨æ»‘åŠ¨
  if (touches.clientY > basedata.windowHeight - basedata.itemHeight - basedata.realBottomSize) {
    // å½“前触摸点pageY + item高度 - (屏幕高度 - åº•部固定区域高度)
    ownerInstance.callMethod('pageScroll', {
      scrollTop: touches.pageY + basedata.itemHeight - (basedata.windowHeight - basedata.realBottomSize)
    })
  } else if (touches.clientY < basedata.itemHeight + basedata.realTopSize) {
    // å½“前触摸点pageY - item高度 - é¡¶éƒ¨å›ºå®šåŒºåŸŸé«˜
    ownerInstance.callMethod('pageScroll', {
      scrollTop: touches.pageY - basedata.itemHeight - basedata.realTopSize
    })
  }
  // è®¾ç½®å½“前激活元素的偏移量
  instance.setStyle({
    'transform': 'translate3d('+ translateX + 'px,' + translateY + 'px, 0)'
  })
  var startKey = state.list[state.current].sortKey
  var currentX = Math.round(translateX / basedata.itemWidth)
  var currentY = Math.round(translateY / basedata.itemHeight)
  var endKey = currentX + basedata.columns * currentY
  // ç›®æ ‡é¡¹æ—¶å›ºå®šé¡¹åˆ™è¿”回
  var item = state.list[endKey]
  if (item && item.fixed) return
  // X轴或者Y轴超出范围则返回
  if (isOutRange(currentX, basedata.columns, currentY, basedata.rows, endKey, state.list.length)) return
  // é˜²æ­¢æ‹–拽过程中发生乱序问题
  if (startKey === endKey || startKey === state.preStartKey) return
  state.preStartKey = startKey
  var list = sortCore(startKey, endKey, state)
  state.itemsInstance.forEach(function(itemInstance, index) {
    var item = list[index]
    if (index !== state.current) {
      itemInstance.setStyle({
        'transform': 'translate3d('+ item.translateX + ',' + item.translateY +', 0)'
      })
    }
  })
  // ownerInstance.callMethod('vibrate')
  ownerInstance.callMethod('listDataChange', {
    data: list
  })
  triggerCustomEvent(list, "change", ownerInstance)
}
var touchEnd = function(event, ownerInstance) {
  var instance = event.instance
  var dataset = instance.getDataset()
  var state = ownerInstance.getState()
  var basedata = state.basedata
  if (!state.dragging || !edit) return
  triggerCustomEvent(state.list, "sortEnd", ownerInstance)
  instance.addClass('tn-drag__transition')
  instance.setStyle({
    'transform': 'translate3d('+ state.list[state.current].translateX + ',' + state.list[state.current].translateY + ', 0)'
  })
  state.itemsInstance.forEach(function(item, index) {
    item.removeClass('tn-drag__transition')
  })
  state.preStartKey = -1
  state.dragging = false
  ownerInstance.callMethod('drag', {
    dragging: false
  })
  state.current = -1
  state.translateX = 0
  state.translateY = 0
}
module.exports = {
    longPress: longPress,
    touchStart: touchStart,
    touchMove: touchMove,
    touchEnd: touchEnd,
    baseDataObserver: baseDataObserver,
    listObserver: listObserver
}
¼ª°²PDA/tuniao-ui/components/tn-drag/tn-drag.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,278 @@
<template>
  <view
    class="tn-drag-class tn-drag"
    :style="{
      height: wrapHeight + 'rpx'
    }"
    :list="listData"
    :basedata="baseData"
    :change:list="wxs.listObserver"
    :change:basedata="wxs.baseDataObserver"
  >
    <!-- #ifdef MP-WEIXIN -->
    <view
      v-for="(item, index) in listData"
      :key="item.id"
      class="tn-drag__item"
      :style="{
        width: 100 / columns + '%',
        height: itemHeight + 'rpx'
      }"
      :data-index="index"
      :data-basedata="baseData"
      :data-edit="edit"
      @longpress="wxs.longPress"
      @touchstart="wxs.touchStart"
      :catch:touchmove="dragging?wxs.touchMove:''"
      :catch:touchend="dragging?wxs.touchEnd:''"
    >
      <slot :entity="item.data" :fixed="item.fixed" :index="index" :height="itemHeight" :isEdit="edit"></slot>
    </view>
    <!-- #endif -->
    <!-- #ifndef MP-WEIXIN -->
    <view
      v-for="(item, index) in listData"
      :key="item.id"
      class="tn-drag__item"
      :style="{
        width: 100 / columns + '%',
        height: itemHeight + 'rpx'
      }"
      @longpress="wxs.longPress"
      :data-index="index"
      :data-basedata="baseData"
      :data-edit="edit"
      @touchstart="wxs.touchStart"
      @touchmove="wxs.touchMove"
      @touchend="wxs.touchEnd"
    >
      <slot :entity="item.data" :fixed="item.fixed" :index="index" :height="itemHeight" :isEdit="edit"></slot>
    </view>
    <!-- #endif -->
  </view>
</template>
<script src="./index.wxs" lang="wxs" module="wxs"></script>
<script>
  export default {
    name: 'tn-drag',
    props: {
      // æ•°æ®æº
      // å¦‚果属性中包含fixed,则标识当前数据不允许拖动
      list: {
        type: Array,
        default () {
          return []
        }
      },
      // æ˜¯å¦å…è®¸æ‹–动编辑
      edit: {
        type: Boolean,
        default: true
      },
      // åˆ—æ•°
      columns: {
        type: Number,
        default: 3
      },
      // item元素高度, å•位rpx
      itemHeight: {
        type: Number,
        default: 0
      },
      // å½“前父元素滚动的高度
      scrollTop: {
        type: Number,
        default: 0
      }
    },
    computed: {
      wrapHeight() {
        return this.rows * this.itemHeight
      }
    },
    data() {
      return {
        // æœªæ¸²æŸ“前节点数据
        baseData: {},
        // æ‹–动后的数据
        dragData: [],
        // è¡Œæ•°
        rows: 0,
        // æ¸²æŸ“数据
        listData: [],
        // æ ‡è®°æ˜¯å¦æ­£åœ¨æ‹–动
        dragging: false
      }
    },
    watch: {
      list(val) {
        this.listData = []
        this.$nextTick(() => {
          this.init()
        })
      },
      columns(val) {
        this.listData = []
        this.$nextTick(() => {
          this.init()
        })
      }
    },
    mounted() {
      this.$nextTick(() => {
        this.init()
      })
    },
    methods: {
      // åˆå§‹åŒ–
      init() {
        this.dragging = true
        const initDragItem = item => {
          const obj = {
            ...item
          }
          const fixed = obj?.fixed || false
          delete obj["fixed"]
          return {
            id: this.unique(),
            fixed,
            data: {
              ...obj
            }
          }
        }
        let i = 0
        const listData = (this.list || []).map((item, index) => {
          let listItem = initDragItem(item)
          // çœŸå®žæŽ’序
          listItem.realKey = i++
          // æ•´ä½“排序
          listItem.sortKey = index
          listItem.translateX = `${(listItem.sortKey % this.columns) * 100}%`
          listItem.translateY = `${Math.floor(listItem.sortKey / this.columns) * 100}%`
          return listItem
        })
        this.rows = Math.ceil(listData.length / this.columns)
        this.listData = listData
        this.dragData = listData
        if (listData.length === 0) return
        // console.log(listData);
        // åˆå§‹åŒ–dom元素
        this.$nextTick(() => {
          this.initRect()
        })
      },
      // åˆå§‹åŒ–dom元素
      initRect() {
        const {
          windowWidth,
          windowHeight
        } = uni.getSystemInfoSync()
        let baseData = {}
        baseData.windowHeight = windowHeight
        baseData.realTopSize = 0
        baseData.realBottomSize = 0
        baseData.columns = this.columns
        baseData.rows = this.rows
        const query = uni.createSelectorQuery().in(this)
        query.select('.tn-drag').boundingClientRect()
        query.select('.tn-drag__item').boundingClientRect()
        query.exec(res => {
          if (!res) {
            setTimeout(() => {
              this.initRect()
            }, 10)
            return
          }
          baseData.itemWidth = res[1].width
          baseData.itemHeight = res[1].height
          baseData.left = res[0].left
          baseData.top = res[0].top + this.scrollTop
          this.dragging = false
          this.baseData = baseData
        })
      },
      // è§¦å‘震动
      vibrate() {
        uni.vibrateShort()
      },
      // æ»šåŠ¨åˆ°æŒ‡å®šçš„ä½ç½®
      pageScroll(e) {
        uni.pageScrollTo({
          scrollTop: e.scrollTop,
          duration: 0
        })
      },
      // ä¿®æ”¹æ‹–动状态
      drag(e) {
        this.dragging = e.dragging
      },
      // æ‹–拽数据发生改变
      listDataChange(e) {
        this.dragData = e.data
      },
      // item被点击
      itemClick(index) {
        const item = this.dragData[index]
        this.$emit('click', {
          key: item.realKey,
          data: item.data
        })
      },
      // æ‹–拽结束事件
      sortEnd(e) {
        this.$emit('end', {
          data: e.data
        })
      },
      // æŽ’序发生改变事件
      change(e) {
        this.$emit('change', {
          data: e.data
        })
      },
      // ç”Ÿæˆå…ƒç´ å”¯ä¸€id
      unique(n = 6) {
        let id = ''
        for (let i = 0; i < n; i++) id += Math.floor(Math.random() * 10)
        return 'tn_' + new Date().getTime() + id
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-drag {
    position: relative;
    &__item {
      position: absolute;
      z-index: 2;
      top: 0;
      left: 0;
    }
    &__transition {
      transition: transform 0.25s !important;
    }
    &__current {
      z-index: 10 !important;
    }
    &__fixed {
      z-index: 1 !important;
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-empty/tn-empty.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,190 @@
<template>
  <view v-if="show" class="tn-empty-class tn-empty" :style="[emptyStyle]">
    <view
      v-if="!isImage"
      class="tn-empty__icon"
      :class="[icon ? `tn-icon-${icon}` : `tn-icon-empty-${mode}`]"
      :style="[iconStyle]"
    ></view>
    <image
      v-else
      class="tn-empty__image"
      :style="[imageStyle]"
      :src="icon"
      mode="widthFix"
    ></image>
    <view
      class="tn-empty__text"
      :style="[textStyle]"
    >{{ text ? text : icons[mode]}}</view>
    <view v-if="$slots.default || $slots.$default" class="tn-empty__slot">
      <slot/>
    </view>
  </view>
</template>
<script>
  export default {
    name: 'tn-empty',
    props: {
      // æ˜¾ç¤ºç©ºç™½é¡µ
      show: {
        type: Boolean,
        default: true
      },
      // å†…ç½®icon的名称
      // å›¾ç‰‡è·¯å¾„,建议使用绝对路径
      icon: {
        type: String,
        default: ''
      },
      // é¢„置图标类型
      mode: {
        type: String,
        default: 'data'
      },
      // æç¤ºæ–‡å­—
      text: {
        type: String,
        default: ''
      },
      // æ–‡å­—颜色
      textColor: {
        type: String,
        default: ''
      },
      // æ–‡å­—大小,单位rpx
      textSize: {
        type: Number,
        default: 0
      },
      // å›¾æ ‡é¢œè‰²
      iconColor: {
        type: String,
        default: ''
      },
      // å›¾æ ‡å¤§å°ï¼Œå•位rpx
      iconSize: {
        type: Number,
        default: 0
      },
      // å›¾ç‰‡å®½åº¦ï¼ˆå½“图标为图片时生效),单位rpx
      imgWidth: {
        type: Number,
        default: 0
      },
      // å›¾ç‰‡é«˜åº¦ï¼ˆå½“图标为图片时生效),单位rpx
      imgHeight: {
        type: Number,
        default: 0
      },
      // è‡ªå®šä¹‰ç»„件样式
      customStyle: {
        type: Object,
        default() {
          return {}
        }
      }
    },
    computed: {
      emptyStyle() {
        let style = {}
        Object.assign(style, this.customStyle)
        return style
      },
      iconStyle() {
        let style = {}
        if (this.iconSize) {
          style.fontSize = this.iconSize + 'rpx'
        }
        if (this.iconColor) {
          style.color = this.iconColor
        }
        return style
      },
      imageStyle() {
        let style = {}
        if (this.imgWidth) {
          style.width = this.imgWidth + 'rpx'
        }
        if (this.imgHeight) {
          style.height = this.imgHeight + 'rpx'
        }
        return style
      },
      textStyle() {
        let style = {}
        if (this.textColor) {
          style.color = this.textColor
        }
        if (this.textSize) {
          style.fontSize = this.textSize + 'rpx'
        }
        return style
      },
      // åˆ¤æ–­ä¼ é€’çš„icon是否为图片
      isImage() {
        return this.icon.indexOf('/') >= 0
      }
    },
    data() {
      return {
        icons: {
          cart: '购物车为空',
          page: '页面不存在',
          search: '搜索结果为空',
          address: '地址为空',
          network: '网络不通',
          order: '订单为空',
          coupon: '优惠券为空',
          favor: '暂无收藏',
          permission: '无权限',
          history: '历史记录为空',
          message: '暂无消息',
          list: '列表为空',
          data: '暂无数据',
          comment: '暂无评论'
        }
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    &__icon {
      margin-top: 14rpx;
      color: #AAAAAA;
      font-size: 90rpx;
    }
    &__image {
      width: 160rpx;
      height: 160rpx;
    }
    &__text {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      margin-top: 20rpx;
      color: #AAAAAA;
      font-size: 30rpx;
    }
    &__slot {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      margin-top: 20rpx;
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-fab/tn-fab.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,523 @@
<template>
  <view class="tn-fab-class tn-fab" @touchmove.stop.prevent>
    <view
      class="tn-fab__box"
      :class="{'tn-fab--right': left === 'auto'}"
      :style="{
        left: $t.string.getLengthUnitValue(fabLeft || left),
        right: $t.string.getLengthUnitValue(fabRight || right),
        bottom: $t.string.getLengthUnitValue(fabBottom || bottom),
        zIndex: elZIndex
      }"
    >
      <view
        v-if="visibleSync"
        class="tn-fab__btns"
        :class="[`tn-fab__btns__animation--${animationType}`,
          showFab ? `tn-fab__btns--visible--${animationType}` : ''
        ]"
      >
        <view
          v-for="(item, index) in btnList"
          :key="index"
          class="tn-fab__item"
          :class="[
            `tn-fab__item__animation--${animationType}`,
            {'tn-fab__item--left': right === 'auto'}
          ]"
          :style="[fabItemStyle(index)]"
          @tap.stop="handleClick(index)"
        >
          <!-- å¸¦å›¾æ ‡æˆ–者图片时显示的文字信息 -->
          <view
            v-if="animationType !== 'around' && (item.imgUrl || item.icon)"
            :class="[left === 'auto' ? 'tn-fab__item__text--right' : 'tn-fab__item__text--left']"
            :style="{
              color: item.textColor || '#FFF',
              fontSize: $t.string.getLengthUnitValue(item.textSize || 28)
            }"
          >{{ item.text || '' }}</view>
          <!-- å¸¦å›¾ç‰‡æˆ–者图标时的图片、图标信息 -->
          <view
            class="tn-fab__item__btn"
            :class="[!item.bgColor ? backgroundColorClass : '']"
            :style="{
              width: $t.string.getLengthUnitValue(width),
              height: $t.string.getLengthUnitValue(height),
              lineHeight: $t.string.getLengthUnitValue(height),
              backgroundColor: item.bgColor || backgroundColorStyle || '#01BEFF',
              borderRadius: $t.string.getLengthUnitValue(radius)
            }"
          >
            <!-- æ— å›¾ç‰‡å’Œæ— å›¾æ ‡æ—¶åªæ˜¾ç¤ºæ–‡å­— -->
            <view
              v-if="!item.imgUrl && !item.icon"
              class="tn-fab__item__btn__title"
              :style="{
                color: item.textColor || '#fff',
                fontSize: $t.string.getLengthUnitValue(item.textSize || 28)
              }"
            >{{ item.text || '' }}</view>
            <!-- å›¾æ ‡ -->
            <view
              v-if="item.icon"
              class="tn-fab__item__btn__icon"
              :class="[`tn-icon-${item.icon}`]"
              :style="{
                color: item.iconColor || '#fff',
                fontSize: $t.string.getLengthUnitValue(item.iconSize || iconSize || 64)
              }"
            ></view>
            <!-- å›¾ç‰‡ -->
            <image
              v-else-if="!item.icon && item.imgUrl"
              class="tn-fab__item__btn__image"
              :style="{
                width: $t.string.getLengthUnitValue(item.imgWidth || 64),
                height: $t.string.getLengthUnitValue(item.imgHeight || 64),
              }"
              :src="item.imgUrl"
            ></image>
          </view>
        </view>
      </view>
      <view
        class="tn-fab__item__btn tn-fab__item__btn--fab"
        :class="[backgroundColorClass, fontColorClass, {'tn-fab__item__btn--active': showFab}]"
        :style="{
          width: $t.string.getLengthUnitValue(width),
          height: $t.string.getLengthUnitValue(height),
          backgroundColor: backgroundColorStyle || !backgroundColorClass ? '#01BEFF' : '',
          color: fontColorStyle || '#fff',
          borderRadius: $t.string.getLengthUnitValue(radius),
          zIndex: elZIndex - 1
        }"
        @tap.stop="fabClick"
      >
        <slot>
          <view class="tn-fab__item__btn__icon" :class="[`tn-icon-${icon}`]" :style="{fontSize: $t.string.getLengthUnitValue(iconSize || 64)}"></view>
        </slot>
      </view>
    </view>
    <view v-if="visibleSync && showMask" class="tn-fab__mask" :class="{'tn-fab__mask--visible': showFab}" :style="{zIndex: elZIndex - 3}" @tap="clickMask()"></view>
  </view>
</template>
<script>
  import componentsColorMixin from '../../libs/mixin/components_color.js'
  export default {
    name: 'tn-fab',
    mixins: [componentsColorMixin],
    props: {
      // æŒ‰é’®åˆ—表
      // {
      //   // èƒŒæ™¯é¢œè‰²
      //   bgColor: '#fff',
      //   // å›¾ç‰‡åœ°å€
      //   imgUrl: '',
      //   // å›¾ç‰‡å®½åº¦
      //   imgWidth: 60,
      //   // å›¾ç‰‡é«˜åº¦
      //   imgHeight: 60,
      //   // å›¾æ ‡åç§°
      //   icon: '',
      //   // å›¾æ ‡å°ºå¯¸
      //   iconSize: 60,
      //   // å›¾æ ‡é¢œè‰²
      //   iconColor: '#fff',
      //   // æç¤ºæ–‡å­—
      //   text: '',
      //   // æ–‡å­—大小
      //   textSize: 30,
      //   // å­—体颜色
      //   textColor: '#fff'
      // }
      btnList: {
        type: Array,
        default() {
          return []
        }
      },
      // è‡ªå®šä¹‰æ‚¬æµ®æŒ‰é’®å†…容
      customBtn: {
        type: Boolean,
        default: false
      },
      // æ‚¬æµ®æŒ‰é’®çš„宽度
      width: {
        type: [String, Number],
        default: 88
      },
      // æ‚¬æµ®æŒ‰é’®çš„高度
      height: {
        type: [String, Number],
        default: 88
      },
      // å›¾æ ‡å¤§å°
      iconSize: {
        type: [String, Number],
        default: 64
      },
      // å›¾æ ‡åç§°
      icon: {
        type: String,
        default: 'open'
      },
      // æŒ‰é’®åœ†è§’
      radius: {
        type: [String, Number],
        default: '50%'
      },
      // æŒ‰é’®è·ç¦»å·¦è¾¹çš„位置
      left: {
        type: [String, Number],
        default: 'auto'
      },
      // æŒ‰é’®è·ç¦»å³è¾¹çš„位置
      right: {
        type: [String, Number],
        default: 'auto'
      },
      // æŒ‰é’®è·ç¦»åº•部的位置
      bottom: {
        type: [String, Number],
        default: 100
      },
      // å±•示动画类型 up å¾€ä¸Šå±•示 around çŽ¯ç»•
      animationType: {
        type: String,
        default: 'up'
      },
      // å½“动画为圆环时,每个弹出按钮之间的距离, å•位px
      aroundBtnDistance: {
        type: Number,
        default: 10
      },
      zIndex: {
        type: Number,
        default: 0
      },
      // æ˜¾ç¤ºé®ç½©
      showMask: {
        type: Boolean,
        default: true
      },
      // ç‚¹å‡»é®ç½©æ˜¯å¦å¯ä»¥å…³é—­
      maskCloseable: {
        type: Boolean,
        default: true
      }
    },
    data() {
      return {
        showFab: false,
        visibleSync: false,
        timer: null,
        fabLeft: 0,
        fabRight: 0,
        fabBottom: 0,
        fabBtnInfo: {
          width: 0,
          height: 0,
          left: 0,
          right: 0,
          bottom: 0
        },
        systemInfo: {
          width: 0,
          height: 0
        },
        updateProps: false
      }
    },
    computed: {
      elZIndex() {
        return this.zIndex || this.$t.zIndex.fab
      },
      propsData() {
        return [this.width, this.height, this.left, this.right, this.bottom]
      },
      fabItemStyle() {
        return (index) => {
          let style = {
            zIndex: this.elZIndex - 2
          }
          if (this.animationType === 'up' || !this.showFab) {
            return style
          }
          let base = 1
          if (this.left === 'auto') {
            base = 1
          } else if (this.right === 'auto') {
            base = -1
          }
          style.transform = `rotate(${base * index * 60}deg) translateX(${(this.aroundBtnDistance + this.fabBtnInfo.width) * (-(base))}px)`
          return style
        }
      }
    },
    watch: {
      propsData() {
        // æ›´æ–°æŒ‰é’®ä¿¡æ¯
        this.updateProps = true
      }
    },
    mounted() {
      this.$nextTick(() => {
        this.getFabBtnRectInfo()
      })
    },
    beforeDestroy() {
      if (this.timer) {
        clearTimeout(this.timer)
      }
    },
    methods: {
      // æŒ‰é’®ç‚¹å‡»äº‹ä»¶
      handleClick(index) {
        this.close()
        this.$emit('click', {index: index})
      },
      // ç‚¹å‡»æ‚¬æµ®æŒ‰é’®
      fabClick() {
        if (this.showFab) {
          this.close()
        } else {
          // console.log(this.visibleSync);
          if (this.visibleSync) {
            this.visibleSync = false
            return
          }
          this.open()
        }
      },
      // ç‚¹å‡»é®ç½©
      clickMask() {
        if (!this.showMask || !this.maskCloseable) return
        this.close()
      },
      open() {
        this.change('visibleSync', 'showFab', true)
        this.translateFabPosition()
      },
      close() {
        this.change('showFab', 'visibleSync', false)
        this.fabLeft = 0
        this.fabRight = 0
        this.fabBottom = 0
      },
      // å…³é—­æ—¶å…ˆé€šè¿‡åŠ¨ç”»éšè—å¼¹çª—å’Œé®ç½©ï¼Œå†ç§»é™¤æ•´ä¸ªç»„ä»¶
      // æ‰“开时,先渲染组件,延时一定时间再让遮罩和弹窗的动画起作用
      change(param1, param2, status) {
        this[param1] = status
        if (status) {
          // #ifdef H5 || MP
          this.timer = setTimeout(() => {
            this[param2] = status
            this.$emit(status ? 'open' : 'close')
            clearTimeout(this.timer)
          }, 10)
          // #endif
          // #ifndef H5 || MP
          this.$nextTick(() => {
            this[param2] = status
            this.$emit(status ? 'open' : 'close')
          })
          // #endif
        } else {
          this.timer = setTimeout(() => {
            this[param2] = status
            this.$emit(status ? 'open' : 'close')
            clearTimeout(this.timer)
          }, 250)
        }
      },
      /******************** æ—‹è½¬åŠ¨ç”»ç›¸å…³å‡½æ•° ********************/
      // èŽ·å–æŒ‰é’®çš„ä¿¡æ¯
      async getFabBtnRectInfo() {
        const systemInfo = uni.getSystemInfoSync()
        const btnRectInfo = await this._tGetRect('.tn-fab__item__btn--fab')
        if (!btnRectInfo) {
          setTimeout(() => {
            this.getFabBtnRectInfo()
          }, 10)
          return
        }
        console.log(btnRectInfo);
        this.systemInfo = {
          width: systemInfo.windowWidth,
          height: systemInfo.windowHeight
        }
        this.fabBtnInfo.width = btnRectInfo.width
        this.fabBtnInfo.height = btnRectInfo.height
        this.fabBtnInfo.left = btnRectInfo.left
        this.fabBtnInfo.right = btnRectInfo.right
        this.fabBtnInfo.bottom = btnRectInfo.bottom
      },
      // æ›´æ–°æ‚¬æµ®æŒ‰é’®çš„位置
      translateFabPosition() {
        if (this.updateProps) {
          this.getFabBtnRectInfo()
          this.updateProps = false
        }
        if (this.animationType === 'up') return
        // æŒ‰é’®ç»„的宽度
        const btnGroupWidth = this.fabBtnInfo.width + this.aroundBtnDistance + 10
        // åˆ¤æ–­å½“前按钮是在左边还是右边
        if (this.left === 'auto' && btnGroupWidth > this.systemInfo.width - this.fabBtnInfo.right) {
          // è·ç¦»ä¸å¤Ÿéœ€è¦ç§»åЍ
          this.fabRight = btnGroupWidth + 'px'
        } else if (this.right === 'auto' && btnGroupWidth > this.fabBtnInfo.left) {
          this.fabLeft = btnGroupWidth + 'px'
        }
        if (btnGroupWidth > this.systemInfo.height - this.fabBtnInfo.bottom) {
          this.fabBottom = btnGroupWidth + 'px'
        }
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-fab {
    &__box {
      display: flex;
      justify-content: center;
      align-items: flex-start;
      flex-direction: column;
      position: fixed;
      transition: all 0.25s ease-in-out;
    }
    &--right {
      align-items: flex-end;
    }
    &__btns {
      transition: all 0.25s cubic-bezier(0,.13,0,1.43);
      transform-origin: 80% bottom;
      &__animation--up {
        opacity: 0;
        transform: translateY(100%);
      }
      &__animation--around {
        position: absolute;
        top: 0;
        left: 0;
      }
      &--visible--up {
        // visibility: visible;
        opacity: 1;
        transform: translateY(0);
      }
      &--visible--around {
        // visibility: visible;
        // opacity: 1;
      }
    }
    &__item {
      display: flex;
      justify-content: flex-end;
      align-items: center;
      padding-bottom: 20rpx;
      &__animation--around {
        position: absolute;
        top: 0;
        left: 0;
        transition: transform 0.25s ease-in-out;
        transform-origin: 50% 50%;
        padding-bottom: 0 !important;
      }
      &--left {
        flex-flow: row-reverse;
      }
      &__text {
        &--left {
          padding-left: 14rpx;
        }
        &--right {
          padding-right: 14rpx;
        }
      }
      &__btn {
        display: flex;
        align-items: center;
        justify-content: center;
        box-shadow: 0 0 5rpx 2rpx rgba(0, 0, 0, 0.07);
        transition: all 0.2s linear;
        &--active {
          animation-name: fab-button-animation;
          animation-duration: 0.2s;
          animation-timing-function: cubic-bezier(0,.13,0,1.43);
        }
        &__title {
          width: 90%;
          text-align: center;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
        }
        &__icon {
          text-align: center;
          font-size: 64rpx;
        }
        &__image {
          display: block;
        }
      }
    }
    &__mask {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: $tn-mask-bg-color;
      transition: all 0.2s ease-in-out;
      opacity: 0;
      &--visible {
        opacity: 1;
      }
    }
  }
  @keyframes fab-button-animation {
    0% {
      transform: scale(0.6);
    }
    // 20% {
    //   transform: scale(1.8);
    // }
    // 40% {
    //   transform: scale(0.4);
    // }
    // 50% {
    //   transform: scale(1.4);
    // }
    // 80% {
    //   transform: scale(0.8);
    // }
    100% {
      transform: scale(1);
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-form-item/tn-form-item.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,457 @@
<template>
  <view
    class="tn-form-item-class tn-form-item"
    :class="{
      'tn-border-solid-bottom': elBorderBottom,
      'tn-form-item__border-bottom--error': validateState === 'error' && showError('border-bottom')
    }"
  >
    <view
      class="tn-form-item__body"
      :style="{
        flexDirection: elLabelPosition == 'left' ? 'row' : 'column'
      }"
    >
      <!-- å¤„理微信小程序中设置属性的问题,不设置值的时候会变成true -->
      <view
        class="tn-form-item--left"
        :style="{
          width: wLabelWidth,
          flex: `0 0 ${wLabelWidth}`,
          marginBottom: elLabelPosition == 'left' ? 0 : '10rpx'
        }"
      >
        <!-- å—对齐 -->
        <view v-if="required || leftIcon || label" class="tn-form-item--left__content"
          :style="[leftContentStyle]"
        >
          <!-- nvue不支持伪元素before -->
          <view v-if="leftIcon" class="tn-form-item--left__content__icon">
            <view :class="[`tn-icon-${leftIcon}`]" :style="leftIconStyle"></view>
          </view>
          <!-- <view
            class="tn-form-item--left__content__label"
            :style="[elLabelStyle, {
              'justify-content': elLabelAlign === 'left' ? 'flex-satrt' : elLabelAlign === 'center' ? 'center' : 'flex-end'
            }]"
          >
            {{label}}
          </view> -->
          <view
            class="tn-form-item--left__content__label"
            :style="[elLabelStyle]"
          >
            {{label}}
          </view>
          <text v-if="required" class="tn-form-item--left__content--required">*</text>
        </view>
      </view>
      <view class="tn-form-item--right tn-flex">
        <view class="tn-form-item--right__content">
          <view class="tn-form-item--right__content__slot">
            <slot></slot>
          </view>
          <view v-if="$slots.right || rightIcon" class="tn-form-item--right__content__icon tn-flex">
            <view v-if="rightIcon" :class="[`tn-icon-${rightIcon}`]" :style="rightIconStyle"></view>
            <slot name="right"></slot>
          </view>
        </view>
      </view>
    </view>
    <view
      v-if="validateState === 'error' && showError('message')"
      class="tn-form-item__message"
      :style="{
        paddingLeft: elLabelPosition === 'left' ? elLabelWidth + 'rpx' : '0'
      }"
    >
      {{validateMessage}}
    </view>
  </view>
</template>
<script>
  import Emitter from '../../libs/utils/emitter.js'
  import schema from '../../libs/utils/async-validator.js'
  // åŽ»é™¤è­¦å‘Šä¿¡æ¯
  schema.warning = function() {}
  export default {
    mixins: [Emitter],
    name: 'tn-form-item',
    inject: {
      tnForm: {
        default() {
          return null
        }
      }
    },
    props: {
      // label提示语
      label: {
        type: String,
        default: ''
      },
      // ç»‘定的值
      prop: {
        type: String,
        default: ''
      },
      // æ˜¯å¦æ˜¾ç¤ºè¡¨å•域的下划线边框
      borderBottom: {
        type:Boolean,
        default: true
      },
      // label(标签名称)的位置
      // left - å·¦è¾¹
      // top - ä¸Šè¾¹
      labelPosition: {
        type: String,
        default: ''
      },
      // label的宽度
      labelWidth: {
        type: Number,
        default: 0
      },
      // label的对齐方式
      // left - å·¦å¯¹é½
      // top - ä¸Šå¯¹é½
      // right - å³å¯¹é½
      // bottom - ä¸‹å¯¹é½
      labelAlign: {
        type: String,
        default: ''
      },
      // label çš„æ ·å¼
      labelStyle: {
        type: Object,
        default() {
          return {}
        }
      },
      // å·¦ä¾§å›¾æ ‡
      leftIcon: {
        type: String,
        default: ''
      },
      // å³ä¾§å›¾æ ‡
      rightIcon: {
        type: String,
        default: ''
      },
      // å·¦ä¾§å›¾æ ‡æ ·å¼
      leftIconStyle: {
        type: Object,
        default() {
          return {}
        }
      },
      // å³ä¾§å›¾æ ‡æ ·å¼
      rightIconStyle: {
        type: Object,
        default() {
          return {}
        }
      },
      // æ˜¯å¦æ˜¾ç¤ºå¿…填项的*,不做校验用途
      required: {
        type: Boolean,
        default: false
      }
    },
    computed: {
      // å¤„理微信小程序label的宽度
      wLabelWidth() {
        // å¦‚果用户设置label为空字符串(微信小程序空字符串最终会变成字符串的'true'),意味着要将label的位置宽度设置为auto
        return this.elLabelPosition === 'left' ? (this.label === 'true' || this.label === '' ? 'auto' : this.elLabelWidth + 'rpx') : '100%'
      },
      // æ˜¯å¦æ˜¾ç¤ºé”™è¯¯æç¤º
      showError() {
        return type => {
          if (this.errorType.indexOf('none') >= 0) return false
          else if (this.errorType.indexOf(type) >= 0) return true
          else return false
        }
      },
      // label的宽度(默认值为90)
      elLabelWidth() {
        return this.labelWidth != 0 ? this.labelWidth : (this.parentData.labelWidth != 0 ? this.parentData.labelWidth : 90)
      },
      // label的样式
      elLabelStyle() {
        return Object.keys(this.labelStyle).length ? this.labelStyle : (Object.keys(this.parentData.labelStyle).length ? this.parentData.labelStyle : {})
      },
      // label显示位置
      elLabelPosition() {
        return this.labelPosition ? this.labelPosition : (this.parentData.labelPosition ? this.parentData.labelPosition : 'left')
      },
      // label对齐方式
      elLabelAlign() {
        return this.labelAlign ? this.labelAlign : (this.parentData.labelAlign ? this.parentData.labelAlign : 'left')
      },
      // label下划线
      elBorderBottom() {
        return this.borderBottom !== '' ? this.borderBottom : (this.parentData.borderBottom !== '' ? this.parentData.borderBottom : true)
      },
      leftContentStyle() {
        let style = {}
        if (this.elLabelPosition === 'left') {
          switch(this.elLabelAlign) {
            case 'left':
              style.justifyContent = 'flex-start'
              break
            case 'center':
              style.justifyContent = 'center'
              break
            default:
              style.justifyContent = 'flex-end'
              break
          }
        }
        return style
      }
    },
    data() {
      return {
        // é»˜è®¤å€¼
        initialValue: '',
        // æ˜¯å¦æ ¡éªŒæˆåŠŸ
        validateState: '',
        // æ ¡éªŒå¤±è´¥æç¤ºä¿¡æ¯
        validateMessage: '',
        // é”™è¯¯çš„æç¤ºæ–¹å¼ï¼ˆå‚考form组件)
        errorType: ['message'],
        // å½“前子组件输入的值
        fieldValue: '',
        // çˆ¶ç»„件的参数
        // ç”±äºŽå†computed中无法得知this.parent的变化,所以放在data中
        parentData: {
          borderBottom: true,
          labelWidth: 90,
          labelPosition: 'left',
          labelAlign: 'left',
          labelStyle: {},
        }
      }
    },
    watch: {
      validateState(val) {
        this.broadcastInputError()
      },
      "tnForm.errorType"(val) {
        this.errorType = val
        this.broadcastInputError()
      }
    },
    mounted() {
      // ç»„件创建完成后,保存当前实例到form组件中
      // æ”¯ä»˜å®ã€å¤´æ¡å°ç¨‹åºä¸æ”¯æŒprovide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环应用\
      this.parent = this.$t.$parent.call(this, 'tn-form')
      if (this.parent) {
        // éåކparentData属性,将parent中同名的属性赋值给parentData
        Object.keys(this.parentData).map(key => {
          this.parentData[key] = this.parent[key]
        })
        // å¦‚果没有传入prop或者tnForm为空(单独使用form-item组件的时候),就不进行校验
        if (this.prop) {
          // å°†æœ¬å®žä¾‹æ·»åŠ åˆ°çˆ¶ç»„ä»¶ä¸­
          this.parent.fields.push(this)
          this.errorType = this.parent.errorType
          // è®¾ç½®åˆå§‹å€¼
          this.initialValue = this.fieldValue
          // æ·»åŠ è¡¨å•æ ¡éªŒï¼Œè¿™é‡Œå¿…é¡»è¦å†™åœ¨$nextTick中,因为tn-form的rules是通过ref手动传入的
          // ä¸åœ¨$nextTick中的话,可能会造成执行此处代码时,父组件还没通过ref把规则给tn-form,导致规则为空
          this.$nextTick(() => {
            this.setRules()
          })
        }
      }
    },
    beforeDestroy() {
      // ç»„件销毁前,将实例从tn-form的缓存中移除
      // å¦‚果当前没有prop的话表示当前不进行删除
      if (this.parent && this.prop) {
        this.parent.fields.map((item, index) => {
          if (item === this) this.parent.fields.splice(index, 1)
        })
      }
    },
    methods: {
      // å‘input组件发出错误事件
      broadcastInputError() {
        this.broadcast('tn-input', 'on-form-item-error', this.validateState === 'error' && this.showError('border'))
      },
      // è®¾ç½®æ ¡éªŒè§„则
      setRules() {
        let that = this
        // ä»Žçˆ¶ç»„ä»¶tn-form拿到当前tn-form-item需要验证 çš„规则
        // let rules = this.getRules()
        // if (rules.length) {
        //     this.isRequired = rules.some(rule => {
        //         // å¦‚果有必填项,就返回,没有的话,就是undefined
        //         return rule.required
        //     })
        // }
        // blur事件
        this.$on('on-form-blur', that.onFieldBlur)
        // change事件
        this.$on('on-form-change', that.onFieldChange)
      },
      // ä»Žform的rules属性中取出当前form-item的校验规则
      getRules() {
        let rules = this.parent.rules
        rules = rules ? rules[this.prop] : []
        // è¿”回数值形式的值
        return [].concat(rules || [])
      },
      // blur事件时进行表单认证
      onFieldBlur() {
        this.validation('blur')
      },
      // change事件时进行表单认证
      onFieldChange() {
        this.validation('change')
      },
      // è¿‡æ»¤å‡ºç¬¦åˆè¦æ±‚çš„rule规则
      getFilterRule(triggerType = '') {
        let rules = this.getRules()
        // æ•´ä½“验证表单时,triggerType为空字符串,此时返回所有规则进行验证
        if (!triggerType) return rules
        // æŸäº›åœºæ™¯å¯èƒ½çš„判断规则,可能不存在trigger属性,故先判断是否存在此属性
        // åŽ†éåˆ¤æ–­è§„åˆ™æ˜¯å¦æœ‰å¯¹åº”çš„äº‹ä»¶ï¼Œæ¯”å¦‚blur,change触发等的事件
        // ä½¿ç”¨indexOf判断,是因为某些时候设置的验证规则的trigger属性可能为多个,比如['blur','change']
        return rules.filter(rule => rule.trigger && rule.trigger.indexOf(triggerType) !== -1)
      },
      // æ ¡éªŒæ•°æ®
      validation(trigger, callback = ()=>{}) {
        // æ ¡éªŒä¹‹å‰å…ˆèŽ·å–éœ€è¦æ ¡éªŒçš„å€¼
        this.fieldValue = this.parent.model[this.prop]
        // blur和change是否有当前方式的校验规则
        let rules = this.getFilterRule(trigger)
        // åˆ¤æ–­æ˜¯å¦æœ‰éªŒè¯è§„则,如果没有规则,也调用回调方法,否则父组件tn-form会因为
        // å¯¹count变量的统计错误而无法进入上一层的回调
        if (!rules || rules.length === 0) {
          return callback('')
        }
        // è®¾ç½®å½“前为校验中
        this.validateState = 'validating'
        // è°ƒç”¨async-validator的方法
        let validator = new schema({
          [this.prop]: rules
        })
        validator.validate({
          [this.prop]: this.fieldValue
        }, {
          firstFields: true
        }, (errors, fields) => {
          // è®°å½•状态和报错信息
          this.validateState = !errors ? 'success' : 'error'
          this.validateMessage = errors ? errors[0].message : ''
          callback(this.validateMessage)
        })
      },
      // æ¸…空当前item信息
      resetField() {
        this.parent.model[this.prop] = this.initialValue
        // æ¸…空错误标记
        this.validateState = 'success'
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-form-item {
    display: flex;
    flex-direction: column;
    padding: 20rpx 0;
    font-size: 28rpx;
    color: $tn-font-color;
    box-sizing: border-box;
    line-height: $tn-form-item-height;
    &__border-bottom--error:after {
      border-color: $tn-color-red;
    }
    &__body {
      display: flex;
      flex-direction: row;
    }
    &--left {
      display: flex;
      flex-direction: row;
      align-items: center;
      &__content {
        display: flex;
        flex-direction: row;
        position: relative;
        align-items: center;
        padding-right: 18rpx;
        flex: 1;
        &--required {
          position: relative;
          right: 0;
          vertical-align: middle;
          color: $tn-color-red;
        }
        &__icon {
          color: $tn-font-sub-color;
          margin-right: 8rpx;
        }
        &__label {
          // display: flex;
          // flex-direction: row;
          // align-items: center;
          // flex: 1;
        }
      }
    }
    &--right {
      flex: 1;
      &__content {
        display: flex;
        flex-direction: row;
        align-items: center;
        flex: 1;
        &__slot {
          flex: 1;
          /* #ifndef MP */
          display: flex;
          flex-direction: row;
          align-items: center;
          /* #endif */
        }
        &__icon {
          margin-left: 10rpx;
          color: $tn-font-sub-color;
          font-size: 30rpx;
        }
      }
    }
    &__message {
      font-size: 24rpx;
      line-height: 24rpx;
      color: $tn-color-red;
      margin-top: 12rpx;
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-form/tn-form.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,139 @@
<template>
  <view class="tn-form-class tn-form">
    <slot></slot>
  </view>
</template>
<script>
  export default {
    name: 'tn-form',
    props: {
      // è¡¨å•数据对象(需要验证的表单数据)
      model: {
        type: Object,
        default() {
          return {}
        }
      },
      // å‘生错误时的提示方式
      // toast - å¼¹å‡ºtoast框
      // message - æç¤ºä¿¡æ¯
      // border - å¦‚果设置了边框,边框会变成红色
      // border-bottom - ä¸‹è¾¹æ¡†ä¼šå‘ˆçŽ°çº¢è‰²
      // none - æ— æç¤º
      errorType: {
        type: Array,
        default() {
          return ['message', 'toast']
        }
      },
      // æ˜¯å¦æ˜¾ç¤ºè¡¨å•域的下划线边框
      borderBottom: {
        type:Boolean,
        default: true
      },
      // label(标签名称)的位置
      // left - å·¦è¾¹
      // top - ä¸Šè¾¹
      labelPosition: {
        type: String,
        default: 'left'
      },
      // label的宽度
      labelWidth: {
        type: Number,
        default: 90
      },
      // label的对齐方式
      // left - å·¦å¯¹é½
      // center - å±…中对齐
      // right - å³å¯¹é½
      labelAlign: {
        type: String,
        default: 'left'
      },
      // label çš„æ ·å¼
      labelStyle: {
        type: Object,
        default() {
          return {}
        }
      }
    },
    // å‘子孙传递数据
    provide() {
      return {
        tnForm: this
      }
    },
    data() {
      return {
        rules: {}
      }
    },
    created() {
      // å­˜å‚¨å½“前form下的所有form-item的实例
      // ä¸èƒ½å®šä¹‰å†data中,否则小程序会循环引用而报错
      this.fields = []
    },
    methods: {
      /**
       * è®¾ç½®è§„则
       *
       * @param {Object} rules
       */
      setRules(rules) {
        this.rules = rules
      },
      /**
       * æ¸…空form-item组件
       */
      resetFields() {
        this.fields.map(field => {
          field.resetField()
        })
      },
      /**
       * æ ¡éªŒæ•°æ®
       * @param {Object} callback æ ¡éªŒå›žè°ƒæ–¹æ³•
       */
      validate(callback) {
        return new Promise(resolve => {
          // æ ‡è®°æ ¡éªŒæ˜¯å¦é€šè¿‡
          let valid = true
          // æ ‡è®°æ˜¯å¦æ£€æŸ¥å®Œæ¯•
          let count = 0
          // å­˜æ”¾é”™è¯¯ä¿¡æ¯
          let errors = []
          // å¯¹æ‰€æœ‰form-item进行校验
          this.fields.map(field => {
            // è°ƒç”¨å¯¹åº”form-item实例的validation校验方法
            field.validation('', error => {
              // å¦‚果有一个form-item校验不通过,则整个表单校验不通过
              if (error) {
                valid = false
                errors.push(error)
              }
              // å½“遍历完所有的form-item的校验规则,返回信息
              if (++count === this.fields.length) {
                resolve(valid)
                // åˆ¤æ–­æ˜¯å¦è®¾ç½®äº†toast的提示方式,只提示表单域中最前面的一条错误信息
                if (this.errorType.indexOf('none') === -1 &&
                    this.errorType.indexOf('toast') >= 0 &&
                    errors.length > 0) {
                  this.$t.message.toast(errors[0])
                }
                // è°ƒç”¨å›žè°ƒæ–¹æ³•
                if (typeof callback == 'function') callback(valid)
              }
            })
          })
        })
      }
    }
  }
</script>
<style>
</style>
¼ª°²PDA/tuniao-ui/components/tn-goods-nav/tn-goods-nav.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,382 @@
<template>
  <view
    class="tn-goods-nav-class tn-goods-nav"
    :class="[
      backgroundColorClass,
      {
        'tn-goods-nav--fixed': fixed,
        'tn-safe-area-inset-bottom': safeAreaInsetBottom,
        'tn-goods-nav--shadow': shadow
      }
    ]"
    :style="[backgroundColorStyle, navStyle]"
  >
    <view class="options">
      <view
        v-for="(item, index) in optionsData"
        :key="index"
        class="options__item"
        :class="[{'options__item--avatar': item.showAvatar}]"
        @tap="handleOptionClick(index)"
      >
        <block v-if="item.showAvatar">
          <tn-avatar
            :src="item.avatar"
            size="sm"
            :badge="item.showBadge"
            :badgeText="item.count"
            :badgeBgColor="item.countBackgroundColor"
            :badgeColor="item.countFontColor"
            :badgeSize="26"
          ></tn-avatar>
        </block>
        <block v-else>
          <view class="options__item__icon" :class="[`tn-icon-${item.icon}`]" :style="[optionStyle(index, 'icon')]">
            <tn-badge v-if="item.showBadge" :absolute="true" :backgroundColor="item.countBackgroundColor" :fontColor="item.countFontColor" :fontSize="16" padding="2rpx 5rpx">{{ item.count }}</tn-badge>
          </view>
          <view class="options__item__text" :style="[optionStyle(index, 'text')]">{{ item.text }}</view>
        </block>
      </view>
    </view>
    <view class="buttons">
      <view
        v-for="(item, index) in buttonGroupsData"
        :key="index"
        class="buttons__item"
        :class="[buttonClass(index)]"
        :style="[buttonStyle(index)]"
        @tap="handleButtonClick(index)"
      >
        <view class="buttons__item__text">{{ item.text }}</view>
      </view>
    </view>
  </view>
</template>
<script>
  export default {
    name: 'tn-goods-nav',
    props: {
      // é€‰é¡¹ä¿¡æ¯
      // å»ºè®®ä¸è¶…过3个
      // {
      //   icon: '', // å›¾æ ‡åç§°
      //   text: '', // æ˜¾ç¤ºçš„æ–‡æœ¬
      //   count: '', // è§’标的值
      //   countBackgroundColor: '', // è§’标背景颜色
      //   countFontColor: '', // è§’标字体颜色
      //   iconColor: '', // å›¾æ ‡é¢œè‰²
      //   textColor: '', // æ–‡æœ¬é¢œè‰²
      //   avatar: '', // æ˜¾ç¤ºå¤´åƒï¼ˆæ­¤æ—¶å°†ä¸æ˜¾ç¤ºå›¾æ ‡å’Œæ–‡æœ¬ï¼‰
      // }
      options: {
        type: Array,
        default() {
          return [{
            icon: 'shop',
            text: '店铺'
          },{
            icon: 'service',
            text: '客服'
          },{
            icon: 'star',
            text: '收藏'
          }]
        }
      },
      // æŒ‰é’®ç»„
      // å»ºè®®ä¸è¶…过2个
      // {
      //   text: '', // æ˜¾ç¤ºçš„æ–‡æœ¬
      //   backgroundColor: '', // æŒ‰é’®èƒŒæ™¯é¢œè‰²
      //   color: '' // æ–‡æœ¬é¢œè‰²
      // }
      buttonGroups: {
        type: Array,
        default() {
          return [{
            text: '加入购物车',
            backgroundColor: '#FFA726',
            color: '#FFFFFF'
          },{
            text: '结算',
            backgroundColor: '#FF7043',
            color: '#FFFFFF'
          }]
        }
      },
      // èƒŒæ™¯é¢œè‰²
      backgroundColor: {
        type: String,
        default: ''
      },
      // å¯¼èˆªçš„高度,单位rpx
      height: {
        type: Number,
        default: 0
      },
      // æ˜¾ç¤ºé˜´å½±
      shadow: {
        type: Boolean,
        default: false
      },
      // å¯¼èˆªçš„层级
      zIndex: {
        type: Number,
        default: 0
      },
      // æŒ‰é’®ç±»åž‹
      // rect -> æ–¹å½¢ paddingRect -> ä¸Šä¸‹å¸¦è¾¹è·æ–¹å½¢ round -> åœ†è§’
      buttonType: {
        type: String,
        default: 'rect'
      },
      // æ˜¯å¦å›ºå®šåœ¨åº•部
      fixed: {
        type: Boolean,
        default: false
      },
      // æ˜¯å¦å¼€å¯åº•部安全区适配,开启的话,会在iPhoneX机型底部添加一定的内边距
      safeAreaInsetBottom: {
          type: Boolean,
          default: false
      }
    },
    computed: {
      backgroundColorStyle() {
        return this.$t.color.getBackgroundColorStyle(this.backgroundColor)
      },
      backgroundColorClass() {
        return this.$t.color.getBackgroundColorInternalClass(this.backgroundColor)
      },
      navStyle() {
        let style = {}
        if (this.height) {
          style.height = this.height + 'rpx'
        }
        style.zIndex = this.zIndex ? this.zIndex : this.$t.zIndex.goodsNav
        return style
      },
      // é€‰é¡¹style
      optionStyle() {
        return (index, type) => {
          let style = {}
          const item = this.optionsData[index]
          if (type === 'icon' && item.iconColor) {
            style.color = item.iconColor
          } else if (type === 'text' && item.fontColor) {
            style.color = item.fontColor
          }
          return style
        }
      },
      // æŒ‰é’®class
      buttonClass() {
        return (index) => {
          let clazz = ''
          const item = this.buttonGroupsData[index]
          if (item.backgroundColorClass) {
            clazz += ` ${item.backgroundColorClass}`
          }
          if (item.colorClass) {
            clazz += ` ${item.colorClass}`
          }
          clazz += ` buttons__item--${this.$t.string.humpConvertChar(this.buttonType, '-')}`
          return clazz
        }
      },
      // æŒ‰é’®style
      buttonStyle() {
        return (index) => {
          let style = {}
          const item = this.buttonGroupsData[index]
          if (item.backgroundColorStyle) {
            style.backgroundColor = item.backgroundColorStyle
          }
          if (item.colorStyle) {
            style.color = item.colorStyle
          }
          return style
        }
      }
    },
    watch: {
      options(val) {
        this.initData()
      },
      buttonGroups(val) {
        this.initData()
      }
    },
    data() {
      return {
        // ä¿å­˜é€‰é¡¹æ•°æ®
        optionsData: [],
        // ä¿å­˜æŒ‰é’®ç»„数据
        buttonGroupsData: []
      }
    },
    created() {
      this.initData()
    },
    methods: {
      // åˆå§‹åŒ–选项和按钮数据
      initData() {
        this.handleOptionsData()
        this.handleButtonGroupsData()
      },
      // é€‰é¡¹ç‚¹å‡»äº‹ä»¶
      handleOptionClick(index) {
        this.$emit('optionClick', {
          index: index
        })
      },
      // æŒ‰é’®ç‚¹å‡»äº‹ä»¶
      handleButtonClick(index) {
        this.$emit('buttonClick', {
          index: index
        })
      },
      // å¤„理选项组数据
      handleOptionsData() {
        this.optionsData = this.options.map((item) => {
          let option = {...item}
          option.showAvatar = item.hasOwnProperty('avatar')
          if (item.hasOwnProperty('count')) {
            const count = this.$t.number.formatNumberString(item.count, 2)
            option.showBadge = true
            option.count = typeof count === 'number' ? String(count) : count
            option.countBackgroundColor = item.countBackgroundColor ? item.countBackgroundColor : '#01BEFF'
            option.countFontColor = item.countFontColor ? item.countFontColor : '#FFFFFF'
          }
          return option
        })
      },
      // å¤„理按钮组数据
      handleButtonGroupsData() {
        this.buttonGroupsData = this.buttonGroups.map((item) => {
          let button = {...item}
          if (item.hasOwnProperty('backgroundColor')) {
            button.backgroundColorClass = this.$t.color.getBackgroundColorInternalClass(item.backgroundColor)
            button.backgroundColorStyle = this.$t.color.getBackgroundColorStyle(item.backgroundColor)
          }
          if (item.hasOwnProperty('color')) {
            button.colorClass = this.$t.color.getBackgroundColorInternalClass(item.color)
            button.colorStyle = this.$t.color.getBackgroundColorStyle(item.color)
          }
          return button
        })
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-goods-nav {
    background-color: #FFFFFF;
    display: flex;
    flex-direction: row;
    align-items: center;
    height: 88rpx;
    width: 100%;
    box-sizing: content-box;
    &--shadow {
      box-shadow: 0rpx -10rpx 30rpx 0rpx rgba(0, 0, 0, 0.05);
      &::before {
        content: " ";
        position: absolute;
        width: 100%;
        height: 100%;
        bottom: 0;
        left: 0;
        right: 0;
        margin: auto;
        background-color: transparent;
        z-index: -1;
      }
    }
    &--fixed {
      position: fixed;
      bottom: 0;
      left: 0;
      right: 0;
    }
    .options {
      display: flex;
      flex-direction: row;
      align-items: center;
      height: 100%;
      color: #AAAAAA;
      &__item {
        padding: 0 26rpx;
        &--avatar {
          padding: 0rpx 0rpx 0rpx 26rpx !important;
        }
        &__icon {
          position: relative;
          font-size: 36rpx;
          margin-bottom: 6rpx;
        }
        &__text {
          font-size: 22rpx;
        }
      }
    }
    .buttons {
      flex: 1;
      display: flex;
      flex-direction: row;
      align-items: center;
      height: 100%;
      &__item {
        flex: 1;
        padding: 0 10rpx;
        display: flex;
        align-items: center;
        justify-content: center;
        &--rect {
          height: 100%;
        }
        &--padding-rect {
          height: 80%;
        }
        &--round {
          height: 75%;
          &:first-child {
            border-top-left-radius: 100rpx;
            border-bottom-left-radius: 100rpx;
          }
          &:last-child {
            border-top-right-radius: 100rpx;
            border-bottom-right-radius: 100rpx;
          }
        }
        &__text {
          display: inline-block;
          font-weight: bold;
          font-size: 30rpx;
          white-space: nowrap;
          text-overflow: ellipsis;
          overflow: hidden;
        }
      }
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-grid-item/tn-grid-item.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,114 @@
<template>
  <view
    class="tn-grid-item-class tn-grid-item"
    :class="[
      backgroundColorClass
    ]"
    :hover-class="hoverClass"
    :hover-stay-time="150"
    :style="{
      backgroundColor: backgroundColorStyle,
      width: gridWidth
    }"
    @tap="click"
  >
    <view
      class="tn-grid-item__box"
    >
      <slot></slot>
    </view>
  </view>
</template>
<script>
  import componentsColorMixin from '../../libs/mixin/components_color.js'
  export default {
    mixins: [ componentsColorMixin ],
    name: 'tn-grid-item',
    props: {
      // åºå·
      index: {
        type: [Number, String],
        default: ''
      }
    },
    data() {
      return {
        // çˆ¶ç»„件数据
        parentData: {
          // æŒ‰ä¸‹åŽ»çš„æ ·å¼
          hoverClass: '',
          col: 3
        }
      }
    },
    created() {
      // çˆ¶ç»„件实例
      this.updateParentData()
      this.parent.children.push(this)
    },
    computed: {
      // è®¡ç®—每个宫格的宽度
      gridWidth() {
        // #ifdef MP-WEIXIN
        return '100%'
        // #endif
        // #ifndef MP-WEIXIN
        return 100 / Number(this.parentData.col) + '%'
        // #endif
      },
      // ç‚¹å‡»æ•ˆæžœ
      hoverClass() {
        return this.parentData.hoverClass !== 'none'
                 ? this.parentData.hoverClass + ' tn-grid-item--hover'
                 : this.parentData.hoverClass
      }
    },
    methods: {
      // èŽ·å–çˆ¶ç»„ä»¶å‚æ•°
      updateParentData() {
        this.getParentData('tn-grid')
      },
      click() {
        this.$emit('click', this.index)
        this.parent && this.parent.click(this.index)
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-grid-item {
    box-sizing: border-box;
    background-color: #FFFFFF;
    /* #ifndef APP-NVUE */
    display: flex;
    flex-direction: row;
    /* #endif */
    align-items: center;
    justify-content: center;
    position: relative;
    flex-direction: column;
    /* #ifdef MP */
    // float: left;
    /* #endif */
    &__box {
      /* #ifndef APP-NVUE */
      display: flex;
      flex-direction: row;
      /* #endif */
      align-items: center;
      justify-content: center;
      flex-direction: column;
      flex: 1;
      width: 100%;
      height: 100%;
    }
    &--hover {
      background: $tn-space-color !important;
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-grid/tn-grid.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,111 @@
<template>
  <view
    class="tn-grid-class tn-grid"
    :style="{
      justifyContent: gridAlignStyle
    }"
  >
    <slot></slot>
  </view>
</template>
<script>
  export default {
    name: 'tn-grid',
    props: {
      // åˆ†æˆå‡ åˆ—
      col: {
        type: [Number, String],
        default: 3
      },
      // å®«æ ¼å¯¹é½æ–¹å¼
      // left å·¦å¯¹é½ center å±…中对齐 right å³å¯¹é½
      align: {
        type: String,
        default: 'left'
      },
      // ç‚¹å‡»æ—¶çš„æ•ˆæžœï¼Œnone没有效果
      hoverClass: {
        type: String,
        default: 'tn-hover'
      }
    },
    data() {
      return {
      }
    },
    watch: {
      // å½“父组件和子组件需要共享参数变化,通知子组件
      parentData() {
        if (this.children.length) {
          this.children.map(child => {
            // åˆ¤æ–­å­ç»„件是否有updateParentData方式,有才执行
            typeof(child.updateParentData) === 'function' && child.updateParentData()
          })
        }
      }
    },
    created() {
      // å¦‚果将children定义在data中,在微信小程序会造成循环引用而报错
      this.children = []
    },
    computed: {
      // è®¡ç®—父组件的值是否发生变化
      parentData() {
        return [this.hoverClass, this.col, this.border]
      },
      // å®«æ ¼å¯¹é½æ–¹å¼
      gridAlignStyle() {
        switch(this.align) {
          case 'left':
            return 'flex-start'
          case 'center':
            return 'center'
          case 'right':
            return 'flex-end'
          default:
            return 'flex-start'
        }
      }
    },
    methods: {
      click(index) {
        this.$emit('click', index)
      }
    }
  }
</script>
<style lang="scss" scoped>
  // ç»„件中兼容小程序的方式,不过不能使用对齐方式
  // .tn-grid {
  //   width: 100%;
  //   /* #ifdef MP */
  //   position: relative;
  //   box-sizing: border-box;
  //   overflow: hidden;
  //   /* #endif */
  //   /* #ifndef MP */
  //   /* #ifndef APP-NVUE */
  //   display: flex;
  //   flex-direction: row;
  //   /* #endif */
  //   flex-wrap: wrap;
  //   align-items: center;
  //   /* #endif */
  // }
  // åœ¨ä½¿ç”¨ç»„件时兼容小程序
  .tn-grid {
    width: 100%;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-image-upload-drag/tn-image-upload-drag.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,995 @@
<template>
  <view v-if="!disabled" class="tn-image-upload-class tn-image-upload">
    <movable-area
      class="tn-image-upload__movable-area"
      :style="{
        height: movableAreaHeight
      }"
      @mouseenter="mouseEnterArea"
      @mouseleave="mouseLeaveArea"
    >
      <block
        v-for="(item, index) in lists"
        :key="item.id"
      >
        <movable-view
          class="tn-image-upload__movable-view"
          :style="{
            width: $t.string.getLengthUnitValue(width),
            height: $t.string.getLengthUnitValue(height),
            zIndex: item.zIndex,
            opacity: item.opacity,
          }"
          :x="item.x"
          :y="item.y"
          direction="all"
          :damping="40"
          :disabled="item.disabled"
          @change="movableChange($event, item)"
          @touchstart="movableStart(item)"
          @mousedown="movableStart(item)"
          @touchend="movableEnd(item)"
          @mouseup="movableEnd(item)"
          @longpress="movableLongPress(item)"
        >
          <view
            class="tn-image-upload__item tn-image-upload__item-preview"
            :style="{
              width: $t.string.getLengthUnitValue(itemWidth, 'px'),
              height: $t.string.getLengthUnitValue(itemHeight, 'px'),
              transform: `scale(${item.scale})`
            }"
          >
            <!-- åˆ é™¤æŒ‰é’® -->
            <view
              v-if="deleteable"
              class="tn-image-upload__item-preview__delete"
              @tap.stop="deleteItem(index)"
              :style="{
                borderTopColor: deleteBackgroundColor
              }"
            >
              <view
                class="tn-image-upload__item-preview__delete--icon"
                :class="[`tn-icon-${deleteIcon}`]"
                :style="{
                  color: deleteColor
                }"
              ></view>
            </view>
            <!-- è¿›åº¦æ¡ -->
            <tn-line-progress
              v-if="showProgress && item.data.progress > 0 && !item.data.error"
              class="tn-image-upload__item-preview__progress"
              :percent="item.data.progress"
              :showPercent="false"
              :round="false"
              :height="8"
            ></tn-line-progress>
            <!-- é‡è¯•按钮 -->
            <view v-if="item.data.error" class="tn-image-upload__item-preview__error-btn" @tap.stop="retry(index)">点击重试</view>
            <!-- å›¾ç‰‡ä¿¡æ¯ -->
            <image
              class="tn-image-upload__item-preview__image"
              :src="item.data.url || item.data.path"
              :mode="imageMode"
              @tap.stop="doPreviewImage(item.data.url || item.data.path, index)"
            ></image>
          </view>
        </movable-view>
      </block>
      <!-- æ·»åŠ æŒ‰é’® -->
      <view
        v-if="maxCount > lists.length"
        class="tn-image-upload__add"
        :style="{
          top: addBtn.y + 'px',
          left: addBtn.x + 'px',
          width: $t.string.getLengthUnitValue(itemWidth, 'px'),
          height: $t.string.getLengthUnitValue(itemHeight, 'px')
        }"
        @tap="selectFile"
      >
        <!-- æ·»åŠ æŒ‰é’® -->
        <view
          class="tn-image-upload__item tn-image-upload__item-add"
          hover-class="tn-hover-class"
          hover-stay-time="150"
          :style="{
            width: $t.string.getLengthUnitValue(itemWidth, 'px'),
            height: $t.string.getLengthUnitValue(itemHeight, 'px')
          }"
        >
          <view class="tn-image-upload__item-add--icon tn-icon-add"></view>
          <view class="tn-image-upload__item-add__tips">{{ uploadText }}</view>
        </view>
      </view>
    </movable-area>
  </view>
</template>
<script>
  export default {
    name: 'tn-image-upload-drag',
    props: {
      // å·²ä¸Šä¼ çš„æ–‡ä»¶åˆ—表
      fileList: {
        type: Array,
        default() {
          return []
        }
      },
      // ä¸Šä¼ å›¾ç‰‡åœ°å€
      action: {
        type: String,
        default: ''
      },
      // ä¸Šä¼ æ–‡ä»¶çš„字段名称
      name: {
        type: String,
        default: 'file'
      },
      // å¤´éƒ¨ä¿¡æ¯
      header: {
        type: Object,
        default() {
          return {}
        }
      },
      // æºå¸¦çš„参数
      formData: {
        type: Object,
        default() {
          return {}
        }
      },
      // æ˜¯å¦ç¦ç”¨
      disabled: {
        type: Boolean,
        default: false
      },
      // æ˜¯å¦è‡ªåŠ¨ä¸Šä¼ 
      autoUpload: {
        type: Boolean,
        default: true
      },
      // æœ€å¤§ä¸Šä¼ æ•°é‡
      maxCount: {
        type: Number,
        default: 9
      },
      // é¢„览上传图片的裁剪模式
      imageMode: {
        type: String,
        default: 'aspectFill'
      },
      // ç‚¹å‡»å›¾ç‰‡æ˜¯å¦å…¨å±é¢„览
      previewFullImage: {
        type: Boolean,
        default: true
      },
      // æ˜¯å¦æ˜¾ç¤ºè¿›åº¦æ¡
      showProgress: {
        type: Boolean,
        default: true
      },
      // æ˜¯å¦æ˜¾ç¤ºåˆ é™¤æŒ‰é’®
      deleteable: {
        type: Boolean,
        default: true
      },
      // åˆ é™¤æŒ‰é’®å›¾æ ‡
      deleteIcon: {
        type: String,
        default: 'close'
      },
      // åˆ é™¤æŒ‰é’®çš„背景颜色
      deleteBackgroundColor: {
        type: String,
        default: ''
      },
      // åˆ é™¤æŒ‰é’®çš„颜色
      deleteColor: {
        type: String,
        default: ''
      },
      // ä¸Šä¼ åŒºåŸŸæç¤ºæ–‡å­—
      uploadText: {
        type: String,
        default: '选择图片'
      },
      // æ˜¾ç¤ºtoast提示
      showTips: {
        type: Boolean,
        default: true
      },
      // é¢„览图片和选择图片区域的宽度
      width: {
        type: Number,
        default: 200
      },
      // é¢„览图片和选择图片区域的高度
      height: {
        type: Number,
        default: 200
      },
      // é€‰æ‹©å›¾ç‰‡çš„尺寸
      // å‚考上传文档 https://uniapp.dcloud.io/api/media/image
      sizeType: {
        type: Array,
        default() {
          return ['original', 'compressed']
        }
      },
      // å›¾ç‰‡æ¥æº
      sourceType: {
        type: Array,
        default() {
          return ['album', 'camera']
        }
      },
      // æ˜¯å¦å¯ä»¥å¤šé€‰
      multiple: {
        type: Boolean,
        default: true
      },
      // æ–‡ä»¶å¤§å°(byte)
      maxSize: {
        type: Number,
        default: 10 * 1024 * 1024
      },
      // å…è®¸ä¸Šä¼ çš„类型
      limitType: {
        type: Array,
        default() {
          return ['png','jpg','jpeg','webp','gif','image']
        }
      },
      // æ˜¯å¦è‡ªå®šè½¬æ¢ä¸ºjson
      toJson: {
        type: Boolean,
        default: true
      },
      // ä¸Šä¼ å‰é’©å­å‡½æ•°ï¼Œæ¯ä¸ªæ–‡ä»¶ä¸Šä¼ å‰éƒ½ä¼šæ‰§è¡Œ
      beforeUpload: {
        type: Function,
        default: null
      },
      // åˆ é™¤æ–‡ä»¶å‰é’©å­å‡½æ•°
      beforeRemove: {
        type: Function,
        default: null
      },
      index: {
        type: [Number, String],
        default: ''
      }
    },
    computed: {
      movableAreaHeight() {
        if (this.lists.length < this.maxCount) {
          return Math.ceil((this.lists.length + 1) / this.baseData.columns) * uni.upx2px(this.height) + 'px'
        } else {
          return Math.ceil(this.lists.length / this.baseData.columns) * uni.upx2px(this.height) + 'px'
        }
      },
      itemWidth() {
        return uni.upx2px(this.width) - (uni.upx2px(10) * 2)
      },
      itemHeight() {
        return uni.upx2px(this.height) - (uni.upx2px(10) * 2)
      }
    },
    data() {
      return {
        lists: [],
        uploading: false,
        baseData: {
          windowWidth: 0,
          columns: 0,
          dragItem: null,
          widthPx: 0,
          heightPx: 0
        },
        addBtn: {
          x: 0,
          y: 0
        },
        timer: null,
        dragging: false
      }
    },
    watch: {
      // fileList: {
      //   handler(val) {
      //     val.map(value => {
      //       // é¦–先检查内部是否已经添加过这张图片,因为外部绑定了一个对象给fileList的话(对象引用),进行修改外部fileList时,
      //       // ä¼šè§¦å‘watch,导致重新把原来的图片再次添加到this.lists
      //       // æ•°ç»„çš„some方法意思是,只要数组元素有任意一个元素条件符合,就返回true,而另一个数组的every方法的意思是数组所有元素都符合条件才返回true
      //       let tmp = this.lists.some(listVal => {
      //         return listVal.url === value.url
      //       })
      //       // å¦‚果内部没有这张图片,则添加到内部
      //       !tmp && this.lists.push({ url: value.url, error: false, progress: 100 })
      //     })
      //   },
      //   immediate: true
      // },
      lists(val) {
        this.$emit('on-list-change', this.sortList(), this.index)
      }
    },
    created() {
      this.baseData.windowWidth = uni.getSystemInfoSync().windowWidth
    },
    mounted() {
      this.$nextTick(() => {
        this.updateDragInfo()
      })
    },
    methods: {
      // æ¸…除列表
      clear() {
        this.lists = []
        this.updateAddBtnPositioin()
      },
      // é‡æ–°ä¸Šä¼ é˜Ÿåˆ—中上传失败所有文件
      reUpload() {
        this.uploadFile()
      },
      // é€‰æ‹©å›¾ç‰‡
      selectFile() {
        if (this.disabled) return
        const {
          name = '',
          maxCount,
          multiple,
          maxSize,
          sizeType,
          lists,
          camera,
          compressed,
          sourceType
        } = this
        let chooseFile = null
        const newMaxCount = maxCount - lists.length
        // åªé€‰æ‹©å›¾ç‰‡çš„æ—¶å€™ä½¿ç”¨ chooseImage æ¥å®žçް
        chooseFile = new Promise((resolve, reject) => {
          uni.chooseImage({
            count: multiple ? (newMaxCount > 9 ? 9 : newMaxCount) : 1,
            sourceType,
            sizeType,
            success: resolve,
            fail: reject
          })
        })
        chooseFile.then(res => {
          let file = null
          let listOldLength = lists.length
          res.tempFiles.map((val, index) => {
            if (!this.checkFileExt(val)) return
            // æ˜¯å¦è¶…出最大限制数量
            if (!multiple && index >= 1) return
            if (val.size > maxSize) {
              this.$emit('on-oversize', val, this.sortList(), this.index)
              this.showToast('超出可允许文件大小')
            } else {
              if (maxCount <= lists.length) {
                this.$emit('on-exceed', val, this.sortList(), this.index)
                this.showToast('超出最大允许的文件数')
                return
              }
              lists.push(this.handleDragListItem({
                url: val.path,
                progress: 0,
                error: false,
                file: val
              }))
              this.updateAddBtnPositioin()
            }
          })
          this.$emit('on-choose-complete', this.sortList(), this.index)
          if (this.autoUpload) this.uploadFile(listOldLength)
        }).catch(err => {
          this.$emit('on-choose-fail', err)
        })
      },
      // æç¤ºç”¨æˆ·ä¿¡æ¯
      showToast(message, force = false) {
        if (this.showTips || force) {
          this.$t.message.toast(message)
        }
      },
      // æ‰‹åŠ¨ä¸Šä¼ ï¼Œé€šè¿‡ref进行调用
      upload() {
        this.uploadFile()
      },
      // å¯¹å¤±è´¥å›¾ç‰‡è¿›è¡Œå†æ¬¡ä¸Šä¼ 
      retry(index) {
        this.lists[index].data.progress = 0
        this.lists[index].data.error = false
        this.lists[index].data.response = null
        this.$t.message.loading('重新上传')
        this.uploadFile(index)
      },
      // ä¸Šä¼ æ–‡ä»¶
      async uploadFile(index = 0) {
        if (this.disabled) return
        if (this.uploading) return
        // å…¨éƒ¨ä¸Šä¼ å®Œæˆ
        if (index >= this.lists.length) {
          this.$emit('on-uploaded', this.sortList(), this.index)
          return
        }
        // æ£€æŸ¥æ˜¯å¦å·²ç»å…¨éƒ¨ä¸Šä¼ æˆ–者上传中
        if (this.lists[index].data.progress === 100) {
          this.lists[index].data.uploadTask = null
          if (this.autoUpload) this.uploadFile(index + 1)
          return
        }
        // æ‰§è¡Œbefore-upload钩子
        if (this.beforeUpload && typeof(this.beforeUpload) === 'function') {
          // åœ¨å¾®ä¿¡ï¼Œæ”¯ä»˜å®ç­‰çŽ¯å¢ƒ(H5正常),会导致父组件定义的函数体中的this变成子组件的this
          // é€šè¿‡bind()方法,绑定父组件的this,让this的this为父组件的上下文
          // å› ä¸ºupload组件可能会被嵌套在其他组件内,比如tn-form,这时this.$parent其实为tn-form的this,
          // éžé¡µé¢çš„this,所以这里需要往上历遍,一直寻找到最顶端的$parent,这里用了this.$u.$parent.call(this)
          let beforeResponse = this.beforeUpload.bind(this.$t.$parent.call(this))(index, this.lists)
          // åˆ¤æ–­æ˜¯å¦è¿”回了Promise
          if (!!beforeResponse && typeof beforeResponse.then === 'function') {
            await beforeResponse.then(res => {
              // promise返回成功,不进行操作继续
            }).catch(err => {
              // è¿›å…¥catch回调的话,继续下一张
              return this.uploadFile(index + 1)
            })
          } else if (beforeResponse === false) {
            // å¦‚果返回flase,继续下一张图片上传
            return this.uploadFile(index + 1)
          } else {
            // ä¸ºtrue的情况,不进行操作
          }
        }
        // æ£€æŸ¥ä¸Šä¼ åœ°å€
        if (!this.action) {
          this.showToast('请配置上传地址', true)
          return
        }
        this.lists[index].data.error = false
        this.uploading = true
        // åˆ›å»ºä¸Šä¼ å¯¹è±¡
        const task = uni.uploadFile({
          url: this.action,
          filePath: this.lists[index].data.url,
          name: this.name,
          formData: this.formData,
          header: this.header,
          success: res => {
            // åˆ¤æ–­å•Šæ˜¯å¦ä¸ºjson字符串,将其转换为json格式
            let data = this.toJson && this.$t.test.jsonString(res.data) ? JSON.parse(res.data) : res.data
            if (![200, 201, 204].includes(res.statusCode)) {
              this.uploadError(index, data)
            } else {
              this.lists[index].data.response = data
              this.lists[index].data.progress = 100
              this.lists[index].data.error = false
              this.$emit('on-success', data, index, this.sortList(), this.index)
            }
          },
          fail: err => {
            this.uploadError(index, err)
          },
          complete: res => {
            this.$t.message.closeLoading()
            this.uploading = false
            this.uploadFile(index + 1)
            this.$emit('on-change', res, index, this.sortList(), this.index)
          }
        })
        this.lists[index].uploadTask = task
        task.onProgressUpdate(res => {
          if (res.progress > 0) {
            this.lists[index].data.progress = res.progress
            this.$emit('on-progress', res, index, this.sortList(), this.index)
          }
        })
      },
      // ä¸Šä¼ å¤±è´¥
      uploadError(index, err) {
        this.lists[index].data.progress = 0
        this.lists[index].data.error = true
        this.lists[index].data.response = null
        this.showToast('上传失败,请重试')
        this.$emit('on-error', err, index, this.sortList(), this.index)
      },
      // åˆ é™¤ä¸€ä¸ªå›¾ç‰‡
      deleteItem(index) {
        if (!this.deleteable) return
        this.$t.message.modal(
          '提示',
          '你确定要删除吗?',
          async () => {
            // å…ˆæ£€æŸ¥æ˜¯å¦æœ‰å®šä¹‰before-remove移除前钩子
            // æ‰§è¡Œbefore-remove钩子
            if (this.beforeRemove && typeof(this.beforeRemove) === 'function') {
              let beforeResponse = this.beforeRemove.bind(this.$t.$parent.call(this))(index, this.lists)
              // åˆ¤æ–­æ˜¯å¦è¿”回promise
              if (!!beforeResponse && typeof beforeResponse.then === 'function') {
                await beforeResponse.then(res => {
                  // promise返回成功不进行操作
                  this.handlerDeleteItem(index)
                }).catch(err => {
                  this.showToast('删除操作被中断')
                })
              } else if (beforeResponse === false) {
                this.showToast('删除操作被中断')
              } else {
                this.handlerDeleteItem(index)
              }
            } else {
              this.handlerDeleteItem(index)
            }
          }, true)
      },
      // ç§»é™¤æ–‡ä»¶æ“ä½œ
      handlerDeleteItem(index) {
        // å¦‚果文件正在上传中,终止上传任务
        if (this.lists[index].data.progress < 100 && this.lists[index].data.progress > 0) {
          typeof this.lists[index].data.uploadTask !== 'undefined' && this.lists[index].data.uploadTask.abort()
        }
        this.remove(index)
        this.$forceUpdate()
        this.$emit('on-remove', index, this.sortList(), this.index)
        this.showToast('删除成功')
      },
      // ç§»é™¤æ–‡ä»¶ï¼Œé€šè¿‡ref手动形式进行调用
      remove(index) {
        if (!this.deleteable) return
        // åˆ¤æ–­ç´¢å¼•合法
        if (index >= 0 && index < this.lists.length) {
          let currentItemIndex = this.lists[index].index
          this.lists.splice(index, 1)
          // é‡æ–°æŽ’列列表信息
          for (let item of this.lists) {
            if (item.index > currentItemIndex) {
              item.index -= 1
              item.x = item.positionX * this.baseData.widthPx
              item.y = item.positionY * this.baseData.heightPx
              item.positionX = item.index % this.baseData.columns
              item.positionY = Math.floor(item.index / this.baseData.columns)
              this.$nextTick(() => {
                item.x = item.positionX * this.baseData.widthPx
                item.y = item.positionY * this.baseData.heightPx
              })
            }
          }
          this.updateAddBtnPositioin()
        }
      },
      // é¢„览图片
      doPreviewImage(url, index) {
        if (!this.previewFullImage) return
        const images = this.lists.sort((l1, l2) => { return l1.index - l2.index}).map(item => item.data.url || item.data.path)
        uni.previewImage({
          urls: images,
          current: url,
          success: () => {
            this.$emit('on-preview', url, this.sortList(), this.index)
          },
          fail: () => {
            this.showToast('预览图片失败')
          }
        })
      },
      // æ£€æŸ¥æ–‡ä»¶åŽç¼€æ˜¯å¦åˆæ³•
      checkFileExt(file) {
        // æ˜¯å¦ä¸ºåˆæ³•后缀
        let noArrowExt = false
        // åŽç¼€å
        let fileExt = ''
        const reg = /.+\./
        // #ifdef H5
        fileExt = file.name.replace(reg, '').toLowerCase()
        // #endif
        // #ifndef H5
        fileExt = file.path.replace(reg, '').toLowerCase()
        // #endif
        noArrowExt = this.limitType.some(ext => {
          return ext.toLowerCase() === fileExt
        })
        if (!noArrowExt) this.showToast(`不支持${fileExt}格式的文件`)
        return noArrowExt
      },
      /********************* æ‹–拽处理 ********************/
      // æ›´æ–°æ‹–拽信息
      updateDragInfo() {
        this.baseData.widthPx = uni.upx2px(this.width)
        this.baseData.heightPx = uni.upx2px(this.height)
        // èŽ·å–å¯ç§»åŠ¨åŒºåŸŸçš„ä¿¡æ¯ï¼Œç”¨äºŽåˆ¤æ–­å½“å‰æœ‰å¤šå°‘åˆ—
        const query = uni.createSelectorQuery().in(this)
        query.select('.tn-image-upload__movable-area').boundingClientRect()
        query.exec((res) => {
          if (!res) {
            setTimeout(() => {
              this.updateDragInfo()
            }, 10)
            return
          }
          this.baseData.columns = Math.floor(res[0].width / this.baseData.widthPx)
          // åˆå§‹åŒ–可拖拽列表信息
          this.lists = []
          this.fileList.forEach((item) => {
            // é¦–先检查内部是否已经添加过这张图片,因为外部绑定了一个对象给fileList的话(对象引用),进行修改外部fileList时,
            // ä¼šè§¦å‘watch,导致重新把原来的图片再次添加到this.lists
            // æ•°ç»„çš„some方法意思是,只要数组元素有任意一个元素条件符合,就返回true,而另一个数组的every方法的意思是数组所有元素都符合条件才返回true
            let tmp = this.lists.map(value => {
              return value.data
            }).some(listVal => {
              return listVal.url === item.url
            })
            // å¦‚果内部没有这张图片,则添加到内部
            !tmp && this.lists.push(this.handleDragListItem({
              url: item.url,
              error: false,
              progress: 100
            }))
          })
          // æ›´æ–°æ·»åŠ æŒ‰é’®ä½ç½®
          this.updateAddBtnPositioin()
        })
      },
      // å¤„理拖拽列表信息
      handleDragListItem(item) {
        const positionX = this.lists.length % this.baseData.columns
        const positionY = Math.floor(this.lists.length / this.baseData.columns)
        const x = positionX * this.baseData.widthPx
        const y = positionY * this.baseData.heightPx
        return {
          id: this.unique(),
          x,
          y,
          preX: x,
          preY: y,
          positionX,
          positionY,
          zIndex:1,
          disabled: true,
          opacity: 1,
          scale: 1,
          index: this.lists.length,
          offset: 0,
          moveEnd: false,
          moving: false,
          data: {
            ...item
          }
        }
      },
      // ç”Ÿæˆå…ƒç´ å”¯ä¸€id
      unique(n = 6) {
        let id = ''
        for (let i = 0; i < n; i++) id += Math.floor(Math.random() * 10)
        return 'tn_' + new Date().getTime() + id
      },
      // æ›´æ–°æ·»åŠ æŒ‰é’®ä½ç½®
      updateAddBtnPositioin() {
        if (this.lists.length >= this.maxCount) return
        this.addBtn.x = (this.lists.length % this.baseData.columns) * this.baseData.widthPx
        this.addBtn.y = Math.floor(this.lists.length / this.baseData.columns) * this.baseData.heightPx
      },
      // èŽ·å–æŽ’åºåŽæ•°æ®
      sortList() {
        const list = this.lists.slice()
        list.sort((l1, l2) => {
          return l1.index - l2.index
        })
        return list.map(item => {
          return item.data
        })
      },
      mouseEnterArea () {
        // #ifdef H5
        this.lists.forEach(item => {
          item.disabled = false
        })
        // #endif
      },
      mouseLeaveArea () {
        // #ifdef H5
        if (this.baseData.dragItem) {
          this.lists.forEach(item => {
            item.disabled = true
            item.zIndex = 1
            item.offset = 0
            item.moveEnd = true
            if (item.id === this.baseData.dragItem.id) {
              if (this.timer) {
                clearTimeout(this.timer)
                this.timer = null
              }
              item.x = item.preX
              item.y = item.preY
              this.$nextTick(() => {
                item.x = item.positionX * this.baseData.widthPx
                item.y = item.positionY * this.baseData.heightPx
                this.baseData.dragItem = null
              })
            }
          })
          this.dragging = false
        }
        // #endif
      },
      movableLongPress(item) {
        // #ifndef H5
          uni.vibrateShort()
          // console.log("LongPress--------------------------------------------------------------");
          this.lists.forEach(value => {
            value.moving = false
          })
          this.dragging = true
          // è®¾ç½®å¯¹åº”的元素允许拖动
          const index = this.lists.findIndex(obj => {
            return obj.id === item.id
          })
          item.disabled = false
          item.opacity = 0.7
          item.scale = 1.1
          this.$set(this.lists, index, item)
        // #endif
      },
      movableChange (e, item) {
        if (!item || !this.dragging) return
        // console.log("movableChange");
        item.moving = true
        item.preX = e.detail.x
        item.preY = e.detail.y
        // console.log(item.preX, item.preY);
        if (e.detail.source === 'touch') {
          if (!item.moveEnd) {
            item.offset = Math.sqrt(
              Math.pow(item.preX - item.positionX * this.baseData.widthPx, 2) +
              Math.pow(item.preY - item.positionY * this.baseData.heightPx, 2))
          }
          let x = Math.floor((e.detail.x + this.baseData.widthPx / 2) / this.baseData.widthPx)
          if (x > this.baseData.columns) return
          let y = Math.floor((e.detail.y + this.baseData.heightPx / 2) / this.baseData.heightPx)
          let index = this.baseData.columns * y + x
          if (item.index !== index && index < this.lists.length) {
            for (let obj of this.lists) {
              if (item.index > index && obj.index >= index && obj.index < item.index) {
                this.updateItemPosition(obj, 1)
              } else if (item.index < index && obj.index <= index && obj.index > item.index) {
                this.updateItemPosition(obj, -1)
              } else if (item.id != obj.id) {
                // obj.offset = 0
                // console.log(obj.moving);
                // if (!obj.moving) {
                //   obj.preX = obj.positionX * this.baseData.widthPx
                //   obj.preY = obj.positionY * this.baseData.heightPx
                //   console.log("moving", obj.id, obj.preX, obj.preY);
                // }
                // obj.x = obj.preX
                // obj.y = obj.preY
                // // console.log(obj.id, obj.preX, obj.preY);
                // this.$nextTick(() => {
                //   obj.x = obj.positionX * this.baseData.widthPx
                //   obj.y = obj.positionY * this.baseData.heightPx
                // })
              }
            }
            item.index = index
            item.positionX = x
            item.positionY = y
            // TODO å‘送事件
          }
        }
      },
      movableStart (item) {
        // console.log("movableStart");
        this.lists.forEach(item => {
          item.zIndex = 1
          // #ifdef H5
          item.disabled = false
          // #endif
        })
        item.zIndex = 10
        item.moveEnd = false
        this.baseData.dragItem = item
        // #ifdef H5
        this.dragging =true
        this.timer = setTimeout(() => {
          item.opacity = 0.7
          item.scale = 1.1
          clearTimeout(this.timer)
          this.timer = null
        }, 200)
        // #endif
      },
      movableEnd (item) {
        if (!this.dragging) return
        // console.log("movableEnd");
        const index = this.lists.findIndex(obj => {
          return obj.id === item.id
        })
        if (!item.moving) {
          item.preX = item.positionX * this.baseData.widthPx
          item.preY = item.positionY * this.baseData.heightPx
        }
        item.x = item.preX
        item.y = item.preY
        item.offset = 0
        item.moveEnd = true
        item.moving = false
        item.disabled = true
        // console.log(item.x, item.y);
        // console.log(item.id, item.moving);
        // this.$set(this.lists, index, item)
        // this.lists[index] = item
        // console.log(this.lists[index]);
        this.lists.forEach(listValue => {
          listValue.moving = false
          listValue.disabled = true
        })
        this.$nextTick(() => {
          item.x = item.positionX * this.baseData.widthPx
          item.y = item.positionY * this.baseData.heightPx
          item.opacity = 1
          item.scale = 1
          this.baseData.dragItem = null
          this.dragging = false
          // console.log(item.x, item.y);
          this.$set(this.lists, index, item)
        })
        this.$emit('sort-list', this.sortList())
      },
      // æ›´æ–°å›¾ç‰‡ä½ç½®ä¿¡æ¯
      updateItemPosition(item, offset) {
        const index = this.lists.findIndex(obj => {
          return obj.id === item.id
        })
        item.index += offset
        item.offset = 0
        item.positionX = item.index % this.baseData.columns
        item.positionY = Math.floor(item.index / this.baseData.columns)
        if (!item.moving) {
          item.preX = item.positionX * this.baseData.widthPx
          item.preY = item.positionY * this.baseData.heightPx
        }
        item.x = item.preX
        item.y = item.preY
        // console.log("updateItemPosition", item.id, item.preX, item.preY);
        // this.$set(this.lists, index, item)
        this.$nextTick(() => {
          item.x = item.positionX * this.baseData.widthPx
          item.y = item.positionY * this.baseData.heightPx
          this.$set(this.lists, index, item)
        })
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-image-upload {
    position: relative;
    &__movable-area {
      width: 100%;
    }
    &__movable-view {
      overflow: hidden;
    }
    &__item {
      /* #ifndef APP-NVUE */
      display: flex;
      /* #endif */
      align-items: center;
      justify-content: center;
      width: 200rpx;
      height: 200rpx;
      background-color: transparent;
      position: relative;
      border-radius: 5rpx;
      overflow: hidden;
      &-preview {
        border: 1rpx solid $tn-space-color;
        &__delete {
          display: flex;
          align-items: center;
          justify-content: center;
          position: absolute;
          top: 0;
          right: 0;
          z-index: 10;
          border-top: 60rpx solid;
          border-left: 60rpx solid transparent;
          border-top-color: rgba(0,0,0,0.1);
          width: 0rpx;
          height: 0rpx;
          &--icon {
            position: absolute;
            top: -50rpx;
            right: 6rpx;
            color: #FFFFFF;
            font-size: 24rpx;
            line-height: 1;
          }
        }
        &__progress {
          position: absolute;
          width: auto;
          bottom: 0rpx;
          left: 0rpx;
          right: 0rpx;
          z-index: 9;
          /* #ifdef MP-WEIXIN */
          display: inline-flex;
          /* #endif */
        }
        &__error-btn {
          position: absolute;
          bottom: 0;
          left: 0;
          right: 0;
          background-color: rgba(0,0,0,0.5);
          color: #FFFFFF;
          font-size: 20rpx;
          padding: 8rpx 0;
          text-align: center;
          z-index: 9;
          line-height: 1;
        }
        &__image {
          display: block;
          width: 100%;
          height: 100%;
          // border-radius: 10rpx;
        }
      }
      &-add {
        flex-direction: column;
        color: $tn-content-color;
        font-size: 26rpx;
        &--icon {
          font-size: 40rpx;
        }
        &__tips {
          margin-top: 20rpx;
          line-height: 40rpx;
        }
      }
    }
    &__add {
      background-color: $tn-space-color;
      position: absolute;
      // border-radius: 10rpx;
      // margin: 10rpx;
      // margin-left: 0;
    }
  }
</style>
¼ª°²PDA/tuniao-ui/components/tn-image-upload/tn-image-upload.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,645 @@
<template>
  <view v-if="!disabled" class="tn-image-upload-class tn-image-upload">
    <block v-if="showUploadList">
      <view
        v-for="(item, index) in lists"
        :key="index"
        class="tn-image-upload__item tn-image-upload__item-preview"
        :style="{
          width: $t.string.getLengthUnitValue(width),
          height: $t.string.getLengthUnitValue(height)
        }"
      >
        <!-- åˆ é™¤æŒ‰é’® -->
        <view
          v-if="deleteable"
          class="tn-image-upload__item-preview__delete"
          @tap.stop="deleteItem(index)"
          :style="{
            borderTopColor: deleteBackgroundColor
          }"
        >
          <view
            class="tn-image-upload__item-preview__delete--icon"
            :class="[`tn-icon-${deleteIcon}`]"
            :style="{
              color: deleteColor
            }"
          ></view>
        </view>
        <!-- è¿›åº¦æ¡ -->
        <tn-line-progress
          v-if="showProgress && item.progress > 0 && !item.error"
          class="tn-image-upload__item-preview__progress"
          :percent="item.progress"
          :showPercent="false"
          :round="false"
          :height="8"
        ></tn-line-progress>
        <!-- é‡è¯•按钮 -->
        <view v-if="item.error" class="tn-image-upload__item-preview__error-btn" @tap.stop="retry(index)">点击重试</view>
        <!-- å›¾ç‰‡ä¿¡æ¯ -->
        <image
          class="tn-image-upload__item-preview__image"
          :src="item.url || item.path"
          :mode="imageMode"
          @tap.stop="doPreviewImage(item.url || item.path, index)"
        ></image>
      </view>
    </block>
    <!-- <view v-if="$slots.file || $slots.$file" style="width: 100%;">
    </view> -->
    <!-- è‡ªå®šä¹‰å›¾ç‰‡å±•示列表 -->
    <slot name="file" :file="lists"></slot>
    <!-- æ·»åŠ æŒ‰é’® -->
    <view v-if="maxCount > lists.length" class="tn-image-upload__add" :class="{'tn-image-upload__add--custom': customBtn}" @tap="selectFile">
      <!-- æ·»åŠ æŒ‰é’® -->
      <view
        v-if="!customBtn"
        class="tn-image-upload__item tn-image-upload__item-add"
        hover-class="tn-hover-class"
        hover-stay-time="150"
        :style="{
          width: $t.string.getLengthUnitValue(width),
          height: $t.string.getLengthUnitValue(height)
        }"
      >
        <view class="tn-image-upload__item-add--icon tn-icon-add"></view>
        <view class="tn-image-upload__item-add__tips">{{ uploadText }}</view>
      </view>
      <!-- è‡ªå®šä¹‰æ·»åŠ æŒ‰é’® -->
      <view>
        <slot name="addBtn"></slot>
      </view>
    </view>
  </view>
</template>
<script>
  export default {
    name: 'tn-image-upload',
    props: {
      // å·²ä¸Šä¼ çš„æ–‡ä»¶åˆ—表
      fileList: {
        type: Array,
        default() {
          return []
        }
      },
      // ä¸Šä¼ å›¾ç‰‡åœ°å€
      action: {
        type: String,
        default: ''
      },
      // ä¸Šä¼ æ–‡ä»¶çš„字段名称
      name: {
        type: String,
        default: 'file'
      },
      // å¤´éƒ¨ä¿¡æ¯
      header: {
        type: Object,
        default() {
          return {}
        }
      },
      // æºå¸¦çš„参数
      formData: {
        type: Object,
        default() {
          return {}
        }
      },
      // æ˜¯å¦ç¦ç”¨
      disabled: {
        type: Boolean,
        default: false
      },
      // æ˜¯å¦è‡ªåŠ¨ä¸Šä¼ 
      autoUpload: {
        type: Boolean,
        default: true
      },
      // æœ€å¤§ä¸Šä¼ æ•°é‡
      maxCount: {
        type: Number,
        default: 9
      },
      // æ˜¯å¦æ˜¾ç¤ºç»„件自带的图片预览
      showUploadList: {
        type: Boolean,
        default: true
      },
      // é¢„览上传图片的裁剪模式
      imageMode: {
        type: String,
        default: 'aspectFill'
      },
      // ç‚¹å‡»å›¾ç‰‡æ˜¯å¦å…¨å±é¢„览
      previewFullImage: {
        type: Boolean,
        default: true
      },
      // æ˜¯å¦æ˜¾ç¤ºè¿›åº¦æ¡
      showProgress: {
        type: Boolean,
        default: true
      },
      // æ˜¯å¦æ˜¾ç¤ºåˆ é™¤æŒ‰é’®
      deleteable: {
        type: Boolean,
        default: true
      },
      // åˆ é™¤æŒ‰é’®å›¾æ ‡
      deleteIcon: {
        type: String,
        default: 'close'
      },
      // åˆ é™¤æŒ‰é’®çš„背景颜色
      deleteBackgroundColor: {
        type: String,
        default: ''
      },
      // åˆ é™¤æŒ‰é’®çš„颜色
      deleteColor: {
        type: String,
        default: ''
      },
      // ä¸Šä¼ åŒºåŸŸæç¤ºæ–‡å­—
      uploadText: {
        type: String,
        default: '选择图片'
      },
      // æ˜¾ç¤ºtoast提示
      showTips: {
        type: Boolean,
        default: true
      },
      // è‡ªå®šä¹‰é€‰æ‹©å›¾æ ‡æŒ‰é’®
      customBtn: {
        type: Boolean,
        default: false
      },
      // é¢„览图片和选择图片区域的宽度
      width: {
        type: Number,
        default: 200
      },
      // é¢„览图片和选择图片区域的高度
      height: {
        type: Number,
        default: 200
      },
      // é€‰æ‹©å›¾ç‰‡çš„尺寸
      // å‚考上传文档 https://uniapp.dcloud.io/api/media/image
      sizeType: {
        type: Array,
        default() {
          return ['original', 'compressed']
        }
      },
      // å›¾ç‰‡æ¥æº
      sourceType: {
        type: Array,
        default() {
          return ['album', 'camera']
        }
      },
      // æ˜¯å¦å¯ä»¥å¤šé€‰
      multiple: {
        type: Boolean,
        default: true
      },
      // æ–‡ä»¶å¤§å°(byte)
      maxSize: {
        type: Number,
        default: 10 * 1024 * 1024
      },
      // å…è®¸ä¸Šä¼ çš„类型
      limitType: {
        type: Array,
        default() {
          return ['png','jpg','jpeg','webp','gif','image']
        }
      },
      // æ˜¯å¦è‡ªå®šè½¬æ¢ä¸ºjson
      toJson: {
        type: Boolean,
        default: true
      },
      // ä¸Šä¼ å‰é’©å­å‡½æ•°ï¼Œæ¯ä¸ªæ–‡ä»¶ä¸Šä¼ å‰éƒ½ä¼šæ‰§è¡Œ
      beforeUpload: {
        type: Function,
        default: null
      },
      // åˆ é™¤æ–‡ä»¶å‰é’©å­å‡½æ•°
      beforeRemove: {
        type: Function,
        default: null
      },
      index: {
        type: [Number, String],
        default: ''
      }
    },
    computed: {
    },
    data() {
      return {
        lists: [],
        uploading: false
      }
    },
    watch: {
      fileList: {
        handler(val) {
          val.map(value => {
            // é¦–先检查内部是否已经添加过这张图片,因为外部绑定了一个对象给fileList的话(对象引用),进行修改外部fileList时,
            // ä¼šè§¦å‘watch,导致重新把原来的图片再次添加到this.lists
            // æ•°ç»„çš„some方法意思是,只要数组元素有任意一个元素条件符合,就返回true,而另一个数组的every方法的意思是数组所有元素都符合条件才返回true
            let tmp = this.lists.some(listVal => {
              return listVal.url === value.url
            })
            // å¦‚果内部没有这张图片,则添加到内部
            !tmp && this.lists.push({ url: value.url, error: false, progress: 100 })
          })
        },
        immediate: true
      },
      lists(val) {
        this.$emit('on-list-change', val, this.index)
      }
    },
    methods: {
      // æ¸…除列表
      clear() {
        this.lists = []
      },
      // é‡æ–°ä¸Šä¼ é˜Ÿåˆ—中上传失败所有文件
      reUpload() {
        this.uploadFile()
      },
      // é€‰æ‹©å›¾ç‰‡
      selectFile() {
        if (this.disabled) return
        const {
          name = '',
          maxCount,
          multiple,
          maxSize,
          sizeType,
          lists,
          camera,
          compressed,
          sourceType
        } = this
        let chooseFile = null
        const newMaxCount = maxCount - lists.length
        // åªé€‰æ‹©å›¾ç‰‡çš„æ—¶å€™ä½¿ç”¨ chooseImage æ¥å®žçް
        chooseFile = new Promise((resolve, reject) => {
          uni.chooseImage({
            count: multiple ? (newMaxCount > 9 ? 9 : newMaxCount) : 1,
            sourceType,
            sizeType,
            success: resolve,
            fail: reject
          })
        })
        chooseFile.then(res => {
          let file = null
          let listOldLength = lists.length
          res.tempFiles.map((val, index) => {
            if (!this.checkFileExt(val)) return
            // æ˜¯å¦è¶…出最大限制数量
            if (!multiple && index >= 1) return
            if (val.size > maxSize) {
              this.$emit('on-oversize', val, lists, this.index)
              this.showToast('超出可允许文件大小')
            } else {
              if (maxCount <= lists.length) {
                this.$emit('on-exceed', val, lists, this.index)
                this.showToast('超出最大允许的文件数')
                return
              }
              lists.push({
                url: val.path,
                progress: 0,
                error: false,
                file: val
              })
            }
          })
          this.$emit('on-choose-complete', this.lists, this.index)
          if (this.autoUpload) this.uploadFile(listOldLength)
        }).catch(err => {
          this.$emit('on-choose-fail', err)
        })
      },
      // æç¤ºç”¨æˆ·ä¿¡æ¯
      showToast(message, force = false) {
        if (this.showTips || force) {
          this.$t.message.toast(message)
        }
      },
      // æ‰‹åŠ¨ä¸Šä¼ ï¼Œé€šè¿‡ref进行调用
      upload() {
        this.uploadFile()
      },
      // å¯¹å¤±è´¥å›¾ç‰‡è¿›è¡Œå†æ¬¡ä¸Šä¼ 
      retry(index) {
        this.lists[index].progress = 0
        this.lists[index].error = false
        this.lists[index].response = null
        this.$t.message.loading('重新上传')
        this.uploadFile(index)
      },
      // ä¸Šä¼ æ–‡ä»¶
      async uploadFile(index = 0) {
        if (this.disabled) return
        if (this.uploading) return
        // å…¨éƒ¨ä¸Šä¼ å®Œæˆ
        if (index >= this.lists.length) {
          this.$emit('on-uploaded', this.lists, this.index)
          return
        }
        // æ£€æŸ¥æ˜¯å¦å·²ç»å…¨éƒ¨ä¸Šä¼ æˆ–者上传中
        if (this.lists[index].progress === 100) {
          this.lists[index].uploadTask = null
          if (this.autoUpload) this.uploadFile(index + 1)
          return
        }
        // æ‰§è¡Œbefore-upload钩子
        if (this.beforeUpload && typeof(this.beforeUpload) === 'function') {
          // åœ¨å¾®ä¿¡ï¼Œæ”¯ä»˜å®ç­‰çŽ¯å¢ƒ(H5正常),会导致父组件定义的函数体中的this变成子组件的this
          // é€šè¿‡bind()方法,绑定父组件的this,让this的this为父组件的上下文
          // å› ä¸ºupload组件可能会被嵌套在其他组件内,比如tn-form,这时this.$parent其实为tn-form的this,
          // éžé¡µé¢çš„this,所以这里需要往上历遍,一直寻找到最顶端的$parent,这里用了this.$u.$parent.call(this)
          let beforeResponse = this.beforeUpload.bind(this.$t.$parent.call(this))(index, this.lists)
          // åˆ¤æ–­æ˜¯å¦è¿”回了Promise
          if (!!beforeResponse && typeof beforeResponse.then === 'function') {
            await beforeResponse.then(res => {
              // promise返回成功,不进行操作继续
            }).catch(err => {
              // è¿›å…¥catch回调的话,继续下一张
              return this.uploadFile(index + 1)
            })
          } else if (beforeResponse === false) {
            // å¦‚果返回flase,继续下一张图片上传
            return this.uploadFile(index + 1)
          } else {
            // ä¸ºtrue的情况,不进行操作
          }
        }
        // æ£€æŸ¥ä¸Šä¼ åœ°å€
        if (!this.action) {
          this.showToast('请配置上传地址', true)
          return
        }
        this.lists[index].error = false
        this.uploading = true
        // åˆ›å»ºä¸Šä¼ å¯¹è±¡
        const task = uni.uploadFile({
          url: this.action,
          filePath: this.lists[index].url,
          name: this.name,
          formData: this.formData,
          header: this.header,
          success: res => {
            // åˆ¤æ–­å•Šæ˜¯å¦ä¸ºjson字符串,将其转换为json格式
            let data = this.toJson && this.$t.test.jsonString(res.data) ? JSON.parse(res.data) : res.data
            if (![200, 201, 204].includes(res.statusCode)) {
              this.uploadError(index, data)
            } else {
              this.lists[index].response = data
              this.lists[index].progress = 100
              this.lists[index].error = false
              this.$emit('on-success', data, index, this.lists, this.index)
            }
          },
          fail: err => {
            this.uploadError(index, err)
          },
          complete: res => {
            this.$t.message.closeLoading()
            this.uploading = false
            this.uploadFile(index + 1)
            this.$emit('on-change', res, index, this.lists, this.index)
          }
        })
        this.lists[index].uploadTask = task
        task.onProgressUpdate(res => {
          if (res.progress > 0) {
            this.lists[index].progress = res.progress
            this.$emit('on-progress', res, index, this.lists, this.index)
          }
        })
      },
      // ä¸Šä¼ å¤±è´¥
      uploadError(index, err) {
        this.lists[index].progress = 0
        this.lists[index].error = true
        this.lists[index].response = null
        this.showToast('上传失败,请重试')
        this.$emit('on-error', err, index, this.lists, this.index)
      },
      // åˆ é™¤ä¸€ä¸ªå›¾ç‰‡
      deleteItem(index) {
        if (!this.deleteable) return
        this.$t.message.modal(
          '提示',
          '您确定要删除吗?',
          async () => {
            // å…ˆæ£€æŸ¥æ˜¯å¦æœ‰å®šä¹‰before-remove移除前钩子
            // æ‰§è¡Œbefore-remove钩子
            if (this.beforeRemove && typeof(this.beforeRemove) === 'function') {
              let beforeResponse = this.beforeRemove.bind(this.$t.$parent.call(this))(index, this.lists)
              // åˆ¤æ–­æ˜¯å¦è¿”回promise
              if (!!beforeResponse && typeof beforeResponse.then === 'function') {
                await beforeResponse.then(res => {
                  // promise返回成功不进行操作
                  this.handlerDeleteItem(index)
                }).catch(err => {
                  this.showToast('删除操作被中断')
                })
              } else if (beforeResponse === false) {
                this.showToast('删除操作被中断')
              } else {
                this.handlerDeleteItem(index)
              }
            } else {
              this.handlerDeleteItem(index)
            }
          }, true)
      },
      // ç§»é™¤æ–‡ä»¶æ“ä½œ
      handlerDeleteItem(index) {
        // å¦‚果文件正在上传中,终止上传任务
        if (this.lists[index].progress < 100 && this.lists[index].progress > 0) {
          typeof this.lists[index].uploadTask !== 'undefined' && this.lists[index].uploadTask.abort()
        }
        this.lists.splice(index, 1)
        this.$forceUpdate()
        this.$emit('on-remove', index, this.lists, this.index)
        this.showToast('删除成功')
      },
      // ç§»é™¤æ–‡ä»¶ï¼Œé€šè¿‡ref手动形式进行调用
      remove(index) {
        if (!this.deleteable) return
        // åˆ¤æ–­ç´¢å¼•合法
        if (index >= 0 && index < this.lists.length) {
          this.lists.splice(index, 1)
        }
      },
      // é¢„览图片
      doPreviewImage(url, index) {
        if (!this.previewFullImage) return
        const images = this.lists.map(item => item.url || item.path)
        uni.previewImage({
          urls: images,
          current: url,
          success: () => {
            this.$emit('on-preview', url, this.lists, this.index)
          },
          fail: () => {
            this.showToast('预览图片失败')
          }
        })
      },
      // æ£€æŸ¥æ–‡ä»¶åŽç¼€æ˜¯å¦åˆæ³•
      checkFileExt(file) {
        // æ˜¯å¦ä¸ºåˆæ³•后缀
        let noArrowExt = false
        // åŽç¼€å
        let fileExt = ''
        const reg = /.+\./
        // #ifdef H5
        fileExt = file.name.replace(reg, '').toLowerCase()
        // #endif
        // #ifndef H5
        fileExt = file.path.replace(reg, '').toLowerCase()
        // #endif
        noArrowExt = this.limitType.some(ext => {
          return ext.toLowerCase() === fileExt
        })
        if (!noArrowExt) this.showToast(`不支持${fileExt}格式的文件`)
        return noArrowExt
      }
    }
  }
</script>
<style lang="scss" scoped>
  .tn-image-upload {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    &__item {
      /* #ifndef APP-NVUE */
      display: flex;
      /* #endif */
      align-items: center;
      justify-content: center;
      width: 200rpx;
      height: 200rpx;
      overflow: hidden;
      margin: 12rpx;
      margin-left: 0;
      background-color: $tn-font-holder-color;
      position: relative;
      border-radius: 10rpx;
      &-preview {
        border: 1rpx solid $tn-border-solid-color;
        &__delete {
          display: flex;
          align-items: center;
          justify-content: center;
          position: absolute;
          top: 0;
          right: 0;
          z-index: 10;
          border-top: 60rpx solid;
          border-left: 60rpx solid transparent;
          border-top-color: $tn-color-red;
          width: 0rpx;
          height: 0rpx;
          &--icon {
            position: absolute;
            top: -50rpx;
            right: 6rpx;
            color: #FFFFFF;
            font-size: 24rpx;
            line-height: 1;
          }
        }
        &__progress {
          position: absolute;
          width: auto;
          bottom: 0rpx;
          left: 0rpx;
          right: 0rpx;
          z-index: 9;
          /* #ifdef MP-WEIXIN */
          display: inline-flex;
          /* #endif */
        }
        &__error-btn {
          position: absolute;
          bottom: 0;
          left: 0;
          right: 0;
          background-color: $tn-color-red;
          color: #FFFFFF;
          font-size: 20rpx;
          padding: 8rpx 0;
          text-align: center;
          z-index: 9;
          line-height: 1;
        }
        &__image {
          display: block;
          width: 100%;
          height: 100%;
          border-radius: 10rpx;
        }
      }
      &-add {
        flex-direction: column;
        color: $tn-content-color;
        font-size: 26rpx;
        &--icon {
          font-size: 40rpx;
        }
        &__tips {
          margin-top: 20rpx;
          line-height: 40rpx;
        }
      }
    }
    &__add {
      width: auto;
      display: inline-block;
      &--custom {
        width: 100%;
      }
    }
  }
</style>
在上述文件截断后对比
吉安PDA/tuniao-ui/components/tn-index-anchor/tn-index-anchor.vue 吉安PDA/tuniao-ui/components/tn-index-list/tn-index-list.vue 吉安PDA/tuniao-ui/components/tn-input/tn-input.vue 吉安PDA/tuniao-ui/components/tn-keyboard/tn-keyboard.vue 吉安PDA/tuniao-ui/components/tn-landscape/tn-landscape.vue 吉安PDA/tuniao-ui/components/tn-lazy-load/tn-lazy-load.vue 吉安PDA/tuniao-ui/components/tn-line-progress/tn-line-progress.vue 吉安PDA/tuniao-ui/components/tn-list-cell/tn-list-cell.vue 吉安PDA/tuniao-ui/components/tn-list-view/tn-list-view.vue 吉安PDA/tuniao-ui/components/tn-load-more/tn-load-more.vue 吉安PDA/tuniao-ui/components/tn-loading/tn-loading.vue 吉安PDA/tuniao-ui/components/tn-modal/tn-modal.vue 吉安PDA/tuniao-ui/components/tn-nav-bar/tn-nav-bar.vue 吉安PDA/tuniao-ui/components/tn-notice-bar/tn-notice-bar.vue 吉安PDA/tuniao-ui/components/tn-number-box/tn-number-box.vue 吉安PDA/tuniao-ui/components/tn-number-keyboard/tn-number-keyboard.vue 吉安PDA/tuniao-ui/components/tn-picker/tn-picker.vue 吉安PDA/tuniao-ui/components/tn-popup/tn-popup.vue 吉安PDA/tuniao-ui/components/tn-radio-group/tn-radio-group.vue 吉安PDA/tuniao-ui/components/tn-radio/tn-radio.vue 吉安PDA/tuniao-ui/components/tn-rate/tn-rate.vue 吉安PDA/tuniao-ui/components/tn-read-more/tn-read-more.vue 吉安PDA/tuniao-ui/components/tn-row-notice/tn-row-notice.vue 吉安PDA/tuniao-ui/components/tn-scroll-list/tn-scroll-list.vue 吉安PDA/tuniao-ui/components/tn-scroll-view/tn-scroll-view.vue 吉安PDA/tuniao-ui/components/tn-select/tn-select.vue 吉安PDA/tuniao-ui/components/tn-sign-board/tn-sign-board.vue 吉安PDA/tuniao-ui/components/tn-skeleton/tn-skeleton.vue 吉安PDA/tuniao-ui/components/tn-slider/tn-slider.vue 吉安PDA/tuniao-ui/components/tn-stack-swiper/index-h5.wxs 吉安PDA/tuniao-ui/components/tn-stack-swiper/index.wxs 吉安PDA/tuniao-ui/components/tn-stack-swiper/tn-stack-swiper.vue 吉安PDA/tuniao-ui/components/tn-steps/tn-steps.vue 吉安PDA/tuniao-ui/components/tn-sticky/tn-sticky.vue 吉安PDA/tuniao-ui/components/tn-subsection/tn-subsection.vue 吉安PDA/tuniao-ui/components/tn-swipe-action-item/index.wxs 吉安PDA/tuniao-ui/components/tn-swipe-action-item/tn-swipe-action-item.vue 吉安PDA/tuniao-ui/components/tn-swipe-action/tn-swipe-action.vue 吉安PDA/tuniao-ui/components/tn-swiper/tn-swiper.vue 吉安PDA/tuniao-ui/components/tn-switch/tn-switch.vue 吉安PDA/tuniao-ui/components/tn-tabbar/tn-tabbar.vue 吉安PDA/tuniao-ui/components/tn-table/tn-table.vue 吉安PDA/tuniao-ui/components/tn-tabs-swiper/tn-tabs-swiper.vue 吉安PDA/tuniao-ui/components/tn-tabs/tn-tabs.vue 吉安PDA/tuniao-ui/components/tn-tag/tn-tag.vue 吉安PDA/tuniao-ui/components/tn-td/tn-td.vue 吉安PDA/tuniao-ui/components/tn-time-line-item/tn-time-line-item.vue 吉安PDA/tuniao-ui/components/tn-time-line-item/tn-time-line-item.vue_bk 吉安PDA/tuniao-ui/components/tn-time-line/tn-time-line.vue 吉安PDA/tuniao-ui/components/tn-time-line/tn-time-line.vue_bk 吉安PDA/tuniao-ui/components/tn-tips/tn-tips.vue 吉安PDA/tuniao-ui/components/tn-toast/tn-toast.vue 吉安PDA/tuniao-ui/components/tn-tr/tn-tr.vue 吉安PDA/tuniao-ui/components/tn-tree-node/tn-tree-node.vue 吉安PDA/tuniao-ui/components/tn-tree-view/tn-tree-view.vue 吉安PDA/tuniao-ui/components/tn-verification-code-input/tn-verification-code-input.vue 吉安PDA/tuniao-ui/components/tn-verification-code/tn-verification-code.vue 吉安PDA/tuniao-ui/components/tn-waterfall/tn-waterfall.vue 吉安PDA/tuniao-ui/iconfont.css 吉安PDA/tuniao-ui/index.js 吉安PDA/tuniao-ui/index.scss 吉安PDA/tuniao-ui/libs/config/color.js 吉安PDA/tuniao-ui/libs/config/zIndex.js 吉安PDA/tuniao-ui/libs/css/color.scss 吉安PDA/tuniao-ui/libs/css/main.scss 吉安PDA/tuniao-ui/libs/css/style.h5.scss 吉安PDA/tuniao-ui/libs/css/style.mp.scss 吉安PDA/tuniao-ui/libs/function/$parent.js 吉安PDA/tuniao-ui/libs/function/array.js 吉安PDA/tuniao-ui/libs/function/color.js 吉安PDA/tuniao-ui/libs/function/colorUtils.js 吉安PDA/tuniao-ui/libs/function/deepClone.js 吉安PDA/tuniao-ui/libs/function/message.js 吉安PDA/tuniao-ui/libs/function/messageUtils.js 吉安PDA/tuniao-ui/libs/function/number.js 吉安PDA/tuniao-ui/libs/function/string.js 吉安PDA/tuniao-ui/libs/function/test.js 吉安PDA/tuniao-ui/libs/function/updateCustomBarInfo.js 吉安PDA/tuniao-ui/libs/function/uuid.js 吉安PDA/tuniao-ui/libs/mixin/components_color.js 吉安PDA/tuniao-ui/libs/mixin/mixin.js 吉安PDA/tuniao-ui/libs/mixin/mpShare.js 吉安PDA/tuniao-ui/libs/mixin/touch.js 吉安PDA/tuniao-ui/libs/utils/area.js 吉安PDA/tuniao-ui/libs/utils/async-validator.js 吉安PDA/tuniao-ui/libs/utils/calendar.js 吉安PDA/tuniao-ui/libs/utils/city.js 吉安PDA/tuniao-ui/libs/utils/emitter.js 吉安PDA/tuniao-ui/libs/utils/province.js 吉安PDA/tuniao-ui/theme.scss 吉安PDA/uni.scss 吉安PDA/uni_modules/uni-badge/changelog.md 吉安PDA/uni_modules/uni-badge/components/uni-badge/uni-badge.vue 吉安PDA/uni_modules/uni-badge/package.json 吉安PDA/uni_modules/uni-badge/readme.md 吉安PDA/uni_modules/uni-card/changelog.md 吉安PDA/uni_modules/uni-card/components/uni-card/uni-card.vue 吉安PDA/uni_modules/uni-card/package.json 吉安PDA/uni_modules/uni-card/readme.md 吉安PDA/uni_modules/uni-combox/changelog.md 吉安PDA/uni_modules/uni-combox/components/uni-combox/uni-combox.vue 吉安PDA/uni_modules/uni-combox/package.json 吉安PDA/uni_modules/uni-combox/readme.md 吉安PDA/uni_modules/uni-data-checkbox/changelog.md 吉安PDA/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue 吉安PDA/uni_modules/uni-data-checkbox/package.json 吉安PDA/uni_modules/uni-data-checkbox/readme.md 吉安PDA/uni_modules/uni-data-select/changelog.md 吉安PDA/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue 吉安PDA/uni_modules/uni-data-select/package.json 吉安PDA/uni_modules/uni-data-select/readme.md 吉安PDA/uni_modules/uni-easyinput/changelog.md 吉安PDA/uni_modules/uni-easyinput/components/uni-easyinput/common.js 吉安PDA/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue 吉安PDA/uni_modules/uni-easyinput/package.json 吉安PDA/uni_modules/uni-easyinput/readme.md 吉安PDA/uni_modules/uni-forms/changelog.md 吉安PDA/uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue 吉安PDA/uni_modules/uni-forms/components/uni-forms/uni-forms.vue 吉安PDA/uni_modules/uni-forms/components/uni-forms/utils.js 吉安PDA/uni_modules/uni-forms/components/uni-forms/validate.js 吉安PDA/uni_modules/uni-forms/package.json 吉安PDA/uni_modules/uni-forms/readme.md 吉安PDA/uni_modules/uni-group/changelog.md 吉安PDA/uni_modules/uni-group/components/uni-group/uni-group.vue 吉安PDA/uni_modules/uni-group/package.json 吉安PDA/uni_modules/uni-group/readme.md 吉安PDA/uni_modules/uni-icons/changelog.md 吉安PDA/uni_modules/uni-icons/components/uni-icons/icons.js 吉安PDA/uni_modules/uni-icons/components/uni-icons/uni-icons.vue 吉安PDA/uni_modules/uni-icons/components/uni-icons/uni.ttf 吉安PDA/uni_modules/uni-icons/components/uni-icons/uniicons.css 吉安PDA/uni_modules/uni-icons/components/uni-icons/uniicons.ttf 吉安PDA/uni_modules/uni-icons/package.json 吉安PDA/uni_modules/uni-icons/readme.md 吉安PDA/uni_modules/uni-id/changelog.md 吉安PDA/uni_modules/uni-id/package.json 吉安PDA/uni_modules/uni-id/readme.md 吉安PDA/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/LICENSE.md 吉安PDA/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/index.js 吉安PDA/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package-lock.json 吉安PDA/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package.json 吉安PDA/uni_modules/uni-list/changelog.md 吉安PDA/uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue 吉安PDA/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss 吉安PDA/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue 吉安PDA/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue 吉安PDA/uni_modules/uni-list/components/uni-list/uni-list.vue 吉安PDA/uni_modules/uni-list/components/uni-list/uni-refresh.vue 吉安PDA/uni_modules/uni-list/components/uni-list/uni-refresh.wxs 吉安PDA/uni_modules/uni-list/package.json 吉安PDA/uni_modules/uni-list/readme.md 吉安PDA/uni_modules/uni-load-more/changelog.md 吉安PDA/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json 吉安PDA/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js 吉安PDA/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json 吉安PDA/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json 吉安PDA/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue 吉安PDA/uni_modules/uni-load-more/package.json 吉安PDA/uni_modules/uni-load-more/readme.md 吉安PDA/uni_modules/uni-nav-bar/changelog.md 吉安PDA/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue 吉安PDA/uni_modules/uni-nav-bar/components/uni-nav-bar/uni-status-bar.vue 吉安PDA/uni_modules/uni-nav-bar/package.json 吉安PDA/uni_modules/uni-nav-bar/readme.md 吉安PDA/uni_modules/uni-popup/changelog.md 吉安PDA/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js 吉安PDA/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue 吉安PDA/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue 吉安PDA/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue 吉安PDA/uni_modules/uni-popup/components/uni-popup/i18n/en.json 吉安PDA/uni_modules/uni-popup/components/uni-popup/i18n/index.js 吉安PDA/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json 吉安PDA/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json 吉安PDA/uni_modules/uni-popup/components/uni-popup/keypress.js 吉安PDA/uni_modules/uni-popup/components/uni-popup/popup.js 吉安PDA/uni_modules/uni-popup/components/uni-popup/uni-popup.vue 吉安PDA/uni_modules/uni-popup/package.json 吉安PDA/uni_modules/uni-popup/readme.md 吉安PDA/uni_modules/uni-scss/changelog.md 吉安PDA/uni_modules/uni-scss/index.scss 吉安PDA/uni_modules/uni-scss/package.json 吉安PDA/uni_modules/uni-scss/readme.md 吉安PDA/uni_modules/uni-scss/styles/index.scss 吉安PDA/uni_modules/uni-scss/styles/setting/_border.scss 吉安PDA/uni_modules/uni-scss/styles/setting/_color.scss 吉安PDA/uni_modules/uni-scss/styles/setting/_radius.scss 吉安PDA/uni_modules/uni-scss/styles/setting/_space.scss 吉安PDA/uni_modules/uni-scss/styles/setting/_styles.scss 吉安PDA/uni_modules/uni-scss/styles/setting/_text.scss 吉安PDA/uni_modules/uni-scss/styles/setting/_variables.scss 吉安PDA/uni_modules/uni-scss/styles/tools/functions.scss 吉安PDA/uni_modules/uni-scss/theme.scss 吉安PDA/uni_modules/uni-scss/variables.scss 吉安PDA/uni_modules/uni-search-bar/changelog.md 吉安PDA/uni_modules/uni-search-bar/components/uni-search-bar/i18n/en.json 吉安PDA/uni_modules/uni-search-bar/components/uni-search-bar/i18n/index.js 吉安PDA/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hans.json 吉安PDA/uni_modules/uni-search-bar/components/uni-search-bar/i18n/zh-Hant.json 吉安PDA/uni_modules/uni-search-bar/components/uni-search-bar/uni-search-bar.vue 吉安PDA/uni_modules/uni-search-bar/package.json 吉安PDA/uni_modules/uni-search-bar/readme.md 吉安PDA/uni_modules/uni-segmented-control/changelog.md 吉安PDA/uni_modules/uni-segmented-control/components/uni-segmented-control/uni-segmented-control.vue 吉安PDA/uni_modules/uni-segmented-control/package.json 吉安PDA/uni_modules/uni-segmented-control/readme.md 吉安PDA/uni_modules/uni-transition/changelog.md 吉安PDA/uni_modules/uni-transition/components/uni-transition/createAnimation.js 吉安PDA/uni_modules/uni-transition/components/uni-transition/uni-transition.vue 吉安PDA/uni_modules/uni-transition/package.json 吉安PDA/uni_modules/uni-transition/readme.md 吉安PDA/unpackage/cache/apk/apkurl 吉安PDA/unpackage/cache/apk/cmManifestCache.json 吉安PDA/unpackage/cache/certdata 吉安PDA/unpackage/cache/cloudcertificate/certini 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/.manifest/icon-android-hdpi.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/.manifest/icon-android-xhdpi.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/.manifest/icon-android-xxhdpi.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/.manifest/icon-android-xxxhdpi.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappchooselocation.js 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniapperror.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappes6.js 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappopenlocation.js 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniapppicker.js 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappquill.js 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappquillimageresize.js 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappscan.js 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappsuccess.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/__uniappview.html 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/app-config-service.js 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/app-config.js 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/app-service.js 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/app-view.js 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/manifest.json 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/BC.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/CK.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/CP.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/CPCK.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/CSJ.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/FL.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/GM.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/JX.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/KCCX.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/KCPD.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/RK.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/SH.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/WMSRK.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/YM.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/ZXRK.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/center-selected.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/center.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/fail.mp3 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/favicon.ico 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/iconfont.css 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/index-selected.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/index.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/login_bottom_bg.jpg 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/login_top2.jpg 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/login_top3.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/logo.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/pp.png 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/repeat.mp3 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/static/success.mp3 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/uni_modules/uni-icons/components/uni-icons/uniicons.ttf 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/view.css 吉安PDA/unpackage/cache/wgt/__UNI__4D0008D/view.umd.min.js 吉安PDA/unpackage/res/icons/1024x1024.png 吉安PDA/unpackage/res/icons/120x120.png 吉安PDA/unpackage/res/icons/144x144.png 吉安PDA/unpackage/res/icons/152x152.png 吉安PDA/unpackage/res/icons/167x167.png 吉安PDA/unpackage/res/icons/180x180.png 吉安PDA/unpackage/res/icons/192x192.png 吉安PDA/unpackage/res/icons/20241228155440.png 吉安PDA/unpackage/res/icons/20x20.png 吉安PDA/unpackage/res/icons/29x29.png 吉安PDA/unpackage/res/icons/40x40.png 吉安PDA/unpackage/res/icons/58x58.png 吉安PDA/unpackage/res/icons/60x60.png 吉安PDA/unpackage/res/icons/72x72.png 吉安PDA/unpackage/res/icons/76x76.png 吉安PDA/unpackage/res/icons/80x80.png 吉安PDA/unpackage/res/icons/87x87.png 吉安PDA/unpackage/res/icons/96x96.png 吉安PDA/unpackage/res/icons/logo.png 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappchooselocation.js 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniapperror.png 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappes6.js 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappopenlocation.js 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniapppicker.js 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappquill.js 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappquillimageresize.js 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappscan.js 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappsuccess.png 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/__uniappview.html 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/app-config-service.js 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/app-config.js 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/app-service.js 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/app-view.js 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/manifest.json 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/center-selected.png 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/center.png 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/favicon.ico 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/index-selected.png 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/index.png 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/login_bottom_bg.jpg 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/login_top2.jpg 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/login_top3.png 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/static/logo.png 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/uni_modules/uni-icons/components/uni-icons/uniicons.ttf 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/view.css 吉安PDA/unpackage/resources/__UNI__BFEF6BA/www/view.umd.min.js 吉安PDA/uview-ui/LICENSE 吉安PDA/uview-ui/README.md 吉安PDA/uview-ui/components/u-action-sheet/u-action-sheet.vue 吉安PDA/uview-ui/components/u-alert-tips/u-alert-tips.vue 吉安PDA/uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue 吉安PDA/uview-ui/components/u-avatar-cropper/weCropper.js 吉安PDA/uview-ui/components/u-avatar/u-avatar.vue 吉安PDA/uview-ui/components/u-back-top/u-back-top.vue 吉安PDA/uview-ui/components/u-badge/u-badge.vue 吉安PDA/uview-ui/components/u-button/u-button.vue 吉安PDA/uview-ui/components/u-calendar/u-calendar.vue 吉安PDA/uview-ui/components/u-car-keyboard/u-car-keyboard.vue 吉安PDA/uview-ui/components/u-card/u-card.vue 吉安PDA/uview-ui/components/u-cell-group/u-cell-group.vue 吉安PDA/uview-ui/components/u-cell-item/u-cell-item.vue 吉安PDA/uview-ui/components/u-checkbox-group/u-checkbox-group.vue 吉安PDA/uview-ui/components/u-checkbox/u-checkbox.vue 吉安PDA/uview-ui/components/u-circle-progress/u-circle-progress.vue 吉安PDA/uview-ui/components/u-col/u-col.vue 吉安PDA/uview-ui/components/u-collapse-item/u-collapse-item.vue 吉安PDA/uview-ui/components/u-collapse/u-collapse.vue 吉安PDA/uview-ui/components/u-column-notice/u-column-notice.vue 吉安PDA/uview-ui/components/u-count-down/u-count-down.vue 吉安PDA/uview-ui/components/u-count-to/u-count-to.vue 吉安PDA/uview-ui/components/u-divider/u-divider.vue 吉安PDA/uview-ui/components/u-dropdown-item/u-dropdown-item.vue 吉安PDA/uview-ui/components/u-dropdown/u-dropdown.vue 吉安PDA/uview-ui/components/u-empty/u-empty.vue 吉安PDA/uview-ui/components/u-field/u-field.vue 吉安PDA/uview-ui/components/u-form-item/u-form-item.vue 吉安PDA/uview-ui/components/u-form/u-form.vue 吉安PDA/uview-ui/components/u-full-screen/u-full-screen.vue 吉安PDA/uview-ui/components/u-gap/u-gap.vue 吉安PDA/uview-ui/components/u-grid-item/u-grid-item.vue 吉安PDA/uview-ui/components/u-grid/u-grid.vue 吉安PDA/uview-ui/components/u-icon/u-icon.vue 吉安PDA/uview-ui/components/u-image/u-image.vue 吉安PDA/uview-ui/components/u-index-anchor/u-index-anchor.vue 吉安PDA/uview-ui/components/u-index-list/u-index-list.vue 吉安PDA/uview-ui/components/u-input/u-input.vue 吉安PDA/uview-ui/components/u-keyboard/u-keyboard.vue 吉安PDA/uview-ui/components/u-lazy-load/u-lazy-load.vue 吉安PDA/uview-ui/components/u-line-progress/u-line-progress.vue 吉安PDA/uview-ui/components/u-line/u-line.vue 吉安PDA/uview-ui/components/u-link/u-link.vue 吉安PDA/uview-ui/components/u-loading-page/u-loading-page.vue 吉安PDA/uview-ui/components/u-loading/u-loading.vue 吉安PDA/uview-ui/components/u-loadmore/u-loadmore.vue 吉安PDA/uview-ui/components/u-mask/u-mask.vue 吉安PDA/uview-ui/components/u-message-input/u-message-input.vue 吉安PDA/uview-ui/components/u-modal/u-modal.vue 吉安PDA/uview-ui/components/u-navbar/u-navbar.vue 吉安PDA/uview-ui/components/u-no-network/u-no-network.vue 吉安PDA/uview-ui/components/u-notice-bar/u-notice-bar.vue 吉安PDA/uview-ui/components/u-number-box/u-number-box.vue 吉安PDA/uview-ui/components/u-number-keyboard/u-number-keyboard.vue 吉安PDA/uview-ui/components/u-parse/libs/CssHandler.js 吉安PDA/uview-ui/components/u-parse/libs/MpHtmlParser.js 吉安PDA/uview-ui/components/u-parse/libs/config.js 吉安PDA/uview-ui/components/u-parse/libs/handler.wxs 吉安PDA/uview-ui/components/u-parse/libs/trees.vue 吉安PDA/uview-ui/components/u-parse/u-parse.vue 吉安PDA/uview-ui/components/u-picker/u-picker.vue 吉安PDA/uview-ui/components/u-popup/u-popup.vue 吉安PDA/uview-ui/components/u-radio-group/u-radio-group.vue 吉安PDA/uview-ui/components/u-radio/u-radio.vue 吉安PDA/uview-ui/components/u-rate/u-rate.vue 吉安PDA/uview-ui/components/u-read-more/u-read-more.vue 吉安PDA/uview-ui/components/u-row-notice/u-row-notice.vue 吉安PDA/uview-ui/components/u-row/u-row.vue 吉安PDA/uview-ui/components/u-search/u-search.vue 吉安PDA/uview-ui/components/u-section/u-section.vue 吉安PDA/uview-ui/components/u-select/u-select.vue 吉安PDA/uview-ui/components/u-skeleton/u-skeleton.vue 吉安PDA/uview-ui/components/u-slider/u-slider.vue 吉安PDA/uview-ui/components/u-steps/u-steps.vue 吉安PDA/uview-ui/components/u-sticky/u-sticky.vue 吉安PDA/uview-ui/components/u-subsection/u-subsection.vue 吉安PDA/uview-ui/components/u-swipe-action/u-swipe-action.vue 吉安PDA/uview-ui/components/u-swiper/u-swiper.vue 吉安PDA/uview-ui/components/u-switch/u-switch.vue 吉安PDA/uview-ui/components/u-tabbar/u-tabbar.vue 吉安PDA/uview-ui/components/u-table/u-table.vue 吉安PDA/uview-ui/components/u-tabs-swiper/u-tabs-swiper.vue 吉安PDA/uview-ui/components/u-tabs/u-tabs.vue 吉安PDA/uview-ui/components/u-tag/u-tag.vue 吉安PDA/uview-ui/components/u-td/u-td.vue 吉安PDA/uview-ui/components/u-th/u-th.vue 吉安PDA/uview-ui/components/u-time-line-item/u-time-line-item.vue 吉安PDA/uview-ui/components/u-time-line/u-time-line.vue 吉安PDA/uview-ui/components/u-toast/u-toast.vue 吉安PDA/uview-ui/components/u-top-tips/u-top-tips.vue 吉安PDA/uview-ui/components/u-tr/u-tr.vue 吉安PDA/uview-ui/components/u-upload/u-upload.vue 吉安PDA/uview-ui/components/u-verification-code/u-verification-code.vue 吉安PDA/uview-ui/components/u-waterfall/u-waterfall.vue 吉安PDA/uview-ui/iconfont.css 吉安PDA/uview-ui/index.js 吉安PDA/uview-ui/index.scss 吉安PDA/uview-ui/libs/config/config.js 吉安PDA/uview-ui/libs/config/zIndex.js 吉安PDA/uview-ui/libs/css/color.scss 吉安PDA/uview-ui/libs/css/common.scss 吉安PDA/uview-ui/libs/css/style.components.scss 吉安PDA/uview-ui/libs/css/style.h5.scss 吉安PDA/uview-ui/libs/css/style.mp.scss 吉安PDA/uview-ui/libs/css/style.nvue.scss 吉安PDA/uview-ui/libs/css/style.vue.scss 吉安PDA/uview-ui/libs/function/$parent.js 吉安PDA/uview-ui/libs/function/addUnit.js 吉安PDA/uview-ui/libs/function/bem.js 吉安PDA/uview-ui/libs/function/color.js 吉安PDA/uview-ui/libs/function/colorGradient.js 吉安PDA/uview-ui/libs/function/debounce.js 吉安PDA/uview-ui/libs/function/deepClone.js 吉安PDA/uview-ui/libs/function/deepMerge.js 吉安PDA/uview-ui/libs/function/getParent.js 吉安PDA/uview-ui/libs/function/guid.js 吉安PDA/uview-ui/libs/function/md5.js 吉安PDA/uview-ui/libs/function/queryParams.js 吉安PDA/uview-ui/libs/function/random.js 吉安PDA/uview-ui/libs/function/randomArray.js 吉安PDA/uview-ui/libs/function/route.js 吉安PDA/uview-ui/libs/function/sys.js 吉安PDA/uview-ui/libs/function/test.js 吉安PDA/uview-ui/libs/function/throttle.js 吉安PDA/uview-ui/libs/function/timeFormat.js 吉安PDA/uview-ui/libs/function/timeFrom.js 吉安PDA/uview-ui/libs/function/toast.js 吉安PDA/uview-ui/libs/function/trim.js 吉安PDA/uview-ui/libs/function/type2icon.js 吉安PDA/uview-ui/libs/mixin/mixin.js 吉安PDA/uview-ui/libs/mixin/mpShare.js 吉安PDA/uview-ui/libs/request/index.js 吉安PDA/uview-ui/libs/store/index.js 吉安PDA/uview-ui/libs/util/area.js 吉安PDA/uview-ui/libs/util/async-validator.js 吉安PDA/uview-ui/libs/util/city.js 吉安PDA/uview-ui/libs/util/emitter.js 吉安PDA/uview-ui/libs/util/province.js 吉安PDA/uview-ui/package.json 吉安PDA/uview-ui/theme.scss 吉安PDA/vue.config.js