├── .editorconfig
├── .gitignore
├── README.md
├── config.xml
├── ionic.config.json
├── package.json
├── resources
├── android
│ ├── icon
│ │ ├── drawable-hdpi-icon.png
│ │ ├── drawable-ldpi-icon.png
│ │ ├── drawable-mdpi-icon.png
│ │ ├── drawable-xhdpi-icon.png
│ │ ├── drawable-xxhdpi-icon.png
│ │ └── drawable-xxxhdpi-icon.png
│ └── splash
│ │ ├── drawable-land-hdpi-screen.png
│ │ ├── drawable-land-ldpi-screen.png
│ │ ├── drawable-land-mdpi-screen.png
│ │ ├── drawable-land-xhdpi-screen.png
│ │ ├── drawable-land-xxhdpi-screen.png
│ │ ├── drawable-land-xxxhdpi-screen.png
│ │ ├── drawable-port-hdpi-screen.png
│ │ ├── drawable-port-ldpi-screen.png
│ │ ├── drawable-port-mdpi-screen.png
│ │ ├── drawable-port-xhdpi-screen.png
│ │ ├── drawable-port-xxhdpi-screen.png
│ │ └── drawable-port-xxxhdpi-screen.png
├── icon.png
├── ios
│ ├── icon
│ │ ├── icon-40.png
│ │ ├── icon-40@2x.png
│ │ ├── icon-40@3x.png
│ │ ├── icon-50.png
│ │ ├── icon-50@2x.png
│ │ ├── icon-60.png
│ │ ├── icon-60@2x.png
│ │ ├── icon-60@3x.png
│ │ ├── icon-72.png
│ │ ├── icon-72@2x.png
│ │ ├── icon-76.png
│ │ ├── icon-76@2x.png
│ │ ├── icon-83.5@2x.png
│ │ ├── icon-small.png
│ │ ├── icon-small@2x.png
│ │ ├── icon-small@3x.png
│ │ ├── icon.png
│ │ └── icon@2x.png
│ └── splash
│ │ ├── Default-568h@2x~iphone.png
│ │ ├── Default-667h.png
│ │ ├── Default-736h.png
│ │ ├── Default-Landscape-736h.png
│ │ ├── Default-Landscape@2x~ipad.png
│ │ ├── Default-Landscape@~ipadpro.png
│ │ ├── Default-Landscape~ipad.png
│ │ ├── Default-Portrait@2x~ipad.png
│ │ ├── Default-Portrait@~ipadpro.png
│ │ ├── Default-Portrait~ipad.png
│ │ ├── Default@2x~iphone.png
│ │ └── Default~iphone.png
└── splash.png
├── src
├── app
│ ├── app.component.ts
│ ├── app.html
│ ├── app.module.ts
│ ├── app.scss
│ └── main.ts
├── directive
│ ├── index.ts
│ └── tab.directive.ts
├── index.html
├── manifest.json
├── message
│ ├── collect.request.ts
│ ├── message.request.ts
│ ├── replies.request.ts
│ ├── topics.request.ts
│ └── user.request.ts
├── pages
│ ├── account
│ │ ├── account-collects.html
│ │ ├── account-collects.scss
│ │ ├── account-collects.ts
│ │ ├── account-messages.html
│ │ ├── account-messages.scss
│ │ ├── account-messages.ts
│ │ ├── account-topics.html
│ │ ├── account-topics.scss
│ │ ├── account-topics.ts
│ │ ├── account.html
│ │ ├── account.scss
│ │ ├── account.ts
│ │ └── index.ts
│ ├── home
│ │ ├── home-add.html
│ │ ├── home-add.scss
│ │ ├── home-add.ts
│ │ ├── home-detail.html
│ │ ├── home-detail.scss
│ │ ├── home-detail.ts
│ │ ├── home.html
│ │ ├── home.scss
│ │ ├── home.ts
│ │ └── index.ts
│ ├── login
│ │ ├── index.ts
│ │ ├── login.html
│ │ ├── login.scss
│ │ └── login.ts
│ └── user
│ │ ├── index.ts
│ │ ├── user.html
│ │ ├── user.scss
│ │ └── user.ts
├── pipe
│ ├── amAgoTime.pipe.ts
│ ├── index.ts
│ └── link.pipe.ts
├── service-worker.js
├── service
│ ├── collect.service.ts
│ ├── core.service.ts
│ ├── index.ts
│ ├── message.service.ts
│ ├── replies.service.ts
│ ├── topic.service.ts
│ ├── user.service.ts
│ └── util.service.ts
└── theme
│ └── variables.scss
├── tsconfig.json
└── tslint.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs
2 | # editorconfig.org
3 |
4 | root = true
5 |
6 | [*]
7 | indent_style = space
8 | indent_size = 2
9 |
10 | # We recommend you to keep these unchanged
11 | end_of_line = lf
12 | charset = utf-8
13 | trim_trailing_whitespace = true
14 | insert_final_newline = true
15 |
16 | [*.md]
17 | trim_trailing_whitespace = false
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Specifies intentionally untracked files to ignore when using Git
2 | # http://git-scm.com/docs/gitignore
3 |
4 | *~
5 | *.sw[mnpcod]
6 | *.log
7 | *.tmp
8 | *.tmp.*
9 | log.txt
10 | *.sublime-project
11 | *.sublime-workspace
12 | .vscode/
13 | npm-debug.log*
14 |
15 | .idea/
16 | .sass-cache/
17 | .tmp/
18 | .versions/
19 | coverage/
20 | dist/
21 | node_modules/
22 | tmp/
23 | temp/
24 | hooks/
25 | platforms/
26 | plugins/
27 | plugins/android.json
28 | plugins/ios.json
29 | www/
30 | $RECYCLE.BIN/
31 |
32 | .DS_Store
33 | Thumbs.db
34 | UserInterfaceState.xcuserstate
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 项目介绍
2 |
3 | 基于Ionic的[CNode中文论坛](https://cnodejs.org/ "CNode中文论坛")客户端,采用最新的Ionic 3.4.2 + Angular 4 + TypeScript 2.3
4 |
5 | # 前置条件
6 |
7 | node.js v6⬆️,ionic cli v3.4.0⬆️, cordova v7.0.1(可尝试降级使用)
8 |
9 | # 安装指南
10 |
11 | 0.npm install -g ionic cordova
12 |
13 | 1.git clone https://github.com/zxj963577494/Ionic2-CNodeClub.git
14 |
15 | 2.cd Ionic2-CNodeClub
16 |
17 | 3.npm install
18 |
19 | 4.ionic cordova platform add android/ios
20 |
21 | 5.ionic cordova build android/ios
22 |
23 | # 在浏览器中查看
24 |
25 | 0.npm install -g ionic cordova
26 |
27 | 1.git clone https://github.com/zxj963577494/Ionic2-CNodeClub.git
28 |
29 | 2.cd Ionic2-CNodeClub
30 |
31 | 3.npm install
32 |
33 | 4.ionic serve (windows可尝试使用 ```npm run ionic:serve```)
34 |
35 | # 下载地址
36 |
37 | 
38 |
39 | [Android](https://fir.im/k4qz "android") / [iOS(需越狱)](https://fir.im/9e6h "IOS")
40 |
41 |
42 | # 项目展示
43 |
44 | 
45 | 
46 | 
47 | 
48 | 
49 | 
50 | 
51 |
--------------------------------------------------------------------------------
/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | CNodeClub
4 | An awesome Ionic/Cordova app.
5 | Xujiang Zheng
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/ionic.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "CNodeClub",
3 | "app_id": "",
4 | "type": "ionic-angular"
5 | }
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "CNodeClub",
3 | "version": "0.0.1",
4 | "author": "Ionic Framework",
5 | "homepage": "http://ionicframework.com/",
6 | "private": true,
7 | "scripts": {
8 | "clean": "ionic-app-scripts clean",
9 | "build": "ionic-app-scripts build",
10 | "lint": "ionic-app-scripts lint",
11 | "ionic:build": "ionic-app-scripts build",
12 | "ionic:serve": "ionic-app-scripts serve"
13 | },
14 | "dependencies": {
15 | "@angular/common": "4.1.3",
16 | "@angular/compiler": "4.1.3",
17 | "@angular/compiler-cli": "4.1.3",
18 | "@angular/core": "4.1.3",
19 | "@angular/forms": "4.1.3",
20 | "@angular/http": "4.1.3",
21 | "@angular/platform-browser": "4.1.3",
22 | "@angular/platform-browser-dynamic": "4.1.3",
23 | "@ionic-native/app-version": "^3.12.1",
24 | "@ionic-native/badge": "^3.12.1",
25 | "@ionic-native/barcode-scanner": "^3.12.1",
26 | "@ionic-native/core": "3.10.2",
27 | "@ionic-native/in-app-browser": "^3.12.1",
28 | "@ionic-native/social-sharing": "^3.12.1",
29 | "@ionic-native/splash-screen": "3.10.2",
30 | "@ionic-native/status-bar": "3.10.2",
31 | "@ionic/storage": "2.0.1",
32 | "cordova-android": "^6.2.3",
33 | "cordova-ios": "^4.4.0",
34 | "cordova-plugin-app-version": "^0.1.9",
35 | "cordova-plugin-badge": "^0.8.1",
36 | "cordova-plugin-browsertab": "^0.2.0",
37 | "cordova-plugin-compat": "^1.1.0",
38 | "cordova-plugin-console": "^1.0.5",
39 | "cordova-plugin-device": "^1.1.4",
40 | "cordova-plugin-inappbrowser": "^1.7.1",
41 | "cordova-plugin-splashscreen": "^4.0.3",
42 | "cordova-plugin-statusbar": "^2.2.2",
43 | "cordova-plugin-whitelist": "^1.3.1",
44 | "cordova-plugin-x-socialsharing": "^5.1.8",
45 | "es6-promise-plugin": "^4.1.0",
46 | "ionic-angular": "3.4.2",
47 | "ionic-plugin-keyboard": "^2.2.1",
48 | "ionicons": "3.0.0",
49 | "phonegap-plugin-barcodescanner": "^6.0.6",
50 | "rxjs": "5.4.0",
51 | "sw-toolbox": "3.6.0",
52 | "zone.js": "0.8.12"
53 | },
54 | "devDependencies": {
55 | "@ionic/app-scripts": "1.3.7",
56 | "@ionic/cli-plugin-cordova": "1.4.0",
57 | "@ionic/cli-plugin-ionic-angular": "1.3.1",
58 | "typescript": "2.3.3"
59 | },
60 | "description": "An Ionic project",
61 | "cordova": {
62 | "plugins": {
63 | "cordova-plugin-console": {},
64 | "cordova-plugin-device": {},
65 | "cordova-plugin-splashscreen": {},
66 | "cordova-plugin-statusbar": {},
67 | "cordova-plugin-whitelist": {},
68 | "ionic-plugin-keyboard": {},
69 | "cordova-plugin-app-version": {},
70 | "cordova-plugin-badge": {},
71 | "phonegap-plugin-barcodescanner": {
72 | "CAMERA_USAGE_DESCRIPTION": " "
73 | },
74 | "cordova-plugin-inappbrowser": {},
75 | "cordova-plugin-x-socialsharing": {}
76 | },
77 | "platforms": [
78 | "android",
79 | "ios"
80 | ]
81 | }
82 | }
--------------------------------------------------------------------------------
/resources/android/icon/drawable-hdpi-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/icon/drawable-hdpi-icon.png
--------------------------------------------------------------------------------
/resources/android/icon/drawable-ldpi-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/icon/drawable-ldpi-icon.png
--------------------------------------------------------------------------------
/resources/android/icon/drawable-mdpi-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/icon/drawable-mdpi-icon.png
--------------------------------------------------------------------------------
/resources/android/icon/drawable-xhdpi-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/icon/drawable-xhdpi-icon.png
--------------------------------------------------------------------------------
/resources/android/icon/drawable-xxhdpi-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/icon/drawable-xxhdpi-icon.png
--------------------------------------------------------------------------------
/resources/android/icon/drawable-xxxhdpi-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/icon/drawable-xxxhdpi-icon.png
--------------------------------------------------------------------------------
/resources/android/splash/drawable-land-hdpi-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/splash/drawable-land-hdpi-screen.png
--------------------------------------------------------------------------------
/resources/android/splash/drawable-land-ldpi-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/splash/drawable-land-ldpi-screen.png
--------------------------------------------------------------------------------
/resources/android/splash/drawable-land-mdpi-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/splash/drawable-land-mdpi-screen.png
--------------------------------------------------------------------------------
/resources/android/splash/drawable-land-xhdpi-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/splash/drawable-land-xhdpi-screen.png
--------------------------------------------------------------------------------
/resources/android/splash/drawable-land-xxhdpi-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/splash/drawable-land-xxhdpi-screen.png
--------------------------------------------------------------------------------
/resources/android/splash/drawable-land-xxxhdpi-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/splash/drawable-land-xxxhdpi-screen.png
--------------------------------------------------------------------------------
/resources/android/splash/drawable-port-hdpi-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/splash/drawable-port-hdpi-screen.png
--------------------------------------------------------------------------------
/resources/android/splash/drawable-port-ldpi-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/splash/drawable-port-ldpi-screen.png
--------------------------------------------------------------------------------
/resources/android/splash/drawable-port-mdpi-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/splash/drawable-port-mdpi-screen.png
--------------------------------------------------------------------------------
/resources/android/splash/drawable-port-xhdpi-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/splash/drawable-port-xhdpi-screen.png
--------------------------------------------------------------------------------
/resources/android/splash/drawable-port-xxhdpi-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/splash/drawable-port-xxhdpi-screen.png
--------------------------------------------------------------------------------
/resources/android/splash/drawable-port-xxxhdpi-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/android/splash/drawable-port-xxxhdpi-screen.png
--------------------------------------------------------------------------------
/resources/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/icon.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-40.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-40@2x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-40@3x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-50.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-50@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-50@2x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-60.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-60@2x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-60@3x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-72.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-72@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-72@2x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-76.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-76@2x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-83.5@2x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-small.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-small@2x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon-small@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon-small@3x.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon.png
--------------------------------------------------------------------------------
/resources/ios/icon/icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/icon/icon@2x.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-568h@2x~iphone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/splash/Default-568h@2x~iphone.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-667h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/splash/Default-667h.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-736h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/splash/Default-736h.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-Landscape-736h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/splash/Default-Landscape-736h.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-Landscape@2x~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/splash/Default-Landscape@2x~ipad.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-Landscape@~ipadpro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/splash/Default-Landscape@~ipadpro.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-Landscape~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/splash/Default-Landscape~ipad.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-Portrait@2x~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/splash/Default-Portrait@2x~ipad.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-Portrait@~ipadpro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/splash/Default-Portrait@~ipadpro.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default-Portrait~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/splash/Default-Portrait~ipad.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default@2x~iphone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/splash/Default@2x~iphone.png
--------------------------------------------------------------------------------
/resources/ios/splash/Default~iphone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/ios/splash/Default~iphone.png
--------------------------------------------------------------------------------
/resources/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zxj963577494/Ionic2-CNodeClub/692cee0f9ee0c9185fca790c43d54b045e793864/resources/splash.png
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewChild } from '@angular/core';
2 | import { Nav, Platform } from 'ionic-angular';
3 | import { StatusBar } from '@ionic-native/status-bar';
4 | import { SplashScreen } from '@ionic-native/splash-screen';
5 | import { InAppBrowser } from '@ionic-native/in-app-browser';
6 |
7 | import { HomePage } from '../pages/home/home';
8 | import { UtilService } from '../service/util.service';
9 |
10 | @Component({
11 | templateUrl: 'app.html'
12 | })
13 | export class AppComponent {
14 | @ViewChild(Nav) nav: Nav;
15 |
16 | rootPage: any = HomePage;
17 |
18 | tabs: Array<{ key: string, value: string, icon: string }>;
19 |
20 | constructor(public platform: Platform, public statusBar: StatusBar, public splashScreen: SplashScreen, private iab: InAppBrowser, private utilService: UtilService) {
21 | this.initializeApp();
22 | this.getTabs();
23 | }
24 |
25 | initializeApp() {
26 | this.platform.ready().then(() => {
27 | // Okay, so the platform is ready and our plugins are available.
28 | // Here you can do any higher level native things you might need.
29 | this.statusBar.styleDefault();
30 | this.splashScreen.hide();
31 | });
32 | }
33 |
34 | getTabs() {
35 | this.tabs = this.utilService.getTabs();
36 | }
37 |
38 | openPage(key: string) {
39 | this.nav.setRoot(HomePage, { tab: key });
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/app/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 栏目
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { HttpModule } from '@angular/http';
2 | import { BrowserModule } from '@angular/platform-browser';
3 | import { ErrorHandler, NgModule } from '@angular/core';
4 | import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
5 | import { IonicStorageModule } from '@ionic/storage';
6 | import { FormsModule } from '@angular/forms';
7 |
8 | import { AppComponent } from './app.component';
9 | import { HomePage, HomeAddPage, HomeDetailPage } from '../pages/home/';
10 | import { LoginPage } from '../pages/login/';
11 | import { AccountPage, AccountCollectsPage, AccountMessagesPage, AccountTopicsPage } from '../pages/account/';
12 | import { UserPage } from '../pages/user/';
13 |
14 | import { StatusBar } from '@ionic-native/status-bar';
15 | import { SplashScreen } from '@ionic-native/splash-screen';
16 | import { InAppBrowser } from '@ionic-native/in-app-browser';
17 | import { Badge } from '@ionic-native/badge';
18 | import { SocialSharing } from '@ionic-native/social-sharing';
19 | import { AppVersion } from '@ionic-native/app-version';
20 | import { BarcodeScanner } from '@ionic-native/barcode-scanner';
21 |
22 | import { TopicService, MessageService, RepliesService, UserService, CollectService, CoreService, UtilService } from '../service/';
23 |
24 | import { TabDirective } from "../directive/";
25 | import { AmAgoTimePipe, LinkPipe } from '../pipe/'
26 |
27 | @NgModule({
28 | declarations: [
29 | AppComponent,
30 | HomePage,
31 | HomeAddPage,
32 | HomeDetailPage,
33 | LoginPage,
34 | AccountPage,
35 | UserPage,
36 | AccountCollectsPage,
37 | AccountMessagesPage,
38 | AccountTopicsPage,
39 | TabDirective,
40 | AmAgoTimePipe,
41 | LinkPipe
42 | ],
43 | imports: [
44 | BrowserModule,
45 | IonicModule.forRoot(AppComponent, {
46 | backButtonText: '',
47 | backButtonIcon: 'ios-arrow-back',
48 | pageTransition: 'ios-transition'
49 | }, {
50 | links: [
51 | { component: HomePage, name: 'Home', segment: 'home' },
52 | { component: HomePage, name: 'Home', segment: 'home/tab/:tab' },
53 | { component: HomeDetailPage, name: 'HomeDetail', segment: 'home/:id' },
54 | { component: HomeAddPage, name: 'HomeAdd', segment: 'home/add' },
55 | { component: UserPage, name: 'User', segment: 'user/:loginname' },
56 | { component: LoginPage, name: 'Login', segment: 'login' },
57 | { component: AccountPage, name: 'Account', segment: 'account' },
58 | { component: AccountCollectsPage, name: 'AccountCollects', segment: 'account/collects' },
59 | { component: AccountMessagesPage, name: 'AccountMessages', segment: 'account/messages' },
60 | { component: AccountTopicsPage, name: 'AccountTopics', segment: 'account/topics' }
61 | ]
62 | }),
63 | HttpModule,
64 | FormsModule,
65 | IonicStorageModule.forRoot()
66 | ],
67 | bootstrap: [IonicApp],
68 | entryComponents: [
69 | AppComponent,
70 | HomePage,
71 | HomeAddPage,
72 | HomeDetailPage,
73 | LoginPage,
74 | AccountPage,
75 | AccountCollectsPage,
76 | AccountMessagesPage,
77 | AccountTopicsPage,
78 | UserPage
79 | ],
80 | providers: [
81 | StatusBar,
82 | SplashScreen,
83 | Badge,
84 | InAppBrowser,
85 | SocialSharing,
86 | AppVersion,
87 | BarcodeScanner,
88 | { provide: ErrorHandler, useClass: IonicErrorHandler },
89 | TopicService,
90 | MessageService,
91 | RepliesService,
92 | TopicService,
93 | UserService,
94 | CollectService,
95 | CoreService,
96 | UtilService
97 | ]
98 | })
99 | export class AppModule { }
100 |
--------------------------------------------------------------------------------
/src/app/app.scss:
--------------------------------------------------------------------------------
1 | // http://ionicframework.com/docs/v2/theming/
2 |
3 |
4 | // App Global Sass
5 | // --------------------------------------------------
6 | // Put style rules here that you want to apply globally. These
7 | // styles are for the entire app and not just one component.
8 | // Additionally, this file can be also used as an entry point
9 | // to import other Sass files to be included in the output CSS.
10 | //
11 | // Shared Sass variables, which can be used to adjust Ionic's
12 | // default Sass variables, belong in "theme/variables.scss".
13 | //
14 | // To declare rules for a specific mode, create a child rule
15 | // for the .md, .ios, or .wp mode classes. The mode class is
16 | // automatically applied to the
element in the app.
17 |
18 | .list-avatar-page {
19 | ion-note {
20 | font-size: 12px;
21 | align-self: flex-start;
22 | margin-top: 14px;
23 | }
24 | }
--------------------------------------------------------------------------------
/src/app/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app.module';
4 |
5 | platformBrowserDynamic().bootstrapModule(AppModule);
6 |
--------------------------------------------------------------------------------
/src/directive/index.ts:
--------------------------------------------------------------------------------
1 | export * from './tab.directive';
--------------------------------------------------------------------------------
/src/directive/tab.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, ElementRef, Input } from '@angular/core';
2 |
3 | @Directive({ selector: '[tab]' })
4 | export class TabDirective {
5 | @Input('tab') set topic(topic: any) {
6 | this.setStyle(topic);
7 | }
8 |
9 | private el: HTMLElement;
10 | private tabMaps: Array<{key: string, value: string}> = [
11 | {
12 | key: 'all',
13 | value: '全部',
14 | },
15 | {
16 | key: 'good',
17 | value: '精华',
18 | },
19 | {
20 | key: 'share',
21 | value: '分享',
22 | },
23 | {
24 | key: 'ask',
25 | value: '问答',
26 | },
27 | {
28 | key: 'job',
29 | value: '招聘',
30 | },
31 | {
32 | key: 'dev',
33 | value: '客户端测试',
34 | }]
35 |
36 | constructor(el: ElementRef) {
37 | this.el = el.nativeElement;
38 | this.setStyle(this.topic);
39 | }
40 |
41 | private setStyle(topic) {
42 | if (topic) {
43 | this.el.style.borderRadius = '4px';
44 | if (topic.top) {
45 | this.el.textContent = '置顶';
46 | this.el.style.background = '#f53d3d';
47 | this.el.style.color = '#fff';
48 | }
49 | else if (topic.good && !topic.top) {
50 | this.el.textContent = '精华';
51 | this.el.style.background = '#3374de';
52 | this.el.style.color = '#fff';
53 | }
54 | else {
55 | this.el.textContent = this.getValue(topic.tab);
56 | this.el.style.background = '#e5e5e5';
57 | this.el.style.color = '#999';
58 | }
59 | }
60 | }
61 |
62 | private getValue(key: string): string {
63 | for(let item of this.tabMaps) {
64 | if (item.key === key) {
65 | return item.value;
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Ionic App
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Ionic",
3 | "short_name": "Ionic",
4 | "start_url": "index.html",
5 | "display": "standalone",
6 | "icons": [{
7 | "src": "assets/imgs/logo.png",
8 | "sizes": "512x512",
9 | "type": "image/png"
10 | }],
11 | "background_color": "#4e8ef7",
12 | "theme_color": "#4e8ef7"
13 | }
--------------------------------------------------------------------------------
/src/message/collect.request.ts:
--------------------------------------------------------------------------------
1 | export class PostCollectRequest {
2 | accesstoken: string;
3 | topic_id: string;
4 | }
5 |
6 | export class DeleteCollectRequest {
7 | accesstoken: string;
8 | topic_id: string;
9 | }
--------------------------------------------------------------------------------
/src/message/message.request.ts:
--------------------------------------------------------------------------------
1 | export class GetMessageCountRequest {
2 | accesstoken: string;
3 | }
4 |
5 | export class GetMessagesRequest {
6 | accesstoken: string;
7 | mdrender: boolean;
8 | }
9 |
10 | export class PutMessageMarkAllRequest {
11 | accesstoken: string;
12 | }
13 |
14 | export class PutMessageMarkOneRequest {
15 | accesstoken: string;
16 | }
--------------------------------------------------------------------------------
/src/message/replies.request.ts:
--------------------------------------------------------------------------------
1 | export class PostRepliesRequest {
2 | accesstoken: string;
3 | content: string;
4 | reply_id: string;
5 | }
6 |
7 | export class PutRepliesUpsRequest {
8 | accesstoken: string;
9 | }
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/message/topics.request.ts:
--------------------------------------------------------------------------------
1 | export class GetTopicsRequest {
2 | page: number;
3 | tab: string;
4 | limit: number;
5 | mdrender: boolean;
6 | }
7 |
8 | export class GetTopicDetailRequest {
9 | mdrender: boolean;
10 | accesstoken: string;
11 | }
12 |
13 | export class PostTopicsRequest {
14 | accesstoken: string;
15 | title: string;
16 | tab: string;
17 | content: string;
18 | }
19 |
20 | export class PutTopicsRequest {
21 | accesstoken: string;
22 | topic_id: string;
23 | title: string;
24 | tab: string;
25 | content: string;
26 | }
--------------------------------------------------------------------------------
/src/message/user.request.ts:
--------------------------------------------------------------------------------
1 | export class PostAccessTokenRequest {
2 | accesstoken: string;
3 | }
--------------------------------------------------------------------------------
/src/pages/account/account-collects.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | 我的收藏
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {{topic.title}}
17 | {{topic.last_reply_at|amAgoTime}}
18 |
19 |
20 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/pages/account/account-collects.scss:
--------------------------------------------------------------------------------
1 | page-account-collects {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/account/account-collects.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { IonicPage, NavController, NavParams } from 'ionic-angular';
3 |
4 | import { UtilService } from "../../service/util.service";
5 | import { CollectService } from "../../service/collect.service";
6 |
7 | @IonicPage()
8 | @Component({
9 | selector: 'page-account-collects',
10 | templateUrl: 'account-collects.html',
11 | })
12 | export class AccountCollectsPage implements OnInit {
13 | myCollects: any[];
14 | collectParams: any;
15 | user: any;
16 | collectCount: number;
17 |
18 | constructor(private navCtrl: NavController, private navParams: NavParams, private collectService: CollectService, private utilService: UtilService) {
19 | this.collectParams = {
20 | topic_id: '',
21 | accesstoken: ''
22 | }
23 | }
24 |
25 | getCollects() {
26 | this.collectService.getCollects(this.user.loginname).subscribe(
27 | (data) => {
28 | this.myCollects = data.data;
29 | this.collectCount = data.data.length;
30 | }
31 | )
32 | }
33 |
34 | remove(topic: any) {
35 | this.collectParams.topic_id = topic.id;
36 | this.collectParams.accesstoken = this.user.accesstoken;
37 | this.collectService.DeleteCollect(this.collectParams).subscribe(
38 | data => {
39 | if (data.success) {
40 | this.myCollects = this.myCollects.filter(item => item !== topic);
41 | this.utilService.toast('移除成功');
42 | }
43 | else {
44 | this.utilService.toast('移除失败');
45 | }
46 | });
47 | }
48 |
49 | ngOnInit() {
50 | this.utilService.getLoginStatus().then((data) => this.user = data).then(() => {
51 | if (this.user) {
52 | this.getCollects();
53 | } else {
54 | this.utilService.toast('请登录');
55 | }
56 | })
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/pages/account/account-messages.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 我的消息
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | 未读消息
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | {{message.topic.loginname}} 回复了你的话题
26 | {{message.topic.title}}
27 |
28 |
29 | {{message.topic.loginname}} 在话题
30 | {{message.topic.title}} 中@了你
31 |
32 |
33 |
34 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | 已读消息
45 |
46 |
47 |
48 |
49 |
50 |
51 | {{message.topic.loginname}} 回复了你的话题
52 | {{message.topic.title}}
53 |
54 |
55 |
56 | {{message.topic.loginname}} 在话题
57 | {{message.topic.title}} 中@了你
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/src/pages/account/account-messages.scss:
--------------------------------------------------------------------------------
1 | page-account-messages {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/account/account-messages.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { IonicPage, NavController, NavParams, Events } from 'ionic-angular';
3 | import { Badge } from '@ionic-native/badge';
4 |
5 | import { UtilService } from "../../service/util.service";
6 | import { MessageService } from "../../service/message.service";
7 | import { HomeDetailPage } from '../../pages/home/home-detail';
8 | import { UserPage } from '../../pages/user/user';
9 |
10 | @IonicPage()
11 | @Component({
12 | selector: 'page-account-messages',
13 | templateUrl: 'account-messages.html',
14 | })
15 | export class AccountMessagesPage implements OnInit {
16 | myMessages: any;
17 | messageParams: any;
18 | hasNotMessageCount: number;
19 | hasMessageCount: number;
20 | user: any;
21 |
22 | constructor(private navCtrl: NavController, private navParams: NavParams, private events: Events, private badge: Badge, private messageService: MessageService, private utilService: UtilService) {
23 | this.messageParams = {
24 | mdrender: true,
25 | accesstoken: ''
26 | }
27 | }
28 |
29 | getMessages() {
30 | this.messageParams.accesstoken = this.user.accesstoken
31 | this.messageService.GetMessages(this.messageParams).subscribe(
32 | (data) => {
33 | this.myMessages = data.data
34 | this.hasNotMessageCount = data.data.hasnot_read_messages.length;
35 | this.hasMessageCount = data.data.has_read_messages.length;
36 | }
37 | )
38 | }
39 |
40 | openTopic(id: string) {
41 | this.navCtrl.push(HomeDetailPage, { id: id });
42 | }
43 |
44 | openUser(loginname: string) {
45 | this.navCtrl.push(UserPage, { loginname: loginname });
46 | }
47 |
48 | markOne(message: any) {
49 | this.messageService.PutMessageMarkOne(message.id, { accesstoken: this.user.accesstoken }).subscribe(
50 | data => {
51 | if (data.success) {
52 | this.myMessages.hasnot_read_messages = this.myMessages.hasnot_read_messages.filter(item => item !== message);
53 | this.myMessages.has_read_messages.unshift(message);
54 | this.events.publish('messageCount', this.myMessages.hasnot_read_messages.length);
55 | this.badge.set(this.myMessages.hasnot_read_messages.length).then().catch(error => console.log(error));
56 | this.utilService.toast('操作成功');
57 | }
58 | });
59 | }
60 |
61 | markAll() {
62 | this.messageService.PutMessageMarkAll({ accesstoken: this.user.accesstoken }).subscribe(
63 | data => {
64 | if (data.success) {
65 | this.events.publish('messageCount', 0);
66 | this.badge.clear();
67 | this.utilService.toast('全部标记为已读成功');
68 | }
69 | });
70 | }
71 |
72 | ngOnInit() {
73 | this.utilService.getLoginStatus().then((data) => this.user = data).then(() => {
74 | if (this.user) {
75 | this.getMessages();
76 | } else {
77 | this.utilService.toast('请登录');
78 | }
79 | })
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/pages/account/account-topics.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 我的话题
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 最近创建的话题
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | {{topic.title}}
23 | {{topic.last_reply_at|amAgoTime}}
24 |
25 |
26 |
27 |
28 | 最近参与的话题
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | {{topic.title}}
38 | {{topic.last_reply_at|amAgoTime}}
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/pages/account/account-topics.scss:
--------------------------------------------------------------------------------
1 | page-account-topics {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/account/account-topics.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { IonicPage, NavController, NavParams } from 'ionic-angular';
3 |
4 | import { HomeDetailPage } from './../home/home-detail';
5 | import { UtilService } from "../../service/util.service";
6 | import { UserService } from '../../service/user.service';
7 |
8 | @IonicPage()
9 | @Component({
10 | selector: 'page-account-topics',
11 | templateUrl: 'account-topics.html',
12 | })
13 | export class AccountTopicsPage implements OnInit {
14 | loginname: string;
15 | topicsCount: number;
16 | repliesCount: number;
17 | user: any;
18 |
19 | constructor(private navCtrl: NavController, private navParams: NavParams, private userService: UserService, private utilService: UtilService) {
20 | this.user = {
21 | recent_topics: [],
22 | recent_replies: []
23 | };
24 | }
25 |
26 | getUser() {
27 | this.userService.getUser(this.loginname).subscribe(
28 | data => {
29 | this.user = data.data
30 | this.topicsCount = data.data.recent_topics.length
31 | this.repliesCount = data.data.recent_replies.length;
32 | }
33 | );
34 | }
35 |
36 | openPage(id: string) {
37 | this.navCtrl.push(HomeDetailPage, { id: id });
38 | }
39 |
40 | ngOnInit() {
41 | this.utilService.getLoginStatus().then((data) => this.loginname = data.loginname).then(() => {
42 | if (this.user) {
43 | this.getUser();
44 | } else {
45 | this.utilService.toast('请登录');
46 | }
47 | })
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/pages/account/account.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | 个人中心
4 |
5 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | {{user?.loginname}}
19 | 积分 {{user?.score}}
20 | 注册日期 {{user?.create_at|date:'yyyy-MM-dd'}}
21 |
22 |
23 |
24 |
25 | 功能
26 |
27 |
28 |
29 |
30 |
31 | 收藏
32 |
33 |
34 |
35 | 消息
36 | {{messageCount}}
37 |
38 |
39 |
40 | 话题
41 |
42 |
43 |
44 |
45 |
46 |
47 | 关于
48 |
49 |
50 | 当前版本
51 | {{versionNumber}}
52 |
53 |
54 | 联系作者
55 | 963577494@qq.com
56 |
57 |
58 | 开源地址
59 | Ionic2-CNodeClub
60 |
61 |
62 | CNode社区
63 | https://cnodejs.org
64 |
65 |
66 |
67 |
68 | © @zxj963577494
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/src/pages/account/account.scss:
--------------------------------------------------------------------------------
1 | page-account {
2 | ion-badge {
3 | position: absolute;
4 | top: 0px;
5 | padding: 2px 5px;
6 | font-size: 1.2rem;
7 | }
8 | }
--------------------------------------------------------------------------------
/src/pages/account/account.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { IonicPage, NavController, NavParams, Events } from 'ionic-angular';
3 | import { AppVersion } from '@ionic-native/app-version';
4 | import { Badge } from '@ionic-native/badge';
5 | import { Storage } from '@ionic/storage';
6 |
7 | import { UserService } from '../../service/user.service';
8 | import { UtilService } from '../../service/util.service';
9 | import { MessageService } from '../../service/message.service';
10 | import { AccountCollectsPage } from '../account';
11 | import { AccountMessagesPage } from '../account';
12 | import { AccountTopicsPage } from '../account';
13 | import { LoginPage } from '../login/login';
14 |
15 | @IonicPage()
16 | @Component({
17 | selector: 'page-account',
18 | templateUrl: 'account.html',
19 | })
20 | export class AccountPage implements OnInit {
21 | versionNumber: string;
22 | user: any;
23 | messageCount: string;
24 |
25 | constructor(private navCtrl: NavController, private navParams: NavParams, private events: Events, private appVersion: AppVersion, private badge: Badge, private storage: Storage, private userService: UserService, private utilService: UtilService, private messageService: MessageService) {
26 | this.user = {
27 | avatar_url: '',
28 | loginname: '',
29 | score: '',
30 | create_at: '',
31 | };
32 | events.subscribe('messageCount', (data) => {
33 | this.messageCount = data;
34 | });
35 | this.versionNumber = '请在手机中运行';
36 | this.appVersion.getVersionNumber().then((data) => {
37 | this.versionNumber = data
38 | }).catch((error) => console.log(error));
39 | }
40 |
41 | getUser() {
42 | this.userService.getUser(this.user.loginname).subscribe(
43 | data => this.user = data.data
44 | );
45 | }
46 |
47 | getMesssge() {
48 | this.messageService.GetMessageCount({ accesstoken: this.user.accesstoken }).subscribe(data => {
49 | this.messageCount = data.data;
50 | this.events.publish('messageCount', data.data);
51 | this.badge.set(data.data).then().catch(error => console.log(error));
52 | })
53 | }
54 |
55 | openPage(cate: string) {
56 | if (cate === 'collects') {
57 | this.navCtrl.push(AccountCollectsPage);
58 | }
59 | else if (cate === 'messages') {
60 | this.navCtrl.push(AccountMessagesPage);
61 | }
62 | else {
63 | this.navCtrl.push(AccountTopicsPage);
64 | }
65 | }
66 |
67 | loginOut() {
68 | this.events.publish('messageCount', 0);
69 | this.storage.clear();
70 | this.badge.clear().then().catch(error => console.log(error));
71 | this.navCtrl.pop();
72 | }
73 |
74 | ngOnInit() {
75 | this.utilService.getLoginStatus().then((data) => {
76 | this.user = data;
77 | }).then(() => {
78 | if (this.user) {
79 | this.getMesssge();
80 | }
81 | else {
82 | return this.navCtrl.push(LoginPage);
83 | }
84 | }).then(() => this.getUser());
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/pages/account/index.ts:
--------------------------------------------------------------------------------
1 | export * from './account';
2 | export * from './account-collects';
3 | export * from './account-messages';
4 | export * from './account-topics';
5 |
--------------------------------------------------------------------------------
/src/pages/home/home-add.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | 创建话题
4 |
5 |
6 |
7 |
8 |
9 |
48 |
--------------------------------------------------------------------------------
/src/pages/home/home-add.scss:
--------------------------------------------------------------------------------
1 | page-home-add {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/home/home-add.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { IonicPage, NavController, NavParams, Events } from 'ionic-angular';
3 |
4 | import { TopicService } from '../../service/topic.service';
5 | import { UtilService } from '../../service/util.service';
6 |
7 | @IonicPage()
8 | @Component({
9 | selector: 'page-home-add',
10 | templateUrl: 'home-add.html',
11 | })
12 | export class HomeAddPage implements OnInit {
13 | topicParams: any;
14 | user: any;
15 |
16 | constructor(private navCtrl: NavController, private navParams: NavParams, private events: Events, private topicService: TopicService, private utilService: UtilService) {
17 | this.topicParams = {
18 | accesstoken: '',
19 | tab: '',
20 | title: '',
21 | content: ''
22 | }
23 | }
24 |
25 | onSubmit() {
26 | this.topicService.PostTopics(this.topicParams).subscribe(
27 | data => {
28 | if (data.success) {
29 | this.utilService.toast('发布成功');
30 | this.events.publish('topicPush', {
31 | id: data.topic_id,
32 | title: this.topicParams.title,
33 | author: {
34 | avatar_url: this.user.avatar_url,
35 | loginname: this.user.loginname
36 | },
37 | last_reply_at: new Date()
38 | });
39 | }
40 | else {
41 | this.utilService.toast('发布失败');
42 | }
43 | }
44 | )
45 | }
46 |
47 | ngOnInit() {
48 | this.utilService.getLoginStatus().then((data) => {
49 | if (data) {
50 | this.user = data;
51 | this.topicParams.accesstoken = data.accesstoken;
52 | }
53 | else {
54 | this.utilService.toast('请登录');
55 | }
56 | });
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/pages/home/home-detail.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 | CNode技术社区
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | {{topic.author.loginname}}
24 | 发布 {{topic.create_at | amAgoTime}} 最后回复 {{topic.last_reply_at | amAgoTime}}
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | {{topic.visit_count}} 浏览
37 |
38 |
39 |
40 |
41 |
42 | {{topic.reply_count}} 评论
43 |
44 |
45 |
46 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | {{item.author.loginname}}
59 | {{item.create_at | amAgoTime}}
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
73 |
74 |
75 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
97 |
--------------------------------------------------------------------------------
/src/pages/home/home-detail.scss:
--------------------------------------------------------------------------------
1 | page-home-detail {
2 | .col {
3 | padding: 0;
4 | }
5 | .text-input {
6 | margin: 0 8px 0 0;
7 | border: 1px solid #ccc;
8 | padding: 5px 0px;
9 | border-radius: 10px;
10 | padding-left: 5px;
11 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
12 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
13 | -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
14 | -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
15 | transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s
16 | }
17 | .text-input:focus {
18 | border-color: #66afe9;
19 | outline: 0;
20 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, .6);
21 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, .6)
22 | }
23 | }
--------------------------------------------------------------------------------
/src/pages/home/home-detail.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { IonicPage, NavController, NavParams } from 'ionic-angular';
3 | import { SocialSharing } from '@ionic-native/social-sharing';
4 | import { DomSanitizer } from '@angular/platform-browser';
5 |
6 | import { TopicService } from '../../service/topic.service';
7 | import { CollectService } from '../../service/collect.service';
8 | import { RepliesService } from '../../service/replies.service';
9 | import { UtilService } from '../../service/util.service';
10 | import { UserPage } from '../user/user';
11 |
12 | @IonicPage()
13 | @Component({
14 | selector: 'page-home-detail',
15 | templateUrl: 'home-detail.html'
16 | })
17 | export class HomeDetailPage implements OnInit {
18 | id: string;
19 | topicParams: any;
20 | topic: any;
21 | replyParams: any;
22 | collectParams: any;
23 | shareParams: any;
24 | user: any;
25 |
26 | constructor(public navCtrl: NavController, public navParams: NavParams, private socialSharing: SocialSharing, private sanitize:DomSanitizer, private topicService: TopicService, private collectService: CollectService, private repliesService: RepliesService, private utilService: UtilService) {
27 | this.id = this.navParams.get('id');
28 | this.topic = {
29 | author: {
30 | loginname: '',
31 | avatar_url: ''
32 | },
33 | create_at: '',
34 | last_reply_at: '',
35 | content: '',
36 | visit_count: '',
37 | reply_count: '',
38 | replies: []
39 | }
40 | this.topicParams = {
41 | mdrender: true,
42 | accesstoken: ''
43 | }
44 | this.replyParams = {
45 | accesstoken: '',
46 | content: '',
47 | replyId: ''
48 | }
49 | this.collectParams = {
50 | accesstoken: '',
51 | topic_id: ''
52 | }
53 | this.shareParams = {
54 | message: '',
55 | subject: '',
56 | link: ''
57 | }
58 | }
59 |
60 | getTopicDetail() {
61 | this.topicService.getTopicDetail(this.id, this.topicParams).subscribe(
62 | data => {
63 | this.topic = data.data;
64 | this.shareParams.message = this.utilService.getHtmlText(data.data.content).substring(0, 150) + '......';
65 | console.log(this.shareParams.message);
66 | this.shareParams.subject = data.data.title;
67 | this.shareParams.link = 'https://cnodejs.org/topic/' + data.data.id;
68 | }
69 | );
70 | }
71 |
72 | openUserPage(loginname: string, event) {
73 | this.navCtrl.push(UserPage, { loginname: loginname });
74 | event.stopPropagation();
75 | }
76 |
77 | collect(topic_id: string) {
78 | if (this.user) {
79 | this.collectParams.topic_id = topic_id;
80 | this.collectService.PostCollect(this.collectParams).subscribe(
81 | data => {
82 | if (data.success) {
83 | this.utilService.toast('收藏成功');
84 | }
85 | else {
86 | this.utilService.toast('收藏失败或已经收藏');
87 | }
88 | });
89 | }
90 | else {
91 | this.utilService.toast('请登录后进行操作');
92 | }
93 | }
94 |
95 | replieUps(replyId: string) {
96 | if (this.user) {
97 | this.repliesService.PutRepliesUps(replyId, { accesstoken: this.user.accesstoken }).subscribe(data => {
98 | if (data.success) {
99 | if (data.action === 'down') {
100 | this.utilService.toast('取消成功');
101 | }
102 | else {
103 | this.utilService.toast('点赞成功');
104 | }
105 | }
106 | else {
107 | this.utilService.toast('操作失败');
108 | }
109 | }, data => {
110 | this.utilService.toast(data.error_msg);
111 | })
112 | }
113 | }
114 |
115 | reReply(replyId: string, loginname: string) {
116 | this.replyParams.content = '@' + loginname + ' ';
117 | this.replyParams.replyId = replyId;
118 | }
119 |
120 | saveReply() {
121 | if (this.user) {
122 | if (this.replyParams.content.indexOf('@') < 0) {
123 | this.replyParams.replyId = '';
124 | }
125 | this.repliesService.PostReplies(this.id, this.replyParams).subscribe((data) => {
126 | if (data.success) {
127 | let replie = {
128 | author: {
129 | loginname: this.user.loginname,
130 | avatar_url: this.user.avatar_url
131 | },
132 | content: '' + this.replyParams.content + '
\n
',
133 | id: data.reply_id
134 | };
135 | this.topic.replies.unshift(replie);
136 | this.utilService.toast('回复成功');
137 | this.replyParams.content = '';
138 | }
139 | });
140 | } else {
141 | this.utilService.toast('请登录后进行操作');
142 | }
143 | }
144 |
145 | share() {
146 | this.socialSharing.share(this.shareParams.message, this.shareParams.subject, '', this.shareParams.link).then().catch(error => console.log(error));;
147 | }
148 |
149 | ngOnInit() {
150 | this.utilService.getLoginStatus().then((logined) => {
151 | this.user = logined;
152 | if (logined) {
153 | this.topicParams.accesstoken = logined.accesstoken;
154 | this.replyParams.accesstoken = logined.accesstoken;
155 | this.collectParams.accesstoken = logined.accesstoken;
156 | }
157 | }).then(() => this.getTopicDetail());
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/src/pages/home/home.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 | CNode技术社区
9 |
10 |
13 | {{messageCount}}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | {{item.title}}
32 | {{item.author.loginname}}
33 | {{item.last_reply_at | amAgoTime}}
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/pages/home/home.scss:
--------------------------------------------------------------------------------
1 | page-home {
2 | ion-badge {
3 | position: absolute;
4 | left: 18px;
5 | top: -5px;
6 | padding: 2px 5px;
7 | font-size: 1.2rem;
8 | }
9 | }
--------------------------------------------------------------------------------
/src/pages/home/home.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { App, IonicPage, NavController, NavParams, Events } from 'ionic-angular';
3 | import { Badge } from '@ionic-native/badge';
4 |
5 | import { TopicService } from '../../service/topic.service';
6 | import { UtilService } from '../../service/util.service';
7 | import { MessageService } from '../../service/message.service';
8 | import { HomeDetailPage } from './home-detail';
9 | import { LoginPage } from '../login/login';
10 | import { HomeAddPage } from './home-add';
11 | import { UserPage } from '../user/user';
12 |
13 | @IonicPage()
14 | @Component({
15 | selector: 'page-home',
16 | templateUrl: 'home.html'
17 | })
18 | export class HomePage implements OnInit {
19 | tab: string;
20 | topics: any[];
21 | params: any;
22 | user: any;
23 | messageCount: number;
24 |
25 | constructor(private appCtrl: App, private navCtrl: NavController, private navParams: NavParams, private events: Events, private badge: Badge, private topicService: TopicService, private utilService: UtilService, private messageService: MessageService) {
26 | this.tab = this.navParams.get('tab');
27 | this.params = {
28 | page: 1,
29 | tab: this.tab || 'all',
30 | limit: 20,
31 | mdrender: false
32 | }
33 | events.subscribe('messageCount', (data) => {
34 | this.messageCount = data;
35 | });
36 | events.subscribe('topicPush', (data) => {
37 | this.topics.unshift(data);
38 | });
39 | events.subscribe('user', (data) => {
40 | this.user = data;
41 | });
42 | }
43 |
44 | GetTopics() {
45 | this.topicService.getTopics(this.params).subscribe(
46 | data => this.topics = data.data
47 | );
48 | }
49 |
50 | doRefresh(refresher) {
51 | this.params.page = 1;
52 | setTimeout(() => {
53 | this.topicService.getTopics(this.params).subscribe(
54 | data => {
55 | this.topics = data.data;
56 | refresher.complete();
57 | }
58 | );
59 | }, 2000);
60 | }
61 |
62 | doInfinite(infiniteScroll) {
63 | this.params.page++;
64 | setTimeout(() => {
65 | this.topicService.getTopics(this.params).subscribe(
66 | data => {
67 | if (data) {
68 | this.topics.push(...data.data);
69 | infiniteScroll.complete();
70 | }
71 | else {
72 | infiniteScroll.enable(false);
73 | }
74 | }
75 | );
76 | }, 500);
77 | }
78 |
79 | openPage(id: string) {
80 | this.appCtrl.getRootNav().push(HomeDetailPage, { id: id });
81 | }
82 | openUserPage(loginname: string, event) {
83 | this.appCtrl.getRootNav().push(UserPage, { loginname: loginname });
84 | event.stopPropagation();
85 | }
86 |
87 | login() {
88 | this.appCtrl.getRootNav().push(LoginPage);
89 | }
90 |
91 | addTopic() {
92 | if (this.user) {
93 | this.navCtrl.push(HomeAddPage);
94 | }
95 | else {
96 | this.utilService.toast('请登录后发帖');
97 | }
98 | }
99 |
100 | getMesssge() {
101 | this.messageService.GetMessageCount({ accesstoken: this.user.accesstoken }).subscribe(data => {
102 | this.messageCount = data.data;
103 | this.badge.set(data.data).then().catch(error => console.log(error));
104 | })
105 | }
106 |
107 | ngOnInit() {
108 | this.utilService.getLoginStatus().then((data) => {
109 | this.user = data;
110 | }).then(() => {
111 | if (this.user) {
112 | this.getMesssge();
113 | }
114 | }).then(() => this.GetTopics());
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/pages/home/index.ts:
--------------------------------------------------------------------------------
1 | export * from './home-detail';
2 | export * from './home';
3 | export * from './home-add';
4 |
--------------------------------------------------------------------------------
/src/pages/login/index.ts:
--------------------------------------------------------------------------------
1 | export * from './login'
--------------------------------------------------------------------------------
/src/pages/login/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | 用户登录
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
14 |
15 | 立即登录
16 |
17 |
18 |
19 |
20 |
21 |
22 | 功能
23 |
24 |
25 |
26 |
27 |
28 | 收藏
29 |
30 |
31 |
32 | 消息
33 |
34 |
35 |
36 | 话题
37 |
38 |
39 |
40 |
41 |
42 |
43 | 关于
44 |
45 |
46 | 当前版本
47 | {{versionNumber}}
48 |
49 |
50 | 联系作者
51 | 963577494@qq.com
52 |
53 |
54 | 开源地址
55 | Ionic2-CNodeClub
56 |
57 |
58 | CNode社区
59 | https://cnodejs.org
60 |
61 |
62 |
63 |
64 | © @zxj963577494
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/src/pages/login/login.scss:
--------------------------------------------------------------------------------
1 | page-login {
2 | .avatar {
3 | width: 60px;
4 | height: 60px;
5 | }
6 | }
--------------------------------------------------------------------------------
/src/pages/login/login.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { IonicPage, NavController, NavParams, AlertController, ViewController, Events } from 'ionic-angular';
3 | import { Storage } from '@ionic/storage';
4 | import { AppVersion } from '@ionic-native/app-version';
5 | import { BarcodeScanner } from '@ionic-native/barcode-scanner';
6 |
7 | import { UserService } from '../../service/user.service';
8 | import { AccountPage } from '../account/account';
9 | import { UtilService } from '../../service/util.service';
10 |
11 | @IonicPage()
12 | @Component({
13 | selector: 'page-login',
14 | templateUrl: 'login.html',
15 | })
16 | export class LoginPage implements OnInit {
17 | versionNumber: string;
18 | user: any;
19 |
20 | constructor(private navCtrl: NavController, private navParams: NavParams, private alertCtrl: AlertController, private viewCtrl: ViewController, private storage: Storage, private events: Events, private appVersion: AppVersion, private barcodeScanner: BarcodeScanner, private userService: UserService, private utilService: UtilService) {
21 | this.user = {
22 | loginname: '',
23 | avatar_url: '',
24 | accesstoken: ''
25 | }
26 | this.appVersion.getVersionNumber().then((data) => {
27 | this.versionNumber = data
28 | }).catch((error) => {
29 | console.log(error);
30 | this.versionNumber = '请在手机中运行';
31 | });
32 | }
33 |
34 | login() {
35 | let alert = this.alertCtrl.create({
36 | title: '扫码登录',
37 | message: 'PC登录 https://cnodejs.org/setting 后,扫描设置页面的Access Token二维码即可完成登录',
38 | buttons: [
39 | {
40 | text: '我知道了',
41 | handler: () => {
42 | this.barcodeScanner.scan().then((barcodeData) => {
43 | this.user.accesstoken = barcodeData.text;
44 | this.userService.PostAccessToken({ accesstoken: this.user.accesstoken }).subscribe((data) => {
45 | if (data.success) {
46 | this.user.loginname = data.loginname;
47 | this.user.avatar_url = data.avatar_url;
48 | this.events.publish('user', this.user);
49 | this.storage.set('user', this.user);
50 | this.navCtrl.push(AccountPage).then(() => {
51 | let index = this.viewCtrl.index;
52 | this.navCtrl.remove(index);
53 | });
54 | this.utilService.toast('登录成功');
55 | }
56 | else {
57 | this.utilService.toast('登录失败');
58 | }
59 | })
60 | }, (err) => {
61 | this.alertCtrl.create({
62 | title: '注意',
63 | message: '在非手机设备(浏览器)时登录,需填入相关用户信息,必填!',
64 | inputs: [
65 | {
66 | name: 'loginname',
67 | placeholder: '用户名'
68 | },
69 | {
70 | name: 'avatar_url',
71 | placeholder: '头像URL',
72 | },
73 | {
74 | name: 'accesstoken',
75 | placeholder: 'accesstoken',
76 | }
77 | ],
78 | buttons: [
79 | {
80 | text: '取消',
81 | role: 'cancel',
82 | handler: data => {
83 | }
84 | },
85 | {
86 | text: '登录',
87 | handler: data => {
88 | if (data.loginname && data.avatar_url && data.accesstoken) {
89 | this.user.loginname = data.loginname;
90 | this.user.avatar_url = data.avatar_url;
91 | this.user.accesstoken = data.accesstoken;
92 | this.events.publish('user', this.user);
93 | this.storage.set('user', this.user);
94 | this.navCtrl.push(AccountPage).then(() => {
95 | let index = this.viewCtrl.index;
96 | this.navCtrl.remove(index);
97 | });
98 | } else {
99 | return false;
100 | }
101 | }
102 | }
103 | ]
104 | }).present();
105 | console.log(err);
106 | });
107 | }
108 | }
109 | ]
110 | });
111 | alert.present();
112 | }
113 |
114 | ionViewCanEnter() {
115 | this.utilService.getLoginStatus().then((data) => {
116 | if (data) {
117 | this.navCtrl.push(AccountPage).then(() => {
118 | let index = this.viewCtrl.index;
119 | this.navCtrl.remove(index);
120 | });
121 | }
122 | })
123 | }
124 |
125 | ngOnInit() {
126 |
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/pages/user/index.ts:
--------------------------------------------------------------------------------
1 | export * from './user';
--------------------------------------------------------------------------------
/src/pages/user/user.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | 用户详情
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | {{user.loginname}}
14 | 积分 {{user.score}}
15 | 注册日期 {{user.create_at|date:'yyyy-MM-dd'}}
16 |
17 |
18 |
19 |
20 | 最近创建的话题
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | {{topic.title}}
30 | {{topic.last_reply_at|amAgoTime}}
31 |
32 |
33 |
34 |
35 | 最近参与的话题
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | {{topic.title}}
45 | {{topic.last_reply_at|amAgoTime}}
46 |
47 |
48 |
49 |
50 | 最近收藏
51 |
52 |
53 |
54 |
55 |
56 | {{topic.title}}
57 | {{topic.last_reply_at|amAgoTime}}
58 |
59 |
60 |
--------------------------------------------------------------------------------
/src/pages/user/user.scss:
--------------------------------------------------------------------------------
1 | page-user {
2 |
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/user/user.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { IonicPage, NavController, NavParams } from 'ionic-angular';
3 |
4 | import { HomeDetailPage } from './../home/home-detail';
5 | import { UserService } from '../../service/user.service';
6 | import { UtilService } from '../../service/util.service';
7 |
8 | @IonicPage()
9 | @Component({
10 | selector: 'page-user',
11 | templateUrl: 'user.html',
12 | })
13 | export class UserPage implements OnInit {
14 | user: any;
15 | loginname: string;
16 | topicsCount: number;
17 | repliesCount: number;
18 |
19 | constructor(private navCtrl: NavController, private navParams: NavParams, private userService: UserService, private utilService: UtilService) {
20 | this.loginname = navParams.get('loginname');
21 | this.user = {
22 | avatar_url: '',
23 | loginname: '',
24 | score: '',
25 | create_at: '',
26 | recent_topics: [],
27 | recent_replies: []
28 | };
29 | }
30 |
31 | getUser() {
32 | this.userService.getUser(this.loginname).subscribe(
33 | data => {
34 | this.user = data.data;
35 | this.topicsCount = data.data.recent_topics.length
36 | this.repliesCount = data.data.recent_replies.length;
37 | }
38 | );
39 | }
40 |
41 | openPage(id: string) {
42 | this.navCtrl.push(HomeDetailPage, { id: id });
43 | }
44 |
45 | ngOnInit() {
46 | // 重要,移除下面这句话,通过href进入无法获取数据
47 | this.utilService.toast('加载中');
48 | this.getUser();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/pipe/amAgoTime.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 |
3 | @Pipe({
4 | name: 'amAgoTime'
5 | })
6 |
7 | export class AmAgoTimePipe implements PipeTransform {
8 | transform(value: any, ...args: any[]): any {
9 | if (value) {
10 | return this.getDateDiff(value);
11 | }
12 | }
13 |
14 | getDateDiff(pTime: string) {
15 | const minute: number = 1000 * 60;
16 | const hour: number = minute * 60;
17 | const day: number = hour * 24;
18 | const month: number = day * 30;
19 | const year: number = day * 365;
20 | const now = new Date().getTime();
21 | const old = new Date(pTime).getTime();
22 | const diffValue = now - old;
23 | const yearC = diffValue / year;
24 | const monthC = diffValue / month;
25 | const weekC = diffValue / (7 * day);
26 | const dayC = diffValue / day;
27 | const hourC = diffValue / hour;
28 | const minC = diffValue / minute;
29 | if (yearC >= 1) {
30 | return Math.round(monthC) + "年前";
31 | }
32 | else if (monthC >= 1) {
33 | return Math.round(monthC) + "个月前";
34 | }
35 | else if (weekC >= 1) {
36 | return Math.round(weekC) + "周前";
37 | }
38 | else if (dayC >= 1) {
39 | return Math.round(dayC) + "天前";
40 | }
41 | else if (hourC >= 1) {
42 | return Math.round(hourC) + "小时前";
43 | }
44 | else if (minC >= 1) {
45 | return Math.round(minC) + "分钟前";
46 | } else {
47 | return "刚刚";
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/src/pipe/index.ts:
--------------------------------------------------------------------------------
1 | export * from './amAgoTime.pipe';
2 | export * from './link.pipe';
--------------------------------------------------------------------------------
/src/pipe/link.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { DomSanitizer } from '@angular/platform-browser';
3 |
4 | @Pipe({
5 | name: 'link'
6 | })
7 |
8 | export class LinkPipe implements PipeTransform {
9 |
10 | constructor(private sanitize:DomSanitizer) { }
11 |
12 | transform(value: any, ...args: any[]): any {
13 | if (value && typeof value === 'string') {
14 | const topicFullLinkRegex = /href="([\S]+)\/topic\/([\S]+)"/gi;
15 | const userFullLinkRegex = /href="([\S]+)\/user\/([\S]+)"/gi;
16 | const userLinkRegex = /href="\/user\/([\S]+)"/gi;
17 | const noProtocolSrcRegex = /src="\/\/([\S]+)"/gi;
18 | const externalLinkRegex = /href="((?!#\/(user|home)\/))([\S]+)"/gi;
19 | let ret = value
20 | .replace(topicFullLinkRegex, 'href="#/home/$2"')
21 | .replace(userFullLinkRegex, 'href="#/user/$2"')
22 | .replace(userLinkRegex, 'href="#/user/$1"')
23 | .replace(noProtocolSrcRegex, 'src="https://$1"')
24 | .replace(externalLinkRegex, "onClick=\"window.open('$3', '_blank', 'location=no')\"")
25 | return this.sanitize.bypassSecurityTrustHtml(ret);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/src/service-worker.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Check out https://googlechrome.github.io/sw-toolbox/ for
3 | * more info on how to use sw-toolbox to custom configure your service worker.
4 | */
5 |
6 |
7 | 'use strict';
8 | importScripts('./build/sw-toolbox.js');
9 |
10 | self.toolbox.options.cache = {
11 | name: 'ionic-cache'
12 | };
13 |
14 | // pre-cache our key assets
15 | self.toolbox.precache(
16 | [
17 | './build/main.js',
18 | './build/main.css',
19 | './build/polyfills.js',
20 | 'index.html',
21 | 'manifest.json'
22 | ]
23 | );
24 |
25 | // dynamically cache any other local assets
26 | self.toolbox.router.any('/*', self.toolbox.cacheFirst);
27 |
28 | // for any other requests go to the network, cache,
29 | // and then only use that cached resource if your user goes offline
30 | self.toolbox.router.default = self.toolbox.networkFirst;
31 |
--------------------------------------------------------------------------------
/src/service/collect.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { Http } from '@angular/http';
3 | import { Observable } from 'rxjs/Observable';
4 | import 'rxjs/add/operator/map';
5 | import 'rxjs/add/operator/catch';
6 |
7 | import { PostCollectRequest, DeleteCollectRequest } from '../message/collect.request';
8 | import { CoreService } from './core.service';
9 |
10 | @Injectable()
11 | export class CollectService {
12 |
13 | constructor(private http: Http, private coreService: CoreService) { }
14 |
15 | PostCollect(request: PostCollectRequest): Observable {
16 | return this.http.post(this.coreService.baseUrl + '/topic_collect/collect', request)
17 | .map(res => res.json());
18 | }
19 |
20 | DeleteCollect(request: DeleteCollectRequest): Observable {
21 | return this.http.post(this.coreService.baseUrl + '/topic_collect/de_collect', request)
22 | .map(res => res.json());
23 | }
24 |
25 | getCollects(loginname: string): Observable {
26 | return this.http.get(this.coreService.baseUrl + '/topic_collect/' + loginname)
27 | .map(res => res.json());
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/src/service/core.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | @Injectable()
4 | export class CoreService {
5 |
6 | constructor() { }
7 |
8 | public baseUrl: string = 'https://cnodejs.org/api/v1';
9 | }
--------------------------------------------------------------------------------
/src/service/index.ts:
--------------------------------------------------------------------------------
1 | export * from './collect.service';
2 | export * from './message.service';
3 | export * from './replies.service';
4 | export * from './topic.service';
5 | export * from './user.service';
6 | export * from './core.service';
7 | export * from './util.service';
8 |
9 |
--------------------------------------------------------------------------------
/src/service/message.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { Http } from '@angular/http';
3 | import { Observable } from 'rxjs/Observable';
4 | import 'rxjs/add/operator/map';
5 | import 'rxjs/add/operator/catch';
6 |
7 | import { GetMessageCountRequest, GetMessagesRequest, PutMessageMarkAllRequest, PutMessageMarkOneRequest } from '../message/message.request';
8 | import { CoreService } from './core.service';
9 |
10 | @Injectable()
11 | export class MessageService {
12 |
13 |
14 | constructor(private http: Http, private coreService: CoreService) { }
15 |
16 | GetMessageCount(request: GetMessageCountRequest): Observable {
17 | return this.http.get(this.coreService.baseUrl + '/message/count', { params: request })
18 | .map(res => res.json());
19 | }
20 |
21 | GetMessages(request: GetMessagesRequest): Observable {
22 | return this.http.get(this.coreService.baseUrl + '/messages', { params: request })
23 | .map(res => res.json());
24 | }
25 |
26 | PutMessageMarkAll(request: PutMessageMarkAllRequest): Observable {
27 | return this.http.post(this.coreService.baseUrl + '/message/mark_all', request)
28 | .map(res => res.json());
29 | }
30 |
31 | PutMessageMarkOne(msg_id: string, request: PutMessageMarkOneRequest): Observable {
32 | return this.http.post(this.coreService.baseUrl + '/message/mark_one/' + msg_id, request)
33 | .map(res => res.json());
34 | }
35 | }
--------------------------------------------------------------------------------
/src/service/replies.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { Http } from '@angular/http';
3 | import { Observable } from 'rxjs/Observable';
4 | import 'rxjs/add/operator/map';
5 | import 'rxjs/add/operator/catch';
6 |
7 | import { PostRepliesRequest, PutRepliesUpsRequest } from '../message/replies.request';
8 | import { CoreService } from './core.service';
9 |
10 | @Injectable()
11 | export class RepliesService {
12 |
13 | constructor(private http: Http, private coreService: CoreService) { }
14 |
15 | PostReplies(topic_id: string, request: PostRepliesRequest): Observable {
16 | return this.http.post(this.coreService.baseUrl + '/topic/' + topic_id + '/replies', request)
17 | .map(res => res.json());
18 | }
19 |
20 | PutRepliesUps(reply_id: string, request: PutRepliesUpsRequest): Observable {
21 | return this.http.post(this.coreService.baseUrl + '/reply/' + reply_id + '/ups', request)
22 | .map(res => res.json()).catch(error => error.json());
23 | }
24 | }
--------------------------------------------------------------------------------
/src/service/topic.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { Http } from '@angular/http';
3 | import { Observable } from 'rxjs/Observable';
4 | import 'rxjs/add/operator/map';
5 | import 'rxjs/add/operator/catch';
6 |
7 | import { GetTopicsRequest, GetTopicDetailRequest, PostTopicsRequest, PutTopicsRequest } from '../message/topics.request';
8 | import { CoreService } from './core.service';
9 |
10 | @Injectable()
11 | export class TopicService {
12 |
13 | constructor(private http: Http, private coreService: CoreService) { }
14 |
15 | getTopics(request: GetTopicsRequest): Observable {
16 | return this.http.get(this.coreService.baseUrl + '/topics', { params: request })
17 | .map(res => res.json());
18 | }
19 |
20 | getTopicDetail(id: string, request: GetTopicDetailRequest): Observable {
21 | return this.http.get(this.coreService.baseUrl + '/topic/' + id, { params: request })
22 | .map(res => res.json());
23 | }
24 |
25 | PostTopics(request: PostTopicsRequest): Observable {
26 | return this.http.post(this.coreService.baseUrl + '/topics', request)
27 | .map(res => res.json());
28 | }
29 |
30 | PutTopics(request: PutTopicsRequest): Observable {
31 | return this.http.post(this.coreService.baseUrl + '/topics/update', request)
32 | .map(res => res.json());
33 | }
34 | }
--------------------------------------------------------------------------------
/src/service/user.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { Http } from '@angular/http';
3 | import { Observable } from 'rxjs/Observable';
4 | import 'rxjs/add/operator/map';
5 | import 'rxjs/add/operator/catch';
6 |
7 | import { PostAccessTokenRequest } from '../message/user.request';
8 | import { CoreService } from './core.service';
9 |
10 | @Injectable()
11 | export class UserService {
12 |
13 | constructor(private http: Http, private coreService: CoreService) { }
14 |
15 | getUser(loginname: string): Observable {
16 | return this.http.get(this.coreService.baseUrl + '/user/' + loginname)
17 | .map(res => res.json());
18 | }
19 |
20 | PostAccessToken(request: PostAccessTokenRequest): Observable {
21 | return this.http.post(this.coreService.baseUrl + '/accesstoken', request)
22 | .map(res => res.json());
23 | }
24 | }
--------------------------------------------------------------------------------
/src/service/util.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { ToastController } from 'ionic-angular';
3 | import { Storage } from '@ionic/storage';
4 |
5 | @Injectable()
6 | export class UtilService {
7 |
8 | constructor(private toastCtrl: ToastController, private storage: Storage) { }
9 |
10 | getTabs(): Array<{ key: string, value: string, icon: string }> {
11 | return [{
12 | key: 'all',
13 | value: '全部',
14 | icon: 'home'
15 | },
16 | {
17 | key: 'good',
18 | value: '精华',
19 | icon: 'star'
20 | },
21 | {
22 | key: 'share',
23 | value: '分享',
24 | icon: 'share'
25 | },
26 | {
27 | key: 'ask',
28 | value: '问答',
29 | icon: 'chatbubbles'
30 | },
31 | {
32 | key: 'job',
33 | value: '招聘',
34 | icon: 'briefcase'
35 | },
36 | {
37 | key: 'dev',
38 | value: '客户端测试',
39 | icon: 'bug'
40 | }]
41 | }
42 |
43 | toast(message: string) {
44 | this.toastCtrl.create({
45 | message: message,
46 | duration: 1500,
47 | position: 'top'
48 | }).present();
49 | }
50 |
51 | getLoginStatus() {
52 | return this.storage.get('user').then((val) => {
53 | return val;
54 | })
55 | }
56 |
57 | getHtmlText(str: string) {
58 | return str.replace(/<[^>]+>/g, '');
59 | }
60 | }
--------------------------------------------------------------------------------
/src/theme/variables.scss:
--------------------------------------------------------------------------------
1 | // Ionic Variables and Theming. For more info, please see:
2 | // http://ionicframework.com/docs/v2/theming/
3 |
4 | // Font path is used to include ionicons,
5 | // roboto, and noto sans fonts
6 | $font-path: "../assets/fonts";
7 |
8 |
9 | // The app direction is used to include
10 | // rtl styles in your app. For more info, please see:
11 | // http://ionicframework.com/docs/theming/rtl-support/
12 | $app-direction: ltr;
13 |
14 |
15 | @import "ionic.globals";
16 |
17 |
18 | // Shared Variables
19 | // --------------------------------------------------
20 | // To customize the look and feel of this app, you can override
21 | // the Sass variables found in Ionic's source scss files.
22 | // To view all the possible Ionic variables, see:
23 | // http://ionicframework.com/docs/v2/theming/overriding-ionic-variables/
24 |
25 |
26 |
27 |
28 | // Named Color Variables
29 | // --------------------------------------------------
30 | // Named colors makes it easy to reuse colors on various components.
31 | // It's highly recommended to change the default colors
32 | // to match your app's branding. Ionic uses a Sass map of
33 | // colors so you can add, rename and remove colors as needed.
34 | // The "primary" color is the only required color in the map.
35 |
36 | $colors: (
37 | primary: #488aff,
38 | secondary: #32db64,
39 | danger: #f53d3d,
40 | light: #f4f4f4,
41 | dark: #222
42 | );
43 |
44 |
45 | // App iOS Variables
46 | // --------------------------------------------------
47 | // iOS only Sass variables can go here
48 |
49 |
50 |
51 |
52 | // App Material Design Variables
53 | // --------------------------------------------------
54 | // Material Design only Sass variables can go here
55 |
56 |
57 |
58 |
59 | // App Windows Variables
60 | // --------------------------------------------------
61 | // Windows only Sass variables can go here
62 |
63 |
64 |
65 |
66 | // App Theme
67 | // --------------------------------------------------
68 | // Ionic apps can have different themes applied, which can
69 | // then be future customized. This import comes last
70 | // so that the above variables are used and Ionic's
71 | // default are overridden.
72 |
73 | @import "ionic.theme.default";
74 |
75 |
76 | // Ionicons
77 | // --------------------------------------------------
78 | // The premium icon font for Ionic. For more info, please see:
79 | // http://ionicframework.com/docs/v2/ionicons/
80 |
81 | @import "ionic.ionicons";
82 |
83 |
84 | // Fonts
85 | // --------------------------------------------------
86 |
87 | @import "roboto";
88 | @import "noto-sans";
89 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "declaration": false,
5 | "emitDecoratorMetadata": true,
6 | "experimentalDecorators": true,
7 | "lib": [
8 | "dom",
9 | "es2015"
10 | ],
11 | "module": "es2015",
12 | "moduleResolution": "node",
13 | "sourceMap": true,
14 | "target": "es5"
15 | },
16 | "include": [
17 | "src/**/*.ts"
18 | ],
19 | "exclude": [
20 | "node_modules"
21 | ],
22 | "compileOnSave": false,
23 | "atom": {
24 | "rewriteTsconfig": false
25 | }
26 | }
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-duplicate-variable": true,
4 | "no-unused-variable": [
5 | true
6 | ]
7 | },
8 | "rulesDirectory": [
9 | "node_modules/tslint-eslint-rules/dist/rules"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------