├── .babelrc ├── .buckconfig ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .watchmanconfig ├── README.md ├── __tests__ ├── index.android.js └── index.ios.js ├── android ├── app │ ├── BUCK │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── rnayinstalment │ │ │ ├── MainActivity.java │ │ │ └── MainApplication.java │ │ └── res │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ └── values │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── keystores │ ├── BUCK │ └── debug.keystore.properties └── settings.gradle ├── app.json ├── app ├── App.js ├── apply │ ├── ApplyDetail.js │ ├── ApplyFirst.js │ ├── ApplyTab.js │ ├── ItemCell │ │ ├── ApplyDescList.js │ │ ├── CommonCell.js │ │ └── StatusList.js │ └── TabItems │ │ ├── ApplyAllItem.js │ │ ├── ApplyFailedItem.js │ │ ├── ApplyedItem.js │ │ └── ApplyingItem.js ├── common │ ├── Common.js │ ├── CommonListEmpty.js │ ├── Config.js │ ├── LoadMoreFooter.js │ ├── NavBarCommon.js │ ├── RNAsyncStorage.js │ ├── Request.js │ └── md5.js ├── home │ ├── HomeBottomList.js │ ├── HomeTab.js │ ├── ProduceDetail.js │ └── QrcScan.js ├── images │ ├── GQZ_QRCode@2x.png │ ├── board-actived.png │ ├── board.png │ ├── common_bg_kong_n@2x.png │ ├── common_bg_kong_n@3x.png │ ├── common_bg_shujushibai_n@2x.png │ ├── common_bg_shujushibai_n@3x.png │ ├── common_bg_wangluoshibai_n@2x.png │ ├── common_bg_wangluoshibai_n@3x.png │ ├── guide_1@2x.png │ ├── guide_2@2x.png │ ├── guide_3@2x.png │ ├── home-actived.png │ ├── home.png │ ├── lanuch.png │ ├── login_logo@2x.png │ ├── login_logo@3x.png │ ├── login_pwd.png │ ├── login_user.png │ ├── nav_back.png │ ├── nav_share.png │ ├── profile-actived.png │ ├── profile.png │ ├── projectGif.gif │ ├── projectShot.jpg │ └── projectTree.jpg ├── login │ ├── Guide.js │ ├── LaunchView.js │ └── Login.js ├── mine │ ├── MineTab.js │ ├── OrderItemList.js │ └── SetRate.js └── navigator │ ├── Navigator.js │ └── TabBar.js ├── assets └── fonts │ └── iconfont.ttf ├── index.android.js ├── index.ios.js ├── ios ├── RNAYInstalment-tvOS │ └── Info.plist ├── RNAYInstalment-tvOSTests │ └── Info.plist ├── RNAYInstalment.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── RNAYInstalment-tvOS.xcscheme │ │ └── RNAYInstalment.xcscheme ├── RNAYInstalment │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── LaunchScreen.xib │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ └── main.m └── RNAYInstalmentTests │ ├── Info.plist │ └── RNAYInstalmentTests.m ├── package-lock.json ├── package.json └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react-native"] 3 | } 4 | -------------------------------------------------------------------------------- /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | .*/Libraries/react-native/ReactNative.js 16 | 17 | [include] 18 | 19 | [libs] 20 | node_modules/react-native/Libraries/react-native/react-native-interface.js 21 | node_modules/react-native/flow 22 | flow/ 23 | 24 | [options] 25 | emoji=true 26 | 27 | module.system=haste 28 | 29 | experimental.strict_type_args=true 30 | 31 | munge_underscores=true 32 | 33 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 34 | 35 | suppress_type=$FlowIssue 36 | suppress_type=$FlowFixMe 37 | suppress_type=$FixMe 38 | 39 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-2]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 40 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-2]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 41 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 42 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 43 | 44 | unsafe.enable_getters_and_setters=true 45 | 46 | [version] 47 | ^0.42.0 48 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 50 | 51 | fastlane/report.xml 52 | fastlane/Preview.html 53 | fastlane/screenshots 54 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-AyInstalment 2 | 基于React-Native 完成的简单金融分期项目 3 | 4 | 5 | ### 项目下载安装: 6 | 1. 目前只支持iOS平台,稍后适配android平台 7 | 2. 下载:git clone [https://github.com/zouyajun/react-native-AyInstalment.git](https://github.com/zouyajun/react-native-AyInstalment.git) 8 | 3. 安装:cd react-native-AyInstalmen --> npm install --> react-native run-ios(run-android) 9 | 4. 登录测试账号:username:13621372137 password: 123456 10 | 11 | ### 项目基础模块如下: 12 | ``` 13 | 支持下拉刷新和上拖加载更多 14 | 首页轮播图 15 | 图片多图预览 16 | 支持顶部多级标签栏切换 17 | 包含登录、退出、启动页、引导页面等 18 | 首页分期模块 19 | 分期申请表单模块 20 | 分期列表详情模块 21 | 个人中心模块 22 | ``` 23 | ### 项目文件目录结构: 24 | 25 | ![](https://github.com/zouyajun/react-native-AyInstalment/blob/master/app/images/projectTree.jpg) 26 | 27 | ### 依赖组件: 28 | ``` 29 | "dependencies": { 30 | "lodash": "^4.17.10", 31 | "query-string": "^6.1.0", 32 | "react": "16.0.0-alpha.6", 33 | "react-native": "0.44.0", 34 | "react-native-app-intro": "^1.1.5", 35 | "react-native-easy-toast": "^1.1.0", 36 | "react-native-gesture-handler": "^1.0.3", 37 | "react-native-image-zoom-viewer": "^2.2.5", 38 | "react-native-loading-spinner-overlay": "^0.3.0", 39 | "react-native-picker": "^4.3.7", 40 | "react-native-scrollable-tab-view": "^0.8.0", 41 | "react-native-simple-picker": "^2.1.0", 42 | "react-native-storage": "^0.2.2", 43 | "react-native-swiper": "^1.5.13", 44 | "react-native-tab-navigator": "^0.3.4", 45 | "react-native-tab-view": "^0.0.78" 46 | } 47 | ``` 48 | ### 安装运行出现问题: 49 | - 登录无法显示数据问题: 50 | > 服务器token失效,需要退出重新登录即可 51 | 52 | 53 | ### 部分页面截图: 54 | 55 | 如果对您有帮助,您可以点右上角 "Star" 支持一下 谢谢! ^_^ 56 | ![](https://github.com/zouyajun/react-native-AyInstalment/blob/master/app/images/projectShot.jpg) 57 | 58 | ### 效果图: 59 | 60 | ![](https://github.com/zouyajun/react-native-AyInstalment/blob/master/app/images/projectGif.gif) 61 | -------------------------------------------------------------------------------- /__tests__/index.android.js: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import Index from '../index.android.js'; 4 | 5 | // Note: test renderer must be required after react-native. 6 | import renderer from 'react-test-renderer'; 7 | 8 | it('renders correctly', () => { 9 | const tree = renderer.create( 10 | 11 | ); 12 | }); 13 | -------------------------------------------------------------------------------- /__tests__/index.ios.js: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import Index from '../index.ios.js'; 4 | 5 | // Note: test renderer must be required after react-native. 6 | import renderer from 'react-test-renderer'; 7 | 8 | it('renders correctly', () => { 9 | const tree = renderer.create( 10 | 11 | ); 12 | }); 13 | -------------------------------------------------------------------------------- /android/app/BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | lib_deps = [] 12 | 13 | for jarfile in glob(['libs/*.jar']): 14 | name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] 15 | lib_deps.append(':' + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | 21 | for aarfile in glob(['libs/*.aar']): 22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] 23 | lib_deps.append(':' + name) 24 | android_prebuilt_aar( 25 | name = name, 26 | aar = aarfile, 27 | ) 28 | 29 | android_library( 30 | name = "all-libs", 31 | exported_deps = lib_deps, 32 | ) 33 | 34 | android_library( 35 | name = "app-code", 36 | srcs = glob([ 37 | "src/main/java/**/*.java", 38 | ]), 39 | deps = [ 40 | ":all-libs", 41 | ":build_config", 42 | ":res", 43 | ], 44 | ) 45 | 46 | android_build_config( 47 | name = "build_config", 48 | package = "com.rnayinstalment", 49 | ) 50 | 51 | android_resource( 52 | name = "res", 53 | package = "com.rnayinstalment", 54 | res = "src/main/res", 55 | ) 56 | 57 | android_binary( 58 | name = "app", 59 | keystore = "//android/keystores:debug", 60 | manifest = "src/main/AndroidManifest.xml", 61 | package_type = "debug", 62 | deps = [ 63 | ":app-code", 64 | ], 65 | ) 66 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | import com.android.build.OutputFile 4 | 5 | /** 6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 7 | * and bundleReleaseJsAndAssets). 8 | * These basically call `react-native bundle` with the correct arguments during the Android build 9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 10 | * bundle directly from the development server. Below you can see all the possible configurations 11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 12 | * `apply from: "../../node_modules/react-native/react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation 19 | * entryFile: "index.android.js", 20 | * 21 | * // whether to bundle JS and assets in debug mode 22 | * bundleInDebug: false, 23 | * 24 | * // whether to bundle JS and assets in release mode 25 | * bundleInRelease: true, 26 | * 27 | * // whether to bundle JS and assets in another build variant (if configured). 28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 29 | * // The configuration property can be in the following formats 30 | * // 'bundleIn${productFlavor}${buildType}' 31 | * // 'bundleIn${buildType}' 32 | * // bundleInFreeDebug: true, 33 | * // bundleInPaidRelease: true, 34 | * // bundleInBeta: true, 35 | * 36 | * // the root of your project, i.e. where "package.json" lives 37 | * root: "../../", 38 | * 39 | * // where to put the JS bundle asset in debug mode 40 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 41 | * 42 | * // where to put the JS bundle asset in release mode 43 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 44 | * 45 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 46 | * // require('./image.png')), in debug mode 47 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 48 | * 49 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 50 | * // require('./image.png')), in release mode 51 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 52 | * 53 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 54 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 55 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 56 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 57 | * // for example, you might want to remove it from here. 58 | * inputExcludes: ["android/**", "ios/**"], 59 | * 60 | * // override which node gets called and with what additional arguments 61 | * nodeExecutableAndArgs: ["node"], 62 | * 63 | * // supply additional arguments to the packager 64 | * extraPackagerArgs: [] 65 | * ] 66 | */ 67 | 68 | apply from: "../../node_modules/react-native/react.gradle" 69 | 70 | /** 71 | * Set this to true to create two separate APKs instead of one: 72 | * - An APK that only works on ARM devices 73 | * - An APK that only works on x86 devices 74 | * The advantage is the size of the APK is reduced by about 4MB. 75 | * Upload all the APKs to the Play Store and people will download 76 | * the correct one based on the CPU architecture of their device. 77 | */ 78 | def enableSeparateBuildPerCPUArchitecture = false 79 | 80 | /** 81 | * Run Proguard to shrink the Java bytecode in release builds. 82 | */ 83 | def enableProguardInReleaseBuilds = false 84 | 85 | android { 86 | compileSdkVersion 23 87 | buildToolsVersion "23.0.1" 88 | 89 | defaultConfig { 90 | applicationId "com.rnayinstalment" 91 | minSdkVersion 16 92 | targetSdkVersion 22 93 | versionCode 1 94 | versionName "1.0" 95 | ndk { 96 | abiFilters "armeabi-v7a", "x86" 97 | } 98 | } 99 | splits { 100 | abi { 101 | reset() 102 | enable enableSeparateBuildPerCPUArchitecture 103 | universalApk false // If true, also generate a universal APK 104 | include "armeabi-v7a", "x86" 105 | } 106 | } 107 | buildTypes { 108 | release { 109 | minifyEnabled enableProguardInReleaseBuilds 110 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 111 | } 112 | } 113 | // applicationVariants are e.g. debug, release 114 | applicationVariants.all { variant -> 115 | variant.outputs.each { output -> 116 | // For each separate APK per architecture, set a unique version code as described here: 117 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits 118 | def versionCodes = ["armeabi-v7a":1, "x86":2] 119 | def abi = output.getFilter(OutputFile.ABI) 120 | if (abi != null) { // null for the universal-debug, universal-release variants 121 | output.versionCodeOverride = 122 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 123 | } 124 | } 125 | } 126 | } 127 | 128 | dependencies { 129 | compile project(':react-native-picker') 130 | compile fileTree(dir: "libs", include: ["*.jar"]) 131 | compile "com.android.support:appcompat-v7:23.0.1" 132 | compile "com.facebook.react:react-native:+" // From node_modules 133 | } 134 | 135 | // Run this once to be able to run the application with BUCK 136 | // puts all compile dependencies into folder libs for BUCK to use 137 | task copyDownloadableDepsToLibs(type: Copy) { 138 | from configurations.compile 139 | into 'libs' 140 | } 141 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Disabling obfuscation is useful if you collect stack traces from production crashes 20 | # (unless you are using a system that supports de-obfuscate the stack traces). 21 | -dontobfuscate 22 | 23 | # React Native 24 | 25 | # Keep our interfaces so they can be used by other ProGuard rules. 26 | # See http://sourceforge.net/p/proguard/bugs/466/ 27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip 28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters 29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip 30 | 31 | # Do not strip any method/class that is annotated with @DoNotStrip 32 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 33 | -keep @com.facebook.common.internal.DoNotStrip class * 34 | -keepclassmembers class * { 35 | @com.facebook.proguard.annotations.DoNotStrip *; 36 | @com.facebook.common.internal.DoNotStrip *; 37 | } 38 | 39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 40 | void set*(***); 41 | *** get*(); 42 | } 43 | 44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 46 | -keepclassmembers,includedescriptorclasses class * { native ; } 47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } 49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } 50 | 51 | -dontwarn com.facebook.react.** 52 | 53 | # TextLayoutBuilder uses a non-public Android constructor within StaticLayout. 54 | # See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. 55 | -dontwarn android.text.StaticLayout 56 | 57 | # okhttp 58 | 59 | -keepattributes Signature 60 | -keepattributes *Annotation* 61 | -keep class okhttp3.** { *; } 62 | -keep interface okhttp3.** { *; } 63 | -dontwarn okhttp3.** 64 | 65 | # okio 66 | 67 | -keep class sun.misc.Unsafe { *; } 68 | -dontwarn java.nio.file.* 69 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 70 | -dontwarn okio.** 71 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/rnayinstalment/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.rnayinstalment; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. 9 | * This is used to schedule rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "RNAYInstalment"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/rnayinstalment/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.rnayinstalment; 2 | 3 | import android.app.Application; 4 | 5 | import com.facebook.react.ReactApplication; 6 | import com.beefe.picker.PickerViewPackage; 7 | import com.facebook.react.ReactNativeHost; 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.shell.MainReactPackage; 10 | import com.facebook.soloader.SoLoader; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | public class MainApplication extends Application implements ReactApplication { 16 | 17 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 18 | @Override 19 | public boolean getUseDeveloperSupport() { 20 | return BuildConfig.DEBUG; 21 | } 22 | 23 | @Override 24 | protected List getPackages() { 25 | return Arrays.asList( 26 | new MainReactPackage(), 27 | new PickerViewPackage() 28 | ); 29 | } 30 | }; 31 | 32 | @Override 33 | public ReactNativeHost getReactNativeHost() { 34 | return mReactNativeHost; 35 | } 36 | 37 | @Override 38 | public void onCreate() { 39 | super.onCreate(); 40 | SoLoader.init(this, /* native exopackage */ false); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | RNAYInstalment 3 | 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.3' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | maven { 20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 21 | url "$rootDir/../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 6 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = "debug", 3 | properties = "debug.keystore.properties", 4 | store = "debug.keystore", 5 | visibility = [ 6 | "PUBLIC", 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'RNAYInstalment' 2 | include ':react-native-picker' 3 | project(':react-native-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-picker/android') 4 | 5 | include ':app' 6 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RNAYInstalment", 3 | "displayName": "RNAYInstalment" 4 | } -------------------------------------------------------------------------------- /app/App.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/28. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | StatusBar, 12 | NavigatorIOS 13 | } from 'react-native'; 14 | 15 | import LaunchView from './login/LaunchView' 16 | 17 | let that 18 | export default class App extends Component { 19 | 20 | constructor(props) { 21 | super(props) 22 | that = this 23 | this.state = { 24 | logined: false 25 | } 26 | } 27 | componentDidMount() { 28 | /** 29 | * 设置状态栏颜色 30 | */ 31 | 32 | } 33 | render() { 34 | return ( 35 | 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/apply/ApplyDetail.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/6/1. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | Dimensions, 12 | ScrollView 13 | } from 'react-native'; 14 | 15 | var ScrollableTabView = require('react-native-scrollable-tab-view') 16 | const {width,height} = Dimensions.get('window') 17 | import NavigationBar from '../common/NavBarCommon' 18 | import CommonCell from '../apply/ItemCell/CommonCell' 19 | import Spinner from 'react-native-loading-spinner-overlay' 20 | 21 | // 申请进度组件 22 | import StatusList from './ItemCell/StatusList' 23 | // 申请详情组件 24 | import ApplyDescList from './ItemCell/ApplyDescList' 25 | 26 | let config = require('../common/Config') 27 | let request = require('../common/Request') 28 | let someStore = require('../common/RNAsyncStorage') 29 | let storage = someStore.storage 30 | let loginData 31 | let that 32 | 33 | export default class ApplyDetail extends Component { 34 | constructor(props) { 35 | super(props) 36 | that = this 37 | this.state = { 38 | visible: false, 39 | data: '' 40 | } 41 | } 42 | componentDidMount() { 43 | console.log(this.props.route.params) 44 | this._loadStorageData() 45 | } 46 | /** 47 | * 读取本地化登录数据 48 | */ 49 | _loadStorageData() { 50 | storage.load({ 51 | key:'loginState', 52 | id: 1001 53 | }).then((data) => { 54 | loginData = data 55 | that._fetchData() 56 | }).catch((error) => { 57 | 58 | }) 59 | } 60 | /** 61 | * 请求网络数据 62 | */ 63 | _fetchData() { 64 | let accessToken = loginData.Token.authorization 65 | let worker = loginData.Token.worker 66 | let applyDetailURL = `${config.api.base}${config.api.applyForDetail}` 67 | var headers = { 68 | 'Content-Type': 'application/json', 69 | 'Authorization': accessToken, 70 | 'Worker': worker, 71 | 'ChannelId': '1000005', 72 | 'Hospital': '130670' 73 | } 74 | var params = { 75 | orderId: this.props.route.params.orderId 76 | } 77 | that._showHud(true) 78 | request.get(applyDetailURL,params,headers) 79 | .then((data) => { 80 | console.log('DetailData:',data) 81 | that.setState({data}) 82 | that._showHud(false) 83 | }) 84 | .catch((error) => { 85 | console.log(error) 86 | that._showHud(false) 87 | }) 88 | } 89 | render() { 90 | return ( 91 | 92 | this._popNav()}/> 96 | 98 | {/*头部组件*/} 99 | 100 | {this._renderHeadCell()} 101 | 102 | 103 | {/*滑动内容区组件*/} 104 | {this._renderContentView()} 105 | 106 | 111 | 112 | ); 113 | } 114 | /** 115 | * 头部组件 116 | */ 117 | _renderHeadCell() { 118 | return ( 119 | 123 | ) 124 | } 125 | /** 126 | * 滑动内容区 127 | */ 128 | _renderContentView() { 129 | return ( 130 | 138 | 141 | 144 | 145 | ) 146 | } 147 | /** 148 | * 导航返回 149 | */ 150 | _popNav(){ 151 | this.props.navigator.pop() 152 | } 153 | /** 154 | * 显示隐藏HUD 155 | */ 156 | _showHud(show) { 157 | this.setState({ 158 | visible: show 159 | }) 160 | } 161 | } 162 | 163 | const styles = StyleSheet.create({ 164 | container: { 165 | flex: 1, 166 | backgroundColor: '#f4f7fe', 167 | }, 168 | headViewStyle: { 169 | alignItems: 'flex-start', 170 | height:165, 171 | width: width 172 | }, 173 | contentStyle: { 174 | marginTop: 10 175 | } 176 | }); 177 | -------------------------------------------------------------------------------- /app/apply/ApplyFirst.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/29. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View 11 | } from 'react-native'; 12 | 13 | import NavigationBar from '../common/NavBarCommon' 14 | export default class ApplyFirst extends Component { 15 | render() { 16 | return ( 17 | 18 | this._popNav()}/> 22 | 23 | ); 24 | } 25 | /** 26 | * 导航返回 27 | */ 28 | _popNav(){ 29 | this.props.navigator.pop() 30 | } 31 | } 32 | 33 | const styles = StyleSheet.create({ 34 | container: { 35 | flex: 1, 36 | backgroundColor: '#f4f7fe' 37 | } 38 | }); 39 | -------------------------------------------------------------------------------- /app/apply/ApplyTab.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/28. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | Dimensions 12 | } from 'react-native'; 13 | 14 | 15 | import NavigationBar from '../common/NavBarCommon' 16 | import ApplyAllItem from './TabItems/ApplyAllItem' 17 | import ApplyingItem from './TabItems/ApplyingItem' 18 | import ApplyedItem from './TabItems/ApplyedItem' 19 | import ApplyFailedItem from './TabItems/ApplyFailedItem' 20 | 21 | var ScrollableTabView = require('react-native-scrollable-tab-view') 22 | 23 | let that 24 | export default class ApplyTab extends Component { 25 | constructor(props) { 26 | super(props) 27 | that = this 28 | this.state = { 29 | selectedTab: 0 30 | } 31 | } 32 | componentDidMount() { 33 | 34 | } 35 | render() { 36 | return ( 37 | 38 | 41 | 47 | 50 | 53 | 56 | 59 | 60 | 61 | ); 62 | } 63 | } 64 | 65 | const styles = StyleSheet.create({ 66 | container: { 67 | flex: 1, 68 | } 69 | }); 70 | -------------------------------------------------------------------------------- /app/apply/ItemCell/ApplyDescList.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/6/2. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | Dimensions, 12 | Image, 13 | Modal, 14 | TouchableOpacity 15 | } from 'react-native'; 16 | 17 | import ImageViewer from 'react-native-image-zoom-viewer' 18 | const {width,height} = Dimensions.get('window') 19 | var cols = 3 20 | var boxWidth = 100 21 | var vMargin = (width - cols * boxWidth) / (cols + 1) 22 | var hMargin = 15 23 | 24 | export default class ApplyDescList extends Component { 25 | constructor(props) { 26 | super(props) 27 | this.state = { 28 | dataArr: [], 29 | imagesArray: [], // 图片数组 30 | showImage: false, // 是否显示图片预览组件 31 | selectedIndex: 0 // 点击预览图片索引 32 | } 33 | } 34 | componentDidMount() { 35 | this._dealWithData(this.props.data) 36 | } 37 | render() { 38 | console.log(this.props.data) 39 | return ( 40 | 41 | {this._renderAllInfoItems()} 42 | {/*影像资料*/} 43 | { 44 | this.state.imagesArray.length > 0 45 | ? 46 | 47 | 医疗确认照 48 | 49 | 50 | {this._renderAllImageItems()} 51 | 52 | 53 | : null 54 | } 55 | {/*是否显示图片预览*/} 56 | { 57 | this.state.showImage 58 | ? 59 | { 63 | this.setState({ 64 | showImage: false 65 | }) 66 | }}/> 67 | : null 68 | } 69 | 70 | ); 71 | } 72 | /** 73 | * 创建总的infoItems 74 | */ 75 | _renderAllInfoItems() { 76 | var itemArr = [] 77 | var titleArr = ['申请信息','贷款信息','还款计划'] 78 | var dataArr = this.state.dataArr 79 | dataArr.forEach((item,idx) => { 80 | itemArr.push( 81 | 85 | ) 86 | }) 87 | return itemArr 88 | } 89 | /** 90 | * 图片九宫格布局 91 | */ 92 | _renderAllImageItems() { 93 | var allItems = [] 94 | var imagesArr = this.state.imagesArray 95 | imagesArr.forEach((item,idx) => { 96 | allItems.push( 97 | this._showImageViewer(idx)} key={idx}> 98 | 99 | 102 | 103 | 104 | ) 105 | }) 106 | return allItems 107 | } 108 | /** 109 | * 显示调用图片预览组件 110 | */ 111 | _showImageViewer(index) { 112 | this.setState({ 113 | selectedIndex: index, 114 | showImage: true 115 | }) 116 | } 117 | /** 118 | * 处理数据 119 | */ 120 | _dealWithData(data) { 121 | var dataArr = [] 122 | var applyTitles = [{ 123 | title: '申请人姓名', 124 | content: data.CustomerRealName 125 | },{ 126 | title: '申请人电话', 127 | content: data.Mobile 128 | },{ 129 | title: '与就诊人关系', 130 | content: data.PatientRelationName 131 | }] 132 | var loanTitles = [{ 133 | title: '就诊诊所', 134 | content: data.HospitalName 135 | },{ 136 | title: '申请产品', 137 | content: data.ProductName 138 | },{ 139 | title: '贷款金额', 140 | content: data.AmountTotal 141 | },{ 142 | title: '期数', 143 | content: `${data.InstalmentsNum}期` 144 | },{ 145 | title: '手续费', 146 | content: `${data.CustomerRebate}元` 147 | }] 148 | var applysArr = [] 149 | var loanArr = [] 150 | var plansArr = [] 151 | plansArr.push({ 152 | title: '期数', 153 | content: '还款金额(元)', 154 | desc: '最迟还款日' 155 | }) 156 | applyTitles.forEach((item,idx) => { 157 | applysArr.push({ 158 | title: item.title, 159 | content:item.content, 160 | desc: '' 161 | }) 162 | }) 163 | loanTitles.forEach((item,idx) => { 164 | loanArr.push({ 165 | title: item.title, 166 | content: item.content, 167 | desc: '' 168 | }) 169 | }) 170 | data.RefundPlanList.forEach((item,idx) => { 171 | plansArr.push({ 172 | title: idx + 1, 173 | content: `¥ ${item.Money}`, 174 | desc: item.Date.split('T')[0] 175 | }) 176 | }) 177 | dataArr.push(applysArr) 178 | dataArr.push(loanArr) 179 | dataArr.push(plansArr) 180 | /** 处理图片数组 */ 181 | var modelImages = data.Image 182 | var imagesArr = [] 183 | modelImages.forEach((item,idx) => { 184 | imagesArr.push({ 185 | url: item.ImgUrl 186 | }) 187 | }) 188 | this.setState({ 189 | dataArr: dataArr, 190 | imagesArray: imagesArr 191 | }) 192 | } 193 | } 194 | 195 | /** 196 | * 创建单个InfoItem 197 | */ 198 | class ItemDescView extends Component { 199 | render() { 200 | return ( 201 | 202 | 203 | {this.props.title} 204 | 205 | 206 | {this._renderItem()} 207 | 208 | 209 | ) 210 | } 211 | _renderItem() { 212 | var itemArr = [] 213 | var titleArr = this.props.data 214 | titleArr.forEach((item,idx) => { 215 | itemArr.push( 216 | 224 | {item.title} 225 | {item.content} 226 | {item.desc} 227 | 228 | ) 229 | }) 230 | return itemArr 231 | } 232 | } 233 | const styles = StyleSheet.create({ 234 | container: { 235 | flex: 1, 236 | backgroundColor: '#f4f7fe' 237 | }, 238 | itemDescContainer: { 239 | backgroundColor: '#fff', 240 | marginTop: 10 241 | }, 242 | itemTopContainer: { 243 | borderBottomWidth: 1, 244 | borderBottomColor: '#dbdbdb', 245 | paddingVertical: 10, 246 | paddingHorizontal: 15 247 | }, 248 | itemBottomContainer: { 249 | 250 | }, 251 | topTitleTextStyle: { 252 | fontSize: 15, 253 | color: '#666' 254 | }, 255 | itemContainer: { 256 | flexDirection: 'row', 257 | paddingHorizontal: 15, 258 | justifyContent: 'space-between', 259 | paddingVertical: 5 260 | }, 261 | infoTextStyle: { 262 | fontSize: 13, 263 | color: '#999', 264 | width: (width - 30) / 3, 265 | textAlign: 'center' 266 | }, 267 | autoViewStyle: { 268 | backgroundColor: '#999', 269 | alignItems: 'center', 270 | width: boxWidth, 271 | height: boxWidth, 272 | marginLeft: vMargin, 273 | marginTop: hMargin 274 | }, 275 | imageStyle: { 276 | width: boxWidth, 277 | height: boxWidth, 278 | resizeMode: 'cover' 279 | }, 280 | bottomContainerStyle: { 281 | backgroundColor: '#fff', 282 | marginVertical: 10 283 | }, 284 | bottomTopStyle: { 285 | borderBottomWidth: 1, 286 | borderBottomColor: '#dbdbdb' 287 | }, 288 | bottomImageItemStyle: { 289 | backgroundColor: '#f4f7fe', 290 | flexDirection: 'row', 291 | flexWrap: 'wrap' 292 | }, 293 | itemTextStyle: { 294 | fontSize: 16, 295 | color: '#666', 296 | paddingVertical: 10, 297 | paddingLeft: 15 298 | } 299 | }); 300 | -------------------------------------------------------------------------------- /app/apply/ItemCell/CommonCell.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/6/1. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | Image, 12 | TouchableOpacity 13 | } from 'react-native'; 14 | 15 | let that 16 | export default class CommonCell extends Component { 17 | constructor(props) { 18 | super(props) 19 | that = this 20 | } 21 | /** 22 | * itemCell点击回调函数 23 | */ 24 | _clickCallBack(orderId) { 25 | var rowData = this.props.rowData 26 | if (this.props.clickItemCallBack == null) return 27 | this.props.clickItemCallBack(orderId,rowData) 28 | } 29 | render() { 30 | var rowData = this.props.rowData.value 31 | return ( 32 | this._clickCallBack(rowData.OrderId)}> 33 | 34 | 35 | 36 | 39 | {rowData.ProductName} 40 | 41 | {this._fetchStateNameWithState(rowData.Status)} 44 | 45 | 46 | 47 | {this._renderItemView(this._dealItemData(rowData))} 48 | 49 | {rowData.StepsName} 50 | 51 | 52 | 53 | ); 54 | } 55 | /** 56 | * 渲染单个tips 57 | */ 58 | _renderItemView(itemList) { 59 | var itemArr = [] 60 | itemList.forEach((item,idx) => { 61 | itemArr.push( 62 | 65 | {item.title} 66 | {item.content} 67 | 68 | ) 69 | }) 70 | return itemArr 71 | } 72 | /** 73 | * 处理单个tips数据 74 | **/ 75 | _dealItemData(rowData) { 76 | var titleArr = ['贷款金额:','申请人:','申请日期:','申请单号:'] 77 | var payAmount = `¥ ${rowData.AmountApp} ${rowData.InstalmentsNum}期` 78 | var applyName = rowData.CustomerRealName 79 | var applyDate = rowData.AddTime.split('T')[0] 80 | var orderNum = rowData.OrderNo 81 | var contentArr = [payAmount,applyName,applyDate,orderNum] 82 | var itemArr = [] 83 | titleArr.forEach((item,idx) => { 84 | itemArr.push({ 85 | title: item, 86 | content:contentArr[idx] 87 | }) 88 | }) 89 | return itemArr 90 | } 91 | /** 92 | * 关联订单状态文字 93 | */ 94 | _fetchStateNameWithState(state) { 95 | switch (state) { 96 | case 1: 97 | return '申请中' 98 | break; 99 | case 2: 100 | return '已通过' 101 | break; 102 | case 3: 103 | return '未通过' 104 | break; 105 | case 1024: 106 | return '已过期' 107 | break; 108 | default: 109 | return '' 110 | } 111 | } 112 | } 113 | 114 | const styles = StyleSheet.create({ 115 | container: { 116 | flex: 1, 117 | backgroundColor: '#fff', 118 | }, 119 | topViewStyle: { 120 | flexDirection: 'row', 121 | paddingHorizontal: 15, 122 | paddingVertical: 10, 123 | borderBottomWidth: 1, 124 | borderBottomColor: '#dbdbdb', 125 | justifyContent: 'space-between' 126 | }, 127 | bottomViewStyle: { 128 | flexDirection: 'row', 129 | justifyContent: 'space-between' 130 | }, 131 | topLeftView: { 132 | flexDirection: 'row', 133 | justifyContent: 'center', 134 | alignItems: 'center' 135 | }, 136 | iconStyle: { 137 | width: 30, 138 | height: 30 139 | }, 140 | titleTextStyle: { 141 | marginLeft: 10, 142 | fontSize: 16 143 | }, 144 | stateTextStyle: { 145 | fontSize: 16, 146 | color: '#666', 147 | justifyContent: 'center', 148 | alignSelf: 'center' 149 | }, 150 | bottomLeftView: { 151 | paddingVertical: 5, 152 | paddingHorizontal: 15 153 | }, 154 | itemViewStyle: { 155 | flexDirection: 'row', 156 | paddingVertical: 5 157 | }, 158 | stateDescTextStyle: { 159 | width: 70, 160 | flexWrap: 'wrap', 161 | fontSize: 14, 162 | color: '#666', 163 | alignSelf: 'center' 164 | } 165 | }); 166 | -------------------------------------------------------------------------------- /app/apply/ItemCell/StatusList.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/6/2. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | FlatList 12 | } from 'react-native'; 13 | 14 | let that 15 | export default class StatusList extends Component { 16 | constructor(props) { 17 | super(props) 18 | that = this 19 | } 20 | render() { 21 | return ( 22 | 23 | 27 | 28 | ); 29 | } 30 | 31 | _keyExtractor = (item,index) => index 32 | 33 | _renderItem = (item) => { 34 | var itemData = item.item 35 | var itemIndex = item.index 36 | var totalLength = that.props.data.length 37 | console.log(itemIndex) 38 | return ( 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | {itemData.Title} 47 | {itemData.Content} 48 | 49 | 50 | ) 51 | } 52 | } 53 | 54 | const styles = StyleSheet.create({ 55 | container: { 56 | flex: 1, 57 | backgroundColor: '#f4f7fe' 58 | }, 59 | itemContainerStyle: { 60 | backgroundColor: '#fff', 61 | flexDirection: 'row', 62 | paddingHorizontal: 15, 63 | 64 | alignItems:'center', 65 | }, 66 | leftViewStyle: { 67 | justifyContent: 'center', 68 | alignItems: 'center' 69 | }, 70 | verTopLineStyle: { 71 | width: 1, 72 | backgroundColor:'#7080fa', 73 | height: 15, 74 | marginBottom: 5 75 | }, 76 | verBottomLineStyle: { 77 | width: 1, 78 | marginTop: 5, 79 | backgroundColor:'#7080fa', 80 | height: 15, 81 | }, 82 | iconTextStyle: { 83 | fontFamily:'iconfont', 84 | fontSize: 20, 85 | color: '#7080fa' 86 | }, 87 | rightViewStyle: { 88 | marginLeft: 15 89 | }, 90 | titleTextStyle: { 91 | fontSize: 18, 92 | color: '#333' 93 | }, 94 | descTextStyle: { 95 | fontSize: 13, 96 | color: '#999', 97 | marginTop: 10 98 | } 99 | 100 | }); 101 | -------------------------------------------------------------------------------- /app/apply/TabItems/ApplyAllItem.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/31. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | FlatList, 12 | ActivityIndicator, 13 | VirtualizedList, 14 | TouchableOpacity 15 | } from 'react-native'; 16 | 17 | import Commoncell from '../ItemCell/CommonCell' 18 | import LoadMoreFooter from '../../common/LoadMoreFooter' 19 | import ApplyDetail from '../ApplyDetail' 20 | 21 | let config = require('../../common/Config') 22 | let request = require('../../common/Request') 23 | let someStore = require('../../common/RNAsyncStorage') 24 | let storage = someStore.storage 25 | let that 26 | /**数据缓冲池*/ 27 | let cachedResult = { 28 | defaultSize: 20, 29 | nextPage: 2, 30 | items: [], // 原始数据 31 | totalPages: 1, 32 | totalItems: 0, 33 | blobItems:[] // 添加key之后的数据 34 | } 35 | /**读取本地token*/ 36 | let loginData 37 | export default class ApplyAllItem extends Component { 38 | 39 | constructor(props) { 40 | super(props) 41 | that = this 42 | this.state = { 43 | totalList: [], // 数据源 44 | isLoadingTail: false, // 是否显示加载更多 45 | isRefreshing: false, // 是否显示下拉刷新 46 | } 47 | } 48 | /** 49 | * 通知组件本身重新渲染 50 | */ 51 | componentWillReceiveProps() { 52 | this._onRefresh() 53 | } 54 | componentDidMount() { 55 | this._loadStorageData() 56 | } 57 | /** 58 | * 下拉刷新 59 | */ 60 | _onRefresh() { 61 | if (!that._hasMore || that.state.isRefreshing) { 62 | return 63 | } 64 | let timer = setTimeout(() => { 65 | clearTimeout(timer) 66 | // 重置nextPage 67 | cachedResult.nextPage = 2 68 | that._fetchData(1) 69 | },1500) 70 | } 71 | /** 72 | * 上拉加载 73 | */ 74 | _fetchMoreData() { 75 | if (!that._hasMore|| that.state.isLoadingTail) { 76 | return 77 | } 78 | var page = cachedResult.nextPage 79 | that._fetchData(page) 80 | } 81 | /** 82 | * 是否有更多数据 83 | */ 84 | _hasMore(){ 85 | return cachedResult.items.length !== cachedResult.totalItems 86 | } 87 | /** 88 | * 加载网络数据 89 | */ 90 | _fetchData(page) { 91 | let accessToken = loginData.Token.authorization 92 | let worker = loginData.Token.worker 93 | let applyListURL = `${config.api.base}${config.api.applyForList}` 94 | var headers = { 95 | 'Content-Type': 'application/json', 96 | 'Authorization': accessToken, 97 | 'Worker': worker, 98 | 'ChannelId': '1000005', 99 | 'Hospital': '130670' 100 | } 101 | var params = { 102 | pageSize: cachedResult.defaultSize, 103 | pageIndex: page, 104 | status: 0 105 | } 106 | if (page !== 1) { 107 | that.setState({ 108 | isLoadingTail: true 109 | }) 110 | } else { 111 | that.setState({ 112 | isRefreshing: true 113 | }) 114 | } 115 | request.get(applyListURL,params,headers) 116 | .then((data) => { 117 | console.log(data) 118 | var items = cachedResult.items.slice() 119 | if (page !== 1) { 120 | items = data.Items.concat(items) 121 | cachedResult.nextPage ++ 122 | } else { 123 | items = data.Items 124 | } 125 | var dataBlob = [] 126 | items.map((item,idx) => { 127 | dataBlob.push({ 128 | key: idx, 129 | value: item 130 | }) 131 | }) 132 | cachedResult.items = items 133 | cachedResult.blobItems = dataBlob 134 | cachedResult.totalPages = data.TotalPages 135 | cachedResult.totalItems = data.TotalItems 136 | console.log(dataBlob) 137 | if (page !== 1) { 138 | that.setState({ 139 | totalList:cachedResult.blobItems, 140 | isLoadingTail: false 141 | }) 142 | } else { 143 | that.setState({ 144 | totalList: cachedResult.blobItems, 145 | isRefreshing: false 146 | }) 147 | } 148 | }) 149 | .catch((error) => { 150 | console.log(error) 151 | if (page !== 1) { 152 | that.setState({isLoadingTail: false}) 153 | } else { 154 | that.setState({isRefreshing: false}) 155 | } 156 | }) 157 | } 158 | /** 159 | * 读取本地化登录数据 160 | */ 161 | _loadStorageData() { 162 | storage.load({ 163 | key:'loginState', 164 | id: 1001 165 | }).then((data) => { 166 | loginData = data 167 | that._fetchData(1) 168 | }).catch((error) => { 169 | console.log(error) 170 | }) 171 | } 172 | /** 173 | * 跳转分期详情页面 174 | */ 175 | _pushNav(orderId,rowData) { 176 | this.props.navigator.push({ 177 | component: ApplyDetail, 178 | title:'', 179 | params: { 180 | orderId:orderId, 181 | rowData: rowData 182 | } 183 | }) 184 | } 185 | render() { 186 | return ( 187 | 188 | 200 | 201 | 202 | ); 203 | } 204 | /** 205 | * 指定刷新位置,减少重新渲染开销 206 | */ 207 | _keyExtractor = (item,index) => index 208 | /** 209 | * 单个Cell组件 210 | */ 211 | _renderItem = ({item}) => { 212 | return ( 213 | this._pushNav(orderId,rowData)}/> 216 | ) 217 | } 218 | /** 219 | * 行内分割线 220 | */ 221 | _itemSeparatorComponent() { 222 | return ( 223 | 224 | ) 225 | } 226 | /** 227 | * 底部加载更多提示 228 | */ 229 | _renderFooter() { 230 | if (!that._hasMore && cachedResult.totalItems !== 0) { 231 | return ( 232 | 233 | 没有更多了 234 | 235 | ) 236 | } 237 | if (that.state.isRefreshing) { 238 | return 240 | } 241 | if (that.state.isLoadingTail) { 242 | return 244 | } 245 | return 246 | } 247 | } 248 | 249 | const styles = StyleSheet.create({ 250 | container: { 251 | flex: 1, 252 | backgroundColor: '#f4f7fe', 253 | }, 254 | loadingMore: { 255 | marginVertical: 20, 256 | backgroundColor: '#333' 257 | }, 258 | loadingText: { 259 | color: '#777', 260 | textAlign:'center' 261 | } 262 | }); 263 | -------------------------------------------------------------------------------- /app/apply/TabItems/ApplyFailedItem.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/31. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | FlatList, 12 | ActivityIndicator, 13 | VirtualizedList 14 | } from 'react-native'; 15 | 16 | import Commoncell from '../ItemCell/CommonCell' 17 | import LoadMoreFooter from '../../common/LoadMoreFooter' 18 | import ListEmptyView from '../../common/CommonListEmpty' 19 | import ApplyDetail from '../ApplyDetail' 20 | 21 | let config = require('../../common/Config') 22 | let request = require('../../common/Request') 23 | let someStore = require('../../common/RNAsyncStorage') 24 | let storage = someStore.storage 25 | let that 26 | /**数据缓冲池*/ 27 | let cachedResult = { 28 | defaultSize: 20, 29 | nextPage: 2, 30 | items: [], // 原始数据 31 | totalPages: 1, 32 | totalItems: 0, 33 | blobItems:[] // 添加key之后的数据 34 | } 35 | /**读取本地token*/ 36 | let loginData 37 | 38 | export default class ApplyFailedItem extends Component { 39 | constructor(props) { 40 | super(props) 41 | that = this 42 | this.state = { 43 | totalList: [], // 数据源 44 | isLoadingTail: false, // 是否显示加载更多 45 | isRefreshing: false, // 是否显示下拉刷新 46 | } 47 | } 48 | /** 49 | * 通知组件本身重新渲染 50 | */ 51 | componentWillReceiveProps() { 52 | this._onRefresh() 53 | } 54 | componentDidMount() { 55 | this._loadStorageData() 56 | } 57 | /** 58 | * 下拉刷新 59 | */ 60 | _onRefresh() { 61 | if (!that._hasMore || that.state.isRefreshing) { 62 | return 63 | } 64 | let timer = setTimeout(() => { 65 | clearTimeout(timer) 66 | // 重置nextPage 67 | cachedResult.nextPage = 2 68 | that._fetchData(1) 69 | },1500) 70 | } 71 | /** 72 | * 上拉加载 73 | */ 74 | _fetchMoreData() { 75 | if (!that._hasMore|| that.state.isLoadingTail) { 76 | return 77 | } 78 | var page = cachedResult.nextPage 79 | that._fetchData(page) 80 | } 81 | /** 82 | * 是否有更多数据 83 | */ 84 | _hasMore(){ 85 | return cachedResult.items.length !== cachedResult.totalItems 86 | }/** 87 | * 加载网络数据 88 | */ 89 | _fetchData(page) { 90 | let accessToken = loginData.Token.authorization 91 | let worker = loginData.Token.worker 92 | let applyListURL = `${config.api.base}${config.api.applyForList}` 93 | var headers = { 94 | 'Content-Type': 'application/json', 95 | 'Authorization': accessToken, 96 | 'Worker': worker, 97 | 'ChannelId': '1000005', 98 | 'Hospital': '130670' 99 | } 100 | var params = { 101 | pageSize: cachedResult.defaultSize, 102 | pageIndex: page, 103 | status: 3 104 | } 105 | if (page !== 1) { 106 | that.setState({ 107 | isLoadingTail: true 108 | }) 109 | } else { 110 | that.setState({ 111 | isRefreshing: true 112 | }) 113 | } 114 | request.get(applyListURL,params,headers) 115 | .then((data) => { 116 | console.log(data) 117 | var items = cachedResult.items.slice() 118 | if (page !== 1) { 119 | items = data.Items.concat(items) 120 | cachedResult.nextPage ++ 121 | } else { 122 | items = data.Items 123 | } 124 | var dataBlob = [] 125 | items.map((item,idx) => { 126 | dataBlob.push({ 127 | key: idx, 128 | value: item 129 | }) 130 | }) 131 | cachedResult.items = items 132 | cachedResult.blobItems = dataBlob 133 | cachedResult.totalPages = data.TotalPages 134 | cachedResult.totalItems = data.TotalItems 135 | console.log(dataBlob) 136 | if (page !== 1) { 137 | that.setState({ 138 | totalList:cachedResult.blobItems, 139 | isLoadingTail: false 140 | }) 141 | } else { 142 | that.setState({ 143 | totalList: cachedResult.blobItems, 144 | isRefreshing: false 145 | }) 146 | } 147 | }) 148 | .catch((error) => { 149 | console.log(error) 150 | if (page !== 1) { 151 | that.setState({isLoadingTail: false}) 152 | } else { 153 | that.setState({isRefreshing: false}) 154 | } 155 | }) 156 | }/** 157 | * 读取本地化登录数据 158 | */ 159 | _loadStorageData() { 160 | storage.load({ 161 | key:'loginState', 162 | id: 1001 163 | }).then((data) => { 164 | loginData = data 165 | that._fetchData(1) 166 | }).catch((error) => { 167 | 168 | }) 169 | } 170 | /** 171 | * 跳转分期详情页面 172 | */ 173 | _pushNav(orderId,rowData) { 174 | this.props.navigator.push({ 175 | component: ApplyDetail, 176 | title:'', 177 | params: { 178 | orderId:orderId, 179 | rowData: rowData 180 | } 181 | }) 182 | } 183 | render() { 184 | return ( 185 | 186 | 199 | 200 | 201 | ); 202 | } 203 | /** 204 | * 指定刷新位置,减少重新渲染开销 205 | */ 206 | _keyExtractor = (item,index) => item.key 207 | /** 208 | * 单个Cell组件 209 | */ 210 | _renderItem = ({item}) => { 211 | return ( 212 | this._pushNav(orderId,rowData)}/> 215 | ) 216 | } 217 | /** 218 | * 行内分割线 219 | */ 220 | _itemSeparatorComponent() { 221 | return ( 222 | 223 | ) 224 | } 225 | /** 226 | * 列表数据为空时占位显示 227 | */ 228 | _renderEmptyComponent() { 229 | return 230 | } 231 | /** 232 | * 底部加载更多提示 233 | */ 234 | _renderFooter() { 235 | if (!that._hasMore && cachedResult.totalItems !== 0) { 236 | return ( 237 | 238 | 没有更多了 239 | 240 | ) 241 | } 242 | if (that.state.isRefreshing) { 243 | return 245 | } 246 | if (that.state.isLoadingTail) { 247 | return 249 | } 250 | return 251 | } 252 | } 253 | 254 | const styles = StyleSheet.create({ 255 | container: { 256 | flex: 1, 257 | backgroundColor: '#f4f7fe', 258 | }, 259 | loadingMore: { 260 | marginVertical: 20, 261 | backgroundColor: '#333' 262 | }, 263 | loadingText: { 264 | color: '#777', 265 | textAlign:'center' 266 | } 267 | }); -------------------------------------------------------------------------------- /app/apply/TabItems/ApplyedItem.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/31. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | FlatList, 12 | ActivityIndicator, 13 | VirtualizedList 14 | } from 'react-native'; 15 | 16 | import Commoncell from '../ItemCell/CommonCell' 17 | import LoadMoreFooter from '../../common/LoadMoreFooter' 18 | import ApplyDetail from '../ApplyDetail' 19 | 20 | let config = require('../../common/Config') 21 | let request = require('../../common/Request') 22 | let someStore = require('../../common/RNAsyncStorage') 23 | let storage = someStore.storage 24 | let that 25 | /**数据缓冲池*/ 26 | let cachedResult = { 27 | defaultSize: 20, 28 | nextPage: 2, 29 | items: [], // 原始数据 30 | totalPages: 1, 31 | totalItems: 0, 32 | blobItems:[] // 添加key之后的数据 33 | } 34 | /**读取本地token*/ 35 | let loginData 36 | 37 | export default class ApplyedItem extends Component { 38 | constructor(props) { 39 | super(props) 40 | that = this 41 | this.state = { 42 | totalList: [], // 数据源 43 | isLoadingTail: false, // 是否显示加载更多 44 | isRefreshing: false, // 是否显示下拉刷新 45 | } 46 | } 47 | /** 48 | * 通知组件本身重新渲染 49 | */ 50 | componentWillReceiveProps() { 51 | this._onRefresh() 52 | } 53 | componentDidMount() { 54 | this._loadStorageData() 55 | } 56 | /** 57 | * 下拉刷新 58 | */ 59 | _onRefresh() { 60 | if (!that._hasMore || that.state.isRefreshing) { 61 | return 62 | } 63 | let timer = setTimeout(() => { 64 | clearTimeout(timer) 65 | // 重置nextPage 66 | cachedResult.nextPage = 2 67 | that._fetchData(1) 68 | },1500) 69 | } 70 | /** 71 | * 上拉加载 72 | */ 73 | _fetchMoreData() { 74 | if (!that._hasMore|| that.state.isLoadingTail) { 75 | return 76 | } 77 | var page = cachedResult.nextPage 78 | that._fetchData(page) 79 | } 80 | /** 81 | * 是否有更多数据 82 | */ 83 | _hasMore(){ 84 | return cachedResult.items.length !== cachedResult.totalItems 85 | }/** 86 | * 加载网络数据 87 | */ 88 | _fetchData(page) { 89 | let accessToken = loginData.Token.authorization 90 | let worker = loginData.Token.worker 91 | let applyListURL = `${config.api.base}${config.api.applyForList}` 92 | var headers = { 93 | 'Content-Type': 'application/json', 94 | 'Authorization': accessToken, 95 | 'Worker': worker, 96 | 'ChannelId': '1000005', 97 | 'Hospital': '130670' 98 | } 99 | var params = { 100 | pageSize: cachedResult.defaultSize, 101 | pageIndex: page, 102 | status: 2 103 | } 104 | if (page !== 1) { 105 | that.setState({ 106 | isLoadingTail: true 107 | }) 108 | } else { 109 | that.setState({ 110 | isRefreshing: true 111 | }) 112 | } 113 | request.get(applyListURL,params,headers) 114 | .then((data) => { 115 | console.log(data) 116 | var items = cachedResult.items.slice() 117 | if (page !== 1) { 118 | items = data.Items.concat(items) 119 | cachedResult.nextPage ++ 120 | } else { 121 | items = data.Items 122 | } 123 | var dataBlob = [] 124 | items.map((item,idx) => { 125 | dataBlob.push({ 126 | key: idx, 127 | value: item 128 | }) 129 | }) 130 | cachedResult.items = items 131 | cachedResult.blobItems = dataBlob 132 | cachedResult.totalPages = data.TotalPages 133 | cachedResult.totalItems = data.TotalItems 134 | console.log(dataBlob) 135 | if (page !== 1) { 136 | that.setState({ 137 | totalList:cachedResult.blobItems, 138 | isLoadingTail: false 139 | }) 140 | } else { 141 | that.setState({ 142 | totalList: cachedResult.blobItems, 143 | isRefreshing: false 144 | }) 145 | } 146 | }) 147 | .catch((error) => { 148 | console.log(error) 149 | if (page !== 1) { 150 | that.setState({isLoadingTail: false}) 151 | } else { 152 | that.setState({isRefreshing: false}) 153 | } 154 | }) 155 | }/** 156 | * 读取本地化登录数据 157 | */ 158 | _loadStorageData() { 159 | storage.load({ 160 | key:'loginState', 161 | id: 1001 162 | }).then((data) => { 163 | loginData = data 164 | that._fetchData(1) 165 | }).catch((error) => { 166 | 167 | }) 168 | } 169 | /** 170 | * 跳转分期详情页面 171 | */ 172 | _pushNav(orderId,rowData) { 173 | this.props.navigator.push({ 174 | component: ApplyDetail, 175 | title:'', 176 | params: { 177 | orderId:orderId, 178 | rowData: rowData 179 | } 180 | }) 181 | } 182 | render() { 183 | return ( 184 | 185 | 197 | 198 | 199 | ); 200 | } 201 | /** 202 | * 指定刷新位置,减少重新渲染开销 203 | */ 204 | _keyExtractor = (item,index) => item.key 205 | /** 206 | * 单个Cell组件 207 | */ 208 | _renderItem = ({item}) => { 209 | return ( 210 | this._pushNav(orderId,rowData)}/> 213 | ) 214 | } 215 | /** 216 | * 行内分割线 217 | */ 218 | _itemSeparatorComponent() { 219 | return ( 220 | 221 | ) 222 | } 223 | /** 224 | * 底部加载更多提示 225 | */ 226 | _renderFooter() { 227 | if (!that._hasMore && cachedResult.totalItems !== 0) { 228 | return ( 229 | 230 | 没有更多了 231 | 232 | ) 233 | } 234 | if (that.state.isRefreshing) { 235 | return 237 | } 238 | if (that.state.isLoadingTail) { 239 | return 241 | } 242 | return 243 | } 244 | } 245 | 246 | const styles = StyleSheet.create({ 247 | container: { 248 | flex: 1, 249 | backgroundColor: '#f4f7fe', 250 | }, 251 | loadingMore: { 252 | marginVertical: 20, 253 | backgroundColor: '#333' 254 | }, 255 | loadingText: { 256 | color: '#777', 257 | textAlign:'center' 258 | } 259 | }); 260 | -------------------------------------------------------------------------------- /app/apply/TabItems/ApplyingItem.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/31. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | FlatList, 12 | ActivityIndicator, 13 | VirtualizedList 14 | } from 'react-native'; 15 | 16 | import Commoncell from '../ItemCell/CommonCell' 17 | import LoadMoreFooter from '../../common/LoadMoreFooter' 18 | import ListEmptyView from '../../common/CommonListEmpty' 19 | import ApplyDetail from '../ApplyDetail' 20 | 21 | let config = require('../../common/Config') 22 | let request = require('../../common/Request') 23 | let someStore = require('../../common/RNAsyncStorage') 24 | let storage = someStore.storage 25 | let that 26 | /**数据缓冲池*/ 27 | let cachedResult = { 28 | defaultSize: 20, 29 | nextPage: 2, 30 | items: [], // 原始数据 31 | totalPages: 1, 32 | totalItems: 0, 33 | blobItems:[] // 添加key之后的数据 34 | } 35 | /**读取本地token*/ 36 | let loginData 37 | 38 | export default class ApplyingItem extends Component { 39 | constructor(props) { 40 | super(props) 41 | that = this 42 | this.state = { 43 | totalList: [], // 数据源 44 | isLoadingTail: false, // 是否显示加载更多 45 | isRefreshing: false, // 是否显示下拉刷新 46 | } 47 | } 48 | /** 49 | * 通知组件本身重新渲染 50 | */ 51 | componentWillReceiveProps() { 52 | this._onRefresh() 53 | } 54 | componentDidMount() { 55 | this._loadStorageData() 56 | } 57 | /** 58 | * 下拉刷新 59 | */ 60 | _onRefresh() { 61 | if (!that._hasMore || that.state.isRefreshing) { 62 | return 63 | } 64 | let timer = setTimeout(() => { 65 | clearTimeout(timer) 66 | // 重置nextPage 67 | cachedResult.nextPage = 2 68 | that._fetchData(1) 69 | },1500) 70 | } 71 | /** 72 | * 上拉加载 73 | */ 74 | _fetchMoreData() { 75 | 76 | if (!that._hasMore|| that.state.isLoadingTail) { 77 | return 78 | } 79 | var page = cachedResult.nextPage 80 | that._fetchData(page) 81 | } 82 | /** 83 | * 是否有更多数据 84 | */ 85 | _hasMore(){ 86 | return cachedResult.items.length !== cachedResult.totalItems 87 | }/** 88 | * 加载网络数据 89 | */ 90 | _fetchData(page) { 91 | let accessToken = loginData.Token.authorization 92 | let worker = loginData.Token.worker 93 | let applyListURL = `${config.api.base}${config.api.applyForList}` 94 | var headers = { 95 | 'Content-Type': 'application/json', 96 | 'Authorization': accessToken, 97 | 'Worker': worker, 98 | 'ChannelId': '1000005', 99 | 'Hospital': '130670' 100 | } 101 | var params = { 102 | pageSize: cachedResult.defaultSize, 103 | pageIndex: page, 104 | status: 1 105 | } 106 | if (page !== 1) { 107 | that.setState({ 108 | isLoadingTail: true 109 | }) 110 | } else { 111 | that.setState({ 112 | isRefreshing: true 113 | }) 114 | } 115 | request.get(applyListURL,params,headers) 116 | .then((data) => { 117 | console.log(data) 118 | var items = cachedResult.items.slice() 119 | if (page !== 1) { 120 | items = data.Items.concat(items) 121 | cachedResult.nextPage ++ 122 | } else { 123 | items = data.Items 124 | } 125 | var dataBlob = [] 126 | items.map((item,idx) => { 127 | dataBlob.push({ 128 | key: idx, 129 | value: item 130 | }) 131 | }) 132 | cachedResult.items = items 133 | cachedResult.blobItems = dataBlob 134 | cachedResult.totalPages = data.TotalPages 135 | cachedResult.totalItems = data.TotalItems 136 | console.log(dataBlob) 137 | if (page !== 1) { 138 | that.setState({ 139 | totalList:cachedResult.blobItems, 140 | isLoadingTail: false, 141 | }) 142 | } else { 143 | that.setState({ 144 | totalList: cachedResult.blobItems, 145 | isRefreshing: false, 146 | }) 147 | } 148 | }) 149 | .catch((error) => { 150 | console.log(error) 151 | if (page !== 1) { 152 | that.setState({isLoadingTail: false}) 153 | } else { 154 | that.setState({isRefreshing: false}) 155 | } 156 | }) 157 | }/** 158 | * 读取本地化登录数据 159 | */ 160 | _loadStorageData() { 161 | storage.load({ 162 | key:'loginState', 163 | id: 1001 164 | }).then((data) => { 165 | loginData = data 166 | that._fetchData(1) 167 | }).catch((error) => { 168 | 169 | }) 170 | } 171 | /** 172 | * 跳转分期详情页面 173 | */ 174 | _pushNav(orderId,rowData) { 175 | this.props.navigator.push({ 176 | component: ApplyDetail, 177 | title:'', 178 | params: { 179 | orderId:orderId, 180 | rowData: rowData 181 | } 182 | }) 183 | } 184 | render() { 185 | return ( 186 | 187 | ( 200 | !that.state.totalList.length? 201 | 202 | : null)} 203 | > 204 | 205 | 206 | ); 207 | } 208 | /** 209 | * 指定刷新位置,减少重新渲染开销 210 | */ 211 | _keyExtractor = (item,index) => item.key 212 | /** 213 | * 单个Cell组件 214 | */ 215 | _renderItem = ({item}) => { 216 | return ( 217 | this._pushNav(orderId,rowData)}/> 220 | ) 221 | } 222 | /** 223 | * 行内分割线 224 | */ 225 | _itemSeparatorComponent() { 226 | return ( 227 | 228 | ) 229 | } 230 | /** 231 | * 列表数据为空时占位显示 232 | */ 233 | _renderEmptyComponent = ({item}) => { 234 | console.log('sss') 235 | return 236 | } 237 | /** 238 | * 底部加载更多提示 239 | */ 240 | _renderFooter() { 241 | if (!that._hasMore && cachedResult.totalItems !== 0) { 242 | return ( 243 | 244 | 没有更多了 245 | 246 | ) 247 | } 248 | if (that.state.isRefreshing) { 249 | return 251 | } 252 | if (that.state.isLoadingTail) { 253 | return 255 | } 256 | return 257 | } 258 | } 259 | 260 | const styles = StyleSheet.create({ 261 | container: { 262 | flex: 1, 263 | backgroundColor: '#f4f7fe', 264 | }, 265 | loadingMore: { 266 | marginVertical: 20, 267 | backgroundColor: '#333' 268 | }, 269 | loadingText: { 270 | color: '#777', 271 | textAlign:'center' 272 | } 273 | }); -------------------------------------------------------------------------------- /app/common/Common.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/6/5. 3 | */ 4 | 5 | 6 | import React, { Component } from 'react'; 7 | import { 8 | AppRegistry, 9 | StyleSheet, 10 | Text, 11 | View, 12 | Dimensions 13 | } from 'react-native'; 14 | 15 | 16 | module.exports = { 17 | screenW: Dimensions.get('window').width, 18 | screenH: Dimensions.get('window').height 19 | } -------------------------------------------------------------------------------- /app/common/CommonListEmpty.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/6/1. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | Image, 12 | Dimensions 13 | } from 'react-native'; 14 | 15 | const {width,height} = Dimensions.get('window') 16 | export default class CommonListEmpty extends Component { 17 | render() { 18 | return ( 19 | 20 | 24 | 暂无记录 25 | 26 | ); 27 | } 28 | } 29 | 30 | const styles = StyleSheet.create({ 31 | container: { 32 | backgroundColor: '#fff', 33 | justifyContent: 'center', 34 | alignItems: 'center', 35 | height: height - 49 -64 - 40 36 | }, 37 | emptyIconStyle: { 38 | width: 180, 39 | height: 130, 40 | resizeMode: 'contain' 41 | }, 42 | infoTextStyle: { 43 | fontSize: 16, 44 | color: '#999', 45 | marginTop: 30, 46 | textAlign: 'center' 47 | } 48 | 49 | }); 50 | -------------------------------------------------------------------------------- /app/common/Config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/28. 3 | */ 4 | 5 | module.exports = { 6 | header: { 7 | method: 'POST', 8 | headers: { 9 | 'Accept': 'application/json', 10 | 'Content-Type': 'application/json' 11 | } 12 | }, 13 | api: { 14 | base: 'http://clinicapi.qiezzitest.info/', 15 | login: 'api/User/Login', 16 | home:'api/GoldEggplant/RecommendProductList', 17 | productDetail: 'api/GoldEggplant/ProductDetail', 18 | getQRCImage: 'api/GoldEggplant/GetQrCodeWithInterestAssumeType', 19 | getHospitalLimit: 'api/GoldEggplant/GetHospitalLimit', 20 | getInstrumentSet: 'api/GoldEggplant/GetInterestAssumeSetting', 21 | setInstrument: 'api/GoldEggplant/SetInterestAssumeSetting', 22 | DetailItemList: 'api/GoldEggplant/DetailList', 23 | applyForList: 'api/GoldEggplant/ApplyforList', 24 | applyForDetail: 'api/GoldEggplant/ApplyforDetail' 25 | } 26 | } -------------------------------------------------------------------------------- /app/common/LoadMoreFooter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/6/1. 3 | */ 4 | 5 | 6 | import React, { Component } from 'react'; 7 | import { 8 | AppRegistry, 9 | StyleSheet, 10 | Text, 11 | View, 12 | ActivityIndicator 13 | } from 'react-native'; 14 | 15 | export default class LoadMoreFooter extends Component { 16 | constructor(props) { 17 | super(props) 18 | } 19 | render() { 20 | return ( 21 | 22 | 26 | {this.props.title} 27 | 28 | ); 29 | } 30 | } 31 | 32 | const styles = StyleSheet.create({ 33 | container: { 34 | flex: 1, 35 | backgroundColor: '#f4f7fe', 36 | flexDirection: 'row', 37 | justifyContent: 'center', 38 | alignItems: 'center' 39 | 40 | }, 41 | loadText: { 42 | fontSize: 16, 43 | color: '#333', 44 | marginLeft: 10 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /app/common/NavBarCommon.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/28. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | TouchableOpacity, 12 | Image, 13 | Platform 14 | } from 'react-native'; 15 | 16 | 17 | export default class NavBarCommon extends Component { 18 | render() { 19 | // leftTitle和leftImage 优先判断leftTitle (即 文本按钮和图片按钮优先显示文本按钮) 20 | const {title,leftTitle,leftImage,leftAction,rightTitle,rightImage,rightAction} = this.props 21 | return ( 22 | 23 | 24 | { 25 | leftTitle ? 26 | {leftAction()} }> 27 | 28 | {leftTitle} 29 | 30 | 31 | : ( 32 | leftImage 33 | ? 34 | {leftAction()}}> 35 | 36 | 40 | 41 | 42 | : null 43 | ) 44 | } 45 | { 46 | title ? 47 | {title || ''} 48 | : null 49 | } 50 | { 51 | rightTitle ? 52 | {rightAction()}}> 53 | 54 | {rightTitle} 55 | 56 | 57 | : ( 58 | rightImage ? 59 | {rightAction()}}> 60 | 61 | 65 | 66 | 67 | : null 68 | ) 69 | } 70 | 71 | 72 | ); 73 | } 74 | } 75 | 76 | const styles = StyleSheet.create({ 77 | barViewStyle: { 78 | height: Platform.OS =='ios' ? 64 : 44, 79 | backgroundColor: '#fff', 80 | borderBottomWidth: 1, 81 | borderBottomColor: '#dbdbdb' 82 | }, 83 | showViewStyle: { 84 | flex: 1, 85 | alignItems: 'center', 86 | justifyContent: 'center', 87 | flexDirection: 'row', 88 | marginTop: Platform.OS == 'ios' ? 20 : 0, 89 | height: 44 90 | }, 91 | leftNavStyle: { 92 | position: 'absolute', 93 | top: 8, 94 | bottom: 8, 95 | left: 8, 96 | justifyContent: 'center' 97 | }, 98 | barButtonStyle: { 99 | color: '#fff', 100 | fontSize: 18 101 | }, 102 | titleStyle: { 103 | color: '#333', 104 | fontSize: 18, 105 | fontWeight: '600' 106 | }, 107 | rightNavStyle: { 108 | position: 'absolute', 109 | top: 8, 110 | bottom: 8, 111 | right: 8, 112 | justifyContent: 'center', 113 | } 114 | }); 115 | -------------------------------------------------------------------------------- /app/common/RNAsyncStorage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/28. 3 | */ 4 | 5 | 6 | import { 7 | AsyncStorage, 8 | } from 'react-native'; 9 | 10 | import Storage from 'react-native-storage' 11 | 12 | let storage = new Storage({ 13 | //最大容量,默认值1000条数据循环存储 14 | size: 1000, 15 | 16 | //存储引擎:RN使用AsyncStorage 17 | //如果不指定则数据只会保存在内存中,重启后即丢失 18 | storageBackend: AsyncStorage, 19 | 20 | //数据过期时间,默认一整天(1000 * 3600 * 24 毫秒),设为null则永不过期 21 | defaultExpires: 1000 * 3600 * 24, 22 | 23 | //读写时在内存中缓存数据,默认开启 24 | enableCache: true, 25 | 26 | // 如果storage中没有相应数据,或数据已过期, 27 | // 则会调用相应的sync方法,无缝返回最新数据。 28 | // sync方法的具体说明会在后文提到 29 | // 你可以在构造函数这里就写好sync的方法 30 | // 或是在任何时候,直接对storage.sync进行赋值修改 31 | // 或是写到另一个文件里,这里require引入 32 | }) 33 | 34 | //导出`storage` 35 | exports.storage = storage; 36 | 37 | // //在这里设置`storage.sync` 38 | // storage.sync = require('./RNAsyncStorage_asyn').ssss; 39 | -------------------------------------------------------------------------------- /app/common/Request.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/28. 3 | */ 4 | 5 | var queryString = require('query-string') 6 | var _ = require('lodash') 7 | var request = {} 8 | var config = require('./Config') 9 | 10 | /** 11 | * GET 请求 12 | */ 13 | request.get = function (url,params,headers) { 14 | if (params) { 15 | url += '?' + queryString.stringify(params) 16 | } 17 | var headers = { 18 | headers: headers 19 | } 20 | console.log(url,headers) 21 | return fetch(url,headers) 22 | .then((response) => response.json()) 23 | } 24 | 25 | /** 26 | * POST 请求 27 | */ 28 | request.post = function (url,body,headers) { 29 | var header = { 30 | method: 'POST', 31 | headers: headers 32 | } 33 | var configHeads = headers ? header : config.header 34 | var options = _.extend(configHeads,{ 35 | body: JSON.stringify(body) 36 | }) 37 | 38 | console.log(url,options,header,body) 39 | return fetch(url,options) 40 | .then((response) =>response) 41 | } 42 | module.exports = request -------------------------------------------------------------------------------- /app/common/md5.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message 3 | * Digest Algorithm, as defined in RFC 1321. 4 | * Version 1.1 Copyright (C) Paul Johnston 1999 - 2002. 5 | * Code also contributed by Greg Holt 6 | * See http://pajhome.org.uk/site/legal.html for details. 7 | */ 8 | 9 | /* 10 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally 11 | * to work around bugs in some JS interpreters. 12 | */ 13 | function safe_add(x, y) { 14 | var lsw = (x & 0xFFFF) + (y & 0xFFFF) 15 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16) 16 | return (msw << 16) | (lsw & 0xFFFF) 17 | } 18 | 19 | /* 20 | * Bitwise rotate a 32-bit number to the left. 21 | */ 22 | function rol(num, cnt) { 23 | return (num << cnt) | (num >>> (32 - cnt)) 24 | } 25 | 26 | /* 27 | * These functions implement the four basic operations the algorithm uses. 28 | */ 29 | function cmn(q, a, b, x, s, t) { 30 | return safe_add(rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b) 31 | } 32 | function ff(a, b, c, d, x, s, t) { 33 | return cmn((b & c) | ((~b) & d), a, b, x, s, t) 34 | } 35 | function gg(a, b, c, d, x, s, t) { 36 | return cmn((b & d) | (c & (~d)), a, b, x, s, t) 37 | } 38 | function hh(a, b, c, d, x, s, t) { 39 | return cmn(b ^ c ^ d, a, b, x, s, t) 40 | } 41 | function ii(a, b, c, d, x, s, t) { 42 | return cmn(c ^ (b | (~d)), a, b, x, s, t) 43 | } 44 | 45 | /* 46 | * Calculate the MD5 of an array of little-endian words, producing an array 47 | * of little-endian words. 48 | */ 49 | function coreMD5(x) { 50 | var a = 1732584193 51 | var b = -271733879 52 | var c = -1732584194 53 | var d = 271733878 54 | 55 | for (var i = 0; i < x.length; i += 16) { 56 | var olda = a 57 | var oldb = b 58 | var oldc = c 59 | var oldd = d 60 | 61 | a = ff(a, b, c, d, x[i + 0], 7, -680876936) 62 | d = ff(d, a, b, c, x[i + 1], 12, -389564586) 63 | c = ff(c, d, a, b, x[i + 2], 17, 606105819) 64 | b = ff(b, c, d, a, x[i + 3], 22, -1044525330) 65 | a = ff(a, b, c, d, x[i + 4], 7, -176418897) 66 | d = ff(d, a, b, c, x[i + 5], 12, 1200080426) 67 | c = ff(c, d, a, b, x[i + 6], 17, -1473231341) 68 | b = ff(b, c, d, a, x[i + 7], 22, -45705983) 69 | a = ff(a, b, c, d, x[i + 8], 7, 1770035416) 70 | d = ff(d, a, b, c, x[i + 9], 12, -1958414417) 71 | c = ff(c, d, a, b, x[i + 10], 17, -42063) 72 | b = ff(b, c, d, a, x[i + 11], 22, -1990404162) 73 | a = ff(a, b, c, d, x[i + 12], 7, 1804603682) 74 | d = ff(d, a, b, c, x[i + 13], 12, -40341101) 75 | c = ff(c, d, a, b, x[i + 14], 17, -1502002290) 76 | b = ff(b, c, d, a, x[i + 15], 22, 1236535329) 77 | 78 | a = gg(a, b, c, d, x[i + 1], 5, -165796510) 79 | d = gg(d, a, b, c, x[i + 6], 9, -1069501632) 80 | c = gg(c, d, a, b, x[i + 11], 14, 643717713) 81 | b = gg(b, c, d, a, x[i + 0], 20, -373897302) 82 | a = gg(a, b, c, d, x[i + 5], 5, -701558691) 83 | d = gg(d, a, b, c, x[i + 10], 9, 38016083) 84 | c = gg(c, d, a, b, x[i + 15], 14, -660478335) 85 | b = gg(b, c, d, a, x[i + 4], 20, -405537848) 86 | a = gg(a, b, c, d, x[i + 9], 5, 568446438) 87 | d = gg(d, a, b, c, x[i + 14], 9, -1019803690) 88 | c = gg(c, d, a, b, x[i + 3], 14, -187363961) 89 | b = gg(b, c, d, a, x[i + 8], 20, 1163531501) 90 | a = gg(a, b, c, d, x[i + 13], 5, -1444681467) 91 | d = gg(d, a, b, c, x[i + 2], 9, -51403784) 92 | c = gg(c, d, a, b, x[i + 7], 14, 1735328473) 93 | b = gg(b, c, d, a, x[i + 12], 20, -1926607734) 94 | 95 | a = hh(a, b, c, d, x[i + 5], 4, -378558) 96 | d = hh(d, a, b, c, x[i + 8], 11, -2022574463) 97 | c = hh(c, d, a, b, x[i + 11], 16, 1839030562) 98 | b = hh(b, c, d, a, x[i + 14], 23, -35309556) 99 | a = hh(a, b, c, d, x[i + 1], 4, -1530992060) 100 | d = hh(d, a, b, c, x[i + 4], 11, 1272893353) 101 | c = hh(c, d, a, b, x[i + 7], 16, -155497632) 102 | b = hh(b, c, d, a, x[i + 10], 23, -1094730640) 103 | a = hh(a, b, c, d, x[i + 13], 4, 681279174) 104 | d = hh(d, a, b, c, x[i + 0], 11, -358537222) 105 | c = hh(c, d, a, b, x[i + 3], 16, -722521979) 106 | b = hh(b, c, d, a, x[i + 6], 23, 76029189) 107 | a = hh(a, b, c, d, x[i + 9], 4, -640364487) 108 | d = hh(d, a, b, c, x[i + 12], 11, -421815835) 109 | c = hh(c, d, a, b, x[i + 15], 16, 530742520) 110 | b = hh(b, c, d, a, x[i + 2], 23, -995338651) 111 | 112 | a = ii(a, b, c, d, x[i + 0], 6, -198630844) 113 | d = ii(d, a, b, c, x[i + 7], 10, 1126891415) 114 | c = ii(c, d, a, b, x[i + 14], 15, -1416354905) 115 | b = ii(b, c, d, a, x[i + 5], 21, -57434055) 116 | a = ii(a, b, c, d, x[i + 12], 6, 1700485571) 117 | d = ii(d, a, b, c, x[i + 3], 10, -1894986606) 118 | c = ii(c, d, a, b, x[i + 10], 15, -1051523) 119 | b = ii(b, c, d, a, x[i + 1], 21, -2054922799) 120 | a = ii(a, b, c, d, x[i + 8], 6, 1873313359) 121 | d = ii(d, a, b, c, x[i + 15], 10, -30611744) 122 | c = ii(c, d, a, b, x[i + 6], 15, -1560198380) 123 | b = ii(b, c, d, a, x[i + 13], 21, 1309151649) 124 | a = ii(a, b, c, d, x[i + 4], 6, -145523070) 125 | d = ii(d, a, b, c, x[i + 11], 10, -1120210379) 126 | c = ii(c, d, a, b, x[i + 2], 15, 718787259) 127 | b = ii(b, c, d, a, x[i + 9], 21, -343485551) 128 | 129 | a = safe_add(a, olda) 130 | b = safe_add(b, oldb) 131 | c = safe_add(c, oldc) 132 | d = safe_add(d, oldd) 133 | } 134 | return [a, b, c, d] 135 | } 136 | 137 | /* 138 | * Convert an array of little-endian words to a hex string. 139 | */ 140 | function binl2hex(binarray) { 141 | var hex_tab = "0123456789abcdef" 142 | var str = "" 143 | for (var i = 0; i < binarray.length * 4; i++) { 144 | str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) + 145 | hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF) 146 | } 147 | return str 148 | } 149 | 150 | /* 151 | * Convert an array of little-endian words to a base64 encoded string. 152 | */ 153 | function binl2b64(binarray) { 154 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" 155 | var str = "" 156 | for (var i = 0; i < binarray.length * 32; i += 6) { 157 | str += tab.charAt(((binarray[i >> 5] << (i % 32)) & 0x3F) | 158 | ((binarray[i >> 5 + 1] >> (32 - i % 32)) & 0x3F)) 159 | } 160 | return str 161 | } 162 | 163 | /* 164 | * Convert an 8-bit character string to a sequence of 16-word blocks, stored 165 | * as an array, and append appropriate padding for MD4/5 calculation. 166 | * If any of the characters are >255, the high byte is silently ignored. 167 | */ 168 | function str2binl(str) { 169 | var nblk = ((str.length + 8) >> 6) + 1 // number of 16-word blocks 170 | var blks = new Array(nblk * 16) 171 | for (var i = 0; i < nblk * 16; i++) blks[i] = 0 172 | for (var i = 0; i < str.length; i++) 173 | blks[i >> 2] |= (str.charCodeAt(i) & 0xFF) << ((i % 4) * 8) 174 | blks[i >> 2] |= 0x80 << ((i % 4) * 8) 175 | blks[nblk * 16 - 2] = str.length * 8 176 | return blks 177 | } 178 | 179 | /* 180 | * Convert a wide-character string to a sequence of 16-word blocks, stored as 181 | * an array, and append appropriate padding for MD4/5 calculation. 182 | */ 183 | function strw2binl(str) { 184 | var nblk = ((str.length + 4) >> 5) + 1 // number of 16-word blocks 185 | var blks = new Array(nblk * 16) 186 | for (var i = 0; i < nblk * 16; i++) blks[i] = 0 187 | for (var i = 0; i < str.length; i++) 188 | blks[i >> 1] |= str.charCodeAt(i) << ((i % 2) * 16) 189 | blks[i >> 1] |= 0x80 << ((i % 2) * 16) 190 | blks[nblk * 16 - 2] = str.length * 16 191 | return blks 192 | } 193 | 194 | /* 195 | * External interface 196 | */ 197 | function hexMD5(str) { return binl2hex(coreMD5(str2binl(str))) } 198 | function hexMD5w(str) { return binl2hex(coreMD5(strw2binl(str))) } 199 | function b64MD5(str) { return binl2b64(coreMD5(str2binl(str))) } 200 | function b64MD5w(str) { return binl2b64(coreMD5(strw2binl(str))) } 201 | /* Backward compatibility */ 202 | function calcMD5(str) { return binl2hex(coreMD5(str2binl(str))) } 203 | 204 | module.exports = { 205 | hexMD5: hexMD5 206 | } -------------------------------------------------------------------------------- /app/home/HomeBottomList.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/29. 3 | */ 4 | 5 | 6 | import React, { Component } from 'react'; 7 | import { 8 | AppRegistry, 9 | StyleSheet, 10 | Text, 11 | View, 12 | ListView, 13 | TouchableOpacity, 14 | Image, 15 | Dimensions 16 | } from 'react-native'; 17 | 18 | import Spinner from 'react-native-loading-spinner-overlay' 19 | 20 | const {width,height} = Dimensions.get('window') 21 | let someStore = require('../../app/common/RNAsyncStorage') 22 | let storage = someStore.storage 23 | let that 24 | let config = require('../common/Config') 25 | let request = require('../common/Request') 26 | 27 | export default class HomeBottomList extends Component { 28 | constructor(props) { 29 | super(props) 30 | that = this 31 | let ds = new ListView.DataSource({ 32 | rowHasChanged: (row1,row2) => row1 !== row2 33 | }) 34 | this.state = { 35 | dataSource: ds.cloneWithRows([]), 36 | visible: false 37 | } 38 | } 39 | componentDidMount() { 40 | this._loadStorageData() 41 | } 42 | render() { 43 | return ( 44 | 45 | 50 | 56 | 57 | ); 58 | } 59 | /** 60 | * 渲染每个ItemCell 61 | */ 62 | _renderRow(rowData) { 63 | return ( 64 | that._clickItemCell(rowData)}> 65 | 66 | 69 | {rowData.ProductName} 70 | {rowData.NowNumber}人申请 71 | 72 | 73 | 74 | {`${rowData.AllowMinCost}~${rowData.AllowMaxCost}`} 75 | {that._dealWithNumStr(rowData.InstalmentsNum)} 76 | {`${rowData.SuccessRate}%`} 77 | 78 | 79 | 80 | 81 | 贷款额度(元) 82 | 期数 83 | 成功率 84 | 85 | 86 | that._applyBtnClick()}> 87 | 88 | 立即申请 89 | 90 | 91 | 92 | 93 | ) 94 | } 95 | /** 96 | * 每个Item的点击事件 97 | */ 98 | _clickItemCell(rowData) { 99 | if (this.props.callBack == null) return 100 | this.props.callBack(rowData.ProductName,rowData.ProductId) 101 | } 102 | /** 103 | * 立即申请点击事件 104 | */ 105 | _applyBtnClick() { 106 | if (this.props.applyCallBack == null) return 107 | this.props.applyCallBack() 108 | } 109 | /** 110 | * 请求产品列表 111 | */ 112 | _fetchMoreData(loginData) { 113 | 114 | let accessToken = loginData.Token.authorization 115 | let worker = loginData.Token.worker 116 | let homeURL = `${config.api.base}${config.api.home}` 117 | var headers = { 118 | 'Content-Type': 'application/json', 119 | 'Authorization': accessToken, 120 | 'Worker': worker, 121 | 'ChannelId': '1000005', 122 | 'Hospital': '130670' 123 | } 124 | this.setState({ 125 | visible: true 126 | }) 127 | request.get(homeURL, null, headers) 128 | .then((data) => { 129 | console.log('homeData', data.List) 130 | that.setState({ 131 | dataSource: that.state.dataSource.cloneWithRows(data.List), 132 | visible: false 133 | }) 134 | }).catch((error) => { 135 | this.setState({ 136 | visible: false 137 | }) 138 | console.log(error) 139 | }) 140 | } 141 | /** 142 | * 读取本地化登录数据 143 | */ 144 | _loadStorageData() { 145 | storage.load({ 146 | key:'loginState', 147 | id: 1001 148 | }).then((data) => { 149 | console.log('读取数据成功',data) 150 | that._fetchMoreData(data) 151 | }).catch((error) => { 152 | console.log('读取数据失败',error) 153 | }) 154 | } 155 | /** 156 | * 处理分期数字符串 157 | */ 158 | _dealWithNumStr(numStr) { 159 | var first = numStr.split(',')[0] 160 | return `${numStr.split(",")[0]}/${numStr.split(",")[1]}` 161 | } 162 | } 163 | 164 | const styles = StyleSheet.create({ 165 | container: { 166 | flex: 1, 167 | backgroundColor: '#f4f7fe' 168 | }, 169 | cellTopViewStyle: { 170 | backgroundColor: '#fff', 171 | flexDirection: 'row', 172 | alignItems: 'center', 173 | paddingVertical: 10, 174 | paddingLeft: 15 175 | }, 176 | cellMiddleViewStyle: { 177 | backgroundColor: '#fff' 178 | }, 179 | cellBottomViewStyle: { 180 | backgroundColor: '#fff' 181 | }, 182 | iconStyle: { 183 | width: 25, 184 | height: 25 185 | }, 186 | titleStyle: { 187 | marginLeft: 10, 188 | fontSize: 16 189 | }, 190 | countTextStyle: { 191 | fontSize: 12, 192 | color: '#666', 193 | borderColor: '#999', 194 | borderWidth: 0.5, 195 | paddingVertical: 2, 196 | paddingHorizontal: 4, 197 | borderRadius: 2, 198 | marginLeft: 10 199 | }, 200 | itemStyle: { 201 | flexDirection: 'row', 202 | marginLeft: 50, 203 | width: width - 100, 204 | justifyContent: 'space-between', 205 | marginVertical: 5 206 | }, 207 | topTextStyle: { 208 | fontSize: 16, 209 | color: '#333', 210 | fontWeight: '500' 211 | }, 212 | bottomTextStyle: { 213 | fontSize: 13, 214 | color: '#666', 215 | }, 216 | applyBtnStyle: { 217 | backgroundColor: '#fff', 218 | paddingVertical: 10, 219 | borderTopColor: '#dbdbdb', 220 | borderTopWidth: 1, 221 | }, 222 | applyTextStyle: { 223 | fontSize: 16, 224 | color: '#605bf5', 225 | textAlign: 'center' 226 | } 227 | 228 | }); 229 | -------------------------------------------------------------------------------- /app/home/HomeTab.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/28. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | Image, 12 | TouchableOpacity, 13 | Dimensions, 14 | ListView, 15 | ScrollView 16 | } from 'react-native'; 17 | 18 | import Picker from 'react-native-picker' 19 | import Swiper from 'react-native-swiper' 20 | 21 | import NavigationBar from '../common/NavBarCommon' 22 | import BottomList from './HomeBottomList' 23 | import QrcScan from './QrcScan' 24 | import ProduceDetail from './ProduceDetail' 25 | import ApplyFirst from '../apply/ApplyFirst' 26 | 27 | const {width,height} = Dimensions.get('window') 28 | let that 29 | const pickerData = ['诊所承担','客户承担','诊所客户各承担一半'] 30 | 31 | export default class HomeTab extends Component { 32 | constructor(props) { 33 | super(props) 34 | that = this 35 | this.state = { 36 | selectedIndex: 0, 37 | itemImages: [], // 轮播图图片数组 38 | } 39 | } 40 | componentDidMount() { 41 | /** 42 | * 获取登录之后设置的全局accessToken 43 | */ 44 | console.log('全局变量accessToken:',global.accessToken) 45 | var items = [ 46 | 'http://clinicapi.qiezzitest.info/Images/QieZiJinRong_Home1_iOS.png', 47 | 'http://blogdailyherald.com/wp-content/uploads/2013/04/382065_560557460633306_930109857_n.jpg', 48 | 'http://img0.pclady.com.cn/pclady/pet/choice/cat/1701/6.jpg', 49 | 'https://gss0.baidu.com/9fo3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/3812b31bb051f819dc048662dbb44aed2e73e7f1.jpg' 50 | ] 51 | this.setState({ 52 | itemImages: items 53 | }) 54 | } 55 | render() { 56 | return ( 57 | 58 | 60 | 61 | {/*轮播图*/} 62 | {this._renderSwiperItem()} 63 | {this._renderSecondItem()} 64 | 65 | 推荐产品 66 | 67 | {/*推荐产品列表*/} 68 | this._ItemClick(title,productId)} 70 | applyCallBack={() => this._applyBtnClick()}/> 71 | 72 | 73 | 74 | ); 75 | } 76 | 77 | /** 78 | * 渲染轮播图组件 79 | */ 80 | _renderSwiperItem() { 81 | return ( 82 | 89 | { 90 | this.state.itemImages.map((item, index) => { 91 | //cover: 等比例放大; center:不变; contain:不变; stretch:填充; 92 | return 96 | }) 97 | } 98 | 99 | 100 | ) 101 | } 102 | /** 103 | * 渲染折扣信息组件 104 | */ 105 | _renderSecondItem() { 106 | return ( 107 | 108 | 111 | this._qrcClick()}> 112 | 113 | 诊所二维码 114 | 115 | 116 | 117 | ) 118 | } 119 | /** 120 | * 每个ItemCell点击事件 121 | */ 122 | _ItemClick(title,productId) { 123 | this.props.navigator.push({ 124 | component: ProduceDetail, 125 | title:'', 126 | params: { 127 | navTitle: title, 128 | productId: productId 129 | } 130 | }) 131 | } 132 | /** 133 | * 立即申请点击事件 134 | */ 135 | _applyBtnClick() { 136 | this.props.navigator.push({ 137 | component: ApplyFirst, 138 | title:'' 139 | }) 140 | } 141 | /** 142 | * 二维码点击事件 143 | */ 144 | _qrcClick() { 145 | Picker.init({ 146 | pickerData: pickerData, 147 | selectedValue: [pickerData[this.state.selectedIndex]], 148 | pickerConfirmBtnText:'确认', 149 | pickerCancelBtnText:'取消', 150 | pickerTitleText:'请选择', 151 | pickerConfirmBtnColor: [96,91,245,1], 152 | pickerCancelBtnColor: [96,91,245,1], 153 | pickerRowHeight: 40, 154 | onPickerConfirm: pickerValue => { 155 | let selectIndex = this._fetchIndexOfValue(pickerValue[0],pickerData) 156 | this.setState({ 157 | selectedIndex: selectIndex 158 | }) 159 | this._pushNav() 160 | }, 161 | onPickerCancel: pickerValue => { 162 | 163 | }, 164 | onPickerSelect: pickerValue => { 165 | 166 | } 167 | }) 168 | Picker.show() 169 | 170 | } 171 | /** 172 | * 跳转二维码页面 173 | */ 174 | _pushNav() { 175 | this.props.navigator.push({ 176 | component: QrcScan, 177 | title:'', 178 | params: { 179 | type: this.state.selectedIndex 180 | } 181 | }) 182 | } 183 | /** 184 | * 遍历数组查找元素下标 185 | */ 186 | _fetchIndexOfValue(value,array) { 187 | for (let i = 0; i < array.length; i++) { 188 | if (array[i] == value) { 189 | return i 190 | } 191 | } 192 | return -1 193 | } 194 | } 195 | 196 | const styles = StyleSheet.create({ 197 | container: { 198 | flex: 1, 199 | backgroundColor: '#f4f7fe', 200 | }, 201 | secondItemStyle: { 202 | marginTop: 10, 203 | backgroundColor: '#fff' 204 | }, 205 | qrcContainerStyle: { 206 | width: width - 90, 207 | height: 35, 208 | alignSelf: 'center', 209 | marginVertical: 15, 210 | borderColor: '#605bf5', 211 | borderRadius: 5, 212 | borderWidth: 1, 213 | justifyContent: 'center' 214 | }, 215 | qrcTextStyle: { 216 | fontSize: 16, 217 | color: '#605bf5', 218 | alignSelf: 'center', 219 | justifyContent:'center' 220 | }, 221 | recommendTextStyle: { 222 | marginTop:10, 223 | paddingVertical: 10, 224 | backgroundColor: '#fff', 225 | borderBottomWidth: 1, 226 | borderBottomColor: '#dbdbdb', 227 | paddingLeft: 15 228 | } 229 | }); 230 | -------------------------------------------------------------------------------- /app/home/ProduceDetail.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/29. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | WebView 12 | } from 'react-native'; 13 | 14 | let config = require('../common/Config') 15 | let request = require('../common/Request') 16 | let someStore = require('../common/RNAsyncStorage') 17 | let storage = someStore.storage 18 | let that 19 | import NavigationBar from '../common/NavBarCommon' 20 | export default class ProduceDetail extends Component { 21 | constructor(props) { 22 | super(props) 23 | that = this 24 | this.state = { 25 | url: '', 26 | title: '', 27 | } 28 | } 29 | componentDidMount() { 30 | console.log(this.props) 31 | this.setState({ 32 | url: this.props.route.params.title, 33 | title: this.props.route.params.navTitle 34 | }) 35 | this._loadStorageData() 36 | } 37 | render() { 38 | return ( 39 | 40 | this._popNav()} 44 | rightImage={require('../images/nav_share.png')} 45 | rightAction={() => { 46 | alert('分享看看') 47 | }}/> 48 | 57 | 58 | ); 59 | } 60 | /** 61 | * 导航返回 62 | */ 63 | _popNav(){ 64 | this.props.navigator.pop() 65 | } 66 | /** 67 | * 获取显示的URL 68 | */ 69 | _fetchProductDetail(loginData) { 70 | let accessToken = loginData.Token.authorization 71 | let worker = loginData.Token.worker 72 | let productDetailURL = `${config.api.base}${config.api.productDetail}` 73 | var headers = { 74 | 'Content-Type': 'application/json', 75 | 'Authorization': accessToken, 76 | 'Worker': worker, 77 | 'ChannelId': '1000005', 78 | 'Hospital': '130670' 79 | } 80 | var params = { 81 | productId: this.props.route.params.productId 82 | } 83 | request.get(productDetailURL,params,headers) 84 | .then((data) => { 85 | console.log(data) 86 | that.setState({ 87 | url: data.Url, 88 | title: data.Title 89 | }) 90 | }) 91 | .catch((error) => { 92 | 93 | }) 94 | } 95 | /** 96 | * 读取本地化登录数据 97 | */ 98 | _loadStorageData() { 99 | storage.load({ 100 | key:'loginState', 101 | id: 1001 102 | }).then((data) => { 103 | that._fetchProductDetail(data) 104 | }).catch((error) => { 105 | 106 | }) 107 | } 108 | } 109 | 110 | const styles = StyleSheet.create({ 111 | container: { 112 | flex: 1, 113 | backgroundColor: '#f4f7fe' 114 | }, 115 | webViewStyle: { 116 | 117 | } 118 | }); 119 | -------------------------------------------------------------------------------- /app/home/QrcScan.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/29. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | Image, 12 | Dimensions 13 | } from 'react-native'; 14 | 15 | import NavigationBar from '../common/NavBarCommon' 16 | import Spinner from 'react-native-loading-spinner-overlay' 17 | import Toast, {DURATION} from 'react-native-easy-toast' 18 | 19 | let config = require('../common/Config') 20 | let request = require('../common/Request') 21 | let someStore = require('../common/RNAsyncStorage') 22 | let storage = someStore.storage 23 | const {width,height} = Dimensions.get('window') 24 | let that 25 | export default class QrcScan extends Component { 26 | constructor(props) { 27 | super(props) 28 | that = this 29 | this.state = { 30 | qrcImageUrl: '', 31 | visible: false 32 | } 33 | } 34 | componentDidMount() { 35 | 36 | this._loadStorageData() 37 | } 38 | render() { 39 | return ( 40 | 41 | this._popNav()}/> 45 | 46 | 请申请人使用常用微信号 47 | 扫描下方二维码进行扫描 48 | 52 | 温馨提示:您扫描的微信号为你后期接受账号提醒的唯一微信号 53 | 54 | 59 | 64 | 65 | ); 66 | } 67 | /** 68 | * 网络请求获取imageUrl 69 | */ 70 | _fetchQRCImageUrl(loginData) { 71 | let accessToken = loginData.Token.authorization 72 | let worker = loginData.Token.worker 73 | let qrcURL = `${config.api.base}${config.api.getQRCImage}` 74 | var headers = { 75 | 'Content-Type': 'application/json', 76 | 'Authorization': accessToken, 77 | 'Worker': worker, 78 | 'ChannelId': '1000005', 79 | 'Hospital': '130670' 80 | } 81 | var params = { 82 | type: this.props.route.params.type 83 | } 84 | this._showSpannerHud(true) 85 | request.get(qrcURL,params,headers) 86 | .then((data) => { 87 | console.log(data) 88 | if (data && !that._isString(data)) { 89 | that.setState({ 90 | qrcImageUrl: data.QrUrl, 91 | visible: false 92 | }) 93 | } else { 94 | that._showSpannerHud(false) 95 | that.refs.toast.show(data,300) 96 | } 97 | }) 98 | .catch((error) => { 99 | console.log(error) 100 | that._showSpannerHud(false) 101 | }) 102 | } 103 | /** 104 | * 读取本地化登录数据 105 | */ 106 | _loadStorageData() { 107 | storage.load({ 108 | key:'loginState', 109 | id: 1001 110 | }).then((data) => { 111 | that._fetchQRCImageUrl(data) 112 | }).catch((error) => { 113 | 114 | }) 115 | } 116 | /** 117 | * 导航返回 118 | */ 119 | _popNav(){ 120 | this.props.navigator.pop() 121 | } 122 | /** 123 | * hud是否显示 124 | */ 125 | _showSpannerHud(show) { 126 | this.setState({ 127 | visible: show 128 | }) 129 | } 130 | /** 131 | * 判断对象是否是字符串 132 | */ 133 | _isString(obj){ 134 | return Object.prototype.toString.call(obj) === "[object String]"; 135 | } 136 | } 137 | 138 | const styles = StyleSheet.create({ 139 | container: { 140 | flex: 1, 141 | backgroundColor: '#fff' 142 | }, 143 | titleStyle: { 144 | fontSize: 18, 145 | marginTop: 20 146 | }, 147 | qrcImageStyle: { 148 | width: 200, 149 | height: 200, 150 | resizeMode: 'contain', 151 | marginTop: 30 152 | }, 153 | tipInfoStyle: { 154 | fontSize: 12, 155 | marginTop: 30, 156 | color: '#666', 157 | flexWrap: 'wrap', 158 | width: width - 80, 159 | textAlign: 'center', 160 | lineHeight: 20 161 | } 162 | }); 163 | -------------------------------------------------------------------------------- /app/images/GQZ_QRCode@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/GQZ_QRCode@2x.png -------------------------------------------------------------------------------- /app/images/board-actived.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/board-actived.png -------------------------------------------------------------------------------- /app/images/board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/board.png -------------------------------------------------------------------------------- /app/images/common_bg_kong_n@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/common_bg_kong_n@2x.png -------------------------------------------------------------------------------- /app/images/common_bg_kong_n@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/common_bg_kong_n@3x.png -------------------------------------------------------------------------------- /app/images/common_bg_shujushibai_n@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/common_bg_shujushibai_n@2x.png -------------------------------------------------------------------------------- /app/images/common_bg_shujushibai_n@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/common_bg_shujushibai_n@3x.png -------------------------------------------------------------------------------- /app/images/common_bg_wangluoshibai_n@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/common_bg_wangluoshibai_n@2x.png -------------------------------------------------------------------------------- /app/images/common_bg_wangluoshibai_n@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/common_bg_wangluoshibai_n@3x.png -------------------------------------------------------------------------------- /app/images/guide_1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/guide_1@2x.png -------------------------------------------------------------------------------- /app/images/guide_2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/guide_2@2x.png -------------------------------------------------------------------------------- /app/images/guide_3@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/guide_3@2x.png -------------------------------------------------------------------------------- /app/images/home-actived.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/home-actived.png -------------------------------------------------------------------------------- /app/images/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/home.png -------------------------------------------------------------------------------- /app/images/lanuch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/lanuch.png -------------------------------------------------------------------------------- /app/images/login_logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/login_logo@2x.png -------------------------------------------------------------------------------- /app/images/login_logo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/login_logo@3x.png -------------------------------------------------------------------------------- /app/images/login_pwd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/login_pwd.png -------------------------------------------------------------------------------- /app/images/login_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/login_user.png -------------------------------------------------------------------------------- /app/images/nav_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/nav_back.png -------------------------------------------------------------------------------- /app/images/nav_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/nav_share.png -------------------------------------------------------------------------------- /app/images/profile-actived.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/profile-actived.png -------------------------------------------------------------------------------- /app/images/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/profile.png -------------------------------------------------------------------------------- /app/images/projectGif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/projectGif.gif -------------------------------------------------------------------------------- /app/images/projectShot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/projectShot.jpg -------------------------------------------------------------------------------- /app/images/projectTree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/app/images/projectTree.jpg -------------------------------------------------------------------------------- /app/login/Guide.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/6/5. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | Dimensions, 12 | Image, 13 | TouchableOpacity 14 | } from 'react-native'; 15 | 16 | 17 | import AppIntro from 'react-native-app-intro' 18 | import Login from '../login/Login' 19 | const {width,height} = Dimensions.get('window') 20 | 21 | export default class Guide extends Component { 22 | 23 | /** 24 | * 立即体验点击事件 25 | */ 26 | showDoneClick = () => { 27 | this.props.navigator.replace({ 28 | component: Login 29 | }) 30 | } 31 | render() { 32 | return ( 33 | 38 | {this._renderItemPage(require('../images/guide_1@2x.png'),1)} 39 | {this._renderItemPage(require('../images/guide_2@2x.png'),2)} 40 | {this._renderItemPage(require('../images/guide_3@2x.png'),3)} 41 | 42 | ); 43 | } 44 | /** 45 | * 引导页图片 46 | */ 47 | _renderItemPage(image,index) { 48 | return ( 49 | 50 | 53 | { 54 | index == 3 55 | ? this._renderShowItem() 56 | : 57 | } 58 | 59 | ) 60 | } 61 | /** 62 | * 立即体验组件 63 | */ 64 | _renderShowItem() { 65 | return ( 66 | this.showDoneClick()}> 67 | 68 | 立即体验 69 | 70 | 71 | ) 72 | } 73 | } 74 | 75 | const styles = StyleSheet.create({ 76 | container: { 77 | flex: 1, 78 | backgroundColor: '#f4f7fe' 79 | }, 80 | swiperImageStyle: { 81 | height: height - 120, 82 | }, 83 | slide: { 84 | flex: 1, 85 | backgroundColor: '#fff' 86 | }, 87 | text: { 88 | color: '#333', 89 | fontSize: 30, 90 | fontWeight: 'bold', 91 | }, 92 | showContainer: { 93 | justifyContent: 'center', 94 | alignSelf: 'center', 95 | width: 120, 96 | height: 44, 97 | backgroundColor: '#7080fa', 98 | borderRadius: 4 99 | }, 100 | showText: { 101 | fontSize: 16, 102 | color: '#fff', 103 | textAlign: 'center', 104 | fontWeight: '600' 105 | } 106 | }); 107 | -------------------------------------------------------------------------------- /app/login/LaunchView.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/6/5. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | Image 12 | } from 'react-native'; 13 | 14 | 15 | import Common from '../common/Common' 16 | /** 主页面(含导航控制器) */ 17 | import Navigator from '../navigator/Navigator' 18 | /** 登录页 */ 19 | import Login from '../login/Login' 20 | /** 引导页 */ 21 | import Guide from '../login/Guide' 22 | 23 | let someStore = require('../common/RNAsyncStorage') 24 | let storage = someStore.storage 25 | let that 26 | export default class LaunchView extends Component { 27 | constructor(props) { 28 | super(props) 29 | that = this 30 | } 31 | componentDidMount() { 32 | /** 33 | * 延时加载(异步读取本地数据) 34 | */ 35 | setTimeout(this._openApp,1500) 36 | } 37 | render() { 38 | return ( 39 | 40 | 43 | 44 | ); 45 | } 46 | /** 47 | * 启动页之后页面导航跳转逻辑 48 | */ 49 | _openApp() { 50 | storage.load({ 51 | key: 'FirstLogin', 52 | id: 1002 53 | }).then((data) => { 54 | console.log('isFirstFlag',data) 55 | /** 获取用户是否登录 */ 56 | storage.load({ 57 | key: 'loginState', 58 | id: 1001 59 | }).then(() => { 60 | /** 登录过,直接加载首页 */ 61 | that.props.navigator.replace({ 62 | component: Navigator 63 | }) 64 | }).catch((error) => { 65 | console.log(error) 66 | /** 未登录过,加载登录页面 */ 67 | that.props.navigator.replace({ 68 | component: Login 69 | }) 70 | }) 71 | }).catch((error) => { 72 | console.log('开启奇幻之旅吧') 73 | that._saveFirstFlag() 74 | }) 75 | } 76 | /** 77 | * 本地存储第一次打开app标识 78 | */ 79 | _saveFirstFlag = () => { 80 | storage.save({ 81 | key: 'FirstLogin', 82 | id: 1002, 83 | data: { 84 | isFirst: 'false' 85 | }, 86 | }).then(() => { 87 | that.props.navigator.replace({ 88 | component: Guide 89 | }) 90 | 91 | }).catch((error) => { 92 | console.log('error',error) 93 | }) 94 | } 95 | } 96 | 97 | const styles = StyleSheet.create({ 98 | container: { 99 | flex: 1, 100 | backgroundColor: '#f4f7fe' 101 | } 102 | }); 103 | -------------------------------------------------------------------------------- /app/login/Login.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/28. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | Image, 12 | TextInput, 13 | Dimensions, 14 | TouchableOpacity 15 | } from 'react-native'; 16 | 17 | import Toast, {DURATION} from 'react-native-easy-toast' 18 | import Spinner from 'react-native-loading-spinner-overlay' 19 | import Navigator from '../navigator/Navigator' 20 | 21 | let someStore = require('../common/RNAsyncStorage') 22 | let storage = someStore.storage 23 | const {width,height} = Dimensions.get('window') 24 | let that 25 | let config = require('../common/Config') 26 | let request = require('../common/Request') 27 | let md5 = require('../common/md5') 28 | var _ = require('lodash') 29 | 30 | export default class Login extends Component { 31 | constructor(props) { 32 | super(props) 33 | that = this 34 | this.state = { 35 | userName: '', 36 | passWord:'', 37 | visible: false 38 | } 39 | } 40 | render() { 41 | return ( 42 | 43 | 47 | 52 | 55 | {/*用户名*/} 56 | { 57 | this._renderInputItem( 58 | '用户名', 59 | require('../images/login_user.png'), 60 | '请输入账号', 61 | false 62 | ) 63 | } 64 | {/*密码*/} 65 | { 66 | this._renderInputItem( 67 | '密码', 68 | require('../images/login_pwd.png'), 69 | '请输入密码', 70 | true 71 | ) 72 | } 73 | {/*登录*/} 74 | this._loginAction()}> 75 | 76 | 登录 77 | 78 | 79 | {/*注册、忘记密码*/} 80 | 81 | this._registerAction()}> 82 | 注册 83 | 84 | this._forgotPassWordAction()}> 85 | 忘记密码? 86 | 87 | 88 | 89 | ); 90 | } 91 | 92 | /** 93 | * 渲染登录注册组件 94 | **/ 95 | _renderInputItem(title,leftImage,placeHolder,isSecureText){ 96 | return ( 97 | 98 | 101 | this._hasChanged(title,text)} 105 | secureTextEntry={isSecureText} 106 | clearButtonMode='while-editing'/> 107 | 108 | ) 109 | } 110 | /** 111 | * 监听输入框 112 | **/ 113 | _hasChanged(title,text) { 114 | console.log(title + text) 115 | if (title == '用户名') { 116 | this.setState({ 117 | userName: text 118 | }) 119 | } else { 120 | this.setState({ 121 | passWord: text 122 | }) 123 | } 124 | } 125 | /** 126 | * 登录事件 127 | **/ 128 | _loginAction() { 129 | 130 | if (!this.state.userName.trim() || !this.state.passWord.trim()) { 131 | this.refs.toast.show('用户名或者密码不能为空',300) 132 | } else { 133 | let signUpURL = `${config.api.base}${config.api.login}` 134 | let userName = this.state.userName; 135 | let securePassWord = md5.hexMD5(this.state.passWord) 136 | let body = { 137 | UserName: userName, 138 | Password: securePassWord 139 | } 140 | var options = _.extend(config.header,{ 141 | body: JSON.stringify(body) 142 | }) 143 | this._showHud(true) 144 | /** 145 | * fetch网络请求接口调用 146 | */ 147 | fetch(signUpURL,options) 148 | .then((response) => response.json()) 149 | .then((data) =>{ 150 | if (data && !that._isString(data)) { 151 | console.log('登录成功') 152 | // 反向传值(数据回调) 153 | console.log(data) 154 | that._showHud(false) 155 | that._saveData(data) 156 | } 157 | else { 158 | that._showHud(false) 159 | that.refs.toast.show(data,300) 160 | } 161 | }) 162 | .catch((error) => { 163 | alert('登录失败了') 164 | console.log('error',error) 165 | that._showHud(false) 166 | }) 167 | } 168 | } 169 | /** 170 | * 登录后数据本地化存储 171 | */ 172 | _saveData = (data) => { 173 | /** 174 | * 此处可以设置全局变量,保存用户登录Token 175 | */ 176 | global.accessToken = { 177 | authorization: data.Web.UserCookie.Value, 178 | worker: data.Web.Cookie.Value 179 | } 180 | // storage.remove({ 181 | // key: 'loginState' 182 | // }) 183 | storage.save({ 184 | key: 'loginState', 185 | id: 1001, 186 | data: { 187 | User: data.User, 188 | HospitalCode: '130670', 189 | Token: { 190 | authorization: data.Web.UserCookie.Value, 191 | worker: data.Web.Cookie.Value 192 | } 193 | }, 194 | //expires为有效时间(一天) 195 | expires: 24 * 3600 * 1000 196 | }).then(() => { 197 | console.log('登录数据保存成功了') 198 | that.props.navigator.replace({ 199 | component: Navigator 200 | }) 201 | }).catch((error) => { 202 | console.log('数据保存失败了') 203 | }) 204 | } 205 | /** 206 | * 注册 207 | **/ 208 | _registerAction() { 209 | alert('注了个册') 210 | } 211 | /** 212 | * 忘记密码 213 | **/ 214 | _forgotPassWordAction() { 215 | alert('忘记密码?你是猪吗') 216 | } 217 | /** 218 | * 判断对象是否是字符串 219 | */ 220 | _isString(obj){ 221 | return Object.prototype.toString.call(obj) === "[object String]"; 222 | } 223 | /** 224 | * hud显示隐藏 225 | **/ 226 | _showHud(show) { 227 | this.setState({ 228 | visible: show 229 | }) 230 | } 231 | } 232 | 233 | const styles = StyleSheet.create({ 234 | container: { 235 | flex: 1, 236 | backgroundColor: '#fff' 237 | }, 238 | logoIconStyle: { 239 | alignSelf: 'center', 240 | justifyContent: 'center', 241 | resizeMode: 'contain', 242 | marginTop: 64, 243 | marginBottom: 50 244 | }, 245 | inputContentStyle: { 246 | flexDirection: 'row', 247 | justifyContent:'space-between', 248 | width: width - 100, 249 | height: 44, 250 | alignSelf: 'center', 251 | borderBottomWidth: 1, 252 | borderBottomColor: '#dbdbdb', 253 | marginTop: 10 254 | 255 | }, 256 | loginIconStyle: { 257 | position: 'absolute', 258 | bottom: 5, 259 | resizeMode: 'contain', 260 | height: 30, 261 | width: 30 262 | }, 263 | textInputStyle: { 264 | flex: 1, 265 | marginLeft: 40 266 | }, 267 | loginBtnStyle: { 268 | marginTop: 34, 269 | width: width - 100, 270 | height: 40, 271 | alignSelf: 'center', 272 | backgroundColor:'#605bf5', 273 | borderRadius: 4, 274 | justifyContent: 'center' 275 | }, 276 | loginTextStyle: { 277 | fontSize: 20, 278 | color: '#fff', 279 | alignSelf: 'center' 280 | }, 281 | registerContainerStyle: { 282 | marginTop: 10, 283 | width: width - 100, 284 | flexDirection: 'row', 285 | justifyContent: 'space-between', 286 | alignSelf: 'center' 287 | }, 288 | registerTextStyle: { 289 | fontSize: 16, 290 | color:'#999' 291 | } 292 | }); 293 | -------------------------------------------------------------------------------- /app/mine/MineTab.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/28. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | TouchableOpacity, 12 | Image, 13 | Alert 14 | } from 'react-native'; 15 | 16 | import Spinner from 'react-native-loading-spinner-overlay' 17 | import NavigationBar from '../common/NavBarCommon' 18 | import SetRate from './SetRate' 19 | import OrderList from './OrderItemList' 20 | import App from '../App' 21 | import Login from '../login/Login' 22 | 23 | 24 | let config = require('../common/Config') 25 | let request = require('../common/Request') 26 | let someStore = require('../common/RNAsyncStorage') 27 | let storage = someStore.storage 28 | let that 29 | export default class MineTab extends Component { 30 | constructor(props) { 31 | super(props) 32 | that = this 33 | this.state = { 34 | visible: false, 35 | totalLimit: '0.00', 36 | remainLimit: '0.00' 37 | } 38 | } 39 | componentDidMount() { 40 | this._loadStorageData() 41 | } 42 | render() { 43 | return ( 44 | 45 | 47 | 48 | 诊所剩余额度(元) 49 | {`¥ ${this.state.remainLimit}`} 50 | {`总额度 ¥ ${this.state.totalLimit}`} 53 | 54 | {this._renderSelectedItem('明细')} 55 | {this._renderSelectedItem('利息承担设置')} 56 | this._logout()}> 57 | 58 | 注销 59 | 60 | 61 | 62 | 67 | 68 | ); 69 | } 70 | /** 71 | * 退出登录 72 | */ 73 | _logout() { 74 | Alert.alert( 75 | '提示', 76 | '确定退出?', 77 | [ 78 | {text:'取消',onPress: () => { 79 | }}, 80 | {text:'确定',onPress: () => { 81 | /** !! 清空map,移除所有"key-id"数据(但会保留只有key的数据) */ 82 | // storage.clearMap() 83 | /** 单个key清除 */ 84 | storage.remove({ 85 | key: 'loginState', 86 | id: 1001 87 | }) 88 | /** 退出登录页面导航跳转(用一个新的路由替换掉当前的场景) */ 89 | that.props.navigator.replace({ 90 | component: Login 91 | }) 92 | }}, 93 | ] 94 | ) 95 | } 96 | 97 | /** 98 | * 获取诊所限制额度 99 | */ 100 | _fetchHospitalLimitData(loginData) { 101 | let accessToken = loginData.Token.authorization 102 | let worker = loginData.Token.worker 103 | let limitURL = `${config.api.base}${config.api.getHospitalLimit}` 104 | var headers = { 105 | 'Content-Type': 'application/json', 106 | 'Authorization': accessToken, 107 | 'Worker': worker, 108 | 'ChannelId': '1000005', 109 | 'Hospital': '130670' 110 | } 111 | this._showHud(true) 112 | request.get(limitURL,null,headers) 113 | .then((data) => { 114 | console.log(data) 115 | that.setState({ 116 | totalLimit: data.TotalLimit, 117 | remainLimit: data.RemainLimit, 118 | visible: false 119 | }) 120 | }) 121 | .catch((error) => { 122 | console.log(error) 123 | that._showHud(false) 124 | }) 125 | } 126 | /** 127 | * 读取本地化登录数据 128 | */ 129 | _loadStorageData() { 130 | storage.load({ 131 | key:'loginState', 132 | id: 1001 133 | }).then((data) => { 134 | that._fetchHospitalLimitData(data) 135 | }).catch((error) => { 136 | 137 | }) 138 | } 139 | /** 140 | * pushItemCell 141 | **/ 142 | _renderSelectedItem(title) { 143 | return ( 144 | this._pushNav(title)}> 145 | 146 | {title} 147 | 148 | 149 | 150 | ) 151 | } 152 | /** 153 | * 导航跳转 154 | */ 155 | _pushNav(title) { 156 | if (title == '明细') { 157 | this.props.navigator.push({ 158 | component: OrderList, 159 | title: '' 160 | }) 161 | } 162 | else { 163 | this.props.navigator.push({ 164 | component: SetRate, 165 | title: '' 166 | }) 167 | } 168 | } 169 | /** 170 | * hud显示隐藏 171 | */ 172 | _showHud(show) { 173 | this.setState({ 174 | visible: show 175 | }) 176 | } 177 | } 178 | 179 | const styles = StyleSheet.create({ 180 | container: { 181 | flex: 1, 182 | backgroundColor: '#f4f7fe' 183 | }, 184 | headerContainerStyle: { 185 | backgroundColor: '#fff', 186 | justifyContent: 'center', 187 | alignItems: 'center', 188 | marginBottom: 10 189 | }, 190 | smallTitleStyle: { 191 | fontSize: 14, 192 | color: '#999', 193 | marginTop: 30 194 | }, 195 | bigTitleStyle: { 196 | fontSize: 30, 197 | color: 'red', 198 | fontWeight: '500', 199 | marginVertical: 20 200 | }, 201 | itemContainerStyle: { 202 | backgroundColor: '#fff', 203 | height: 44, 204 | borderBottomWidth: 1, 205 | borderBottomColor: '#dbdbdb', 206 | flexDirection: 'row', 207 | alignItems: 'center', 208 | paddingHorizontal: 15, 209 | justifyContent: 'space-between' 210 | }, 211 | iconStyle: { 212 | fontFamily: 'iconfont', 213 | fontSize: 12, 214 | color: '#666' 215 | }, 216 | logoutViewStyle: { 217 | marginHorizontal: 15, 218 | height: 44, 219 | marginTop: 20, 220 | backgroundColor: '#FF236F', 221 | borderRadius: 4, 222 | alignItems: 'center', 223 | justifyContent: 'center' 224 | }, 225 | logoutTextStyle: { 226 | justifyContent: 'center', 227 | alignItems: 'center', 228 | fontSize: 20, 229 | color: '#fff', 230 | } 231 | }); 232 | -------------------------------------------------------------------------------- /app/mine/OrderItemList.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/29. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | SectionList, 12 | TouchableOpacity 13 | } from 'react-native'; 14 | 15 | import NavigationBar from '../common/NavBarCommon' 16 | import ApplyDetail from '../apply/ApplyDetail' 17 | 18 | import Spinner from 'react-native-loading-spinner-overlay' 19 | let config = require('../common/Config') 20 | let request = require('../common/Request') 21 | let someStore = require('../common/RNAsyncStorage') 22 | let storage = someStore.storage 23 | let that 24 | export default class OrderItemList extends Component { 25 | constructor(props) { 26 | super(props) 27 | that = this 28 | this.state = { 29 | totalList:[], // 数据源 30 | visible: false 31 | } 32 | } 33 | componentDidMount() { 34 | this._loadStorageData() 35 | } 36 | /** 37 | * 跳转分期详情页面 38 | */ 39 | _pushNav(orderId,rowData) { 40 | alert('去列表跳跳看噢') 41 | // this.props.navigator.push({ 42 | // component: ApplyDetail, 43 | // title:'', 44 | // params: { 45 | // orderId:orderId, 46 | // rowData: rowData 47 | // } 48 | // }) 49 | } 50 | render() { 51 | return ( 52 | 53 | this._popNav()}/> 57 | 68 | 73 | 74 | ); 75 | } 76 | /** 77 | * 指定刷新位置,减少重新渲染开销 78 | */ 79 | _keyExtractor = (item,index) => index 80 | /** 81 | * 分组section组件 82 | */ 83 | _sectionComp = ({section}) => { 84 | return ( 85 | 86 | {section.title} 87 | {`¥${section.totalAmount}`} 88 | 89 | ) 90 | } 91 | /** 92 | * 单个Cell组件 93 | */ 94 | _renderItem = ({item}) => { 95 | var formateDate = item.AddTime.split('T')[0] 96 | return ( 97 | this._pushNav(item.OrderId,item)}> 98 | 99 | 100 | {item.ProductName} 101 | {`¥ ${item.AmountApp}`} 102 | 103 | 104 | {item.PatientName} 105 | {formateDate} 106 | 107 | 108 | 109 | ) 110 | } 111 | /** 112 | * 行内分割线 113 | */ 114 | _itemSeparatorComponent() { 115 | return ( 116 | 117 | ) 118 | } 119 | /** 120 | * 下拉刷新 121 | */ 122 | _refreshing() { 123 | 124 | } 125 | /** 126 | * 加载更多 127 | */ 128 | _loadMore(loginData) { 129 | let accessToken = loginData.Token.authorization 130 | let worker = loginData.Token.worker 131 | let productDetailURL = `${config.api.base}${config.api.DetailItemList}` 132 | var headers = { 133 | 'Content-Type': 'application/json', 134 | 'Authorization': accessToken, 135 | 'Worker': worker, 136 | 'ChannelId': '1000005', 137 | 'Hospital': '130670' 138 | } 139 | var params = { 140 | pageSize: 20, 141 | pageIndex: 1 142 | } 143 | that._showHud(true) 144 | request.get(productDetailURL,params,headers) 145 | .then((data) => { 146 | console.log(data) 147 | that._showHud(false) 148 | that._dealWithResData(data) 149 | }) 150 | .catch((error) => { 151 | that._showHud(false) 152 | console.log(error) 153 | }) 154 | } 155 | /** 156 | * 接口返回的数据进行分组处理 157 | */ 158 | _dealWithResData(result) { 159 | var titleList = [] // 分组标题 160 | var sectionDic = {} // 分组标题数据绑定 161 | var totalAmountList = [] // 分组标题金额 162 | result.Items.forEach(item => { 163 | var keyStr = item.AddTime.split('T')[0].split('-')[1]; 164 | keyStr = `${keyStr}月` 165 | if (titleList.indexOf(keyStr) > -1) { 166 | var list = sectionDic.keyStr 167 | list.push(item.List) 168 | } else { 169 | titleList.push(keyStr) 170 | var itemList = item.List 171 | sectionDic[keyStr] = itemList 172 | totalAmountList.push(item.AmountTotal) 173 | } 174 | }); 175 | console.log("sectionDict:",sectionDic); 176 | var tempTotalList = [] 177 | titleList.forEach((item,idx) => { 178 | var tempList = sectionDic[item] 179 | var total = totalAmountList[idx] 180 | var tempTitle = item; 181 | var arrItem = { 182 | title: tempTitle, 183 | data: tempList, 184 | key: idx, 185 | totalAmount: total 186 | }; 187 | tempTotalList.push(arrItem); 188 | }) 189 | this.setState({ 190 | totalList: tempTotalList 191 | }) 192 | console.log('TotalList:',tempTotalList); 193 | } 194 | /** 195 | * 读取本地化登录数据 196 | */ 197 | _loadStorageData() { 198 | storage.load({ 199 | key:'loginState', 200 | id: 1001 201 | }).then((data) => { 202 | that._loadMore(data) 203 | }).catch((error) => { 204 | 205 | }) 206 | } 207 | /** 208 | * 导航返回 209 | */ 210 | _popNav(){ 211 | this.props.navigator.pop() 212 | } 213 | /** 214 | * 显示隐藏HUD 215 | */ 216 | _showHud(show) { 217 | this.setState({ 218 | visible: show 219 | }) 220 | } 221 | } 222 | 223 | const styles = StyleSheet.create({ 224 | container: { 225 | flex: 1, 226 | backgroundColor: '#f4f7fe' 227 | }, 228 | sectionHeaderStyle: { 229 | backgroundColor: '#f4f7fe', 230 | height: 30, 231 | flexDirection: 'row', 232 | justifyContent: 'space-between', 233 | paddingHorizontal: 15, 234 | alignItems: 'center' 235 | }, 236 | sectionTextStyle: { 237 | fontSize: 14, 238 | color: '#666' 239 | }, 240 | itemContainerStyle: { 241 | backgroundColor: '#fff', 242 | height: 70, 243 | paddingHorizontal: 15 244 | }, 245 | topViewStyle: { 246 | flexDirection:'row', 247 | justifyContent: 'space-between', 248 | alignItems: 'center', 249 | marginTop: 12, 250 | }, 251 | bottomViewStyle: { 252 | flexDirection:'row', 253 | justifyContent: 'space-between', 254 | alignItems: 'center', 255 | marginTop: 10, 256 | }, 257 | topLeftTextStyle: { 258 | fontSize: 16, 259 | color: '#333' 260 | }, 261 | topRightTextStyle: { 262 | fontSize: 14, 263 | color: '#666' 264 | }, 265 | bottomLeftTextStyle: { 266 | fontSize: 14, 267 | color: '#666' 268 | }, 269 | bottomRightTextStyle: { 270 | fontSize: 16, 271 | color: '#333' 272 | } 273 | }); 274 | -------------------------------------------------------------------------------- /app/mine/SetRate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/29. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | Image, 12 | TouchableOpacity 13 | } from 'react-native'; 14 | 15 | import Picker from 'react-native-picker' 16 | import Toast, {DURATION} from 'react-native-easy-toast' 17 | import Spinner from 'react-native-loading-spinner-overlay' 18 | import NavigationBar from '../common/NavBarCommon' 19 | 20 | var _ = require('lodash') 21 | let config = require('../common/Config') 22 | let request = require('../common/Request') 23 | let someStore = require('../common/RNAsyncStorage') 24 | let storage = someStore.storage 25 | let that 26 | const pickerData = ['诊所承担','客户承担','诊所客户各承担一半'] 27 | export default class SetRate extends Component { 28 | constructor(props) { 29 | super(props) 30 | that = this 31 | this.state = { 32 | visible: false, 33 | itemArray: [], 34 | loginData: '' 35 | } 36 | } 37 | componentDidMount() { 38 | this._loadStorageData() 39 | } 40 | render() { 41 | return ( 42 | 43 | this._popNav()}/> 47 | {this._renderAllItem()} 48 | 53 | 57 | 58 | ); 59 | } 60 | /** 61 | * 渲染所有Item 62 | */ 63 | _renderAllItem() { 64 | let itemArr = [] 65 | this.state.itemArray.forEach((item,idx) => { 66 | var title = `${item.Num}期` 67 | var detail = pickerData[item.InterestAssumeType] 68 | itemArr.push( 69 | 72 | this._pickerSelectedAction(item,idx)}> 75 | 76 | {title} 77 | {detail} 78 | 79 | 80 | 81 | 82 | ) 83 | }) 84 | return itemArr 85 | } 86 | /** 87 | * 设置利息承担比例 88 | */ 89 | _fetchSetInstrument(itemData) { 90 | let accessToken = this.state.loginData.Token.authorization 91 | let worker = this.state.loginData.Token.worker 92 | let setInstrumentURL = `${config.api.base}${config.api.setInstrument}` 93 | var headers = { 94 | 'Content-Type': 'application/json', 95 | 'Authorization': accessToken, 96 | 'Worker': worker, 97 | 'ChannelId': '1000005', 98 | 'Hospital': '130670' 99 | } 100 | var rateName = pickerData[itemData.InterestAssumeType] 101 | var params = _.extend(itemData,{ 102 | rateName:rateName 103 | }) 104 | var body = { 105 | InterestAssumeList: [params] 106 | } 107 | this._showHud(true) 108 | request.post(setInstrumentURL,body,headers) 109 | .then((data) => { 110 | console.log(data) 111 | this._showHud(false) 112 | if (data && data.status == 200) { 113 | that.refs.toast.show('设置成功',300) 114 | } else { 115 | that.refs.toast.show(data.json(),300) 116 | } 117 | }) 118 | .catch((error) => { 119 | console.log(error) 120 | this._showHud(false) 121 | }) 122 | } 123 | /** 124 | * 获取利息承担比例设置 125 | */ 126 | _fetchInstrumentSet(loginData) { 127 | let accessToken = loginData.Token.authorization 128 | let worker = loginData.Token.worker 129 | let instrumentSetURL = `${config.api.base}${config.api.getInstrumentSet}` 130 | var headers = { 131 | 'Content-Type': 'application/json', 132 | 'Authorization': accessToken, 133 | 'Worker': worker, 134 | 'ChannelId': '1000005', 135 | 'Hospital': '130670' 136 | } 137 | this._showHud(true) 138 | request.get(instrumentSetURL,null,headers) 139 | .then((data) => { 140 | console.log(data) 141 | that.setState({ 142 | itemArray: data 143 | }) 144 | that._showHud(false) 145 | }) 146 | .catch((error) => { 147 | console.log(error) 148 | that._showHud(false) 149 | }) 150 | } 151 | /** 152 | * 读取本地化登录数据 153 | */ 154 | _loadStorageData() { 155 | storage.load({ 156 | key:'loginState', 157 | id: 1001 158 | }).then((data) => { 159 | that.setState({ 160 | loginData: data 161 | }) 162 | that._fetchInstrumentSet(data) 163 | }).catch((error) => { 164 | 165 | }) 166 | } 167 | /** 168 | * 选择器事件 169 | */ 170 | _pickerSelectedAction(data,index) { 171 | let tempData = data 172 | Picker.init({ 173 | pickerData: pickerData, 174 | selectedValue: [pickerData[tempData.InterestAssumeType]], 175 | pickerConfirmBtnText:'确认', 176 | pickerCancelBtnText:'取消', 177 | pickerTitleText:'请选择', 178 | pickerConfirmBtnColor: [96,91,245,1], 179 | pickerCancelBtnColor: [96,91,245,1], 180 | pickerRowHeight: 40, 181 | onPickerConfirm: pickerValue => { 182 | let selectIndex = this._fetchIndexOfValue(pickerValue[0],pickerData) 183 | tempData.InterestAssumeType = selectIndex 184 | var tempArr = this.state.itemArray 185 | // 数组元素替换 186 | tempArr.splice(index,1,tempData) 187 | that.setState({ 188 | itemArray: tempArr 189 | }) 190 | that._fetchSetInstrument(tempData) 191 | }, 192 | onPickerCancel: pickerValue => { 193 | 194 | }, 195 | onPickerSelect: pickerValue => { 196 | 197 | } 198 | }) 199 | Picker.show() 200 | } 201 | /** 202 | * 遍历数组查找元素下标 203 | */ 204 | _fetchIndexOfValue(value,array) { 205 | for (let i = 0; i < array.length; i++) { 206 | if (array[i] == value) { 207 | return i 208 | } 209 | } 210 | return -1 211 | } 212 | /** 213 | * 导航返回 214 | */ 215 | _popNav(){ 216 | this.props.navigator.pop() 217 | } 218 | /** 219 | * hud显示隐藏 220 | */ 221 | _showHud(show) { 222 | this.setState({ 223 | visible: show 224 | }) 225 | } 226 | } 227 | 228 | const styles = StyleSheet.create({ 229 | container: { 230 | flex: 1, 231 | backgroundColor: '#f4f7fe' 232 | }, 233 | itemContainerStyle: { 234 | height: 44, 235 | backgroundColor: '#fff', 236 | flexDirection: 'row', 237 | alignItems: 'center', 238 | justifyContent: 'space-between', 239 | paddingHorizontal: 15, 240 | borderBottomWidth: 1, 241 | borderBottomColor: '#dbdbdb' 242 | }, 243 | leftItemStyle: { 244 | flexDirection: 'row', 245 | alignItems: 'center', 246 | flex: 1, 247 | justifyContent: 'space-between', 248 | marginRight: 8 249 | }, 250 | iconStyle: { 251 | fontFamily: 'iconfont', 252 | fontSize: 12, 253 | color: '#666', 254 | position: 'absolute', 255 | right: 15 256 | }, 257 | textStyle: { 258 | fontSize: 16 259 | } 260 | 261 | }); 262 | -------------------------------------------------------------------------------- /app/navigator/Navigator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/28. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | NavigatorIOS 12 | } from 'react-native'; 13 | 14 | import TabBar from '../navigator/TabBar' 15 | import Login from '../login/Login' 16 | import LaunchView from '../login/LaunchView' 17 | 18 | export default class Navigator extends Component { 19 | render() { 20 | return ( 21 | 34 | ); 35 | } 36 | } 37 | 38 | const styles = StyleSheet.create({ 39 | pageStyle: { 40 | flex: 1 41 | } 42 | }); 43 | -------------------------------------------------------------------------------- /app/navigator/TabBar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Ryan on 2018/5/28. 3 | */ 4 | 5 | import React, { Component } from 'react'; 6 | import { 7 | AppRegistry, 8 | StyleSheet, 9 | Text, 10 | View, 11 | Dimensions, 12 | Platform, 13 | Image 14 | } from 'react-native'; 15 | 16 | const {width,height} = Dimensions.get('window') 17 | import TabNavigator from 'react-native-tab-navigator' 18 | 19 | import Home from '../home/HomeTab' 20 | import ApplyList from '../apply/ApplyTab' 21 | import Mine from '../mine/MineTab' 22 | 23 | export default class TabBar extends Component { 24 | constructor(props) { 25 | super(props) 26 | this.state = { 27 | selectedTab: 'home', 28 | tabBarHeight: 49 29 | } 30 | } 31 | render() { 32 | return ( 33 | 34 | 39 | {/*首页*/} 40 | { 41 | this._renderTabBarItem( 42 | '爱牙分期', 43 | '', 44 | '', 45 | 'home', 46 | Home) 47 | } 48 | {/*分期申请列表*/} 49 | { 50 | this._renderTabBarItem( 51 | '申请', 52 | require('../images/board.png'), 53 | require('../images/board-actived.png'), 54 | 'apply', 55 | ApplyList) 56 | } 57 | {/*分期管理*/} 58 | { 59 | this._renderTabBarItem( 60 | '分期管理', 61 | require('../images/profile.png'), 62 | require('../images/profile-actived.png'), 63 | 'mine', 64 | Mine) 65 | } 66 | 67 | 68 | ); 69 | } 70 | /** 71 | * 抽取每个tabBarItem 72 | */ 73 | _renderTabBarItem(title,iconName,selectedIconName,selectedTab,component) { 74 | var name = '' 75 | return ( 76 | this._renderNormalItemIcon(title)} 80 | renderSelectedIcon={() => this._renderSelectedItemIcon(title)} 81 | titleStyle={styles.tabText} 82 | selectedTitleStyle={styles.selectedTabText} 83 | onPress={() => this.setState({ selectedTab: selectedTab })}> 84 | { 85 | this._renderItemPage(title) 86 | } 87 | 88 | ) 89 | } 90 | /** 91 | * 普通状态Icon 92 | */ 93 | _renderNormalItemIcon(title) { 94 | if (title == '爱牙分期') { 95 | return 96 | } else if (title == '申请') { 97 | return 98 | } else { 99 | return 100 | } 101 | } 102 | /** 103 | * 选中状态Icon 104 | */ 105 | _renderSelectedItemIcon(title) { 106 | if (title == '爱牙分期') { 107 | return 108 | } else if (title == '申请') { 109 | return 110 | } else { 111 | return 112 | } 113 | } 114 | 115 | /** 116 | * 渲染Tab页面 117 | */ 118 | _renderItemPage(title) { 119 | if (title == '爱牙分期') { 120 | return ( 121 | 123 | ) 124 | } else if (title == '申请') { 125 | return ( 126 | 128 | ) 129 | } else { 130 | return ( 131 | 133 | ) 134 | } 135 | } 136 | } 137 | const styles = StyleSheet.create({ 138 | container: { 139 | flex: 1, 140 | }, 141 | tabText: { 142 | color:'#999', 143 | fontSize:14 144 | }, 145 | selectedTabText: { 146 | color:'#605bf5' 147 | }, 148 | iconFontStyle: { 149 | fontFamily: 'iconfont', 150 | fontSize: 24, 151 | color: '#999' 152 | }, 153 | tabBar: { 154 | backgroundColor: '#fff' 155 | }, 156 | 157 | }); 158 | 159 | -------------------------------------------------------------------------------- /assets/fonts/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zouyajun/react-native-AyInstalment/6415c8d9cfe41726de6c749f6a6d3e201aca29d2/assets/fonts/iconfont.ttf -------------------------------------------------------------------------------- /index.android.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from 'react'; 8 | import { 9 | AppRegistry, 10 | StyleSheet, 11 | Text, 12 | View 13 | } from 'react-native'; 14 | 15 | export default class RNAYInstalment extends Component { 16 | render() { 17 | return ( 18 | 19 | 20 | Welcome to React Native! 21 | 22 | 23 | To get started, edit index.android.js 24 | 25 | 26 | Double tap R on your keyboard to reload,{'\n'} 27 | Shake or press menu button for dev menu 28 | 29 | 30 | ); 31 | } 32 | } 33 | 34 | const styles = StyleSheet.create({ 35 | container: { 36 | flex: 1, 37 | justifyContent: 'center', 38 | alignItems: 'center', 39 | backgroundColor: '#F5FCFF', 40 | }, 41 | welcome: { 42 | fontSize: 20, 43 | textAlign: 'center', 44 | margin: 10, 45 | }, 46 | instructions: { 47 | textAlign: 'center', 48 | color: '#333333', 49 | marginBottom: 5, 50 | }, 51 | }); 52 | 53 | AppRegistry.registerComponent('RNAYInstalment', () => RNAYInstalment); 54 | -------------------------------------------------------------------------------- /index.ios.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from 'react'; 8 | import { 9 | AppRegistry, 10 | StyleSheet, 11 | Text, 12 | View 13 | } from 'react-native'; 14 | 15 | import App from './app/App' 16 | 17 | export default class RNAYInstalment extends Component { 18 | render() { 19 | return ( 20 | 21 | ); 22 | } 23 | } 24 | AppRegistry.registerComponent('RNAYInstalment', () => RNAYInstalment); 25 | -------------------------------------------------------------------------------- /ios/RNAYInstalment-tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UIViewControllerBasedStatusBarAppearance 38 | 39 | NSLocationWhenInUseUsageDescription 40 | 41 | NSAppTransportSecurity 42 | 43 | 44 | NSExceptionDomains 45 | 46 | localhost 47 | 48 | NSExceptionAllowsInsecureHTTPLoads 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /ios/RNAYInstalment-tvOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/RNAYInstalment.xcodeproj/xcshareddata/xcschemes/RNAYInstalment-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /ios/RNAYInstalment.xcodeproj/xcshareddata/xcschemes/RNAYInstalment.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /ios/RNAYInstalment/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ios/RNAYInstalment/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import 13 | #import 14 | 15 | @implementation AppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 18 | { 19 | NSURL *jsCodeLocation; 20 | 21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; 22 | 23 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 24 | moduleName:@"RNAYInstalment" 25 | initialProperties:nil 26 | launchOptions:launchOptions]; 27 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 28 | 29 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 30 | UIViewController *rootViewController = [UIViewController new]; 31 | rootViewController.view = rootView; 32 | self.window.rootViewController = rootViewController; 33 | [self.window makeKeyAndVisible]; 34 | return YES; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /ios/RNAYInstalment/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /ios/RNAYInstalment/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /ios/RNAYInstalment/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIAppFonts 6 | 7 | iconfont.ttf 8 | 9 | CFBundleDevelopmentRegion 10 | en 11 | CFBundleDisplayName 12 | RNAYInstalment 13 | CFBundleExecutable 14 | $(EXECUTABLE_NAME) 15 | CFBundleIdentifier 16 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 17 | CFBundleInfoDictionaryVersion 18 | 6.0 19 | CFBundleName 20 | $(PRODUCT_NAME) 21 | CFBundlePackageType 22 | APPL 23 | CFBundleShortVersionString 24 | 1.0 25 | CFBundleSignature 26 | ???? 27 | CFBundleVersion 28 | 1 29 | LSRequiresIPhoneOS 30 | 31 | UILaunchStoryboardName 32 | LaunchScreen 33 | UIRequiredDeviceCapabilities 34 | 35 | armv7 36 | 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | 43 | UIViewControllerBasedStatusBarAppearance 44 | 45 | NSLocationWhenInUseUsageDescription 46 | 47 | NSAppTransportSecurity 48 | 49 | NSAllowsArbitraryLoads 50 | 51 | NSExceptionDomains 52 | 53 | localhost 54 | 55 | NSExceptionAllowsInsecureHTTPLoads 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /ios/RNAYInstalment/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ios/RNAYInstalmentTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/RNAYInstalmentTests/RNAYInstalmentTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | #import 12 | 13 | #import 14 | #import 15 | 16 | #define TIMEOUT_SECONDS 600 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface RNAYInstalmentTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation RNAYInstalmentTests 24 | 25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 26 | { 27 | if (test(view)) { 28 | return YES; 29 | } 30 | for (UIView *subview in [view subviews]) { 31 | if ([self findSubviewInView:subview matching:test]) { 32 | return YES; 33 | } 34 | } 35 | return NO; 36 | } 37 | 38 | - (void)testRendersWelcomeScreen 39 | { 40 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 42 | BOOL foundElement = NO; 43 | 44 | __block NSString *redboxError = nil; 45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 46 | if (level >= RCTLogLevelError) { 47 | redboxError = message; 48 | } 49 | }); 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | RCTSetLogFunction(RCTDefaultLogFunction); 64 | 65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 67 | } 68 | 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RNAYInstalment", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start", 7 | "test": "jest" 8 | }, 9 | "dependencies": { 10 | "lodash": "^4.17.10", 11 | "query-string": "^6.1.0", 12 | "react": "16.0.0-alpha.6", 13 | "react-native": "0.44.0", 14 | "react-native-app-intro": "^1.1.5", 15 | "react-native-easy-toast": "^1.1.0", 16 | "react-native-gesture-handler": "^1.0.3", 17 | "react-native-image-zoom-viewer": "^2.2.5", 18 | "react-native-loading-spinner-overlay": "^0.3.0", 19 | "react-native-picker": "^4.3.7", 20 | "react-native-scrollable-tab-view": "^0.8.0", 21 | "react-native-simple-picker": "^2.1.0", 22 | "react-native-storage": "^0.2.2", 23 | "react-native-swiper": "^1.5.13", 24 | "react-native-tab-navigator": "^0.3.4", 25 | "react-native-tab-view": "^0.0.78" 26 | }, 27 | "devDependencies": { 28 | "babel-jest": "23.0.1", 29 | "babel-preset-react-native": "4.0.0", 30 | "jest": "23.0.1", 31 | "react-test-renderer": "16.0.0-alpha.6" 32 | }, 33 | "jest": { 34 | "preset": "react-native" 35 | } 36 | } 37 | --------------------------------------------------------------------------------