浏览代码

before frontend login

master
peter 6 年前
父节点
当前提交
5466a3e8e8
共有 57 个文件被更改,包括 1010 次插入2082 次删除
  1. 143
    3
      package-lock.json
  2. 4
    3
      package.json
  3. 36
    38
      src/backend/Admin/Admin.ts
  4. 34
    0
      src/backend/Components/Debugger/Debugger.ts
  5. 5
    4
      src/backend/Components/Eventbus.ts
  6. 107
    0
      src/backend/Components/Item/ItemManager.ts
  7. 196
    0
      src/backend/Components/Login/LoginManager.ts
  8. 2
    2
      src/backend/Components/PluginLoader.ts
  9. 0
    0
      src/backend/Components/RPCConfigLoader.ts
  10. 95
    0
      src/backend/Components/Raid/RaidManager.ts
  11. 0
    24
      src/backend/Installer.ts
  12. 20
    2
      src/backend/Launcher.ts
  13. 0
    14
      src/backend/Types.ts
  14. 24
    0
      src/backend/Types/FrontworkComponent.ts
  15. 1
    1
      src/backend/Types/Interfaces.ts
  16. 64
    0
      src/backend/Types/Items.ts
  17. 1
    1
      src/backend/Types/Plugin.ts
  18. 7
    0
      src/backend/Types/PrivilegedRPCExporter.ts
  19. 91
    0
      src/backend/Types/Types.ts
  20. 6
    2
      src/frontend/angular.json
  21. 4
    0
      src/frontend/custom-webpack.config.js
  22. 24
    4
      src/frontend/package-lock.json
  23. 3
    1
      src/frontend/package.json
  24. 13
    125
      src/frontend/src/app/@core/core.module.ts
  25. 0
    1
      src/frontend/src/app/@core/mock/README.md
  26. 0
    29
      src/frontend/src/app/@core/mock/country-order.service.ts
  27. 0
    103
      src/frontend/src/app/@core/mock/earning.service.ts
  28. 0
    95
      src/frontend/src/app/@core/mock/electricity.service.ts
  29. 0
    65
      src/frontend/src/app/@core/mock/mock-data.module.ts
  30. 0
    155
      src/frontend/src/app/@core/mock/orders-chart.service.ts
  31. 0
    45
      src/frontend/src/app/@core/mock/orders-profit-chart.service.ts
  32. 0
    33
      src/frontend/src/app/@core/mock/periods.service.ts
  33. 0
    43
      src/frontend/src/app/@core/mock/profit-bar-animation-chart.service.ts
  34. 0
    77
      src/frontend/src/app/@core/mock/profit-chart.service.ts
  35. 0
    30
      src/frontend/src/app/@core/mock/security-cameras.service.ts
  36. 0
    432
      src/frontend/src/app/@core/mock/smart-table.service.ts
  37. 0
    12
      src/frontend/src/app/@core/mock/solar.service.ts
  38. 0
    16
      src/frontend/src/app/@core/mock/stats-bar.service.ts
  39. 0
    31
      src/frontend/src/app/@core/mock/stats-progress-bar.service.ts
  40. 0
    27
      src/frontend/src/app/@core/mock/temperature-humidity.service.ts
  41. 0
    47
      src/frontend/src/app/@core/mock/traffic-bar.service.ts
  42. 0
    16
      src/frontend/src/app/@core/mock/traffic-chart.service.ts
  43. 0
    85
      src/frontend/src/app/@core/mock/traffic-list.service.ts
  44. 0
    57
      src/frontend/src/app/@core/mock/user-activity.service.ts
  45. 0
    53
      src/frontend/src/app/@core/mock/users.service.ts
  46. 0
    57
      src/frontend/src/app/@core/mock/visitors-analytics.service.ts
  47. 1
    4
      src/frontend/src/app/@theme/components/footer/footer.component.ts
  48. 2
    5
      src/frontend/src/app/@theme/components/header/header.component.html
  49. 5
    4
      src/frontend/src/app/@theme/components/header/header.component.ts
  50. 1
    1
      src/frontend/src/app/@theme/theme.module.ts
  51. 2
    32
      src/frontend/src/app/app-routing.module.ts
  52. 3
    1
      src/frontend/src/app/app.component.ts
  53. 95
    0
      src/frontend/src/app/frontcraft/login-api.ts
  54. 18
    0
      src/frontend/src/app/frontcraft/user.service.ts
  55. 0
    243
      src/frontend/src/app/pages/pages-menu.ts
  56. 1
    58
      src/frontend/src/app/pages/pages-routing.module.ts
  57. 2
    1
      src/frontend/src/tsconfig.app.json

+ 143
- 3
package-lock.json 查看文件

@@ -1382,6 +1382,14 @@
1382 1382
       "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
1383 1383
       "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
1384 1384
     },
1385
+    "define-properties": {
1386
+      "version": "1.1.3",
1387
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
1388
+      "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
1389
+      "requires": {
1390
+        "object-keys": "^1.0.12"
1391
+      }
1392
+    },
1385 1393
     "define-property": {
1386 1394
       "version": "2.0.2",
1387 1395
       "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
@@ -1571,6 +1579,33 @@
1571 1579
         "prr": "~1.0.1"
1572 1580
       }
1573 1581
     },
1582
+    "es-abstract": {
1583
+      "version": "1.16.0",
1584
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz",
1585
+      "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==",
1586
+      "requires": {
1587
+        "es-to-primitive": "^1.2.0",
1588
+        "function-bind": "^1.1.1",
1589
+        "has": "^1.0.3",
1590
+        "has-symbols": "^1.0.0",
1591
+        "is-callable": "^1.1.4",
1592
+        "is-regex": "^1.0.4",
1593
+        "object-inspect": "^1.6.0",
1594
+        "object-keys": "^1.1.1",
1595
+        "string.prototype.trimleft": "^2.1.0",
1596
+        "string.prototype.trimright": "^2.1.0"
1597
+      }
1598
+    },
1599
+    "es-to-primitive": {
1600
+      "version": "1.2.0",
1601
+      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz",
1602
+      "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==",
1603
+      "requires": {
1604
+        "is-callable": "^1.1.4",
1605
+        "is-date-object": "^1.0.1",
1606
+        "is-symbol": "^1.0.2"
1607
+      }
1608
+    },
1574 1609
     "escape-html": {
1575 1610
       "version": "1.0.3",
1576 1611
       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -2764,6 +2799,11 @@
2764 2799
         }
2765 2800
       }
2766 2801
     },
2802
+    "function-bind": {
2803
+      "version": "1.1.1",
2804
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
2805
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
2806
+    },
2767 2807
     "gauge": {
2768 2808
       "version": "2.7.4",
2769 2809
       "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
@@ -2982,12 +3022,25 @@
2982 3022
         "har-schema": "^2.0.0"
2983 3023
       }
2984 3024
     },
3025
+    "has": {
3026
+      "version": "1.0.3",
3027
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
3028
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
3029
+      "requires": {
3030
+        "function-bind": "^1.1.1"
3031
+      }
3032
+    },
2985 3033
     "has-flag": {
2986 3034
       "version": "3.0.0",
2987 3035
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
2988 3036
       "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
2989 3037
       "dev": true
2990 3038
     },
3039
+    "has-symbols": {
3040
+      "version": "1.0.0",
3041
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
3042
+      "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q="
3043
+    },
2991 3044
     "has-unicode": {
2992 3045
       "version": "2.0.1",
2993 3046
       "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
@@ -3235,6 +3288,11 @@
3235 3288
       "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
3236 3289
       "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
3237 3290
     },
3291
+    "is-callable": {
3292
+      "version": "1.1.4",
3293
+      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
3294
+      "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA=="
3295
+    },
3238 3296
     "is-data-descriptor": {
3239 3297
       "version": "0.1.4",
3240 3298
       "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
@@ -3253,6 +3311,11 @@
3253 3311
         }
3254 3312
       }
3255 3313
     },
3314
+    "is-date-object": {
3315
+      "version": "1.0.1",
3316
+      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
3317
+      "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
3318
+    },
3256 3319
     "is-descriptor": {
3257 3320
       "version": "0.1.6",
3258 3321
       "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
@@ -3340,6 +3403,14 @@
3340 3403
       "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
3341 3404
       "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
3342 3405
     },
3406
+    "is-regex": {
3407
+      "version": "1.0.4",
3408
+      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
3409
+      "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
3410
+      "requires": {
3411
+        "has": "^1.0.1"
3412
+      }
3413
+    },
3343 3414
     "is-relative": {
3344 3415
       "version": "1.0.0",
3345 3416
       "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
@@ -3354,6 +3425,14 @@
3354 3425
       "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
3355 3426
       "dev": true
3356 3427
     },
3428
+    "is-symbol": {
3429
+      "version": "1.0.2",
3430
+      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
3431
+      "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==",
3432
+      "requires": {
3433
+        "has-symbols": "^1.0.0"
3434
+      }
3435
+    },
3357 3436
     "is-typedarray": {
3358 3437
       "version": "1.0.0",
3359 3438
       "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
@@ -4182,6 +4261,16 @@
4182 4261
         }
4183 4262
       }
4184 4263
     },
4264
+    "object-inspect": {
4265
+      "version": "1.6.0",
4266
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz",
4267
+      "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ=="
4268
+    },
4269
+    "object-keys": {
4270
+      "version": "1.1.1",
4271
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
4272
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
4273
+    },
4185 4274
     "object-visit": {
4186 4275
       "version": "1.0.1",
4187 4276
       "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
@@ -4201,6 +4290,15 @@
4201 4290
         "isobject": "^3.0.0"
4202 4291
       }
4203 4292
     },
4293
+    "object.getownpropertydescriptors": {
4294
+      "version": "2.0.3",
4295
+      "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
4296
+      "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=",
4297
+      "requires": {
4298
+        "define-properties": "^1.1.2",
4299
+        "es-abstract": "^1.5.1"
4300
+      }
4301
+    },
4204 4302
     "object.map": {
4205 4303
       "version": "1.0.1",
4206 4304
       "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz",
@@ -4863,9 +4961,9 @@
4863 4961
       }
4864 4962
     },
4865 4963
     "rpclibrary": {
4866
-      "version": "1.3.17",
4867
-      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.3.17.tgz",
4868
-      "integrity": "sha512-ZdhZ1TSDO+bcz5kCJ7Ol+YAAyYpwg7YI/hETS4vv3RYerUEQVZSZjcm22J5a91RnQVN2SRiXzdoXbbFb/Renog==",
4964
+      "version": "1.4.0",
4965
+      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.4.0.tgz",
4966
+      "integrity": "sha512-JUU7+HymV2ZTI+NrIVOiIr5LGFoRsPq4k/ffdUonqIpd9fjOHBQ2/PFLVXx9z94+dKxdqN8/D9ZXPwU03ovZrg==",
4869 4967
       "requires": {
4870 4968
         "bsock": "^0.1.9",
4871 4969
         "http": "0.0.0",
@@ -5403,6 +5501,24 @@
5403 5501
         "strip-ansi": "^5.1.0"
5404 5502
       }
5405 5503
     },
5504
+    "string.prototype.trimleft": {
5505
+      "version": "2.1.0",
5506
+      "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz",
5507
+      "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==",
5508
+      "requires": {
5509
+        "define-properties": "^1.1.3",
5510
+        "function-bind": "^1.1.1"
5511
+      }
5512
+    },
5513
+    "string.prototype.trimright": {
5514
+      "version": "2.1.0",
5515
+      "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz",
5516
+      "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==",
5517
+      "requires": {
5518
+        "define-properties": "^1.1.3",
5519
+        "function-bind": "^1.1.1"
5520
+      }
5521
+    },
5406 5522
     "string_decoder": {
5407 5523
       "version": "1.1.1",
5408 5524
       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
@@ -5842,6 +5958,15 @@
5842 5958
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
5843 5959
       "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
5844 5960
     },
5961
+    "util.promisify": {
5962
+      "version": "1.0.0",
5963
+      "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz",
5964
+      "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==",
5965
+      "requires": {
5966
+        "define-properties": "^1.1.2",
5967
+        "object.getownpropertydescriptors": "^2.0.3"
5968
+      }
5969
+    },
5845 5970
     "utils-merge": {
5846 5971
       "version": "1.0.1",
5847 5972
       "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
@@ -6080,6 +6205,21 @@
6080 6205
         }
6081 6206
       }
6082 6207
     },
6208
+    "xml2js": {
6209
+      "version": "0.4.22",
6210
+      "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.22.tgz",
6211
+      "integrity": "sha512-MWTbxAQqclRSTnehWWe5nMKzI3VmJ8ltiJEco8akcC6j3miOhjjfzKum5sId+CWhfxdOs/1xauYr8/ZDBtQiRw==",
6212
+      "requires": {
6213
+        "sax": ">=0.6.0",
6214
+        "util.promisify": "~1.0.0",
6215
+        "xmlbuilder": "~11.0.0"
6216
+      }
6217
+    },
6218
+    "xmlbuilder": {
6219
+      "version": "11.0.1",
6220
+      "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
6221
+      "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
6222
+    },
6083 6223
     "xtend": {
6084 6224
       "version": "4.0.2",
6085 6225
       "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",

+ 4
- 3
package.json 查看文件

@@ -9,7 +9,7 @@
9 9
     "build-backend": "tsc; npm run webpack",
10 10
     "build-frontend": "npm run build-dashboard; cp node_modules/rpclibrary/js/browser/rpclibrary.browser.js ./dist/static/FrontblockLib.js",
11 11
     "build-dashboard": "cd src/frontend; npm i && npm run build; mkdir ../../dist/static; cp -r dist/* ../../dist/static",
12
-    "clean": "rm -rf lib static plugins conf dist widget .rpt2_cache *.js *.ts src/frontend/dist data",
12
+    "clean": "rm -rf lib static plugins conf dist/static widget .rpt2_cache *.js *.ts src/frontend/dist data",
13 13
     "update-frontblock": "npm remove frontblock frontblock-generic; npm install frontblock-generic@latest frontblock@latest",
14 14
     "webpack": "webpack  --config src/backend/webpack.prod.js --progress --colors"
15 15
   },
@@ -37,13 +37,14 @@
37 37
     "node-fetch": "^2.6.0",
38 38
     "path": "^0.12.7",
39 39
     "rimraf": "^3.0.0",
40
-    "rpclibrary": "^1.3.17",
40
+    "rpclibrary": "^1.4.0",
41 41
     "simple-git": "^1.124.0",
42 42
     "spawn-sync": "^2.0.0",
43 43
     "sqlite3": "^4.1.0",
44 44
     "trash": "^6.0.0",
45 45
     "upgiter": "^1.0.4",
46
-    "uuid": "^3.3.3"
46
+    "uuid": "^3.3.3",
47
+    "xml2js": "^0.4.22"
47 48
   },
48 49
   "devDependencies": {
49 50
     "@types/express": "^4.17.0",

src/backend/Admin.ts → src/backend/Admin/Admin.ts 查看文件

@@ -3,35 +3,55 @@
3 3
 import { getLogger } from 'frontblock-generic/Types';
4 4
 import { promises as fs, mkdirSync } from "fs"
5 5
 import { RPCServer } from 'rpclibrary'
6
-import { AdminConf, TableDefiniton } from './Types';
7
-import { RPCConfigLoader } from './RPCConfigLoader';
8
-import { RPCPluginLoader } from './PluginLoader';
6
+import { AdminConf, TableDefiniton } from '../Types/Types';
7
+import { RPCConfigLoader } from '../Components/RPCConfigLoader';
9 8
 import * as Path from 'path'
10
-import Knex = require('knex');
11
-import http = require('http');
12
-import express = require('express');
13
-import { TableDefinitionExporter } from './Interfaces';
14
-import { FrontworkEventBus } from './Eventbus';
9
+import * as Knex from  'knex';
10
+import * as http from 'http';
11
+import * as express from 'express';
12
+import { TableDefinitionExporter } from '../Types/Interfaces';
13
+import { FrontworkComponent } from '../Types/FrontworkComponent';
15 14
 
16 15
 const logger = getLogger("admin", 'debug') 
17 16
 
18 17
 export class FrontworkAdmin 
19 18
 implements TableDefinitionExporter {
19
+    knex:Knex
20
+    config: RPCConfigLoader<AdminConf>
20 21
 
21 22
     private express
22 23
     private httpServer
23
-    private pluginLoader:RPCPluginLoader = new RPCPluginLoader(this)
24
-    private eventBus:FrontworkEventBus = new FrontworkEventBus(this)
25
-    config: RPCConfigLoader<AdminConf>
26
-    knex:Knex
27 24
 
28
-    constructor(){}
25
+    constructor(private components: FrontworkComponent[]){
26
+        this.config = new RPCConfigLoader<AdminConf>({
27
+            name: "FrontworkAdminConf", 
28
+            getDefaultConfig: () => {
29
+                return {
30
+                    httpPort: 8080,
31
+                    eventBusConf: {},
32
+                    dbConf: {
33
+                        client: 'sqlite3',
34
+                        connection: {
35
+                            filename: Path.join(__dirname, "data/frontworkAdmin.sqlite")
36
+                        },
37
+                        useNullAsDefault: true
38
+                    }
39
+                }   
40
+            }
41
+        }, './config', this.configChangeHandler) 
42
+
43
+        components.forEach(c => {
44
+            c.admin = this
45
+            if(c.onSetAdmin) c.onSetAdmin(this)
46
+        })
47
+    }
29 48
 
30 49
     async start(){
31
-        this.initConfig()
32 50
         await this.makeKnex()
33 51
         this.startWebsocket()
52
+        await Promise.all( this.components.map(c => c.initialize?c.initialize():undefined ))
34 53
         this.startWebserver()
54
+        
35 55
     }
36 56
 
37 57
     protected configChangeHandler = (conf:AdminConf, key?:string) => {
@@ -48,37 +68,15 @@ implements TableDefinitionExporter {
48 68
         return this.config.setConfigKey(key, value)
49 69
     }
50 70
 
51
-    private initConfig(){
52
-        this.config = new RPCConfigLoader<AdminConf>({
53
-            name: "FrontworkAdminConf", 
54
-            getDefaultConfig: () => {
55
-                return {
56
-                    httpPort: 8080,
57
-                    eventBusConf: {},
58
-                    dbConf: {
59
-                        client: 'sqlite3',
60
-                        connection: {
61
-                            filename: Path.join(__dirname, "data/frontworkAdmin.sqlite")
62
-                        },
63
-                        useNullAsDefault: true
64
-                    }
65
-                }   
66
-            }
67
-        }, './config', this.configChangeHandler) 
68
-    }
69
-
70 71
     getTableDefinitions(): TableDefiniton[]{
71 72
         return [
72
-            this.eventBus,
73
-            ...this.pluginLoader.getPlugins()
73
+            ...this.components
74 74
         ].flatMap(exporter => exporter.getTableDefinitions())
75 75
     }
76 76
 
77 77
     private startWebsocket(){
78 78
         new RPCServer(20000, [
79
-            this.config,
80
-            this.pluginLoader,
81
-            this.eventBus
79
+            ...this.components,
82 80
         ])
83 81
     }
84 82
 

+ 34
- 0
src/backend/Components/Debugger/Debugger.ts 查看文件

@@ -0,0 +1,34 @@
1
+import { RPCExporter } from "rpclibrary"
2
+import { FrontworkAdmin } from "../../Admin/Admin"
3
+import { TableDefiniton } from "../../Types/Types"
4
+import { PrivilegedRPCExporter } from "../../Types/PrivilegedRPCExporter"
5
+import { FrontworkComponent } from "../../Types/FrontworkComponent"
6
+
7
+export class Debugger 
8
+implements FrontworkComponent<any,any>{
9
+    public admin: FrontworkAdmin
10
+    name = "Debugger" 
11
+    
12
+
13
+    constructor(private exporters: PrivilegedRPCExporter[]){
14
+    }
15
+
16
+    exportRPCs(){
17
+        
18
+        return [{
19
+            name: 'getTable',
20
+            call: async(table:string) => this.admin.knex.select('*').from(table)
21
+        }, 
22
+        ...this.exporters.flatMap(e => e.exportRPCs()),
23
+        ...this.exporters.flatMap(e => e.exportRPCFeatures().flatMap(e => e.exportRPCs()))]
24
+    }
25
+
26
+    exportRPCFeatures(): RPCExporter<any, any, {}>[] {
27
+        return []
28
+    }
29
+
30
+    getTableDefinitions(): TableDefiniton[] {
31
+        return []
32
+    }
33
+
34
+}

src/backend/Eventbus.ts → src/backend/Components/Eventbus.ts 查看文件

@@ -1,9 +1,10 @@
1 1
 import { RPCExporter, SubscriptionResponse, ErrorResponse, SuccessResponse } from "rpclibrary";
2
-import { FrontworkAdmin } from "./Admin";
3
-import { TableDefinitionExporter } from "./Interfaces";
2
+import { FrontworkAdmin } from "../Admin/Admin";
3
+import { TableDefinitionExporter } from "../Types/Interfaces";
4 4
 import { getLogger } from 'frontblock-generic/Types';
5 5
 
6 6
 import * as uuid from 'uuid/v4'
7
+import { TableDefiniton } from "../Types/Types";
7 8
 
8 9
 export type NotificationSeverity = 'Info' | 'Important' | 'Error'
9 10
 
@@ -84,11 +85,11 @@ implements RPCExporter<EventbusIfc, "Eventbus">, TableDefinitionExporter {
84 85
         }]
85 86
     }
86 87
 
87
-    getTableDefinitions(){
88
+    getTableDefinitions(): TableDefiniton[]{
88 89
         return [{
89 90
             name: 'notifications',
90 91
             tableBuilder: (table) => {
91
-                table.increments('ID');
92
+                table.increments('ID').primary();
92 93
                 table.string('severity');
93 94
                 table.string('topic');
94 95
                 table.string('message');

+ 107
- 0
src/backend/Components/Item/ItemManager.ts 查看文件

@@ -0,0 +1,107 @@
1
+import { TableDefinitionExporter } from "../../Types/Interfaces";
2
+import { TableDefiniton, _Rank } from "../../Types/Types";
3
+import { FrontworkAdmin } from "../../Admin/Admin";
4
+import { T1 } from "../../Types/Items";
5
+import { FrontworkComponent } from "../../Types/FrontworkComponent";
6
+import { RPC } from "rpclibrary";
7
+const fetch = require('node-fetch')
8
+const xml2js = require('xml2js');
9
+const parser = new xml2js.Parser(/* options */);
10
+
11
+
12
+export type ItemManagerFeatureIfc = any
13
+
14
+export type Item = {
15
+    id?:number
16
+    name:string
17
+    iconname:string
18
+    url:string
19
+    quality:string
20
+    hidden:boolean
21
+}
22
+
23
+export class ItemManager
24
+implements FrontworkComponent<ItemManagerFeatureIfc>, TableDefinitionExporter{
25
+    
26
+    admin:FrontworkAdmin    
27
+    name = "ItemManager";    
28
+    
29
+    exportRPCs(): RPC<any, any>[]{
30
+        return [{
31
+            name: 'getItems',
32
+            call: async () => await this.getItems()
33
+        },{
34
+            name: 'getItem',
35
+            call: async (name:string) => await this.getItem(name) 
36
+        }]
37
+    }
38
+
39
+    exportRPCFeatures() {
40
+        return []
41
+    }
42
+
43
+    getItems = async () :Promise<Item[]> => await this.admin.knex.select('*').from('items')
44
+
45
+    getItem  = async (name:string):Promise<Item> => {
46
+        const res = await fetch('https://classic.wowhead.com/item='+name+'&xml'); 
47
+        const txt = await res.text(); 
48
+        const r = await parser.parseStringPromise(txt); 
49
+
50
+        try{
51
+            return <Item>{
52
+                name: r.wowhead.item[0].name[0],
53
+                iconname: r.wowhead.item[0].icon[0]._,
54
+                url: r.wowhead.item[0].link[0],
55
+                quality: r.wowhead.item[0].quality[0]._,
56
+            } 
57
+        }catch (e){
58
+            console.log(name)
59
+            throw e
60
+        }
61
+    }
62
+
63
+    getTableDefinitions(): TableDefiniton[] {
64
+        return [
65
+            {
66
+                name: 'reservations',
67
+                tableBuilder: (table) => {
68
+                    table.integer("user_id").primary()
69
+                    table.foreign("user_id").references("id").inTable('users')
70
+                    table.integer("item_id").primary()
71
+                    table.foreign("item_id").references("id").inTable('items')
72
+                    table.integer("raid_id").primary()
73
+                    table.foreign("raid_id").references("id").inTable('raids')
74
+                }
75
+            },{
76
+                name: 'items',
77
+                tableBuilder: (table) => {
78
+                    table.increments("id").primary()
79
+                    table.string('name').unique().notNullable()
80
+                    table.string('iconname').notNullable()
81
+                    table.string('url').notNullable()
82
+                    table.string('quality').defaultTo('Epic').notNullable()
83
+                    table.boolean('hidden').defaultTo(false).notNullable()
84
+                }
85
+            }]
86
+    }
87
+
88
+    countItems = async() :Promise<number> => {
89
+        const count = await this.admin.knex('items').count('*');
90
+        return <number>count[0]['count(*)']
91
+    }
92
+
93
+    initialize = async() => {
94
+        const allItems = [...T1]
95
+        const countCache = await this.countItems()
96
+        if(countCache != allItems.length){
97
+            const items:Item[] = await Promise.all(allItems.map(async (i) => this.getItem(i)))
98
+            try{
99
+                await this.admin
100
+                .knex('items')
101
+                .insert(items)
102
+            }catch(e){
103
+                console.error(e)
104
+            }
105
+        }
106
+    }
107
+}

+ 196
- 0
src/backend/Components/Login/LoginManager.ts 查看文件

@@ -0,0 +1,196 @@
1
+import { RPCServer } from "rpclibrary";
2
+import { TableDefiniton, AnyRPCExporter, User, RPCPermission, _Rank, Token, Auth } from "../../Types/Types";
3
+import { FrontworkAdmin } from "../../Admin/Admin";
4
+import { PrivilegedRPCExporter } from "../../Types/PrivilegedRPCExporter";
5
+import { FrontworkComponent } from "../../Types/FrontworkComponent";
6
+const uuid = require('uuid/v4')
7
+
8
+
9
+export class LoginManager
10
+implements FrontworkComponent{
11
+    name = "Authenticator" as "Authenticator";   
12
+    admin:FrontworkAdmin
13
+    
14
+    constructor(private exporters: PrivilegedRPCExporter[]){}
15
+
16
+    exportRPCs() {
17
+        return [
18
+            {
19
+                name: 'login' as 'login',
20
+                call: async (username:string, pwHash:string) => await this.login(username, pwHash) 
21
+            },{
22
+                name: 'authenticate' as 'authenticate',
23
+                call: async (tokenValue:string | Token) => await this.authenticate(tokenValue)
24
+            }
25
+        ]
26
+    }
27
+
28
+    onSetAdmin(admin:FrontworkAdmin){
29
+        this.exporters.forEach(e => e['admin'] = admin)
30
+    }
31
+
32
+    exportRPCFeatures() {
33
+        return [{
34
+            name: 'createUser' as 'createUser',
35
+            exportRPCs: () => [{
36
+                name: 'createUser' as 'createUser',
37
+                call: async (user:User) => {
38
+                    return await this.createUser(user)
39
+                } 
40
+            }]
41
+        },{
42
+            name: 'modifyPermissions' as 'modifyPermissions',
43
+            exportRPCs: () => [{
44
+                name: 'getPermissions' as 'getPermissions',
45
+                call: async () => await this.getPermissions() 
46
+            },{
47
+                name: 'setPermission' as 'setPermission',
48
+                call: async (perm: RPCPermission) => await this.setPermission(perm) 
49
+            }]
50
+        }]
51
+    }
52
+    
53
+    getTableDefinitions(): TableDefiniton[] {
54
+        return [
55
+            {
56
+                name: 'users',
57
+                tableBuilder: (table) => {
58
+                    table.increments("id").primary()
59
+                    table.string("name").notNullable().unique()
60
+                    table.string("pwhash").notNullable()
61
+                    table.string("rank").notNullable()
62
+                    table.string("class").notNullable()
63
+                    table.string("email").nullable().unique()
64
+                }
65
+            },{
66
+                name: 'rpcpermissions',
67
+                tableBuilder: (table) => {
68
+                    table.string("rpcName").primary().notNullable()
69
+                    table.boolean("ADMIN").defaultTo(true).notNullable()
70
+                    _Rank.forEach(r => table.boolean(r).defaultTo(false).notNullable())
71
+                }
72
+            },{
73
+                name: 'tokens',
74
+                tableBuilder: (table) => {
75
+                    table.string('value').primary()
76
+                    table.integer('user_id').notNullable()
77
+                    table.foreign('user_id').references('users')
78
+                    table.dateTime('created').defaultTo(this.admin.knex.fn.now())
79
+                }
80
+            }
81
+        ,...this.exporters.flatMap(exp => exp['getTableDefinitions']?exp['getTableDefinitions']():undefined)]
82
+    }
83
+
84
+    async initialize(){
85
+        await Promise.all( 
86
+            [this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (rpc) => {
87
+            try{
88
+                await this.admin.knex.insert({ rpcname: rpc.name }).into('rpcpermissions')
89
+            }catch(e){}
90
+        })))
91
+
92
+        await Promise.all(this.exporters.map(ex => ex['initialize']?ex['initialize']():undefined))
93
+    }
94
+
95
+    async setPermission(permission: RPCPermission){
96
+        await this.admin.knex('rpcpermissions')
97
+        .where('rpcname', '=', permission.name)
98
+        .update(permission)
99
+    }
100
+
101
+    getPermissions = async () : Promise<RPCPermission[]> => {
102
+        return await this.admin.knex.select('*').from('rpcpermissions')
103
+    }
104
+
105
+    getRPCForUser = async (user:User): Promise<AnyRPCExporter[]> => {
106
+        return [...this.exportRPCFeatures(), ...this.exporters.flatMap((exp) => exp.exportRPCFeatures())]
107
+    }
108
+
109
+    createUser = async(user:User): Promise<User> => {
110
+        await this.admin.knex('users')
111
+        .insert(user)
112
+        
113
+        const users = await this.admin.knex
114
+        .select("*")
115
+        .from('users')
116
+        .where(user)
117
+        return users[0]
118
+    }
119
+
120
+    login = async(username:string, pwHash:string) : Promise<Token> => {
121
+        const res:User[] = await this.admin.knex
122
+        .select("*")
123
+        .from('users')
124
+        .where({ name: username })
125
+        
126
+        if(res.length > 0 && pwHash === res[0].pwhash){
127
+            return await this.createToken(res[0])
128
+        }
129
+
130
+        throw new Error('login failed')
131
+    }
132
+
133
+    authenticate = async(tokenValue: string | Token) : Promise<Auth> => {
134
+        if(typeof tokenValue !== 'string') tokenValue = tokenValue.value 
135
+
136
+        const res : User[] = await this.admin.knex
137
+        .select('users.id', 'name', 'class', 'rank', 'email')
138
+        .from('tokens')
139
+        .join('users', function(){
140
+            this.on('users.id', '=', 'tokens.user_id')
141
+        })
142
+        .where({ value: tokenValue})
143
+
144
+        if(res.length === 0)
145
+            throw new Error('authentication failed')
146
+
147
+        const allowedRPCs = await this.getRPCForUser(res[0])
148
+        const randomPort = 20000 + Math.floor(Math.random() * 10000)
149
+        while(true){
150
+            try{
151
+                let commSock = new RPCServer(randomPort, allowedRPCs, {
152
+                    closeHandler: () => { 
153
+                        console.log(res[0].name, 'disconnected')
154
+                        commSock.destroy() 
155
+                    },
156
+                    connectionHandler: () => {
157
+                        console.log(res[0].name, 'connected')
158
+                        cancelTimeout()
159
+                    },
160
+                    sesame: tokenValue
161
+                })
162
+                const timeout = setTimeout(() => {
163
+                    console.log(res[0].name, 'timeout')
164
+                    commSock.destroy()
165
+                }, 10000)
166
+                const cancelTimeout = () => { clearTimeout(timeout) }
167
+                break;
168
+            }catch(e){
169
+                //retry
170
+            }
171
+        }
172
+
173
+        return {
174
+            port: randomPort,
175
+            user: res[0],
176
+            token: {
177
+                value: tokenValue,
178
+                user_id: res[0].id!
179
+            }
180
+        }
181
+    }
182
+
183
+    createToken = async(user:User): Promise<Token> => {
184
+        const old = await this.admin.knex.select('*').from('tokens').where({user_id: user.id})
185
+        if(old.length === 0){
186
+            const token:Token = {
187
+                value: uuid(),
188
+                user_id: user.id!
189
+            }
190
+            await this.admin.knex('tokens').insert(token)
191
+            return token
192
+        }else{
193
+            return old[0]
194
+        }
195
+    }
196
+}

src/backend/PluginLoader.ts → src/backend/Components/PluginLoader.ts 查看文件

@@ -1,8 +1,8 @@
1 1
 import { RPCExporter } from "rpclibrary";
2 2
 import { Git } from "upgiter"
3 3
 import { FolderStatus } from "upgiter/js/src/Types";
4
-import { Plugin } from "./Plugin";
5
-import { FrontworkAdmin } from "./Admin";
4
+import { Plugin } from "../Types/Plugin";
5
+import { FrontworkAdmin } from "../Admin/Admin";
6 6
 
7 7
 class PluginLoader {
8 8
     private runningPlugins: Plugin[] = []

src/backend/RPCConfigLoader.ts → src/backend/Components/RPCConfigLoader.ts 查看文件


+ 95
- 0
src/backend/Components/Raid/RaidManager.ts 查看文件

@@ -0,0 +1,95 @@
1
+import { TableDefiniton, User, _Rank, Raid, Signup, RaidManagerFeatureIfc } from "../../Types/Types";
2
+import { FrontworkAdmin } from "../../Admin/Admin";
3
+import { FrontworkComponent } from "../../Types/FrontworkComponent";
4
+
5
+
6
+export class RaidManager
7
+implements FrontworkComponent<RaidManagerFeatureIfc>{
8
+    name = "RaidManager";    
9
+    admin: FrontworkAdmin
10
+
11
+    exportRPCs = () => []
12
+
13
+    exportRPCFeatures() {
14
+        return [{
15
+            name: 'manageRaid' as 'manageRaid',
16
+            exportRPCs: () => [{
17
+                name: 'createRaid' as 'createRaid',
18
+                call: async (raid:Raid) => await this.createRaid(raid)
19
+            },{
20
+                name: 'addSignup' as 'addSignup',
21
+                call: async(signup: Signup) => await this.addSignup(signup)
22
+            },{
23
+                name: 'removeSignup' as 'removeSignup',
24
+                call: async(signup: Signup) => await this.removeSignup(signup)
25
+            }]
26
+        },{
27
+            name: 'signup' as 'signup',
28
+            exportRPCs: () => [{
29
+                name: 'getRaids' as 'getRaids',
30
+                call: async () => await this.getRaids()
31
+            },{
32
+                name: 'getSingups' as 'getSingups',
33
+                call: async(raid: Raid) => await this.getSignups(raid)
34
+            },{
35
+                name: 'sign' as 'sign',
36
+                call: async(user:User, raid:Raid) => await this.sign(user, raid)
37
+            }]
38
+        },]
39
+    }
40
+    
41
+    getTableDefinitions(): TableDefiniton[] {
42
+        return [
43
+            {
44
+                name: 'raids',
45
+                tableBuilder: (table) => {
46
+                    table.increments('id').primary()
47
+                    table.dateTime('start').notNullable()
48
+                    table.string('description').notNullable()
49
+                    table.string('title').notNullable()
50
+                    table.integer('minrank').notNullable()
51
+                }
52
+            },{
53
+                name: 'signups',
54
+                tableBuilder: (table) => {
55
+                    table.integer('raid_id').primary()
56
+                    table.foreign('raid_id').references('id').inTable('raids')
57
+                    table.integer('user_id').primary()
58
+                    table.foreign('user_id').references('id').inTable('users')
59
+                }
60
+            }            
61
+        ]
62
+    }
63
+
64
+    createRaid = async (raid:Raid) => await this.admin
65
+    .knex('raids')
66
+    .insert(raid)
67
+    
68
+    addSignup = async (signup: Signup) => await this.admin
69
+    .knex('signups')
70
+    .insert(signup)
71
+    
72
+    removeSignup = async (signup: Signup) => await this.admin
73
+    .knex('signups')
74
+    .where({
75
+        raid_id: signup.raid_id, 
76
+        user_id: signup.user_id
77
+    })
78
+    .delete()
79
+
80
+    getRaids = async () => await this.admin.knex
81
+    .select('*')
82
+    .from('raids')
83
+    
84
+    getSignups = async (raid:Raid) => await this.admin.knex
85
+    .select('*')
86
+    .from('signups')
87
+    .where('raid_id', '=', raid.id!)
88
+    
89
+    sign = async (user:User, raid:Raid) => await this.admin
90
+    .knex('signups')
91
+    .insert({
92
+        raid_id: raid.id!,
93
+        user_id: user.id!
94
+    })
95
+}

+ 0
- 24
src/backend/Installer.ts 查看文件

@@ -1,24 +0,0 @@
1
-import { Plugin } from "./Plugin"
2
-import { getLogger } from "frontblock-generic/Types"
3
-import { FrontworkAdmin } from "./Admin";
4
-var exec = require('child-process-promise').exec;
5
-
6
-const logger = getLogger("installer", 'info') 
7
-
8
-export type NPMPkgName = string
9
-export type NPMVersion = string
10
-
11
-export const installAdmin = (plugins: Plugin[] = []) => {
12
-    
13
-    const npmPkgs:[NPMPkgName, NPMVersion][] = [['sqlite3', '4.1.0'], ['knex', '0.19.2']]
14
-    const deps = npmPkgs.map(tuple => tuple.join('@') ).join(" ")
15
-    logger.info("Installing plaform dependencies: "+deps)
16
-
17
-    exec("npm i " + deps).then(async process => {
18
-        logger.debug(process.stdout)    
19
-        const Admin = require("./Admin").FrontworkAdmin
20
-        const fbAdmin:FrontworkAdmin = new Admin(plugins)
21
-        fbAdmin.start()
22
-    })
23
-
24
-}

+ 20
- 2
src/backend/Launcher.ts 查看文件

@@ -1,2 +1,20 @@
1
-import { installAdmin } from "./Installer";
2
-installAdmin()
1
+import { FrontworkAdmin } from './Admin/Admin'
2
+import { RaidManager } from "./Components/Raid/RaidManager";
3
+import { ItemManager } from "./Components/Item/ItemManager";
4
+import { LoginManager } from "./Components/Login/LoginManager";
5
+import { Debugger } from './Components/Debugger/Debugger';
6
+import { FrontworkComponent } from './Types/FrontworkComponent';
7
+require('events').EventEmitter.defaultMaxListeners = 0;
8
+
9
+let raidManager = new RaidManager()
10
+let itemManager = new ItemManager()
11
+let loginManager = new LoginManager([
12
+    raidManager,
13
+    itemManager
14
+])
15
+
16
+let components:FrontworkComponent[] = [ raidManager, itemManager, loginManager ]
17
+let dbg = new Debugger(components)
18
+
19
+
20
+new FrontworkAdmin([dbg, ...components]).start()

+ 0
- 14
src/backend/Types.ts 查看文件

@@ -1,14 +0,0 @@
1
-import Knex = require("knex")
2
-
3
-export declare type NotificationSeverity = 'Info' | 'Important' | 'Error';
4
-
5
-export type AdminConf = { 
6
-    httpPort: number,
7
-    dbConf:Knex.Config, 
8
-    eventBusConf: { [topic in string]: NotificationSeverity}
9
-}
10
-
11
-export type TableDefiniton = {
12
-    name: string, 
13
-    tableBuilder: (table: Knex.CreateTableBuilder) => void
14
-}

+ 24
- 0
src/backend/Types/FrontworkComponent.ts 查看文件

@@ -0,0 +1,24 @@
1
+import { PrivilegedRPCExporter } from "./PrivilegedRPCExporter";
2
+import { RPCInterface, RPC, AnyFunction, RPCExporter } from "rpclibrary";
3
+import { TableDefinitionExporter } from "./Interfaces";
4
+import { FrontworkAdmin } from "../Admin/Admin";
5
+import { TableDefiniton } from "./Types";
6
+
7
+export interface FrontworkComponent<
8
+    Ifc extends RPCInterface = RPCInterface, 
9
+    Name extends keyof Ifc = keyof Ifc, 
10
+    SubresT = {}
11
+> extends
12
+    PrivilegedRPCExporter<Ifc, Name, SubresT>,
13
+    TableDefinitionExporter
14
+{
15
+    admin:FrontworkAdmin
16
+    name: string;
17
+
18
+    exportRPCFeatures(): RPCExporter<Ifc, Name, SubresT>[] 
19
+    exportRPCs(): RPC<string, AnyFunction, {}>[] 
20
+    getTableDefinitions(): TableDefiniton[] 
21
+
22
+    initialize?(): Promise<any>
23
+    onSetAdmin?(admin:FrontworkAdmin): void
24
+}

src/backend/Interfaces.ts → src/backend/Types/Interfaces.ts 查看文件

@@ -2,4 +2,4 @@ import { TableDefiniton } from "./Types";
2 2
 
3 3
 export interface TableDefinitionExporter{
4 4
     getTableDefinitions(): TableDefiniton[]
5
-}
5
+}

+ 64
- 0
src/backend/Types/Items.ts 查看文件

@@ -0,0 +1,64 @@
1
+export const T1 = [
2
+"Robe of Volatile Power",
3
+"Salamander Scale Pants",
4
+"Heavy Dark Iron Ring",
5
+"Ring of Spell Power",
6
+"Sorcerous Dagger",
7
+"Wristguards of Stability",
8
+"Helm of the Lifegiver",
9
+"Fire Runed Grimoire",
10
+"Crimson Shocker",
11
+"Mana Igniting Cord",
12
+"Quick Strike Ring",
13
+"Seal of the Archmagus",
14
+"Talisman of Ephemeral Power",
15
+"Flameguard Gauntlets",
16
+"Magma Tempered Boots",
17
+"Obsidian Edged Blade",
18
+"Aged Core Leather Gloves",
19
+"Sabatons of the Flamewalker",
20
+"Striker's Mark",
21
+"Medallion of Steadfast Might",
22
+"Earthshaker",
23
+"Brutality Blade",
24
+"Aurastone Hammer",
25
+"Gutgore Ripper",
26
+"Drillborer Disk",
27
+"Azuresong Mageblade",
28
+"Staff of Dominance",
29
+"Blastershot Launcher",
30
+"The Eye of Divinity",
31
+"Ancient Petrified Leaf",
32
+"Finkle's Lava Dredger",
33
+"Core Hound Tooth",
34
+"Core Forged Greaves",
35
+"Gloves of the Hypnotic Flame",
36
+"Sash of Whispered Secrets",
37
+"Wild Growth Spaulders",
38
+"Fireproof Cloak",
39
+"Wristguards of True Flight",
40
+"Fireguard Shoulders",
41
+"Cauterizing Band",
42
+"Onslaught Girdle",
43
+"Perdition's Blade",
44
+"Cloak of the Shrouded Mists",
45
+"Band of Accuria",
46
+"Crown of Destruction",
47
+"Choker of the Fire Lord",
48
+"Band of Sulfuras",
49
+"Dragon's Blood Cape",
50
+"Malistar's Defender",
51
+"Spinal Reaper",
52
+"Bonereaver's Edge",
53
+"Shard of the Flame",
54
+"Essence of the Pure Flame",
55
+"Eye of Sulfuras",
56
+"Deathbringer",
57
+"Vis'kag the Bloodletter",
58
+"Sapphiron Drape",
59
+"Ancient Cornerstone Grimoire",
60
+"Eskhandar's Collar",
61
+"Ring of Binding",
62
+"Shard of the Scale",
63
+"Head of Onyxia",
64
+"Bindings of the Windseeker"]

src/backend/Plugin.ts → src/backend/Types/Plugin.ts 查看文件

@@ -1,4 +1,4 @@
1
-import { FrontworkAdmin } from "./Admin"
1
+import { FrontworkAdmin } from "../Admin/Admin"
2 2
 import { RPC, RPCExporter } from "rpclibrary"
3 3
 import { TableDefiniton } from "./Types"
4 4
 import { TableDefinitionExporter } from "./Interfaces"

+ 7
- 0
src/backend/Types/PrivilegedRPCExporter.ts 查看文件

@@ -0,0 +1,7 @@
1
+import { RPCExporter, RPCInterface, RPC, RPCInterfaceArray } from "rpclibrary";
2
+
3
+export interface PrivilegedRPCExporter <Ifc extends RPCInterface = RPCInterface, Name extends keyof Ifc = keyof Ifc, SubresT = {}>
4
+extends RPCExporter<any,any>{
5
+
6
+    exportRPCFeatures() : RPCExporter<Ifc, Name, SubresT>[]
7
+}

+ 91
- 0
src/backend/Types/Types.ts 查看文件

@@ -0,0 +1,91 @@
1
+import * as Knex from "knex"
2
+import { RPCExporter } from "rpclibrary";
3
+
4
+export declare type NotificationSeverity = 'Info' | 'Important' | 'Error';
5
+
6
+export type AdminConf = { 
7
+    httpPort: number,
8
+    dbConf:Knex.Config, 
9
+    eventBusConf: { [topic in string]: NotificationSeverity}
10
+}
11
+
12
+export type TableDefiniton = {
13
+    name: string, 
14
+    tableBuilder: (table: Knex.CreateTableBuilder) => void
15
+}
16
+
17
+export type Rank =             "ADMIN" | "Guildmaster" | "Officer" | "Classleader" | "Raider" | "Trial" | "Social" | "Guest"
18
+export const _Rank : Rank[] = ["Guildmaster" , "Officer" , "Classleader" , "Raider" , "Trial" , "Social" , "Guest"]
19
+export type Class =              "Warrior" | "Rogue" | "Hunter" | "Mage" | "Warlock" | "Priest" | "Shaman" | "Paladin" | "Druid"
20
+export const _Class : Class[] = ["Warrior" , "Rogue" , "Hunter" , "Mage" , "Warlock" , "Priest" , "Shaman" , "Paladin" , "Druid"]
21
+
22
+export type AnyRPCExporter = RPCExporter<any,any>
23
+
24
+export type RPCPermission = {
25
+    name: string
26
+} & {
27
+    [rank in Rank] : boolean
28
+}
29
+
30
+export type User = {
31
+    id?: number
32
+    name: string
33
+    pwhash: string
34
+    class: Class
35
+    rank: Rank
36
+    email?: string
37
+}
38
+
39
+export type Raid = {
40
+    id?: number
41
+    title: string
42
+    description: string
43
+    start: string
44
+    minrank: Rank
45
+}
46
+
47
+export type Signup = {
48
+    raid_id: number
49
+    user_id: number
50
+}
51
+
52
+export type Token = {
53
+    value: string
54
+    user_id: number
55
+    created?: number
56
+}
57
+
58
+export type Auth = {port: number, user: User, token: Token}
59
+
60
+export type FrontcraftFeatureIfc =  RaidManagerFeatureIfc & LoginManagerFeatureIfc 
61
+
62
+
63
+export type LoginManagerIfc = {
64
+    Authenticator: {
65
+        login: (username:string, pwHash:string) => Promise<Token>
66
+        authenticate: (token:string | Token) => Promise<Auth>
67
+    }
68
+}
69
+
70
+export type LoginManagerFeatureIfc = {
71
+    createUser: {
72
+        createUser: (user:User) => Promise<User>
73
+    }
74
+    modifyPermissions: {
75
+        setPermission: (perm: RPCPermission) => Promise<void>
76
+        getPermissions: () => Promise<RPCPermission[]>
77
+    }
78
+}
79
+
80
+export type RaidManagerFeatureIfc = {
81
+    manageRaid: {
82
+        createRaid: (raid:Raid) => Promise<any>
83
+        addSignup: (signup: Signup) => Promise<any>
84
+        removeSignup: (signup: Signup) => Promise<any>    
85
+    }
86
+    signup: {
87
+        getRaids: () => Promise<Raid[]>
88
+        getSingups: (raid:Raid) => Promise<Signup[]>
89
+        sign: (user:User, raid:Raid, attending:boolean) => Promise<any>
90
+    }
91
+}

+ 6
- 2
src/frontend/angular.json 查看文件

@@ -9,8 +9,12 @@
9 9
       "projectType": "application",
10 10
       "architect": {
11 11
         "build": {
12
-          "builder": "@angular-devkit/build-angular:browser",
12
+          "builder": "@angular-builders/custom-webpack:browser",
13 13
           "options": {
14
+            "customWebpackConfig": {
15
+              "path": "./custom-webpack.config.js",
16
+              "replaceDuplicatePlugins": true
17
+            },
14 18
             "preserveSymlinks": true,
15 19
             "rebaseRootRelativeCssUrls": true,
16 20
             "outputPath": "dist",
@@ -75,7 +79,7 @@
75 79
           }
76 80
         },
77 81
         "serve": {
78
-          "builder": "@angular-devkit/build-angular:dev-server",
82
+          "builder": "@angular-builders/custom-webpack:dev-server",
79 83
           "options": {
80 84
             "browserTarget": "ngx-admin-demo:build"
81 85
           },

+ 4
- 0
src/frontend/custom-webpack.config.js 查看文件

@@ -0,0 +1,4 @@
1
+module.exports = {
2
+    externals: ['http'],
3
+    node: {global: true, fs: 'empty'}
4
+}

+ 24
- 4
src/frontend/package-lock.json 查看文件

@@ -9,6 +9,22 @@
9 9
       "resolved": "https://registry.npmjs.org/@agm/core/-/core-1.0.0-beta.5.tgz",
10 10
       "integrity": "sha512-LVENJqtBZEWpX+uJkGI0zgg+Xkm2KkktQm4ojZozArbeNvQkVL6pqVc04Mme6vvOzwJpD1cET5w4byC8Xaq1QQ=="
11 11
     },
12
+    "@angular-builders/custom-webpack": {
13
+      "version": "8.2.0",
14
+      "resolved": "https://registry.npmjs.org/@angular-builders/custom-webpack/-/custom-webpack-8.2.0.tgz",
15
+      "integrity": "sha512-6654RfyqhTGhCI0edC9YU/iMn1UJnzX01bxYJbDWFgvReCqXdlgy+Fe9tp1MeqKweX6BQ1d0gRroR/WjY1aX0A==",
16
+      "requires": {
17
+        "lodash": "^4.17.10",
18
+        "webpack-merge": "^4.2.1"
19
+      },
20
+      "dependencies": {
21
+        "lodash": {
22
+          "version": "4.17.15",
23
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
24
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
25
+        }
26
+      }
27
+    },
12 28
     "@angular-devkit/architect": {
13 29
       "version": "0.800.2",
14 30
       "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.800.2.tgz",
@@ -11695,6 +11711,11 @@
11695 11711
         }
11696 11712
       }
11697 11713
     },
11714
+    "ngx-cookie-service": {
11715
+      "version": "2.2.0",
11716
+      "resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-2.2.0.tgz",
11717
+      "integrity": "sha512-2kaC1itlEMxiMAPJ320hOpcwU9vhvjbKQCZ1Go6bGhYjJtqG7eYvhNP7mM9IhFz1/afG2tBryJPySWmFUGhRpA=="
11718
+    },
11698 11719
     "ngx-echarts": {
11699 11720
       "version": "4.0.1",
11700 11721
       "resolved": "https://registry.npmjs.org/ngx-echarts/-/ngx-echarts-4.0.1.tgz",
@@ -14314,9 +14335,9 @@
14314 14335
       "integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
14315 14336
     },
14316 14337
     "rpclibrary": {
14317
-      "version": "1.3.17",
14318
-      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.3.17.tgz",
14319
-      "integrity": "sha512-ZdhZ1TSDO+bcz5kCJ7Ol+YAAyYpwg7YI/hETS4vv3RYerUEQVZSZjcm22J5a91RnQVN2SRiXzdoXbbFb/Renog==",
14338
+      "version": "1.4.0",
14339
+      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.4.0.tgz",
14340
+      "integrity": "sha512-JUU7+HymV2ZTI+NrIVOiIr5LGFoRsPq4k/ffdUonqIpd9fjOHBQ2/PFLVXx9z94+dKxdqN8/D9ZXPwU03ovZrg==",
14320 14341
       "requires": {
14321 14342
         "bsock": "^0.1.9",
14322 14343
         "http": "0.0.0",
@@ -20446,7 +20467,6 @@
20446 20467
       "version": "4.2.1",
20447 20468
       "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.1.tgz",
20448 20469
       "integrity": "sha512-4p8WQyS98bUJcCvFMbdGZyZmsKuWjWVnVHnAS3FFg0HDaRVrPbkivx2RYCre8UiemD67RsiFFLfn4JhLAin8Vw==",
20449
-      "dev": true,
20450 20470
       "requires": {
20451 20471
         "lodash": "^4.17.5"
20452 20472
       }

+ 3
- 1
src/frontend/package.json 查看文件

@@ -30,6 +30,7 @@
30 30
   },
31 31
   "dependencies": {
32 32
     "@agm/core": "^1.0.0-beta.5",
33
+    "@angular-builders/custom-webpack": "^8.2.0",
33 34
     "@angular/animations": "^8.0.0",
34 35
     "@angular/cdk": "^8.0.0",
35 36
     "@angular/common": "^8.0.0",
@@ -62,12 +63,13 @@
62 63
     "ng2-ckeditor": "^1.2.2",
63 64
     "ng2-completer": "2.0.8",
64 65
     "ng2-smart-table": "1.3.5",
66
+    "ngx-cookie-service": "^2.2.0",
65 67
     "ngx-echarts": "^4.0.1",
66 68
     "node-sass": "^4.12.0",
67 69
     "normalize.css": "6.0.0",
68 70
     "pace-js": "1.0.2",
69 71
     "roboto-fontface": "0.8.0",
70
-    "rpclibrary": "^1.3.17",
72
+    "rpclibrary": "^1.4.0",
71 73
     "rxjs": "6.5.2",
72 74
     "rxjs-compat": "6.3.0",
73 75
     "socicon": "3.0.5",

+ 13
- 125
src/frontend/src/app/@core/core.module.ts 查看文件

@@ -1,146 +1,35 @@
1
-import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';
1
+import { ModuleWithProviders, NgModule, Optional, SkipSelf, APP_INITIALIZER } from '@angular/core';
2 2
 import { CommonModule } from '@angular/common';
3
-import { NbAuthModule, NbDummyAuthStrategy } from '@nebular/auth';
4
-import { NbSecurityModule, NbRoleProvider } from '@nebular/security';
5
-import { of as observableOf } from 'rxjs';
6
-
7 3
 import { throwIfAlreadyLoaded } from './module-import-guard';
4
+import { CookieService } from 'ngx-cookie-service';
5
+
8 6
 import {
9 7
   AnalyticsService,
10 8
   LayoutService,
11 9
   PlayerService,
12 10
   StateService,
13 11
 } from './utils';
14
-import { UserData } from './data/users';
15
-import { ElectricityData } from './data/electricity';
16
-import { SmartTableData } from './data/smart-table';
17
-import { UserActivityData } from './data/user-activity';
18
-import { OrdersChartData } from './data/orders-chart';
19
-import { ProfitChartData } from './data/profit-chart';
20
-import { TrafficListData } from './data/traffic-list';
21
-import { EarningData } from './data/earning';
22
-import { OrdersProfitChartData } from './data/orders-profit-chart';
23
-import { TrafficBarData } from './data/traffic-bar';
24
-import { ProfitBarAnimationChartData } from './data/profit-bar-animation-chart';
25
-import { TemperatureHumidityData } from './data/temperature-humidity';
26
-import { SolarData } from './data/solar';
27
-import { TrafficChartData } from './data/traffic-chart';
28
-import { StatsBarData } from './data/stats-bar';
29
-import { CountryOrderData } from './data/country-order';
30
-import { StatsProgressBarData } from './data/stats-progress-bar';
31
-import { VisitorsAnalyticsData } from './data/visitors-analytics';
32
-import { SecurityCamerasData } from './data/security-cameras';
12
+import { LoginApiService, initializeLoginSvc } from '../frontcraft/login-api';
33 13
 
34
-import { UserService } from './mock/users.service';
35
-import { ElectricityService } from './mock/electricity.service';
36
-import { SmartTableService } from './mock/smart-table.service';
37
-import { UserActivityService } from './mock/user-activity.service';
38
-import { OrdersChartService } from './mock/orders-chart.service';
39
-import { ProfitChartService } from './mock/profit-chart.service';
40
-import { TrafficListService } from './mock/traffic-list.service';
41
-import { EarningService } from './mock/earning.service';
42
-import { OrdersProfitChartService } from './mock/orders-profit-chart.service';
43
-import { TrafficBarService } from './mock/traffic-bar.service';
44
-import { ProfitBarAnimationChartService } from './mock/profit-bar-animation-chart.service';
45
-import { TemperatureHumidityService } from './mock/temperature-humidity.service';
46
-import { SolarService } from './mock/solar.service';
47
-import { TrafficChartService } from './mock/traffic-chart.service';
48
-import { StatsBarService } from './mock/stats-bar.service';
49
-import { CountryOrderService } from './mock/country-order.service';
50
-import { StatsProgressBarService } from './mock/stats-progress-bar.service';
51
-import { VisitorsAnalyticsService } from './mock/visitors-analytics.service';
52
-import { SecurityCamerasService } from './mock/security-cameras.service';
53
-import { MockDataModule } from './mock/mock-data.module';
54
-
55
-const socialLinks = [
56
-  {
57
-    url: 'https://github.com/akveo/nebular',
58
-    target: '_blank',
59
-    icon: 'github',
60
-  },
14
+const DATA_SERVICES = [  
15
+  {provide: LoginApiService, useClass: LoginApiService},
16
+  {provide: CookieService, useClass: CookieService},
61 17
   {
62
-    url: 'https://www.facebook.com/akveo/',
63
-    target: '_blank',
64
-    icon: 'facebook',
65
-  },
66
-  {
67
-    url: 'https://twitter.com/akveo_inc',
68
-    target: '_blank',
69
-    icon: 'twitter',
70
-  },
71
-];
72
-
73
-const DATA_SERVICES = [
74
-  { provide: UserData, useClass: UserService },
75
-  { provide: ElectricityData, useClass: ElectricityService },
76
-  { provide: SmartTableData, useClass: SmartTableService },
77
-  { provide: UserActivityData, useClass: UserActivityService },
78
-  { provide: OrdersChartData, useClass: OrdersChartService },
79
-  { provide: ProfitChartData, useClass: ProfitChartService },
80
-  { provide: TrafficListData, useClass: TrafficListService },
81
-  { provide: EarningData, useClass: EarningService },
82
-  { provide: OrdersProfitChartData, useClass: OrdersProfitChartService },
83
-  { provide: TrafficBarData, useClass: TrafficBarService },
84
-  { provide: ProfitBarAnimationChartData, useClass: ProfitBarAnimationChartService },
85
-  { provide: TemperatureHumidityData, useClass: TemperatureHumidityService },
86
-  { provide: SolarData, useClass: SolarService },
87
-  { provide: TrafficChartData, useClass: TrafficChartService },
88
-  { provide: StatsBarData, useClass: StatsBarService },
89
-  { provide: CountryOrderData, useClass: CountryOrderService },
90
-  { provide: StatsProgressBarData, useClass: StatsProgressBarService },
91
-  { provide: VisitorsAnalyticsData, useClass: VisitorsAnalyticsService },
92
-  { provide: SecurityCamerasData, useClass: SecurityCamerasService },
93
-];
94
-
95
-export class NbSimpleRoleProvider extends NbRoleProvider {
96
-  getRole() {
97
-    // here you could provide any role based on any auth flow
98
-    return observableOf('guest');
18
+    provide: APP_INITIALIZER,
19
+    useFactory: initializeLoginSvc,
20
+    deps: [LoginApiService, CookieService],
21
+    multi: true
99 22
   }
100
-}
23
+];
101 24
 
102 25
 export const NB_CORE_PROVIDERS = [
103
-  ...MockDataModule.forRoot().providers,
104 26
   ...DATA_SERVICES,
105
-  ...NbAuthModule.forRoot({
106 27
 
107
-    strategies: [
108
-      NbDummyAuthStrategy.setup({
109
-        name: 'email',
110
-        delay: 3000,
111
-      }),
112
-    ],
113
-    forms: {
114
-      login: {
115
-        socialLinks: socialLinks,
116
-      },
117
-      register: {
118
-        socialLinks: socialLinks,
119
-      },
120
-    },
121
-  }).providers,
122
-
123
-  NbSecurityModule.forRoot({
124
-    accessControl: {
125
-      guest: {
126
-        view: '*',
127
-      },
128
-      user: {
129
-        parent: 'guest',
130
-        create: '*',
131
-        edit: '*',
132
-        remove: '*',
133
-      },
134
-    },
135
-  }).providers,
136
-
137
-  {
138
-    provide: NbRoleProvider, useClass: NbSimpleRoleProvider,
139
-  },
140 28
   AnalyticsService,
141 29
   LayoutService,
142 30
   PlayerService,
143 31
   StateService,
32
+  CookieService,
144 33
 ];
145 34
 
146 35
 @NgModule({
@@ -148,7 +37,6 @@ export const NB_CORE_PROVIDERS = [
148 37
     CommonModule,
149 38
   ],
150 39
   exports: [
151
-    NbAuthModule,
152 40
   ],
153 41
   declarations: [],
154 42
 })

+ 0
- 1
src/frontend/src/app/@core/mock/README.md 查看文件

@@ -1 +0,0 @@
1
-Application-wise data providers.

+ 0
- 29
src/frontend/src/app/@core/mock/country-order.service.ts 查看文件

@@ -1,29 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { of as observableOf, Observable } from 'rxjs';
3
-import { CountryOrderData } from '../data/country-order';
4
-
5
-@Injectable()
6
-export class CountryOrderService extends CountryOrderData {
7
-
8
-  private countriesCategories = [
9
-    'Sofas',
10
-    'Furniture',
11
-    'Lighting',
12
-    'Tables',
13
-    'Textiles',
14
-  ];
15
-  private countriesCategoriesLength = this.countriesCategories.length;
16
-  private generateRandomData(nPoints: number): number[] {
17
-    return Array.from(Array(nPoints)).map(() => {
18
-      return Math.round(Math.random() * 20);
19
-    });
20
-  }
21
-
22
-  getCountriesCategories(): Observable<string[]> {
23
-    return observableOf(this.countriesCategories);
24
-  }
25
-
26
-  getCountriesCategoriesData(country: string): Observable<number[]> {
27
-    return observableOf(this.generateRandomData(this.countriesCategoriesLength));
28
-  }
29
-}

+ 0
- 103
src/frontend/src/app/@core/mock/earning.service.ts 查看文件

@@ -1,103 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { of as observableOf, Observable } from 'rxjs';
3
-import { LiveUpdateChart, PieChart, EarningData } from '../data/earning';
4
-
5
-@Injectable()
6
-export class EarningService extends EarningData {
7
-
8
-  private currentDate: Date = new Date();
9
-  private currentValue = Math.random() * 1000;
10
-  private ONE_DAY = 24 * 3600 * 1000;
11
-
12
-  private pieChartData = [
13
-    {
14
-      value: 50,
15
-      name: 'Bitcoin',
16
-    },
17
-    {
18
-      value: 25,
19
-      name: 'Tether',
20
-    },
21
-    {
22
-      value: 25,
23
-      name: 'Ethereum',
24
-    },
25
-  ];
26
-
27
-  private liveUpdateChartData = {
28
-    bitcoin: {
29
-      liveChart: [],
30
-      delta: {
31
-        up: true,
32
-        value: 4,
33
-      },
34
-      dailyIncome: 45895,
35
-    },
36
-    tether: {
37
-      liveChart: [],
38
-      delta: {
39
-        up: false,
40
-        value: 9,
41
-      },
42
-      dailyIncome: 5862,
43
-    },
44
-    ethereum: {
45
-      liveChart: [],
46
-      delta: {
47
-        up: false,
48
-        value: 21,
49
-      },
50
-      dailyIncome: 584,
51
-    },
52
-  };
53
-
54
-  getDefaultLiveChartData(elementsNumber: number) {
55
-    this.currentDate = new Date();
56
-    this.currentValue = Math.random() * 1000;
57
-
58
-    return Array.from(Array(elementsNumber))
59
-      .map(item => this.generateRandomLiveChartData());
60
-  }
61
-
62
-  generateRandomLiveChartData() {
63
-    this.currentDate = new Date(+this.currentDate + this.ONE_DAY);
64
-    this.currentValue = this.currentValue + Math.random() * 20 - 11;
65
-
66
-    if (this.currentValue < 0) {
67
-      this.currentValue = Math.random() * 100;
68
-    }
69
-
70
-    return {
71
-      value: [
72
-        [
73
-          this.currentDate.getFullYear(),
74
-          this.currentDate.getMonth(),
75
-          this.currentDate.getDate(),
76
-        ].join('/'),
77
-        Math.round(this.currentValue),
78
-      ],
79
-    };
80
-  }
81
-
82
-  getEarningLiveUpdateCardData(currency): Observable<any[]> {
83
-    const data = this.liveUpdateChartData[currency.toLowerCase()];
84
-    const newValue = this.generateRandomLiveChartData();
85
-
86
-    data.liveChart.shift();
87
-    data.liveChart.push(newValue);
88
-
89
-    return observableOf(data.liveChart);
90
-  }
91
-
92
-  getEarningCardData(currency: string): Observable<LiveUpdateChart> {
93
-    const data = this.liveUpdateChartData[currency.toLowerCase()];
94
-
95
-    data.liveChart = this.getDefaultLiveChartData(150);
96
-
97
-    return observableOf(data);
98
-  }
99
-
100
-  getEarningPieChartData(): Observable<PieChart[]> {
101
-    return observableOf(this.pieChartData);
102
-  }
103
-}

+ 0
- 95
src/frontend/src/app/@core/mock/electricity.service.ts 查看文件

@@ -1,95 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { of as observableOf, Observable } from 'rxjs';
3
-import { Electricity, ElectricityChart, ElectricityData } from '../data/electricity';
4
-
5
-@Injectable()
6
-export class ElectricityService extends ElectricityData {
7
-
8
-  private listData: Electricity[] = [
9
-    {
10
-      title: '2015',
11
-      months: [
12
-        { month: 'Jan', delta: '0.97', down: true, kWatts: '816', cost: '97' },
13
-        { month: 'Feb', delta: '1.83', down: true, kWatts: '806', cost: '95' },
14
-        { month: 'Mar', delta: '0.64', down: true, kWatts: '803', cost: '94' },
15
-        { month: 'Apr', delta: '2.17', down: false, kWatts: '818', cost: '98' },
16
-        { month: 'May', delta: '1.32', down: true, kWatts: '809', cost: '96' },
17
-        { month: 'Jun', delta: '0.05', down: true, kWatts: '808', cost: '96' },
18
-        { month: 'Jul', delta: '1.39', down: false, kWatts: '815', cost: '97' },
19
-        { month: 'Aug', delta: '0.73', down: true, kWatts: '807', cost: '95' },
20
-        { month: 'Sept', delta: '2.61', down: true, kWatts: '792', cost: '92' },
21
-        { month: 'Oct', delta: '0.16', down: true, kWatts: '791', cost: '92' },
22
-        { month: 'Nov', delta: '1.71', down: true, kWatts: '786', cost: '89' },
23
-        { month: 'Dec', delta: '0.37', down: false, kWatts: '789', cost: '91' },
24
-      ],
25
-    },
26
-    {
27
-      title: '2016',
28
-      active: true,
29
-      months: [
30
-        { month: 'Jan', delta: '1.56', down: true, kWatts: '789', cost: '91' },
31
-        { month: 'Feb', delta: '0.33', down: false, kWatts: '791', cost: '92' },
32
-        { month: 'Mar', delta: '0.62', down: true, kWatts: '790', cost: '92' },
33
-        { month: 'Apr', delta: '1.93', down: true, kWatts: '783', cost: '87' },
34
-        { month: 'May', delta: '2.52', down: true, kWatts: '771', cost: '83' },
35
-        { month: 'Jun', delta: '0.39', down: false, kWatts: '774', cost: '85' },
36
-        { month: 'Jul', delta: '1.61', down: true, kWatts: '767', cost: '81' },
37
-        { month: 'Aug', delta: '1.41', down: true, kWatts: '759', cost: '76' },
38
-        { month: 'Sept', delta: '1.03', down: true, kWatts: '752', cost: '74' },
39
-        { month: 'Oct', delta: '2.94', down: false, kWatts: '769', cost: '82' },
40
-        { month: 'Nov', delta: '0.26', down: true, kWatts: '767', cost: '81' },
41
-        { month: 'Dec', delta: '1.62', down: true, kWatts: '760', cost: '76' },
42
-      ],
43
-    },
44
-    {
45
-      title: '2017',
46
-      months: [
47
-        { month: 'Jan', delta: '1.34', down: false, kWatts: '789', cost: '91' },
48
-        { month: 'Feb', delta: '0.95', down: false, kWatts: '793', cost: '93' },
49
-        { month: 'Mar', delta: '0.25', down: true, kWatts: '791', cost: '92' },
50
-        { month: 'Apr', delta: '1.72', down: false, kWatts: '797', cost: '95' },
51
-        { month: 'May', delta: '2.62', down: true, kWatts: '786', cost: '90' },
52
-        { month: 'Jun', delta: '0.72', down: false, kWatts: '789', cost: '91' },
53
-        { month: 'Jul', delta: '0.78', down: true, kWatts: '784', cost: '89' },
54
-        { month: 'Aug', delta: '0.36', down: true, kWatts: '782', cost: '88' },
55
-        { month: 'Sept', delta: '0.55', down: false, kWatts: '787', cost: '90' },
56
-        { month: 'Oct', delta: '1.81', down: true, kWatts: '779', cost: '86' },
57
-        { month: 'Nov', delta: '1.12', down: true, kWatts: '774', cost: '84' },
58
-        { month: 'Dec', delta: '0.52', down: false, kWatts: '776', cost: '95' },
59
-      ],
60
-    },
61
-  ];
62
-
63
-  private chartPoints = [
64
-    490, 490, 495, 500,
65
-    505, 510, 520, 530,
66
-    550, 580, 630, 720,
67
-    800, 840, 860, 870,
68
-    870, 860, 840, 800,
69
-    720, 200, 145, 130,
70
-    130, 145, 200, 570,
71
-    635, 660, 670, 670,
72
-    660, 630, 580, 460,
73
-    380, 350, 340, 340,
74
-    340, 340, 340, 340,
75
-    340, 340, 340,
76
-  ];
77
-
78
-  chartData: ElectricityChart[];
79
-
80
-  constructor() {
81
-    super();
82
-    this.chartData = this.chartPoints.map((p, index) => ({
83
-      label: (index % 5 === 3) ? `${Math.round(index / 5)}` : '',
84
-      value: p,
85
-    }));
86
-  }
87
-
88
-  getListData(): Observable<Electricity[]> {
89
-    return observableOf(this.listData);
90
-  }
91
-
92
-  getChartData(): Observable<ElectricityChart[]> {
93
-    return observableOf(this.chartData);
94
-  }
95
-}

+ 0
- 65
src/frontend/src/app/@core/mock/mock-data.module.ts 查看文件

@@ -1,65 +0,0 @@
1
-import { NgModule, ModuleWithProviders } from '@angular/core';
2
-import { CommonModule } from '@angular/common';
3
-
4
-import { UserService } from './users.service';
5
-import { ElectricityService } from './electricity.service';
6
-import { SmartTableService } from './smart-table.service';
7
-import { UserActivityService } from './user-activity.service';
8
-import { OrdersChartService } from './orders-chart.service';
9
-import { ProfitChartService } from './profit-chart.service';
10
-import { TrafficListService } from './traffic-list.service';
11
-import { PeriodsService } from './periods.service';
12
-import { EarningService } from './earning.service';
13
-import { OrdersProfitChartService } from './orders-profit-chart.service';
14
-import { TrafficBarService } from './traffic-bar.service';
15
-import { ProfitBarAnimationChartService } from './profit-bar-animation-chart.service';
16
-import { TemperatureHumidityService } from './temperature-humidity.service';
17
-import { SolarService } from './solar.service';
18
-import { TrafficChartService } from './traffic-chart.service';
19
-import { StatsBarService } from './stats-bar.service';
20
-import { CountryOrderService } from './country-order.service';
21
-import { StatsProgressBarService } from './stats-progress-bar.service';
22
-import { VisitorsAnalyticsService } from './visitors-analytics.service';
23
-import { SecurityCamerasService } from './security-cameras.service';
24
-
25
-const SERVICES = [
26
-  UserService,
27
-  ElectricityService,
28
-  SmartTableService,
29
-  UserActivityService,
30
-  OrdersChartService,
31
-  ProfitChartService,
32
-  TrafficListService,
33
-  PeriodsService,
34
-  EarningService,
35
-  OrdersProfitChartService,
36
-  TrafficBarService,
37
-  ProfitBarAnimationChartService,
38
-  TemperatureHumidityService,
39
-  SolarService,
40
-  TrafficChartService,
41
-  StatsBarService,
42
-  CountryOrderService,
43
-  StatsProgressBarService,
44
-  VisitorsAnalyticsService,
45
-  SecurityCamerasService,
46
-];
47
-
48
-@NgModule({
49
-  imports: [
50
-    CommonModule,
51
-  ],
52
-  providers: [
53
-    ...SERVICES,
54
-  ],
55
-})
56
-export class MockDataModule {
57
-  static forRoot(): ModuleWithProviders {
58
-    return <ModuleWithProviders>{
59
-      ngModule: MockDataModule,
60
-      providers: [
61
-        ...SERVICES,
62
-      ],
63
-    };
64
-  }
65
-}

+ 0
- 155
src/frontend/src/app/@core/mock/orders-chart.service.ts 查看文件

@@ -1,155 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { PeriodsService } from './periods.service';
3
-import { OrdersChart, OrdersChartData } from '../data/orders-chart';
4
-
5
-@Injectable()
6
-export class OrdersChartService extends OrdersChartData {
7
-
8
-  private year = [
9
-    '2012',
10
-    '2013',
11
-    '2014',
12
-    '2015',
13
-    '2016',
14
-    '2017',
15
-    '2018',
16
-  ];
17
-
18
-  private data = { };
19
-
20
-  constructor(private period: PeriodsService) {
21
-    super();
22
-    this.data = {
23
-      week: this.getDataForWeekPeriod(),
24
-      month: this.getDataForMonthPeriod(),
25
-      year: this.getDataForYearPeriod(),
26
-    };
27
-  }
28
-
29
-  private getDataForWeekPeriod(): OrdersChart {
30
-    return {
31
-      chartLabel: this.getDataLabels(42, this.period.getWeeks()),
32
-      linesData: [
33
-        [
34
-          184, 267, 326, 366, 389, 399,
35
-          392, 371, 340, 304, 265, 227,
36
-          191, 158, 130, 108, 95, 91, 97,
37
-          109, 125, 144, 166, 189, 212,
38
-          236, 259, 280, 300, 316, 329,
39
-          338, 342, 339, 329, 312, 288,
40
-          258, 221, 178, 128, 71,
41
-        ],
42
-        [
43
-          158, 178, 193, 205, 212, 213,
44
-          204, 190, 180, 173, 168, 164,
45
-          162, 160, 159, 158, 159, 166,
46
-          179, 195, 215, 236, 257, 276,
47
-          292, 301, 304, 303, 300, 293,
48
-          284, 273, 262, 251, 241, 234,
49
-          232, 232, 232, 232, 232, 232,
50
-        ],
51
-        [
52
-          58, 137, 202, 251, 288, 312,
53
-          323, 324, 311, 288, 257, 222,
54
-          187, 154, 124, 100, 81, 68, 61,
55
-          58, 61, 69, 80, 96, 115, 137,
56
-          161, 186, 210, 233, 254, 271,
57
-          284, 293, 297, 297, 297, 297,
58
-          297, 297, 297, 297, 297,
59
-        ],
60
-      ],
61
-    };
62
-  }
63
-
64
-  private getDataForMonthPeriod(): OrdersChart {
65
-    return {
66
-      chartLabel: this.getDataLabels(47, this.period.getMonths()),
67
-      linesData: [
68
-        [
69
-          5, 63, 113, 156, 194, 225,
70
-          250, 270, 283, 289, 290,
71
-          286, 277, 264, 244, 220,
72
-          194, 171, 157, 151, 150,
73
-          152, 155, 160, 166, 170,
74
-          167, 153, 135, 115, 97,
75
-          82, 71, 64, 63, 62, 61,
76
-          62, 65, 73, 84, 102,
77
-          127, 159, 203, 259, 333,
78
-        ],
79
-        [
80
-          6, 83, 148, 200, 240,
81
-          265, 273, 259, 211,
82
-          122, 55, 30, 28, 36,
83
-          50, 68, 88, 109, 129,
84
-          146, 158, 163, 165,
85
-          173, 187, 208, 236,
86
-          271, 310, 346, 375,
87
-          393, 400, 398, 387,
88
-          368, 341, 309, 275,
89
-          243, 220, 206, 202,
90
-          207, 222, 247, 286, 348,
91
-        ],
92
-        [
93
-          398, 348, 315, 292, 274,
94
-          261, 251, 243, 237, 231,
95
-          222, 209, 192, 172, 152,
96
-          132, 116, 102, 90, 80, 71,
97
-          64, 58, 53, 49, 48, 54, 66,
98
-          84, 104, 125, 142, 156, 166,
99
-          172, 174, 172, 167, 159, 149,
100
-          136, 121, 105, 86, 67, 45, 22,
101
-        ],
102
-      ],
103
-    };
104
-  }
105
-
106
-  private getDataForYearPeriod(): OrdersChart {
107
-    return {
108
-      chartLabel: this.getDataLabels(42, this.year),
109
-      linesData: [
110
-        [
111
-          190, 269, 327, 366, 389, 398,
112
-          396, 387, 375, 359, 343, 327,
113
-          312, 298, 286, 276, 270, 268,
114
-          265, 258, 247, 234, 220, 204,
115
-          188, 172, 157, 142, 128, 116,
116
-          106, 99, 95, 94, 92, 89, 84,
117
-          77, 69, 60, 49, 36, 22,
118
-        ],
119
-        [
120
-          265, 307, 337, 359, 375, 386,
121
-          393, 397, 399, 397, 390, 379,
122
-          365, 347, 326, 305, 282, 261,
123
-          241, 223, 208, 197, 190, 187,
124
-          185, 181, 172, 160, 145, 126,
125
-          105, 82, 60, 40, 26, 19, 22,
126
-          43, 82, 141, 220, 321,
127
-        ],
128
-        [
129
-          9, 165, 236, 258, 244, 206,
130
-          186, 189, 209, 239, 273, 307,
131
-          339, 365, 385, 396, 398, 385,
132
-          351, 300, 255, 221, 197, 181,
133
-          170, 164, 162, 161, 159, 154,
134
-          146, 135, 122, 108, 96, 87,
135
-          83, 82, 82, 82, 82, 82, 82,
136
-        ],
137
-      ],
138
-    };
139
-  }
140
-
141
-  getDataLabels(nPoints: number, labelsArray: string[]): string[] {
142
-    const labelsArrayLength = labelsArray.length;
143
-    const step = Math.round(nPoints / labelsArrayLength);
144
-
145
-    return Array.from(Array(nPoints)).map((item, index) => {
146
-      const dataIndex = Math.round(index / step);
147
-
148
-      return index % step === 0 ? labelsArray[dataIndex] : '';
149
-    });
150
-  }
151
-
152
-  getOrdersChartData(period: string): OrdersChart {
153
-    return this.data[period];
154
-  }
155
-}

+ 0
- 45
src/frontend/src/app/@core/mock/orders-profit-chart.service.ts 查看文件

@@ -1,45 +0,0 @@
1
-import { of as observableOf,  Observable } from 'rxjs';
2
-import { Injectable } from '@angular/core';
3
-import { OrdersChart, OrdersChartData } from '../data/orders-chart';
4
-import { OrderProfitChartSummary, OrdersProfitChartData } from '../data/orders-profit-chart';
5
-import { ProfitChart, ProfitChartData } from '../data/profit-chart';
6
-
7
-@Injectable()
8
-export class OrdersProfitChartService extends OrdersProfitChartData {
9
-
10
-  private summary = [
11
-    {
12
-      title: 'Marketplace',
13
-      value: 3654,
14
-    },
15
-    {
16
-      title: 'Last Month',
17
-      value: 946,
18
-    },
19
-    {
20
-      title: 'Last Week',
21
-      value: 654,
22
-    },
23
-    {
24
-      title: 'Today',
25
-      value: 230,
26
-    },
27
-  ];
28
-
29
-  constructor(private ordersChartService: OrdersChartData,
30
-              private profitChartService: ProfitChartData) {
31
-    super();
32
-  }
33
-
34
-  getOrderProfitChartSummary(): Observable<OrderProfitChartSummary[]> {
35
-    return observableOf(this.summary);
36
-  }
37
-
38
-  getOrdersChartData(period: string): Observable<OrdersChart> {
39
-    return observableOf(this.ordersChartService.getOrdersChartData(period));
40
-  }
41
-
42
-  getProfitChartData(period: string): Observable<ProfitChart> {
43
-    return observableOf(this.profitChartService.getProfitChartData(period));
44
-  }
45
-}

+ 0
- 33
src/frontend/src/app/@core/mock/periods.service.ts 查看文件

@@ -1,33 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-
3
-@Injectable()
4
-export class PeriodsService {
5
-  getYears() {
6
-    return [
7
-      '2010', '2011', '2012',
8
-      '2013', '2014', '2015',
9
-      '2016', '2017', '2018',
10
-    ];
11
-  }
12
-
13
-  getMonths() {
14
-    return [
15
-      'Jan', 'Feb', 'Mar',
16
-      'Apr', 'May', 'Jun',
17
-      'Jul', 'Aug', 'Sep',
18
-      'Oct', 'Nov', 'Dec',
19
-    ];
20
-  }
21
-
22
-  getWeeks() {
23
-    return [
24
-      'Mon',
25
-      'Tue',
26
-      'Wed',
27
-      'Thu',
28
-      'Fri',
29
-      'Sat',
30
-      'Sun',
31
-    ];
32
-  }
33
-}

+ 0
- 43
src/frontend/src/app/@core/mock/profit-bar-animation-chart.service.ts 查看文件

@@ -1,43 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { of as observableOf,  Observable } from 'rxjs';
3
-import { ProfitBarAnimationChartData } from '../data/profit-bar-animation-chart';
4
-
5
-@Injectable()
6
-export class ProfitBarAnimationChartService extends ProfitBarAnimationChartData {
7
-
8
-  private data: any;
9
-
10
-  constructor() {
11
-    super();
12
-    this.data = {
13
-      firstLine: this.getDataForFirstLine(),
14
-      secondLine: this.getDataForSecondLine(),
15
-    };
16
-  }
17
-
18
-  getDataForFirstLine(): number[] {
19
-    return this.createEmptyArray(100)
20
-      .map((_, index) => {
21
-        const oneFifth = index / 5;
22
-
23
-        return (Math.sin(oneFifth) * (oneFifth - 10) + index / 6) * 5;
24
-      });
25
-  }
26
-
27
-  getDataForSecondLine(): number[] {
28
-    return this.createEmptyArray(100)
29
-      .map((_, index) => {
30
-        const oneFifth = index / 5;
31
-
32
-        return (Math.cos(oneFifth) * (oneFifth - 10) + index / 6) * 5;
33
-      });
34
-  }
35
-
36
-  createEmptyArray(nPoints: number) {
37
-    return Array.from(Array(nPoints));
38
-  }
39
-
40
-  getChartData(): Observable<{ firstLine: number[]; secondLine: number[]; }> {
41
-    return observableOf(this.data);
42
-  }
43
-}

+ 0
- 77
src/frontend/src/app/@core/mock/profit-chart.service.ts 查看文件

@@ -1,77 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { PeriodsService } from './periods.service';
3
-import { ProfitChart, ProfitChartData } from '../data/profit-chart';
4
-
5
-@Injectable()
6
-export class ProfitChartService extends ProfitChartData {
7
-
8
-  private year = [
9
-    '2012',
10
-    '2013',
11
-    '2014',
12
-    '2015',
13
-    '2016',
14
-    '2017',
15
-    '2018',
16
-  ];
17
-
18
-  private data = { };
19
-
20
-  constructor(private period: PeriodsService) {
21
-    super();
22
-    this.data = {
23
-      week: this.getDataForWeekPeriod(),
24
-      month: this.getDataForMonthPeriod(),
25
-      year: this.getDataForYearPeriod(),
26
-    };
27
-  }
28
-
29
-  private getDataForWeekPeriod(): ProfitChart {
30
-    const nPoint = this.period.getWeeks().length;
31
-
32
-    return {
33
-      chartLabel: this.period.getWeeks(),
34
-      data: [
35
-        this.getRandomData(nPoint),
36
-        this.getRandomData(nPoint),
37
-        this.getRandomData(nPoint),
38
-      ],
39
-    };
40
-  }
41
-
42
-  private getDataForMonthPeriod(): ProfitChart {
43
-    const nPoint = this.period.getMonths().length;
44
-
45
-    return {
46
-      chartLabel: this.period.getMonths(),
47
-      data: [
48
-        this.getRandomData(nPoint),
49
-        this.getRandomData(nPoint),
50
-        this.getRandomData(nPoint),
51
-      ],
52
-    };
53
-  }
54
-
55
-  private getDataForYearPeriod(): ProfitChart {
56
-    const nPoint = this.year.length;
57
-
58
-    return {
59
-      chartLabel: this.year,
60
-      data: [
61
-        this.getRandomData(nPoint),
62
-        this.getRandomData(nPoint),
63
-        this.getRandomData(nPoint),
64
-      ],
65
-    };
66
-  }
67
-
68
-  private getRandomData(nPoints: number): number[] {
69
-    return Array.from(Array(nPoints)).map(() => {
70
-      return Math.round(Math.random() * 500);
71
-    });
72
-  }
73
-
74
-  getProfitChartData(period: string): ProfitChart {
75
-    return this.data[period];
76
-  }
77
-}

+ 0
- 30
src/frontend/src/app/@core/mock/security-cameras.service.ts 查看文件

@@ -1,30 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { of as observableOf, Observable } from 'rxjs';
3
-import { Camera, SecurityCamerasData } from '../data/security-cameras';
4
-
5
-@Injectable()
6
-export class SecurityCamerasService extends SecurityCamerasData {
7
-
8
-  private cameras: Camera[] = [
9
-    {
10
-      title: 'Camera #1',
11
-      source: 'assets/images/camera1.jpg',
12
-    },
13
-    {
14
-      title: 'Camera #2',
15
-      source: 'assets/images/camera2.jpg',
16
-    },
17
-    {
18
-      title: 'Camera #3',
19
-      source: 'assets/images/camera3.jpg',
20
-    },
21
-    {
22
-      title: 'Camera #4',
23
-      source: 'assets/images/camera4.jpg',
24
-    },
25
-  ];
26
-
27
-  getCamerasData(): Observable<Camera[]> {
28
-    return observableOf(this.cameras);
29
-  }
30
-}

+ 0
- 432
src/frontend/src/app/@core/mock/smart-table.service.ts 查看文件

@@ -1,432 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { SmartTableData } from '../data/smart-table';
3
-
4
-@Injectable()
5
-export class SmartTableService extends SmartTableData {
6
-
7
-  data = [{
8
-    id: 1,
9
-    firstName: 'Mark',
10
-    lastName: 'Otto',
11
-    username: '@mdo',
12
-    email: 'mdo@gmail.com',
13
-    age: '28',
14
-  }, {
15
-    id: 2,
16
-    firstName: 'Jacob',
17
-    lastName: 'Thornton',
18
-    username: '@fat',
19
-    email: 'fat@yandex.ru',
20
-    age: '45',
21
-  }, {
22
-    id: 3,
23
-    firstName: 'Larry',
24
-    lastName: 'Bird',
25
-    username: '@twitter',
26
-    email: 'twitter@outlook.com',
27
-    age: '18',
28
-  }, {
29
-    id: 4,
30
-    firstName: 'John',
31
-    lastName: 'Snow',
32
-    username: '@snow',
33
-    email: 'snow@gmail.com',
34
-    age: '20',
35
-  }, {
36
-    id: 5,
37
-    firstName: 'Jack',
38
-    lastName: 'Sparrow',
39
-    username: '@jack',
40
-    email: 'jack@yandex.ru',
41
-    age: '30',
42
-  }, {
43
-    id: 6,
44
-    firstName: 'Ann',
45
-    lastName: 'Smith',
46
-    username: '@ann',
47
-    email: 'ann@gmail.com',
48
-    age: '21',
49
-  }, {
50
-    id: 7,
51
-    firstName: 'Barbara',
52
-    lastName: 'Black',
53
-    username: '@barbara',
54
-    email: 'barbara@yandex.ru',
55
-    age: '43',
56
-  }, {
57
-    id: 8,
58
-    firstName: 'Sevan',
59
-    lastName: 'Bagrat',
60
-    username: '@sevan',
61
-    email: 'sevan@outlook.com',
62
-    age: '13',
63
-  }, {
64
-    id: 9,
65
-    firstName: 'Ruben',
66
-    lastName: 'Vardan',
67
-    username: '@ruben',
68
-    email: 'ruben@gmail.com',
69
-    age: '22',
70
-  }, {
71
-    id: 10,
72
-    firstName: 'Karen',
73
-    lastName: 'Sevan',
74
-    username: '@karen',
75
-    email: 'karen@yandex.ru',
76
-    age: '33',
77
-  }, {
78
-    id: 11,
79
-    firstName: 'Mark',
80
-    lastName: 'Otto',
81
-    username: '@mark',
82
-    email: 'mark@gmail.com',
83
-    age: '38',
84
-  }, {
85
-    id: 12,
86
-    firstName: 'Jacob',
87
-    lastName: 'Thornton',
88
-    username: '@jacob',
89
-    email: 'jacob@yandex.ru',
90
-    age: '48',
91
-  }, {
92
-    id: 13,
93
-    firstName: 'Haik',
94
-    lastName: 'Hakob',
95
-    username: '@haik',
96
-    email: 'haik@outlook.com',
97
-    age: '48',
98
-  }, {
99
-    id: 14,
100
-    firstName: 'Garegin',
101
-    lastName: 'Jirair',
102
-    username: '@garegin',
103
-    email: 'garegin@gmail.com',
104
-    age: '40',
105
-  }, {
106
-    id: 15,
107
-    firstName: 'Krikor',
108
-    lastName: 'Bedros',
109
-    username: '@krikor',
110
-    email: 'krikor@yandex.ru',
111
-    age: '32',
112
-  }, {
113
-    'id': 16,
114
-    'firstName': 'Francisca',
115
-    'lastName': 'Brady',
116
-    'username': '@Gibson',
117
-    'email': 'franciscagibson@comtours.com',
118
-    'age': 11,
119
-  }, {
120
-    'id': 17,
121
-    'firstName': 'Tillman',
122
-    'lastName': 'Figueroa',
123
-    'username': '@Snow',
124
-    'email': 'tillmansnow@comtours.com',
125
-    'age': 34,
126
-  }, {
127
-    'id': 18,
128
-    'firstName': 'Jimenez',
129
-    'lastName': 'Morris',
130
-    'username': '@Bryant',
131
-    'email': 'jimenezbryant@comtours.com',
132
-    'age': 45,
133
-  }, {
134
-    'id': 19,
135
-    'firstName': 'Sandoval',
136
-    'lastName': 'Jacobson',
137
-    'username': '@Mcbride',
138
-    'email': 'sandovalmcbride@comtours.com',
139
-    'age': 32,
140
-  }, {
141
-    'id': 20,
142
-    'firstName': 'Griffin',
143
-    'lastName': 'Torres',
144
-    'username': '@Charles',
145
-    'email': 'griffincharles@comtours.com',
146
-    'age': 19,
147
-  }, {
148
-    'id': 21,
149
-    'firstName': 'Cora',
150
-    'lastName': 'Parker',
151
-    'username': '@Caldwell',
152
-    'email': 'coracaldwell@comtours.com',
153
-    'age': 27,
154
-  }, {
155
-    'id': 22,
156
-    'firstName': 'Cindy',
157
-    'lastName': 'Bond',
158
-    'username': '@Velez',
159
-    'email': 'cindyvelez@comtours.com',
160
-    'age': 24,
161
-  }, {
162
-    'id': 23,
163
-    'firstName': 'Frieda',
164
-    'lastName': 'Tyson',
165
-    'username': '@Craig',
166
-    'email': 'friedacraig@comtours.com',
167
-    'age': 45,
168
-  }, {
169
-    'id': 24,
170
-    'firstName': 'Cote',
171
-    'lastName': 'Holcomb',
172
-    'username': '@Rowe',
173
-    'email': 'coterowe@comtours.com',
174
-    'age': 20,
175
-  }, {
176
-    'id': 25,
177
-    'firstName': 'Trujillo',
178
-    'lastName': 'Mejia',
179
-    'username': '@Valenzuela',
180
-    'email': 'trujillovalenzuela@comtours.com',
181
-    'age': 16,
182
-  }, {
183
-    'id': 26,
184
-    'firstName': 'Pruitt',
185
-    'lastName': 'Shepard',
186
-    'username': '@Sloan',
187
-    'email': 'pruittsloan@comtours.com',
188
-    'age': 44,
189
-  }, {
190
-    'id': 27,
191
-    'firstName': 'Sutton',
192
-    'lastName': 'Ortega',
193
-    'username': '@Black',
194
-    'email': 'suttonblack@comtours.com',
195
-    'age': 42,
196
-  }, {
197
-    'id': 28,
198
-    'firstName': 'Marion',
199
-    'lastName': 'Heath',
200
-    'username': '@Espinoza',
201
-    'email': 'marionespinoza@comtours.com',
202
-    'age': 47,
203
-  }, {
204
-    'id': 29,
205
-    'firstName': 'Newman',
206
-    'lastName': 'Hicks',
207
-    'username': '@Keith',
208
-    'email': 'newmankeith@comtours.com',
209
-    'age': 15,
210
-  }, {
211
-    'id': 30,
212
-    'firstName': 'Boyle',
213
-    'lastName': 'Larson',
214
-    'username': '@Summers',
215
-    'email': 'boylesummers@comtours.com',
216
-    'age': 32,
217
-  }, {
218
-    'id': 31,
219
-    'firstName': 'Haynes',
220
-    'lastName': 'Vinson',
221
-    'username': '@Mckenzie',
222
-    'email': 'haynesmckenzie@comtours.com',
223
-    'age': 15,
224
-  }, {
225
-    'id': 32,
226
-    'firstName': 'Miller',
227
-    'lastName': 'Acosta',
228
-    'username': '@Young',
229
-    'email': 'milleryoung@comtours.com',
230
-    'age': 55,
231
-  }, {
232
-    'id': 33,
233
-    'firstName': 'Johnston',
234
-    'lastName': 'Brown',
235
-    'username': '@Knight',
236
-    'email': 'johnstonknight@comtours.com',
237
-    'age': 29,
238
-  }, {
239
-    'id': 34,
240
-    'firstName': 'Lena',
241
-    'lastName': 'Pitts',
242
-    'username': '@Forbes',
243
-    'email': 'lenaforbes@comtours.com',
244
-    'age': 25,
245
-  }, {
246
-    'id': 35,
247
-    'firstName': 'Terrie',
248
-    'lastName': 'Kennedy',
249
-    'username': '@Branch',
250
-    'email': 'terriebranch@comtours.com',
251
-    'age': 37,
252
-  }, {
253
-    'id': 36,
254
-    'firstName': 'Louise',
255
-    'lastName': 'Aguirre',
256
-    'username': '@Kirby',
257
-    'email': 'louisekirby@comtours.com',
258
-    'age': 44,
259
-  }, {
260
-    'id': 37,
261
-    'firstName': 'David',
262
-    'lastName': 'Patton',
263
-    'username': '@Sanders',
264
-    'email': 'davidsanders@comtours.com',
265
-    'age': 26,
266
-  }, {
267
-    'id': 38,
268
-    'firstName': 'Holden',
269
-    'lastName': 'Barlow',
270
-    'username': '@Mckinney',
271
-    'email': 'holdenmckinney@comtours.com',
272
-    'age': 11,
273
-  }, {
274
-    'id': 39,
275
-    'firstName': 'Baker',
276
-    'lastName': 'Rivera',
277
-    'username': '@Montoya',
278
-    'email': 'bakermontoya@comtours.com',
279
-    'age': 47,
280
-  }, {
281
-    'id': 40,
282
-    'firstName': 'Belinda',
283
-    'lastName': 'Lloyd',
284
-    'username': '@Calderon',
285
-    'email': 'belindacalderon@comtours.com',
286
-    'age': 21,
287
-  }, {
288
-    'id': 41,
289
-    'firstName': 'Pearson',
290
-    'lastName': 'Patrick',
291
-    'username': '@Clements',
292
-    'email': 'pearsonclements@comtours.com',
293
-    'age': 42,
294
-  }, {
295
-    'id': 42,
296
-    'firstName': 'Alyce',
297
-    'lastName': 'Mckee',
298
-    'username': '@Daugherty',
299
-    'email': 'alycedaugherty@comtours.com',
300
-    'age': 55,
301
-  }, {
302
-    'id': 43,
303
-    'firstName': 'Valencia',
304
-    'lastName': 'Spence',
305
-    'username': '@Olsen',
306
-    'email': 'valenciaolsen@comtours.com',
307
-    'age': 20,
308
-  }, {
309
-    'id': 44,
310
-    'firstName': 'Leach',
311
-    'lastName': 'Holcomb',
312
-    'username': '@Humphrey',
313
-    'email': 'leachhumphrey@comtours.com',
314
-    'age': 28,
315
-  }, {
316
-    'id': 45,
317
-    'firstName': 'Moss',
318
-    'lastName': 'Baxter',
319
-    'username': '@Fitzpatrick',
320
-    'email': 'mossfitzpatrick@comtours.com',
321
-    'age': 51,
322
-  }, {
323
-    'id': 46,
324
-    'firstName': 'Jeanne',
325
-    'lastName': 'Cooke',
326
-    'username': '@Ward',
327
-    'email': 'jeanneward@comtours.com',
328
-    'age': 59,
329
-  }, {
330
-    'id': 47,
331
-    'firstName': 'Wilma',
332
-    'lastName': 'Briggs',
333
-    'username': '@Kidd',
334
-    'email': 'wilmakidd@comtours.com',
335
-    'age': 53,
336
-  }, {
337
-    'id': 48,
338
-    'firstName': 'Beatrice',
339
-    'lastName': 'Perry',
340
-    'username': '@Gilbert',
341
-    'email': 'beatricegilbert@comtours.com',
342
-    'age': 39,
343
-  }, {
344
-    'id': 49,
345
-    'firstName': 'Whitaker',
346
-    'lastName': 'Hyde',
347
-    'username': '@Mcdonald',
348
-    'email': 'whitakermcdonald@comtours.com',
349
-    'age': 35,
350
-  }, {
351
-    'id': 50,
352
-    'firstName': 'Rebekah',
353
-    'lastName': 'Duran',
354
-    'username': '@Gross',
355
-    'email': 'rebekahgross@comtours.com',
356
-    'age': 40,
357
-  }, {
358
-    'id': 51,
359
-    'firstName': 'Earline',
360
-    'lastName': 'Mayer',
361
-    'username': '@Woodward',
362
-    'email': 'earlinewoodward@comtours.com',
363
-    'age': 52,
364
-  }, {
365
-    'id': 52,
366
-    'firstName': 'Moran',
367
-    'lastName': 'Baxter',
368
-    'username': '@Johns',
369
-    'email': 'moranjohns@comtours.com',
370
-    'age': 20,
371
-  }, {
372
-    'id': 53,
373
-    'firstName': 'Nanette',
374
-    'lastName': 'Hubbard',
375
-    'username': '@Cooke',
376
-    'email': 'nanettecooke@comtours.com',
377
-    'age': 55,
378
-  }, {
379
-    'id': 54,
380
-    'firstName': 'Dalton',
381
-    'lastName': 'Walker',
382
-    'username': '@Hendricks',
383
-    'email': 'daltonhendricks@comtours.com',
384
-    'age': 25,
385
-  }, {
386
-    'id': 55,
387
-    'firstName': 'Bennett',
388
-    'lastName': 'Blake',
389
-    'username': '@Pena',
390
-    'email': 'bennettpena@comtours.com',
391
-    'age': 13,
392
-  }, {
393
-    'id': 56,
394
-    'firstName': 'Kellie',
395
-    'lastName': 'Horton',
396
-    'username': '@Weiss',
397
-    'email': 'kellieweiss@comtours.com',
398
-    'age': 48,
399
-  }, {
400
-    'id': 57,
401
-    'firstName': 'Hobbs',
402
-    'lastName': 'Talley',
403
-    'username': '@Sanford',
404
-    'email': 'hobbssanford@comtours.com',
405
-    'age': 28,
406
-  }, {
407
-    'id': 58,
408
-    'firstName': 'Mcguire',
409
-    'lastName': 'Donaldson',
410
-    'username': '@Roman',
411
-    'email': 'mcguireroman@comtours.com',
412
-    'age': 38,
413
-  }, {
414
-    'id': 59,
415
-    'firstName': 'Rodriquez',
416
-    'lastName': 'Saunders',
417
-    'username': '@Harper',
418
-    'email': 'rodriquezharper@comtours.com',
419
-    'age': 20,
420
-  }, {
421
-    'id': 60,
422
-    'firstName': 'Lou',
423
-    'lastName': 'Conner',
424
-    'username': '@Sanchez',
425
-    'email': 'lousanchez@comtours.com',
426
-    'age': 16,
427
-  }];
428
-
429
-  getData() {
430
-    return this.data;
431
-  }
432
-}

+ 0
- 12
src/frontend/src/app/@core/mock/solar.service.ts 查看文件

@@ -1,12 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { of as observableOf,  Observable } from 'rxjs';
3
-import { SolarData } from '../data/solar';
4
-
5
-@Injectable()
6
-export class SolarService extends SolarData {
7
-  private value = 42;
8
-
9
-  getSolarData(): Observable<number> {
10
-    return observableOf(this.value);
11
-  }
12
-}

+ 0
- 16
src/frontend/src/app/@core/mock/stats-bar.service.ts 查看文件

@@ -1,16 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { of as observableOf, Observable } from 'rxjs';
3
-import { StatsBarData } from '../data/stats-bar';
4
-
5
-@Injectable()
6
-export class StatsBarService extends StatsBarData {
7
-
8
-  private statsBarData: number[] = [
9
-    300, 520, 435, 530,
10
-    730, 620, 660, 860,
11
-  ];
12
-
13
-  getStatsBarData(): Observable<number[]> {
14
-    return observableOf(this.statsBarData);
15
-  }
16
-}

+ 0
- 31
src/frontend/src/app/@core/mock/stats-progress-bar.service.ts 查看文件

@@ -1,31 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { of as observableOf, Observable } from 'rxjs';
3
-import { ProgressInfo, StatsProgressBarData } from '../data/stats-progress-bar';
4
-
5
-@Injectable()
6
-export class StatsProgressBarService extends StatsProgressBarData {
7
-  private progressInfoData: ProgressInfo[] = [
8
-    {
9
-      title: 'Today’s Profit',
10
-      value: 572900,
11
-      activeProgress: 70,
12
-      description: 'Better than last week (70%)',
13
-    },
14
-    {
15
-      title: 'New Orders',
16
-      value: 6378,
17
-      activeProgress: 30,
18
-      description: 'Better than last week (30%)',
19
-    },
20
-    {
21
-      title: 'New Comments',
22
-      value: 200,
23
-      activeProgress: 55,
24
-      description: 'Better than last week (55%)',
25
-    },
26
-  ];
27
-
28
-  getProgressInfoData(): Observable<ProgressInfo[]> {
29
-    return observableOf(this.progressInfoData);
30
-  }
31
-}

+ 0
- 27
src/frontend/src/app/@core/mock/temperature-humidity.service.ts 查看文件

@@ -1,27 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { of as observableOf,  Observable } from 'rxjs';
3
-import { TemperatureHumidityData, Temperature } from '../data/temperature-humidity';
4
-
5
-@Injectable()
6
-export class TemperatureHumidityService extends TemperatureHumidityData {
7
-
8
-  private temperatureDate: Temperature = {
9
-    value: 24,
10
-    min: 12,
11
-    max: 30,
12
-  };
13
-
14
-  private humidityDate: Temperature = {
15
-    value: 87,
16
-    min: 0,
17
-    max: 100,
18
-  };
19
-
20
-  getTemperatureData(): Observable<Temperature> {
21
-    return observableOf(this.temperatureDate);
22
-  }
23
-
24
-  getHumidityData(): Observable<Temperature> {
25
-    return observableOf(this.humidityDate);
26
-  }
27
-}

+ 0
- 47
src/frontend/src/app/@core/mock/traffic-bar.service.ts 查看文件

@@ -1,47 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { of as observableOf,  Observable } from 'rxjs';
3
-import { PeriodsService } from './periods.service';
4
-import { TrafficBarData, TrafficBar } from '../data/traffic-bar';
5
-
6
-@Injectable()
7
-export class TrafficBarService extends TrafficBarData {
8
-
9
-  private data = { };
10
-
11
-  constructor(private period: PeriodsService) {
12
-    super();
13
-    this.data = {
14
-      week: this.getDataForWeekPeriod(),
15
-      month: this.getDataForMonthPeriod(),
16
-      year: this.getDataForYearPeriod(),
17
-    };
18
-  }
19
-
20
-  getDataForWeekPeriod(): TrafficBar {
21
-    return {
22
-      data: [10, 15, 19, 7, 20, 13, 15],
23
-      labels: this.period.getWeeks(),
24
-      formatter: '{c0} MB',
25
-    };
26
-  }
27
-
28
-  getDataForMonthPeriod(): TrafficBar {
29
-    return {
30
-      data: [0.5, 0.3, 0.8, 0.2, 0.3, 0.7, 0.8, 1, 0.7, 0.8, 0.6, 0.7],
31
-      labels: this.period.getMonths(),
32
-      formatter: '{c0} GB',
33
-    };
34
-  }
35
-
36
-  getDataForYearPeriod(): TrafficBar {
37
-    return {
38
-      data: [10, 15, 19, 7, 20, 13, 15, 19, 11],
39
-      labels: this.period.getYears(),
40
-      formatter: '{c0} GB',
41
-    };
42
-  }
43
-
44
-  getTrafficBarData(period: string): Observable<TrafficBar> {
45
-    return observableOf(this.data[period]);
46
-  }
47
-}

+ 0
- 16
src/frontend/src/app/@core/mock/traffic-chart.service.ts 查看文件

@@ -1,16 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { of as observableOf,  Observable } from 'rxjs';
3
-import { TrafficChartData } from '../data/traffic-chart';
4
-
5
-@Injectable()
6
-export class TrafficChartService extends TrafficChartData {
7
-
8
-  private data: number[] = [
9
-    300, 520, 435, 530,
10
-    730, 620, 660, 860,
11
-  ];
12
-
13
-  getTrafficChartData(): Observable<number[]> {
14
-    return observableOf(this.data);
15
-  }
16
-}

+ 0
- 85
src/frontend/src/app/@core/mock/traffic-list.service.ts 查看文件

@@ -1,85 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { of as observableOf,  Observable } from 'rxjs';
3
-import { PeriodsService } from './periods.service';
4
-import { TrafficList, TrafficListData } from '../data/traffic-list';
5
-
6
-@Injectable()
7
-export class TrafficListService extends TrafficListData {
8
-
9
-  private getRandom = (roundTo: number) => Math.round(Math.random() * roundTo);
10
-  private data = {};
11
-
12
-  constructor(private period: PeriodsService) {
13
-    super();
14
-    this.data = {
15
-      week: this.getDataWeek(),
16
-      month: this.getDataMonth(),
17
-      year: this.getDataYear(),
18
-    };
19
-  }
20
-
21
-  private getDataWeek(): TrafficList[] {
22
-    const getFirstDateInPeriod = () => {
23
-      const weeks = this.period.getWeeks();
24
-
25
-      return weeks[weeks.length - 1];
26
-    };
27
-
28
-    return this.reduceData(this.period.getWeeks(), getFirstDateInPeriod);
29
-  }
30
-
31
-  private getDataMonth(): TrafficList[] {
32
-    const getFirstDateInPeriod = () => {
33
-      const months = this.period.getMonths();
34
-
35
-      return months[months.length - 1];
36
-    };
37
-
38
-    return this.reduceData(this.period.getMonths(), getFirstDateInPeriod);
39
-  }
40
-
41
-  private getDataYear(): TrafficList[] {
42
-    const getFirstDateInPeriod = () => {
43
-      const years = this.period.getYears();
44
-
45
-      return `${parseInt(years[0], 10) - 1}`;
46
-    };
47
-
48
-    return this.reduceData(this.period.getYears(), getFirstDateInPeriod);
49
-  }
50
-
51
-  private reduceData(timePeriods: string[], getFirstDateInPeriod: () => string): TrafficList[] {
52
-    return timePeriods.reduce((result, timePeriod, index) => {
53
-      const hasResult = result[index - 1];
54
-      const prevDate = hasResult ?
55
-        result[index - 1].comparison.nextDate :
56
-        getFirstDateInPeriod();
57
-      const prevValue = hasResult ?
58
-        result[index - 1].comparison.nextValue :
59
-        this.getRandom(100);
60
-      const nextValue = this.getRandom(100);
61
-      const deltaValue = prevValue - nextValue;
62
-
63
-      const item = {
64
-        date: timePeriod,
65
-        value: this.getRandom(1000),
66
-        delta: {
67
-          up: deltaValue <= 0,
68
-          value: Math.abs(deltaValue),
69
-        },
70
-        comparison: {
71
-          prevDate,
72
-          prevValue,
73
-          nextDate: timePeriod,
74
-          nextValue,
75
-        },
76
-      };
77
-
78
-      return [...result, item];
79
-    }, []);
80
-  }
81
-
82
-  getTrafficListData(period: string): Observable<TrafficList> {
83
-    return observableOf(this.data[period]);
84
-  }
85
-}

+ 0
- 57
src/frontend/src/app/@core/mock/user-activity.service.ts 查看文件

@@ -1,57 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { of as observableOf,  Observable } from 'rxjs';
3
-import { PeriodsService } from './periods.service';
4
-import { UserActive, UserActivityData } from '../data/user-activity';
5
-
6
-@Injectable()
7
-export class UserActivityService extends UserActivityData {
8
-
9
-  private getRandom = (roundTo: number) => Math.round(Math.random() * roundTo);
10
-  private generateUserActivityRandomData(date) {
11
-    return {
12
-      date,
13
-      pagesVisitCount: this.getRandom(1000),
14
-      deltaUp: this.getRandom(1) % 2 === 0,
15
-      newVisits: this.getRandom(100),
16
-    };
17
-  }
18
-
19
-  data = {};
20
-
21
-  constructor(private periods: PeriodsService) {
22
-    super();
23
-    this.data = {
24
-      week: this.getDataWeek(),
25
-      month: this.getDataMonth(),
26
-      year: this.getDataYear(),
27
-    };
28
-  }
29
-
30
-  private getDataWeek(): UserActive[] {
31
-    return this.periods.getWeeks().map((week) => {
32
-      return this.generateUserActivityRandomData(week);
33
-    });
34
-  }
35
-
36
-  private getDataMonth(): UserActive[] {
37
-    const currentDate = new Date();
38
-    const days = currentDate.getDate();
39
-    const month = this.periods.getMonths()[currentDate.getMonth()];
40
-
41
-    return Array.from(Array(days)).map((_, index) => {
42
-      const date = `${index + 1} ${month}`;
43
-
44
-      return this.generateUserActivityRandomData(date);
45
-    });
46
-  }
47
-
48
-  private getDataYear(): UserActive[] {
49
-    return this.periods.getYears().map((year) => {
50
-      return this.generateUserActivityRandomData(year);
51
-    });
52
-  }
53
-
54
-  getUserActivityData(period: string): Observable<UserActive[]> {
55
-    return observableOf(this.data[period]);
56
-  }
57
-}

+ 0
- 53
src/frontend/src/app/@core/mock/users.service.ts 查看文件

@@ -1,53 +0,0 @@
1
-import { of as observableOf,  Observable } from 'rxjs';
2
-import { Injectable } from '@angular/core';
3
-import { Contacts, RecentUsers, UserData } from '../data/users';
4
-
5
-@Injectable()
6
-export class UserService extends UserData {
7
-
8
-  private time: Date = new Date;
9
-
10
-  private users = {
11
-    nick: { name: 'Nick Jones', picture: 'assets/images/nick.png' },
12
-    eva: { name: 'Eva Moor', picture: 'assets/images/eva.png' },
13
-    jack: { name: 'Jack Williams', picture: 'assets/images/jack.png' },
14
-    lee: { name: 'Lee Wong', picture: 'assets/images/lee.png' },
15
-    alan: { name: 'Alan Thompson', picture: 'assets/images/alan.png' },
16
-    kate: { name: 'Kate Martinez', picture: 'assets/images/kate.png' },
17
-  };
18
-  private types = {
19
-    mobile: 'mobile',
20
-    home: 'home',
21
-    work: 'work',
22
-  };
23
-  private contacts: Contacts[] = [
24
-    { user: this.users.nick, type: this.types.mobile },
25
-    { user: this.users.eva, type: this.types.home },
26
-    { user: this.users.jack, type: this.types.mobile },
27
-    { user: this.users.lee, type: this.types.mobile },
28
-    { user: this.users.alan, type: this.types.home },
29
-    { user: this.users.kate, type: this.types.work },
30
-  ];
31
-  private recentUsers: RecentUsers[]  = [
32
-    { user: this.users.alan, type: this.types.home, time: this.time.setHours(21, 12)},
33
-    { user: this.users.eva, type: this.types.home, time: this.time.setHours(17, 45)},
34
-    { user: this.users.nick, type: this.types.mobile, time: this.time.setHours(5, 29)},
35
-    { user: this.users.lee, type: this.types.mobile, time: this.time.setHours(11, 24)},
36
-    { user: this.users.jack, type: this.types.mobile, time: this.time.setHours(10, 45)},
37
-    { user: this.users.kate, type: this.types.work, time: this.time.setHours(9, 42)},
38
-    { user: this.users.kate, type: this.types.work, time: this.time.setHours(9, 31)},
39
-    { user: this.users.jack, type: this.types.mobile, time: this.time.setHours(8, 0)},
40
-  ];
41
-
42
-  getUsers(): Observable<any> {
43
-    return observableOf(this.users);
44
-  }
45
-
46
-  getContacts(): Observable<Contacts[]> {
47
-    return observableOf(this.contacts);
48
-  }
49
-
50
-  getRecentUsers(): Observable<RecentUsers[]> {
51
-    return observableOf(this.recentUsers);
52
-  }
53
-}

+ 0
- 57
src/frontend/src/app/@core/mock/visitors-analytics.service.ts 查看文件

@@ -1,57 +0,0 @@
1
-import { Injectable } from '@angular/core';
2
-import { of as observableOf, Observable } from 'rxjs';
3
-import { PeriodsService } from './periods.service';
4
-import { OutlineData, VisitorsAnalyticsData } from '../data/visitors-analytics';
5
-
6
-@Injectable()
7
-export class VisitorsAnalyticsService extends VisitorsAnalyticsData {
8
-
9
-  constructor(private periodService: PeriodsService) {
10
-    super();
11
-  }
12
-
13
-  private pieChartValue = 75;
14
-  private innerLinePoints: number[] = [
15
-    94, 188, 225, 244, 253, 254, 249, 235, 208,
16
-    173, 141, 118, 105, 97, 94, 96, 104, 121, 147,
17
-    183, 224, 265, 302, 333, 358, 375, 388, 395,
18
-    400, 400, 397, 390, 377, 360, 338, 310, 278,
19
-    241, 204, 166, 130, 98, 71, 49, 32, 20, 13, 9,
20
-  ];
21
-  private outerLinePoints: number[] = [
22
-    85, 71, 59, 50, 45, 42, 41, 44 , 58, 88,
23
-    136 , 199, 267, 326, 367, 391, 400, 397,
24
-    376, 319, 200, 104, 60, 41, 36, 37, 44,
25
-    55, 74, 100 , 131, 159, 180, 193, 199, 200,
26
-    195, 184, 164, 135, 103, 73, 50, 33, 22, 15, 11,
27
-  ];
28
-  private generateOutlineLineData(): OutlineData[] {
29
-    const months = this.periodService.getMonths();
30
-    const outerLinePointsLength = this.outerLinePoints.length;
31
-    const monthsLength = months.length;
32
-
33
-    return this.outerLinePoints.map((p, index) => {
34
-      const monthIndex = Math.round(index / 4);
35
-      const label = (index % Math.round(outerLinePointsLength / monthsLength) === 0)
36
-        ? months[monthIndex]
37
-        : '';
38
-
39
-      return {
40
-        label,
41
-        value: p,
42
-      };
43
-    });
44
-  }
45
-
46
-  getInnerLineChartData(): Observable<number[]> {
47
-    return observableOf(this.innerLinePoints);
48
-  }
49
-
50
-  getOutlineLineChartData(): Observable<OutlineData[]> {
51
-    return observableOf(this.generateOutlineLineData());
52
-  }
53
-
54
-  getPieChartData(): Observable<number> {
55
-    return observableOf(this.pieChartValue);
56
-  }
57
-}

+ 1
- 4
src/frontend/src/app/@theme/components/footer/footer.component.ts 查看文件

@@ -6,10 +6,7 @@ import { Component } from '@angular/core';
6 6
   template: `
7 7
     <span class="created-by">Created with ♥ by <b><a href="https://akveo.com" target="_blank">Akveo</a></b> 2019</span>
8 8
     <div class="socials">
9
-      <a href="#" target="_blank" class="ion ion-social-github"></a>
10
-      <a href="#" target="_blank" class="ion ion-social-facebook"></a>
11
-      <a href="#" target="_blank" class="ion ion-social-twitter"></a>
12
-      <a href="#" target="_blank" class="ion ion-social-linkedin"></a>
9
+      <a href="http://www.versioncontrol.me/" target="_blank" class="ion ion-social-github"></a>
13 10
     </div>
14 11
   `,
15 12
 })

+ 2
- 5
src/frontend/src/app/@theme/components/header/header.component.html 查看文件

@@ -3,11 +3,8 @@
3 3
     <a (click)="toggleSidebar()" href="#" class="sidebar-toggle">
4 4
       <nb-icon icon="menu-2-outline"></nb-icon>
5 5
     </a>
6
-    <a class="logo" href="#" (click)="navigateHome()">ngx-<span>admin</span></a>
6
+    <a class="logo" href="#" (click)="navigateHome()">Frontcraft</a>
7 7
   </div>
8
-  <nb-select [selected]="currentTheme" (selectedChange)="changeTheme($event)" status="primary">
9
-    <nb-option *ngFor="let theme of themes" [value]="theme.value"> {{ theme.name }}</nb-option>
10
-  </nb-select>
11 8
 </div>
12 9
 
13 10
 <div class="header-container">
@@ -18,7 +15,7 @@
18 15
     </nb-action>
19 16
     <nb-action class="control-item" icon="email-outline"></nb-action>
20 17
     <nb-action class="control-item" icon="bell-outline"></nb-action>
21
-    <nb-action class="user-action" *nbIsGranted="['view', 'user']" >
18
+    <nb-action class="user-action">
22 19
       <nb-user [nbContextMenu]="userMenu"
23 20
                [onlyPicture]="userPictureOnly"
24 21
                [name]="user?.name"

+ 5
- 4
src/frontend/src/app/@theme/components/header/header.component.ts 查看文件

@@ -36,14 +36,13 @@ export class HeaderComponent implements OnInit, OnDestroy {
36 36
     },
37 37
   ];
38 38
 
39
-  currentTheme = 'default';
39
+  currentTheme = 'dark';
40 40
 
41 41
   userMenu = [ { title: 'Profile' }, { title: 'Log out' } ];
42 42
 
43 43
   constructor(private sidebarService: NbSidebarService,
44 44
               private menuService: NbMenuService,
45 45
               private themeService: NbThemeService,
46
-              private userService: UserData,
47 46
               private layoutService: LayoutService,
48 47
               private breakpointService: NbMediaBreakpointsService) {
49 48
   }
@@ -51,10 +50,12 @@ export class HeaderComponent implements OnInit, OnDestroy {
51 50
   ngOnInit() {
52 51
     this.currentTheme = this.themeService.currentTheme;
53 52
 
53
+    /*
54 54
     this.userService.getUsers()
55 55
       .pipe(takeUntil(this.destroy$))
56
-      .subscribe((users: any) => this.user = users.nick);
57
-
56
+      .subscribe((users: any) => this.user = users.lee);
57
+    */
58
+   
58 59
     const { xl } = this.breakpointService.getBreakpointsMap();
59 60
     this.themeService.onMediaQueryChange()
60 61
       .pipe(

+ 1
- 1
src/frontend/src/app/@theme/theme.module.ts 查看文件

@@ -82,7 +82,7 @@ export class ThemeModule {
82 82
       providers: [
83 83
         ...NbThemeModule.forRoot(
84 84
           {
85
-            name: 'default',
85
+            name: 'dark',
86 86
           },
87 87
           [ DEFAULT_THEME, COSMIC_THEME, CORPORATE_THEME, DARK_THEME ],
88 88
         ).providers,

+ 2
- 32
src/frontend/src/app/app-routing.module.ts 查看文件

@@ -1,7 +1,6 @@
1 1
 import { ExtraOptions, RouterModule, Routes } from '@angular/router';
2 2
 import { NgModule } from '@angular/core';
3 3
 import {
4
-  NbAuthComponent,
5 4
   NbLoginComponent,
6 5
   NbLogoutComponent,
7 6
   NbRegisterComponent,
@@ -12,39 +11,10 @@ import {
12 11
 const routes: Routes = [
13 12
   {
14 13
     path: 'pages',
15
-    loadChildren: () => import('app/pages/pages.module')
14
+    loadChildren: () => import('./pages/pages.module')
16 15
       .then(m => m.PagesModule),
17 16
   },
18
-  {
19
-    path: 'auth',
20
-    component: NbAuthComponent,
21
-    children: [
22
-      {
23
-        path: '',
24
-        component: NbLoginComponent,
25
-      },
26
-      {
27
-        path: 'login',
28
-        component: NbLoginComponent,
29
-      },
30
-      {
31
-        path: 'register',
32
-        component: NbRegisterComponent,
33
-      },
34
-      {
35
-        path: 'logout',
36
-        component: NbLogoutComponent,
37
-      },
38
-      {
39
-        path: 'request-password',
40
-        component: NbRequestPasswordComponent,
41
-      },
42
-      {
43
-        path: 'reset-password',
44
-        component: NbResetPasswordComponent,
45
-      },
46
-    ],
47
-  },
17
+  
48 18
   { path: '', redirectTo: 'pages', pathMatch: 'full' },
49 19
   { path: '**', redirectTo: 'pages' },
50 20
 ];

+ 3
- 1
src/frontend/src/app/app.component.ts 查看文件

@@ -5,6 +5,7 @@
5 5
  */
6 6
 import { Component, OnInit } from '@angular/core';
7 7
 import { AnalyticsService } from './@core/utils/analytics.service';
8
+import { LoginApiService } from './frontcraft/login-api';
8 9
 
9 10
 @Component({
10 11
   selector: 'ngx-app',
@@ -12,11 +13,12 @@ import { AnalyticsService } from './@core/utils/analytics.service';
12 13
 })
13 14
 export class AppComponent implements OnInit {
14 15
 
15
-  constructor(private analytics: AnalyticsService) {
16
+  constructor(private loginSvc: LoginApiService, private analytics: AnalyticsService) {
16 17
     
17 18
   }
18 19
 
19 20
   ngOnInit(): void {
20 21
     this.analytics.trackPageViews();
22
+    window['s'] = this.loginSvc
21 23
   }
22 24
 }

+ 95
- 0
src/frontend/src/app/frontcraft/login-api.ts 查看文件

@@ -0,0 +1,95 @@
1
+import { Injectable } from "@angular/core";
2
+import {RPCSocket} from 'rpclibrary/js/src/Frontend'
3
+
4
+import { Token, Auth, User, _Rank, _Class, FrontcraftFeatureIfc, LoginManagerIfc, } from '../../../../backend/Types/Types'
5
+import { CookieService } from 'ngx-cookie-service';
6
+
7
+@Injectable()
8
+export class LoginApiService{
9
+    private socket:RPCSocket & LoginManagerIfc;
10
+    private auth:Auth
11
+    private privSocket: RPCSocket & FrontcraftFeatureIfc
12
+
13
+    constructor(
14
+        private cookieSvc : CookieService
15
+    ){}
16
+
17
+    getUnprivilegedSocket = () : RPCSocket & LoginManagerIfc => this.socket
18
+
19
+    private getPrivilegedSocket = async (auth:Auth) : Promise<RPCSocket & FrontcraftFeatureIfc> => {
20
+        if(this.privSocket) return this.privSocket
21
+        try{
22
+            const sock: RPCSocket & FrontcraftFeatureIfc = await new RPCSocket(auth.port, window.location.hostname).connect(auth.token.value)
23
+            //login success
24
+            this.auth = auth
25
+            this.privSocket = sock
26
+            this.setCookie(auth.token)
27
+            return sock
28
+        }catch(e){ 
29
+            //login failed
30
+            throw new Error('login failed')
31
+        }
32
+    } 
33
+
34
+    getCurrentUser = () : User => this.auth 
35
+                                ? this.auth.user 
36
+                                : { 
37
+                                    name: 'Guest', 
38
+                                    class: _Class[Math.floor(_Class.length * Math.random())], 
39
+                                    pwhash: '',
40
+                                    rank: 'Guest'
41
+                                }
42
+
43
+    authenticate = async (token : Token | string) : Promise<RPCSocket & FrontcraftFeatureIfc> => {
44
+        const auth = await this.socket.Authenticator.authenticate(token)
45
+        return await this.getPrivilegedSocket(auth)
46
+    }
47
+
48
+    login = async (username, password) => {
49
+        const buf = str2arraybuf(password)
50
+        const pwHash = await crypto.subtle.digest('SHA-256', buf);
51
+        const token = await this.socket.Authenticator.login(username, buf2hex(pwHash))
52
+        return await this.authenticate(token)
53
+    }
54
+
55
+    logout = () => {
56
+        this.cookieSvc.deleteAll()
57
+        this.auth  = null
58
+        if(this.privSocket) this.privSocket.destroy()
59
+        this.privSocket = null
60
+    }
61
+
62
+    private setCookie = (token: string | Token) => {
63
+        token = 'string' === typeof token? token : token.value 
64
+        this.cookieSvc.set('token', token)
65
+    }
66
+
67
+    private getCookie = () : string | Token | undefined => {
68
+        return this.cookieSvc.get('token')
69
+    }
70
+
71
+    initialize = async () : Promise<RPCSocket> => {
72
+        const sock : RPCSocket & LoginManagerIfc = await new RPCSocket(20000, window.location.hostname).connect()
73
+        this.socket = sock
74
+
75
+        const cookie = this.getCookie()
76
+        if(cookie) {
77
+            return await this.authenticate(cookie)
78
+        }
79
+
80
+        return sock
81
+    }
82
+}
83
+
84
+function str2arraybuf(str:string): ArrayBuffer {
85
+    return new Buffer(str)
86
+  }
87
+  
88
+function buf2hex(buffer) { // buffer is an ArrayBuffer
89
+    return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
90
+}
91
+
92
+
93
+export function initializeLoginSvc(svc: LoginApiService): () => Promise<RPCSocket> {
94
+    return svc.initialize
95
+}

+ 18
- 0
src/frontend/src/app/frontcraft/user.service.ts 查看文件

@@ -0,0 +1,18 @@
1
+import { Injectable } from "@angular/core";
2
+import {RPCSocket} from 'rpclibrary'
3
+var crypto = require('crypto');
4
+
5
+import { User, } from '../../../../backend/Types/Types'
6
+
7
+@Injectable()
8
+export class UserService{
9
+    
10
+    private loginSocket = new RPCSocket(20000, window.location.hostname).connect()
11
+
12
+    constructor(){}
13
+
14
+    login = async (username:string, password:string) => {
15
+        const pwHash = crypto.createHash('sha256').update(password).digest('hex');
16
+        
17
+    }
18
+}

+ 0
- 243
src/frontend/src/app/pages/pages-menu.ts 查看文件

@@ -1,247 +1,4 @@
1 1
 import { NbMenuItem } from '@nebular/theme';
2 2
 
3 3
 export const MENU_ITEMS: NbMenuItem[] = [
4
-  {
5
-    title: 'E-commerce',
6
-    icon: 'shopping-cart-outline',
7
-    link: '/pages/dashboard',
8
-    home: true,
9
-  },
10
-  {
11
-    title: 'IoT Dashboard',
12
-    icon: 'home-outline',
13
-    link: '/pages/iot-dashboard',
14
-  },
15
-  {
16
-    title: 'FEATURES',
17
-    group: true,
18
-  },
19
-  {
20
-    title: 'Layout',
21
-    icon: 'layout-outline',
22
-    children: [
23
-      {
24
-        title: 'Stepper',
25
-        link: '/pages/layout/stepper',
26
-      },
27
-      {
28
-        title: 'List',
29
-        link: '/pages/layout/list',
30
-      },
31
-      {
32
-        title: 'Infinite List',
33
-        link: '/pages/layout/infinite-list',
34
-      },
35
-      {
36
-        title: 'Accordion',
37
-        link: '/pages/layout/accordion',
38
-      },
39
-      {
40
-        title: 'Tabs',
41
-        pathMatch: 'prefix',
42
-        link: '/pages/layout/tabs',
43
-      },
44
-    ],
45
-  },
46
-  {
47
-    title: 'Forms',
48
-    icon: 'edit-2-outline',
49
-    children: [
50
-      {
51
-        title: 'Form Inputs',
52
-        link: '/pages/forms/inputs',
53
-      },
54
-      {
55
-        title: 'Form Layouts',
56
-        link: '/pages/forms/layouts',
57
-      },
58
-      {
59
-        title: 'Buttons',
60
-        link: '/pages/forms/buttons',
61
-      },
62
-      {
63
-        title: 'Datepicker',
64
-        link: '/pages/forms/datepicker',
65
-      },
66
-    ],
67
-  },
68
-  {
69
-    title: 'UI Features',
70
-    icon: 'keypad-outline',
71
-    link: '/pages/ui-features',
72
-    children: [
73
-      {
74
-        title: 'Grid',
75
-        link: '/pages/ui-features/grid',
76
-      },
77
-      {
78
-        title: 'Icons',
79
-        link: '/pages/ui-features/icons',
80
-      },
81
-      {
82
-        title: 'Typography',
83
-        link: '/pages/ui-features/typography',
84
-      },
85
-      {
86
-        title: 'Animated Searches',
87
-        link: '/pages/ui-features/search-fields',
88
-      },
89
-    ],
90
-  },
91
-  {
92
-    title: 'Modal & Overlays',
93
-    icon: 'browser-outline',
94
-    children: [
95
-      {
96
-        title: 'Dialog',
97
-        link: '/pages/modal-overlays/dialog',
98
-      },
99
-      {
100
-        title: 'Window',
101
-        link: '/pages/modal-overlays/window',
102
-      },
103
-      {
104
-        title: 'Popover',
105
-        link: '/pages/modal-overlays/popover',
106
-      },
107
-      {
108
-        title: 'Toastr',
109
-        link: '/pages/modal-overlays/toastr',
110
-      },
111
-      {
112
-        title: 'Tooltip',
113
-        link: '/pages/modal-overlays/tooltip',
114
-      },
115
-    ],
116
-  },
117
-  {
118
-    title: 'Extra Components',
119
-    icon: 'message-circle-outline',
120
-    children: [
121
-      {
122
-        title: 'Calendar',
123
-        link: '/pages/extra-components/calendar',
124
-      },
125
-      {
126
-        title: 'Progress Bar',
127
-        link: '/pages/extra-components/progress-bar',
128
-      },
129
-      {
130
-        title: 'Spinner',
131
-        link: '/pages/extra-components/spinner',
132
-      },
133
-      {
134
-        title: 'Alert',
135
-        link: '/pages/extra-components/alert',
136
-      },
137
-      {
138
-        title: 'Calendar Kit',
139
-        link: '/pages/extra-components/calendar-kit',
140
-      },
141
-      {
142
-        title: 'Chat',
143
-        link: '/pages/extra-components/chat',
144
-      },
145
-    ],
146
-  },
147
-  {
148
-    title: 'Maps',
149
-    icon: 'map-outline',
150
-    children: [
151
-      {
152
-        title: 'Google Maps',
153
-        link: '/pages/maps/gmaps',
154
-      },
155
-      {
156
-        title: 'Leaflet Maps',
157
-        link: '/pages/maps/leaflet',
158
-      },
159
-      {
160
-        title: 'Bubble Maps',
161
-        link: '/pages/maps/bubble',
162
-      },
163
-      {
164
-        title: 'Search Maps',
165
-        link: '/pages/maps/searchmap',
166
-      },
167
-    ],
168
-  },
169
-  {
170
-    title: 'Charts',
171
-    icon: 'pie-chart-outline',
172
-    children: [
173
-      {
174
-        title: 'Echarts',
175
-        link: '/pages/charts/echarts',
176
-      },
177
-      {
178
-        title: 'Charts.js',
179
-        link: '/pages/charts/chartjs',
180
-      },
181
-      {
182
-        title: 'D3',
183
-        link: '/pages/charts/d3',
184
-      },
185
-    ],
186
-  },
187
-  {
188
-    title: 'Editors',
189
-    icon: 'text-outline',
190
-    children: [
191
-      {
192
-        title: 'TinyMCE',
193
-        link: '/pages/editors/tinymce',
194
-      },
195
-      {
196
-        title: 'CKEditor',
197
-        link: '/pages/editors/ckeditor',
198
-      },
199
-    ],
200
-  },
201
-  {
202
-    title: 'Tables & Data',
203
-    icon: 'grid-outline',
204
-    children: [
205
-      {
206
-        title: 'Smart Table',
207
-        link: '/pages/tables/smart-table',
208
-      },
209
-      {
210
-        title: 'Tree Grid',
211
-        link: '/pages/tables/tree-grid',
212
-      },
213
-    ],
214
-  },
215
-  {
216
-    title: 'Miscellaneous',
217
-    icon: 'shuffle-2-outline',
218
-    children: [
219
-      {
220
-        title: '404',
221
-        link: '/pages/miscellaneous/404',
222
-      },
223
-    ],
224
-  },
225
-  {
226
-    title: 'Auth',
227
-    icon: 'lock-outline',
228
-    children: [
229
-      {
230
-        title: 'Login',
231
-        link: '/auth/login',
232
-      },
233
-      {
234
-        title: 'Register',
235
-        link: '/auth/register',
236
-      },
237
-      {
238
-        title: 'Request Password',
239
-        link: '/auth/request-password',
240
-      },
241
-      {
242
-        title: 'Reset Password',
243
-        link: '/auth/reset-password',
244
-      },
245
-    ],
246
-  },
247 4
 ];

+ 1
- 58
src/frontend/src/app/pages/pages-routing.module.ts 查看文件

@@ -10,64 +10,7 @@ const routes: Routes = [{
10 10
   path: '',
11 11
   component: PagesComponent,
12 12
   children: [
13
-    {
14
-      path: 'dashboard',
15
-      component: ECommerceComponent,
16
-    },
17
-    {
18
-      path: 'iot-dashboard',
19
-      component: DashboardComponent,
20
-    },
21
-    {
22
-      path: 'layout',
23
-      loadChildren: () => import('./layout/layout.module')
24
-        .then(m => m.LayoutModule),
25
-    },
26
-    {
27
-      path: 'forms',
28
-      loadChildren: () => import('./forms/forms.module')
29
-        .then(m => m.FormsModule),
30
-    },
31
-    {
32
-      path: 'ui-features',
33
-      loadChildren: () => import('./ui-features/ui-features.module')
34
-        .then(m => m.UiFeaturesModule),
35
-    },
36
-    {
37
-      path: 'modal-overlays',
38
-      loadChildren: () => import('./modal-overlays/modal-overlays.module')
39
-        .then(m => m.ModalOverlaysModule),
40
-    },
41
-    {
42
-      path: 'extra-components',
43
-      loadChildren: () => import('./extra-components/extra-components.module')
44
-        .then(m => m.ExtraComponentsModule),
45
-    },
46
-    {
47
-      path: 'maps',
48
-      loadChildren: () => import('./maps/maps.module')
49
-        .then(m => m.MapsModule),
50
-    },
51
-    {
52
-      path: 'charts',
53
-      loadChildren: () => import('./charts/charts.module')
54
-        .then(m => m.ChartsModule),
55
-    },
56
-    {
57
-      path: 'editors',
58
-      loadChildren: () => import('./editors/editors.module')
59
-        .then(m => m.EditorsModule),
60
-    },
61
-    {
62
-      path: 'tables',
63
-      loadChildren: () => import('./tables/tables.module')
64
-        .then(m => m.TablesModule),
65
-    },
66
-    {
67
-      path: 'miscellaneous',
68
-      loadChildren: () => import('./miscellaneous/miscellaneous.module')
69
-        .then(m => m.MiscellaneousModule),
70
-    },
13
+    
71 14
     {
72 15
       path: '',
73 16
       redirectTo: 'dashboard',

+ 2
- 1
src/frontend/src/tsconfig.app.json 查看文件

@@ -15,7 +15,8 @@
15 15
   "exclude": [
16 16
     "test.ts",
17 17
     "**/*.spec.ts",
18
-    "../node_modules/@nebular/**/*.spec.ts"
18
+    "../node_modules/@nebular/**/*.spec.ts",
19
+    "../node_modules/rpclibrary/js/**/*"
19 20
   ],
20 21
   "include": [
21 22
     "../src/*.ts",

正在加载...
取消
保存