mm_os 3.3.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (380) hide show
  1. package/LICENSE +21 -201
  2. package/README.md +491 -99
  3. package/README_EN.md +498 -0
  4. package/adapter/adapter.js +431 -0
  5. package/adapter/custom_persistence.js +660 -0
  6. package/adapter/mqtt.js +273 -0
  7. package/adapter/socket.js +113 -0
  8. package/adapter/web.js +67 -0
  9. package/adapter/websocket.js +146 -0
  10. package/com/api/com.json +5 -0
  11. package/{core/com → com}/api/config.tpl.json +8 -8
  12. package/com/api/drive.js +708 -0
  13. package/com/api/index.js +198 -0
  14. package/com/api/oauth.js +200 -0
  15. package/com/api/script.tpl.js +32 -0
  16. package/com/cmd/README.md +11 -0
  17. package/com/cmd/com.json +5 -0
  18. package/com/cmd/config.tpl.json +122 -0
  19. package/com/cmd/drive.js +1548 -0
  20. package/com/cmd/index.js +1066 -0
  21. package/com/cmd/msg.json +48 -0
  22. package/com/cmd/nlp.js +525 -0
  23. package/com/cmd/script.tpl.js +32 -0
  24. package/com/db/com.json +5 -0
  25. package/com/db/drive.js +1999 -0
  26. package/com/db/index.js +242 -0
  27. package/{core/com → com}/event/README.md +4 -4
  28. package/com/event/com.json +5 -0
  29. package/{core/com → com}/event/config.tpl.json +18 -18
  30. package/com/event/drive.js +59 -0
  31. package/com/event/index.js +409 -0
  32. package/com/event/script.tpl.js +23 -0
  33. package/com/mqtt/com.json +5 -0
  34. package/{core/com → com}/mqtt/config.tpl.json +3 -5
  35. package/com/mqtt/drive.js +676 -0
  36. package/com/mqtt/index.js +822 -0
  37. package/com/mqtt/mm_mqtt.js +425 -0
  38. package/com/mqtt/script.tpl.js +723 -0
  39. package/com/nav/com.json +5 -0
  40. package/com/nav/config.tpl.json +84 -0
  41. package/com/nav/drive.js +702 -0
  42. package/com/nav/index.js +231 -0
  43. package/{core/com → com}/nav/tpl/admin_pc/page_config.vue +280 -280
  44. package/{core/com → com}/nav/tpl/admin_pc/page_config_form.vue +194 -194
  45. package/com/nav/tpl/admin_pc/page_form.vue +180 -0
  46. package/com/nav/tpl/admin_pc/page_view.vue +124 -0
  47. package/com/nav/tpl/dev_pc/page_default.vue +247 -0
  48. package/com/nav/tpl/dev_pc/page_type.vue +313 -0
  49. package/com/nav/tpl/home_pc/page_default.vue +234 -0
  50. package/com/nav/tpl/home_pc/page_form.vue +137 -0
  51. package/com/nav/tpl/home_pc/page_list.vue +234 -0
  52. package/com/nav/tpl/home_pc/page_nav.vue +221 -0
  53. package/com/nav/tpl/home_pc/page_type.vue +234 -0
  54. package/com/nav/tpl/home_pc/page_view.vue +125 -0
  55. package/com/nav/tpl/home_phone/page_channel.vue +234 -0
  56. package/com/nav/tpl/home_phone/page_default.vue +234 -0
  57. package/com/nav/tpl/home_phone/page_form.vue +137 -0
  58. package/com/nav/tpl/home_phone/page_nav.vue +237 -0
  59. package/com/nav/tpl/home_phone/page_type.vue +234 -0
  60. package/com/nav/tpl/home_phone/page_view.vue +125 -0
  61. package/com/nav/viewmodel.js +446 -0
  62. package/com/param/com.json +5 -0
  63. package/{core/com → com}/param/config.tpl.json +7 -1
  64. package/com/param/drive.js +502 -0
  65. package/com/param/index.js +155 -0
  66. package/com/param/script.tpl.js +12 -0
  67. package/com/pendant/com.json +5 -0
  68. package/{core/com/component → com/pendant}/config.tpl.json +15 -13
  69. package/com/pendant/drive.js +204 -0
  70. package/com/pendant/index.js +441 -0
  71. package/com/pendant/pendant.html +16 -0
  72. package/com/pendant/script.tpl.js +18 -0
  73. package/com/socket/com.json +5 -0
  74. package/com/socket/config.tpl.json +12 -0
  75. package/com/socket/drive.js +651 -0
  76. package/com/socket/index.js +351 -0
  77. package/com/socket/script.tpl.js +41 -0
  78. package/com/sql/com.json +5 -0
  79. package/{core/com → com}/sql/config.tpl.json +13 -9
  80. package/com/sql/drive.js +1259 -0
  81. package/com/sql/index.js +150 -0
  82. package/com/sql/script.tpl.js +47 -0
  83. package/com/static/com.json +5 -0
  84. package/{core/com → com}/static/config.tpl.json +10 -6
  85. package/com/static/drive.js +194 -0
  86. package/com/static/index.js +226 -0
  87. package/com/static/script.tpl.js +28 -0
  88. package/com/task/com.json +5 -0
  89. package/{core/com → com}/task/config.tpl.json +4 -6
  90. package/com/task/drive.js +405 -0
  91. package/com/task/index.js +148 -0
  92. package/com/task/script.tpl.js +37 -0
  93. package/com/template/com.json +5 -0
  94. package/com/template/config.tpl.json +16 -0
  95. package/com/template/drive.js +80 -0
  96. package/com/template/index.js +141 -0
  97. package/com.js +156 -0
  98. package/common/README.md +2 -0
  99. package/common/handler/msg/handler.json +22 -0
  100. package/common/handler/msg/index.js +23 -0
  101. package/common/handler/player/handler.json +22 -0
  102. package/common/handler/player/index.js +287 -0
  103. package/common/handler/user/handler.json +22 -0
  104. package/common/handler/user/index.js +23 -0
  105. package/common/middleware/web_after/index.js +29 -0
  106. package/common/middleware/web_after/middleware.json +9 -0
  107. package/common/middleware/web_base/index.js +113 -0
  108. package/common/middleware/web_base/middleware.json +19 -0
  109. package/common/middleware/web_before/index.js +33 -0
  110. package/common/middleware/web_before/middleware.json +9 -0
  111. package/common/middleware/web_cors/index.js +87 -0
  112. package/common/middleware/web_cors/middleware.json +24 -0
  113. package/common/middleware/web_error/index.js +119 -0
  114. package/common/middleware/web_error/middleware.json +18 -0
  115. package/common/middleware/web_ip/index.js +15 -0
  116. package/common/middleware/web_ip/middleware.json +14 -0
  117. package/common/middleware/web_logger/index.js +156 -0
  118. package/common/middleware/web_logger/middleware.json +14 -0
  119. package/common/middleware/web_main/index.js +24 -0
  120. package/common/middleware/web_main/middleware.json +9 -0
  121. package/common/middleware/web_static/index.js +73 -0
  122. package/common/middleware/web_static/middleware.json +54 -0
  123. package/common/middleware/web_waf/index.js +385 -0
  124. package/common/middleware/web_waf/middleware.json +13 -0
  125. package/common/model/msg/index.js +88 -0
  126. package/common/model/msg/model.json +401 -0
  127. package/common/model/player/index.js +63 -0
  128. package/common/model/player/model.json +185 -0
  129. package/common/model/user/index.js +11 -0
  130. package/common/model/user/model.json +219 -0
  131. package/core/app/config.tpl.json +67 -0
  132. package/core/app/index.js +632 -0
  133. package/core/app/script.tpl.js +52 -0
  134. package/core/channel/index.js +899 -0
  135. package/core/channel/matcher.js +585 -0
  136. package/core/com/config.tpl.json +16 -0
  137. package/core/com/index.js +74 -0
  138. package/core/com/script.tpl.js +5 -0
  139. package/core/component/component.js +42 -0
  140. package/core/component/config.tpl.json +63 -0
  141. package/core/component/index.js +273 -0
  142. package/core/component/script.tpl.js +19 -0
  143. package/core/controller/config.tpl.json +14 -0
  144. package/core/controller/index.js +373 -0
  145. package/core/controller/script.tpl.js +27 -0
  146. package/core/factory/config.tpl.json +14 -0
  147. package/core/factory/entity.js +275 -0
  148. package/core/factory/index.js +241 -0
  149. package/core/factory/script.tpl.js +16 -0
  150. package/core/game/bat/index.js +137 -0
  151. package/core/game/bat/world.js +622 -0
  152. package/core/game/config.tpl.json +16 -0
  153. package/core/game/entity_admin.js +230 -0
  154. package/core/game/index.js +186 -0
  155. package/core/handler/config.tpl.json +22 -0
  156. package/core/handler/index.js +181 -0
  157. package/core/handler/script.tpl.js +23 -0
  158. package/core/logic/config.tpl.json +14 -0
  159. package/core/logic/index.js +59 -0
  160. package/core/logic/script.tpl.js +19 -0
  161. package/core/middleware/config.tpl.json +16 -0
  162. package/core/middleware/index.js +125 -0
  163. package/core/middleware/script.tpl.js +37 -0
  164. package/core/mod/config.tpl.json +22 -0
  165. package/core/mod/index.js +130 -0
  166. package/core/mod/script.tpl.js +34 -0
  167. package/core/model/config.tpl.json +219 -0
  168. package/core/model/index.js +272 -0
  169. package/core/model/model.js +27 -0
  170. package/core/model/script.tpl.js +20 -0
  171. package/core/notifier/config.tpl.json +14 -0
  172. package/core/notifier/index.js +77 -0
  173. package/core/notifier/script.tpl.js +20 -0
  174. package/core/plugin/config.tpl.json +24 -0
  175. package/core/plugin/index.js +232 -0
  176. package/core/plugin/script.tpl.js +51 -0
  177. package/core/pusher/config.tpl.json +14 -0
  178. package/core/pusher/index.js +161 -0
  179. package/core/pusher/script.tpl.js +20 -0
  180. package/core/room/bat/index.js +170 -0
  181. package/core/room/bat/room.js +524 -0
  182. package/core/room/config.tpl.json +20 -0
  183. package/core/room/index.js +249 -0
  184. package/core/room/room.js +61 -0
  185. package/core/scene/config.tpl.json +14 -0
  186. package/core/scene/index.js +466 -0
  187. package/core/scene/loop.js +1255 -0
  188. package/core/scene/map.js +28 -0
  189. package/core/scene/script.tpl.js +22 -0
  190. package/core/sender/config.tpl.json +14 -0
  191. package/core/sender/index.js +79 -0
  192. package/core/sender/script.tpl.js +20 -0
  193. package/core/service/config.tpl.json +14 -0
  194. package/core/service/index.js +100 -0
  195. package/core/service/script.tpl.js +25 -0
  196. package/core/store/config.tpl.json +26 -0
  197. package/core/store/index.js +1755 -0
  198. package/core/store/script.tpl.js +22 -0
  199. package/core/store/sql.js +1464 -0
  200. package/core/system/config.tpl.json +18 -0
  201. package/core/system/index.js +312 -0
  202. package/core/system/script.tpl.js +77 -0
  203. package/core/view/config.tpl.json +14 -0
  204. package/core/view/index.js +91 -0
  205. package/core/view/script.tpl.js +20 -0
  206. package/core/zone/bat/index.js +725 -0
  207. package/core/zone/config.tpl.json +54 -0
  208. package/core/zone/index.js +614 -0
  209. package/core/zone/script.tpl.js +10 -0
  210. package/core/zone/zone_bat.js +136 -0
  211. package/core//345/237/272/347/261/273/346/250/241/345/235/227/346/270/205/345/215/225.md +24 -0
  212. package/index.js +17 -333
  213. package/os.js +57 -0
  214. package/package.json +58 -58
  215. package/server.js +598 -0
  216. package/README.en.md +0 -36
  217. package/conf.json +0 -3
  218. package/core/base/mqtt/index.js +0 -1110
  219. package/core/base/mqtt/lib.js +0 -40
  220. package/core/base/web/index.js +0 -245
  221. package/core/com/api/com.json +0 -4
  222. package/core/com/api/drive.js +0 -668
  223. package/core/com/api/index.js +0 -108
  224. package/core/com/api/oauth.js +0 -158
  225. package/core/com/api/script.js +0 -32
  226. package/core/com/app/README.md +0 -3
  227. package/core/com/app/com.json +0 -4
  228. package/core/com/app/config.tpl.json +0 -16
  229. package/core/com/app/drive.js +0 -309
  230. package/core/com/app/index.js +0 -211
  231. package/core/com/app/script.js +0 -155
  232. package/core/com/cmd/com.json +0 -4
  233. package/core/com/cmd/config.tpl.json +0 -66
  234. package/core/com/cmd/drive.js +0 -513
  235. package/core/com/cmd/index.js +0 -354
  236. package/core/com/cmd/old/5w2h.js +0 -54
  237. package/core/com/cmd/old/drive.js +0 -423
  238. package/core/com/cmd/script.js +0 -11
  239. package/core/com/component/README.md +0 -3
  240. package/core/com/component/com.json +0 -4
  241. package/core/com/component/component.html +0 -16
  242. package/core/com/component/drive.js +0 -197
  243. package/core/com/component/index.js +0 -312
  244. package/core/com/component/script.js +0 -18
  245. package/core/com/db/com.json +0 -4
  246. package/core/com/db/drive.js +0 -1160
  247. package/core/com/db/index.js +0 -176
  248. package/core/com/event/com.json +0 -4
  249. package/core/com/event/drive.js +0 -133
  250. package/core/com/event/index.js +0 -345
  251. package/core/com/event/script.js +0 -26
  252. package/core/com/eventer/com.js +0 -477
  253. package/core/com/eventer/com.json +0 -4
  254. package/core/com/middleware/com.js +0 -154
  255. package/core/com/middleware/com.json +0 -4
  256. package/core/com/middleware/config.tpl.json +0 -8
  257. package/core/com/middleware/script.js +0 -9
  258. package/core/com/mqtt/com.json +0 -4
  259. package/core/com/mqtt/drive.js +0 -600
  260. package/core/com/mqtt/index.js +0 -572
  261. package/core/com/mqtt/mm_mqtt.js +0 -330
  262. package/core/com/mqtt/script.js +0 -604
  263. package/core/com/msg/com.js +0 -296
  264. package/core/com/msg/com.json +0 -4
  265. package/core/com/nav/com.json +0 -4
  266. package/core/com/nav/config.tpl.json +0 -75
  267. package/core/com/nav/drive.js +0 -549
  268. package/core/com/nav/index.js +0 -182
  269. package/core/com/nav/tpl/admin_pc/page_form.vue +0 -180
  270. package/core/com/nav/tpl/admin_pc/page_view.vue +0 -124
  271. package/core/com/nav/tpl/dev_pc/page_default.vue +0 -247
  272. package/core/com/nav/tpl/dev_pc/page_type.vue +0 -313
  273. package/core/com/nav/tpl/home_pc/page_default.vue +0 -234
  274. package/core/com/nav/tpl/home_pc/page_form.vue +0 -137
  275. package/core/com/nav/tpl/home_pc/page_list.vue +0 -234
  276. package/core/com/nav/tpl/home_pc/page_nav.vue +0 -221
  277. package/core/com/nav/tpl/home_pc/page_type.vue +0 -234
  278. package/core/com/nav/tpl/home_pc/page_view.vue +0 -125
  279. package/core/com/nav/tpl/home_phone/page_channel.vue +0 -234
  280. package/core/com/nav/tpl/home_phone/page_default.vue +0 -234
  281. package/core/com/nav/tpl/home_phone/page_form.vue +0 -137
  282. package/core/com/nav/tpl/home_phone/page_nav.vue +0 -237
  283. package/core/com/nav/tpl/home_phone/page_type.vue +0 -234
  284. package/core/com/nav/tpl/home_phone/page_view.vue +0 -125
  285. package/core/com/nav/viewmodel.js +0 -296
  286. package/core/com/param/drive.js +0 -366
  287. package/core/com/param/index.js +0 -80
  288. package/core/com/param/script.js +0 -12
  289. package/core/com/param/test.js +0 -98
  290. package/core/com/plugin/README.md +0 -3
  291. package/core/com/plugin/com.json +0 -4
  292. package/core/com/plugin/config.tpl.json +0 -26
  293. package/core/com/plugin/drive.js +0 -536
  294. package/core/com/plugin/index.js +0 -259
  295. package/core/com/plugin/script.js +0 -213
  296. package/core/com/rpc/com.json +0 -4
  297. package/core/com/rpc/drive.js +0 -160
  298. package/core/com/rpc/index.js +0 -87
  299. package/core/com/rpc/rpc.js +0 -118
  300. package/core/com/socket/com.json +0 -4
  301. package/core/com/socket/config.tpl.json +0 -14
  302. package/core/com/socket/drive.js +0 -403
  303. package/core/com/socket/index.js +0 -62
  304. package/core/com/socket/script.js +0 -42
  305. package/core/com/sql/drive.js +0 -1087
  306. package/core/com/sql/index.js +0 -83
  307. package/core/com/sql/script.js +0 -48
  308. package/core/com/static/com.json +0 -4
  309. package/core/com/static/drive.js +0 -220
  310. package/core/com/static/index.js +0 -149
  311. package/core/com/static/script.js +0 -28
  312. package/core/com/task/com.json +0 -4
  313. package/core/com/task/drive.js +0 -403
  314. package/core/com/task/index.js +0 -110
  315. package/core/com/task/script.js +0 -37
  316. package/core/com/timer/com.js +0 -217
  317. package/core/com/timer/com.json +0 -4
  318. package/core/com/tpl/com.js +0 -19
  319. package/core/com/tpl/com.json +0 -4
  320. package/lib/actions.js +0 -50
  321. package/lib/base.js +0 -361
  322. package/lib/com.js +0 -29
  323. package/lib/ref.js +0 -121
  324. package/middleware/cors/index.js +0 -119
  325. package/middleware/cors/middleware.json +0 -20
  326. package/middleware/csrf/index.js +0 -202
  327. package/middleware/csrf/middleware.json +0 -24
  328. package/middleware/ip_firewall/index.js +0 -476
  329. package/middleware/ip_firewall/middleware.json +0 -109
  330. package/middleware/mqtt_base/index.js +0 -10
  331. package/middleware/mqtt_base/middleware.json +0 -11
  332. package/middleware/security_audit/index.js +0 -543
  333. package/middleware/security_audit/middleware.json +0 -48
  334. package/middleware/waf/index.js +0 -343
  335. package/middleware/waf/middleware.json +0 -10
  336. package/middleware/waf_ddos/index.js +0 -520
  337. package/middleware/waf_ddos/middleware.json +0 -38
  338. package/middleware/waf_xss/index.js +0 -269
  339. package/middleware/waf_xss/middleware.json +0 -18
  340. package/middleware/web_after/index.js +0 -33
  341. package/middleware/web_after/middleware.json +0 -10
  342. package/middleware/web_base/index.js +0 -90
  343. package/middleware/web_base/middleware.json +0 -10
  344. package/middleware/web_before/index.js +0 -27
  345. package/middleware/web_before/middleware.json +0 -10
  346. package/middleware/web_check/index.js +0 -28
  347. package/middleware/web_check/middleware.json +0 -10
  348. package/middleware/web_main/index.js +0 -28
  349. package/middleware/web_main/middleware.json +0 -10
  350. package/middleware/web_proxy/index.js +0 -37
  351. package/middleware/web_proxy/middleware.json +0 -10
  352. package/middleware/web_render/index.js +0 -87
  353. package/middleware/web_render/middleware.json +0 -10
  354. package/middleware/web_socket/index.js +0 -34
  355. package/middleware/web_socket/middleware.json +0 -10
  356. package/middleware/web_static/index.js +0 -115
  357. package/middleware/web_static/middleware.json +0 -10
  358. /package/{core/com → com}/api/README.md +0 -0
  359. /package/{core/com → com}/db/README.md +0 -0
  360. /package/{core/com → com}/mqtt/README.md +0 -0
  361. /package/{core/com → com}/nav/README.md +0 -0
  362. /package/{core/com → com}/nav/tpl/admin_pc/page_channel.vue +0 -0
  363. /package/{core/com → com}/nav/tpl/admin_pc/page_default.vue +0 -0
  364. /package/{core/com → com}/nav/tpl/admin_pc/page_lang.vue +0 -0
  365. /package/{core/com → com}/nav/tpl/admin_pc/page_nav.vue +0 -0
  366. /package/{core/com → com}/nav/tpl/admin_pc/page_table.vue +0 -0
  367. /package/{core/com → com}/nav/tpl/admin_pc/page_type.vue +0 -0
  368. /package/{core/com → com}/nav/tpl/dev_pc/page_channel.vue +0 -0
  369. /package/{core/com → com}/nav/tpl/dev_pc/page_config.vue +0 -0
  370. /package/{core/com → com}/nav/tpl/dev_pc/page_form.vue +0 -0
  371. /package/{core/com → com}/nav/tpl/dev_pc/page_nav.vue +0 -0
  372. /package/{core/com → com}/nav/tpl/dev_pc/page_table.vue +0 -0
  373. /package/{core/com → com}/nav/tpl/home_pc/page_channel.vue +0 -0
  374. /package/{core/com → com}/nav/tpl/home_phone/page_list.vue +0 -0
  375. /package/{core/com → com}/param/README.md +0 -0
  376. /package/{core/com/cmd → com/pendant}/README.md +0 -0
  377. /package/{core/com → com}/socket/README.md +0 -0
  378. /package/{core/com → com}/sql/README.md +0 -0
  379. /package/{core/com → com}/static/README.md +0 -0
  380. /package/{core/com → com}/task/README.md +0 -0
@@ -0,0 +1,1999 @@
1
+ const Item = require('mm_machine').Drive;
2
+ const fs = require('fs');
3
+
4
+ if (!$.dict.user_id) {
5
+ $.dict.user_id = 'user_id';
6
+ }
7
+
8
+ var keyword_default =
9
+ "`user_id` in (SELECT `user_id` FROM `user_account` WHERE `nickname` LIKE '%{0}%' OR `phone` LIKE '%{0}%' OR `wallet_address` LIKE '%{0}%')";
10
+
11
+ var keyword_default_tip = '昵称、手机号、钱包地址';
12
+
13
+ /**
14
+ * db数据库开发驱动类
15
+ * @augments {Item}
16
+ * @class
17
+ */
18
+ class Drive extends Item {
19
+ static config = {
20
+ // 库表名称(唯一标识)
21
+ 'name': 'db',
22
+ // 标题(中文名)
23
+ 'title': '',
24
+ // 表名
25
+ 'table': '',
26
+ // 主键,用于实体模型
27
+ 'key': '',
28
+ // 字段
29
+ 'fields': [
30
+ /* */
31
+ ],
32
+ 'index‌': [],
33
+ // 主程序文件 - 默认为空
34
+ 'main': ''
35
+ };
36
+
37
+ /**
38
+ * 构造函数
39
+ * @param {object} config 配置参数
40
+ * @param {object} parent 父对象
41
+ * @class
42
+ */
43
+ constructor(config, parent) {
44
+ super({ ...Drive.config, ...config }, parent);
45
+ }
46
+ }
47
+
48
+ /**
49
+ * 重置配置参数
50
+ */
51
+ Drive.prototype._reset = function () {
52
+ this.query_string = ['name', 'title', 'keywords', 'tag', 'description', 'content'];
53
+
54
+ // 是否设置数值类型为可查询
55
+ this.query_number = ['state', 'uin'];
56
+
57
+ // 是否设置数值类型为关键词可查
58
+ this.query_keyword = ['name', 'title', 'keywords', 'tag', 'description'];
59
+
60
+ // 是否设置以下字段为get查列表SQL时不可见
61
+ this.get_not = ['password', 'salt', 'content'];
62
+
63
+ // 是否设置以下字段为getObj查对象SQL时不可见
64
+ this.getobj_not = ['password', 'salt', 'display'];
65
+
66
+ // 是否设置默认该表仅用户可访问
67
+ this.query_default_table = ['user'];
68
+ }
69
+
70
+ /**
71
+ * 解析字段类型
72
+ * @param {string} type 字段类型
73
+ * @returns {object} 解析结果
74
+ */
75
+ Drive.prototype._parseFieldType = function (type) {
76
+ var tp = type.left('(', true);
77
+ var len = type.between('(', ')');
78
+ var max = 0;
79
+ var decimal = 0;
80
+ if (len) {
81
+ max = number(len.left(',', true));
82
+ var d = len.right(',');
83
+ if (d) {
84
+ decimal = number(d);
85
+ }
86
+ }
87
+ return { tp, max, decimal };
88
+ };
89
+
90
+ /**
91
+ * 解析字段备注
92
+ * @param {string} note 字段备注
93
+ * @param {string} tp 字段类型
94
+ * @param {number} max_length 最大长度
95
+ * @returns {object} 解析结果
96
+ */
97
+ Drive.prototype._parseFieldNote = function (note, tp, max_length) {
98
+ var proc_note = note.replace(':', ':').replace('(', '(').replace(')', ')');
99
+ var title = proc_note.left(':', true).trim();
100
+ var desc = proc_note.right(':');
101
+ var description = '';
102
+ var map = '';
103
+ var min = 0;
104
+ var max = 0;
105
+ var local_max_length = max_length;
106
+
107
+ if (desc) {
108
+ description = desc.right(']', true).left('(', true).trim();
109
+ var range = desc.between('[', ']');
110
+ if (range) {
111
+ var min_str = range.left(',', true);
112
+ if (min_str) {
113
+ min = number(min_str);
114
+ }
115
+ var max_str = range.right(',');
116
+ if (max_str) {
117
+ var n = number(max_str);
118
+ if (tp === 'varchar') {
119
+ if (n < local_max_length) {
120
+ local_max_length = n;
121
+ }
122
+ } else {
123
+ max = n;
124
+ }
125
+ }
126
+ }
127
+ map = desc.between('(', ')');
128
+ }
129
+
130
+ return { title, description, map, min, max, max_length: local_max_length };
131
+ };
132
+
133
+ /**
134
+ * 计算字段最大值
135
+ * @param {string} tp 字段类型
136
+ * @param {number} max 当前最大值
137
+ * @param {number} max_length 最大长度
138
+ * @returns {number} 计算后的最大值
139
+ */
140
+ Drive.prototype._calculateMaxValue = function (tp, max, max_length) {
141
+ var local_max = max;
142
+ if (local_max === 0) {
143
+ switch (tp) {
144
+ case 'tinyint':
145
+ local_max = 1;
146
+ break;
147
+ case 'smallint':
148
+ local_max = 32767;
149
+ break;
150
+ case 'mediumint':
151
+ local_max = 8388607;
152
+ break;
153
+ case 'int':
154
+ local_max = 2147483647;
155
+ break;
156
+ case 'bigint':
157
+ local_max = 0;
158
+ break;
159
+ default:
160
+ break;
161
+ }
162
+ if (max_length) {
163
+ var num = Math.pow(10, max_length) - 1;
164
+ if (local_max > num) {
165
+ local_max = num;
166
+ }
167
+ }
168
+ }
169
+ return local_max;
170
+ };
171
+
172
+ /**
173
+ * 处理字段默认值
174
+ * @param {string} tp 字段类型
175
+ * @param {boolean} not_null 是否非空
176
+ * @param {*} default_val 默认值
177
+ * @returns {*} 处理后的默认值
178
+ */
179
+ Drive.prototype._handleDefaultValue = function (tp, not_null, default_val) {
180
+ if (not_null && !default_val) {
181
+ if (tp === 'varchar' || tp === 'text') {
182
+ return '';
183
+ } else {
184
+ return '0';
185
+ }
186
+ }
187
+ return default_val;
188
+ };
189
+
190
+ /**
191
+ * 创建字段模型对象
192
+ * @param {string} name 字段名
193
+ * @param {string} title 字段标题
194
+ * @param {string} description 字段描述
195
+ * @param {string} tp 字段类型
196
+ * @param {boolean} pk 是否主键
197
+ * @param {boolean} auto 是否自动
198
+ * @param {boolean} not_null 是否非空
199
+ * @param {number} min_length 最小长度
200
+ * @param {number} max_length 最大长度
201
+ * @param {number} min 最小值
202
+ * @param {number} max 最大值
203
+ * @param {number} decimal 小数位
204
+ * @param {*} default_val 默认值
205
+ * @param {object} map 转换编排
206
+ * @returns {object} 字段模型对象
207
+ * @private
208
+ */
209
+ Drive.prototype._createFieldModel = function (
210
+ name, title, description, tp, pk, auto, not_null,
211
+ min_length, max_length, min, max, decimal, default_val, map
212
+ ) {
213
+ return {
214
+ // 字段名
215
+ 'name': name,
216
+ // 字段标题
217
+ 'title': title,
218
+ // 字段描述
219
+ 'description': description,
220
+ // 字段类型 smallint短整数、mediumint中长整数、int整数、float浮点数、double双精度、tinyint二进制(0和1的布尔)、text文本、varchar字符串、datetime日期时间、date日期、time时间、timestamp时间戳
221
+ 'type': tp,
222
+ // 是否主键
223
+ 'key': pk,
224
+ // 自动
225
+ 'auto': auto,
226
+ // 是否含符号
227
+ 'symbol': tp === 'float' || tp === 'decimal',
228
+ // 是否填充零,用于数字类型
229
+ 'fill_zero': false,
230
+ // 非空
231
+ 'not_null': not_null,
232
+ // 最小长度
233
+ 'min_length': min_length,
234
+ // 最大长度
235
+ 'max_length': max_length,
236
+ // 最小值
237
+ 'min': min,
238
+ // 最大值
239
+ 'max': max,
240
+ // 小数位
241
+ 'decimal': decimal,
242
+ // 默认值
243
+ 'default': default_val,
244
+ // 转换编排
245
+ 'map': map
246
+ };
247
+ };
248
+
249
+ /**
250
+ * 创建字段模型
251
+ * @param {object} fields 字段对象
252
+ * @param {string} fields.name 字段名称
253
+ * @param {object} fields.default 默认值
254
+ * @param {object} fields.notnull 是否非空
255
+ * @param {object} fields.type 字段类型
256
+ * @param {object} fields.pk 是否主键
257
+ * @param {object} fields.auto 是否自动增长
258
+ * @param {object} fields.note 字段备注
259
+ * @returns {object} 返回字段模型
260
+ */
261
+ Drive.prototype.model = function (fields) {
262
+ var {
263
+ name,
264
+ notnull,
265
+ type,
266
+ pk,
267
+ note,
268
+ auto
269
+ } = fields;
270
+
271
+ var { tp, max: max_length, decimal } = this._parseFieldType(type);
272
+ var {
273
+ title,
274
+ description,
275
+ map,
276
+ min,
277
+ max: parsedMax,
278
+ max_length: parsedMaxLength
279
+ } = this._parseFieldNote(note, tp, max_length);
280
+
281
+ var max = this._calcMaxValue(tp, parsedMax, parsedMaxLength);
282
+
283
+ if (name.indexOf('_id') !== -1 || name == 'id') {
284
+ min = 0;
285
+ }
286
+
287
+ var not_null = notnull | pk | (tp !== 'varchar' && tp !== 'text');
288
+
289
+ var config = this.config;
290
+ if (pk && !config.key) {
291
+ config.key = name;
292
+ }
293
+
294
+ var default_value = this._handleDefaultValue(tp, not_null, fields.default);
295
+
296
+ return this._createFieldModel(
297
+ name, title, description, tp, pk, auto, not_null,
298
+ min_length, parsedMaxLength, min, max, decimal,
299
+ default_value, map
300
+ );
301
+ };
302
+
303
+ /**
304
+ * 创建索引字段模型
305
+ * @param {object} o 索引对象
306
+ * @property {string} o.Key_name 索引名称
307
+ * @property {string} o.Non_unique 是否唯一索引
308
+ * @property {string} o.Column_name 索引字段
309
+ * @property {string} o.Manager_comment 索引备注
310
+ * @returns {object} 返回索引模型
311
+ */
312
+ Drive.prototype.modelmanager = function (o) {
313
+ return {
314
+ 'name': o.Key_name,
315
+ 'type': o.Non_unique ? 'unique' : 'index',
316
+ 'fields': o.Column_name.replace(/`/g, '').split(','),
317
+ 'comment': o.Manager_comment
318
+ };
319
+ };
320
+
321
+ /**
322
+ * 从数据库更新索引配置
323
+ * @param {object} db 数据库管理器
324
+ * @returns {Array} 索引列表
325
+ */
326
+ Drive.prototype.updateFilemanager = function (db) {
327
+ var sql = 'SHOW INDEX FROM `' + this.config.table + '`';
328
+ var rows = db.run(sql);
329
+ var dict = {};
330
+ for (var i = 0; i < rows.length; i++) {
331
+ var o = rows[i];
332
+ if (o.Key_name !== 'PRIMARY') {
333
+ if (!dict[o.Key_name]) {
334
+ dict[o.Key_name] = {
335
+ column_name: []
336
+ };
337
+ }
338
+ dict[o.Key_name].Column_name.push(o.Column_name);
339
+ }
340
+ }
341
+ var list = [];
342
+ for (var k in dict) {
343
+ var m = this.modelmanager(dict[k]);
344
+ list.push(m);
345
+ }
346
+
347
+ return list;
348
+ };
349
+
350
+ /**
351
+ * 从数据库更新配置
352
+ * @param {object} db 数据库管理器
353
+ * @param {boolean} cover 是否覆盖文件
354
+ */
355
+ Drive.prototype.updateFile = async function (db, cover) {
356
+ var cg = this.config;
357
+ var list = [];
358
+
359
+ // 查询表注释并修改
360
+ var sql = "SELECT TABLE_NAME, TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '" + db
361
+ .database() +
362
+ "' && TABLE_NAME = '" + cg.table + "';";
363
+
364
+ var lt = await db.run(sql);
365
+ if (lt && lt.length > 0) {
366
+ var commit = lt[0].TABLE_COMMENT;
367
+ var arr = commit.replace(':', ':').split(':');
368
+ cg.title = arr[0];
369
+ if (arr.length > 1) {
370
+ cg.description = arr[1];
371
+ }
372
+ }
373
+
374
+ // 设置表名
375
+ db.table = cg.table + '';
376
+
377
+ // 获取所有字段
378
+ var fields = await db.fields();
379
+ for (var i = 0; i < fields.length; i++) {
380
+ var field = this.model(fields[i]);
381
+ list.push(field);
382
+ }
383
+ cg.fields = list;
384
+ cg.index‌ = await this.updateFilemanager(db);
385
+ if (!cg.name) {
386
+ cg.name = cg.table;
387
+ }
388
+ await this.updateApp(cover);
389
+ };
390
+
391
+ /**
392
+ * 更新索引
393
+ * @param {object} db 数据库管理器
394
+ */
395
+ Drive.prototype.updateDbmanager = async function (db) {
396
+ var cg = this.config;
397
+ let index = cg.index || [];
398
+ // 更新索引
399
+ if (index) {
400
+ var len = index.length;
401
+ for (var i = 0; i < len; i++) {
402
+ var o = index‌[i];
403
+ var sql_start = '';
404
+ if (o.type === 'unique') {
405
+ sql_start = 'CREATE UNIQUE INDEX `';
406
+ } else {
407
+ sql_start = 'CREATE INDEX `';
408
+ }
409
+ await db.exec(sql_start + o.name + '` ON `' + table + '` (' + o.fields + ');');
410
+ }
411
+ }
412
+ };
413
+
414
+ /**
415
+ * 初始化数据表
416
+ * @param {object} db 数据库管理器
417
+ * @param {object} cg 配置对象
418
+ * @param {Array} list 字段列表
419
+ * @returns {Array} 字段列表
420
+ */
421
+ Drive.prototype._initTable = async function (db, cg, list) {
422
+ var fields = await db.fields();
423
+ if (fields.length === 0) {
424
+ var k = cg.key;
425
+ var len = list.length;
426
+ for (var i = 0; i < len; i++) {
427
+ var o = list[i];
428
+ if (k === o.name) {
429
+ await db.addTable(cg.table, o.name, o.type, o.auto, cg.title + ':' + cg.description);
430
+ fields.push({
431
+ name: o.name
432
+ });
433
+ break;
434
+ }
435
+ }
436
+ } else {
437
+ var commit = cg.title + ':' + cg.description;
438
+ var sql = "alter table `{0}` comment '{1}';".replace('{0}', cg.table).replace('{1}', commit);
439
+ await db.exec(sql);
440
+ }
441
+ return fields;
442
+ };
443
+
444
+ /**
445
+ * 删除配置中没有的字段
446
+ * @param {object} db 数据库管理器
447
+ * @param {Array} fields 数据库字段列表
448
+ * @param {Array} list 配置字段列表
449
+ */
450
+ Drive.prototype._deleteUnusedFields = async function (db, fields, list) {
451
+ for (var i = 0; i < fields.length; i++) {
452
+ var o = fields[i];
453
+ var obj = list.getObj({
454
+ name: o.name
455
+ });
456
+
457
+ if (!obj) {
458
+ await db.fieldDel(o.name);
459
+ }
460
+ }
461
+ };
462
+
463
+ /**
464
+ * 生成字段SQL
465
+ * @param {object} o 字段对象
466
+ * @returns {string} 字段SQL
467
+ */
468
+ Drive.prototype._generateFieldSql = function (o) {
469
+ var type = this._getTypeSql(o);
470
+ var notnull = this._getNotNullSql(o);
471
+ var value = this._getValueSql(o);
472
+ var note = this._getNoteSql(o);
473
+
474
+ return this._buildFieldSql(o.name, type, notnull, value, note);
475
+ };
476
+
477
+ /**
478
+ * 获取类型SQL
479
+ * @param {object} o 字段对象
480
+ * @returns {string} 类型SQL
481
+ * @private
482
+ */
483
+ Drive.prototype._getTypeSql = function (o) {
484
+ var type;
485
+ if (o.decimal) {
486
+ type = o.type + '(' + o.max_length + ',' + o.decimal + ')';
487
+ } else {
488
+ type = o.type + '(' + o.max_length + ')';
489
+ }
490
+
491
+ if (!o.symbol && (o.type !== 'varchar' && o.type !== 'longtext' && o.type !== 'text' &&
492
+ o.type !== 'date' && o.type !== 'time' && o.type !== 'datetime' && o.type !== 'timestamp')) {
493
+ type += ' UNSIGNED';
494
+ }
495
+
496
+ return type;
497
+ };
498
+
499
+ /**
500
+ * 获取NOT NULL SQL
501
+ * @param {object} o 字段对象
502
+ * @returns {string} NOT NULL SQL
503
+ * @private
504
+ */
505
+ Drive.prototype._getNotNullSql = function (o) {
506
+ var notnull = '';
507
+
508
+ if (this._isNotNullRequired(o)) {
509
+ notnull = 'NOT NULL';
510
+ }
511
+
512
+ if (this._isAutoInc(o)) {
513
+ notnull += ' AUTO_INCREMENT';
514
+ }
515
+
516
+ return notnull;
517
+ };
518
+
519
+ /**
520
+ * 检查是否需要NOT NULL
521
+ * @param {object} o 字段对象
522
+ * @returns {boolean} 是否需要NOT NULL
523
+ * @private
524
+ */
525
+ Drive.prototype._isNotNullRequired = function (o) {
526
+ return o.not_null || this._isDateTimeType(o.type) || this._isNumericType(o.type);
527
+ };
528
+
529
+ /**
530
+ * 检查是否为日期时间类型
531
+ * @param {string} type 类型
532
+ * @returns {boolean} 是否为日期时间类型
533
+ * @private
534
+ */
535
+ Drive.prototype._isDateTimeType = function (type) {
536
+ return type === 'date' || type === 'time' || type === 'datetime' || type === 'timestamp';
537
+ };
538
+
539
+ /**
540
+ * 检查是否为数字类型
541
+ * @param {string} type 类型
542
+ * @returns {boolean} 是否为数字类型
543
+ * @private
544
+ */
545
+ Drive.prototype._isNumericType = function (type) {
546
+ return type !== 'varchar' && type !== 'longtext' && type !== 'text' && !this._isDateTimeType(type);
547
+ };
548
+
549
+ /**
550
+ * 检查是否需要AUTO_INCREMENT
551
+ * @param {object} o 字段对象
552
+ * @returns {boolean} 是否需要AUTO_INCREMENT
553
+ * @private
554
+ */
555
+ Drive.prototype._isAutoInc = function (o) {
556
+ return o.auto && !this._isDateTimeType(o.type);
557
+ };
558
+
559
+ /**
560
+ * 获取默认值SQL
561
+ * @param {object} o 字段对象
562
+ * @returns {string} 默认值SQL
563
+ * @private
564
+ */
565
+ Drive.prototype._getValueSql = function (o) {
566
+ if (this._isAutoTime(o)) {
567
+ return 'DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP';
568
+ }
569
+
570
+ if (o.default === null) {
571
+ return 'DEFAULT NULL';
572
+ }
573
+
574
+ if (o.default) {
575
+ return this._getDefaultValueSql(o);
576
+ }
577
+
578
+ return this._getDefaultEmptySql(o);
579
+ };
580
+
581
+ /**
582
+ * 检查是否为自动时间
583
+ * @param {object} o 字段对象
584
+ * @returns {boolean} 是否为自动时间
585
+ * @private
586
+ */
587
+ Drive.prototype._isAutoTime = function (o) {
588
+ return o.auto && this._isDateTimeType(o.type);
589
+ };
590
+
591
+ /**
592
+ * 获取默认值SQL
593
+ * @param {object} o 字段对象
594
+ * @returns {string} 默认值SQL
595
+ * @private
596
+ */
597
+ Drive.prototype._getDefaultValueSql = function (o) {
598
+ if (this._isCurrentDefault(o)) {
599
+ return 'DEFAULT ' + o.default;
600
+ } else if (this._isStringType(o.type)) {
601
+ return "DEFAULT '" + o.default + "'";
602
+ } else {
603
+ return 'DEFAULT ' + o.default;
604
+ }
605
+ };
606
+
607
+ /**
608
+ * 检查是否为当前时间默认值
609
+ * @param {object} o 字段对象
610
+ * @returns {boolean} 是否为当前时间默认值
611
+ * @private
612
+ */
613
+ Drive.prototype._isCurrentDefault = function (o) {
614
+ return this._isDateTimeType(o.type) && o.default.indexOf('CURR') !== -1;
615
+ };
616
+
617
+ /**
618
+ * 检查是否为字符串类型
619
+ * @param {string} type 类型
620
+ * @returns {boolean} 是否为字符串类型
621
+ * @private
622
+ */
623
+ Drive.prototype._isStringType = function (type) {
624
+ return type === 'varchar' || type === 'longtext' || type === 'text' ||
625
+ type === 'date' || type === 'time' || type === 'datetime' || type === 'timestamp';
626
+ };
627
+
628
+ /**
629
+ * 获取空默认值SQL
630
+ * @param {object} o 字段对象
631
+ * @returns {string} 空默认值SQL
632
+ * @private
633
+ */
634
+ Drive.prototype._getDefaultEmptySql = function (o) {
635
+ if (this._isStringType(o.type)) {
636
+ return "DEFAULT ''";
637
+ } else {
638
+ return 'DEFAULT 0';
639
+ }
640
+ };
641
+
642
+ /**
643
+ * 获取注释SQL
644
+ * @param {object} o 字段对象
645
+ * @returns {string} 注释SQL
646
+ * @private
647
+ */
648
+ Drive.prototype._getNoteSql = function (o) {
649
+ var note = o.title + ':';
650
+
651
+ if (o.type === 'varchar' || o.type === 'text' || o.type === 'longtext') {
652
+ if (o.max_length) {
653
+ note += '[' + o.min_length + ',' + o.max_length + ']';
654
+ } else if (o.min_length) {
655
+ note += '[' + o.min_length + ']';
656
+ }
657
+ } else {
658
+ if (o.max) {
659
+ note += '[' + o.min + ',' + o.max + ']';
660
+ } else if (o.min) {
661
+ note += '[' + o.min + ']';
662
+ }
663
+ }
664
+
665
+ note += o.description;
666
+ if (o.map) {
667
+ note += '(' + o.map + ')';
668
+ }
669
+
670
+ return note;
671
+ };
672
+
673
+ /**
674
+ * 构建字段SQL
675
+ * @param {string} name 字段名
676
+ * @param {string} type 类型
677
+ * @param {string} notnull NOT NULL
678
+ * @param {string} value 默认值
679
+ * @param {string} note 注释
680
+ * @returns {string} 字段SQL
681
+ * @private
682
+ */
683
+ Drive.prototype._buildFieldSql = function (name, type, notnull, value, note) {
684
+ var sql = "`{1}` {2} {3} {4} COMMENT '{5}'";
685
+ return sql.replace('{1}', name).replace('{2}', type).replace('{3}', notnull).replace('{4}', value)
686
+ .replace('{5}', note);
687
+ };
688
+
689
+ /**
690
+ * 添加或修改字段
691
+ * @param {object} db 数据库管理器
692
+ * @param {string} table 表名
693
+ * @param {object} o 字段对象
694
+ * @param {Array} fields 数据库字段列表
695
+ */
696
+ Drive.prototype._addOrUpdateField = async function (db, table, o, fields) {
697
+ var arr = fields.get({
698
+ name: o.name
699
+ });
700
+ var sql = this._generateFieldSql(o);
701
+
702
+ if (arr.length === 0) {
703
+ // 如果没有则添加
704
+ await db.exec('alter table `{0}` add '.replace('{0}', table) + sql);
705
+ } else {
706
+ // 如果有则修改
707
+ await db.exec('alter table `{0}` change `{1}` '.replace('{0}', table).replace('{1}', o.name) + sql);
708
+ }
709
+ };
710
+
711
+ /**
712
+ * 通过配置更新数据库
713
+ * @param {object} db 数据库管理器
714
+ * @returns {string} 更新成功返回空,否则返回错误提示
715
+ */
716
+ Drive.prototype.updateDb = async function (db) {
717
+ var cg = this.config;
718
+ db.table = cg.table + '';
719
+ var table = cg.table;
720
+ var list = cg.fields;
721
+
722
+ var fields = await this._initTable(db, cg, list);
723
+
724
+ if (fields.length > 0) {
725
+ // 删除配置中没有的字段
726
+ await this._deleteUnusedFields(db, fields, list);
727
+
728
+ // 添加或修改配置
729
+ var len = list.length;
730
+ for (var i = 0; i < len; i++) {
731
+ var o = list[i];
732
+ await this._addOrUpdateField(db, table, o, fields);
733
+ }
734
+ } else {
735
+ return '数据表更新失败';
736
+ }
737
+ };
738
+
739
+ /**
740
+ * 确定目录结构
741
+ * @param {object} cg 配置对象
742
+ * @returns {object} 目录信息
743
+ * @private
744
+ */
745
+ Drive.prototype._deteDire = function (cg) {
746
+ var p = './app/'.fullname();
747
+ var dir_arr = cg.table.split('_');
748
+ var scope = dir_arr[0];
749
+ var dir = p + scope;
750
+ var dir_api = dir + '/plugin/server';
751
+ var db_dir = dir_api + '/db';
752
+ var config_file = db_dir.fullname() + cg.table.replace(scope + '_', '') + '.db.json';
753
+
754
+ return {
755
+ scope,
756
+ dir,
757
+ dir_api,
758
+ db_dir,
759
+ config_file
760
+ };
761
+ };
762
+
763
+ /**
764
+ * 确保目录存在
765
+ * @param {string} dir 目录路径
766
+ * @private
767
+ */
768
+ Drive.prototype._ensureDir = function (dir) {
769
+ if (!fs.existsSync(dir)) {
770
+ fs.mkdirSync(dir);
771
+ }
772
+ };
773
+
774
+ /**
775
+ * 处理配置文件
776
+ * @param {string} f 文件路径
777
+ * @param {boolean} cover 是否覆盖文件
778
+ * @private
779
+ */
780
+ Drive.prototype._handleConfigFile = function (f, cover) {
781
+ if (!f.hasFile()) {
782
+ this.save();
783
+ } else if (cover) {
784
+ var jobj = f.loadJson();
785
+ var o = { ...this.config };
786
+ if (!o.title) {
787
+ delete o.title;
788
+ }
789
+ if (!o.description) {
790
+ delete o.description;
791
+ }
792
+ $.push(jobj, o, true);
793
+ f.saveText(JSON.stringify(jobj, null, 4));
794
+ }
795
+ };
796
+
797
+ /**
798
+ * 更新应用,根据表生成目录结构和文件
799
+ * @param {boolean} cover 是否覆盖文件
800
+ */
801
+ Drive.prototype.updateApp = async function (cover) {
802
+ var cg = this.config;
803
+ var f;
804
+ var dir_api;
805
+
806
+ if (!this.config_file) {
807
+ var dirs = this._deteDire(cg);
808
+
809
+ this._ensureDir(dirs.dir);
810
+ this._ensureDir(dirs.dir + '/plugin');
811
+ this._ensureDir(dirs.dir_api);
812
+ this._ensureDir(dirs.db_dir);
813
+
814
+ this.dir = dirs.db_dir.fullname();
815
+ this.config_file = dirs.config_file;
816
+ f = dirs.config_file;
817
+ dir_api = dirs.dir_api;
818
+ } else {
819
+ f = this.config_file + '.db.json';
820
+ }
821
+
822
+ if (f) {
823
+ if (!this.dir) {
824
+ this.dir = f.dirname();
825
+ if (!fs.existsSync(this.dir)) {
826
+ fs.mkdirSync(this.dir);
827
+ }
828
+ }
829
+ if (!dir_api) {
830
+ dir_api = this.dir.dirname();
831
+ }
832
+
833
+ this._handleConfigFile(f, cover);
834
+ this.updateApi(dir_api, cover);
835
+ }
836
+ };
837
+
838
+ /**
839
+ * 确保API目录存在
840
+ * @param {string} dir 目录路径
841
+ * @private
842
+ */
843
+ Drive.prototype._ensureApiDir = function (dir) {
844
+ if (!fs.existsSync(dir)) {
845
+ fs.mkdirSync(dir);
846
+ }
847
+ };
848
+
849
+ /**
850
+ * 确定API目录路径
851
+ * @param {string} dir 基础目录
852
+ * @param {string} app 应用名称
853
+ * @param {string} type 类型 (client 或 manage)
854
+ * @param {string} name 目录名称
855
+ * @returns {string} 完整目录路径
856
+ * @private
857
+ */
858
+ Drive.prototype._deteApiDir = function (dir, app, type, name) {
859
+ var l = $.slash;
860
+ var o = $.pool.api[app + '_' + type];
861
+ var api_dir;
862
+
863
+ if (o) {
864
+ api_dir = dir + l + 'api_' + app + '_' + type;
865
+ } else {
866
+ api_dir = dir + l + 'api_' + type;
867
+ }
868
+
869
+ this._ensureApiDir(api_dir);
870
+ api_dir += '/' + name;
871
+ this._ensureApiDir(api_dir);
872
+
873
+ return api_dir;
874
+ };
875
+
876
+ /**
877
+ * 更新API及相关配置文件
878
+ * @param {string} dir API存放目录
879
+ * @param {boolean} cover 是否覆盖文件
880
+ */
881
+ Drive.prototype.updateApi = async function (dir, cover) {
882
+ var cg = this.config;
883
+ var arr = cg.table.split('_');
884
+
885
+ var name = 'root';
886
+ if (arr.length > 1) {
887
+ name = cg.table.replace(arr[0], '').trim('_');
888
+ }
889
+ var app = arr[0];
890
+
891
+ var client = this._deteApiDir(dir, app, 'client', name);
892
+ var manage = this._deteApiDir(dir, app, 'manage', name);
893
+
894
+ this.newSql(client, manage, cover);
895
+ await this.newParam(client, manage, cover);
896
+ this.newApi(client, manage, cover);
897
+ };
898
+
899
+ /**
900
+ * 新建event配置文件和文件
901
+ * @param {string} dir 保存的路径
902
+ * @param {string} path 检索路径
903
+ * @param {string} scope 接口域
904
+ */
905
+ Drive.prototype.newEvent = async function (dir, path, scope) {
906
+ var f = dir + '/main.js';
907
+ if (!f.hasFile()) {
908
+ var code = (__dirname + '/event_script.js').loadText();
909
+ code = code.replaceAll('{0}', path).replaceAll('{1}', scope);
910
+ f.saveText(code);
911
+ }
912
+ };
913
+
914
+ /**
915
+ * 处理带逗号的列表映射
916
+ * @param {Array} list 列表
917
+ * @returns {Array} 处理后的列表
918
+ * @private
919
+ */
920
+ Drive.prototype._handleCommaList = function (list) {
921
+ return list.map((o) => {
922
+ var arr = o.split(',');
923
+ var value = arr[0];
924
+ if (arr.length > 0) {
925
+ return {
926
+ name: arr[1],
927
+ value: value
928
+ };
929
+ } else {
930
+ return {
931
+ name: value,
932
+ value
933
+ };
934
+ }
935
+ });
936
+ };
937
+
938
+ /**
939
+ * 处理数字列表映射
940
+ * @param {Array} list 列表
941
+ * @param {string} map 映射字符串
942
+ * @returns {Array} 处理后的列表
943
+ * @private
944
+ */
945
+ Drive.prototype._handleNumberList = function (list, map) {
946
+ if (map.indexOf('0') !== 0) {
947
+ list.unshift('');
948
+ }
949
+ return list.map((value) => {
950
+ return value.replace(/[0-9]+/, '');
951
+ });
952
+ };
953
+
954
+ /**
955
+ * 处理简单列表映射
956
+ * @param {Array} list 列表
957
+ * @returns {Array} 处理后的列表
958
+ * @private
959
+ */
960
+ Drive.prototype._handleSimpleList = function (list) {
961
+ return list.map((value) => {
962
+ return {
963
+ name: value,
964
+ value
965
+ };
966
+ });
967
+ };
968
+
969
+ /**
970
+ * 处理点分隔的映射
971
+ * @param {object} obj 字段对象
972
+ * @param {string} map 映射字符串
973
+ * @returns {object} 处理后的格式对象
974
+ * @private
975
+ */
976
+ Drive.prototype._handleDotMap = function (obj, map) {
977
+ var arr = map.split('.');
978
+ var format = {
979
+ table: arr[0],
980
+ name: arr[1]
981
+ };
982
+ if (arr.length > 2) {
983
+ format.id = arr[2];
984
+ } else {
985
+ format.id = obj.name;
986
+ }
987
+ return format;
988
+ };
989
+
990
+ /**
991
+ * 处理简单映射
992
+ * @param {object} obj 字段对象
993
+ * @param {string} map 映射字符串
994
+ * @returns {object} 处理后的格式对象
995
+ * @private
996
+ */
997
+ Drive.prototype._handleSimpleMap = function (obj, map) {
998
+ return {
999
+ table: map,
1000
+ id: obj.name,
1001
+ name: 'name'
1002
+ };
1003
+ };
1004
+
1005
+ /**
1006
+ * 获取格式
1007
+ * @param {object} obj 字段对象
1008
+ * @returns {object} 返回格式
1009
+ */
1010
+ Drive.prototype.getFormat = async function (obj) {
1011
+ var map = obj.map;
1012
+ var format = {
1013
+ key: obj.name,
1014
+ title: obj.title.replace('ID', '').replace('id', '')
1015
+ };
1016
+
1017
+ if (map.indexOf('|') !== -1) {
1018
+ var list = map.split('|');
1019
+ if (map.indexOf(',') !== -1) {
1020
+ format.list = this._handleCommaList(list);
1021
+ } else if (/^[0-9]+/.test(map)) {
1022
+ format.list = this._handleNumberList(list, map);
1023
+ } else {
1024
+ format.list = this._handleSimpleList(list);
1025
+ }
1026
+ } else {
1027
+ if (map.indexOf('.') !== -1) {
1028
+ Object.assign(format, this._handleDotMap(obj, map));
1029
+ } else {
1030
+ Object.assign(format, this._handleSimpleMap(obj, map));
1031
+ }
1032
+ }
1033
+
1034
+ return format;
1035
+ };
1036
+
1037
+ /**
1038
+ * 处理字段选择
1039
+ * @param {string} field_name 字段名
1040
+ * @param {string} field_type 字段类型
1041
+ * @returns {object} 处理结果
1042
+ * @private
1043
+ */
1044
+ Drive.prototype._procFieldSel = function (field_name, field_type) {
1045
+ var res = {
1046
+ field: '',
1047
+ field_obj: ''
1048
+ };
1049
+
1050
+ if (this.isCan(field_name, this.get_not, field_type)) {
1051
+ res.field += ',`' + field_name + '`';
1052
+ }
1053
+ if (this.isCan(field_name, this.getObj_not)) {
1054
+ res.field_obj += ',`' + field_name + '`';
1055
+ }
1056
+
1057
+ return res;
1058
+ };
1059
+
1060
+ /**
1061
+ * 处理字符串类型字段
1062
+ * @param {object} query 查询对象
1063
+ * @param {string} field_name 字段名
1064
+ * @param {string} keyword 关键词
1065
+ * @returns {string} 更新后的关键词
1066
+ * @private
1067
+ */
1068
+ Drive.prototype._procStringQuery = function (query, field_name, keyword) {
1069
+ var new_keyword = keyword;
1070
+ query[field_name] = '`' + field_name + "` like '%{0}%'";
1071
+ if (this.isSet(field_name, this.query_keyword)) {
1072
+ new_keyword += ' || `' + field_name + "` like '%{0}%'";
1073
+ }
1074
+ return new_keyword;
1075
+ };
1076
+
1077
+ /**
1078
+ * 处理日期时间类型字段
1079
+ * @param {object} query 查询对象
1080
+ * @param {string} field_name 字段名
1081
+ * @private
1082
+ */
1083
+ Drive.prototype._procDateTimeQuery = function (query, field_name) {
1084
+ query[field_name + '_min'] = '`' + field_name + "` >= '{0}'";
1085
+ query[field_name + '_max'] = '`' + field_name + "` <= '{0}'";
1086
+ };
1087
+
1088
+ /**
1089
+ * 处理数字类型字段
1090
+ * @param {object} query 查询对象
1091
+ * @param {object} update_obj 更新对象
1092
+ * @param {string} field_name 字段名
1093
+ * @param {string} uid 用户ID
1094
+ * @param {boolean} query_default_user 是否默认用户查询
1095
+ * @param {string} orderby 排序
1096
+ * @returns {object} 处理结果
1097
+ * @private
1098
+ */
1099
+ Drive.prototype._procNumberQuery = function (
1100
+ query, update_obj, field_name, uid, query_default_user, orderby
1101
+ ) {
1102
+ var res = {
1103
+ orderby: orderby,
1104
+ update: { ...update_obj }
1105
+ };
1106
+
1107
+ if (!field_name.end('id')) {
1108
+ query[field_name + '_min'] = '`' + field_name + '` >= {0}';
1109
+ query[field_name + '_max'] = '`' + field_name + '` <= {0}';
1110
+ res.update[field_name + '_add'] = '`' + field_name + '` = `' + field_name + '` + {0}';
1111
+
1112
+ if (field_name === 'sort' || field_name === 'display' || field_name === 'orderby') {
1113
+ res.orderby = '`' + field_name + '` asc';
1114
+ }
1115
+ } else if (field_name === uid && query_default_user) {
1116
+ res.query_default = '`' + field_name + '` = {' + uid + '}';
1117
+ } else if (field_name === 'available' || field_name === 'show') {
1118
+ res.query_default = '`' + field_name + '` = 1';
1119
+ }
1120
+
1121
+ return res;
1122
+ };
1123
+
1124
+ /**
1125
+ * 处理字段类型
1126
+ * @param {string} type 字段类型
1127
+ * @param {string} field_name 字段名
1128
+ * @param {object} query 查询对象
1129
+ * @param {object} update_obj 更新对象
1130
+ * @param {string} uid 用户ID
1131
+ * @param {boolean} query_default_user 是否默认用户查询
1132
+ * @param {string} orderby 排序
1133
+ * @param {string} keyword 关键词
1134
+ * @returns {object} 处理结果
1135
+ * @private
1136
+ */
1137
+ Drive.prototype._procFieldType = function (
1138
+ type, field_name, query, update_obj, uid, query_default_user, orderby, keyword
1139
+ ) {
1140
+ var result = {
1141
+ keyword: keyword,
1142
+ orderby: orderby,
1143
+ update_obj: update_obj,
1144
+ query_default: {}
1145
+ };
1146
+
1147
+ if (type === 'varchar' || type === 'text' || type === 'longtext') {
1148
+ result.keyword = this._procStringQuery(query, field_name, keyword);
1149
+ } else if (type === 'date' || type === 'time' || type === 'datetime' || type === 'timestamp') {
1150
+ this._procDateTimeQuery(query, field_name);
1151
+ } else if (type !== 'tinyint') {
1152
+ var num_res = this._procNumberQuery(
1153
+ query, update_obj, field_name, uid, query_default_user, orderby
1154
+ );
1155
+ result.orderby = num_res.orderby;
1156
+ result.update_obj = num_res.update;
1157
+ if (num_res.query_default) {
1158
+ result.query_default[field_name] = num_res.query_default;
1159
+ }
1160
+ }
1161
+
1162
+ return result;
1163
+ };
1164
+
1165
+ /**
1166
+ * 处理单个字段
1167
+ * @param {object} field 字段对象
1168
+ * @param {object} query 查询对象
1169
+ * @param {object} update_obj 更新对象
1170
+ * @param {string} uid 用户ID
1171
+ * @param {boolean} query_default_user 是否默认用户查询
1172
+ * @param {string} orderby 排序
1173
+ * @param {string} keyword 关键词
1174
+ * @returns {object} 处理结果
1175
+ * @private
1176
+ */
1177
+ Drive.prototype._procSingleField = async function (
1178
+ field, query, update_obj, uid, query_default_user, orderby, keyword
1179
+ ) {
1180
+ var o = field;
1181
+ var p = o.type;
1182
+ var n = o.name;
1183
+ var result = {
1184
+ field: '',
1185
+ field_obj: '',
1186
+ keyword: keyword,
1187
+ orderby: orderby,
1188
+ update_obj: update_obj,
1189
+ query_default: {},
1190
+ format: []
1191
+ };
1192
+
1193
+ var field_sel = this._procFieldSel(n, p);
1194
+ result.field = field_sel.field;
1195
+ result.field_obj = field_sel.field_obj;
1196
+
1197
+ var type_info = this._procFieldType(
1198
+ p, n, query, update_obj, uid, query_default_user, orderby, keyword
1199
+ );
1200
+ result.keyword = type_info.keyword;
1201
+ result.orderby = type_info.orderby;
1202
+ result.update_obj = type_info.update_obj;
1203
+ result.query_default = type_info.query_default;
1204
+
1205
+ if (o.map) {
1206
+ var fmt = await this.getFormat(o);
1207
+ if (fmt) {
1208
+ result.format.push(fmt);
1209
+ }
1210
+ }
1211
+
1212
+ return result;
1213
+ };
1214
+
1215
+ /**
1216
+ * 处理字段和查询条件
1217
+ * @param {Array} fields 字段列表
1218
+ * @param {string} table 表名
1219
+ * @returns {object} 处理结果
1220
+ * @private
1221
+ */
1222
+ Drive.prototype._procFields = async function (fields, table) {
1223
+ var query = {};
1224
+ var update_obj = {};
1225
+ var field = '';
1226
+ var field_obj = '';
1227
+ var query_default = {};
1228
+ var format = [];
1229
+ var orderby = '';
1230
+ var uid = $.dict.user_id;
1231
+ var keyword = '';
1232
+ var query_default_user = this.isSet(table, this.query_default_table);
1233
+
1234
+ for (var i = 0; i < fields.length; i++) {
1235
+ var field_info = await this._procSingleField(
1236
+ fields[i], query, update_obj, uid, query_default_user, orderby, keyword
1237
+ );
1238
+
1239
+ field += field_info.field;
1240
+ field_obj += field_info.field_obj;
1241
+ keyword = field_info.keyword;
1242
+ orderby = field_info.orderby;
1243
+ update_obj = field_info.update_obj;
1244
+
1245
+ // 合并查询默认值
1246
+ for (var key in field_info.query_default) {
1247
+ query_default[key] = field_info.query_default[key];
1248
+ }
1249
+
1250
+ // 合并格式
1251
+ format = format.concat(field_info.format);
1252
+ }
1253
+
1254
+ return {
1255
+ query,
1256
+ update: update_obj,
1257
+ field,
1258
+ field_obj,
1259
+ query_default,
1260
+ format,
1261
+ orderby,
1262
+ keyword
1263
+ };
1264
+ };
1265
+
1266
+ /**
1267
+ * 处理关键字搜索
1268
+ * @param {string} keyword 关键字
1269
+ * @param {string} table 表名
1270
+ * @returns {object} 处理后的查询对象
1271
+ * @private
1272
+ */
1273
+ Drive.prototype._procKeyword = function (keyword, table) {
1274
+ var new_keyword = keyword;
1275
+ if (table.indexOf('user_') !== -1) {
1276
+ new_keyword += ' || ' + keyword_default;
1277
+ }
1278
+
1279
+ var query = {};
1280
+ if (new_keyword) {
1281
+ query['keyword'] = '(' + new_keyword.replace(' || ', '') + ')';
1282
+ }
1283
+
1284
+ return query;
1285
+ };
1286
+
1287
+ /**
1288
+ * 创建基础模型
1289
+ * @param {object} cg 配置对象
1290
+ * @param {object} processed 处理结果
1291
+ * @param {object} keyword_query 关键字查询
1292
+ * @returns {object} 基础模型
1293
+ * @private
1294
+ */
1295
+ Drive.prototype._createBaseModel = function (cg, processed, keyword_query) {
1296
+ return {
1297
+ name: cg.table,
1298
+ title: cg.title,
1299
+ table: cg.table,
1300
+ key: cg.key,
1301
+ orderby_default: '`' + cg.key + '` desc',
1302
+ field_obj: processed.field_obj.replace(',', ''),
1303
+ field_default: processed.field.replace(',', ''),
1304
+ method: 'get get_obj avg sum count',
1305
+ query: { ...processed.query, ...keyword_query },
1306
+ query_default: processed.query_default,
1307
+ update: processed.update,
1308
+ format: processed.format
1309
+ };
1310
+ };
1311
+
1312
+ /**
1313
+ * 保存客户端配置
1314
+ * @param {string} client 客户端配置保存路径
1315
+ * @param {object} base_model 基础模型
1316
+ * @param {string} orderby 排序
1317
+ * @param {string} uid 用户ID
1318
+ * @param {string} table 表名
1319
+ * @param {boolean} cover 是否覆盖文件
1320
+ * @private
1321
+ */
1322
+ Drive.prototype._saveClientConfig = function (client, base_model, orderby, uid, table, cover) {
1323
+ var oj = { ...base_model };
1324
+ if (orderby) {
1325
+ oj.orderby_default = orderby;
1326
+ }
1327
+ if (oj.query_default[uid] && table.indexOf('user_') !== -1) {
1328
+ oj.filter = {
1329
+ 'table': 'table',
1330
+ 'page': 'page',
1331
+ 'size': 'size',
1332
+ 'method': 'method',
1333
+ 'orderby': 'orderby',
1334
+ 'field': 'field',
1335
+ 'count_ret': 'count_ret'
1336
+ };
1337
+ oj.filter[uid] = uid;
1338
+ }
1339
+ this.saveFile(client + '/sql.json', oj, cover);
1340
+ };
1341
+
1342
+ /**
1343
+ * 保存管理端配置
1344
+ * @param {string} manage 管理端配置保存路径
1345
+ * @param {object} base_model 基础模型
1346
+ * @param {boolean} cover 是否覆盖文件
1347
+ * @private
1348
+ */
1349
+ Drive.prototype._saveManageConfig = function (manage, base_model, cover) {
1350
+ var m = { ...base_model };
1351
+ delete m.method;
1352
+ m.field_hide = [];
1353
+ m.name += 2;
1354
+ m.field_obj = m.field_obj.replace(',`time_create`', '').replace(',`time_update`', '')
1355
+ .replace(',`create_time`', '').replace(',`update_time`', '');
1356
+ delete m.query_default;
1357
+ this.saveFile(manage + '/sql.json', m, cover);
1358
+ };
1359
+
1360
+ /**
1361
+ * 新建sql配置文件
1362
+ * @param {string} client 客户端配置保存路径
1363
+ * @param {string} manage 管理端配置保存路径
1364
+ * @param {boolean} cover 是否覆盖文件
1365
+ */
1366
+ Drive.prototype.newSql = async function (client, manage, cover) {
1367
+ var cg = this.config;
1368
+ var uid = $.dict.user_id;
1369
+
1370
+ var processed = await this._procFields(cg.fields, cg.table);
1371
+ var keyword_query = this._procKeyword(processed.keyword, cg.table);
1372
+ var base_model = this._createBaseModel(cg, processed, keyword_query);
1373
+
1374
+ if (client) {
1375
+ this._saveClientConfig(client, base_model, processed.orderby, uid, cg.table, cover);
1376
+ }
1377
+
1378
+ if (manage) {
1379
+ this._saveManageConfig(manage, base_model, cover);
1380
+ }
1381
+ };
1382
+
1383
+ /**
1384
+ * 保存sql配置
1385
+ * @param {string} file 文件名
1386
+ * @param {object} model 配置模型
1387
+ * @param {boolean} cover 是否覆盖文件
1388
+ */
1389
+ Drive.prototype.saveFile = function (file, model, cover) {
1390
+ if (!file.hasFile()) {
1391
+ file.saveText(JSON.stringify(model, null, 4));
1392
+ } else if (cover) {
1393
+ var jobj = file.loadJson();
1394
+ for (var k in model) {
1395
+ var val = model[k];
1396
+ if (!val) {
1397
+ model[k] = jobj[k];
1398
+ }
1399
+ }
1400
+ $.push(jobj, model, true);
1401
+ file.saveText(JSON.stringify(jobj, null, 4));
1402
+ }
1403
+ };
1404
+
1405
+ /**
1406
+ * 新建param配置文件
1407
+ * @param {string} client 客户端配置保存路径
1408
+ * @param {string} manage 管理端配置保存路径
1409
+ * @param {boolean} cover 是否覆盖文件
1410
+ */
1411
+ Drive.prototype.new = async function (client, manage, cover) {
1412
+ var cg = this.config;
1413
+ var lt = cg.fields;
1414
+ var cm = this._initParamConfig(cg);
1415
+ var keyword = '';
1416
+
1417
+ for (var i = 0; i < lt.length; i++) {
1418
+ var o = lt[i];
1419
+ var p = o.type;
1420
+ var n = o.name;
1421
+ var m = this._createBaseModel(o, p, n);
1422
+
1423
+ if (this._isStringType(p)) {
1424
+ keyword = this._processStringField(cm, m, o, n, keyword);
1425
+ } else if (this._isDateTimeType(p)) {
1426
+ this._processDateTimeField(cm, m, o, n);
1427
+ } else {
1428
+ this._processNumberField(cm, m, o, n, cg);
1429
+ }
1430
+ }
1431
+
1432
+ this._addKeywordConfig(cm, keyword, cg);
1433
+ this._saveParamFiles(cm, client, manage, cover);
1434
+ };
1435
+
1436
+ /**
1437
+ * 初始化参数配置对象
1438
+ * @param {object} cg 配置对象
1439
+ * @returns {object} 参数配置对象
1440
+ * @private
1441
+ */
1442
+ Drive.prototype._initParamConfig = function (cg) {
1443
+ return {
1444
+ name: cg.table,
1445
+ title: cg.title,
1446
+ add: {
1447
+ body: [],
1448
+ body_required: []
1449
+ },
1450
+ del: {
1451
+ query: [],
1452
+ query_required: []
1453
+ },
1454
+ set: {
1455
+ query: [],
1456
+ query_required: [],
1457
+ body: [],
1458
+ body_required: [],
1459
+ body_not: []
1460
+ },
1461
+ get: {
1462
+ query: [],
1463
+ query_required: []
1464
+ },
1465
+ get_obj: {
1466
+ query_required: []
1467
+ },
1468
+ list: []
1469
+ };
1470
+ };
1471
+
1472
+ /**
1473
+ * 创建基础模型
1474
+ * @param {object} field 字段对象
1475
+ * @param {string} type 字段类型
1476
+ * @param {string} name 字段名
1477
+ * @returns {object} 基础模型对象
1478
+ * @private
1479
+ */
1480
+ Drive.prototype._createBaseModel = function (field, type, name) {
1481
+ return {
1482
+ name: name,
1483
+ title: field.title,
1484
+ description: field.description + (field.map ? '(' + field.map + ')' : ''),
1485
+ key: field.pk,
1486
+ type: '',
1487
+ dataType: type
1488
+ };
1489
+ };
1490
+
1491
+ /**
1492
+ * 检查是否为字符串类型
1493
+ * @param {string} type 字段类型
1494
+ * @returns {boolean} 是否为字符串类型
1495
+ * @private
1496
+ */
1497
+ Drive.prototype._isStringType = function (type) {
1498
+ return type === 'varchar' || type === 'text' || type === 'longtext';
1499
+ };
1500
+
1501
+ /**
1502
+ * 检查是否为日期时间类型
1503
+ * @param {string} type 字段类型
1504
+ * @returns {boolean} 是否为日期时间类型
1505
+ * @private
1506
+ */
1507
+ Drive.prototype._isDateTimeType = function (type) {
1508
+ return type === 'date' || type === 'time' || type === 'datetime' || type === 'timestamp';
1509
+ };
1510
+
1511
+ /**
1512
+ * 处理字符串类型字段
1513
+ * @param {object} cm 参数配置对象
1514
+ * @param {object} m 模型对象
1515
+ * @param {object} o 字段对象
1516
+ * @param {string} n 字段名
1517
+ * @param {string} keyword 关键词
1518
+ * @returns {string} 更新后的关键词
1519
+ * @private
1520
+ */
1521
+ Drive.prototype._processStringField = function (cm, m, o, n, keyword) {
1522
+ var new_keyword = keyword;
1523
+ m.type = 'string';
1524
+ m.default = o.default;
1525
+ m.string = {};
1526
+
1527
+ this._addStringRange(m, o);
1528
+ this._addStringFormat(m, n);
1529
+
1530
+ if (o.not_null) {
1531
+ m.string.not_empty = !!o.not_null;
1532
+ cm.add.body_required.push(n);
1533
+ } else {
1534
+ cm.add.body.push(n);
1535
+ }
1536
+
1537
+ if (this.isSet(n, this.query_string)) {
1538
+ cm.get.query.push(n);
1539
+ cm.set.query.push(n);
1540
+ new_keyword += '、' + o.title + '(' + n + ')';
1541
+ }
1542
+
1543
+ cm.set.body.push(n);
1544
+ cm.list.push(m);
1545
+ return new_keyword;
1546
+ };
1547
+
1548
+ /**
1549
+ * 添加字符串范围验证
1550
+ * @param {object} m 模型对象
1551
+ * @param {object} o 字段对象
1552
+ * @private
1553
+ */
1554
+ Drive.prototype._addStringRange = function (m, o) {
1555
+ var range = (o.min_length && o.max_length) ? [o.min_length, o.max_length] : [];
1556
+ if (range.length > 0) {
1557
+ m.string.range = range;
1558
+ } else if (o.min_length) {
1559
+ m.string.min = o.min_length;
1560
+ } else if (o.max_length) {
1561
+ m.string.max = o.max_length;
1562
+ }
1563
+ };
1564
+
1565
+ /**
1566
+ * 检查字段名是否包含指定关键词
1567
+ * @param {string} field_name 字段名
1568
+ * @param {string} keyword 关键词
1569
+ * @returns {boolean} 是否包含
1570
+ * @private
1571
+ */
1572
+ Drive.prototype._hasKeyword = function (field_name, keyword) {
1573
+ return field_name.has(keyword);
1574
+ };
1575
+
1576
+ /**
1577
+ * 检查字段名是否等于指定值
1578
+ * @param {string} field_name 字段名
1579
+ * @param {Array} values 值数组
1580
+ * @returns {boolean} 是否等于
1581
+ * @private
1582
+ */
1583
+ Drive.prototype._isEqual = function (field_name, values) {
1584
+ return values.includes(field_name);
1585
+ };
1586
+
1587
+ /**
1588
+ * 添加字符串格式验证
1589
+ * @param {object} m 模型对象
1590
+ * @param {string} n 字段名
1591
+ * @private
1592
+ */
1593
+ Drive.prototype._addStringFormat = function (m, n) {
1594
+ if (this._hasKeyword(n, 'phone') || this._isEqual(n, ['tel'])) {
1595
+ m.string.format = 'phone';
1596
+ } else if (this._hasKeyword(n, 'url') || this._isEqual(n, ['src', 'source'])) {
1597
+ m.string.format = 'url';
1598
+ } else if (this._hasKeyword(n, 'date')) {
1599
+ m.string.format = 'date';
1600
+ } else if (this._isEqual(n, ['num', 'number', 'count'])) {
1601
+ m.string.format = 'digits';
1602
+ } else if (this._isEqual(n, ['money', 'coin'])) {
1603
+ m.string.format = 'number';
1604
+ } else if (this._hasKeyword(n, 'email')) {
1605
+ m.string.format = 'email';
1606
+ }
1607
+ };
1608
+
1609
+ /**
1610
+ * 处理日期时间类型字段
1611
+ * @param {object} cm 参数配置对象
1612
+ * @param {object} m 模型对象
1613
+ * @param {object} o 字段对象
1614
+ * @param {string} n 字段名
1615
+ * @private
1616
+ */
1617
+ Drive.prototype._processDateTimeField = function (cm, m, o, n) {
1618
+ var format = (o.type === 'timestamp') ? 'datetime' : o.type;
1619
+ m.type = 'string';
1620
+ m.default = '';
1621
+ m.string = {
1622
+ not_empty: true,
1623
+ format: format
1624
+ };
1625
+
1626
+ cm.list.push(m);
1627
+ this._addDateTimeRange(cm, m, n);
1628
+
1629
+ if (n.indexOf('create') !== -1 && n.indexOf('update') !== -1) {
1630
+ cm.add.body.push(n);
1631
+ cm.set.body.push(n);
1632
+ }
1633
+
1634
+ cm.get.query.push(n + '_min');
1635
+ cm.get.query.push(n + '_max');
1636
+ };
1637
+
1638
+ /**
1639
+ * 添加日期时间范围模型
1640
+ * @param {object} cm 参数配置对象
1641
+ * @param {object} m 模型对象
1642
+ * @param {string} n 字段名
1643
+ * @private
1644
+ */
1645
+ Drive.prototype._addDateTimeRange = function (cm, m, n) {
1646
+ var m_min = { ...m };
1647
+ m_min.name = n + '_min';
1648
+ m_min.title += '——开始时间';
1649
+ cm.list.push(m_min);
1650
+
1651
+ var m_max = { ...m };
1652
+ m_max.name = n + '_max';
1653
+ m_max.title += '——结束时间';
1654
+ cm.list.push(m_max);
1655
+ };
1656
+
1657
+ /**
1658
+ * 处理数字类型字段
1659
+ * @param {object} cm 参数配置对象
1660
+ * @param {object} m 模型对象
1661
+ * @param {object} o 字段对象
1662
+ * @param {string} n 字段名
1663
+ * @param {object} cg 配置对象
1664
+ * @private
1665
+ */
1666
+ Drive.prototype._processNumberField = function (cm, m, o, n, cg) {
1667
+ m.type = 'number';
1668
+ m.default = number(o.default) + '';
1669
+ m.number = {};
1670
+
1671
+ this._addNumberRange(m, o);
1672
+
1673
+ if (o.name === cg.key) {
1674
+ this._processPrimaryKey(cm, m, n);
1675
+ } else {
1676
+ this._processNonPrimaryKey(cm, m, n);
1677
+ }
1678
+ };
1679
+
1680
+ /**
1681
+ * 添加数字范围验证
1682
+ * @param {object} m 模型对象
1683
+ * @param {object} o 字段对象
1684
+ * @private
1685
+ */
1686
+ Drive.prototype._addNumberRange = function (m, o) {
1687
+ var range = (o.min && o.max) ? [o.min, o.max] : [];
1688
+ if (range.length > 0) {
1689
+ m.number.range = range;
1690
+ } else if (o.min) {
1691
+ m.number.min = o.min;
1692
+ } else if (o.max) {
1693
+ m.number.max = o.max;
1694
+ }
1695
+ };
1696
+
1697
+ /**
1698
+ * 处理主键字段
1699
+ * @param {object} cm 参数配置对象
1700
+ * @param {object} m 模型对象
1701
+ * @param {string} n 字段名
1702
+ * @private
1703
+ */
1704
+ Drive.prototype._processPrimaryKey = function (cm, m, n) {
1705
+ cm.del.query_required.push(n);
1706
+ cm.set.query.push(n);
1707
+ cm.get.query.push(n);
1708
+ cm.get_obj.query_required.push(n);
1709
+ cm.list.push(m);
1710
+ };
1711
+
1712
+ /**
1713
+ * 处理非主键字段
1714
+ * @param {object} cm 参数配置对象
1715
+ * @param {object} m 模型对象
1716
+ * @param {string} n 字段名
1717
+ * @private
1718
+ */
1719
+ Drive.prototype._processNonPrimaryKey = function (cm, m, n) {
1720
+ cm.add.body.push(n);
1721
+ cm.set.body.push(n);
1722
+ cm.list.push(m);
1723
+
1724
+ if (m.dataType !== 'tinyint') {
1725
+ this._processNonTinyInt(cm, m, n);
1726
+ } else {
1727
+ cm.set.query.push(n);
1728
+ cm.get.query.push(n);
1729
+ }
1730
+ };
1731
+
1732
+ /**
1733
+ * 处理非tinyint字段
1734
+ * @param {object} cm 参数配置对象
1735
+ * @param {object} m 模型对象
1736
+ * @param {string} n 字段名
1737
+ * @private
1738
+ */
1739
+ Drive.prototype._processNonTinyInt = function (cm, m, n) {
1740
+ var ne = n;
1741
+ if (!ne.end('id')) {
1742
+ this._addNumberRangeFields(cm, m, n);
1743
+ } else {
1744
+ cm.get.query.push(n);
1745
+ if (this.isSet(n, this.query_number)) {
1746
+ cm.set.query.push(n);
1747
+ }
1748
+ }
1749
+ };
1750
+
1751
+ /**
1752
+ * 添加数字范围字段
1753
+ * @param {object} cm 参数配置对象
1754
+ * @param {object} m 模型对象
1755
+ * @param {string} n 字段名
1756
+ * @private
1757
+ */
1758
+ Drive.prototype._addNumberRangeFields = function (cm, m, n) {
1759
+ cm.get.query.push(n + '_min');
1760
+ cm.get.query.push(n + '_max');
1761
+ cm.set.query.push(n + '_min');
1762
+ cm.set.query.push(n + '_max');
1763
+ cm.set.body.push(n + '_add');
1764
+
1765
+ var m_min = { ...m };
1766
+ m_min.name = n + '_min';
1767
+ m_min.title += '——最小值';
1768
+ cm.list.push(m_min);
1769
+
1770
+ var m_max = { ...m };
1771
+ m_max.name = n + '_max';
1772
+ m_max.title += '——最大值';
1773
+ cm.list.push(m_max);
1774
+ };
1775
+
1776
+ /**
1777
+ * 添加关键词配置
1778
+ * @param {object} cm 参数配置对象
1779
+ * @param {string} keyword 关键词
1780
+ * @param {object} cg 配置对象
1781
+ * @private
1782
+ */
1783
+ Drive.prototype._addKeywordConfig = function (cm, keyword, cg) {
1784
+ if (keyword) {
1785
+ cm.get.query.push('keyword');
1786
+ cm.set.query.push('keyword');
1787
+ var new_keyword = keyword;
1788
+ if (cg.table.indexOf('user_') !== -1) {
1789
+ new_keyword += '、' + keyword_default_tip;
1790
+ }
1791
+ var m_k = {
1792
+ name: 'keyword',
1793
+ title: '关键词',
1794
+ description: '用于搜索' + new_keyword.replace('、', ''),
1795
+ type: 'string',
1796
+ string: {}
1797
+ };
1798
+ cm.list.push(m_k);
1799
+ }
1800
+ };
1801
+
1802
+ /**
1803
+ * 保存参数配置文件
1804
+ * @param {object} cm 参数配置对象
1805
+ * @param {string} client 客户端配置保存路径
1806
+ * @param {string} manage 管理端配置保存路径
1807
+ * @param {boolean} cover 是否覆盖文件
1808
+ * @private
1809
+ */
1810
+ Drive.prototype._saveParamFiles = function (cm, client, manage, cover) {
1811
+ if (client) {
1812
+ this.saveFile(client + '/param.json', cm, cover);
1813
+ }
1814
+ if (manage) {
1815
+ var manage_cm = { ...cm };
1816
+ delete manage_cm.method;
1817
+ manage_cm.name += 2;
1818
+ this.saveFile(manage + '/param.json', manage_cm, cover);
1819
+ }
1820
+ };
1821
+
1822
+ /**
1823
+ * 是否设置
1824
+ * @param {string} name 名称
1825
+ * @param {Array} arr 匹配的对象
1826
+ * @returns {boolean} 是否设置
1827
+ */
1828
+ Drive.prototype.isSet = function (name, arr) {
1829
+ var bl = false;
1830
+ for (var i = 0; i < arr.length; i++) {
1831
+ if (name.indexOf(arr[i]) !== -1) {
1832
+ bl = true;
1833
+ break;
1834
+ }
1835
+ }
1836
+ return bl;
1837
+ };
1838
+
1839
+ /**
1840
+ * 是否排除
1841
+ * @param {string} name 名称
1842
+ * @param {Array} arr 匹配的对象
1843
+ * @param {string} type 数据类型
1844
+ * @returns {boolean} 是否可以
1845
+ */
1846
+ Drive.prototype.isCan = function (name, arr, type) {
1847
+ if (type === 'longtext') {
1848
+ return false;
1849
+ }
1850
+ var bl = false;
1851
+ for (var i = 0; i < arr.length; i++) {
1852
+ if (name.indexOf(arr[i]) !== -1) {
1853
+ bl = true;
1854
+ break;
1855
+ }
1856
+ }
1857
+ return !bl;
1858
+ };
1859
+
1860
+
1861
+ /**
1862
+ * 确定API路径
1863
+ * @param {object} cg 配置对象
1864
+ * @returns {string} API路径
1865
+ * @private
1866
+ */
1867
+ Drive.prototype._deteApiPath = function (cg) {
1868
+ var arr = cg.table.split('_');
1869
+ var p = '/api/';
1870
+ if (arr.length > 1) {
1871
+ p += cg.table.replace('_', '/');
1872
+ } else {
1873
+ p += arr[0];
1874
+ }
1875
+ return p;
1876
+ };
1877
+
1878
+ /**
1879
+ * 创建基础API配置
1880
+ * @param {object} cg 配置对象
1881
+ * @param {string} path API路径
1882
+ * @returns {object} 基础API配置
1883
+ * @private
1884
+ */
1885
+ Drive.prototype._createBaseApiConfig = function (cg, path) {
1886
+ return {
1887
+ 'name': cg.table,
1888
+ 'title': cg.title,
1889
+ 'description': cg.description,
1890
+ 'path': path,
1891
+ 'method': 'ALL',
1892
+ 'cache': 0,
1893
+ 'client_cache': false,
1894
+ 'param_path': './param.json',
1895
+ 'sql_path': './sql.json',
1896
+ 'check_param': true
1897
+ };
1898
+ };
1899
+
1900
+ /**
1901
+ * 检查是否包含用户ID字段
1902
+ * @param {Array} fields 字段列表
1903
+ * @returns {boolean} 是否包含用户ID字段
1904
+ * @private
1905
+ */
1906
+ Drive.prototype._hasUserIdField = function (fields) {
1907
+ for (var i = 0, item; item = fields[i++];) {
1908
+ var name = item.name;
1909
+ if (name == $.dict.user_id || name === 'uid' || name === 'user_id' || name === 'userid') {
1910
+ return true;
1911
+ }
1912
+ }
1913
+ return false;
1914
+ };
1915
+
1916
+ /**
1917
+ * 保存客户端API配置
1918
+ * @param {string} client 客户端配置保存路径
1919
+ * @param {object} base_config 基础配置
1920
+ * @param {object} cg 配置对象
1921
+ * @param {boolean} cover 是否覆盖文件
1922
+ * @private
1923
+ */
1924
+ Drive.prototype._saveClientApiConfig = function (client, base_config, cg, cover) {
1925
+ var o = { ...base_config };
1926
+
1927
+ if (cg.title.indexOf('user') !== -1) {
1928
+ if (this._hasUserIdField(cg.fields)) {
1929
+ o.oauth = {
1930
+ 'scope': true,
1931
+ 'sign_in': true,
1932
+ 'vip': 0,
1933
+ 'user_group': []
1934
+ };
1935
+ }
1936
+ }
1937
+ o.method = 'GET';
1938
+ this.saveFile(client + '/api.json', o, cover);
1939
+ };
1940
+
1941
+ /**
1942
+ * 保存管理端API配置
1943
+ * @param {string} manage 管理端配置保存路径
1944
+ * @param {object} base_config 基础配置
1945
+ * @param {boolean} cover 是否覆盖文件
1946
+ * @private
1947
+ */
1948
+ Drive.prototype._saveManageApiConfig = function (manage, base_config, cover) {
1949
+ var o = { ...base_config };
1950
+ o.oauth = {
1951
+ 'scope': true,
1952
+ 'sign_in': true,
1953
+ 'gm': 2,
1954
+ 'user_admin': []
1955
+ };
1956
+ o.path = o.path.replace('/api/', '/apis/');
1957
+ o.name += '_manage';
1958
+ this.saveFile(manage + '/api.json', o, cover);
1959
+ };
1960
+
1961
+ /**
1962
+ * 新建api配置文件
1963
+ * @param {string} client 客户端配置保存路径
1964
+ * @param {string} manage 管理端配置保存路径
1965
+ * @param {boolean} cover 是否覆盖文件
1966
+ */
1967
+ Drive.prototype.newApi = async function (client, manage, cover) {
1968
+ var cg = this.config;
1969
+ var path = this._deteApiPath(cg);
1970
+ var base_config = this._createBaseApiConfig(cg, path);
1971
+
1972
+ if (client) {
1973
+ this._saveClientApiConfig(client, base_config, cg, cover);
1974
+ }
1975
+
1976
+ if (manage) {
1977
+ this._saveManageApiConfig(manage, base_config, cover);
1978
+ }
1979
+ };
1980
+
1981
+ /**
1982
+ * 获取模型
1983
+ * @param {string} type 模型类型
1984
+ * @returns {object} 返回获取到的模型
1985
+ */
1986
+ Drive.prototype.getModel = function (type) {
1987
+ let model = { ...this.config };
1988
+ let dir = this._getDir();
1989
+ let l = $.slash;
1990
+ let app_name = dir.between('app' + l, l);
1991
+ let plugin_name = dir.between('plugin' + l, l);
1992
+ let name = dir.basename();
1993
+ model.app = app_name;
1994
+ model.plugin = plugin_name;
1995
+ model.name = model.name || name;
1996
+ return model;
1997
+ };
1998
+
1999
+ module.exports = Drive;