├── _config.yml ├── src ├── index.ts ├── constants │ └── counter.ts ├── assets │ └── img │ │ ├── back.png │ │ ├── scan.png │ │ ├── search.png │ │ ├── more-icon.png │ │ ├── right-arrow.png │ │ ├── storage-add.png │ │ ├── storage-clear.png │ │ ├── storage-delete.png │ │ └── storage-modify.png ├── reducers │ ├── index.ts │ └── counter.ts ├── pages │ └── index │ │ ├── index.scss │ │ └── index.tsx ├── app.scss ├── actions │ └── counter.ts ├── components │ ├── debug │ │ ├── debug.scss │ │ └── Debug.tsx │ ├── appInformation │ │ ├── appInformation.scss │ │ └── AppInformation.tsx │ ├── changePin │ │ ├── changePin.scss │ │ └── changePin.tsx │ ├── positionSimulation │ │ ├── positionSimulation.scss │ │ └── PositionSimulation.tsx │ ├── h5door │ │ ├── h5door.scss │ │ └── H5door.tsx │ └── storage │ │ ├── storage.scss │ │ └── Storage.tsx ├── types │ └── DebugTypes.ts ├── store │ └── index.ts ├── index.html ├── app.tsx └── utils │ ├── consants.ts │ └── util.js ├── config ├── dev.js ├── prod.js └── index.js ├── .gitignore ├── .editorconfig ├── .prettierrc ├── global.d.ts ├── tsconfig.json ├── .eslintrc ├── project.config.json ├── package.json └── README.md /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Debug } from './components/debug/Debug' 2 | -------------------------------------------------------------------------------- /src/constants/counter.ts: -------------------------------------------------------------------------------- 1 | export const ADD = 'ADD' 2 | export const MINUS = 'MINUS' 3 | -------------------------------------------------------------------------------- /src/assets/img/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlfe/minidebug/HEAD/src/assets/img/back.png -------------------------------------------------------------------------------- /src/assets/img/scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlfe/minidebug/HEAD/src/assets/img/scan.png -------------------------------------------------------------------------------- /src/assets/img/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlfe/minidebug/HEAD/src/assets/img/search.png -------------------------------------------------------------------------------- /src/assets/img/more-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlfe/minidebug/HEAD/src/assets/img/more-icon.png -------------------------------------------------------------------------------- /src/assets/img/right-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlfe/minidebug/HEAD/src/assets/img/right-arrow.png -------------------------------------------------------------------------------- /src/assets/img/storage-add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlfe/minidebug/HEAD/src/assets/img/storage-add.png -------------------------------------------------------------------------------- /src/assets/img/storage-clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlfe/minidebug/HEAD/src/assets/img/storage-clear.png -------------------------------------------------------------------------------- /src/assets/img/storage-delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlfe/minidebug/HEAD/src/assets/img/storage-delete.png -------------------------------------------------------------------------------- /src/assets/img/storage-modify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdlfe/minidebug/HEAD/src/assets/img/storage-modify.png -------------------------------------------------------------------------------- /src/reducers/index.ts: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux' 2 | import counter from './counter' 3 | 4 | export default combineReducers({ 5 | counter 6 | }) 7 | -------------------------------------------------------------------------------- /config/dev.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | NODE_ENV: '"development"' 4 | }, 5 | defineConstants: { 6 | }, 7 | weapp: {}, 8 | h5: {} 9 | } 10 | -------------------------------------------------------------------------------- /src/pages/index/index.scss: -------------------------------------------------------------------------------- 1 | .debug-img { 2 | width: 120px; 3 | height: 120px; 4 | border: 0.5px solid #f1f1f1; 5 | margin-top: 400px; 6 | border-radius: 50%; 7 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | deploy_versions/ 3 | .temp/ 4 | .rn_temp/ 5 | node_modules/ 6 | .DS_Store 7 | build/ 8 | 9 | # temp file for git conflict merging 10 | *.log 11 | *.swo 12 | *.swp 13 | *.vi 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "singleQuote": true, 4 | "tabWidth": 2, 5 | "trailingComma": "es5", 6 | "semi": false, 7 | "bracketSpacing": true, 8 | "jsxBracketSameLine": false, 9 | "jsxSingleQuote": false, 10 | "arrowParens": "avoid" 11 | } 12 | -------------------------------------------------------------------------------- /src/app.scss: -------------------------------------------------------------------------------- 1 | @import "~taro-ui/dist/style/components/list.scss"; 2 | @import "~taro-ui/dist/style/components/icon.scss"; 3 | @import "~taro-ui/dist/style/components/action-sheet.scss"; 4 | @import "~taro-ui/dist/style/components/float-layout.scss"; 5 | /**app.wxss**/ 6 | .container { 7 | height: 100%; 8 | display: flex; 9 | box-sizing: border-box; 10 | } -------------------------------------------------------------------------------- /src/actions/counter.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ADD, 3 | MINUS 4 | } from '../constants/counter' 5 | 6 | export const add = () => { 7 | return { 8 | type: ADD 9 | } 10 | } 11 | export const minus = () => { 12 | return { 13 | type: MINUS 14 | } 15 | } 16 | 17 | // 异步的action 18 | export function asyncAdd () { 19 | return dispatch => { 20 | setTimeout(() => { 21 | dispatch(add()) 22 | }, 2000) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /config/prod.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | NODE_ENV: '"production"' 4 | }, 5 | defineConstants: { 6 | }, 7 | weapp: {}, 8 | h5: { 9 | /** 10 | * 如果h5端编译后体积过大,可以使用webpack-bundle-analyzer插件对打包体积进行分析。 11 | * 参考代码如下: 12 | * webpackChain (chain) { 13 | * chain.plugin('analyzer') 14 | * .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, []) 15 | * } 16 | */ 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /global.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.png"; 2 | declare module "*.gif"; 3 | declare module "*.jpg"; 4 | declare module "*.jpeg"; 5 | declare module "*.svg"; 6 | declare module "*.css"; 7 | declare module "*.less"; 8 | declare module "*.scss"; 9 | declare module "*.sass"; 10 | declare module "*.styl"; 11 | 12 | // @ts-ignore 13 | declare const process: { 14 | env: { 15 | TARO_ENV: 'weapp' | 'swan' | 'alipay' | 'h5' | 'rn' | 'tt' | 'quickapp' | 'qq'; 16 | [key: string]: any; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/reducers/counter.ts: -------------------------------------------------------------------------------- 1 | import { ADD, MINUS } from '../constants/counter' 2 | 3 | const INITIAL_STATE = { 4 | num: 0 5 | } 6 | 7 | export default function counter (state = INITIAL_STATE, action) { 8 | switch (action.type) { 9 | case ADD: 10 | return { 11 | ...state, 12 | num: state.num + 1 13 | } 14 | case MINUS: 15 | return { 16 | ...state, 17 | num: state.num - 1 18 | } 19 | default: 20 | return state 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/components/debug/debug.scss: -------------------------------------------------------------------------------- 1 | .debug-container { 2 | width: 750px; 3 | height: 100%; 4 | background: #ffffff; 5 | } 6 | .home-container { 7 | display: flex; 8 | align-items: center;; 9 | justify-content: center; 10 | width: 80px; 11 | height: 80px; 12 | border: 0.5px solid #d4d4d4; 13 | margin-top: 400px; 14 | border-radius: 50%; 15 | position: fixed; 16 | right: 20px; 17 | bottom: 200px; 18 | z-index: 1000; 19 | background-color: #FFFFFF; 20 | .home-img { 21 | width: 60px; 22 | height: 60px; 23 | } 24 | } -------------------------------------------------------------------------------- /src/types/DebugTypes.ts: -------------------------------------------------------------------------------- 1 | export type Menu = { 2 | title: string 3 | type?: number 4 | desc: string 5 | } 6 | export type ENV = { 7 | env: string 8 | name: string 9 | } 10 | export type SystemInfoItem = { 11 | name: string 12 | value: string | number 13 | type?: string 14 | } 15 | export type TransTypeItem = { 16 | type: number 17 | name: string 18 | } 19 | export type AddrInfo = { 20 | key: string, 21 | value: string, 22 | title: string, 23 | disabled: boolean 24 | } 25 | export type StorageModifyItem = { 26 | key: string 27 | value: string 28 | isModify: boolean 29 | ischecked: boolean 30 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "commonjs", 5 | "removeComments": false, 6 | "preserveConstEnums": true, 7 | "moduleResolution": "node", 8 | "experimentalDecorators": true, 9 | "noImplicitAny": false, 10 | "allowSyntheticDefaultImports": true, 11 | "outDir": "lib", 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "strictNullChecks": true, 15 | "sourceMap": true, 16 | "baseUrl": ".", 17 | "rootDir": ".", 18 | "jsx": "preserve", 19 | "jsxFactory": "Taro.createElement", 20 | "allowJs": true, 21 | "resolveJsonModule": true, 22 | "typeRoots": [ 23 | "node_modules/@types" 24 | ] 25 | }, 26 | "exclude": [ 27 | "node_modules", 28 | "dist" 29 | ], 30 | "compileOnSave": false 31 | } 32 | -------------------------------------------------------------------------------- /src/pages/index/index.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentClass } from 'react' 2 | import Taro, { Component, Config } from '@tarojs/taro' 3 | import { View } from '@tarojs/components' 4 | 5 | import './index.scss' 6 | import Debug from '../../components/debug/Debug' 7 | 8 | type PageStateProps = {} 9 | 10 | type PageDispatchProps = {} 11 | 12 | type PageOwnProps = {} 13 | 14 | type PageState = {} 15 | 16 | type IProps = PageStateProps & PageDispatchProps & PageOwnProps 17 | 18 | interface Index { 19 | props: IProps; 20 | } 21 | 22 | class Index extends Component { 23 | 24 | config: Config = { 25 | navigationBarTitleText: '首页' 26 | } 27 | render () { 28 | return ( 29 | 30 | 31 | 32 | ) 33 | } 34 | } 35 | 36 | export default Index as ComponentClass 37 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux' 2 | import thunkMiddleware from 'redux-thunk' 3 | import rootReducer from '../reducers' 4 | 5 | const composeEnhancers = 6 | typeof window === 'object' && 7 | window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? 8 | window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ 9 | // Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize... 10 | }) : compose 11 | 12 | const middlewares = [ 13 | thunkMiddleware 14 | ] 15 | 16 | if (process.env.NODE_ENV === 'development' && process.env.TARO_ENV !== 'quickapp') { 17 | middlewares.push(require('redux-logger').createLogger()) 18 | } 19 | 20 | const enhancer = composeEnhancers( 21 | applyMiddleware(...middlewares), 22 | // other store enhancers if any 23 | ) 24 | 25 | export default function configStore () { 26 | const store = createStore(rootReducer, enhancer) 27 | return store 28 | } 29 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["taro", "plugin:@typescript-eslint/recommended"], 3 | "parser": "@typescript-eslint/parser", 4 | "rules": { 5 | "no-unused-vars": ["error", { "varsIgnorePattern": "Taro" }], 6 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx", ".tsx"] }], 7 | "@typescript-eslint/no-unused-vars": ["error", { "varsIgnorePattern": "Taro" }], 8 | "@typescript-eslint/member-delimiter-style": { 9 | "multiline": { 10 | "delimiter": "none", 11 | "requireLast": false 12 | }, 13 | "singleline": { 14 | "delimiter": "none", 15 | "requireLast": false 16 | } 17 | }, 18 | "@typescript-eslint/explicit-function-return-type": 0, 19 | "@typescript-eslint/no-empty-function": ["warn"] 20 | }, 21 | "parserOptions": { 22 | "ecmaFeatures": { 23 | "jsx": true 24 | }, 25 | "useJSXTextNode": true, 26 | "project": "./tsconfig.json" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "miniprogramRoot": "dist/", 3 | "projectname": "MiniDebug", 4 | "description": "小程序MiniDebug工具", 5 | "appid": "wx444d544f65a4f311", 6 | "setting": { 7 | "urlCheck": true, 8 | "es6": false, 9 | "enhance": false, 10 | "postcss": false, 11 | "preloadBackgroundData": false, 12 | "minified": false, 13 | "newFeature": false, 14 | "coverView": true, 15 | "nodeModules": false, 16 | "autoAudits": false, 17 | "showShadowRootInWxmlPanel": true, 18 | "scopeDataCheck": false, 19 | "uglifyFileName": false, 20 | "checkInvalidKey": true, 21 | "checkSiteMap": true, 22 | "uploadWithSourceMap": true, 23 | "compileHotReLoad": false, 24 | "babelSetting": { 25 | "ignore": [], 26 | "disablePlugins": [], 27 | "outputPath": "" 28 | }, 29 | "useIsolateContext": true, 30 | "useCompilerModule": true, 31 | "userConfirmedUseCompilerModuleSwitch": false 32 | }, 33 | "compileType": "miniprogram", 34 | "simulatorType": "wechat", 35 | "simulatorPluginLibVersion": {}, 36 | "condition": {} 37 | } -------------------------------------------------------------------------------- /src/components/appInformation/appInformation.scss: -------------------------------------------------------------------------------- 1 | .info-container { 2 | background: #FFFFFF; 3 | border-top: 1px solid #f6f6f6; 4 | } 5 | .info-header { 6 | height: 80px; 7 | line-height: 80px; 8 | font-size: 28px; 9 | color:#6a6a77; 10 | padding-left: 50px; 11 | font-weight: bold; 12 | position: relative; 13 | &::before { 14 | content: ""; 15 | display: inline-block; 16 | position: absolute; 17 | left: 24px; 18 | top: 50%; 19 | margin-top: -20px; 20 | width: 2PX; 21 | height: 40px; 22 | background-color: #e1251b; 23 | box-shadow: 0 7px 12px 0 rgba(97, 144, 232, 0.2); 24 | border-radius: 1PX; 25 | } 26 | } 27 | .info-item { 28 | display:flex; 29 | align-items:center; 30 | font-size: 32px; 31 | color: #333; 32 | justify-content:space-between; 33 | padding:0 32px; 34 | height:90px; 35 | border-bottom:1px solid #efefef; 36 | } 37 | .img { 38 | width: 80px; 39 | height:80px; 40 | display:inline-block; 41 | overflow:hidden; 42 | border-radius:50%; 43 | margin-right: 20px; 44 | } 45 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /src/components/changePin/changePin.scss: -------------------------------------------------------------------------------- 1 | .pin-container { 2 | display: flex; 3 | flex-direction: column; 4 | border-top: 1px solid #f6f6f6; 5 | .appinfo-item { 6 | display:flex; 7 | align-items:center; 8 | font-size: 32px; 9 | color: #333; 10 | justify-content:space-between; 11 | padding:0 32px; 12 | height:104px; 13 | border-bottom:1px solid #efefef; 14 | background: #ffffff; 15 | .item-value { 16 | flex: 1; 17 | white-space: nowrap; 18 | text-overflow: ellipsis; 19 | overflow: hidden; 20 | text-align: right; 21 | } 22 | } 23 | .appinfo-input { 24 | font-size: 32px; 25 | color: #333; 26 | padding:0 32px; 27 | height:104px; 28 | border-bottom:1px solid #efefef; 29 | background: #ffffff; 30 | } 31 | .confirm-button{ 32 | position: absolute; 33 | bottom: 30px; 34 | left: 30px; 35 | width: 690px; 36 | height: 100px; 37 | background: #E1251B; 38 | border: 0; 39 | color:#ffffff; 40 | text-align: center; 41 | line-height: 100px; 42 | font-size: 32px; 43 | } 44 | } -------------------------------------------------------------------------------- /src/components/positionSimulation/positionSimulation.scss: -------------------------------------------------------------------------------- 1 | .position-tools{ 2 | background: #ffffff; 3 | border-top: 0.5px solid #d6e4ef; 4 | .tools-item{ 5 | height: 90px; 6 | line-height: 90px; 7 | color: #333; 8 | font-size: 30px; 9 | padding-left: 24px; 10 | position: relative; 11 | text-align: left; 12 | background-color:#fff; 13 | &::after { 14 | content: ' '; 15 | position: absolute; 16 | box-sizing: border-box; 17 | top: auto; 18 | left: 24px; 19 | right: 0; 20 | bottom: 0; 21 | border-bottom: 1PX solid #d6e4ef; 22 | transform: scaleY(0.5); 23 | transform-origin: center; 24 | } 25 | .tools-img{ 26 | height: 34px; 27 | width: 20px; 28 | position: absolute; 29 | right: 24px; 30 | top: 50%; 31 | transform: translateY(-50%); 32 | } 33 | .item-title{ 34 | background: #fff; 35 | color: #333; 36 | font-size: 32px; 37 | text-align: left; 38 | padding: 0; 39 | height: 90px; 40 | line-height: 90px; 41 | &:after{ 42 | border:0 43 | } 44 | } 45 | } 46 | } 47 | .trans-item { 48 | height: 100px; 49 | text-align: center; 50 | line-height: 100px; 51 | border: 0.5px solid #F5F6F7; 52 | } -------------------------------------------------------------------------------- /src/app.tsx: -------------------------------------------------------------------------------- 1 | import '@tarojs/async-await' 2 | import Taro, { Component, Config } from '@tarojs/taro' 3 | import { Provider } from '@tarojs/redux' 4 | 5 | import Index from './pages/index/index' 6 | 7 | import configStore from './store' 8 | 9 | import './app.scss' 10 | 11 | // 如果需要在 h5 环境中开启 React Devtools 12 | // 取消以下注释: 13 | // if (process.env.NODE_ENV !== 'production' && process.env.TARO_ENV === 'h5') { 14 | // require('nerv-devtools') 15 | // } 16 | 17 | const store = configStore() 18 | 19 | class App extends Component { 20 | /** 21 | * 指定config的类型声明为: Taro.Config 22 | * 23 | * 由于 typescript 对于 object 类型推导只能推出 Key 的基本类型 24 | * 对于像 navigationBarTextStyle: 'black' 这样的推导出的类型是 string 25 | * 提示和声明 navigationBarTextStyle: 'black' | 'white' 类型冲突, 需要显示声明类型 26 | */ 27 | config: Config = { 28 | pages: [ 29 | 'pages/index/index', 30 | ], 31 | window: { 32 | backgroundTextStyle: 'light', 33 | navigationBarBackgroundColor: '#fff', 34 | navigationBarTitleText: 'WeChat', 35 | navigationBarTextStyle: 'black', 36 | }, 37 | permission: { 38 | 'scope.userLocation': { 39 | desc: '您的位置信息将用于小程序定位', 40 | }, 41 | }, 42 | } 43 | 44 | globalData: object = {} 45 | 46 | // componentDidMount() {} 47 | 48 | // componentDidShow() {} 49 | 50 | // componentDidHide() {} 51 | 52 | // componentDidCatchError() {} 53 | 54 | // 在 App 类中的 render() 函数没有实际作用 55 | // 请勿修改此函数 56 | render() { 57 | return ( 58 | 59 | 60 | 61 | ) 62 | } 63 | } 64 | 65 | Taro.render(, document.getElementById('app')) 66 | -------------------------------------------------------------------------------- /src/components/changePin/changePin.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentClass } from 'react' 2 | import Taro, { Component } from '@tarojs/taro' 3 | import { View, Text, Input, Button, } from '@tarojs/components' 4 | 5 | import './ChangePin.scss' 6 | import { relaunch } from '../../utils/util' 7 | 8 | const app = Taro.getApp() 9 | 10 | type PageStateProps = { 11 | } 12 | 13 | type PageDispatchProps = { 14 | } 15 | 16 | type PageOwnProps = {} 17 | 18 | type PageState = { 19 | userPin: string 20 | inputPin: string 21 | } 22 | 23 | type IProps = PageStateProps & PageDispatchProps & PageOwnProps 24 | 25 | interface ChangePin { 26 | props: IProps; 27 | } 28 | 29 | class ChangePin extends Component { 30 | state = { 31 | userPin: app.globalData.userPin, 32 | inputPin: '' 33 | } 34 | 35 | handleInput = (e) => { 36 | this.setState({ 37 | inputPin: e.detail.value 38 | }) 39 | } 40 | 41 | handleConfirm = () => { 42 | app.globalData.userPin = this.state.inputPin 43 | relaunch({ content: '修改成功,应用即将重启', }) 44 | } 45 | 46 | render () { 47 | const { userPin, inputPin, } = this.state 48 | return ( 49 | 50 | 51 | 当前用户pin: 52 | {userPin} 53 | 54 | 55 | 56 | 57 | ) 58 | } 59 | } 60 | 61 | export default ChangePin as ComponentClass 62 | -------------------------------------------------------------------------------- /src/utils/consants.ts: -------------------------------------------------------------------------------- 1 | import { Menu, ENV, TransTypeItem } from "../types/DebugTypes" 2 | 3 | export const FEATURE: any = { 4 | DEFAULT: -1, 5 | CHANGE_ENV: 1, 6 | CHANGE_PIN: 2, 7 | GET_APP_INFO: 3, 8 | MOCK_POSITION: 4, 9 | MANAGE_STORAGE: 5, 10 | SCAN: 6, 11 | JUMP_H5: 7, 12 | UPDATE: 8, 13 | } 14 | export const HOME_OPERATION_LIST: Array = [ 15 | FEATURE.DEFAULT, 16 | FEATURE.CHANGE_ENV, 17 | FEATURE.SCAN, 18 | FEATURE.UPDATE 19 | ] 20 | export const HOME_MENU: Array = [ 21 | { 22 | title: '环境切换', 23 | type: FEATURE.CHANGE_ENV, 24 | desc: '测试、预发、正式环境切换' 25 | }, 26 | { 27 | title: '身份Mock', 28 | type: FEATURE.CHANGE_PIN, 29 | desc: '动态修改pin,只支持测试环境', 30 | }, 31 | { 32 | title: '应用信息获取', 33 | type: FEATURE.GET_APP_INFO, 34 | desc: '点击查看设备信息', 35 | }, 36 | { 37 | title: '位置模拟', 38 | type: FEATURE.MOCK_POSITION, 39 | desc: '模拟位置数据', 40 | }, 41 | { 42 | title: '缓存管理', 43 | type: FEATURE.MANAGE_STORAGE, 44 | desc: '缓存数据新增、删除、修改', 45 | }, 46 | { 47 | title: '扫一扫', 48 | type: FEATURE.SCAN, 49 | desc: '可用于扫描微信小程序码或二维码', 50 | }, 51 | { 52 | title: 'H5跳转', 53 | type: FEATURE.JUMP_H5, 54 | desc: '跳转指定H5链接' 55 | }, 56 | { 57 | title: '更新版本', 58 | type: FEATURE.UPDATE, 59 | desc: '更新应用版本', 60 | }, 61 | ] 62 | export const ENV_LIST: Array = [ 63 | { 64 | env: 'development', 65 | name: '测试', 66 | }, 67 | { 68 | env: 'prepare', 69 | name: '预发', 70 | }, 71 | { 72 | env: 'production', 73 | name: '正式', 74 | }, 75 | ] 76 | export const CONVERT_LIST: Array = [ 77 | { 78 | type: 0, 79 | name: 'wgs84转gcj02' 80 | }, 81 | { 82 | type: 1, 83 | name: 'gcj02转wgs84' 84 | } 85 | ] 86 | -------------------------------------------------------------------------------- /src/components/h5door/h5door.scss: -------------------------------------------------------------------------------- 1 | $storage-color: #E1251B; 2 | $input-height: 380px; 3 | .container { 4 | .url-area{ 5 | height: $input-height; 6 | width: 100%; 7 | position: absolute; 8 | left: 0; 9 | top: 0; 10 | z-index: 1; 11 | } 12 | .input-box{ 13 | width: 100%; 14 | border: 2px solid #efefef; 15 | height: $input-height; 16 | position: relative; 17 | } 18 | .scan{ 19 | position: absolute; 20 | right: 32px; 21 | bottom: 32px; 22 | height: 56px; 23 | width: 56px; 24 | z-index: 99; 25 | } 26 | .scan image{ 27 | height: 56px; 28 | width: 56px; 29 | } 30 | .history-list{ 31 | padding: 0 20px; 32 | } 33 | .history-content{ 34 | max-height: 600px; 35 | overflow: auto; 36 | } 37 | .history-item { 38 | height: 90px; 39 | line-height: 90px; 40 | padding-left: 57px; 41 | position: relative; 42 | font-size: 24px; 43 | color: #333333; 44 | overflow: hidden; 45 | text-overflow: ellipsis; 46 | white-space: nowrap; 47 | border-bottom: 2px solid #efefef; 48 | } 49 | .clear { 50 | width: 100%; 51 | text-align: center; 52 | font-size: 24px; 53 | margin-top: 40px; 54 | height: 32px; 55 | line-height: 32px; 56 | color: #999; 57 | } 58 | .search { 59 | height: 40px; 60 | width: 40px; 61 | position: absolute; 62 | left: 0; 63 | bottom: 23px; 64 | } 65 | .jump-btn { 66 | position: absolute; 67 | bottom: 30px; 68 | left: 30px; 69 | width: 690px; 70 | height: 100px; 71 | background: $storage-color; 72 | border: 0; 73 | color:#ffffff; 74 | line-height: 100px; 75 | font-size: 32px; 76 | text-align: center; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | projectName: 'MiniDebug', 3 | date: '2020-3-16', 4 | designWidth: 750, 5 | deviceRatio: { 6 | '640': 2.34 / 2, 7 | '750': 1, 8 | '828': 1.81 / 2 9 | }, 10 | sourceRoot: 'src', 11 | outputRoot: 'dist', 12 | plugins: { 13 | babel: { 14 | sourceMap: true, 15 | presets: [ 16 | ['env', { 17 | modules: false 18 | }] 19 | ], 20 | plugins: [ 21 | 'transform-decorators-legacy', 22 | 'transform-class-properties', 23 | 'transform-object-rest-spread' 24 | ] 25 | } 26 | }, 27 | defineConstants: { 28 | }, 29 | weapp: { 30 | module: { 31 | postcss: { 32 | autoprefixer: { 33 | enable: true, 34 | config: { 35 | browsers: [ 36 | 'last 3 versions', 37 | 'Android >= 4.1', 38 | 'ios >= 8' 39 | ] 40 | } 41 | }, 42 | pxtransform: { 43 | enable: true, 44 | config: { 45 | 46 | } 47 | }, 48 | url: { 49 | enable: true, 50 | config: { 51 | limit: 10240 // 设定转换尺寸上限 52 | } 53 | }, 54 | cssModules: { 55 | enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true 56 | config: { 57 | namingPattern: 'module', // 转换模式,取值为 global/module 58 | generateScopedName: '[name]__[local]___[hash:base64:5]' 59 | } 60 | } 61 | } 62 | } 63 | }, 64 | h5: { 65 | publicPath: '/', 66 | staticDirectory: 'static', 67 | module: { 68 | postcss: { 69 | autoprefixer: { 70 | enable: true, 71 | config: { 72 | browsers: [ 73 | 'last 3 versions', 74 | 'Android >= 4.1', 75 | 'ios >= 8' 76 | ] 77 | } 78 | }, 79 | cssModules: { 80 | enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true 81 | config: { 82 | namingPattern: 'module', // 转换模式,取值为 global/module 83 | generateScopedName: '[name]__[local]___[hash:base64:5]' 84 | } 85 | } 86 | } 87 | } 88 | } 89 | } 90 | 91 | module.exports = function (merge) { 92 | if (process.env.NODE_ENV === 'development') { 93 | return merge({}, config, require('./dev')) 94 | } 95 | return merge({}, config, require('./prod')) 96 | } 97 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jdlfe/minidebug", 3 | "version": "1.0.1", 4 | "private": false, 5 | "description": "小程序MiniDebug工具", 6 | "main": "src/index.ts", 7 | "templateInfo": { 8 | "name": "redux", 9 | "typescript": true, 10 | "css": "sass" 11 | }, 12 | "keywords": [ 13 | "taro", 14 | "taro-ui", 15 | "mini", 16 | "minidebug", 17 | "debug" 18 | ], 19 | "scripts": { 20 | "build:weapp": "taro build --type weapp", 21 | "build:swan": "taro build --type swan", 22 | "build:alipay": "taro build --type alipay", 23 | "build:tt": "taro build --type tt", 24 | "build:h5": "taro build --type h5", 25 | "build:rn": "taro build --type rn", 26 | "build:qq": "taro build --type qq", 27 | "build:quickapp": "taro build --type quickapp", 28 | "dev:weapp": "npm run build:weapp -- --watch", 29 | "dev:swan": "npm run build:swan -- --watch", 30 | "dev:alipay": "npm run build:alipay -- --watch", 31 | "dev:tt": "npm run build:tt -- --watch", 32 | "dev:h5": "npm run build:h5 -- --watch", 33 | "dev:rn": "npm run build:rn -- --watch", 34 | "dev:qq": "npm run build:qq -- --watch", 35 | "dev:quickapp": "npm run build:quickapp -- --watch" 36 | }, 37 | "author": "", 38 | "license": "MIT", 39 | "dependencies": { 40 | "redux": "^4.0.0", 41 | "redux-logger": "^3.0.6", 42 | "redux-thunk": "^2.3.0", 43 | "taro-ui": "^2.3.4" 44 | }, 45 | "devDependencies": { 46 | "@tarojs/async-await": "1.3.39", 47 | "@tarojs/cli": "1.3.39", 48 | "@tarojs/components": "1.3.39", 49 | "@tarojs/components-qa": "1.3.39", 50 | "@tarojs/redux": "1.3.39", 51 | "@tarojs/redux-h5": "1.3.39", 52 | "@tarojs/router": "1.3.39", 53 | "@tarojs/taro": "1.3.39", 54 | "@tarojs/taro-alipay": "1.3.39", 55 | "@tarojs/taro-h5": "1.3.39", 56 | "@tarojs/taro-qq": "1.3.39", 57 | "@tarojs/taro-quickapp": "1.3.39", 58 | "@tarojs/taro-rn": "1.3.39", 59 | "@tarojs/taro-swan": "1.3.39", 60 | "@tarojs/taro-tt": "1.3.39", 61 | "@tarojs/taro-weapp": "1.3.39", 62 | "nerv-devtools": "^1.5.5", 63 | "nervjs": "^1.5.5", 64 | "@tarojs/plugin-babel": "1.3.39", 65 | "@tarojs/plugin-csso": "1.3.39", 66 | "@tarojs/plugin-sass": "1.3.39", 67 | "@tarojs/plugin-uglifyjs": "1.3.39", 68 | "@tarojs/webpack-runner": "1.3.39", 69 | "@types/react": "^16.4.8", 70 | "@types/webpack-env": "^1.13.6", 71 | "@typescript-eslint/eslint-plugin": "^2.13.0", 72 | "@typescript-eslint/parser": "^2.13.0", 73 | "babel-eslint": "^8.2.3", 74 | "babel-plugin-transform-class-properties": "^6.24.1", 75 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 76 | "babel-plugin-transform-jsx-stylesheet": "^0.6.5", 77 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 78 | "babel-preset-env": "^1.6.1", 79 | "eslint": "^5.16.0", 80 | "eslint-config-taro": "1.3.39", 81 | "eslint-plugin-import": "^2.12.0", 82 | "eslint-plugin-react": "^7.8.2", 83 | "eslint-plugin-react-hooks": "^1.6.1", 84 | "eslint-plugin-taro": "1.3.39", 85 | "stylelint": "9.3.0", 86 | "stylelint-config-taro-rn": "1.3.39", 87 | "stylelint-taro-rn": "1.3.39", 88 | "typescript": "^3.0.1" 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/components/h5door/H5door.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentClass } from 'react' 2 | import Taro, { Component, } from '@tarojs/taro' 3 | import { 4 | View, 5 | Textarea, 6 | Image, 7 | Button, 8 | WebView 9 | } from '@tarojs/components' 10 | 11 | import './H5door.scss' 12 | 13 | type PageStateProps = { 14 | } 15 | 16 | type PageDispatchProps = { 17 | } 18 | 19 | type PageOwnProps = {} 20 | 21 | type PageState = { 22 | jumpUrl: string 23 | urlList: Array 24 | showWebview: boolean 25 | } 26 | 27 | type IProps = PageStateProps & PageDispatchProps & PageOwnProps 28 | 29 | interface H5door { 30 | props: IProps; 31 | } 32 | 33 | class H5door extends Component { 34 | state = { 35 | jumpUrl: '', 36 | urlList: [], 37 | showWebview: false, 38 | } 39 | componentDidMount() { 40 | this.getUrlList() 41 | } 42 | getUrlList = () => { 43 | let urlArr = [] 44 | let storageUrl = Taro.getStorageSync('debug-url') 45 | if (storageUrl) { 46 | urlArr = urlArr.concat(storageUrl.split(',')) 47 | } 48 | this.setState({ 49 | urlList: urlArr 50 | }) 51 | } 52 | setJumpUrl = (e) => { 53 | this.setState({ 54 | jumpUrl: e.target.dataset.url 55 | }) 56 | } 57 | scanCode = () => { 58 | Taro.scanCode({ 59 | success: res => { 60 | this.setState({ 61 | jumpUrl: res.result, 62 | }, () => { 63 | this.jump() 64 | }) 65 | } 66 | }) 67 | } 68 | onUrlInputChange = (event) => { 69 | this.setState({ 70 | jumpUrl: event.detail.value 71 | }) 72 | } 73 | clearHistory = () => { 74 | Taro.clearStorageSync() 75 | this.getUrlList() 76 | } 77 | storageUrl = () => { 78 | const { jumpUrl, urlList, } = this.state 79 | if (urlList.indexOf(jumpUrl) === -1) { 80 | const newHistoryList = [...urlList, jumpUrl] 81 | this.setState({ 82 | urlList: newHistoryList, 83 | }) 84 | Taro.setStorage({ 85 | key: 'debug-url', 86 | data: newHistoryList.join(',') 87 | }) 88 | } 89 | } 90 | jump = () => { 91 | if (!this.state.jumpUrl) { 92 | Taro.showToast({ title: '请输入跳转链接' }) 93 | return 94 | } 95 | this.storageUrl() 96 | this.setState({ showWebview: true }) 97 | } 98 | 99 | render() { 100 | const { jumpUrl, urlList, showWebview } = this.state 101 | return ( 102 | 103 | 104 | 111 | 112 | 115 | 116 | 117 | {urlList.length > 0 && ( 118 | 119 | 120 | {urlList.map((item) => { 121 | return ( 122 | 128 | 132 | {item} 133 | 134 | ) 135 | })} 136 | 137 | 138 | 清空搜索历史 139 | 140 | 141 | )} 142 | 148 | {showWebview && } 149 | 150 | ) 151 | } 152 | } 153 | 154 | export default H5door as ComponentClass -------------------------------------------------------------------------------- /src/components/appInformation/AppInformation.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentClass } from 'react' 2 | import Taro, { Component, } from '@tarojs/taro' 3 | import { View, Text, Image } from '@tarojs/components' 4 | import { AtList, AtListItem, } from 'taro-ui' 5 | 6 | import './AppInformation.scss' 7 | 8 | import { SystemInfoItem, } from '../../types/DebugTypes' 9 | 10 | import { transSystemInfo, transUserInfo, transAuthInfo } from '../../utils/util' 11 | 12 | type PageStateProps = { 13 | } 14 | 15 | type PageDispatchProps = { 16 | } 17 | 18 | type PageOwnProps = {} 19 | 20 | type PageState = { 21 | systemInfoList: Array, 22 | accountInfoList: Array, 23 | userInfoList: Array, 24 | authInfoList: Array 25 | } 26 | 27 | type IProps = PageStateProps & PageDispatchProps & PageOwnProps 28 | 29 | interface AppInformation { 30 | props: IProps; 31 | } 32 | 33 | class AppInformation extends Component { 34 | state = { 35 | systemInfoList: [], 36 | accountInfoList: [], 37 | userInfoList: [], 38 | authInfoList: [], 39 | } 40 | 41 | componentDidMount() { 42 | this.getSystemInfo() 43 | this.getAccountInfo() 44 | this.getUserInfo() 45 | this.getAuthInfo() 46 | } 47 | 48 | getSystemInfo = () => { 49 | Taro.getSystemInfo({ 50 | success: res => { 51 | this.setState({ 52 | systemInfoList: transSystemInfo(res) 53 | }) 54 | } 55 | }) 56 | } 57 | getAccountInfo = () => { 58 | this.setState({ 59 | accountInfoList: [{ 60 | name: '小程序APPID', 61 | value: Taro.getAccountInfoSync().miniProgram.appId 62 | }] 63 | }) 64 | } 65 | getUserInfo = () => { 66 | Taro.getUserInfo({ 67 | success: res => { 68 | this.setState({ 69 | userInfoList: transUserInfo(res.userInfo) 70 | }) 71 | } 72 | }) 73 | } 74 | getAuthInfo = () => { 75 | Taro.getSetting({ 76 | success: res => { 77 | this.setState({ 78 | authInfoList: transAuthInfo(res.authSetting) 79 | }) 80 | } 81 | }) 82 | } 83 | 84 | render () { 85 | const { systemInfoList, accountInfoList, userInfoList, authInfoList } = this.state 86 | return ( 87 | 88 | {systemInfoList.length > 0 && ( 89 | 系统信息 90 | )} 91 | 92 | {systemInfoList.map((item: SystemInfoItem) => ( 93 | 98 | ))} 99 | 100 | {accountInfoList.length > 0 && ( 101 | 账号信息 102 | )} 103 | 104 | {accountInfoList.map((item: SystemInfoItem) => ( 105 | 110 | ))} 111 | 112 | {userInfoList.length > 0 && ( 113 | 用户信息 114 | )} 115 | 116 | {userInfoList.map((item: SystemInfoItem) => ( 117 | item.type === 'img' ? ( 118 | 119 | {item.name} 120 | 121 | 122 | ) : ( 123 | 128 | ) 129 | ))} 130 | 131 | {authInfoList.length > 0 && ( 132 | 授权信息 133 | )} 134 | 135 | {authInfoList.map((item: SystemInfoItem) => ( 136 | 141 | ))} 142 | 143 | 144 | ) 145 | } 146 | } 147 | 148 | export default AppInformation as ComponentClass -------------------------------------------------------------------------------- /src/components/positionSimulation/PositionSimulation.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentClass } from 'react' 2 | import { View, Button, Image, } from '@tarojs/components' 3 | import Taro, { Component, } from '@tarojs/taro' 4 | import { AtActionSheet, AtListItem, } from 'taro-ui' 5 | import './PositionSimulation.scss' 6 | import { relaunch, transformFromWGSToGCJ, transformFromGCJToWGS, } from '../../utils/util' 7 | import { TransTypeItem } from '../../types/DebugTypes' 8 | import { CONVERT_LIST } from '../../utils/consants' 9 | 10 | const app = Taro.getApp() 11 | 12 | type PageStateProps = { 13 | } 14 | 15 | type PageDispatchProps = { 16 | } 17 | 18 | type PageOwnProps = {} 19 | 20 | type PageState = { 21 | currentLatitude: number 22 | currentLongitude: number 23 | showPopup: boolean 24 | transTypeList: Array 25 | } 26 | 27 | type IProps = PageStateProps & PageDispatchProps & PageOwnProps 28 | 29 | interface PositionSimulation { 30 | props: IProps; 31 | } 32 | 33 | class PositionSimulation extends Component { 34 | state = { 35 | currentLatitude: 0, 36 | currentLongitude: 0, 37 | showPopup: false, 38 | transTypeList: CONVERT_LIST 39 | } 40 | 41 | componentDidMount() { 42 | this.getMyPosition() 43 | } 44 | 45 | choosePosition = () => { 46 | Taro.chooseLocation({ 47 | success: res => { 48 | this.setState({ 49 | currentLatitude: res.latitude, 50 | currentLongitude: res.longitude 51 | }) 52 | Object.defineProperty(Taro, 'getLocation', { 53 | get() { 54 | return function(obj) { 55 | obj.success({ latitude: res.latitude, longitude: res.longitude }) 56 | } 57 | } 58 | }) 59 | console.log('chosen position...', res.latitude, res.longitude) 60 | relaunch({ content: '位置修改成功,即将导航到首页', }) 61 | } 62 | }) 63 | } 64 | getMyPosition = () => { 65 | Taro.getLocation({ 66 | type: 'gcj02', 67 | success: res => { 68 | this.setState({ 69 | currentLatitude: res.latitude, 70 | currentLongitude: res.longitude 71 | }) 72 | console.log('current position...', res.latitude, res.longitude) 73 | } 74 | }) 75 | } 76 | openMyPosition = () => { 77 | Taro.getLocation({ 78 | type: 'gcj02', 79 | success(res) { 80 | Taro.openLocation({ 81 | latitude: res.latitude, 82 | longitude: res.longitude, 83 | scale: 18 84 | }) 85 | } 86 | }) 87 | } 88 | resetPosition = () => { 89 | Object.defineProperty(Taro, 'getLocation', { 90 | get() { 91 | return function(obj) { 92 | obj.success({ latitude: app.initialLocation.latitude, longitude: app.initialLocation.longitude }) 93 | } 94 | } 95 | }) 96 | Taro.showToast({ title: '还原成功!', icon: 'none' }) 97 | this.getMyPosition() 98 | } 99 | convertPosition = () => { 100 | this.setState({ 101 | showPopup: true, 102 | }) 103 | } 104 | handleItemSelected = (e) => { 105 | const { type } = e.currentTarget.dataset.item 106 | const { latitude, longitude, } = Taro.getStorageSync('location') 107 | let obj: any = null 108 | if (type === 0) { 109 | obj = transformFromWGSToGCJ(latitude, longitude) 110 | } else if (type === 1) { 111 | obj = transformFromGCJToWGS(latitude, longitude) 112 | } 113 | Taro.setStorageSync('location', obj) 114 | console.log('transform result...', obj) 115 | Taro.showToast({ title: '转换成功!', icon: 'none' }) 116 | this.setState({ 117 | showPopup: !this.state.showPopup, 118 | }) 119 | } 120 | 121 | render() { 122 | const { showPopup, transTypeList, } = this.state 123 | return ( 124 | 125 | 126 | 129 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | {transTypeList.map((item: TransTypeItem) => ( 140 | {item.name} 141 | ))} 142 | 143 | 144 | 145 | ) 146 | } 147 | } 148 | 149 | export default PositionSimulation as ComponentClass 150 | -------------------------------------------------------------------------------- /src/components/storage/storage.scss: -------------------------------------------------------------------------------- 1 | $storage-color: #E1251B; 2 | .storage-container { 3 | padding: 40px; 4 | left: 0; 5 | right: 0; 6 | top: 0; 7 | bottom: 0; 8 | overflow: hidden; 9 | position: fixed; 10 | border-top: 1px solid #f6f6f6; 11 | .mask { 12 | position: fixed; 13 | left: 0; 14 | top: 0; 15 | right: 0; 16 | bottom: 0; 17 | background: rgba(0, 0, 0, 0.6); 18 | z-index: 10; 19 | } 20 | .storage-list { 21 | overflow: auto; 22 | height: 840px; 23 | margin-top: 20px; 24 | } 25 | .header { 26 | position: relative; 27 | height: 88px; 28 | .storage-manage{ 29 | position: absolute; 30 | right: 0; 31 | top: 20px; 32 | image{ 33 | width: 40px; 34 | height: 40px; 35 | } 36 | } 37 | .operate-list{ 38 | position: absolute; 39 | width: 240px; 40 | font-size: 28px; 41 | background: #fff; 42 | box-sizing: border-box; 43 | right: 0; 44 | top: 92px; 45 | z-index: 99; 46 | .arrow { 47 | position: absolute; 48 | width: 0; 49 | height: 0; 50 | border: 16px solid; 51 | border-color: transparent transparent #fff; 52 | right: 10px; 53 | top: -30px; 54 | } 55 | .operate-item { 56 | width: 100%; 57 | height: 72px; 58 | line-height: 72px; 59 | border-bottom: 1px solid #efefef; 60 | image { 61 | height: 40px; 62 | width: 40px; 63 | vertical-align: middle; 64 | margin-right: 20px; 65 | margin-left: 20px; 66 | } 67 | } 68 | } 69 | 70 | } 71 | .storage-list-container { 72 | margin-top: 30px; 73 | .table-title{ 74 | overflow: hidden; 75 | height: 68px; 76 | } 77 | .key-title{ 78 | width: 230px; 79 | height: 68px; 80 | float: left; 81 | margin-right: 2px; 82 | font-size: 28px; 83 | line-height: 68px; 84 | color: #fff; 85 | border-radius: 16px 0 0 16px; 86 | background: $storage-color; 87 | text-align: center; 88 | } 89 | .value-title{ 90 | width: 430px; 91 | float: left; 92 | height: 68px; 93 | font-size: 28px; 94 | line-height: 68px; 95 | color: #fff; 96 | border-radius: 0 16px 16px 0; 97 | background: $storage-color; 98 | text-align: center; 99 | } 100 | } 101 | .head-title{ 102 | font-size: 28px; 103 | } 104 | .storage-item { 105 | display:flex; 106 | flex-flow:row nowrap; 107 | font-size: 24px; 108 | height:80px; 109 | line-height: 80px; 110 | border-bottom: 1px solid #f6f6f6; 111 | .storage-key{ 112 | flex: 2.6; 113 | padding-left: 10px; 114 | } 115 | .storage-value{ 116 | flex: 6; 117 | padding-left: 10px; 118 | overflow: scroll; 119 | } 120 | .add-some-flex{ 121 | flex: 3.2 122 | } 123 | } 124 | .clear-single-btn{ 125 | flex:0.5; 126 | line-height:90px; 127 | text-align: center; 128 | image{ 129 | height:32px; 130 | width: 32px; 131 | } 132 | } 133 | .disabled { 134 | color: #888; 135 | } 136 | } 137 | .storage-footer { 138 | position: fixed; 139 | bottom: 30px; 140 | left: 40px; 141 | display: flex; 142 | .operate-btn{ 143 | display: flex; 144 | justify-content: center; 145 | align-items: center; 146 | background: #fff; 147 | color: $storage-color; 148 | border: 1px solid $storage-color; 149 | height: 88px; 150 | width: 224px; 151 | margin-right: 16px; 152 | font-size: 34px; 153 | } 154 | .operate-btn-delete{ 155 | display: flex; 156 | justify-content: center; 157 | align-items: center; 158 | background: #D8D8D8; 159 | color: #fff; 160 | height: 88px; 161 | width: 430px; 162 | box-sizing: border-box; 163 | &.delete-active{ 164 | background: $storage-color; 165 | } 166 | font-size: 34px; 167 | } 168 | 169 | } 170 | .add-input-container { 171 | margin-top: 20px; 172 | .add-input { 173 | width: 100%; 174 | border: 0; 175 | border-bottom: 1px solid #EEEEEE; 176 | padding-bottom: 16px; 177 | margin-top: 20px; 178 | } 179 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # MiniDebug 3 | 4 | MiniDebug是一款旨在提高多端小程序开发、测试效率的工具库。 5 | 6 | ## 特性 7 | 8 | - 基于[Taro框架](https://taro.aotu.io/home/in.html)开发,支持多端。 9 | - 基于[Taro UI组件库](https://taro-ui.aotu.io/#/)实现,界面美观。 10 | - 功能丰富,满足多样化开发、调试需求。 11 | - 本身是组件,引入简单,代码侵入性小。 12 | 13 | ## 架构图 14 | 15 | ### 1. MiniDebug架构图 16 | 17 | miniDebug工具基于[Taro框架](https://taro.aotu.io/home/in.html)开发,可编译成多端小程序应用。利用原生能力支持,通过暴露API,以及修改全局state、storage数据实现和业务层的数据交互。 18 | 19 | 20 | 21 | ### 2. 宿主工程引入MiniDebug架构图 22 | 23 | 宿主工程通过npm引入miniDebug工具,通过判断环境ENV,在编译阶段实现miniDebug承载页的动态注册。 24 | 25 | 26 | 27 | ## 功能介绍 28 | 29 | 主要功能包括环境切换、身份Mock、应用信息获取、位置模拟、缓存管理、扫一扫、H5跳转、更新版本等。工具首页如图所示。 30 | 31 | 32 | 33 | ### 1. 环境切换 34 | 35 | 让小程序在测试、预发、正式环境中随意切换。支持热加载,无需手动重启应用。 36 | 37 | 38 | 39 | ### 2. 身份Mock 40 | 41 | 动态切换登录账号(仅支持测试环境,预发、正式环境不建议明文传输用户身份)。 42 | 43 | 44 | 45 | ### 3. 应用信息获取 46 | 47 | 一键查看系统、账号、用户、授权信息,快速定位测试、UAT问题。 48 | 49 | 50 | 51 | ### 4. 位置模拟 52 | 53 | 功能包括 54 | - 快速授权,小程序授权入口很深,该功能可一键快速进行权限授权。 55 | - 查看位置,在地图上快速确定自己的位置。 56 | - 选择位置,代理小程序getLocation方法,无需修改代码即可任意切换当前位置。 57 | - 还原,一键还原用户位置。 58 | - 地址转换,支持wgs84和gcj02坐标系互转。 59 | 60 | 61 | 62 | ### 5. 缓存管理 63 | 64 | 支持storage信息的查看、新增、删除、修改。 65 | 66 | 67 | 68 | ### 6. 扫一扫 69 | 70 | 主要用于扫描小程序码、二维码场景。微信原生扫一扫扫码会直接跳转线上版本,该功能可以跳转至相应开发、体验版本,提高测试效率,降低上线风险。 71 | 72 | ### 7. H5跳转 73 | 74 | 主要用于在App环境打开H5场景。如测试H5在微信环境某些特殊逻辑。 75 | 76 | 77 | 78 | ### 8. 更新版本 79 | 80 | 更新小程序版本。 81 | 82 | ## 快速上手 83 | 84 | miniDebug工具基于[Taro框架](https://taro.aotu.io/home/in.html)和[Taro UI组件库](https://taro-ui.aotu.io/#/)开发,下面详细介绍引入步骤。 85 | 86 | ### 安装npm包 87 | 88 | 如果您的taro版本为1.x、2.x,请按如下方式安装 89 | 90 | ```bash 91 | npm install @jdlfe/minidebug --save-dev 92 | ``` 93 | 94 | 如果您的taro版本为3.x,请按如下方式安装 95 | 96 | ```bash 97 | npm install @jdlfe/minidebug-next --save-dev 98 | ``` 99 | 100 | ### 新建空页面 101 | 102 | 推荐在空目录下创建页面,该页面用于引入miniDebug组件 103 | 104 | ![avatar](https://m.360buyimg.com/marketingminiapp/jfs/t1/138948/20/3649/5434/5f1a3ee5E70d7fa1d/6cd409231879147c.png) 105 | 106 | ### 动态注册miniDebug承载页 107 | 108 | taro1.x、2.x版本: 109 | 修改App下的config对象里的pages属性,利用[Taro的preval](http://taro-docs-in.jd.com/taro/docs/envs.html)。如下所示,判断process.env.NODE_ENV,在非生产环境时才将miniDebug承载页注册,保证生产环境打包不包含miniDebug内容。 110 | 111 | ```javascript 112 | class App extends Taro.Component { 113 | config = { 114 | pages: preval` 115 | module.exports=(function() { 116 | const path = [ 117 | 'pages/module/pageA', 118 | 'pages/module/pageB', 119 | 'pages/module/pageC' 120 | ] 121 | if (process.env.NODE_ENV !== 'production') { 122 | path.push('packageD/debug/index') 123 | } 124 | return path 125 | })() 126 | `, 127 | ``` 128 | 129 | taro3.x版本: 130 | 在app.config.ts中注册miniDebug承载页 131 | 132 | ```javascript 133 | // 获取页面路径 134 | const getPages = () => { 135 | const path = [ 136 | 'pages/module/pageA', 137 | 'pages/module/pageB', 138 | 'pages/module/pageC' 139 | ] 140 | // 非生产环境注册debug承载页 141 | if (process.env.NODE_ENV !== 'production') { 142 | path.push('packageD/debug/index') 143 | } 144 | return path 145 | } 146 | export default { 147 | pages: getPages(), 148 | window: { 149 | backgroundTextStyle: 'light', 150 | navigationBarBackgroundColor: '#fff', 151 | navigationBarTitleText: 'WeChat', 152 | navigationBarTextStyle: 'black' 153 | } 154 | } 155 | ``` 156 | 157 | ### 引入miniDebug组件 158 | 159 | 只需将miniDebug作为普通Taro组件引入。taro1.x、2.x版本: 160 | 161 | ```javascript 162 | import { Debug } from '@jdlfe/minidebug' 163 | ``` 164 | taro 3.x版本: 165 | 166 | ```javascript 167 | import { Debug } from '@jdlfe/minidebug-next' 168 | ``` 169 | 170 | 引入组件依赖的样式文件。taro1.x、2.x版本: 171 | 172 | ```scss 173 | @import '~@jdlfe/minidebug/src/app.scss' 174 | ``` 175 | 176 | taro 3.x版本: 177 | 178 | ```scss 179 | @import "~@jdlfe/minidebug-next/dist/style/index.scss"; 180 | ``` 181 | 182 | ### 修改render函数 183 | 184 | ```javascript 185 | render() { 186 | return ( 187 | 188 | {/* 将miniDebug当做普通组件引入 */} 189 | 190 | 191 | ) 192 | } 193 | ``` 194 | 195 | ### 首页新增miniDebug入口 196 | 197 | 该方法需在render函数中调用 198 | 199 | ```javascript 200 | renderDebug() { 201 | // 只有测试、预发环境,才会展示miniDebug入口 202 | if (process.env.NODE_ENV === 'production') return false 203 | return ( 204 | 205 | debug 206 | 207 | ) 208 | } 209 | ``` 210 | 211 | ### 跳转miniDebug方法 212 | 213 | ```javascript 214 | goMiniDebug() { 215 | Taro.navigateTo({ 216 | url: `/packageD/debug/index` 217 | }) 218 | } 219 | ``` 220 | 221 | ### 切换环境功能引入 222 | 223 | 因不同项目测试、预发、正式环境变量不同,因此,通过miniDebug切换完环境后,首先会将设置的环境变量保存到storage中,然后会暴露一个全局状态,在应用首页检测到该状态值时,需要您自行实现环境变量切换的方法。 224 | 225 | ```javascript 226 | // 此段代码通常在小程序入口文件,onLoad第一行 227 | // Taro.getApp().needResetHttp为true,代表用户通过miniDebug修改了环境变量 228 | if (Taro.getApp().needResetHttp) { 229 | // 将标识重置 230 | Taro.getApp().needResetHttp = false 231 | // resetHttp即为更改环境变量的方法,需要自行实现 232 | resetHttp() 233 | } 234 | // 参考实现 235 | const ROOT_PATH = { 236 | development: 'https://test.test.com', 237 | prepare: 'https://uat.test.com', 238 | production: 'https://prod.test.com', 239 | } 240 | resetHttp() { 241 | try { 242 | // 先获取miniDebug中修改的env环境变量,有效取值为"development"、"prepare"、"production" 243 | const env = Taro.getStorageSync('env') || "production" 244 | // 根据miniDebug设置的env,更改网络请求URL 245 | // 你的项目可能识别的设置方式,目的是更改网络请求的base URL 246 | Taro.getApp().globalData.Http.config.root = ROOT_PATH[env] 247 | } catch (e) {} 248 | } 249 | ``` 250 | ## F&Q 251 | ### 1. taro1.x版本,构建后提示“Error: File to import not found or unreadable: ~@jdlfe/minidebug/src/app.scss.” 252 | 原因是找不到minidebug的样式文件,需要在config/index配置文件新增sass配置,参考配置如下: 253 | ```javascript 254 | const path = require('path') 255 | const sassImporter = function(url) { 256 | if (url[0] === '~' && url[1] !== '/' && (url.includes('minidebug') || url.includes('taro-ui'))) { 257 | return { 258 | file: path.resolve(__dirname, '..', 'node_modules', url.substr(1)) 259 | } 260 | } 261 | } 262 | const config = { 263 | // ... 264 | sass: { 265 | importer: sassImporter, 266 | } 267 | } 268 | ``` -------------------------------------------------------------------------------- /src/components/debug/Debug.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentClass } from 'react' 2 | import Taro, { Component, } from '@tarojs/taro' 3 | import { View, CoverImage, CoverView, } from '@tarojs/components' 4 | import { AtList, AtListItem, AtActionSheet, AtActionSheetItem, } from 'taro-ui' 5 | 6 | import './Debug.scss' 7 | import { Menu, ENV } from '../../types/DebugTypes' 8 | import { FEATURE, HOME_OPERATION_LIST, HOME_MENU, ENV_LIST } from '../../utils/consants' 9 | 10 | import ChangePin from '../changePin/ChangePin' 11 | import AppInformation from '../../components/appinformation/AppInformation' 12 | import PositionSimulation from '../../components/positionSimulation/PositionSimulation' 13 | import H5door from '../../components/h5door/H5door' 14 | import Storage from '../../components/storage/Storage' 15 | 16 | const app = Taro.getApp() 17 | 18 | type PageStateProps = { 19 | HOME_PAGE: string 20 | } 21 | 22 | type PageDispatchProps = {} 23 | 24 | type PageOwnProps = {} 25 | 26 | type PageState = { 27 | menuList: Array 28 | envList: Array 29 | showPopup: boolean 30 | curEnv: string 31 | featureType: number 32 | hideHomeMenu: boolean 33 | } 34 | 35 | type IProps = PageStateProps & PageDispatchProps & PageOwnProps 36 | 37 | interface Debug { 38 | props: IProps; 39 | } 40 | 41 | class Debug extends Component { 42 | state = { 43 | menuList: HOME_MENU, 44 | envList: ENV_LIST, 45 | showPopup: false, 46 | curEnv: '', 47 | featureType: FEATURE.DEFAULT, 48 | hideHomeMenu: false, 49 | } 50 | 51 | componentDidMount() { 52 | const envEnum = Taro.getStorageSync('env') 53 | const envItem = this.state.envList.find(item => item.env === envEnum) 54 | this.setState({ 55 | curEnv: envItem ? envItem.name : '', 56 | }) 57 | if (!app.initialLocation) { 58 | Taro.getLocation({ 59 | success: res => { 60 | app.initialLocation = { 61 | latitude: res.latitude, 62 | longitude: res.longitude 63 | } 64 | Taro.setStorageSync('location', app.initialLocation) 65 | console.log('initialLocation', app.initialLocation) 66 | } 67 | }) 68 | } 69 | } 70 | 71 | onUpdate = () => { 72 | const updateManager = Taro.getUpdateManager() 73 | updateManager.onCheckForUpdate(function(res) { 74 | if (res && !res.hasUpdate) { 75 | // 请求完新版本信息的回调 76 | Taro.showModal({ 77 | title: '更新提示', 78 | content: '当前已经是最新版本' 79 | }) 80 | } 81 | }) 82 | updateManager.onUpdateReady(function() { 83 | Taro.showModal({ 84 | title: '更新提示', 85 | content: '新版本已经准备好,是否重启应用?', 86 | success(res) { 87 | if (res.confirm) { 88 | // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启 89 | updateManager.applyUpdate() 90 | } 91 | } 92 | }) 93 | }) 94 | updateManager.onUpdateFailed(function() { 95 | // 新版本下载失败 96 | }) 97 | } 98 | onChangeEnv = () => { 99 | this.showAddPopup() 100 | } 101 | onScan = () => { 102 | Taro.scanCode({ 103 | success: (res) => { 104 | console.log('scan result...', res) 105 | res.path && Taro.reLaunch({ url:`/${res.path}` }) 106 | } 107 | }) 108 | } 109 | showAddPopup = () => { 110 | this.setState({ 111 | showPopup: true, 112 | }) 113 | } 114 | closeAll = () => { 115 | this.setState({ 116 | showPopup: false, 117 | }) 118 | } 119 | openSetting = () => { 120 | Taro.openSetting({ 121 | success: function(res) { 122 | console.log(res) 123 | } 124 | }) 125 | } 126 | handleMenuClicked = (event) => { 127 | const { type, } = event.currentTarget.dataset.item 128 | this.setState({ featureType: type }) 129 | if (type === FEATURE.CHANGE_ENV) { 130 | this.onChangeEnv() 131 | } else if (type === FEATURE.SCAN) { 132 | this.onScan() 133 | } else if (type === FEATURE.UPDATE) { 134 | this.onUpdate() 135 | } 136 | 137 | 138 | } 139 | handleChangeEnv = (env) => { 140 | const that = this; 141 | Taro.setStorage({ 142 | key: 'env', 143 | data: env, 144 | success: () => { 145 | Taro.showModal({ 146 | title: '提示', 147 | content: '环境设置成功,应用即将重启', 148 | confirmText: '知道了', 149 | showCancel: false, 150 | success: res => { 151 | if (res.confirm) { 152 | // reLaunch不走app.js了 153 | Taro.getApp().needResetHttp = true 154 | Taro.reLaunch({ url: that.props.HOME_PAGE || '/pages/index/index' }) 155 | } 156 | } 157 | }) 158 | }, 159 | complete: () => { 160 | this.closeAll() 161 | } 162 | }) 163 | } 164 | 165 | onShowHomeMenu = () => { 166 | this.setState({ hideHomeMenu: false, }) 167 | } 168 | onHideHomeMenu = () => { 169 | this.setState({ hideHomeMenu: true, }) 170 | } 171 | 172 | render () { 173 | const { menuList, showPopup, envList, curEnv, featureType, hideHomeMenu, } = this.state 174 | const showDebugMenu = HOME_OPERATION_LIST.indexOf(featureType) > -1 175 | return ( 176 | 177 | {!showDebugMenu && !hideHomeMenu && ( 178 | 179 | { this.setState({ featureType: -1 }) }} 183 | > 184 | 185 | 186 | )} 187 | {showDebugMenu && ( 188 | 189 | {menuList.map(item => ( 190 | { 195 | e.currentTarget.dataset.item = item 196 | this.handleMenuClicked(e) 197 | }} 198 | note={item.title !== '环境切换' ? item.desc : (curEnv ? `当前环境:${curEnv}` : '环境切换')} 199 | hasBorder 200 | /> 201 | ))} 202 | 203 | )} 204 | 205 | {envList.map(item => ( 206 | { 209 | this.handleChangeEnv(item.env) 210 | }} 211 | > 212 | {item.name} 213 | 214 | ))} 215 | 216 | 217 | {featureType === FEATURE.CHANGE_PIN && ( 218 | 219 | )} 220 | {featureType === FEATURE.GET_APP_INFO && ( 221 | 222 | )} 223 | {featureType === FEATURE.MOCK_POSITION && ( 224 | 225 | )} 226 | {featureType === FEATURE.JUMP_H5 && ( 227 | 228 | )} 229 | {/* 缓存管理 */} 230 | {featureType === FEATURE.MANAGE_STORAGE && ( 231 | 232 | )} 233 | 234 | ) 235 | } 236 | } 237 | 238 | // #region 导出注意 239 | // 240 | // 经过上面的声明后需要将导出的 Taro.Component 子类修改为子类本身的 props 属性 241 | // 这样在使用这个子类时 Ts 才不会提示缺少 JSX 类型参数错误 242 | // 243 | // #endregion 244 | 245 | export default Debug as ComponentClass 246 | -------------------------------------------------------------------------------- /src/utils/util.js: -------------------------------------------------------------------------------- 1 | import Taro from '@tarojs/taro' 2 | 3 | export const handleGoPage = url => { 4 | Taro.navigateTo({ 5 | url 6 | }) 7 | } 8 | export const relaunch = ({ title = '提示', content, confirmText = '知道了', showCancel = false, cancelText = '', }) => { 9 | Taro.showModal({ 10 | title, 11 | content, 12 | confirmText, 13 | showCancel, 14 | cancelText, 15 | success: res => { 16 | if (res.confirm) { 17 | Taro.reLaunch({ url: '/pages/index/index' }) 18 | } 19 | } 20 | }) 21 | } 22 | /** 23 | * 将WGS-84(国际标准)转为GCJ-02(火星坐标): 24 | */ 25 | export function transformFromWGSToGCJ(latitude, longitude) { 26 | var ee = 0.00669342162296594323; 27 | var a = 6378245.0; 28 | var pi = 3.14159265358979324; 29 | var adjustLat = transformLatWithXY(longitude - 105.0, latitude - 35.0); 30 | var adjustLon = transformLonWithXY(longitude - 105.0, latitude - 35.0); 31 | var radLat = latitude / 180.0 * pi; 32 | var magic = Math.sin(radLat); 33 | magic = 1 - ee * magic * magic; 34 | var sqrtMagic = Math.sqrt(magic); 35 | adjustLat = (adjustLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi); 36 | adjustLon = (adjustLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi); 37 | latitude = latitude + adjustLat; 38 | longitude = longitude + adjustLon; 39 | return { latitude: latitude, longitude: longitude }; 40 | 41 | } 42 | /** 43 | * 将GCJ-02(火星坐标)转为WGS-84: 44 | */ 45 | export function transformFromGCJToWGS(latitude, longitude) { 46 | var threshold = 0.00001; 47 | 48 | // The boundary 49 | var minLat = latitude - 0.5; 50 | var maxLat = latitude + 0.5; 51 | var minLng = longitude - 0.5; 52 | var maxLng = longitude + 0.5; 53 | 54 | var delta = 1; 55 | var maxIteration = 30; 56 | 57 | while (true) { 58 | var leftBottom = transformFromWGSToGCJ(minLat, minLng); 59 | var rightBottom = transformFromWGSToGCJ(minLat, maxLng); 60 | var leftUp = transformFromWGSToGCJ(maxLat, minLng); 61 | var midPoint = transformFromWGSToGCJ((minLat + maxLat) / 2, (minLng + maxLng) / 2); 62 | delta = Math.abs(midPoint.latitude - latitude) + Math.abs(midPoint.longitude - longitude); 63 | 64 | if (maxIteration-- <= 0 || delta <= threshold) { 65 | return { latitude: (minLat + maxLat) / 2, longitude: (minLng + maxLng) / 2 }; 66 | } 67 | 68 | if (isContains({ latitude: latitude, longitude: longitude }, leftBottom, midPoint)) { 69 | maxLat = (minLat + maxLat) / 2; 70 | maxLng = (minLng + maxLng) / 2; 71 | } 72 | else if (isContains({ latitude: latitude, longitude: longitude }, rightBottom, midPoint)) { 73 | maxLat = (minLat + maxLat) / 2; 74 | minLng = (minLng + maxLng) / 2; 75 | } 76 | else if (isContains({ latitude: latitude, longitude: longitude }, leftUp, midPoint)) { 77 | minLat = (minLat + maxLat) / 2; 78 | maxLng = (minLng + maxLng) / 2; 79 | } 80 | else { 81 | minLat = (minLat + maxLat) / 2; 82 | minLng = (minLng + maxLng) / 2; 83 | } 84 | } 85 | 86 | } 87 | function transformLatWithXY(x, y) { 88 | var pi = 3.14159265358979324; 89 | var lat = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x)); 90 | lat += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; 91 | lat += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0; 92 | lat += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0; 93 | return lat; 94 | } 95 | 96 | function transformLonWithXY(x, y) { 97 | var pi = 3.14159265358979324; 98 | var lon = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x)); 99 | lon += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; 100 | lon += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0; 101 | lon += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0; 102 | return lon; 103 | } 104 | function isContains(point, p1, p2) { 105 | return (point.latitude >= Math.min(p1.latitude, p2.latitude) && point.latitude <= Math.max(p1.latitude, p2.latitude)) && (point.longitude >= Math.min(p1.longitude, p2.longitude) && point.longitude <= Math.max(p1.longitude, p2.longitude)); 106 | } 107 | function transBool(bol) { 108 | return bol ? '是' : '否' 109 | } 110 | 111 | const getPerformance = function(lev) { 112 | if (lev === -2 || lev === 0) return '该设备无法运行小游戏' 113 | if (lev === -1) return '性能未知' 114 | if (lev > 1 && lev < 10) return '低' 115 | if (lev > 11 && lev < 25) return '中' 116 | if (lev > 26 && lev < 50) return '优' 117 | } 118 | 119 | export const transSystemInfo = function(info) { 120 | 121 | return [ 122 | { 123 | name: '设备品牌', 124 | value: info.brand 125 | }, 126 | { 127 | name: '设备型号', 128 | value: info.model 129 | }, 130 | { 131 | name: '设备像素比', 132 | value: info.pixelRatio 133 | }, 134 | { 135 | name: '屏幕宽高', 136 | value: info.screenWidth + '/' + info.screenHeight 137 | }, 138 | { 139 | name: '可视区域宽高', 140 | value: info.windowWidth + '/' + info.windowHeight 141 | }, 142 | { 143 | name: '微信版本号', 144 | value: info.version 145 | }, 146 | { 147 | name: '操作系统及版本号', 148 | value: info.system 149 | }, 150 | { 151 | name: '客户端平台', 152 | value: info.platform 153 | }, 154 | { 155 | name: '设备性能值', 156 | value: getPerformance(info.benchmarkLevel) 157 | }, 158 | { 159 | name: '允许微信使用摄像头的开关', 160 | value: transBool(info.cameraAuthorized) 161 | }, 162 | { 163 | name: '允许微信使用定位的开关', 164 | value: transBool(info.locationAuthorized) 165 | }, 166 | { 167 | name: '允许微信使用麦克风的开关', 168 | value: transBool(info.microphoneAuthorized) 169 | }, 170 | { 171 | name: '允许微信通知的开关', 172 | value: transBool(info.notificationAuthorized) 173 | }, 174 | { 175 | name: '地理位置的系统开关', 176 | value: transBool(info.locationEnabled) 177 | }, 178 | { 179 | name: 'Wi-Fi 的系统开关', 180 | value: transBool(info.wifiEnabled) 181 | } 182 | ] 183 | } 184 | export const transUserInfo = function(info) { 185 | return [ 186 | { 187 | name: '昵称', 188 | value: info.nickName 189 | }, 190 | { 191 | name: '性别', 192 | value: info.gender === 1 ? '男' : '女' 193 | }, 194 | { 195 | name: '地区', 196 | value: info.city + ' ' + info.province + ' ' + info.country 197 | }, 198 | { 199 | name: '头像', 200 | type: 'img', 201 | value: info.avatarUrl 202 | } 203 | ] 204 | } 205 | 206 | export const transAuthInfo = function(info) { 207 | return [ 208 | { 209 | name: '是否授权用户信息', 210 | value: transBool(info['scope.userInfo']) 211 | }, 212 | { 213 | name: '是否授权地理位置', 214 | value: transBool(info['scope.userLocation']) 215 | }, 216 | { 217 | name: '是否授权通讯地址', 218 | value: transBool(info['scope.address']) 219 | }, 220 | { 221 | name: '是否授权发票抬头', 222 | value: transBool(info['scope.invoiceTitle']) 223 | }, 224 | { 225 | name: '是否授权获取发票', 226 | value: transBool(info['scope.invoice']) 227 | }, 228 | { 229 | name: '是否授权微信运动步数', 230 | value: transBool(info['scope.werun']) 231 | }, 232 | { 233 | name: '是否授权录音功能', 234 | value: transBool(info['scope.record']) 235 | }, 236 | { 237 | name: '是否授权保存到相册', 238 | value: transBool(info['scope.writePhotosAlbum']) 239 | }, 240 | { 241 | name: '是否授权摄像头', 242 | value: transBool(info['scope.camera']) 243 | } 244 | ] 245 | } 246 | -------------------------------------------------------------------------------- /src/components/storage/Storage.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | View, 3 | Image, 4 | CheckboxGroup, 5 | Checkbox, 6 | Text, 7 | Input, 8 | Button 9 | } from '@tarojs/components' 10 | import Taro, { Component, } from '@tarojs/taro' 11 | import { ComponentClass } from 'react' 12 | import { AtFloatLayout, } from 'taro-ui' 13 | import './Storage.scss' 14 | 15 | import { AddrInfo, StorageModifyItem, } from '../../types/DebugTypes' 16 | 17 | type PageStateProps = { 18 | } 19 | 20 | type PageDispatchProps = { 21 | } 22 | 23 | type PageOwnProps = { 24 | onShowHomeMenu: () => void 25 | onHideHomeMenu: () => void 26 | } 27 | 28 | type PageState = { 29 | storage: Array 30 | limitSize: number 31 | currentSize: number 32 | isShowManage: boolean 33 | showPopup: boolean 34 | isShowMask: boolean 35 | isDeleteMode: boolean 36 | checkedStorage: Array 37 | addInfo: AddrInfo 38 | } 39 | 40 | type IProps = PageStateProps & PageDispatchProps & PageOwnProps 41 | 42 | interface Storage { 43 | props: IProps; 44 | } 45 | 46 | class Storage extends Component { 47 | state = { 48 | storage: [], 49 | limitSize: 0, 50 | currentSize: 0, 51 | isShowManage: false, 52 | showPopup: false, 53 | isShowMask: false, 54 | isDeleteMode: false, 55 | checkedStorage: [], 56 | addInfo: { 57 | key: '', 58 | value: '', 59 | title: '新增Storage', 60 | disabled: false 61 | }, 62 | } 63 | 64 | componentDidMount() { 65 | this.handleResetData() 66 | } 67 | 68 | openDeleteMode = () => { 69 | this.setState({ 70 | isDeleteMode: true 71 | }) 72 | this.closeAll() 73 | } 74 | cancelDelete = () => { 75 | this.setState({ 76 | isDeleteMode: false 77 | }) 78 | } 79 | showAddPopup = () => { 80 | this.setState({ 81 | isShowManage: false, 82 | showPopup: true, 83 | isShowMask: false, 84 | addInfo: { 85 | key: '', 86 | value: '', 87 | title: '新增Storage', 88 | disabled: false 89 | } 90 | }) 91 | this.props.onHideHomeMenu && this.props.onHideHomeMenu() 92 | } 93 | getStorageInfo = () => { 94 | const storageArr: Array = [] 95 | const storageInfo = Taro.getStorageInfoSync() 96 | storageInfo.keys.forEach(key => { 97 | const result = Taro.getStorageSync(key) 98 | const info = { 99 | key, 100 | value: JSON.stringify(result), 101 | isModify: false, 102 | ischecked: false 103 | } 104 | storageArr.push(info) 105 | }) 106 | this.setState({ 107 | limitSize: storageInfo.limitSize, 108 | currentSize: storageInfo.currentSize, 109 | storage: storageArr 110 | }) 111 | } 112 | closeAll = () => { 113 | this.setState({ 114 | isShowManage: false, 115 | isShowMask: false, 116 | showPopup: false, 117 | }) 118 | this.state.isDeleteMode && this.setState({ isDeleteMode: false }) 119 | this.props.onShowHomeMenu && this.props.onShowHomeMenu() 120 | } 121 | openManageMenu = () => { 122 | this.setState({ 123 | isShowManage: true, 124 | isShowMask: true 125 | }) 126 | this.props.onHideHomeMenu && this.props.onHideHomeMenu() 127 | } 128 | clearStorage = (event) => { 129 | if (!this.state.checkedStorage.length) { 130 | return 131 | } 132 | Taro.showModal({ 133 | title: '提示', 134 | content: '确定删除选中缓存?', 135 | success: res => { 136 | if (res.confirm) { 137 | this.state.checkedStorage.forEach(item => { 138 | Taro.removeStorageSync(item) 139 | }) 140 | this.handleResetData() 141 | } 142 | } 143 | }) 144 | } 145 | handleResetData = () => { 146 | this.setState({ 147 | addInfo: { 148 | key: '', 149 | value: '', 150 | title: '新增Storage', 151 | disabled: false 152 | } 153 | }) 154 | this.getStorageInfo() 155 | } 156 | clearAll = () => { 157 | this.setState({ 158 | isShowManage: false 159 | }) 160 | Taro.showModal({ 161 | title: '提示', 162 | content: '确定要清除全部缓存吗?', 163 | success: res => { 164 | if (res.confirm) { 165 | Taro.clearStorageSync() 166 | this.handleResetData() 167 | } 168 | this.closeAll() 169 | } 170 | }) 171 | } 172 | onCheckChanged = (event) => { 173 | this.setState({ checkedStorage: event.detail.value }) 174 | } 175 | onModifyClicked = (event) => { 176 | this.setState({ 177 | showPopup: true, 178 | addInfo: { 179 | key: event.currentTarget.dataset.key, 180 | value: event.currentTarget.dataset.value, 181 | title: '修改Storage', 182 | disabled: true 183 | } 184 | }) 185 | this.props.onHideHomeMenu && this.props.onHideHomeMenu() 186 | } 187 | onKeyInput = (event) => { 188 | const addInfo = Object.assign({}, this.state.addInfo, { key: event.detail.value }) 189 | this.setState({ addInfo }) 190 | } 191 | onValueInput = (event) => { 192 | const addInfo = Object.assign({}, this.state.addInfo, { value: event.detail.value }) 193 | this.setState({ addInfo }) 194 | } 195 | addStorage = () => { 196 | if (this.state.addInfo.key && this.state.addInfo.value) { 197 | try { 198 | const parseVal = JSON.parse(this.state.addInfo.value) 199 | Taro.setStorageSync(this.state.addInfo.key, parseVal) 200 | this.handleResetData() 201 | this.closeAll() 202 | } catch(e) { 203 | Taro.showModal({ 204 | title: '提示', 205 | content: '新增缓存失败,请检查输入内容', 206 | confirmText: '知道了', 207 | showCancel: false, 208 | }) 209 | } 210 | } 211 | } 212 | 213 | render() { 214 | const { 215 | isShowMask, 216 | limitSize, 217 | currentSize, 218 | isShowManage, 219 | storage, 220 | isDeleteMode, 221 | showPopup, 222 | addInfo, 223 | checkedStorage 224 | } = this.state 225 | const deleteActive = checkedStorage.length > 0 226 | return ( 227 | 228 | {isShowMask && } 229 | 230 | {`限制空间大小:${limitSize} KB`} 231 | {`当前占用空间大小:${currentSize} KB`} 232 | 233 | 234 | 235 | {isShowManage && ( 236 | 237 | 238 | 239 | 240 | 新增 241 | 242 | 243 | 244 | 删除 245 | 246 | 247 | 248 | 清除全部 249 | 250 | 251 | )} 252 | 253 | 254 | 255 | Key 256 | Value 257 | 258 | 262 | {storage.map((item: StorageModifyItem, index) => { 263 | return ( 264 | 268 | {isDeleteMode && ( 269 | 273 | )} 274 | 279 | {item.key} 280 | 281 | 282 | {item.value} 283 | 284 | 290 | 291 | 292 | 293 | ) 294 | })} 295 | 296 | 297 | 302 | 303 | 304 | {'键名:Key' + (addInfo.disabled ? '(不可修改)' : '')} 305 | 306 | 313 | 314 | 315 | 键值:Value 316 | 322 | 323 | 324 | {isDeleteMode && ( 325 | 326 | 329 | 338 | 339 | )} 340 | 341 | ) 342 | } 343 | } 344 | 345 | export default Storage as ComponentClass --------------------------------------------------------------------------------