29 changed files with 22238 additions and 3737 deletions
@ -1,13 +1,559 @@ |
|||
{ |
|||
"name": "epmet-work-mp", |
|||
"version": "1.0.0", |
|||
"lockfileVersion": 1, |
|||
"lockfileVersion": 2, |
|||
"requires": true, |
|||
"packages": { |
|||
"": { |
|||
"name": "epmet-work-mp", |
|||
"version": "1.0.0", |
|||
"license": "ISC", |
|||
"dependencies": { |
|||
"@vant/weapp": "^1.11.4", |
|||
"uview-ui": "^2.0.36", |
|||
"vant": "^4.9.8" |
|||
}, |
|||
"devDependencies": {} |
|||
}, |
|||
"node_modules/@babel/helper-string-parser": { |
|||
"version": "7.25.9", |
|||
"resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", |
|||
"integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", |
|||
"peer": true, |
|||
"engines": { |
|||
"node": ">=6.9.0" |
|||
} |
|||
}, |
|||
"node_modules/@babel/helper-validator-identifier": { |
|||
"version": "7.25.9", |
|||
"resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", |
|||
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", |
|||
"peer": true, |
|||
"engines": { |
|||
"node": ">=6.9.0" |
|||
} |
|||
}, |
|||
"node_modules/@babel/parser": { |
|||
"version": "7.25.9", |
|||
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.25.9.tgz", |
|||
"integrity": "sha512-aI3jjAAO1fh7vY/pBGsn1i9LDbRP43+asrRlkPuTXW5yHXtd1NgTEMudbBoDDxrf1daEEfPJqR+JBMakzrR4Dg==", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@babel/types": "^7.25.9" |
|||
}, |
|||
"bin": { |
|||
"parser": "bin/babel-parser.js" |
|||
}, |
|||
"engines": { |
|||
"node": ">=6.0.0" |
|||
} |
|||
}, |
|||
"node_modules/@babel/types": { |
|||
"version": "7.25.9", |
|||
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.25.9.tgz", |
|||
"integrity": "sha512-OwS2CM5KocvQ/k7dFJa8i5bNGJP0hXWfVCfDkqRFP1IreH1JDC7wG6eCYCi0+McbfT8OR/kNqsI0UU0xP9H6PQ==", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@babel/helper-string-parser": "^7.25.9", |
|||
"@babel/helper-validator-identifier": "^7.25.9" |
|||
}, |
|||
"engines": { |
|||
"node": ">=6.9.0" |
|||
} |
|||
}, |
|||
"node_modules/@jridgewell/sourcemap-codec": { |
|||
"version": "1.5.0", |
|||
"resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", |
|||
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", |
|||
"peer": true |
|||
}, |
|||
"node_modules/@vant/popperjs": { |
|||
"version": "1.3.0", |
|||
"resolved": "https://registry.npmmirror.com/@vant/popperjs/-/popperjs-1.3.0.tgz", |
|||
"integrity": "sha512-hB+czUG+aHtjhaEmCJDuXOep0YTZjdlRR+4MSmIFnkCQIxJaXLQdSsR90XWvAI2yvKUI7TCGqR8pQg2RtvkMHw==" |
|||
}, |
|||
"node_modules/@vant/use": { |
|||
"version": "1.6.0", |
|||
"resolved": "https://registry.npmmirror.com/@vant/use/-/use-1.6.0.tgz", |
|||
"integrity": "sha512-PHHxeAASgiOpSmMjceweIrv2AxDZIkWXyaczksMoWvKV2YAYEhoizRuk/xFnKF+emUIi46TsQ+rvlm/t2BBCfA==", |
|||
"peerDependencies": { |
|||
"vue": "^3.0.0" |
|||
} |
|||
}, |
|||
"node_modules/@vant/weapp": { |
|||
"version": "1.11.4", |
|||
"resolved": "https://registry.npmmirror.com/@vant/weapp/-/weapp-1.11.4.tgz", |
|||
"integrity": "sha512-egOsWO4hVMP1SQSqQ46jy8UD3WysvlnUecRzPM21Y3ovkOFZ6wlaO7oHQmTXRpwr+V41Qri1qEbtNjhVxFqdyw==" |
|||
}, |
|||
"node_modules/@vue/compiler-core": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.12.tgz", |
|||
"integrity": "sha512-ISyBTRMmMYagUxhcpyEH0hpXRd/KqDU4ymofPgl2XAkY9ZhQ+h0ovEZJIiPop13UmR/54oA2cgMDjgroRelaEw==", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@babel/parser": "^7.25.3", |
|||
"@vue/shared": "3.5.12", |
|||
"entities": "^4.5.0", |
|||
"estree-walker": "^2.0.2", |
|||
"source-map-js": "^1.2.0" |
|||
} |
|||
}, |
|||
"node_modules/@vue/compiler-dom": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.12.tgz", |
|||
"integrity": "sha512-9G6PbJ03uwxLHKQ3P42cMTi85lDRvGLB2rSGOiQqtXELat6uI4n8cNz9yjfVHRPIu+MsK6TE418Giruvgptckg==", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@vue/compiler-core": "3.5.12", |
|||
"@vue/shared": "3.5.12" |
|||
} |
|||
}, |
|||
"node_modules/@vue/compiler-sfc": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.12.tgz", |
|||
"integrity": "sha512-2k973OGo2JuAa5+ZlekuQJtitI5CgLMOwgl94BzMCsKZCX/xiqzJYzapl4opFogKHqwJk34vfsaKpfEhd1k5nw==", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@babel/parser": "^7.25.3", |
|||
"@vue/compiler-core": "3.5.12", |
|||
"@vue/compiler-dom": "3.5.12", |
|||
"@vue/compiler-ssr": "3.5.12", |
|||
"@vue/shared": "3.5.12", |
|||
"estree-walker": "^2.0.2", |
|||
"magic-string": "^0.30.11", |
|||
"postcss": "^8.4.47", |
|||
"source-map-js": "^1.2.0" |
|||
} |
|||
}, |
|||
"node_modules/@vue/compiler-ssr": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.12.tgz", |
|||
"integrity": "sha512-eLwc7v6bfGBSM7wZOGPmRavSWzNFF6+PdRhE+VFJhNCgHiF8AM7ccoqcv5kBXA2eWUfigD7byekvf/JsOfKvPA==", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@vue/compiler-dom": "3.5.12", |
|||
"@vue/shared": "3.5.12" |
|||
} |
|||
}, |
|||
"node_modules/@vue/reactivity": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.12.tgz", |
|||
"integrity": "sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg==", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@vue/shared": "3.5.12" |
|||
} |
|||
}, |
|||
"node_modules/@vue/runtime-core": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.12.tgz", |
|||
"integrity": "sha512-hrMUYV6tpocr3TL3Ad8DqxOdpDe4zuQY4HPY3X/VRh+L2myQO8MFXPAMarIOSGNu0bFAjh1yBkMPXZBqCk62Uw==", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@vue/reactivity": "3.5.12", |
|||
"@vue/shared": "3.5.12" |
|||
} |
|||
}, |
|||
"node_modules/@vue/runtime-dom": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.12.tgz", |
|||
"integrity": "sha512-q8VFxR9A2MRfBr6/55Q3umyoN7ya836FzRXajPB6/Vvuv0zOPL+qltd9rIMzG/DbRLAIlREmnLsplEF/kotXKA==", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@vue/reactivity": "3.5.12", |
|||
"@vue/runtime-core": "3.5.12", |
|||
"@vue/shared": "3.5.12", |
|||
"csstype": "^3.1.3" |
|||
} |
|||
}, |
|||
"node_modules/@vue/server-renderer": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.12.tgz", |
|||
"integrity": "sha512-I3QoeDDeEPZm8yR28JtY+rk880Oqmj43hreIBVTicisFTx/Dl7JpG72g/X7YF8hnQD3IFhkky5i2bPonwrTVPg==", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@vue/compiler-ssr": "3.5.12", |
|||
"@vue/shared": "3.5.12" |
|||
}, |
|||
"peerDependencies": { |
|||
"vue": "3.5.12" |
|||
} |
|||
}, |
|||
"node_modules/@vue/shared": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.12.tgz", |
|||
"integrity": "sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==" |
|||
}, |
|||
"node_modules/csstype": { |
|||
"version": "3.1.3", |
|||
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz", |
|||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", |
|||
"peer": true |
|||
}, |
|||
"node_modules/entities": { |
|||
"version": "4.5.0", |
|||
"resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz", |
|||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", |
|||
"peer": true, |
|||
"engines": { |
|||
"node": ">=0.12" |
|||
}, |
|||
"funding": { |
|||
"url": "https://github.com/fb55/entities?sponsor=1" |
|||
} |
|||
}, |
|||
"node_modules/estree-walker": { |
|||
"version": "2.0.2", |
|||
"resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", |
|||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", |
|||
"peer": true |
|||
}, |
|||
"node_modules/magic-string": { |
|||
"version": "0.30.12", |
|||
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.12.tgz", |
|||
"integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@jridgewell/sourcemap-codec": "^1.5.0" |
|||
} |
|||
}, |
|||
"node_modules/nanoid": { |
|||
"version": "3.3.7", |
|||
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.7.tgz", |
|||
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", |
|||
"funding": [ |
|||
{ |
|||
"type": "github", |
|||
"url": "https://github.com/sponsors/ai" |
|||
} |
|||
], |
|||
"peer": true, |
|||
"bin": { |
|||
"nanoid": "bin/nanoid.cjs" |
|||
}, |
|||
"engines": { |
|||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" |
|||
} |
|||
}, |
|||
"node_modules/picocolors": { |
|||
"version": "1.1.1", |
|||
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", |
|||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", |
|||
"peer": true |
|||
}, |
|||
"node_modules/postcss": { |
|||
"version": "8.4.47", |
|||
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.47.tgz", |
|||
"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", |
|||
"funding": [ |
|||
{ |
|||
"type": "opencollective", |
|||
"url": "https://opencollective.com/postcss/" |
|||
}, |
|||
{ |
|||
"type": "tidelift", |
|||
"url": "https://tidelift.com/funding/github/npm/postcss" |
|||
}, |
|||
{ |
|||
"type": "github", |
|||
"url": "https://github.com/sponsors/ai" |
|||
} |
|||
], |
|||
"peer": true, |
|||
"dependencies": { |
|||
"nanoid": "^3.3.7", |
|||
"picocolors": "^1.1.0", |
|||
"source-map-js": "^1.2.1" |
|||
}, |
|||
"engines": { |
|||
"node": "^10 || ^12 || >=14" |
|||
} |
|||
}, |
|||
"node_modules/source-map-js": { |
|||
"version": "1.2.1", |
|||
"resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", |
|||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", |
|||
"peer": true, |
|||
"engines": { |
|||
"node": ">=0.10.0" |
|||
} |
|||
}, |
|||
"node_modules/uview-ui": { |
|||
"version": "2.0.36", |
|||
"resolved": "https://registry.npmmirror.com/uview-ui/-/uview-ui-2.0.36.tgz", |
|||
"integrity": "sha512-ASSZT6M8w3GTO1eFPbsgEFV0U5UujK+8pTNr+MSUbRNcRMC1u63DDTLJVeArV91kWM0bfAexK3SK9pnTqF9TtA==", |
|||
"engines": { |
|||
"HBuilderX": "^3.1.0" |
|||
} |
|||
}, |
|||
"node_modules/vant": { |
|||
"version": "4.9.8", |
|||
"resolved": "https://registry.npmmirror.com/vant/-/vant-4.9.8.tgz", |
|||
"integrity": "sha512-iP+jNzwxkCeEdTrlUjro3WoXgY32+1CldOtLSc2K8acY7hR7t1zCkjzXSR9zWjtWT7zgNL1LEXofL8O7mtkYdQ==", |
|||
"dependencies": { |
|||
"@vant/popperjs": "^1.3.0", |
|||
"@vant/use": "^1.6.0", |
|||
"@vue/shared": "^3.5.11" |
|||
}, |
|||
"peerDependencies": { |
|||
"vue": "^3.0.0" |
|||
} |
|||
}, |
|||
"node_modules/vue": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.12.tgz", |
|||
"integrity": "sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==", |
|||
"peer": true, |
|||
"dependencies": { |
|||
"@vue/compiler-dom": "3.5.12", |
|||
"@vue/compiler-sfc": "3.5.12", |
|||
"@vue/runtime-dom": "3.5.12", |
|||
"@vue/server-renderer": "3.5.12", |
|||
"@vue/shared": "3.5.12" |
|||
}, |
|||
"peerDependencies": { |
|||
"typescript": "*" |
|||
}, |
|||
"peerDependenciesMeta": { |
|||
"typescript": { |
|||
"optional": true |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"dependencies": { |
|||
"@babel/helper-string-parser": { |
|||
"version": "7.25.9", |
|||
"resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", |
|||
"integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", |
|||
"peer": true |
|||
}, |
|||
"@babel/helper-validator-identifier": { |
|||
"version": "7.25.9", |
|||
"resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", |
|||
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", |
|||
"peer": true |
|||
}, |
|||
"@babel/parser": { |
|||
"version": "7.25.9", |
|||
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.25.9.tgz", |
|||
"integrity": "sha512-aI3jjAAO1fh7vY/pBGsn1i9LDbRP43+asrRlkPuTXW5yHXtd1NgTEMudbBoDDxrf1daEEfPJqR+JBMakzrR4Dg==", |
|||
"peer": true, |
|||
"requires": { |
|||
"@babel/types": "^7.25.9" |
|||
} |
|||
}, |
|||
"@babel/types": { |
|||
"version": "7.25.9", |
|||
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.25.9.tgz", |
|||
"integrity": "sha512-OwS2CM5KocvQ/k7dFJa8i5bNGJP0hXWfVCfDkqRFP1IreH1JDC7wG6eCYCi0+McbfT8OR/kNqsI0UU0xP9H6PQ==", |
|||
"peer": true, |
|||
"requires": { |
|||
"@babel/helper-string-parser": "^7.25.9", |
|||
"@babel/helper-validator-identifier": "^7.25.9" |
|||
} |
|||
}, |
|||
"@jridgewell/sourcemap-codec": { |
|||
"version": "1.5.0", |
|||
"resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", |
|||
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", |
|||
"peer": true |
|||
}, |
|||
"@vant/popperjs": { |
|||
"version": "1.3.0", |
|||
"resolved": "https://registry.npmmirror.com/@vant/popperjs/-/popperjs-1.3.0.tgz", |
|||
"integrity": "sha512-hB+czUG+aHtjhaEmCJDuXOep0YTZjdlRR+4MSmIFnkCQIxJaXLQdSsR90XWvAI2yvKUI7TCGqR8pQg2RtvkMHw==" |
|||
}, |
|||
"@vant/use": { |
|||
"version": "1.6.0", |
|||
"resolved": "https://registry.npmmirror.com/@vant/use/-/use-1.6.0.tgz", |
|||
"integrity": "sha512-PHHxeAASgiOpSmMjceweIrv2AxDZIkWXyaczksMoWvKV2YAYEhoizRuk/xFnKF+emUIi46TsQ+rvlm/t2BBCfA==", |
|||
"requires": {} |
|||
}, |
|||
"@vant/weapp": { |
|||
"version": "1.11.4", |
|||
"resolved": "https://registry.npmmirror.com/@vant/weapp/-/weapp-1.11.4.tgz", |
|||
"integrity": "sha512-egOsWO4hVMP1SQSqQ46jy8UD3WysvlnUecRzPM21Y3ovkOFZ6wlaO7oHQmTXRpwr+V41Qri1qEbtNjhVxFqdyw==" |
|||
}, |
|||
"@vue/compiler-core": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.12.tgz", |
|||
"integrity": "sha512-ISyBTRMmMYagUxhcpyEH0hpXRd/KqDU4ymofPgl2XAkY9ZhQ+h0ovEZJIiPop13UmR/54oA2cgMDjgroRelaEw==", |
|||
"peer": true, |
|||
"requires": { |
|||
"@babel/parser": "^7.25.3", |
|||
"@vue/shared": "3.5.12", |
|||
"entities": "^4.5.0", |
|||
"estree-walker": "^2.0.2", |
|||
"source-map-js": "^1.2.0" |
|||
} |
|||
}, |
|||
"@vue/compiler-dom": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.12.tgz", |
|||
"integrity": "sha512-9G6PbJ03uwxLHKQ3P42cMTi85lDRvGLB2rSGOiQqtXELat6uI4n8cNz9yjfVHRPIu+MsK6TE418Giruvgptckg==", |
|||
"peer": true, |
|||
"requires": { |
|||
"@vue/compiler-core": "3.5.12", |
|||
"@vue/shared": "3.5.12" |
|||
} |
|||
}, |
|||
"@vue/compiler-sfc": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.12.tgz", |
|||
"integrity": "sha512-2k973OGo2JuAa5+ZlekuQJtitI5CgLMOwgl94BzMCsKZCX/xiqzJYzapl4opFogKHqwJk34vfsaKpfEhd1k5nw==", |
|||
"peer": true, |
|||
"requires": { |
|||
"@babel/parser": "^7.25.3", |
|||
"@vue/compiler-core": "3.5.12", |
|||
"@vue/compiler-dom": "3.5.12", |
|||
"@vue/compiler-ssr": "3.5.12", |
|||
"@vue/shared": "3.5.12", |
|||
"estree-walker": "^2.0.2", |
|||
"magic-string": "^0.30.11", |
|||
"postcss": "^8.4.47", |
|||
"source-map-js": "^1.2.0" |
|||
} |
|||
}, |
|||
"@vue/compiler-ssr": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.12.tgz", |
|||
"integrity": "sha512-eLwc7v6bfGBSM7wZOGPmRavSWzNFF6+PdRhE+VFJhNCgHiF8AM7ccoqcv5kBXA2eWUfigD7byekvf/JsOfKvPA==", |
|||
"peer": true, |
|||
"requires": { |
|||
"@vue/compiler-dom": "3.5.12", |
|||
"@vue/shared": "3.5.12" |
|||
} |
|||
}, |
|||
"@vue/reactivity": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.12.tgz", |
|||
"integrity": "sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg==", |
|||
"peer": true, |
|||
"requires": { |
|||
"@vue/shared": "3.5.12" |
|||
} |
|||
}, |
|||
"@vue/runtime-core": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.12.tgz", |
|||
"integrity": "sha512-hrMUYV6tpocr3TL3Ad8DqxOdpDe4zuQY4HPY3X/VRh+L2myQO8MFXPAMarIOSGNu0bFAjh1yBkMPXZBqCk62Uw==", |
|||
"peer": true, |
|||
"requires": { |
|||
"@vue/reactivity": "3.5.12", |
|||
"@vue/shared": "3.5.12" |
|||
} |
|||
}, |
|||
"@vue/runtime-dom": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.12.tgz", |
|||
"integrity": "sha512-q8VFxR9A2MRfBr6/55Q3umyoN7ya836FzRXajPB6/Vvuv0zOPL+qltd9rIMzG/DbRLAIlREmnLsplEF/kotXKA==", |
|||
"peer": true, |
|||
"requires": { |
|||
"@vue/reactivity": "3.5.12", |
|||
"@vue/runtime-core": "3.5.12", |
|||
"@vue/shared": "3.5.12", |
|||
"csstype": "^3.1.3" |
|||
} |
|||
}, |
|||
"@vue/server-renderer": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.12.tgz", |
|||
"integrity": "sha512-I3QoeDDeEPZm8yR28JtY+rk880Oqmj43hreIBVTicisFTx/Dl7JpG72g/X7YF8hnQD3IFhkky5i2bPonwrTVPg==", |
|||
"peer": true, |
|||
"requires": { |
|||
"@vue/compiler-ssr": "3.5.12", |
|||
"@vue/shared": "3.5.12" |
|||
} |
|||
}, |
|||
"@vue/shared": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.12.tgz", |
|||
"integrity": "sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==" |
|||
}, |
|||
"csstype": { |
|||
"version": "3.1.3", |
|||
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz", |
|||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", |
|||
"peer": true |
|||
}, |
|||
"entities": { |
|||
"version": "4.5.0", |
|||
"resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz", |
|||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", |
|||
"peer": true |
|||
}, |
|||
"estree-walker": { |
|||
"version": "2.0.2", |
|||
"resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", |
|||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", |
|||
"peer": true |
|||
}, |
|||
"magic-string": { |
|||
"version": "0.30.12", |
|||
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.12.tgz", |
|||
"integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", |
|||
"peer": true, |
|||
"requires": { |
|||
"@jridgewell/sourcemap-codec": "^1.5.0" |
|||
} |
|||
}, |
|||
"nanoid": { |
|||
"version": "3.3.7", |
|||
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.7.tgz", |
|||
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", |
|||
"peer": true |
|||
}, |
|||
"picocolors": { |
|||
"version": "1.1.1", |
|||
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", |
|||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", |
|||
"peer": true |
|||
}, |
|||
"postcss": { |
|||
"version": "8.4.47", |
|||
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.47.tgz", |
|||
"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", |
|||
"peer": true, |
|||
"requires": { |
|||
"nanoid": "^3.3.7", |
|||
"picocolors": "^1.1.0", |
|||
"source-map-js": "^1.2.1" |
|||
} |
|||
}, |
|||
"source-map-js": { |
|||
"version": "1.2.1", |
|||
"resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", |
|||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", |
|||
"peer": true |
|||
}, |
|||
"uview-ui": { |
|||
"version": "2.0.36", |
|||
"resolved": "https://registry.npmmirror.com/uview-ui/-/uview-ui-2.0.36.tgz", |
|||
"integrity": "sha512-ASSZT6M8w3GTO1eFPbsgEFV0U5UujK+8pTNr+MSUbRNcRMC1u63DDTLJVeArV91kWM0bfAexK3SK9pnTqF9TtA==" |
|||
}, |
|||
"vant": { |
|||
"version": "4.9.8", |
|||
"resolved": "https://registry.npmmirror.com/vant/-/vant-4.9.8.tgz", |
|||
"integrity": "sha512-iP+jNzwxkCeEdTrlUjro3WoXgY32+1CldOtLSc2K8acY7hR7t1zCkjzXSR9zWjtWT7zgNL1LEXofL8O7mtkYdQ==", |
|||
"requires": { |
|||
"@vant/popperjs": "^1.3.0", |
|||
"@vant/use": "^1.6.0", |
|||
"@vue/shared": "^3.5.11" |
|||
} |
|||
}, |
|||
"vue": { |
|||
"version": "3.5.12", |
|||
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.12.tgz", |
|||
"integrity": "sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==", |
|||
"peer": true, |
|||
"requires": { |
|||
"@vue/compiler-dom": "3.5.12", |
|||
"@vue/compiler-sfc": "3.5.12", |
|||
"@vue/runtime-dom": "3.5.12", |
|||
"@vue/server-renderer": "3.5.12", |
|||
"@vue/shared": "3.5.12" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
File diff suppressed because it is too large
@ -0,0 +1,6 @@ |
|||
## 1.0.2(2024-05-10) |
|||
修复attrs问题 |
|||
## 1.0.1(2024-05-09) |
|||
修复异步 默认值回填 问题 |
|||
## 1.0.0(2024-05-01) |
|||
1.0.0 |
File diff suppressed because it is too large
@ -0,0 +1,409 @@ |
|||
<template> |
|||
<view class="uni-data-tree"> |
|||
<slot :data="gridText"> |
|||
<!-- 输入框 --> |
|||
<view class="uni-data-tree-input" @click="handleInput"> |
|||
<view class="input-value" :class="{ 'input-value-border': border }"> |
|||
<!-- 展示选择的值 --> |
|||
<scroll-view v-if="gridText" class="selected-area" scroll-x="true"> |
|||
<view class="selected-list"> |
|||
<view class="selected-item"> |
|||
<text>{{ gridText }}</text> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
<!-- 提示信息 --> |
|||
<text v-else class="selected-area placeholder">{{ placeholder }}</text> |
|||
<!-- 展示删除按钮 --> |
|||
<view v-if="clearIcon && !readonly && gridText" class="icon-clear" @click.stop="clear"> |
|||
<view class="dialog-close"> |
|||
<view class="dialog-close-plus" data-id="close"></view> |
|||
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view> |
|||
</view> |
|||
</view> |
|||
<!-- 展示下拉图标 --> |
|||
<view class="arrow-area" v-if="(!clearIcon || !gridText) && !readonly"> |
|||
<view class="input-arrow"></view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</slot> |
|||
<!-- 遮罩层 --> |
|||
<view class="uni-data-tree-cover" v-if="isOpened" @click="handleClose"></view> |
|||
<!-- 弹出层 --> |
|||
<view class="uni-data-tree-dialog" v-show="isOpened"> |
|||
<view class="uni-popper__arrow"></view> |
|||
<view class="dialog-caption"> |
|||
<view class="title-area"> |
|||
<text class="dialog-title">{{ popupTitle }}</text> |
|||
</view> |
|||
<view class="dialog-close" @click="handleClose"> |
|||
<view class="dialog-close-plus" data-id="close"></view> |
|||
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view> |
|||
</view> |
|||
</view> |
|||
<tui-cascade-selection ref="gridSelet" v-bind="$attrs" @complete="complete" @change="onChange"></tui-cascade-selection> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import tuiCascadeSelection from './select.vue'; |
|||
|
|||
export default { |
|||
name: 'grid-cascade-selection', |
|||
data() { |
|||
return { |
|||
isOpened: false, |
|||
gridText: '' |
|||
}; |
|||
}, |
|||
components: { |
|||
tuiCascadeSelection |
|||
}, |
|||
emits: ['popupopened', 'popupclosed', 'completeChange', 'inputChange'], |
|||
|
|||
props: { |
|||
placeholder: { |
|||
type: String, |
|||
default: '请选择' |
|||
}, |
|||
popupTitle: { |
|||
type: String, |
|||
default: '请选择' |
|||
}, |
|||
readonly: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
clearIcon: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
border: { |
|||
type: Boolean, |
|||
default: true |
|||
} |
|||
}, |
|||
created() {}, |
|||
|
|||
watch: { |
|||
'$attrs.defaultItemList': { |
|||
handler(newVal, oldVal) { |
|||
if (!(newVal === oldVal)) { |
|||
this.gridText = this.getInitValue(); |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
// 初始化默认值 |
|||
getInitValue() { |
|||
let { defaultItemList, request } = this.$attrs; |
|||
let list = JSON.parse(JSON.stringify(defaultItemList || [])); |
|||
if ((typeof list[0] === 'string' || typeof list[0] === 'number') && !this.request) { |
|||
return list.join('/'); |
|||
} else { |
|||
let selsctArr = []; |
|||
list.forEach((item) => { |
|||
selsctArr.push(item.text); |
|||
}); |
|||
|
|||
return selsctArr.join('/'); |
|||
} |
|||
}, |
|||
// 选择完毕后触发 |
|||
complete(e) { |
|||
console.log(e); |
|||
let list = JSON.parse(JSON.stringify(e.result || [])); |
|||
let selsctArr = []; |
|||
list.forEach((item) => { |
|||
selsctArr.push(item.text); |
|||
}); |
|||
this.gridText = selsctArr.join('/'); |
|||
this.isOpened = false; |
|||
this.$emit('completeChange', e); |
|||
this.$emit('popupclosed'); |
|||
}, |
|||
//展示 |
|||
show() { |
|||
this.isOpened = true; |
|||
this.$emit('popupopened'); |
|||
}, |
|||
// 变化时触发 |
|||
onChange(e) { |
|||
this.$emit('inputChange', e); |
|||
}, |
|||
// 关闭 |
|||
hide() { |
|||
this.isOpened = false; |
|||
this.$emit('popupclosed'); |
|||
}, |
|||
// 展示 |
|||
handleInput() { |
|||
if (this.readonly) { |
|||
return; |
|||
} |
|||
this.show(); |
|||
}, |
|||
// 关闭 |
|||
handleClose(e) { |
|||
this.hide(); |
|||
}, |
|||
// 删除按钮 |
|||
clear() { |
|||
this.gridText = ''; |
|||
this.$refs.gridSelet.clear(); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style> |
|||
.uni-data-tree { |
|||
position: relative; |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.error-text { |
|||
color: #dd524d; |
|||
} |
|||
|
|||
.input-value { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
align-items: center; |
|||
flex-wrap: nowrap; |
|||
font-size: 14px; |
|||
line-height: 38px; |
|||
padding: 0 5px; |
|||
overflow: hidden; |
|||
/* #ifdef APP-NVUE */ |
|||
height: 40px; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.input-value-border { |
|||
border: 1px solid #e5e5e5; |
|||
border-radius: 5px; |
|||
} |
|||
|
|||
.selected-area { |
|||
flex: 1; |
|||
overflow: hidden; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
} |
|||
|
|||
.load-more { |
|||
/* #ifndef APP-NVUE */ |
|||
margin-right: auto; |
|||
/* #endif */ |
|||
/* #ifdef APP-NVUE */ |
|||
width: 40px; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.selected-list { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
flex-wrap: nowrap; |
|||
padding: 0 5px; |
|||
} |
|||
|
|||
.selected-item { |
|||
flex-direction: row; |
|||
padding: 0 1px; |
|||
/* #ifndef APP-NVUE */ |
|||
white-space: nowrap; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.placeholder { |
|||
font-size: 24rpx; |
|||
color: #bbbbbb; |
|||
} |
|||
|
|||
.input-split-line { |
|||
opacity: 0.5; |
|||
} |
|||
|
|||
.arrow-area { |
|||
position: relative; |
|||
width: 20px; |
|||
/* #ifndef APP-NVUE */ |
|||
margin-bottom: 5px; |
|||
margin-left: auto; |
|||
display: flex; |
|||
/* #endif */ |
|||
justify-content: center; |
|||
transform: rotate(-45deg); |
|||
transform-origin: center; |
|||
} |
|||
|
|||
.input-arrow { |
|||
width: 7px; |
|||
height: 7px; |
|||
border-left: 1px solid #999; |
|||
border-bottom: 1px solid #999; |
|||
} |
|||
|
|||
.uni-data-tree-cover { |
|||
position: fixed; |
|||
left: 0; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background-color: rgba(0, 0, 0, 0.4); |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: column; |
|||
z-index: 100; |
|||
} |
|||
|
|||
.uni-data-tree-dialog { |
|||
position: fixed; |
|||
left: 0; |
|||
top: 20%; |
|||
right: 0; |
|||
bottom: 0; |
|||
background-color: #ffffff; |
|||
border-top-left-radius: 10px; |
|||
border-top-right-radius: 10px; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: column; |
|||
z-index: 102; |
|||
overflow: hidden; |
|||
/* #ifdef APP-NVUE */ |
|||
width: 750rpx; |
|||
/* #endif */ |
|||
} |
|||
|
|||
.dialog-caption { |
|||
position: relative; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
/* border-bottom: 1px solid #f0f0f0; */ |
|||
} |
|||
|
|||
.title-area { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
align-items: center; |
|||
/* #ifndef APP-NVUE */ |
|||
margin: auto; |
|||
/* #endif */ |
|||
padding: 0 10px; |
|||
} |
|||
|
|||
.dialog-title { |
|||
/* font-weight: bold; */ |
|||
line-height: 44px; |
|||
} |
|||
|
|||
.dialog-close { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
align-items: center; |
|||
padding: 0 15px; |
|||
z-index: 999; |
|||
} |
|||
|
|||
.dialog-close-plus { |
|||
width: 16px; |
|||
height: 2px; |
|||
background-color: #666; |
|||
border-radius: 2px; |
|||
transform: rotate(45deg); |
|||
} |
|||
|
|||
.dialog-close-rotate { |
|||
position: absolute; |
|||
transform: rotate(-45deg); |
|||
} |
|||
|
|||
.picker-view { |
|||
flex: 1; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
/* #ifdef H5 */ |
|||
@media all and (min-width: 768px) { |
|||
.uni-data-tree-cover { |
|||
background-color: transparent; |
|||
} |
|||
|
|||
.uni-data-tree-dialog { |
|||
position: absolute; |
|||
top: 55px; |
|||
/* height: auto; */ |
|||
/* min-height: 400px; */ |
|||
max-height: 50vh; |
|||
background-color: #fff; |
|||
border: 1px solid #ebeef5; |
|||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |
|||
border-radius: 4px; |
|||
overflow: unset; |
|||
} |
|||
|
|||
.dialog-caption { |
|||
display: none; |
|||
} |
|||
|
|||
.icon-clear { |
|||
margin-right: 5px; |
|||
} |
|||
} |
|||
|
|||
/* #endif */ |
|||
|
|||
/* picker 弹出层通用的指示小三角, todo:扩展至上下左右方向定位 */ |
|||
/* #ifndef APP-NVUE */ |
|||
.uni-popper__arrow, |
|||
.uni-popper__arrow::after { |
|||
position: absolute; |
|||
display: block; |
|||
width: 0; |
|||
height: 0; |
|||
border-color: transparent; |
|||
border-style: solid; |
|||
border-width: 6px; |
|||
} |
|||
|
|||
.uni-popper__arrow { |
|||
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03)); |
|||
top: -6px; |
|||
left: 10%; |
|||
margin-right: 3px; |
|||
border-top-width: 0; |
|||
border-bottom-color: #ebeef5; |
|||
} |
|||
|
|||
.uni-popper__arrow::after { |
|||
content: ' '; |
|||
top: 1px; |
|||
margin-left: -6px; |
|||
border-top-width: 0; |
|||
border-bottom-color: #fff; |
|||
} |
|||
|
|||
/* #endif */ |
|||
</style> |
@ -0,0 +1,723 @@ |
|||
<template> |
|||
<view class="tui-cascade-selection"> |
|||
<!-- 头部导航栏 --> |
|||
<scroll-view |
|||
scroll-x |
|||
scroll-with-animation |
|||
:scroll-into-view="scrollViewId" |
|||
:style="{ backgroundColor: headerBgColor }" |
|||
class="tui-bottom-line" |
|||
:class="{ 'tui-btm-none': !headerLine }" |
|||
> |
|||
<view class="tui-selection-header" :style="{ height: tabsHeight, backgroundColor: backgroundColor }"> |
|||
<view |
|||
class="tui-header-item" |
|||
:class="{ 'tui-font-bold': idx === currentTab && bold }" |
|||
:style="{ color: idx === currentTab ? getActiveColor : color, fontSize: size + 'rpx' }" |
|||
:id="`id_${idx}`" |
|||
@tap.stop="swichNav" |
|||
:data-current="idx" |
|||
v-for="(item, idx) in selectedArr" |
|||
:key="idx" |
|||
> |
|||
{{ item.text }} |
|||
<view class="tui-active-line" :style="{ backgroundColor: getLineColor }" v-if="idx === currentTab && showLine"></view> |
|||
</view> |
|||
</view> |
|||
</scroll-view> |
|||
<!-- 视图切换器 --> |
|||
<swiper class="tui-selection-list" :current="defTab" duration="300" @change="switchTab" :style="{ height: height, backgroundColor: backgroundColor }"> |
|||
<swiper-item v-for="(item, index) in selectedArr" :key="index"> |
|||
<scroll-view scroll-y :scroll-into-view="item.scrollViewId" class="tui-selection-item" :style="{ height: height }"> |
|||
<view class="tui-first-item" :style="{ height: firstItemTop }"></view> |
|||
<view |
|||
class="tui-selection-cell" |
|||
:style="{ padding: padding, backgroundColor: backgroundColor }" |
|||
:id="`id_${subIndex}`" |
|||
v-for="(subItem, subIndex) in item.list" |
|||
:key="subIndex" |
|||
@tap.stop="change(index, subIndex, subItem)" |
|||
> |
|||
<icon type="success_no_circle" v-if="item.index === subIndex" :color="getCkMarkColor" :size="checkMarkSize" class="tui-icon-success"></icon> |
|||
<image :src="subItem.src" v-if="subItem.src" class="tui-cell-img" :style="{ width: imgWidth, height: imgHeight, borderRadius: radius }"></image> |
|||
<view |
|||
class="tui-cell-title" |
|||
:class="{ 'tui-font-bold': item.index === subIndex && textBold, 'tui-flex-shrink': nowrap }" |
|||
:style="{ color: item.index === subIndex ? textActiveColor : textColor, fontSize: textSize + 'rpx' }" |
|||
> |
|||
{{ subItem.text }} |
|||
</view> |
|||
<view class="tui-cell-sub_title" :style="{ color: subTextColor, fontSize: subTextSize + 'rpx' }" v-if="subItem.subText">{{ subItem.subText }}</view> |
|||
</view> |
|||
</scroll-view> |
|||
</swiper-item> |
|||
</swiper> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
/** |
|||
* 如果下一级是请求返回,则为第一级数据,否则所有数据 |
|||
* 数据格式 |
|||
[{ |
|||
src: "", |
|||
text: "", |
|||
subText: "", |
|||
value: 0, |
|||
children:[{ |
|||
text: "", |
|||
subText: "", |
|||
value: 0, |
|||
children:[] |
|||
}] |
|||
}] |
|||
* */ |
|||
itemList: { |
|||
type: Array, |
|||
default: () => { |
|||
return []; |
|||
} |
|||
}, |
|||
/* |
|||
初始化默认选中数据 |
|||
[{ |
|||
text: "",//选中text |
|||
subText: '',//选中subText |
|||
value: '',//选中value |
|||
src: '', //选中src,没有则传空或不传 |
|||
index: 0, //选中数据在当前layer索引 |
|||
list: [{src: "", text: "", subText: "", value: 101}] //当前layer下所有数据集合 |
|||
}]; |
|||
|
|||
*/ |
|||
defaultItemList: { |
|||
type: Array, |
|||
default() { |
|||
return []; |
|||
} |
|||
}, |
|||
defaultKey: { |
|||
type: String, |
|||
default: 'text' |
|||
}, |
|||
//是否显示header底部细线 |
|||
headerLine: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
//header背景颜色 |
|||
headerBgColor: { |
|||
type: String, |
|||
default: '#FFFFFF' |
|||
}, |
|||
//顶部标签栏高度 |
|||
tabsHeight: { |
|||
type: String, |
|||
default: '88rpx' |
|||
}, |
|||
//默认显示文字 |
|||
text: { |
|||
type: String, |
|||
default: '请选择' |
|||
}, |
|||
//tabs 文字大小 |
|||
size: { |
|||
type: Number, |
|||
default: 28 |
|||
}, |
|||
//tabs 文字颜色 |
|||
color: { |
|||
type: String, |
|||
default: '#555' |
|||
}, |
|||
//选中颜色 |
|||
activeColor: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
//选中后文字加粗 |
|||
bold: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
//选中后是否显示底部线条 |
|||
showLine: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
//线条颜色 |
|||
lineColor: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
//icon 大小 |
|||
checkMarkSize: { |
|||
type: Number, |
|||
default: 15 |
|||
}, |
|||
//icon 颜色 |
|||
checkMarkColor: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
//item 图片宽度 |
|||
imgWidth: { |
|||
type: String, |
|||
default: '40rpx' |
|||
}, |
|||
//item 图片高度 |
|||
imgHeight: { |
|||
type: String, |
|||
default: '40rpx' |
|||
}, |
|||
//图片圆角 |
|||
radius: { |
|||
type: String, |
|||
default: '50%' |
|||
}, |
|||
//item text颜色 |
|||
textColor: { |
|||
type: String, |
|||
default: '#333' |
|||
}, |
|||
textActiveColor: { |
|||
type: String, |
|||
default: '#333' |
|||
}, |
|||
//选中后字体是否加粗 |
|||
textBold: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
//item text字体大小 |
|||
textSize: { |
|||
type: Number, |
|||
default: 28 |
|||
}, |
|||
//text 是否不换行 |
|||
nowrap: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
//item subText颜色 |
|||
subTextColor: { |
|||
type: String, |
|||
default: '#999' |
|||
}, |
|||
//item subText字体大小 |
|||
subTextSize: { |
|||
type: Number, |
|||
default: 24 |
|||
}, |
|||
// item padding |
|||
padding: { |
|||
type: String, |
|||
default: '20rpx 30rpx' |
|||
}, |
|||
//占位高度,第一条数据距离顶部距离 |
|||
firstItemTop: { |
|||
type: String, |
|||
default: '20rpx' |
|||
}, |
|||
//swiper 高度 |
|||
height: { |
|||
type: String, |
|||
default: '410px' |
|||
}, |
|||
//item swiper 内容部分背景颜色 |
|||
backgroundColor: { |
|||
type: String, |
|||
default: '#FFFFFF' |
|||
}, |
|||
//子集数据是否请求返回(默认false,一次性返回所有数据) |
|||
request: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
//子级数据(当有改变时,默认当前选中项新增子级数据,request=true时生效) |
|||
receiveData: { |
|||
type: Array, |
|||
default: () => { |
|||
return []; |
|||
} |
|||
}, |
|||
//改变值则重置数据 |
|||
reset: { |
|||
type: [Number, String], |
|||
default: 0 |
|||
} |
|||
}, |
|||
computed: { |
|||
getActiveColor() { |
|||
return this.activeColor || (uni && uni.$tui && uni.$tui.color.primary) || '#5677fc'; |
|||
}, |
|||
getLineColor() { |
|||
return this.lineColor || (uni && uni.$tui && uni.$tui.color.primary) || '#5677fc'; |
|||
}, |
|||
getCkMarkColor() { |
|||
return this.checkMarkColor || (uni && uni.$tui && uni.$tui.color.primary) || '#5677fc'; |
|||
} |
|||
}, |
|||
watch: { |
|||
itemList(val) { |
|||
this.initData(val, -1); |
|||
}, |
|||
receiveData(val) { |
|||
this.subLevelData(val, this.currentTab); |
|||
}, |
|||
reset() { |
|||
this.initData(this.itemList, -1); |
|||
}, |
|||
defaultItemList(val) { |
|||
this.setDefaultData(val); |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
currentTab: 0, //滚动的索引 |
|||
defTab: 0, |
|||
//tab栏scrollview滚动的位置 |
|||
scrollViewId: 'id__1', |
|||
selectedArr: [] //可以选择的数组 |
|||
}; |
|||
}, |
|||
|
|||
created() { |
|||
this.setDefaultData(this.defaultItemList); |
|||
}, |
|||
methods: { |
|||
clear: function () { |
|||
this.initData(this.itemList, -1); |
|||
}, |
|||
|
|||
/** |
|||
* 切换当前激活的标签页 |
|||
* @param {Object} e 事件对象,携带切换后的当前标签页信息 |
|||
* @returns 无返回值 |
|||
*/ |
|||
switchTab: function (e) { |
|||
// 更新当前激活的标签页 |
|||
this.currentTab = e.detail.current; |
|||
// 检查并处理可能的错误或状态变化 |
|||
this.checkCor(); |
|||
}, |
|||
/** |
|||
* 检查并更新当前选项卡的滚动视图ID。 |
|||
* 该函数首先根据当前选中的选项卡索引,更新一个指定对象的scrollViewId属性, |
|||
* 然后根据选项卡的索引调整全局的scrollViewId。 |
|||
* 此函数不接受参数,并且没有返回值。 |
|||
*/ |
|||
checkCor: function () { |
|||
// 获取当前选项卡对应的项,并设置其scrollViewId为一个固定的初始值 |
|||
let item = this.selectedArr[this.currentTab]; |
|||
item.scrollViewId = 'id__1'; |
|||
|
|||
// 使用$nextTick确保DOM更新后,设置一个延时操作来更新item的scrollViewId |
|||
this.$nextTick(() => { |
|||
setTimeout(() => { |
|||
// 根据item的index值计算新的scrollViewId,并更新item的scrollViewId |
|||
let val = item.index < 2 ? 0 : Number(item.index - 2); |
|||
item.scrollViewId = `id_${val}`; |
|||
}, 20); |
|||
}); |
|||
|
|||
// 根据当前Tab的索引,更新全局的scrollViewId |
|||
if (this.currentTab > 1) { |
|||
this.scrollViewId = `id_${this.currentTab - 1}`; |
|||
} else { |
|||
this.scrollViewId = `id_0`; |
|||
} |
|||
}, |
|||
/** |
|||
* 初始化数据函数 |
|||
* @param {Array} data 要初始化的数据数组 |
|||
* @param {Number} layer 数据所在的层级 |
|||
* @description 根据传入的数据和层级,对数据进行初始化处理。如果数据为空或不存在,则不执行任何操作。 |
|||
* 如果已有请求,则处理第一级数据;否则,根据选定的值或默认条件来处理数据。 |
|||
*/ |
|||
initData(data, layer) { |
|||
// 检查数据是否为空,若为空则不执行后续操作 |
|||
if (!data || data.length === 0) return; |
|||
if (this.request) { |
|||
// 当已有请求时,处理第一级数据 |
|||
this.subLevelData(data, layer); |
|||
} else { |
|||
let selectedValue = this.selectedValue || {}; |
|||
|
|||
// 检查是否有选定的类型,若有则设置默认数据 |
|||
if (selectedValue.type) { |
|||
this.setDefaultData(selectedValue); |
|||
} else { |
|||
// 无选定类型时,根据层级获取并处理数据列表 |
|||
this.subLevelData(this.getItemList(layer, -1), layer); |
|||
} |
|||
} |
|||
}, |
|||
/** |
|||
* 处理子级数据选择逻辑 |
|||
* @param {Array} data - 提供选择的数据数组 |
|||
* @param {number} layer - 当前选择的层级 |
|||
* 完成选择时,会通过$emit发送选择结果;重置数据时,更新selectedArr以备下次选择。 |
|||
*/ |
|||
subLevelData(data, layer) { |
|||
// 当数据为空或不存在时,处理完成选择或重置数据的逻辑 |
|||
if (!data || data.length === 0) { |
|||
if (layer == -1) return; |
|||
// 完成选择逻辑,根据当前层级更新selectedArr,并删除不需要的属性 |
|||
let arr = this.selectedArr; |
|||
if (layer < arr.length - 1) { |
|||
let newArr = arr.slice(0, layer + 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 { |
|||
// 重置数据逻辑,根据当前层级更新selectedArr,并设置默认选项 |
|||
let item = [ |
|||
{ |
|||
text: this.text, |
|||
subText: '', |
|||
value: '', |
|||
src: '', |
|||
index: -1, |
|||
scrollViewId: 'id__1', |
|||
list: data |
|||
} |
|||
]; |
|||
if (layer == -1) { |
|||
this.selectedArr = item; |
|||
} else { |
|||
let retainArr = this.selectedArr.slice(0, layer + 1) || []; |
|||
this.selectedArr = retainArr.concat(item); |
|||
} |
|||
// 更新当前选项卡与滚动视图ID,以适应界面显示 |
|||
let current = this.selectedArr.length - 1; |
|||
if (current >= this.currentTab) { |
|||
this.defTab = this.currentTab; |
|||
} |
|||
this.$nextTick(() => { |
|||
setTimeout(() => { |
|||
this.defTab = current; |
|||
this.currentTab = current; |
|||
// 更新滚动视图ID,用于定位当前选项卡 |
|||
this.scrollViewId = `id_${this.currentTab > 1 ? this.currentTab - 1 : 0}`; |
|||
}, 50); |
|||
}); |
|||
} |
|||
}, |
|||
/** |
|||
* 从数据中移除所有子项属性 |
|||
* @param {Array} data - 包含具有子项属性的对象的数组 |
|||
* @returns {Array} 返回一个移除了子项属性的新数组 |
|||
*/ |
|||
removeChildren(data) { |
|||
// 遍历数据数组,移除每个对象中的子项属性,并返回新数组 |
|||
let list = data.map((item) => { |
|||
delete item['children']; |
|||
return item; |
|||
}); |
|||
return list; |
|||
}, |
|||
/** |
|||
* 根据指定层号和索引获取项目列表。 |
|||
* @param {number} layer - 层号,用于指定要获取的项目列表所在的层级。 |
|||
* @param {number} index - 当前层的索引值,用于指定要获取的具体项目。 |
|||
* @param {Array} selectedArr - 已选择的项目数组,用于在多层选择时追踪已选择的项。 |
|||
* @returns {Array} 返回一个项目列表数组。 |
|||
*/ |
|||
getItemList(layer, index, selectedArr) { |
|||
let list = []; |
|||
let arr = JSON.parse(JSON.stringify(this.itemList)); // 创建itemList的深拷贝。 |
|||
selectedArr = selectedArr || this.selectedArr; // 如果未提供selectedArr,则使用默认的selectedArr。 |
|||
if (layer == -1) { |
|||
// 如果layer为-1,移除所有子项,返回最顶层的项目列表。 |
|||
list = this.removeChildren(arr); |
|||
} else { |
|||
// 根据提供的layer和index,获取对应层的项目列表。 |
|||
let value = selectedArr[0].index; |
|||
value = value === undefined || value == -1 ? index : value; |
|||
if (arr[value] && arr[value].children) { |
|||
list = arr[value].children; |
|||
} |
|||
// 如果layer大于0,则继续深入层级获取更具体的项目列表。 |
|||
if (layer > 0) { |
|||
for (let i = 1; i < layer + 1; i++) { |
|||
let val = layer === i ? index : selectedArr[i].index; |
|||
list = val === -1 ? [] : list[val].children || []; |
|||
if (list.length === 0) break; // 如果获取的列表为空,则终止循环。 |
|||
} |
|||
} |
|||
// 移除list中的所有子项,确保返回的列表不包含子级项目。 |
|||
list = this.removeChildren(list); |
|||
} |
|||
return list; |
|||
}, |
|||
/** |
|||
* 设置默认数据 |
|||
* @param val 可以是数组,用于设置默认选中的项目。如果为空或未定义,则不执行任何操作。 |
|||
*/ |
|||
setDefaultData(val) { |
|||
// 创建一个与传入值(如果存在)相同的数组,用于后续处理 |
|||
let defaultItemList = JSON.parse(JSON.stringify(val || [])); |
|||
|
|||
// 当默认项目列表不为空时 |
|||
if (defaultItemList.length > 0) { |
|||
// 检查默认列表的首元素是否为字符串或数字,并且没有发起请求 |
|||
if ((typeof defaultItemList[0] === 'string' || typeof defaultItemList[0] === 'number') && !this.request) { |
|||
// 初始化变量用于记录子项索引和已选择的数组 |
|||
let subi = -1; |
|||
let selectedArr = []; |
|||
// 遍历默认项目列表 |
|||
for (let j = 0, len = defaultItemList.length; j < len; j++) { |
|||
let item = defaultItemList[j]; |
|||
let list = []; |
|||
let obj = {}; |
|||
// 对于第一个元素,获取初始项目列表;对于其他元素,基于前一个元素的子项索引和已选择数组获取项目列表 |
|||
if (j === 0) { |
|||
list = this.getItemList(-1); |
|||
} else { |
|||
list = this.getItemList(j - 1, subi, selectedArr); |
|||
} |
|||
// 获取当前项目在列表中的默认索引 |
|||
subi = this.getDefaultIndex(list, item); |
|||
// 如果找到了当前项目的索引,则将其相关信息添加到已选择数组中 |
|||
if (subi !== -1) { |
|||
obj = list[subi]; |
|||
selectedArr.push({ |
|||
text: obj.text || this.text, |
|||
value: obj.value || '', |
|||
src: obj.src || '', |
|||
subText: obj.subText || '', |
|||
index: subi, |
|||
scrollViewId: `id_${subi}`, |
|||
list: list |
|||
}); |
|||
} |
|||
|
|||
// 如果找不到当前项目的索引,跳出循环 |
|||
if (subi === -1) break; |
|||
} |
|||
// 更新已选择数组和默认标签 |
|||
this.selectedArr = selectedArr; |
|||
this.defTab = this.currentTab; |
|||
// 使用$nextTick确保DOM更新后,设置当前标签并校正位置 |
|||
this.$nextTick(() => { |
|||
setTimeout(() => { |
|||
this.currentTab = selectedArr.length - 1; |
|||
this.defTab = this.currentTab; |
|||
this.checkCor(); |
|||
}, 20); |
|||
}); |
|||
} else { |
|||
// 如果默认列表的首元素不是字符串或数字,或已发起请求,则直接使用默认列表生成已选择数组 |
|||
defaultItemList.map((item) => { |
|||
item.scrollViewId = `id_${item.index}`; |
|||
}); |
|||
this.selectedArr = defaultItemList; |
|||
this.defTab = this.currentTab; |
|||
// 同样,在DOM更新后设置当前标签并校正位置 |
|||
this.$nextTick(() => { |
|||
setTimeout(() => { |
|||
this.currentTab = defaultItemList.length - 1; |
|||
this.defTab = this.currentTab; |
|||
this.checkCor(); |
|||
}, 20); |
|||
}); |
|||
} |
|||
} else { |
|||
// 如果默认项目列表为空,则使用初始化数据 |
|||
this.initData(this.itemList, -1); |
|||
} |
|||
}, |
|||
/** |
|||
* 点击标题切换当前选项卡 |
|||
* @param {Object} e 事件对象,包含了触发事件的元素信息 |
|||
* 无返回值 |
|||
*/ |
|||
swichNav: function (e) { |
|||
// 获取当前点击元素的数据当前索引 |
|||
let cur = e.currentTarget.dataset.current; |
|||
// 如果当前选项卡不是点击的选项卡 |
|||
if (this.currentTab != cur) { |
|||
// 先将当前选项卡保存为默认选项卡 |
|||
this.defTab = this.currentTab; |
|||
// 使用setTimeout延时20毫秒后,切换到点击的选项卡,并更新默认选项卡 |
|||
setTimeout(() => { |
|||
this.currentTab = cur; |
|||
this.defTab = this.currentTab; |
|||
}, 20); |
|||
} |
|||
}, |
|||
/** |
|||
* 处理选项更改事件。 |
|||
* @param {number} index 主选项索引。 |
|||
* @param {number} subIndex 子选项索引。 |
|||
* @param {Object} subItem 子选项对象,包含文本、值、子文本和图片源等属性。 |
|||
* 此函数更新当前选定项的索引和属性,并根据条件触发数据更新或事件emit。 |
|||
*/ |
|||
change(index, subIndex, subItem) { |
|||
let item = this.selectedArr[index]; // 获取当前选定的主选项对象 |
|||
|
|||
// 如果选定的子选项索引未改变,则不进行任何操作 |
|||
if (item.index == subIndex) return; |
|||
|
|||
// 更新选定项的索引和属性 |
|||
item.index = subIndex; |
|||
item.text = subItem.text; |
|||
item.value = subItem.value; |
|||
item.subText = subItem.subText || ''; // 如果存在子文本则更新,否则设为空字符串 |
|||
item.src = subItem.src || ''; // 如果存在图片源则更新,否则设为空字符串 |
|||
|
|||
// 发出选项更改事件,包含当前层索引、子选项索引和子选项详细信息 |
|||
this.$emit('change', { |
|||
layer: index, |
|||
subIndex: subIndex, //layer=> Array index |
|||
...subItem |
|||
}); |
|||
|
|||
// 如果未进行异步请求,则根据当前索引和子索引获取下级选项列表并更新 |
|||
if (!this.request) { |
|||
let data = this.getItemList(index, subIndex); |
|||
this.subLevelData(data, index); |
|||
} |
|||
}, |
|||
/** |
|||
* 获取给定数组中与指定值匹配的默认索引。 |
|||
* @param {Array} arr - 待搜索的数组。 |
|||
* @param {any} val - 要在数组中查找的值。 |
|||
* @returns {number} 如果找到匹配项,则返回匹配项的索引;如果没有找到或输入数组为空、undefined,或指定值未定义,则返回-1。 |
|||
*/ |
|||
getDefaultIndex(arr, val) { |
|||
// 当数组不存在、为空,或指定值未定义时,直接返回-1 |
|||
if (!arr || arr.length === 0 || val === undefined) return -1; |
|||
let index = -1; // 默认索引值初始化为-1 |
|||
let key = this.defaultKey || 'text'; // 使用defaultKey属性定义的键名,若不存在则默认使用'text' |
|||
// 遍历数组,寻找与指定值匹配的项 |
|||
for (let i = 0, len = arr.length; i < len; i++) { |
|||
if (arr[i][key] == val) { |
|||
index = i; // 找到匹配项,更新索引值 |
|||
break; // 找到一个匹配项后即停止遍历 |
|||
} |
|||
} |
|||
return index; // 返回最终的索引值 |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.tui-cascade-selection { |
|||
width: 100%; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.tui-selection-header { |
|||
width: 100%; |
|||
display: flex; |
|||
align-items: center; |
|||
position: relative; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.tui-bottom-line { |
|||
position: relative; |
|||
} |
|||
|
|||
.tui-bottom-line::after { |
|||
width: 100%; |
|||
content: ''; |
|||
position: absolute; |
|||
border-bottom: 1rpx solid #eaeef1; |
|||
-webkit-transform: scaleY(0.5) translateZ(0); |
|||
transform: scaleY(0.5) translateZ(0); |
|||
transform-origin: 0 100%; |
|||
bottom: 0; |
|||
right: 0; |
|||
left: 0; |
|||
} |
|||
|
|||
.tui-btm-none::after { |
|||
border-bottom: 0 !important; |
|||
} |
|||
|
|||
.tui-header-item { |
|||
max-width: 240rpx; |
|||
padding: 15rpx 30rpx; |
|||
box-sizing: border-box; |
|||
flex-shrink: 0; |
|||
overflow: hidden; |
|||
white-space: nowrap; |
|||
text-overflow: ellipsis; |
|||
position: relative; |
|||
} |
|||
|
|||
.tui-font-bold { |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.tui-active-line { |
|||
width: 60rpx; |
|||
height: 6rpx; |
|||
border-radius: 4rpx; |
|||
position: absolute; |
|||
bottom: 0; |
|||
right: 0; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
} |
|||
|
|||
.tui-selection-cell { |
|||
width: 100%; |
|||
box-sizing: border-box; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.tui-icon-success { |
|||
margin-right: 12rpx; |
|||
} |
|||
|
|||
.tui-cell-img { |
|||
margin-right: 12rpx; |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.tui-cell-title { |
|||
word-break: break-all; |
|||
} |
|||
|
|||
.tui-flex-shrink { |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.tui-font-bold { |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.tui-cell-sub_title { |
|||
margin-left: 20rpx; |
|||
word-break: break-all; |
|||
} |
|||
|
|||
.tui-first-item { |
|||
width: 100%; |
|||
} |
|||
</style> |
@ -0,0 +1,82 @@ |
|||
{ |
|||
"id": "jia-cascader", |
|||
"displayName": "级联数据选择 data-picker 自定义多级选择 多级联动选择、 ", |
|||
"version": "1.0.2", |
|||
"description": "弹窗联动选择器, 无限级联,单选,远程/ajax加载,子节点增量/异步渲染, ", |
|||
"keywords": [ |
|||
"仿uniui", |
|||
"data-picker", |
|||
"异步级联" |
|||
], |
|||
"repository": "", |
|||
"engines": { |
|||
}, |
|||
"dcloudext": { |
|||
"type": "component-vue", |
|||
"sale": { |
|||
"regular": { |
|||
"price": "0.00" |
|||
}, |
|||
"sourcecode": { |
|||
"price": "0.00" |
|||
} |
|||
}, |
|||
"contact": { |
|||
"qq": "" |
|||
}, |
|||
"declaration": { |
|||
"ads": "无", |
|||
"data": "暂无", |
|||
"permissions": "无" |
|||
}, |
|||
"npmurl": "" |
|||
}, |
|||
"uni_modules": { |
|||
"dependencies": [], |
|||
"encrypt": [], |
|||
"platforms": { |
|||
"cloud": { |
|||
"tcb": "y", |
|||
"aliyun": "y" |
|||
}, |
|||
"client": { |
|||
"Vue": { |
|||
"vue2": "u", |
|||
"vue3": "u" |
|||
}, |
|||
"App": { |
|||
"app-vue": "u", |
|||
"app-nvue": "u" |
|||
}, |
|||
"H5-mobile": { |
|||
"Safari": "y", |
|||
"Android Browser": "y", |
|||
"微信浏览器(Android)": "y", |
|||
"QQ浏览器(Android)": "y" |
|||
}, |
|||
"H5-pc": { |
|||
"Chrome": "y", |
|||
"IE": "u", |
|||
"Edge": "y", |
|||
"Firefox": "y", |
|||
"Safari": "y" |
|||
}, |
|||
"小程序": { |
|||
"微信": "y", |
|||
"阿里": "y", |
|||
"百度": "u", |
|||
"字节跳动": "y", |
|||
"QQ": "u", |
|||
"钉钉": "u", |
|||
"快手": "u", |
|||
"飞书": "u", |
|||
"京东": "u" |
|||
}, |
|||
"快应用": { |
|||
"华为": "u", |
|||
"联盟": "u" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,465 @@ |
|||
# jia-cascader (内部携带最新省市区编码 需要可自取) |
|||
# Props |
|||
|
|||
| 属性名 | 类型 | 说明 | 默认值 | |
|||
| ---------------- | --------------- | ------------------------------------------------------------ | ----------------- | |
|||
| readonly | Boolean | 只读 |false |
|||
| border | Boolean | 边框 | true |
|||
| clearIcon | Boolean | 清除按钮 | true |
|||
| placeholder | String | 默认提示 |请选择 |
|||
| popupTitle | String | 弹窗标题 |请选择 |
|||
| itemList | Array | 级联数据, 如果下一级是请求返回,则为第一级数据,否则为所有数据 | [ ] | |
|||
| defaultItemList | Array | 初始化默认选中数据,当一次性传入所有数据时,默认值可为字符串数组,如:['安徽省','阜阳市','颍上县'] | [ ] | |
|||
| defaultKey | V1.7.2+ String | 默认值字段key,可传值:text,value,仅当一次性传入所有数据时有效 | text | |
|||
| headerLine | Boolean | 是否显示header底部细线 | true | |
|||
| headerBgColor | String | header背景颜色 | #FFFFFF | |
|||
| tabsHeight | String | 顶部标签栏高度 | 88rpx | |
|||
| text | String | 默认显示文字 | 请选择 | |
|||
| size | Number | tabs 文字大小 | 28 | |
|||
| color | String | tabs 文字颜色 | #555 | |
|||
| activeColor | String | 选中颜色 | #5677fc | |
|||
| bold | Boolean | 选中后文字加粗 | true | |
|||
| showLine | Boolean | 选中后是否显示底部线条 | true | |
|||
| lineColor | String | 线条颜色 | #5677fc | |
|||
| checkMarkSize | Number | icon 大小 | 15 | |
|||
| checkMarkColor | String | icon 颜色 | #5677fc | |
|||
| imgWidth | String | item 图片宽度 | 40rpx | |
|||
| imgHeight | String | item 图片高度 | 40rpx | |
|||
| radius | String | 图片圆角 | 50% | |
|||
| textColor | String | item text颜色 | #333 | |
|||
| textActiveColor | String | item text选中后颜色 | #333 | |
|||
| textBold | Boolean | 选中后字体是否加粗 | true | |
|||
| textSize | Number | item text字体大小 | 28 | |
|||
| nowrap | Boolean | text 是否不换行 | false | |
|||
| subTextColor | String | item subText颜色 | #999 | |
|||
| subTextSize | Number | item subText字体大小 | 24 | |
|||
| padding | String | item padding | 20rpx 30rpx | |
|||
| firstItemTop | String | 占位高度,第一条数据距离顶部距离 | 20rpx | |
|||
| height | String | swiper 高度 | 300px | |
|||
| backgroundColor | String | item swiper 内容部分背景颜色 | #FFFFFF | |
|||
| request | Boolean | 子级数据是否请求返回(默认false,一次性返回所有数据) | false | |
|||
| receiveData | Array | 子级数据(当有改变时,默认为当前选中项新增子级数据,request为true时生效) | [ ] | |
|||
| reset | [Number, String]| 改变reset值则重置所有数据 |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
# 事件方法 |
|||
|
|||
| 属性 | 类型 | 说明 | 返回值 | |
|||
|----------|-----|------------------|----------------- |--------| |
|||
| popupopened | Events | 弹框打开时触发 | | |
|||
| popupclosed | Events | 弹框关闭时触发 | | |
|||
| completeChange | Events | 选择器中item项点击时触发| | |
|||
| inputChange | Events | 选择结果数据 | | |
|||
|
|||
|
|||
|
|||
# inputChange事件回调参数说明: |
|||
- layer 当前所属层级 |
|||
- subIndex 当前层级点击项索引值 |
|||
- subItem项 当前层级点击项所有数据,由父组件传入的数据 |
|||
|
|||
# completeChange事件回调参数说明: |
|||
- result 当前选择的结果 |
|||
- text 所有层级选择的text值拼接数据,如:安徽省合肥市庐阳区 |
|||
- value 最后一级点击项的value值 |
|||
- subText 最后一级点击项的text值 |
|||
- src 最后一级点击项的src值 |
|||
|
|||
# temList 属性Object参数说明 |
|||
属性 receiveData 数据格式与 itemList中子集数据一致,数据为约定格式,尽量保持一致。 |
|||
|
|||
``` js |
|||
[{ |
|||
src: "", //图标地址 |
|||
text: "",//主文本 |
|||
subText: "",//副文本 |
|||
value: 0, //value值 |
|||
children:[{ |
|||
text: "",//主文本 |
|||
subText: "",//副文本 |
|||
value: 0,//value值 |
|||
children:[] //子级数据 如果数据长度为0则表示没有下一级数据了 |
|||
}] //子级数据 |
|||
}] |
|||
``` |
|||
|
|||
# defaultItemList 属性Object参数说明 |
|||
数据为约定格式,尽量保持一致,当一次性传入所有数据时,默认值可为字符串数组。 |
|||
|
|||
``` js |
|||
[{ |
|||
text: "", //选中的text |
|||
subText: '', //选中的subText |
|||
value: '', //选中的value |
|||
src: '', //选中的src,没有则传空或不传 |
|||
index: 0, //选中数据在当前layer索引 |
|||
list: [{ |
|||
src: "",//图标地址 |
|||
text: "", //主文本 |
|||
subText: "",//副文本 |
|||
value: 101 //value值 |
|||
}] //当前layer下所有数据集合 |
|||
}] |
|||
|
|||
``` |
|||
|
|||
使用方法示例 |
|||
|
|||
在template中使用 |
|||
|
|||
``` vue |
|||
<template> |
|||
<template> |
|||
<view> |
|||
<jia-cascader request :itemList="itemList" :receiveData="receiveData" :defaultItemList="defaultItemList" @completeChange="complete" @inputChange="change"></jia-cascader> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
// data 数据 及 方法 |
|||
export default { |
|||
data() { |
|||
return { |
|||
itemList: [], |
|||
receiveData: [], |
|||
defaultItemList: [ |
|||
{ |
|||
src: '', |
|||
text: '高一(3)班', |
|||
subText: '30人', |
|||
value: 102, |
|||
index: 1, //选中数据在当前layer索引 |
|||
list: [ |
|||
{ |
|||
src: '', |
|||
text: '高一(1)班', |
|||
subText: '30人', |
|||
value: 101 |
|||
}, |
|||
{ |
|||
src: '', |
|||
text: '高一(2)班', |
|||
subText: '30人', |
|||
value: 102 |
|||
}, |
|||
{ |
|||
src: '', |
|||
text: '高一(3)班', |
|||
subText: '30人', |
|||
value: 103 |
|||
}, |
|||
{ |
|||
src: '', |
|||
text: '高一(1)班', |
|||
subText: '30人', |
|||
value: 101 |
|||
}, |
|||
{ |
|||
src: '', |
|||
text: '高一(2)班', |
|||
subText: '30人', |
|||
value: 102 |
|||
}, |
|||
{ |
|||
src: '', |
|||
text: '高一(1)班', |
|||
subText: '30人', |
|||
value: 101 |
|||
}, |
|||
{ |
|||
src: '', |
|||
text: '高一(2)班', |
|||
subText: '30人', |
|||
value: 102 |
|||
}, |
|||
{ |
|||
src: '', |
|||
text: '高一(1)班', |
|||
subText: '30人', |
|||
value: 101 |
|||
}, |
|||
{ |
|||
src: '', |
|||
text: '高一(2)班', |
|||
subText: '30人', |
|||
value: 102 |
|||
}, |
|||
{ |
|||
src: '', |
|||
text: '高一(1)班', |
|||
subText: '30人', |
|||
value: 101 |
|||
}, |
|||
{ |
|||
src: '', |
|||
text: '高一(2)班', |
|||
subText: '30人', |
|||
value: 102 |
|||
}, |
|||
{ |
|||
src: '', |
|||
text: '高一(1)班', |
|||
subText: '30人', |
|||
value: 101 |
|||
}, |
|||
{ |
|||
src: '', |
|||
text: '高一(2)班', |
|||
subText: '30人', |
|||
value: 102 |
|||
}, |
|||
{ |
|||
src: '', |
|||
text: '高一(1)班', |
|||
subText: '30人', |
|||
value: 101 |
|||
}, |
|||
{ |
|||
src: '', |
|||
text: '高一(2)班', |
|||
subText: '30人', |
|||
value: 102 |
|||
}, |
|||
{ |
|||
src: '', |
|||
text: '高一(1)班', |
|||
subText: '30人', |
|||
value: 101 |
|||
} |
|||
] //当前layer下所有数据集合 |
|||
}, |
|||
{ |
|||
text: '周小小', //选中的text |
|||
subText: '女', //选中的subText |
|||
value: 11103, //选中的value |
|||
src: '', //选中的src,没有则传空或不传 |
|||
index: 2, //选中数据在当前layer索引 |
|||
list: [ |
|||
{ |
|||
text: '张三', |
|||
subText: '男', |
|||
value: 11101 |
|||
}, |
|||
{ |
|||
text: '王五', |
|||
subText: '男', |
|||
value: 11102 |
|||
}, |
|||
{ |
|||
text: '周小小', |
|||
subText: '女', |
|||
value: 11103 |
|||
}, |
|||
{ |
|||
text: '周小小', |
|||
subText: '女', |
|||
value: 11103 |
|||
}, |
|||
{ |
|||
text: '周小小', |
|||
subText: '女', |
|||
value: 11103 |
|||
} |
|||
] //当前layer下所有数据集合 |
|||
} |
|||
] |
|||
}; |
|||
}, |
|||
onLoad() { |
|||
this.itemList = [ |
|||
{ |
|||
src: ' ', |
|||
text: '高一(1)班', |
|||
subText: '30人', |
|||
value: 101 |
|||
}, |
|||
{ |
|||
src: ' ', |
|||
text: '高一(2)班', |
|||
subText: '30人', |
|||
value: 102 |
|||
}, |
|||
{ |
|||
src: ' ', |
|||
text: '高一(3)班', |
|||
subText: '30人', |
|||
value: 103 |
|||
}, |
|||
{ |
|||
src: ' ', |
|||
text: '高一(4)班', |
|||
subText: '28人', |
|||
value: 104 |
|||
}, |
|||
{ |
|||
src: ' ', |
|||
text: '高一(5)班', |
|||
subText: '28人', |
|||
value: 105 |
|||
}, |
|||
{ |
|||
src: ' ', |
|||
text: '高一(6)班', |
|||
subText: '28人', |
|||
value: 106 |
|||
}, |
|||
{ |
|||
src: ' ', |
|||
text: '高一(7)班', |
|||
subText: '28人', |
|||
value: 107 |
|||
}, |
|||
{ |
|||
src: ' ', |
|||
text: '高一(8)班', |
|||
subText: '38人', |
|||
value: 108 |
|||
}, |
|||
{ |
|||
src: ' ', |
|||
text: '高一(9)班', |
|||
subText: '38人', |
|||
value: 109 |
|||
}, |
|||
{ |
|||
src: ' ', |
|||
text: '高一(10)班', |
|||
subText: '38人', |
|||
value: 110 |
|||
}, |
|||
{ |
|||
src: ' ', |
|||
text: '高一(11)班', |
|||
subText: '38人', |
|||
value: 111 |
|||
}, |
|||
{ |
|||
src: ' ', |
|||
text: '高一(12)班', |
|||
subText: '38人', |
|||
value: 112 |
|||
} |
|||
]; |
|||
}, |
|||
methods: { |
|||
change(e) { |
|||
console.log(e); |
|||
/** |
|||
* layer: 0 第几级 index |
|||
src: '/static/images/basic/color.png' |
|||
subIndex: 2 //当前层级下选中项index |
|||
subText: '30人' //选中项数据 |
|||
text: '高一(3)班' |
|||
value: 103 //选中项value数据 |
|||
* */ |
|||
|
|||
// 模拟请求 |
|||
let value = e.value; |
|||
let layer = e.layer; |
|||
if (layer === 7) { |
|||
//实际中以请求数据为准,无下级数据则传空数组 |
|||
this.receiveData = []; |
|||
} else { |
|||
uni.showLoading({ |
|||
title: '请稍候...' |
|||
}); |
|||
setTimeout(() => { |
|||
uni.hideLoading(); |
|||
//请求完成后将数据处理成以下格式,传入,最后一级没有则传空数组 |
|||
switch (layer) { |
|||
case 0: |
|||
this.receiveData = [ |
|||
{ |
|||
text: '张三', |
|||
subText: '男', |
|||
value: 11101 |
|||
}, |
|||
{ |
|||
text: '王五', |
|||
subText: '男', |
|||
value: 11102 |
|||
}, |
|||
{ |
|||
text: '周小小', |
|||
subText: '女', |
|||
value: 11103 |
|||
}, |
|||
{ |
|||
text: '周小小', |
|||
subText: '女', |
|||
value: 11103 |
|||
}, |
|||
{ |
|||
text: '周小小', |
|||
subText: '女', |
|||
value: 11103 |
|||
} |
|||
]; |
|||
break; |
|||
case 1: |
|||
this.receiveData = [ |
|||
{ |
|||
text: '他(她)说', |
|||
value: 11101 |
|||
} |
|||
]; |
|||
break; |
|||
case 2: |
|||
this.receiveData = [ |
|||
{ |
|||
text: '这是一个', |
|||
value: 11101 |
|||
} |
|||
]; |
|||
break; |
|||
case 3: |
|||
this.receiveData = [ |
|||
{ |
|||
text: '级联选择器', |
|||
value: 11101 |
|||
} |
|||
]; |
|||
break; |
|||
case 4: |
|||
this.receiveData = [ |
|||
{ |
|||
text: '测试例子', |
|||
value: 11101 |
|||
} |
|||
]; |
|||
break; |
|||
case 5: |
|||
this.receiveData = [ |
|||
{ |
|||
text: '总共', |
|||
value: 11101 |
|||
} |
|||
]; |
|||
break; |
|||
case 6: |
|||
this.receiveData = [ |
|||
{ |
|||
text: '8级数据', |
|||
value: 11101 |
|||
} |
|||
]; |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
}, 800); |
|||
} |
|||
}, |
|||
complete(e) { |
|||
console.log(e); |
|||
console.log('您选择的数据为:' + e.text); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
|
|||
``` |
@ -0,0 +1,4 @@ |
|||
## 1.0.1(2022-06-11) |
|||
修复苹果手机在微信中无法获取音频长度问题 |
|||
## 1.0.0(2022-06-10) |
|||
版本上线 |
@ -0,0 +1,113 @@ |
|||
<template> |
|||
<view class="recorder"> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
isUserMedia: false, |
|||
stream: null, |
|||
audio: null, |
|||
recorder: null, |
|||
chunks: [], |
|||
startTime: 0 |
|||
} |
|||
}, |
|||
mounted() { |
|||
/** |
|||
* error 事件的返回状态 |
|||
* 100: 请在HTTPS环境中使用 |
|||
* 101: 浏览器不支持 |
|||
* 201: 用户拒绝授权 |
|||
* 500: 未知错误 |
|||
* */ |
|||
if (origin.indexOf('https') === -1) { |
|||
this.$emit('error', '100') |
|||
throw '请在 https 环境中使用本插件。' |
|||
} |
|||
if (!navigator.mediaDevices || !window.MediaRecorder) { |
|||
this.$emit('error', '101') |
|||
throw '当前浏览器不支持' |
|||
} |
|||
|
|||
this.getRecorderManager() |
|||
}, |
|||
methods: { |
|||
getRecorderManager() { |
|||
this.audio = document.createElement('audio') |
|||
navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => { |
|||
this.isUserMedia = true |
|||
stream.getTracks().forEach((track) => { |
|||
track.stop() |
|||
}) |
|||
}).catch(err => { |
|||
this.onErrorHandler(err) |
|||
}) |
|||
}, |
|||
start() { |
|||
if (!this.isUserMedia) return console.log('设备不支持') |
|||
|
|||
navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => { |
|||
this.startTime = new Date().getTime() |
|||
this.stream = stream |
|||
this.recorder = new MediaRecorder(stream) |
|||
this.recorder.ondataavailable = this.getRecordingData |
|||
this.recorder.onstop = this.saveRecordingData |
|||
this.recorder.start() |
|||
}).catch(err => { |
|||
this.onErrorHandler(err) |
|||
}) |
|||
}, |
|||
stop() { |
|||
this.recorder.stop() |
|||
this.stream.getTracks().forEach((track) => { |
|||
track.stop() |
|||
}) |
|||
}, |
|||
getRecordingData(e) { |
|||
this.chunks.push(e.data) |
|||
}, |
|||
saveRecordingData() { |
|||
const blob = new Blob(this.chunks, { 'type': 'audio/mpeg' }), |
|||
localUrl = URL.createObjectURL(blob) |
|||
|
|||
const endTime = new Date().getTime() |
|||
|
|||
let duration = (endTime - this.startTime).toString().split('') |
|||
duration.splice(duration.length - 2) |
|||
duration.splice(duration.length - 1, 0, '.') |
|||
duration = parseFloat(duration.join('')) |
|||
|
|||
const recorder = { |
|||
data: blob, |
|||
duration: duration, |
|||
localUrl: localUrl |
|||
} |
|||
this.$emit('success', recorder) |
|||
}, |
|||
onErrorHandler(err) { |
|||
console.log(err) |
|||
if (err.name === 'NotAllowedError') { |
|||
this.$emit('error', '201') |
|||
throw '用户拒绝了当前的浏览器实例的访问请求' |
|||
} |
|||
|
|||
if (err.name === 'NotReadableError') { |
|||
this.$emit('error', '101') |
|||
throw '当前浏览器不支持' |
|||
} |
|||
|
|||
this.$emit('error', '500') |
|||
throw '调用失败,原因不详' |
|||
|
|||
} |
|||
}, |
|||
destroyed() { |
|||
this.stop() |
|||
} |
|||
} |
|||
</script> |
|||
<style> |
|||
</style> |
@ -0,0 +1,87 @@ |
|||
{ |
|||
"id": "mumu-recorder", |
|||
"displayName": "h5录音组件,调用H5原生功能使用麦克风进行录音", |
|||
"version": "1.0.1", |
|||
"description": "演示案例中模仿了微信的长按发送语音,与普通录音demo。", |
|||
"keywords": [ |
|||
"录音", |
|||
"麦克风", |
|||
"模仿微信" |
|||
], |
|||
"repository": "", |
|||
"engines": { |
|||
"HBuilderX": "^3.1.0" |
|||
}, |
|||
"dcloudext": { |
|||
"category": [ |
|||
"前端组件", |
|||
"通用组件" |
|||
], |
|||
"sale": { |
|||
"regular": { |
|||
"price": "0.00" |
|||
}, |
|||
"sourcecode": { |
|||
"price": "0.00" |
|||
} |
|||
}, |
|||
"contact": { |
|||
"qq": "" |
|||
}, |
|||
"declaration": { |
|||
"ads": "无", |
|||
"data": "无", |
|||
"permissions": "麦克风" |
|||
}, |
|||
"npmurl": "" |
|||
}, |
|||
"uni_modules": { |
|||
"dependencies": [], |
|||
"encrypt": [], |
|||
"platforms": { |
|||
"cloud": { |
|||
"tcb": "y", |
|||
"aliyun": "y" |
|||
}, |
|||
"client": { |
|||
"Vue": { |
|||
"vue2": "y", |
|||
"vue3": "y" |
|||
}, |
|||
"App": { |
|||
"app-vue": "n", |
|||
"app-nvue": "n" |
|||
}, |
|||
"H5-mobile": { |
|||
"Safari": "y", |
|||
"Android Browser": "y", |
|||
"微信浏览器(Android)": "y", |
|||
"QQ浏览器(Android)": "y" |
|||
}, |
|||
"H5-pc": { |
|||
"Chrome": "y", |
|||
"IE": "n", |
|||
"Edge": "y", |
|||
"Firefox": "y", |
|||
"Safari": "y" |
|||
}, |
|||
"小程序": { |
|||
"微信": "u", |
|||
"阿里": "u", |
|||
"百度": "u", |
|||
"字节跳动": "u", |
|||
"QQ": "u", |
|||
"钉钉": "u", |
|||
"快手": "u", |
|||
"飞书": "u", |
|||
"京东": "u", |
|||
"小红书": "u" |
|||
}, |
|||
"快应用": { |
|||
"华为": "u", |
|||
"联盟": "u" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,117 @@ |
|||
## 插件简绍 |
|||
|
|||
### 实现原理 |
|||
|
|||
> 通过 navigator.mediaDevices.getUserMedia(需要https环境) 这个api调用麦克风,获取到到音频流数据。 |
|||
> |
|||
> 通过 MediaRecorder 这个构造函数对音频流进行接收,完成录制后会返回一个存储`Blob`内容的录制数据。 |
|||
|
|||
|
|||
### 使用环境 |
|||
|
|||
需要https环境才能使用,本地测试可以在 manifest.json 中点击源码展示,找到h5 ,添加:"devServer" : { "https" : true} |
|||
|
|||
**请勿使用 UC浏览器 与 夸克等阿里旗下的浏览器,发现他们使用的内核都较低,无法正常获取音频流,并且都有对接音频流截取的插件,导致无法正常获取音频流的数据。在微信中可以正常使用,推荐在微信内打开演示案例 ** |
|||
|
|||
需要https环境才能使用!!! |
|||
|
|||
需要https环境才能使用!!! |
|||
|
|||
需要https环境才能使用!!! |
|||
|
|||
### 插件使用 |
|||
|
|||
**插件已支持 uni_modules 支持组件easycom,以下代码演示的是普通使用** |
|||
|
|||
``` html |
|||
<!-- HTML --> |
|||
<view> |
|||
<audio :src='recorder.localUrl' v-if='recorder' name='本地录音' controls="true"></audio> |
|||
<view @click='handlerOnCahnger'> |
|||
{{!status?'开始录音':'结束录音'}} |
|||
</view> |
|||
<mumu-recorder ref='recorder' @success='handlerSuccess' @error='handlerError'></mumu-recorder> |
|||
</view> |
|||
``` |
|||
|
|||
``` javascript |
|||
// js |
|||
import MumuRecorder from '@/uni_modules/mumu-recorder/components/mumu-recorder/mumu-recorder.vue' |
|||
export default { |
|||
components: { MumuRecorder }, |
|||
data() { |
|||
return { |
|||
status: false, |
|||
recorder: null |
|||
} |
|||
}, |
|||
onLoad() { |
|||
|
|||
}, |
|||
methods: { |
|||
handlerSave() { |
|||
let tag = document.createElement('a') |
|||
tag.href = this.recorder.localUrl |
|||
tag.download = '录音' |
|||
tag.click() |
|||
}, |
|||
handlerOnCahnger() { |
|||
if (this.status) { |
|||
this.$refs.recorder.stop() |
|||
} else { |
|||
this.$refs.recorder.start() |
|||
} |
|||
this.status = !this.status |
|||
}, |
|||
handlerSuccess(res) { |
|||
console.log(res) |
|||
this.recorder = res |
|||
}, |
|||
handlerError(code) { |
|||
switch (code) { |
|||
case '101': |
|||
uni.showModal({ |
|||
content: '当前浏览器版本较低,请更换浏览器使用,推荐在微信中打开。' |
|||
}) |
|||
break; |
|||
case '201': |
|||
uni.showModal({ |
|||
content: '麦克风权限被拒绝,请刷新页面后授权麦克风权限。' |
|||
}) |
|||
break |
|||
default: |
|||
uni.showModal({ |
|||
content: '未知错误,请刷新页面重试' |
|||
}) |
|||
break |
|||
} |
|||
} |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### 相关API |
|||
|
|||
##### 组件内部方法($refs 调用) |
|||
|
|||
| 方法名 | 说明 | 参数 | |
|||
| ------ | -------- | ---- | |
|||
| start | 开始录音 | 无 | |
|||
| stop | 结束录音 | 无 | |
|||
|
|||
|
|||
|
|||
##### 事件(Events) |
|||
|
|||
| 事件名 | 说明 | 回调参数 | |
|||
| ------- | -------------------- | ------------------------------------------------------------ | |
|||
| success | 停止录音后调用此事件 | 返回录音数据,是一个对象<br />{ data: 音频的 blob 数据,上传请使用这个 <br />duration: 当前音频长度<br/>localUrl: 当前音频的本地链接,可直接通过 audio 标签进行播放 } | |
|||
| error | 组件内部发生错误 | 错误码:<100 当前不是https环境> <101 浏览器不支持> <201 麦克风权限被拒绝> <500 未知错误> | |
|||
|
|||
### 案例演示 |
|||
|
|||
 |
|||
|
|||
## 支持作者 |
|||
|
|||
 |
@ -0,0 +1,264 @@ |
|||
<template> |
|||
<uni-shadow-root class="vant-cascader-index"><view v-if="showHeader" class="van-cascader__header"> |
|||
<slot name="title" v-if="useTitleSlot"></slot> |
|||
<text class="van-cascader__title" v-else>{{ title }}</text> |
|||
<van-icon v-if="closeable" :name="closeIcon" class="van-cascader__close-icon" @click.native="onClose"></van-icon> |
|||
</view> |
|||
|
|||
<van-tabs :active="activeTab" custom-class="van-cascader__tabs" wrap-class="van-cascader__tabs-wrap" tab-class="van-cascader__tab" :color="activeColor" :border="false" :swipeable="swipeable" :ellipsis="ellipsis" @click="onClickTab"> |
|||
<van-tab v-for="(tab,tabIndex) in (tabs)" :key="tab.tabIndex" :title="tab.selected ? tab.selected[textKey] : placeholder" style="width: 100%;" :title-style="(!tab.selected ? 'color: #969799;font-weight:normal;' : '')"> |
|||
|
|||
|
|||
<view class="van-cascader__options"> |
|||
<view v-for="(option,index) in (tab.options)" :key="option.index" :class="(option.className)+' '+(utils.optionClass(tab, valueKey, option))" :style="utils.optionStyle({ tab, valueKey, option, activeColor })" :data-option="option" :data-tab-index="tabIndex" @click="onSelect"> |
|||
<text>{{ option[textKey] }}</text> |
|||
<van-icon v-if="utils.isSelected(tab, valueKey, option)" name="success" size="18"></van-icon> |
|||
</view> |
|||
</view> |
|||
|
|||
|
|||
</van-tab> |
|||
</van-tabs></uni-shadow-root> |
|||
</template> |
|||
<wxs src="./index.wxs" module="utils"></wxs> |
|||
<script> |
|||
import VanIcon from '../icon/index.vue' |
|||
import VanTab from '../tab/index.vue' |
|||
import VanTabs from '../tabs/index.vue' |
|||
global['__wxVueOptions'] = {components:{'van-icon': VanIcon,'van-tab': VanTab,'van-tabs': VanTabs}} |
|||
|
|||
global['__wxRoute'] = 'vant/cascader/index' |
|||
"use strict"; |
|||
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { |
|||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { |
|||
if (ar || !(i in from)) { |
|||
if (!ar) ar = Array.prototype.slice.call(from, 0, i); |
|||
ar[i] = from[i]; |
|||
} |
|||
} |
|||
return to.concat(ar || Array.prototype.slice.call(from)); |
|||
}; |
|||
Object.defineProperty(exports, "__esModule", { value: true }); |
|||
var component_1 = require("../common/component"); |
|||
var FieldName; |
|||
(function (FieldName) { |
|||
FieldName["TEXT"] = "text"; |
|||
FieldName["VALUE"] = "value"; |
|||
FieldName["CHILDREN"] = "children"; |
|||
})(FieldName || (FieldName = {})); |
|||
var defaultFieldNames = { |
|||
text: FieldName.TEXT, |
|||
value: FieldName.VALUE, |
|||
children: FieldName.CHILDREN, |
|||
}; |
|||
(0, component_1.VantComponent)({ |
|||
props: { |
|||
title: String, |
|||
value: { |
|||
type: String, |
|||
}, |
|||
placeholder: { |
|||
type: String, |
|||
value: '请选择', |
|||
}, |
|||
activeColor: { |
|||
type: String, |
|||
value: '#1989fa', |
|||
}, |
|||
options: { |
|||
type: Array, |
|||
value: [], |
|||
}, |
|||
swipeable: { |
|||
type: Boolean, |
|||
value: false, |
|||
}, |
|||
closeable: { |
|||
type: Boolean, |
|||
value: true, |
|||
}, |
|||
ellipsis: { |
|||
type: Boolean, |
|||
value: true, |
|||
}, |
|||
showHeader: { |
|||
type: Boolean, |
|||
value: true, |
|||
}, |
|||
closeIcon: { |
|||
type: String, |
|||
value: 'cross', |
|||
}, |
|||
fieldNames: { |
|||
type: Object, |
|||
value: defaultFieldNames, |
|||
observer: 'updateFieldNames', |
|||
}, |
|||
useTitleSlot: Boolean, |
|||
}, |
|||
data: { |
|||
tabs: [], |
|||
activeTab: 0, |
|||
textKey: FieldName.TEXT, |
|||
valueKey: FieldName.VALUE, |
|||
childrenKey: FieldName.CHILDREN, |
|||
innerValue: '', |
|||
}, |
|||
watch: { |
|||
options: function (newVal,oldVal) { |
|||
this.updateTabs(); |
|||
}, |
|||
value: function (newVal) { |
|||
this.updateValue(newVal); |
|||
}, |
|||
}, |
|||
created: function () { |
|||
this.updateTabs(); |
|||
}, |
|||
methods: { |
|||
updateValue: function (val) { |
|||
var _this = this; |
|||
if (val !== undefined) { |
|||
var values = this.data.tabs.map(function (tab) { return tab.selected && tab.selected[_this.data.valueKey]; }); |
|||
if (values.indexOf(val) > -1) { |
|||
return; |
|||
} |
|||
} |
|||
this.innerValue = val; |
|||
this.updateTabs(); |
|||
}, |
|||
updateFieldNames: function () { |
|||
var _a = this.data.fieldNames || defaultFieldNames, _b = _a.text, text = _b === void 0 ? 'text' : _b, _c = _a.value, value = _c === void 0 ? 'value' : _c, _d = _a.children, children = _d === void 0 ? 'children' : _d; |
|||
this.setData({ |
|||
textKey: text, |
|||
valueKey: value, |
|||
childrenKey: children, |
|||
}); |
|||
}, |
|||
getSelectedOptionsByValue: function (options, value) { |
|||
for (var i = 0; i < options.length; i++) { |
|||
var option = options[i]; |
|||
if (option[this.data.valueKey] === value) { |
|||
return [option]; |
|||
} |
|||
if (option[this.data.childrenKey]) { |
|||
var selectedOptions = this.getSelectedOptionsByValue(option[this.data.childrenKey], value); |
|||
if (selectedOptions) { |
|||
return __spreadArray([option], selectedOptions, true); |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
updateTabs: function () { |
|||
var _this = this; |
|||
var options = this.data.options; |
|||
var innerValue = this.innerValue; |
|||
if (!options.length) { |
|||
return; |
|||
} |
|||
if (innerValue !== undefined) { |
|||
var selectedOptions = this.getSelectedOptionsByValue(options, innerValue); |
|||
if (selectedOptions) { |
|||
var optionsCursor_1 = options; |
|||
var tabs_1 = selectedOptions.map(function (option) { |
|||
var tab = { |
|||
options: optionsCursor_1, |
|||
selected: option, |
|||
}; |
|||
var next = optionsCursor_1.find(function (item) { return item[_this.data.valueKey] === option[_this.data.valueKey]; }); |
|||
if (next) { |
|||
optionsCursor_1 = next[_this.data.childrenKey]; |
|||
} |
|||
return tab; |
|||
}); |
|||
if (optionsCursor_1) { |
|||
tabs_1.push({ |
|||
options: optionsCursor_1, |
|||
selected: null, |
|||
}); |
|||
} |
|||
this.setData({ |
|||
tabs: tabs_1, |
|||
}); |
|||
wx.nextTick(function () { |
|||
_this.setData({ |
|||
activeTab: tabs_1.length - 1, |
|||
}); |
|||
}); |
|||
return; |
|||
} |
|||
} |
|||
this.setData({ |
|||
tabs: [ |
|||
{ |
|||
options: options, |
|||
selected: null, |
|||
}, |
|||
], |
|||
activeTab: 0, |
|||
}); |
|||
console.log(this.tabs,'see'); |
|||
}, |
|||
onClose: function () { |
|||
this.$emit('close'); |
|||
}, |
|||
onClickTab: function (e) { |
|||
var _a = e.detail, tabIndex = _a.index, title = _a.title; |
|||
this.$emit('click-tab', { title: title, tabIndex: tabIndex }); |
|||
this.setData({ |
|||
activeTab: tabIndex, |
|||
}); |
|||
}, |
|||
// 选中 |
|||
onSelect: function (e) { |
|||
var _this = this; |
|||
var _a = e.currentTarget.dataset, option = _a.option, tabIndex = _a.tabIndex; |
|||
if (option && option.disabled) { |
|||
return; |
|||
} |
|||
var _b = this.data, valueKey = _b.valueKey, childrenKey = _b.childrenKey; |
|||
var tabs = this.data.tabs; |
|||
tabs[tabIndex].selected = option; |
|||
if (tabs.length > tabIndex + 1) { |
|||
tabs = tabs.slice(0, tabIndex + 1); |
|||
} |
|||
if (option[childrenKey]) { |
|||
var nextTab = { |
|||
options: option[childrenKey], |
|||
selected: null, |
|||
}; |
|||
if (tabs[tabIndex + 1]) { |
|||
tabs[tabIndex + 1] = nextTab; |
|||
} |
|||
else { |
|||
tabs.push(nextTab); |
|||
} |
|||
wx.nextTick(function () { |
|||
_this.setData({ |
|||
activeTab: tabIndex + 1, |
|||
}); |
|||
}); |
|||
} |
|||
this.setData({ |
|||
tabs: tabs, |
|||
}); |
|||
var selectedOptions = tabs.map(function (tab) { return tab.selected; }).filter(Boolean); |
|||
var value = option[valueKey]; |
|||
var params = { |
|||
value: value, |
|||
tabIndex: tabIndex, |
|||
selectedOptions: selectedOptions, |
|||
}; |
|||
this.innerValue = value; |
|||
this.$emit('change', params); |
|||
if (!option[childrenKey]) { |
|||
this.$emit('finish', params); |
|||
} |
|||
}, |
|||
}, |
|||
}); |
|||
export default global['__wxComponents']['vant/cascader/index'] |
|||
</script> |
|||
<style platform="mp-weixin"> |
|||
@import '../common/index.css';.van-cascader__header{align-items:center;display:flex;height:48px;justify-content:space-between;padding:0 16px}.van-cascader__title{font-size:16px;font-weight:600;line-height:20px}.van-cascader__close-icon{color:#c8c9cc;font-size:22px;height:22px}.van-cascader__tabs-wrap{height:48px!important;padding:0 8px}.van-cascader__tab{color:#323233!important;flex:none!important;font-weight:600!important;padding:0 8px!important}.van-cascader__tab--unselected{color:#969799!important;font-weight:400!important}.van-cascader__option{align-items:center;cursor:pointer;display:flex;font-size:14px;justify-content:space-between;line-height:20px;padding:10px 16px}.van-cascader__option:active{background-color:#f2f3f5}.van-cascader__option--selected{color:#1989fa;font-weight:600}.van-cascader__option--disabled{color:#c8c9cc;cursor:not-allowed}.van-cascader__option--disabled:active{background-color:initial}.van-cascader__options{-webkit-overflow-scrolling:touch;box-sizing:border-box;height:384px;overflow-y:auto;padding-top:6px} |
|||
</style> |
@ -0,0 +1,42 @@ |
|||
/* eslint-disable */ |
|||
var object = require('./object.wxs'); |
|||
var array = require('./array.wxs'); |
|||
|
|||
function kebabCase(word) { |
|||
var newWord = word |
|||
.replace(getRegExp("[A-Z]", 'g'), function (i) { |
|||
return '-' + i; |
|||
}) |
|||
.toLowerCase() |
|||
|
|||
return newWord; |
|||
} |
|||
|
|||
function style(styles) { |
|||
if (array.isArray(styles)) { |
|||
return styles |
|||
.filter(function (item) { |
|||
return item != null && item !== ''; |
|||
}) |
|||
.map(function (item) { |
|||
return style(item); |
|||
}) |
|||
.join(';'); |
|||
} |
|||
|
|||
if ('Object' === styles.constructor) { |
|||
return object |
|||
.keys(styles) |
|||
.filter(function (key) { |
|||
return styles[key] != null && styles[key] !== ''; |
|||
}) |
|||
.map(function (key) { |
|||
return [kebabCase(key), [styles[key]]].join(':'); |
|||
}) |
|||
.join(';'); |
|||
} |
|||
|
|||
return styles; |
|||
} |
|||
|
|||
module.exports = style; |
@ -0,0 +1,12 @@ |
|||
/* eslint-disable */ |
|||
var REGEXP = getRegExp('^-?\d+(\.\d+)?$'); |
|||
|
|||
function addUnit(value) { |
|||
if (value == null) { |
|||
return undefined; |
|||
} |
|||
|
|||
return REGEXP.test('' + value) ? value + 'px' : value; |
|||
} |
|||
|
|||
module.exports = addUnit; |
@ -0,0 +1,5 @@ |
|||
function isArray(array) { |
|||
return array && (array.constructor === 'Array' || (typeof Array !== 'undefined' && Array.isArray(array))); |
|||
} |
|||
|
|||
module.exports.isArray = isArray; |
@ -0,0 +1,39 @@ |
|||
/* eslint-disable */ |
|||
var array = require('./array.wxs'); |
|||
var object = require('./object.wxs'); |
|||
var PREFIX = 'van-'; |
|||
|
|||
function join(name, mods) { |
|||
name = PREFIX + name; |
|||
mods = mods.map(function(mod) { |
|||
return name + '--' + mod; |
|||
}); |
|||
mods.unshift(name); |
|||
return mods.join(' '); |
|||
} |
|||
|
|||
function traversing(mods, conf) { |
|||
if (!conf) { |
|||
return; |
|||
} |
|||
|
|||
if (typeof conf === 'string' || typeof conf === 'number') { |
|||
mods.push(conf); |
|||
} else if (array.isArray(conf)) { |
|||
conf.forEach(function(item) { |
|||
traversing(mods, item); |
|||
}); |
|||
} else if (typeof conf === 'object') { |
|||
object.keys(conf).forEach(function(key) { |
|||
conf[key] && mods.push(key); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
function bem(name, conf) { |
|||
var mods = []; |
|||
traversing(mods, conf); |
|||
return join(name, mods); |
|||
} |
|||
|
|||
module.exports = bem; |
@ -0,0 +1,55 @@ |
|||
/** |
|||
* Simple memoize |
|||
* wxs doesn't support fn.apply, so this memoize only support up to 2 args |
|||
*/ |
|||
/* eslint-disable */ |
|||
|
|||
function isPrimitive(value) { |
|||
var type = typeof value; |
|||
return ( |
|||
type === 'boolean' || |
|||
type === 'number' || |
|||
type === 'string' || |
|||
type === 'undefined' || |
|||
value === null |
|||
); |
|||
} |
|||
|
|||
// mock simple fn.call in wxs |
|||
function call(fn, args) { |
|||
if (args.length === 2) { |
|||
return fn(args[0], args[1]); |
|||
} |
|||
|
|||
if (args.length === 1) { |
|||
return fn(args[0]); |
|||
} |
|||
|
|||
return fn(); |
|||
} |
|||
|
|||
function serializer(args) { |
|||
if (args.length === 1 && isPrimitive(args[0])) { |
|||
return args[0]; |
|||
} |
|||
var obj = {}; |
|||
for (var i = 0; i < args.length; i++) { |
|||
obj['key' + i] = args[i]; |
|||
} |
|||
return JSON.stringify(obj); |
|||
} |
|||
|
|||
function memoize(fn) { |
|||
var cache = {}; |
|||
|
|||
return function() { |
|||
var key = serializer(arguments); |
|||
if (cache[key] === undefined) { |
|||
cache[key] = call(fn, arguments); |
|||
} |
|||
|
|||
return cache[key]; |
|||
}; |
|||
} |
|||
|
|||
module.exports = memoize; |
@ -0,0 +1,13 @@ |
|||
/* eslint-disable */ |
|||
var REGEXP = getRegExp('{|}|"', 'g'); |
|||
|
|||
function keys(obj) { |
|||
return JSON.stringify(obj) |
|||
.replace(REGEXP, '') |
|||
.split(',') |
|||
.map(function(item) { |
|||
return item.split(':')[0]; |
|||
}); |
|||
} |
|||
|
|||
module.exports.keys = keys; |
@ -0,0 +1,10 @@ |
|||
/* eslint-disable */ |
|||
var bem = require('./bem.wxs'); |
|||
var memoize = require('./memoize.wxs'); |
|||
var addUnit = require('./add-unit.wxs'); |
|||
|
|||
module.exports = { |
|||
bem: memoize(bem), |
|||
memoize: memoize, |
|||
addUnit: addUnit |
|||
}; |
Loading…
Reference in new issue