├── .air.conf ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── go.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── apis ├── dashboard │ └── dashboard.go ├── log │ └── loginLog.go ├── monitor │ └── server.go ├── process │ ├── classify.go │ ├── process.go │ ├── task.go │ ├── tpl.go │ └── workOrder.go ├── public │ └── file.go ├── system │ ├── captcha.go │ ├── dept.go │ ├── index.go │ ├── info.go │ ├── menu.go │ ├── post.go │ ├── role.go │ ├── rolemenu.go │ ├── settings.go │ └── sysuser.go └── tpl │ └── tpl.go ├── build.sh ├── cmd ├── api │ └── server.go ├── cobra.go └── migrate │ └── server.go ├── config ├── db.sql ├── ferry.sql ├── rbac_model.conf ├── settings.dev.yml └── settings.yml ├── database ├── initialize.go ├── interface.go └── mysql.go ├── deploy ├── deploy.md ├── helm │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ │ ├── NOTES.txt │ │ ├── _helpers.tpl │ │ ├── configmap.yaml │ │ ├── deployment.yaml │ │ ├── mysql │ │ │ ├── persistentvolumeclaim.yaml │ │ │ ├── service.yaml │ │ │ ├── sql │ │ │ │ ├── db.sql │ │ │ │ └── ferry.sql │ │ │ └── statefulset.yaml │ │ ├── persistentvolumeclaim.yaml │ │ ├── redis │ │ │ ├── deployment.yaml │ │ │ ├── persistentvolumeclaim.yaml │ │ │ └── service.yaml │ │ ├── secret.yaml │ │ └── service.yaml │ └── values.yaml └── kubernetes │ ├── config.yaml │ ├── deploy.yaml │ ├── mysql.yaml │ ├── redis.yaml │ ├── secret.yaml │ └── sql │ ├── db.sql │ └── ferry.sql ├── docker-compose.yml ├── docker └── entrypoint.sh ├── global └── orm │ └── db.go ├── go.mod ├── go.sum ├── handler ├── auth.go ├── httpshandler.go └── ping.go ├── main.go ├── middleware ├── auth.go ├── customerror.go ├── header.go ├── init.go ├── logger.go ├── permission.go └── requestid.go ├── models ├── base │ └── base.go ├── gorm │ └── gorm.go ├── process │ ├── circulationHistory.go │ ├── classify.go │ ├── history.go │ ├── process.go │ ├── task.go │ ├── tpl.go │ ├── tplData.go │ └── workOrder.go └── system │ ├── casbinrule.go │ ├── dept.go │ ├── initdb.go │ ├── login.go │ ├── loginlog.go │ ├── menu.go │ ├── model.go │ ├── post.go │ ├── role.go │ ├── roledept.go │ ├── rolemenu.go │ ├── settings.go │ └── sysuser.go ├── pkg ├── casbin │ └── mycasbin.go ├── jsonTime │ └── JSONTime.go ├── jwtauth │ └── jwtauth.go ├── ldap │ ├── connection.go │ ├── ldapFieldsMap.go │ ├── login.go │ ├── search.go │ └── updatePwd.go ├── logger │ └── logger.go ├── notify │ ├── dingtalk │ │ └── dingtalk.go │ ├── email │ │ └── email.go │ └── send.go ├── pagination │ ├── pagination.go │ └── params.go ├── service │ ├── createWorkOrder.go │ ├── dashboard.go │ ├── getPrincipal.go │ ├── getState.go │ ├── getVariableValue.go │ ├── handle.go │ ├── process.go │ ├── task.go │ ├── userAuthority.go │ └── workOrderList.go ├── settings │ └── get_content.go ├── task │ ├── send.go │ ├── server.go │ └── worker │ │ ├── tasks.go │ │ └── worker.go └── utils │ └── file.go ├── router ├── dashboard │ └── dashboard.go ├── init_router.go ├── process │ ├── classify.go │ ├── process.go │ ├── task.go │ ├── tpl.go │ └── workOrder.go ├── router.go └── system │ └── sys_router.go ├── static ├── scripts │ ├── echo_test-4171bc7f4a05-admin.sh │ └── print_hello_world-d266ee2a8029-admin.py ├── template │ └── email.html └── web │ ├── 00280aae09f2a71c1ab46c7cfb9f491c.js │ ├── 02703e133100c3be64cfec414d4db706.js │ ├── 03276b6288c255cf1682f53ec11bb5a2.js │ ├── 036680d9c1d332cf478c5823cd2a47db.js │ ├── 0536af8c74f6fdf2d45e5e8990ee60cc.js │ ├── 06d453ace473034cd357edb758d539ab.js │ ├── 0768225f873adf5f103dcb714f17783d.js │ ├── 07c0a60b390501dfbb57219d5c8fbc1a.js │ ├── 07c26a67fe6aa27f701c6fb03a7bbafd.js │ ├── 0870bcf868f8d64dc9a6226a6c8b341d.js │ ├── 09195a75bcf8a7ac579281ac2ed5954a.js │ ├── 0a4b12234fd7cba4d7c62207e4835f4c.js │ ├── 0a5adf8110dfa37b8a75edf8cafb1dd7.js │ ├── 0ab67a107deacf1d9b22eb0b706486db.js │ ├── 0b56e82ae05b7ec2022e1cb35b8b6e10.js │ ├── 0bd6d25a3183a767309cd45cd8b8f347.js │ ├── 0c125a87d8efb9ce303b6b91783eb165.js │ ├── 0c2b3b3b66a73e289e2ca47cf22ef150.js │ ├── 0cab51dee983721ec757e7e209a67c1d.js │ ├── 0cbaf3ecc6b20dbc83c2164e9a1eac02.js │ ├── 0dc486b4415f7cbd7ddde8f32b6f12f1.js │ ├── 0dd0f45c3dde9af3fcf9706e6a2a1edd.js │ ├── 0e7164b2216605b024f4dc8d910ac5e8.js │ ├── 0ebc6c9681e409f2bf3bb6d8ce64e28e.js │ ├── 100f9b1846c1e1ecae19e0ca2fc8224c.js │ ├── 1084edaced97872890c9d87a9944cdcd.js │ ├── 10bc79414b62df132421027bbf5e5c3e.js │ ├── 117389396b5ae8131c2a299bfc802c7a.js │ ├── 119d8ff08e82b0f391f59f1fe657130f.js │ ├── 1295d4470d348d3ff8ea442b1dcef3d3.js │ ├── 1365ff3d277ebdab408e6aeec886cf08.js │ ├── 13b157cfddcb9a76ae0800b47a8f0122.js │ ├── 142d258626093a8c3187029538e32bbc.js │ ├── 144991c48dbba89bfe10e886aaaed32a.js │ ├── 155500be4d3113e94dca99f997defb7a.js │ ├── 1570e695c448e6a4f3a6bdf0372b58f0.js │ ├── 15abe309c5ecbc579dccc79beb041fd8.js │ ├── 167a62ec377adafbeb4bbb1cef73250d.js │ ├── 17c85759d562794da4d2ff11f1b9b3bd.js │ ├── 1840080076c4078d157a5b05d0d95551.js │ ├── 18a893070398343ab529fdb7b62f1b6d.js │ ├── 19573d26f286762809b86f935516c1ac.js │ ├── 19a2b55271f405d0b97fad53c9d5ec2d.js │ ├── 1afbeca385b131cfc3ae515b89e552c7.js │ ├── 1afe87852eca4b28294075c659ff8c45.js │ ├── 1c9874850164cfdaa7e1d212d09124a7.js │ ├── 1cb8df3a3416707163473b1ee9268faf.js │ ├── 1d837e2c9de35cbb09a85208da4a0d8a.js │ ├── 1e33cb44dfab039b4a7e88a3ee1bbfe7.js │ ├── 1f03c9a69a8b9f79bcb7a338963f80c8.js │ ├── 1f1abd5e247cf6b2e9a3db6303277572.js │ ├── 2031467f3d02be43b638c5e3ccba3996.js │ ├── 20642f73792092d3c71a4f1f4290430b.js │ ├── 20f8061729d26f9786679bbf7af0b87a.js │ ├── 214a729dcea91ee8a56f8ef43e17243a.js │ ├── 21dca974f7343f200597e43a55766c6e.js │ ├── 21fab653998af15bced8d4890e41bebc.js │ ├── 2208705283adad817bb4a5af647f77ab.js │ ├── 223593fe8dd78b83f22808f9aad86ae9.js │ ├── 22812e27a1f54c0a4ff744a444a32d6c.js │ ├── 22b1c8bf4c2bdd7e438f832b888c75e4.js │ ├── 22d4f336d4fbe548273812e6e4cd345e.js │ ├── 242fb5a92733d151e9ca303fcd3ae7ff.js │ ├── 243d8101969c933d25388b5287bb3425.js │ ├── 2487e54390024553d757b9bd73dd1647.js │ ├── 2681042a598b029b51d51f7669b81c4d.js │ ├── 280ba139ff95428f262adbf81b77aeb4.js │ ├── 2839e845bd0cf60f35f3a8ca90a5ee22.js │ ├── 28f7c5b28bbad7b0bac0cc3cc5b89bad.js │ ├── 294fbc5b00264d6215dd8ff838dc2999.js │ ├── 29a4e3548d286388c4d5e8f0670a4381.js │ ├── 2a7b2ac7dc47105609001b93c25190b8.js │ ├── 2ac58492ad5a1b5244deb0fef1e5a773.js │ ├── 2bba99eb717e1aa22e45284a964ca73f.js │ ├── 2dea096a03cd8f864db5f06e9f0113e5.js │ ├── 2f6f1f6753d430190cb38411a9112f08.js │ ├── 2fe13737434324ed67582ac97d484c54.js │ ├── 30314e1b4a51b1aed3766eadecde2a42.js │ ├── 3045404d52d03253c81822bdf760cfd1.js │ ├── 30f5b57295dfda4eafc7f8c098160582.js │ ├── 31459a657ac30dcaa54765c6d76d8c81.js │ ├── 318f90759f2ff0d2a437350e87578172.js │ ├── 31bcb02e59d84ce2e38b85616a0b44db.js │ ├── 31f3f1c32b27587832d28b634351325c.js │ ├── 330543be2120b9dcc9bec41ba5e05805.js │ ├── 34f05dc84111ffe37a1d5b5aacff7488.js │ ├── 35858a47038a7be957df49854e8e5eea.js │ ├── 35dc4119f9e28cb9baba1475537460bb.js │ ├── 37bc2ca46b9a9d40678a3cd05d50e397.js │ ├── 37e37aa178d97ffcd94eeee1e1a25967.js │ ├── 37f7ac1ef289fe8cd4f522a14df1f007.js │ ├── 38528de2a5c097da375fd0a076667441.js │ ├── 38a696bcfe6021b6442e70b6d3017b93.js │ ├── 3a9544afd4e48fd7c2ad5839ea48beb6.js │ ├── 3a969f15f742add3d383e55d0ceb3d25.js │ ├── 3b5b61cdd5efaaa85816fbf4ac68207e.js │ ├── 3baeab62d681338ba3287f0a50e5dad1.js │ ├── 3c0ec12aff6e148d235875bfed4ca421.js │ ├── 3c58f68d787710c79906a2cd6d248295.js │ ├── 3cab7110c6a090f72c540dcc1cfbe3b5.js │ ├── 3cce0c7e1a8e1148f97de59a4b1ee73f.js │ ├── 3cd86defa6e36c165ae673afab6b5eab.js │ ├── 3cf64ec91a700bfa1dece0957c49c7dc.js │ ├── 3e6808cd6eefd1be1040403985581374.js │ ├── 3e6cde7f6a3d84c5cff5127be1c019f3.js │ ├── 3f9e3ae9d4ee540b9fb067b6fd29d529.js │ ├── 400622a60e8e3194e3d666d073e3c7db.js │ ├── 4037e6d4b18e3e286dec455cc63c1d17.js │ ├── 40505d6c2f34fc08502d3e596573c7f8.js │ ├── 40ba797ae7e4433f9847cd2c68bfbdf7.js │ ├── 413ec783ae29da56e8bdabae45457f91.js │ ├── 4190490a8257bdfcce6e2bd4f0634086.js │ ├── 41f85ea0c545f0539b6ae2753eb1f79c.js │ ├── 4263ed179f5b2268965e1157074583e8.js │ ├── 42837f940cb1b7ef3aacf38a45916320.js │ ├── 434a5902436fc0f4bac913f7ae1471c6.js │ ├── 43a9bcfc200d80676bc68fe9a3c8ab6d.js │ ├── 43bd62d6b50d1253f782c9ae5be1593d.js │ ├── 43dab3876e6402fc9ae359a033683cc4.js │ ├── 4474c9775d04684871043fae3501ec66.js │ ├── 44b4462224957b51234691dacc5dd4c8.js │ ├── 44e6d883ecccba28d8adf592cb83e01b.js │ ├── 451c3753fb6dfc1f2de25cb7524f4bb2.js │ ├── 46bac1e89f220258537c533035a6e263.js │ ├── 4705b919138245a5b454d25f8e418435.js │ ├── 4750f0ff62cbd59f35aac31b996194e6.js │ ├── 476880245318ad211000fa55cb15d83f.js │ ├── 47cd5c7d174e6b624e55510c4e503600.js │ ├── 47ecd829f86e48857a05b2189ee9c097.js │ ├── 4ab6dffb1b7255cc39ef77a35eb53293.js │ ├── 4cbd6f8a4f52821c1d3476139078797d.js │ ├── 4cf2f8563b2e07e643af9cc19cd44a2e.js │ ├── 4d694d41a0c1b3eaad752a8352c5661c.js │ ├── 4e4d407bd6bf0ce7bfc869f7eb6e93d3.js │ ├── 4e9e0e943cacfdf9d350ba0c59bfb53b.js │ ├── 4f0436f3850202d127036b38729c6861.js │ ├── 4f96d1df55d7c479ed066be2863223c7.js │ ├── 5094b30d2471cc7312746173d8a4bb25.js │ ├── 51e6918f996813eafa4b1491d9dd343b.js │ ├── 51e6ccd3ea9d7443949b155b113eebd5.js │ ├── 52193d41677f370ad903b5437974afef.js │ ├── 536bba7b10d156b509ec6516577ad3ce.js │ ├── 540bba54b49ea7a6ec513270449132db.js │ ├── 553aa6bb3b625428f4df57f5885d50f3.js │ ├── 5540bb93f39dcb670a0f9b4e4b793d02.js │ ├── 57c2d2eb6a844a8c9ecd932c6d4067b0.js │ ├── 57c7c145c720f31f3749b658e3769833.js │ ├── 587c674b536ffaf75df5db37c7b67c4a.js │ ├── 58d885ab56201085ce55e8eb5d3f2ac2.js │ ├── 59457eef0e0be735680874d74c13e469.js │ ├── 5bd58f2ebad7e63ff72a891fb43e2b38.js │ ├── 5ce9c9a26cf28c9ccdcf82388efacf29.js │ ├── 5e1dbd63b493d399404d7d8d5b9e5934.js │ ├── 5e4dd0452f14cf5dbb02a7dc7d9dda76.js │ ├── 5e62ca244220154bbcae2a7eb2c50e0f.js │ ├── 5e9314c1c0d4e5f4cb7a3f80fc01530c.js │ ├── 5eeee1acc01b04328cf42db0715bb7f5.js │ ├── 5f0b8714b08d299edbdf3b3d9adb7e71.js │ ├── 5f6f5026d13b2a9b884a8144a119cf9e.js │ ├── 60fc15a66fa7ba74ccd248f85b50fbe5.js │ ├── 61cc56da80a76731283878abc3b13761.js │ ├── 628b24103fca421515ec8724d12f026f.js │ ├── 63999023068dcbebee417ac354fe4e78.js │ ├── 63ccb1f1a27a2bf6271f40d3082186f4.js │ ├── 642f5bce034554539cc93a5b965e730a.js │ ├── 646c9322233a0ba128268dee916e5719.js │ ├── 6477e8f75e2259e66e943bdef7b9e4a7.js │ ├── 64a7727963416cd27ab100d1dfff8168.js │ ├── 64f93b6b093bba4147485023263cf65f.js │ ├── 66670f2c1f5e7c4e531007e89bb85355.js │ ├── 666899335e954b291e938197a76bc90c.js │ ├── 68cf9a0e1eaff7cc991e970a855108f8.js │ ├── 697c2df91bf7c729d317c620a3cd77bd.js │ ├── 6a42bdf71e3ae785252f124075145d08.js │ ├── 6c6f2df70d907fa6b59b176f4d02dffd.js │ ├── 6d9ca7a980db8fa74e39b1ff3b0c75cd.js │ ├── 6dafd4eb9102ea47229a42a24d40f457.js │ ├── 6e4d1075690c1f17775f02251592ac60.js │ ├── 6e88d3943f4c3a068493aad131cd4898.js │ ├── 6e9ca56e0fa3e784eab3da45f8d0d8ac.js │ ├── 6f0543453c605ea6d673a3bd31dd1090.js │ ├── 6f61a36cc8b4cd9472559c6f0c2374a0.js │ ├── 6f783ca6efdcb90ccde9175312f6558d.js │ ├── 7074e18e67a10875c827b6cfe2665b83.js │ ├── 7150c52abe226d317116208cfe9fdc88.js │ ├── 727184c92f9da8d8b0c013fd79cf32fe.js │ ├── 72d23326220bc76ce06b4c1c68efb378.js │ ├── 74973bbb728e661679e49a16773535a4.js │ ├── 78999d905693a14a2c4677977ba222fb.js │ ├── 79701bbf8c5436771916d9af708ae8ec.js │ ├── 7982ae381c10e501e9a46d8693deddf6.js │ ├── 7af5865535fb306e7d0364a9ff81f389.js │ ├── 7bdb2e4d3bc51d15863aa7be6e0a23a9.js │ ├── 7cef38946c33fa981d6d2c86c62428e0.js │ ├── 7d46cd8e5efaac33d5bf823ed4268841.js │ ├── 7d4e1c98726f11ff7baaf1a31882c59f.js │ ├── 7da5aafe24e626f9bced82fe40567386.js │ ├── 7e89c064ec09f955a6c3ffbfb96908a2.js │ ├── 7e98c4d98664d6f7bcc52a07f21a1f9f.js │ ├── 7f10fe526aec57bd522af77ea6ac2b62.js │ ├── 7f63b670b51e07bd9a30869b68ada191.js │ ├── 7f97ea63879ac5f3a2b491a651a1a82f.js │ ├── 8043595ccf704fc61e7e3e4c7c7e77a5.js │ ├── 806bfd960245b1da40a7e1057a076289.js │ ├── 8103e73d2ea3574b81428aafc4e01c71.js │ ├── 8120c57dbca7501da3ecf702c811f16f.js │ ├── 817d52a47a4657b8a4dab79e057f5fb0.js │ ├── 81be1aff3c1cfa0531037ebab355abbb.js │ ├── 82ce99851e7fc39e91603bc3320fe6d2.js │ ├── 833b242747fd7b098d46011e4289bc3f.js │ ├── 83a1ba72f83e644dc4fbbc0d48501061.js │ ├── 83ea78d42f1a8e5f7346f3a30140ebfb.js │ ├── 8468b2aa5fbe665b49784c30b4a908f7.js │ ├── 84d3403e422e4697e86914f183a60a13.js │ ├── 84f75bf9ddb5400925d2a043a2013cec.js │ ├── 852f3a4ec9ee58d75bd55c85161bb68f.js │ ├── 8536514f6ace9c40d36020af05e067fe.js │ ├── 85e246a36ca53e3f767608542dcd26b3.js │ ├── 85f71b723441bcf428b8abed1fc8f56f.js │ ├── 85fe85850b026b668c10d2c9e0e5e8c6.js │ ├── 867fb2b26eef123915aff8634c0bbf4a.js │ ├── 8681f562786fa45bebe8ee7ed2461026.js │ ├── 86dfc095a8bb97b2b6d94b798ebcdc61.js │ ├── 8833a126ef9d8892bfb372d227f7f088.js │ ├── 8870430db332faf22d90e12f1620ee84.js │ ├── 88d5efab68c7526ad2ad4196932adb03.js │ ├── 88f2b86b79781364b99947d07d3c3469.js │ ├── 89392e9dbbec39477b4b3e52a0676422.js │ ├── 89859a411a50c90f1e669deaf8a6775f.js │ ├── 89a47a0051ac0b3885ef8af2476526f0.js │ ├── 8a7d1e82245ba58033df533faadfbaf4.js │ ├── 8afcf3a037a7f37f9c0bbad01507d73b.js │ ├── 8bdbab2f0d58195a7d509ad6fbe02966.js │ ├── 8dec848a9d34e3804976ae4a589fbc4f.js │ ├── 8e6a809082edab0aaf90b9eb118ae571.js │ ├── 8e81f51d2e7be98e9e45fe93239c7e99.js │ ├── 8ee6948d963e299de55144b3c7a60c0a.js │ ├── 8f69fc81a83ba318eca7dbae6c6eba75.js │ ├── 90643b9da87302fef490f3f48af806e2.js │ ├── 908119c25a234151c8c7c1a97005c866.js │ ├── 91832748c8f066b07af2341ccc6dd5b1.js │ ├── 92cf63e9a949f08d97a74d9ed17392ed.js │ ├── 9360974ffacadb05145e2f6c1458f35b.js │ ├── 93edcad7b93942b98afaab6436a13d10.js │ ├── 94a0179602c94d55621a35e41c97ed5c.js │ ├── 94a5c40baab0f2df8b43889ed5fb6b8a.js │ ├── 9588381016bdc5e88634572e630b4551.js │ ├── 983ddc3115fae8e0dfd108d799662892.js │ ├── 985b400088bf5e23fb83e70d9948eccb.js │ ├── 998c5f13555e18b42e9bf826578b2e16.js │ ├── 99b756405f919e9022e6a4e3579dd5ee.js │ ├── 99f6bcba35fb277563c6362f3caab715.js │ ├── 9abcc804fa38b6d05e62a10cb8dbb668.js │ ├── 9c202aefac35a5ff49d3d3795e9932bc.js │ ├── 9cf3be7669b89ac4036cd07c9baf7e13.js │ ├── 9d0f4f65be2f50ad54488089f126feda.js │ ├── 9e357a97da26127713394684a51946b8.js │ ├── 9e69cb39701c3578226b39536edd4dd7.js │ ├── 9e875d25eb6d80340adac0cfc35700c1.js │ ├── a026164ca1f6f157fcb0f5f6bfd4abce.js │ ├── a06ea1f6e485f67413d6cb34d7cc3515.js │ ├── a07f2b025030bd4f277803aea0e6a539.js │ ├── a26463d029a2515171748a1ebcca53c3.js │ ├── a311e02008e0f00a37305a12d479159a.js │ ├── a33f52a5f1ea0162305f99d63235f807.js │ ├── a477d7b35783dd10040a243a84c86a0c.js │ ├── a5cb31cfb4711ef14999198f0d35eaf3.js │ ├── a5cd4d965591278c0519bdfa761ea3aa.js │ ├── a65a0bae3e5b73407d15ea6bbb08e515.js │ ├── a71d8ecb9a2a4b35fcd828bb970e7e84.js │ ├── a84f565fc5473f112281550ea6c2ccf4.js │ ├── aa2f98073a8d9f266f3928b5d9c457d1.js │ ├── ab16c1237e6e04bbf0024ee2bae42130.js │ ├── acc30207efba7ab5b7b509b599f37e6f.js │ ├── acc4ded8b9debce27f884c9cce5bf63c.js │ ├── acc7448b80728a73c9a4046b3ec4407f.js │ ├── adbb57fa182dce548204311d3be6dffa.js │ ├── ae5d4d6eea08ccfac67e44bfe11da4ed.js │ ├── b02513e1d0cc664936e1ba9cb5a923af.js │ ├── b0fc54e0e936c84253a30c9b39cfd9bf.js │ ├── b111a00f8f22708140c6fdbc26963155.js │ ├── b131314d1ea62fa7bba91a4da8360298.js │ ├── b1ff2cb4863b8ed961d815393cfe246d.js │ ├── b225cb9e753bd0a8ca508ccb2637bf91.js │ ├── b25d5064a26eda70aa3d2bae3a1122cc.js │ ├── b26738d581e044c69f7a4392906e6843.js │ ├── b2a2011665f9a22c8dddaf833ec822b8.js │ ├── b435aebcb57d65080cfd510e0a9d5d9d.js │ ├── b4787b2bbb3e2481e0aca0830ab31484.js │ ├── b49c9a9ab619e46a7ba6f9f89c800589.js │ ├── b4bd28ac3a7935d0c52a6cb19c89aced.js │ ├── b518725b1ee5b4ba27eec173687966f0.js │ ├── b830d88aa22a866a208be27af90526a7.js │ ├── ba07c8c1ca6ea903fd0f0379db66ea1e.js │ ├── bae95bdb1bbcc0969e0e40fb72539df3.js │ ├── bb3e0098a11d21ca01d6e44c2e39f90b.js │ ├── bb48e1051c32d32d425681e9200706bc.js │ ├── bb9282d93d3ae9d53870a66627f8c797.js │ ├── bbd62124f6d03e01eb4332f55ead999d.js │ ├── bc26ab0797e975ba01e701683935864b.js │ ├── bd33197d8c34bf6387e39130c28f8342.js │ ├── bd98610e395f3b4c7915cf3fbe854f6f.js │ ├── bd9ff502ba460f402b4e2005689402a7.js │ ├── be2fbe775b19bdc18e4f78de18beb433.js │ ├── be734ac9c9a7b29439001bfc78984ba3.js │ ├── bf06f353bf67ef497b65afe567e7f294.js │ ├── bffad0f26b7a14d73f338aefa2d2f9e5.js │ ├── c02d976c2c838a2b5ad0e5dfd1facb75.js │ ├── c033d0cf791d80ef14327c1ade637578.js │ ├── c0b4241b59cd6750a7d6ad4f3d019d84.js │ ├── c0b4cd50c3fcc1292b34cedf813a16dd.js │ ├── c0f91d067bd4f665ec7b85a632e3168d.js │ ├── c23b1f80ab9746b425f3848bdaacc144.js │ ├── c24de6963d7d00c269db34091059e06d.js │ ├── c2b469d0ddb280bda5f621563579725d.js │ ├── c2c0e5fa8323e2c5c1f54f20afda51b8.js │ ├── c38a3226f3858a47ba9fb788dc7b44fc.js │ ├── c3b0cd15adcc12a549e7ac5d165ac1f4.js │ ├── c502e0f58557345fbd8e157a93dc4d43.js │ ├── c5d7c4a345a7bb4c84ee8ced7322a8db.js │ ├── c6d4a590e14107a8a5ad505d66241032.js │ ├── c6f608398c43e25821557ee65cda5e58.js │ ├── c755e7fc08446566ee8dd3a8aa8fe43f.js │ ├── c797cd030330cde3e9c0f5e9db6b2be5.js │ ├── c7d3b0afe7600a632fbf44ee8d84996e.js │ ├── c7fb0ccebacccfb5c2f7b2f6023ebe4a.js │ ├── c806ba4f0026195e7907bfb62d00b502.js │ ├── c8bdb139ff462c0e7dc4ba2f56a49318.js │ ├── c8c48c73e7d7dd2c142badc913ab26fe.js │ ├── c98e5722b508d4eb3afcea637246de33.js │ ├── ca1483809659f6c87cc6f588891d2bd4.js │ ├── cb332e7b5386c55fe0ced93b36d73da7.js │ ├── ce73c3243f61524d76000c4ace94f2bb.js │ ├── cf0a04afa21ac9ba23a1de0416a03105.js │ ├── cf1f6c842a1ec0af6b00ce1859dce6d5.js │ ├── css.worker.js │ ├── css │ ├── app.2a1944af.css │ ├── chunk-0279f58f.f040dd0a.css │ ├── chunk-05a99c67.b1dd7a76.css │ ├── chunk-24a54a1d.03727b70.css │ ├── chunk-39b1e937.e5d373cf.css │ ├── chunk-6260e53b.bcae8e8e.css │ ├── chunk-88ab404a.8ffb2425.css │ ├── chunk-fb24efc2.3de04029.css │ └── chunk-libs.77b8d5d9.css │ ├── d08030a8f6057b63643bacf4cee162b0.js │ ├── d08daa8e673c585e1311729dbcb63eb4.js │ ├── d27d5c5480c14bffe9ffc07fec3a806d.js │ ├── d2b533a0128ef6edfaf153c0fa19e432.js │ ├── d2e30554e6939a2542e5135fff541daa.js │ ├── d465c0a35c6ef244bf587b0e6bdb4019.js │ ├── d47938906a471dea833a3b57991c7124.js │ ├── d5a596705e8b1c50832d29b25f4ffb0a.js │ ├── d70ab0885fcc546aaf5eee0c5fca6278.js │ ├── d750a8dbf9dd09c0a33b9986e79e3c8c.js │ ├── d754905fe54aac6f3c350df34f51a0b6.js │ ├── d7889907dbb51f58ceadb3e1eec03a5d.js │ ├── d7cdf8e31755f70cd564c742feec3be0.js │ ├── d7e8066668f05d83f86a128d7dbd45a2.js │ ├── d7f9c3bcea90f112bc7cac6559dcb00c.js │ ├── d8c239d65159c02ebd6a2afa3cdc584b.js │ ├── d9a00ccd64f554cd458b3d6f6c66f465.js │ ├── d9e70caae42a8f91d34536f0d7941673.js │ ├── da06d4429e8bccd9ef90b16ebe49354b.js │ ├── da1719655627488c0c1afaa1379e2c1d.js │ ├── dad7909925cdea4ce193d5c14a13abf3.js │ ├── db7eff370e6f80152653db4bc1c65285.js │ ├── dcb084d6aacfa517923dd3a94e3b9af5.js │ ├── dcf82c5c24de859d74953010a3bf7f11.js │ ├── dcf8b9b721cab79d285ab33fe2154a58.js │ ├── dd40dfc7840568927fdef65087a233ed.js │ ├── dde12e6c2c05d17c95ed0a94da234b3b.js │ ├── de385e48e4b7a8c5837c9a2fd07ede3e.js │ ├── de581fe10be3ac282fa6abc2f8171551.js │ ├── e0476257d7657264e527f7a1f1ecbece.js │ ├── e0e2b1267a5d4acb4dda3a4a598cd8a5.js │ ├── e1dbe800b2d3f5d74b2b5480ea2b897a.js │ ├── e2792218bae78a6aef6764de4e61fd82.js │ ├── e393bf5358fc198ca07e518900b24311.js │ ├── e4d51c8b4202d444cb39db4e7642d7d9.js │ ├── e6c2b11f457b5aa71fd08de4ae738c3f.js │ ├── e6fe37aef08c1bd39b8fc610216b5228.js │ ├── e745f8fb4f054a3f5b66ccad100a1217.js │ ├── e7a892eff1dd4ac60e8201386497b66b.js │ ├── e8250271e7641960341ae2ac170af4ac.js │ ├── ea5c101c16108be8cf1522aae5736f5f.js │ ├── eb6f00b565c6441d02346354a0ef64ce.js │ ├── editor.worker.js │ ├── ef2640638453d7df3e7e1659d1f67105.js │ ├── efa2aae8c65855514b0ca66c4fe1cc68.js │ ├── efc508c36f4e417ec6bd5ec72989443b.js │ ├── f023b7e5335b8e16fb42f8f3e18ecf3f.js │ ├── f102c542cd35eef623ab82b087af2f14.js │ ├── f120c3f4e008f9abcd3a576bd66dd315.js │ ├── f2040b70e41cfa457e9796aca8abfeea.js │ ├── f2195d2eae3dbef7e3798e115209dcd7.js │ ├── f29286fc7d5663eb11457f48664f324d.js │ ├── f2cfc0e604350e23bfcd7c78165b1411.js │ ├── f35e34e60520cef0b0dbba2bc2931941.js │ ├── f3a0f6e7e442de2ae51eddbf4eb98d97.js │ ├── f3b6993cd8f9bbdd1d5ad68a5e1cdf70.js │ ├── f457edce8a9809fa16aab3c8e695bf38.js │ ├── f473db7186a8dd6d4526d55c4d7ed873.js │ ├── f4b747bf296f21fcf6d59357e92f948d.js │ ├── f4ee92824c023ab7278694588c9c40f1.js │ ├── f50d7c4ce743ce495230d19bd33fefab.js │ ├── f5292be525fc36a337ce7bfb792070de.js │ ├── f52e2798c3b260592cf35f3a20958d87.js │ ├── f61f1aaed3f32a7dabd977a6f47ecd5f.js │ ├── f6cfc0e0566a350632db32ece39b649d.js │ ├── f7443e8232a7e4289b9f2ed4a512750c.js │ ├── f7b04f07406ef16d88688a7ffb81ce3f.js │ ├── f80c6eb0f52a68464b21211240e3d6e6.js │ ├── f88127ad8950e3c94c3af6c65a7120fa.js │ ├── f913332fa21973f354fcb5b680811e56.js │ ├── f95dc04dc50d90d0555ca3561e75c4c2.js │ ├── fa1618cda4da7d5362c381ea2d5f7321.js │ ├── faf460076b3383fdc3ecc224068964cf.js │ ├── favicon.ico │ ├── fb4580529d9585e912b7142f6b62cae4.js │ ├── fe4de7aeda3abed04c238956a8565de4.js │ ├── fe51d45583c0425b00c9a784727072e0.js │ ├── fe56e099960b1f5a3ac7143e245f7ce1.js │ ├── fe58209a4ef163863b95ab289a69cdaf.js │ ├── fe5fd32b764aa22fde63925ac549a9c9.js │ ├── fffbc895129cdb3efeafa5b234743aa0.js │ ├── fonts │ ├── eiconfont.016bbe3f.woff │ ├── eiconfont.0ff67604.ttf │ ├── eiconfont.ae6bc167.eot │ ├── element-icons.535877f5.woff │ ├── element-icons.732389de.ttf │ ├── fontawesome-webfont.674f50d2.eot │ ├── fontawesome-webfont.af7ae505.woff2 │ ├── fontawesome-webfont.b06871f2.ttf │ ├── fontawesome-webfont.fee66e71.woff │ ├── iconfont.34ea3475.34ea3475.woff │ ├── iconfont.34ea3475.woff │ ├── iconfont.4d5a9051.4d5a9051.ttf │ ├── iconfont.4d5a9051.ttf │ ├── iconfont.8efbc988.8efbc988.eot │ └── iconfont.8efbc988.eot │ ├── html.worker.js │ ├── img │ ├── 401.089007e7.gif │ ├── 404.a57b6f31.png │ ├── 404_cloud.0f4bc32b.png │ ├── eiconfont.30cb46e7.svg │ ├── end.9687f898.svg │ ├── exclusive-gateway.56b82dfd.svg │ ├── fontawesome-webfont.912ec66d.svg │ ├── icon_java.d3cc233a.svg │ ├── icon_mail.0f68d5c7.svg │ ├── icon_message.01031aed.svg │ ├── icon_receive.a6c46918.svg │ ├── icon_script.07c7423e.svg │ ├── icon_signal.0e96b3b6.svg │ ├── icon_timer.b4fcbba6.svg │ ├── icon_user.2b39cf22.svg │ ├── iconfont.6c66fc36.svg │ ├── iconfont.f0e930ef.f0e930ef.svg │ ├── iconfont.f0e930ef.svg │ ├── login.ede1cdb8.png │ ├── parallel-gateway.dfb4ebaf.svg │ ├── receive-task.e1131038.svg │ ├── start.894f1842.svg │ └── user-task.90bd34cf.svg │ ├── index.html │ ├── js │ ├── app.9311df7b.js │ ├── chunk-0279f58f.1f192749.js │ ├── chunk-05a99c67.cfbcb6c6.js │ ├── chunk-192165dd.25e2ffe9.js │ ├── chunk-24a54a1d.eeaaeb1b.js │ ├── chunk-292427cd.49f63400.js │ ├── chunk-2d0e2366.359919a5.js │ ├── chunk-2d2105d3.b54ad484.js │ ├── chunk-2d230fe7.19def69d.js │ ├── chunk-39b1e937.3a2314ea.js │ ├── chunk-4f5f604e.cf35faa9.js │ ├── chunk-50a983d1.babc8539.js │ ├── chunk-6260e53b.51269640.js │ ├── chunk-748b566e.2d85de49.js │ ├── chunk-88ab404a.4ce530b5.js │ ├── chunk-cff79be6.1d9c70c2.js │ ├── chunk-elementUI.749da353.js │ ├── chunk-fb24efc2.cba6adf3.js │ └── chunk-libs.c758eded.js │ ├── json.worker.js │ └── ts.worker.js ├── template ├── api.go.template ├── js.go.template ├── model.go.template ├── router.go.template ├── vue.go.template └── web │ └── index.html ├── test ├── api.go.template └── model.go.template └── tools ├── app ├── model.go ├── msg │ └── message.go └── return.go ├── captcha └── captcha.go ├── config ├── application.go ├── config.go ├── database.go ├── jwt.go └── ssl.go ├── env.go ├── float64.go ├── int.go ├── int64.go ├── ip.go ├── string.go ├── url.go ├── user.go └── utils.go /.air.conf: -------------------------------------------------------------------------------- 1 | # Config file for [Air](https://github.com/cosmtrek/air) in TOML format 2 | 3 | # Working directory 4 | # . or absolute path, please note that the directories following must be under root. 5 | root = "." 6 | tmp_dir = "tmp" 7 | 8 | [build] 9 | # Just plain old shell command. You could use `make` as well. 10 | cmd = "go build -o ./tmp/main ." 11 | # Binary file yields from `cmd`. 12 | bin = "tmp/main" 13 | # Customize binary. 14 | # full_bin = "APP_ENV=dev APP_USER=air ./tmp/main" 15 | full_bin = "./tmp/main server -c=config/settings.dev.yml" 16 | # Watch these filename extensions. 17 | include_ext = ["go", "tpl", "tmpl", "html"] 18 | # Ignore these filename extensions or directories. 19 | exclude_dir = ["assets", "tmp", "vendor", "frontend/node_modules"] 20 | # Watch these directories if you specified. 21 | include_dir = [] 22 | # Exclude files. 23 | exclude_file = [] 24 | # This log file places in your tmp_dir. 25 | log = "./tmp/air.log" 26 | # It's not necessary to trigger build each time file changes if it's too frequent. 27 | delay = 1000 # ms 28 | # Stop running old binary when build errors occur. 29 | stop_on_error = true 30 | # Send Interrupt signal before killing process (windows does not support this feature) 31 | send_interrupt = false 32 | # Delay after sending Interrupt signal 33 | kill_delay = 500 # ms 34 | 35 | [log] 36 | # Show log time 37 | time = false 38 | 39 | [color] 40 | # Customize each part's color. If no color found, use the raw app log. 41 | main = "magenta" 42 | watcher = "cyan" 43 | build = "yellow" 44 | runner = "green" 45 | 46 | [misc] 47 | # Delete tmp directory on exit 48 | clean_on_exit = true 49 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | build: 12 | name: Build 13 | runs-on: ubuntu-latest 14 | steps: 15 | 16 | - name: Set up Go 1.13 17 | uses: actions/setup-go@v1 18 | with: 19 | go-version: 1.13 20 | id: go 21 | 22 | - name: Check out code into the Go module directory 23 | uses: actions/checkout@v2 24 | 25 | - name: Get dependencies 26 | run: | 27 | go get -v -t -d ./... 28 | if [ -f Gopkg.toml ]; then 29 | curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh 30 | dep ensure 31 | fi 32 | 33 | - name: Build 34 | run: go build -v . 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | static/uploadfile 3 | ferry 4 | temp/ 5 | !temp 6 | vendor 7 | tmp/ 8 | config/settings.dev.yml 9 | logs 10 | mysql/data 11 | redis/data 12 | data/ 13 | needinit -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 lanyulei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT:=ferry 2 | 3 | .PHONY: build 4 | build: 5 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o ferry main.go && upx -9 ferry 6 | build-sqlite: 7 | go build -tags sqlite3 -o ferry main.go 8 | #.PHONY: test 9 | #test: 10 | # go test -v ./... -cover 11 | 12 | #.PHONY: docker 13 | #docker: 14 | # docker build . -t ferry:latest 15 | -------------------------------------------------------------------------------- /apis/monitor/server.go: -------------------------------------------------------------------------------- 1 | package monitor 2 | 3 | import ( 4 | "ferry/tools/app" 5 | "runtime" 6 | 7 | "github.com/gin-gonic/gin" 8 | "github.com/shirou/gopsutil/cpu" 9 | "github.com/shirou/gopsutil/disk" 10 | "github.com/shirou/gopsutil/mem" 11 | ) 12 | 13 | const ( 14 | B = 1 15 | KB = 1024 * B 16 | MB = 1024 * KB 17 | GB = 1024 * MB 18 | ) 19 | 20 | func ServerInfo(c *gin.Context) { 21 | 22 | osDic := make(map[string]interface{}, 0) 23 | osDic["goOs"] = runtime.GOOS 24 | osDic["arch"] = runtime.GOARCH 25 | osDic["mem"] = runtime.MemProfileRate 26 | osDic["compiler"] = runtime.Compiler 27 | osDic["version"] = runtime.Version() 28 | osDic["numGoroutine"] = runtime.NumGoroutine() 29 | 30 | dis, _ := disk.Usage("/") 31 | diskTotalGB := int(dis.Total) / GB 32 | diskFreeGB := int(dis.Free) / GB 33 | diskDic := make(map[string]interface{}, 0) 34 | diskDic["total"] = diskTotalGB 35 | diskDic["free"] = diskFreeGB 36 | 37 | mem, _ := mem.VirtualMemory() 38 | memUsedMB := int(mem.Used) / GB 39 | memTotalMB := int(mem.Total) / GB 40 | memFreeMB := int(mem.Free) / GB 41 | memUsedPercent := int(mem.UsedPercent) 42 | memDic := make(map[string]interface{}, 0) 43 | memDic["total"] = memTotalMB 44 | memDic["used"] = memUsedMB 45 | memDic["free"] = memFreeMB 46 | memDic["usage"] = memUsedPercent 47 | 48 | cpuDic := make(map[string]interface{}, 0) 49 | cpuDic["cpuNum"], _ = cpu.Counts(false) 50 | 51 | app.Custum(c, gin.H{ 52 | "code": 200, 53 | "os": osDic, 54 | "mem": memDic, 55 | "cpu": cpuDic, 56 | "disk": diskDic, 57 | }) 58 | } 59 | -------------------------------------------------------------------------------- /apis/system/captcha.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "ferry/tools/app" 5 | "ferry/tools/captcha" 6 | "fmt" 7 | 8 | "github.com/gin-gonic/gin" 9 | ) 10 | 11 | /* 12 | @Author : lanyulei 13 | */ 14 | 15 | func GenerateCaptchaHandler(c *gin.Context) { 16 | id, b64s, _, err := captcha.DriverDigitFunc() 17 | if err != nil { 18 | app.Error(c, -1, err, fmt.Sprintf("验证码获取失败, %v", err.Error())) 19 | return 20 | } 21 | app.Custum(c, gin.H{ 22 | "code": 200, 23 | "data": b64s, 24 | "id": id, 25 | "msg": "success", 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /apis/system/index.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | ) 6 | 7 | /* 8 | @Author : lanyulei 9 | */ 10 | 11 | const INDEX = ` 12 | 13 | 14 | 15 | 16 | ferry欢迎您 17 | 24 | 25 | 33 | 34 | 35 | 36 | 37 | 38 | ` 39 | 40 | func HelloWorld(c *gin.Context) { 41 | c.Header("Content-Type", "text/html; charset=utf-8") 42 | c.String(200, INDEX) 43 | } 44 | -------------------------------------------------------------------------------- /apis/system/info.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "ferry/models/system" 5 | "ferry/tools" 6 | "ferry/tools/app" 7 | 8 | "github.com/gin-gonic/gin" 9 | ) 10 | 11 | /* 12 | @Author : lanyulei 13 | */ 14 | 15 | func GetInfo(c *gin.Context) { 16 | 17 | var roles = make([]string, 1) 18 | roles[0] = tools.GetRoleName(c) 19 | 20 | var permissions = make([]string, 1) 21 | permissions[0] = "*:*:*" 22 | 23 | var buttons = make([]string, 1) 24 | buttons[0] = "*:*:*" 25 | 26 | RoleMenu := system.RoleMenu{} 27 | RoleMenu.RoleId = tools.GetRoleId(c) 28 | 29 | var mp = make(map[string]interface{}) 30 | mp["roles"] = roles 31 | if tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员" { 32 | mp["permissions"] = permissions 33 | mp["buttons"] = buttons 34 | } else { 35 | list, _ := RoleMenu.GetPermis() 36 | mp["permissions"] = list 37 | mp["buttons"] = list 38 | } 39 | 40 | sysuser := system.SysUser{} 41 | sysuser.UserId = tools.GetUserId(c) 42 | user, err := sysuser.Get() 43 | if err != nil { 44 | app.Error(c, -1, err, "") 45 | return 46 | } 47 | 48 | mp["introduction"] = " am a super administrator" 49 | 50 | mp["avatar"] = "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif" 51 | if user.Avatar != "" { 52 | mp["avatar"] = user.Avatar 53 | } 54 | mp["userName"] = user.NickName 55 | mp["userId"] = user.UserId 56 | mp["deptId"] = user.DeptId 57 | mp["name"] = user.NickName 58 | 59 | app.OK(c, mp, "") 60 | } 61 | -------------------------------------------------------------------------------- /apis/system/rolemenu.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "ferry/models/system" 5 | "ferry/tools/app" 6 | "net/http" 7 | 8 | "github.com/gin-gonic/gin" 9 | ) 10 | 11 | /* 12 | @Author : lanyulei 13 | */ 14 | 15 | // @Summary RoleMenu列表数据 16 | // @Description 获取JSON 17 | // @Tags 角色菜单 18 | // @Param RoleId query string false "RoleId" 19 | // @Success 200 {string} string "{"code": 200, "data": [...]}" 20 | // @Success 200 {string} string "{"code": -1, "message": "抱歉未找到相关信息"}" 21 | // @Router /api/v1/rolemenu [get] 22 | // @Security Bearer 23 | func GetRoleMenu(c *gin.Context) { 24 | var ( 25 | res app.Response 26 | Rm system.RoleMenu 27 | ) 28 | _ = c.ShouldBind(&Rm) 29 | result, err := Rm.Get() 30 | if err != nil { 31 | app.Error(c, -1, err, "") 32 | return 33 | } 34 | res.Data = result 35 | c.JSON(http.StatusOK, res.ReturnOK()) 36 | } 37 | 38 | type RoleMenuPost struct { 39 | RoleId string 40 | RoleMenu []system.RoleMenu 41 | } 42 | 43 | func InsertRoleMenu(c *gin.Context) { 44 | 45 | var res app.Response 46 | res.Msg = "添加成功" 47 | c.JSON(http.StatusOK, res.ReturnOK()) 48 | } 49 | 50 | // @Summary 删除用户菜单数据 51 | // @Description 删除数据 52 | // @Tags 角色菜单 53 | // @Param id path string true "id" 54 | // @Param menu_id query string false "menu_id" 55 | // @Success 200 {string} string "{"code": 200, "message": "删除成功"}" 56 | // @Success 200 {string} string "{"code": -1, "message": "删除失败"}" 57 | // @Router /api/v1/rolemenu/{id} [delete] 58 | func DeleteRoleMenu(c *gin.Context) { 59 | var t system.RoleMenu 60 | id := c.Param("id") 61 | menuId := c.Request.FormValue("menu_id") 62 | _, err := t.Delete(id, menuId) 63 | if err != nil { 64 | app.Error(c, -1, err, "") 65 | return 66 | } 67 | var res app.Response 68 | res.Msg = "删除成功" 69 | c.JSON(http.StatusOK, res.ReturnOK()) 70 | } 71 | -------------------------------------------------------------------------------- /apis/system/settings.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "ferry/global/orm" 5 | "ferry/models/system" 6 | "ferry/tools/app" 7 | "fmt" 8 | 9 | "github.com/gin-gonic/gin" 10 | ) 11 | 12 | /* 13 | @Author : lanyulei 14 | */ 15 | 16 | // 设置系统信息 17 | func GetSettingsInfo(c *gin.Context) { 18 | var ( 19 | err error 20 | settingsInfo []*system.Settings 21 | classify string 22 | ) 23 | db := orm.Eloquent.Model(&settingsInfo) 24 | classify = c.DefaultQuery("classify", "") 25 | if classify != "" { 26 | db = db.Where("classify = ?", classify) 27 | } 28 | 29 | err = db.Find(&settingsInfo).Error 30 | if err != nil { 31 | app.Error(c, -1, fmt.Errorf("查询数据失败,%v", err.Error()), "") 32 | return 33 | } 34 | 35 | app.OK(c, settingsInfo, "查询配置信息成功") 36 | } 37 | 38 | // 设置系统信息 39 | func SetSettingsInfo(c *gin.Context) { 40 | var ( 41 | err error 42 | settingsInfo system.Settings 43 | settingsCount int 44 | ) 45 | 46 | err = c.ShouldBind(&settingsInfo) 47 | if err != nil { 48 | app.Error(c, -1, fmt.Errorf("绑定数据失败,%v", err.Error()), "") 49 | return 50 | } 51 | 52 | // 查询数据是否存在 53 | err = orm.Eloquent.Model(&system.Settings{}). 54 | Where("classify = ?", settingsInfo.Classify). 55 | Count(&settingsCount).Error 56 | if err != nil { 57 | app.Error(c, -1, fmt.Errorf("查询数据失败,%v", err.Error()), "") 58 | return 59 | } 60 | if settingsCount == 0 { 61 | // 创建新的配置信息 62 | err = orm.Eloquent.Create(&settingsInfo).Error 63 | if err != nil { 64 | app.Error(c, -1, fmt.Errorf("创建配置信息失败,%v", err.Error()), "") 65 | return 66 | } 67 | } else { 68 | err = orm.Eloquent.Model(&settingsInfo). 69 | Where("classify = ?", settingsInfo.Classify). 70 | Updates(&settingsInfo).Error 71 | if err != nil { 72 | app.Error(c, -1, fmt.Errorf("更新配置信息失败,%v", err.Error()), "") 73 | return 74 | } 75 | } 76 | 77 | app.OK(c, "", "配置信息设置成功") 78 | } 79 | -------------------------------------------------------------------------------- /apis/tpl/tpl.go: -------------------------------------------------------------------------------- 1 | package tpl 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gin-gonic/gin" 7 | ) 8 | 9 | /* 10 | @Author : lanyulei 11 | */ 12 | 13 | func Tpl(c *gin.Context) { 14 | c.HTML(http.StatusOK, "index.html", gin.H{}) 15 | } 16 | -------------------------------------------------------------------------------- /cmd/cobra.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "errors" 5 | "ferry/cmd/api" 6 | "ferry/cmd/migrate" 7 | "ferry/pkg/logger" 8 | "os" 9 | 10 | "github.com/spf13/cobra" 11 | ) 12 | 13 | var rootCmd = &cobra.Command{ 14 | Use: "ferry", 15 | Short: "-v", 16 | SilenceUsage: true, 17 | DisableAutoGenTag: true, 18 | Long: `ferry`, 19 | Args: func(cmd *cobra.Command, args []string) error { 20 | if len(args) < 1 { 21 | return errors.New("requires at least one arg") 22 | } 23 | return nil 24 | }, 25 | PersistentPreRunE: func(*cobra.Command, []string) error { return nil }, 26 | Run: func(cmd *cobra.Command, args []string) { 27 | usageStr := `欢迎使用 ferry,可以使用 -h 查看命令` 28 | logger.Infof("%s\n", usageStr) 29 | }, 30 | } 31 | 32 | func init() { 33 | rootCmd.AddCommand(api.StartCmd) 34 | rootCmd.AddCommand(migrate.StartCmd) 35 | } 36 | 37 | //Execute : apply commands 38 | func Execute() { 39 | if err := rootCmd.Execute(); err != nil { 40 | os.Exit(-1) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /cmd/migrate/server.go: -------------------------------------------------------------------------------- 1 | package migrate 2 | 3 | import ( 4 | "ferry/database" 5 | "ferry/global/orm" 6 | "ferry/models/gorm" 7 | "ferry/models/system" 8 | "ferry/pkg/logger" 9 | config2 "ferry/tools/config" 10 | "fmt" 11 | 12 | "github.com/spf13/cobra" 13 | ) 14 | 15 | var ( 16 | config string 17 | mode string 18 | StartCmd = &cobra.Command{ 19 | Use: "init", 20 | Short: "initialize the database", 21 | Run: func(cmd *cobra.Command, args []string) { 22 | run() 23 | }, 24 | } 25 | ) 26 | 27 | func init() { 28 | StartCmd.PersistentFlags().StringVarP(&config, "config", "c", "config/settings.yml", "Start server with provided configuration file") 29 | StartCmd.PersistentFlags().StringVarP(&mode, "mode", "m", "dev", "server mode ; eg:dev,test,prod") 30 | } 31 | 32 | func run() { 33 | usage := `start init` 34 | fmt.Println(usage) 35 | //1. 读取配置 36 | config2.ConfigSetup(config) 37 | //2. 初始化数据库链接 38 | database.Setup() 39 | //3. 数据库迁移 40 | _ = migrateModel() 41 | logger.Info("数据库结构初始化成功!") 42 | //4. 数据初始化完成 43 | if err := system.InitDb(); err != nil { 44 | logger.Fatalf("数据库基础数据初始化失败,%v", err) 45 | } 46 | 47 | usage = `数据库基础数据初始化成功` 48 | fmt.Println(usage) 49 | } 50 | 51 | func migrateModel() error { 52 | if config2.DatabaseConfig.Dbtype == "mysql" { 53 | orm.Eloquent = orm.Eloquent.Set("gorm:table_options", "ENGINE=InnoDB CHARSET=utf8mb4") 54 | } 55 | return gorm.AutoMigrate(orm.Eloquent) 56 | } 57 | -------------------------------------------------------------------------------- /config/rbac_model.conf: -------------------------------------------------------------------------------- 1 | [request_definition] 2 | r = sub, obj, act 3 | 4 | [policy_definition] 5 | p = sub, obj, act 6 | 7 | [policy_effect] 8 | e = some(where (p.eft == allow)) 9 | 10 | [matchers] 11 | m = r.sub == p.sub && (keyMatch2(r.obj, p.obj) || keyMatch(r.obj, p.obj)) && (r.act == p.act || p.act == "*") -------------------------------------------------------------------------------- /config/settings.dev.yml: -------------------------------------------------------------------------------- 1 | script: 2 | path: ./static/scripts 3 | settings: 4 | application: 5 | domain: localhost:8002 6 | host: 0.0.0.0 7 | ishttps: false 8 | mode: dev 9 | name: ferry-test 10 | port: "8002" 11 | readtimeout: 1 12 | writertimeout: 2 13 | database: 14 | dbtype: mysql 15 | host: 192.168.31.94 16 | name: ferry 17 | password: 123456 18 | port: 3306 19 | username: root 20 | dingtalk: 21 | agentid: 1234567890 22 | appkey: your dingtalk appkey 23 | appsecret: your dingtalk appsecret 24 | enable: false 25 | domain: 26 | gethost: 1 27 | url: localhost:9527 28 | email: 29 | alias: ferry 30 | host: smtp.163.com 31 | pass: your password 32 | port: 465 33 | user: fdevops@163.com 34 | gorm: 35 | logmode: 0 36 | maxidleconn: 0 37 | maxopenconn: 20000 38 | jwt: 39 | secret: ferry 40 | timeout: 86400 41 | ldap: 42 | anonymousquery: 0 43 | basedn: dc=fdevops,dc=com 44 | bindpwd: 123456 45 | binduserdn: cn=admin,dc=fdevops,dc=com 46 | host: localhost 47 | port: 389 48 | tls: 0 49 | userfield: uid 50 | log: 51 | compress: 1 52 | consolestdout: 1 53 | filestdout: 0 54 | level: debug 55 | localtime: 1 56 | maxage: 30 57 | maxbackups: 300 58 | maxsize: 10240 59 | path: ./logs/ferry.log 60 | public: 61 | islocation: 0 62 | redis: 63 | url: redis://:123456@192.168.31.94:6379 64 | ssl: 65 | key: keystring 66 | pem: temp/pem.pem 67 | -------------------------------------------------------------------------------- /config/settings.yml: -------------------------------------------------------------------------------- 1 | script: 2 | path: ./static/scripts 3 | settings: 4 | application: 5 | domain: localhost:8002 6 | host: 0.0.0.0 7 | ishttps: false 8 | mode: dev 9 | name: ferry 10 | port: "8002" 11 | readtimeout: 1 12 | writertimeout: 2 13 | database: 14 | dbtype: mysql 15 | host: ferry_mysql 16 | name: ferry 17 | password: 123456 18 | port: 3306 19 | username: root 20 | dingtalk: 21 | agentid: 1234567890 22 | appkey: your dingtalk appkey 23 | appsecret: your dingtalk appsecret 24 | enable: false 25 | domain: 26 | gethost: 1 27 | url: localhost:9527 28 | email: 29 | alias: ferry 30 | host: smtp.163.com 31 | pass: your password 32 | port: 465 33 | user: fdevops@163.com 34 | gorm: 35 | logmode: 0 36 | maxidleconn: 0 37 | maxopenconn: 20000 38 | jwt: 39 | secret: ferry 40 | timeout: 86400 41 | ldap: 42 | anonymousquery: 0 43 | basedn: dc=fdevops,dc=com 44 | bindpwd: 123456 45 | binduserdn: cn=admin,dc=fdevops,dc=com 46 | host: localhost 47 | port: 389 48 | tls: 0 49 | userfield: uid 50 | log: 51 | compress: 1 52 | consolestdout: 1 53 | filestdout: 0 54 | level: debug 55 | localtime: 1 56 | maxage: 30 57 | maxbackups: 300 58 | maxsize: 10240 59 | path: ./logs/ferry.log 60 | public: 61 | islocation: 0 62 | redis: 63 | url: redis://ferry_redis:6379 64 | ssl: 65 | key: keystring 66 | pem: temp/pem.pem 67 | -------------------------------------------------------------------------------- /database/initialize.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import "ferry/tools/config" 4 | 5 | func Setup() { 6 | dbType := config.DatabaseConfig.Dbtype 7 | if dbType == "mysql" { 8 | var db = new(Mysql) 9 | db.Setup() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /database/interface.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import "github.com/jinzhu/gorm" 4 | 5 | type Database interface { 6 | Open(dbType string, conn string) (db *gorm.DB, err error) 7 | GetConnect() string 8 | } 9 | -------------------------------------------------------------------------------- /deploy/helm/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /deploy/helm/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: ferry_helm 3 | description: A Helm chart for Kubernetes 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 18 | version: 0.1.0 19 | 20 | # This is the version number of the application being deployed. This version number should be 21 | # incremented each time you make changes to the application. Versions are not expected to 22 | # follow Semantic Versioning. They should reflect the version the application is using. 23 | # It is recommended to use it with quotes. 24 | appVersion: "1.16.0" 25 | -------------------------------------------------------------------------------- /deploy/helm/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | ********** 2 | Attention! 3 | ********** 4 | 5 | Before using Ferry, you need to import ferry.sql and db.sql from templates/mysql/sql into your database! 6 | You need to import ferroy.sql first and then import db.sql. It is recommended that you import it into a database called ferroy! 7 | 8 | 9 | Thank you for installing {{ .Chart.Name }}. 10 | 11 | Your release is named {{ .Release.Name }}. 12 | 13 | To learn more about the release, try: 14 | 15 | $ helm status {{ .Release.Name }} -n {{ .Values.namespace }} 16 | $ helm get all {{ .Release.Name }} -n {{ .Values.namespace }} 17 | -------------------------------------------------------------------------------- /deploy/helm/templates/configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: ferry-config 5 | namespace: {{ .Values.namespace }} 6 | data: 7 | rbac_model.conf: | 8 | {{ .Values.configMap.rbac_model_conf | nindent 4 }} 9 | 10 | settings.yml: | 11 | {{ .Values.configMap.settings_yml | indent 4 }} 12 | -------------------------------------------------------------------------------- /deploy/helm/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: ferry 5 | namespace: {{ .Values.namespace }} 6 | labels: 7 | app: ferry 8 | spec: 9 | replicas: {{ .Values.replicaCount }} 10 | selector: 11 | matchLabels: 12 | app: ferry 13 | template: 14 | metadata: 15 | labels: 16 | app: ferry 17 | spec: 18 | volumes: 19 | - name: ferry-secret 20 | secret: 21 | secretName: ferry-secret 22 | - name: ferry-storage 23 | persistentVolumeClaim: 24 | claimName: ferry-pvc 25 | - name: ferry-config-volume 26 | configMap: 27 | name: ferry-config 28 | - name: ferry-rbac 29 | configMap: 30 | name: ferry-config 31 | containers: 32 | - name: ferry 33 | image: "{{ .Values.ferry.image.repository }}:{{ .Values.ferry.image.tag }}" 34 | imagePullPolicy: {{ .Values.ferry.image.pullPolicy }} 35 | env: 36 | - name: ENV 37 | value: {{ .Values.env.ENV | quote }} 38 | volumeMounts: 39 | - name: ferry-storage 40 | mountPath: /opt/workflow/ferry/config 41 | - name: ferry-config-volume 42 | mountPath: /opt/workflow/ferry/config/settings.yml 43 | subPath: settings.yml 44 | - name: ferry-rbac 45 | mountPath: /opt/workflow/ferry/config/rbac_model.conf 46 | subPath: rbac_model.conf 47 | ports: 48 | - containerPort: 8002 49 | 50 | -------------------------------------------------------------------------------- /deploy/helm/templates/mysql/persistentvolumeclaim.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Values.mysql.enable }} 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: ferry-mysql-pvc 6 | namespace: {{ .Values.namespace }} 7 | spec: 8 | storageClassName: {{ .Values.global.storageClassName }} 9 | accessModes: 10 | - {{ .Values.ferry.persistentVolume.accessModes | join ", " }} 11 | resources: 12 | requests: 13 | storage: {{ .Values.mysql.persistentVolume.size }} 14 | {{ end }} 15 | -------------------------------------------------------------------------------- /deploy/helm/templates/mysql/service.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Values.mysql.enable }} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: ferry-mysql 6 | namespace: {{ .Values.namespace }} 7 | spec: 8 | selector: 9 | app: ferry-mysql 10 | ports: 11 | - protocol: TCP 12 | port: {{ .Values.mysql.port }} 13 | targetPort: {{ .Values.mysql.port }} 14 | type: ClusterIP 15 | {{ end }} -------------------------------------------------------------------------------- /deploy/helm/templates/mysql/statefulset.yaml: -------------------------------------------------------------------------------- 1 | # templates/mysql/statefulset.yaml 2 | {{ if .Values.mysql.enable }} 3 | apiVersion: apps/v1 4 | kind: StatefulSet 5 | metadata: 6 | name: ferry-mysql 7 | namespace: {{ .Values.namespace }} 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: ferry-mysql 13 | template: 14 | metadata: 15 | labels: 16 | app: ferry-mysql 17 | spec: 18 | containers: 19 | - name: mysql 20 | image: {{ .Values.mysql.image.repository }}:{{ .Values.mysql.image.tag }} 21 | env: 22 | - name: MYSQL_ROOT_PASSWORD 23 | valueFrom: 24 | secretKeyRef: 25 | name: ferry-secret 26 | key: MYSQL_ROOT_PASSWORD 27 | - name: MYSQL_USER 28 | valueFrom: 29 | secretKeyRef: 30 | name: ferry-secret 31 | key: MYSQL_USER 32 | - name: MYSQL_PASSWORD 33 | valueFrom: 34 | secretKeyRef: 35 | name: ferry-secret 36 | key: MYSQL_PASSWORD 37 | - name: MYSQL_DATABASE 38 | valueFrom: 39 | secretKeyRef: 40 | name: ferry-secret 41 | key: MYSQL_DATABASE 42 | volumeMounts: 43 | - name: mysql-storage 44 | mountPath: /var/lib/mysql 45 | ports: 46 | - containerPort: 3306 47 | volumes: 48 | - name: mysql-storage 49 | persistentVolumeClaim: 50 | claimName: ferry-mysql-pvc 51 | {{ end }} 52 | -------------------------------------------------------------------------------- /deploy/helm/templates/persistentvolumeclaim.yaml: -------------------------------------------------------------------------------- 1 | # templates/persistentvolumeclaim.yaml 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: ferry-pvc 6 | namespace: {{ .Values.namespace }} 7 | spec: 8 | storageClassName: {{ .Values.global.storageClassName }} 9 | accessModes: 10 | - {{ .Values.ferry.persistentVolume.accessModes | join ", " }} 11 | resources: 12 | requests: 13 | storage: {{ .Values.ferry.persistentVolume.size }} 14 | -------------------------------------------------------------------------------- /deploy/helm/templates/redis/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Values.redis.enable }} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: ferry-redis 6 | namespace: {{ .Values.namespace }} 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: ferry-redis 12 | template: 13 | metadata: 14 | labels: 15 | app: ferry-redis 16 | spec: 17 | containers: 18 | - name: redis 19 | image: "{{ .Values.redis.image.repository }}:{{ .Values.redis.image.tag }}" 20 | command: 21 | - redis-server 22 | - "--save" 23 | - "60" 24 | - "1" 25 | - "--loglevel" 26 | - "warning" 27 | ports: 28 | - containerPort: {{ .Values.redis.port }} 29 | volumeMounts: 30 | - name: redis-storage 31 | mountPath: /data 32 | volumes: 33 | - name: redis-storage 34 | persistentVolumeClaim: 35 | claimName: ferry-redis-pvc 36 | {{ end }} 37 | 38 | -------------------------------------------------------------------------------- /deploy/helm/templates/redis/persistentvolumeclaim.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Values.redis.enable }} 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: ferry-redis-pvc 6 | namespace: {{ .Values.namespace }} 7 | spec: 8 | accessModes: 9 | - {{ .Values.ferry.persistentVolume.accessModes | join ", " }} 10 | resources: 11 | requests: 12 | storage: {{ .Values.redis.persistentVolume.size }} 13 | storageClassName: {{ .Values.global.storageClassName }} 14 | {{ end }} 15 | -------------------------------------------------------------------------------- /deploy/helm/templates/redis/service.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Values.redis.enable }} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: ferry-redis 6 | namespace: {{ .Values.namespace }} 7 | spec: 8 | ports: 9 | - port: {{ .Values.redis.port }} 10 | targetPort: {{ .Values.redis.port }} 11 | selector: 12 | app: ferry-redis 13 | clusterIP: None 14 | {{ end }} 15 | -------------------------------------------------------------------------------- /deploy/helm/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | # templates/secret.yaml 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: ferry-secret 6 | namespace: {{ .Values.namespace }} 7 | type: Opaque 8 | data: 9 | MYSQL_ROOT_PASSWORD: {{ .Values.env.MYSQL_ROOT_PASSWORD | b64enc | quote }} 10 | MYSQL_USER: {{ .Values.env.MYSQL_USER | b64enc | quote }} 11 | MYSQL_DATABASE: {{ .Values.env.MYSQL_DATABASE | b64enc | quote }} 12 | MYSQL_PASSWORD: {{ .Values.env.MYSQL_PASSWORD | b64enc | quote }} -------------------------------------------------------------------------------- /deploy/helm/templates/service.yaml: -------------------------------------------------------------------------------- 1 | # templates/service.yaml 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: ferry 6 | namespace: {{ .Values.namespace }} 7 | spec: 8 | selector: 9 | app: ferry 10 | ports: 11 | - protocol: TCP 12 | port: {{ .Values.ferry.service.port }} 13 | targetPort: {{ .Values.ferry.service.port }} 14 | type: {{ .Values.ferry.service.type }} 15 | -------------------------------------------------------------------------------- /deploy/kubernetes/deploy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: ferry 5 | namespace: ferry 6 | labels: 7 | app: ferry 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: ferry 13 | template: 14 | metadata: 15 | labels: 16 | app: ferry 17 | spec: 18 | volumes: 19 | - name: ferry-secret 20 | secret: 21 | secretName: ferry-secret 22 | - name: ferry-storage 23 | persistentVolumeClaim: 24 | claimName: ferry-pvc 25 | - name: ferry-config-volume 26 | configMap: 27 | name: ferry-config 28 | - name: ferry-rbac 29 | configMap: 30 | name: ferry-config 31 | containers: 32 | - name: ferry 33 | image: beatrueman/ferry:1.0.0 34 | env: 35 | - name: ENV 36 | value: "production" 37 | volumeMounts: 38 | - name: ferry-storage 39 | mountPath: /opt/workflow/ferry/config 40 | - name: ferry-config-volume 41 | mountPath: /opt/workflow/ferry/config/settings.yml 42 | subPath: settings.yml 43 | - name: ferry-rbac 44 | mountPath: /opt/workflow/ferry/config/rbac_model.conf 45 | subPath: rbac_model.conf 46 | ports: 47 | - containerPort: 8002 48 | 49 | --- 50 | 51 | apiVersion: v1 52 | kind: PersistentVolumeClaim 53 | metadata: 54 | name: ferry-pvc 55 | namespace: ferry 56 | spec: 57 | storageClassName: longhorn 58 | accessModes: 59 | - ReadWriteOnce 60 | resources: 61 | requests: 62 | storage: 2Gi 63 | --- 64 | apiVersion: v1 65 | kind: Service 66 | metadata: 67 | name: ferry 68 | namespace: ferry 69 | spec: 70 | selector: 71 | app: ferry 72 | ports: 73 | - protocol: TCP 74 | port: 8002 75 | targetPort: 8002 76 | type: NodePort 77 | 78 | -------------------------------------------------------------------------------- /deploy/kubernetes/redis.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: ferry-redis 5 | namespace: ferry 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: ferry-redis 11 | template: 12 | metadata: 13 | labels: 14 | app: ferry-redis 15 | spec: 16 | containers: 17 | - name: redis 18 | image: redis:latest 19 | command: 20 | - redis-server 21 | - "--save" 22 | - "60" 23 | - "1" 24 | - "--loglevel" 25 | - "warning" 26 | ports: 27 | - containerPort: 6379 28 | volumeMounts: 29 | - name: redis-storage 30 | mountPath: /data 31 | volumes: 32 | - name: redis-storage 33 | persistentVolumeClaim: 34 | claimName: redis-pvc 35 | 36 | --- 37 | apiVersion: v1 38 | kind: PersistentVolumeClaim 39 | metadata: 40 | name: redis-pvc 41 | namespace: ferry 42 | spec: 43 | accessModes: 44 | - ReadWriteOnce 45 | resources: 46 | requests: 47 | storage: 1Gi 48 | storageClassName: longhorn 49 | 50 | --- 51 | apiVersion: v1 52 | kind: Service 53 | metadata: 54 | name: ferry-redis 55 | namespace: ferry 56 | spec: 57 | ports: 58 | - port: 6379 59 | targetPort: 6379 60 | selector: 61 | app: ferry-redis 62 | clusterIP: None 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /deploy/kubernetes/secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: ferry-secret 5 | namespace: ferry 6 | type: Opaque 7 | # 将所有凭据转为base64后填入 8 | data: 9 | MYSQL_ROOT_PASSWORD: "" 10 | MYSQL_USER: "" 11 | MYSQL_DATABASE: "" 12 | MYSQL_PASSWORD: "" 13 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | 4 | ferry_mysql: 5 | image: mysql:8 6 | container_name: ferry_mysql 7 | restart: unless-stopped 8 | # 可开放出来 9 | #ports: 10 | # - 3306:3306 11 | environment: 12 | MYSQL_ROOT_PASSWORD: '123456' 13 | MYSQL_DATABASE: 'ferry' 14 | MYSQL_USER: 'ferry' 15 | MYSQL_PASSWORD: '123456' 16 | volumes: 17 | - './mysql/db:/var/lib/mysql' 18 | - '/etc/localtime:/etc/localtime:ro' 19 | 20 | ferry_redis: 21 | container_name: ferry_redis 22 | image: redis:latest 23 | restart: unless-stopped 24 | # 可开放出来 25 | #ports: 26 | # - 6379:6379 27 | command: redis-server --save 60 1 --loglevel warning 28 | 29 | ferry: 30 | build: 31 | context: "." 32 | dockerfile: "Dockerfile" 33 | image: ferry:latest 34 | container_name: ferry 35 | restart: unless-stopped 36 | depends_on: 37 | - ferry_mysql 38 | - ferry_redis 39 | ports: 40 | - "8002:8002" 41 | volumes: 42 | - '/etc/localtime:/etc/localtime:ro' 43 | - './config:/opt/workflow/ferry/config' 44 | logging: 45 | driver: json-file 46 | options: 47 | max-size: "10m" 48 | max-file: "10" 49 | -------------------------------------------------------------------------------- /docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | if [[ ! -f /opt/workflow/ferry/config/settings.yml ]] 4 | then 5 | cp /opt/workflow/ferry/default_config/* /opt/workflow/ferry/config/ 6 | fi 7 | if [[ -f /opt/workflow/ferry/config/needinit ]] 8 | then 9 | /opt/workflow/ferry/ferry init -c=/opt/workflow/ferry/config/settings.yml 10 | rm -f /opt/workflow/ferry/config/needinit 11 | fi 12 | /opt/workflow/ferry/ferry server -c=/opt/workflow/ferry/config/settings.yml 13 | -------------------------------------------------------------------------------- /global/orm/db.go: -------------------------------------------------------------------------------- 1 | package orm 2 | 3 | import ( 4 | "github.com/jinzhu/gorm" 5 | ) 6 | 7 | var Eloquent *gorm.DB 8 | var MysqlConn string 9 | 10 | -------------------------------------------------------------------------------- /handler/httpshandler.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "ferry/tools/config" 5 | 6 | "github.com/gin-gonic/gin" 7 | "github.com/unrolled/secure" 8 | ) 9 | 10 | func TlsHandler() gin.HandlerFunc { 11 | return func(c *gin.Context) { 12 | secureMiddleware := secure.New(secure.Options{ 13 | SSLRedirect: true, 14 | SSLHost: config.ApplicationConfig.Domain, 15 | }) 16 | err := secureMiddleware.Process(c.Writer, c.Request) 17 | if err != nil { 18 | return 19 | } 20 | c.Next() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /handler/ping.go: -------------------------------------------------------------------------------- 1 | package handler 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | ) 6 | 7 | func Ping(c *gin.Context) { 8 | c.JSON(200, gin.H{ 9 | "message": "ok", 10 | }) 11 | } -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "ferry/cmd" 5 | ) 6 | 7 | func main() { 8 | cmd.Execute() 9 | } 10 | -------------------------------------------------------------------------------- /middleware/auth.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "ferry/handler" 5 | jwt "ferry/pkg/jwtauth" 6 | "ferry/tools/config" 7 | "time" 8 | ) 9 | 10 | func AuthInit() (*jwt.GinJWTMiddleware, error) { 11 | return jwt.New(&jwt.GinJWTMiddleware{ 12 | Realm: "test zone", 13 | Key: []byte(config.ApplicationConfig.JwtSecret), 14 | Timeout: time.Hour, 15 | MaxRefresh: time.Hour, 16 | PayloadFunc: handler.PayloadFunc, 17 | IdentityHandler: handler.IdentityHandler, 18 | Authenticator: handler.Authenticator, 19 | Authorizator: handler.Authorizator, 20 | Unauthorized: handler.Unauthorized, 21 | TokenLookup: "header: Authorization, query: token, cookie: jwt", 22 | TokenHeadName: "Bearer", 23 | TimeFunc: time.Now, 24 | }) 25 | 26 | } 27 | -------------------------------------------------------------------------------- /middleware/customerror.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "net/http" 7 | "strconv" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | func CustomError(c *gin.Context) { 13 | defer func() { 14 | if err := recover(); err != nil { 15 | 16 | if c.IsAborted() { 17 | c.Status(200) 18 | } 19 | switch errStr := err.(type) { 20 | case string: 21 | p := strings.Split(errStr, "#") 22 | if len(p) == 3 && p[0] == "CustomError" { 23 | statusCode, e := strconv.Atoi(p[1]) 24 | if e != nil { 25 | break 26 | } 27 | c.Status(statusCode) 28 | fmt.Println( 29 | time.Now().Format("\n 2006-01-02 15:04:05.9999"), 30 | "[ERROR]", 31 | c.Request.Method, 32 | c.Request.URL, 33 | statusCode, 34 | c.Request.RequestURI, 35 | c.ClientIP(), 36 | p[2], 37 | ) 38 | c.JSON(http.StatusOK, gin.H{ 39 | "code": statusCode, 40 | "msg": p[2], 41 | }) 42 | } 43 | default: 44 | panic(err) 45 | } 46 | } 47 | }() 48 | c.Next() 49 | } 50 | -------------------------------------------------------------------------------- /middleware/header.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "net/http" 6 | "time" 7 | ) 8 | 9 | // NoCache is a middleware function that appends headers 10 | // to prevent the client from caching the HTTP response. 11 | func NoCache(c *gin.Context) { 12 | c.Header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, value") 13 | c.Header("Expires", "Thu, 01 Jan 1970 00:00:00 GMT") 14 | c.Header("Last-Modified", time.Now().UTC().Format(http.TimeFormat)) 15 | c.Next() 16 | } 17 | 18 | // Options is a middleware function that appends headers 19 | // for options requests and aborts then exits the middleware 20 | // chain and ends the request. 21 | func Options(c *gin.Context) { 22 | if c.Request.Method != "OPTIONS" { 23 | c.Next() 24 | } else { 25 | c.Header("Access-Control-Allow-Origin", "*") 26 | c.Header("Access-Control-Allow-Methods", "GET,POST,PUT,PATCH,DELETE,OPTIONS") 27 | c.Header("Access-Control-Allow-Headers", "authorization, origin, content-type, accept") 28 | c.Header("Allow", "HEAD,GET,POST,PUT,PATCH,DELETE,OPTIONS") 29 | c.Header("Content-Type", "application/json") 30 | c.AbortWithStatus(200) 31 | } 32 | } 33 | 34 | // Secure is a middleware function that appends security 35 | // and resource access headers. 36 | func Secure(c *gin.Context) { 37 | c.Header("Access-Control-Allow-Origin", "*") 38 | //c.Header("X-Frame-Options", "DENY") 39 | c.Header("X-Content-Type-Options", "nosniff") 40 | c.Header("X-XSS-Protection", "1; mode=block") 41 | if c.Request.TLS != nil { 42 | c.Header("Strict-Transport-Security", "max-age=31536000") 43 | } 44 | 45 | // Also consider adding Content-Security-Policy headers 46 | // c.Header("Content-Security-Policy", "script-src 'self' https://cdnjs.cloudflare.com") 47 | } 48 | -------------------------------------------------------------------------------- /middleware/init.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | 6 | ) 7 | 8 | 9 | func InitMiddleware(r *gin.Engine) { 10 | // 日志处理 11 | r.Use(LoggerToFile()) 12 | // 自定义错误处理 13 | r.Use(CustomError) 14 | // NoCache is a middleware function that appends headers 15 | r.Use(NoCache) 16 | // 跨域处理 17 | r.Use(Options) 18 | // Secure is a middleware function that appends security 19 | r.Use(Secure) 20 | // Set X-Request-Id header 21 | r.Use(RequestId()) 22 | } -------------------------------------------------------------------------------- /middleware/logger.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "ferry/pkg/logger" 5 | "time" 6 | 7 | "github.com/gin-gonic/gin" 8 | ) 9 | 10 | // 日志记录到文件 11 | func LoggerToFile() gin.HandlerFunc { 12 | 13 | return func(c *gin.Context) { 14 | // 开始时间 15 | startTime := time.Now() 16 | 17 | // 处理请求 18 | c.Next() 19 | 20 | // 结束时间 21 | endTime := time.Now() 22 | 23 | // 执行时间 24 | latencyTime := endTime.Sub(startTime) 25 | 26 | // 请求方式 27 | reqMethod := c.Request.Method 28 | 29 | // 请求路由 30 | reqUri := c.Request.RequestURI 31 | 32 | // 状态码 33 | statusCode := c.Writer.Status() 34 | 35 | // 请求IP 36 | clientIP := c.ClientIP() 37 | 38 | // 日志格式 39 | logger.Infof(" %s %3d %13v %15s %s %s", 40 | startTime.Format("2006-01-02 15:04:05.9999"), 41 | statusCode, 42 | latencyTime, 43 | clientIP, 44 | reqMethod, 45 | reqUri, 46 | ) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /middleware/permission.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | mycasbin "ferry/pkg/casbin" 5 | "ferry/pkg/jwtauth" 6 | _ "ferry/pkg/jwtauth" 7 | "ferry/pkg/logger" 8 | "ferry/tools" 9 | "fmt" 10 | "net/http" 11 | 12 | "github.com/gin-gonic/gin" 13 | ) 14 | 15 | //权限检查中间件 16 | func AuthCheckRole() gin.HandlerFunc { 17 | return func(c *gin.Context) { 18 | data, _ := c.Get("JWT_PAYLOAD") 19 | v := data.(jwtauth.MapClaims) 20 | e, err := mycasbin.Casbin() 21 | tools.HasError(err, "", 500) 22 | //检查权限 23 | res, err := e.Enforce(v["rolekey"], c.Request.URL.Path, c.Request.Method) 24 | logger.Info(v["rolekey"], c.Request.URL.Path, c.Request.Method) 25 | tools.HasError(err, "", 500) 26 | 27 | if res { 28 | c.Next() 29 | } else { 30 | c.JSON(http.StatusOK, gin.H{ 31 | "code": 403, 32 | "msg": fmt.Sprintf("对不起,您没有 <%v-%v> 访问权限,请联系管理员", c.Request.URL.Path, c.Request.Method), 33 | }) 34 | c.Abort() 35 | return 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /middleware/requestid.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/google/uuid" 6 | ) 7 | 8 | func RequestId() gin.HandlerFunc { 9 | return func(c *gin.Context) { 10 | // Check for incoming header, use it if exists 11 | requestId := c.Request.Header.Get("X-Request-Id") 12 | 13 | // Create request id with UUID4 14 | if requestId == "" { 15 | requestId = uuid.NewString() 16 | } 17 | 18 | // Expose it for use in the application 19 | c.Set("X-Request-Id", requestId) 20 | 21 | // Set X-Request-Id header 22 | c.Writer.Header().Set("X-Request-Id", requestId) 23 | c.Next() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /models/base/base.go: -------------------------------------------------------------------------------- 1 | /* 2 | @Author : lanyulei 3 | */ 4 | 5 | package base 6 | 7 | import ( 8 | "ferry/pkg/jsonTime" 9 | ) 10 | 11 | type Model struct { 12 | Id int `gorm:"primary_key;AUTO_INCREMENT;column:id" json:"id" form:"id"` 13 | CreatedAt jsonTime.JSONTime `gorm:"column:create_time" json:"create_time" form:"create_time"` 14 | UpdatedAt jsonTime.JSONTime `gorm:"column:update_time" json:"update_time" form:"update_time"` 15 | DeletedAt *jsonTime.JSONTime `gorm:"column:delete_time" sql:"index" json:"-"` 16 | } 17 | -------------------------------------------------------------------------------- /models/gorm/gorm.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "ferry/models/process" 5 | "ferry/models/system" 6 | 7 | "github.com/jinzhu/gorm" 8 | ) 9 | 10 | func AutoMigrate(db *gorm.DB) error { 11 | db.SingularTable(true) 12 | return db.AutoMigrate( 13 | // 系统管理 14 | new(system.CasbinRule), 15 | new(system.Dept), 16 | new(system.Menu), 17 | new(system.LoginLog), 18 | new(system.RoleMenu), 19 | new(system.SysRoleDept), 20 | new(system.SysUser), 21 | new(system.SysRole), 22 | new(system.Post), 23 | new(system.Settings), 24 | 25 | // 流程中心 26 | new(process.Classify), 27 | new(process.TplInfo), 28 | new(process.TplData), 29 | new(process.WorkOrderInfo), 30 | new(process.TaskInfo), 31 | new(process.Info), 32 | new(process.History), 33 | new(process.CirculationHistory), 34 | ).Error 35 | } 36 | -------------------------------------------------------------------------------- /models/process/circulationHistory.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import ( 4 | "ferry/models/base" 5 | ) 6 | 7 | /* 8 | @Author : lanyulei 9 | */ 10 | 11 | // 工单流转历史 12 | type CirculationHistory struct { 13 | base.Model 14 | Title string `gorm:"column:title; type: varchar(128)" json:"title" form:"title"` // 工单标题 15 | WorkOrder int `gorm:"column:work_order; type: int(11)" json:"work_order" form:"work_order"` // 工单ID 16 | State string `gorm:"column:state; type: varchar(128)" json:"state" form:"state"` // 工单状态 17 | Source string `gorm:"column:source; type: varchar(128)" json:"source" form:"source"` // 源节点ID 18 | Target string `gorm:"column:target; type: varchar(128)" json:"target" form:"target"` // 目标节点ID 19 | Circulation string `gorm:"column:circulation; type: varchar(128)" json:"circulation" form:"circulation"` // 流转ID 20 | Status int `gorm:"column:status; type: int(11)" json:"status" form:"status"` // 流转状态 1 同意, 0 拒绝, 2 其他 21 | Processor string `gorm:"column:processor; type: varchar(45)" json:"processor" form:"processor"` // 处理人 22 | ProcessorId int `gorm:"column:processor_id; type: int(11)" json:"processor_id" form:"processor_id"` // 处理人ID 23 | CostDuration int64 `gorm:"column:cost_duration; type: int(11)" json:"cost_duration" form:"cost_duration"` // 处理时长 24 | Remarks string `gorm:"column:remarks; type: longtext" json:"remarks" form:"remarks"` // 备注 25 | } 26 | 27 | func (CirculationHistory) TableName() string { 28 | return "p_work_order_circulation_history" 29 | } 30 | -------------------------------------------------------------------------------- /models/process/classify.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import ( 4 | "ferry/models/base" 5 | ) 6 | 7 | /* 8 | @Author : lanyulei 9 | */ 10 | 11 | // 流程分类 12 | type Classify struct { 13 | base.Model 14 | Name string `gorm:"column:name; type: varchar(128)" json:"name" form:"name"` // 分类名称 15 | Creator int `gorm:"column:creator; type: int(11)" json:"creator" form:"creator"` // 创建者 16 | } 17 | 18 | func (Classify) TableName() string { 19 | return "p_process_classify" 20 | } 21 | -------------------------------------------------------------------------------- /models/process/history.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import ( 4 | "ferry/models/base" 5 | ) 6 | 7 | /* 8 | @Author : lanyulei 9 | */ 10 | 11 | // 任务 12 | type History struct { 13 | base.Model 14 | Task int `gorm:"column:task; type: int(11)" json:"task" form:"task"` // 任务ID 15 | Name string `gorm:"column:name; type: varchar(256)" json:"name" form:"name"` // 任务名称 16 | TaskType int `gorm:"column:task_type; type: int(11)" json:"task_type" form:"task_type"` // 任务类型, python, shell 17 | ExecutionTime string `gorm:"column:execution_time; type: varchar(128)" json:"execution_time" form:"execution_time"` // 执行时间 18 | Result string `gorm:"column:result; type: longtext" json:"result" form:"result"` // 任务返回 19 | } 20 | 21 | func (History) TableName() string { 22 | return "p_task_history" 23 | } 24 | -------------------------------------------------------------------------------- /models/process/process.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import ( 4 | "encoding/json" 5 | "ferry/models/base" 6 | ) 7 | 8 | /* 9 | @Author : lanyulei 10 | */ 11 | 12 | // 流程 13 | type Info struct { 14 | base.Model 15 | Name string `gorm:"column:name; type:varchar(128)" json:"name" form:"name"` // 流程名称 16 | Icon string `gorm:"column:icon; type:varchar(128)" json:"icon" form:"icon"` // 流程标签 17 | Structure json.RawMessage `gorm:"column:structure; type:json" json:"structure" form:"structure"` // 流程结构 18 | Classify int `gorm:"column:classify; type:int(11)" json:"classify" form:"classify"` // 分类ID 19 | Tpls json.RawMessage `gorm:"column:tpls; type:json" json:"tpls" form:"tpls"` // 模版 20 | Task json.RawMessage `gorm:"column:task; type:json" json:"task" form:"task"` // 任务ID, array, 可执行多个任务,可以当成通知任务,每个节点都会去执行 21 | SubmitCount int `gorm:"column:submit_count; type:int(11); default:0" json:"submit_count" form:"submit_count"` // 提交统计 22 | Creator int `gorm:"column:creator; type:int(11)" json:"creator" form:"creator"` // 创建者 23 | Notice json.RawMessage `gorm:"column:notice; type:json" json:"notice" form:"notice"` // 绑定通知 24 | Remarks string `gorm:"column:remarks; type:varchar(1024)" json:"remarks" form:"remarks"` // 流程备注 25 | } 26 | 27 | func (Info) TableName() string { 28 | return "p_process_info" 29 | } 30 | -------------------------------------------------------------------------------- /models/process/task.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import ( 4 | "ferry/models/base" 5 | ) 6 | 7 | /* 8 | @Author : lanyulei 9 | */ 10 | 11 | // 任务 12 | type TaskInfo struct { 13 | base.Model 14 | Name string `gorm:"column:name; type: varchar(256)" json:"name" form:"name"` // 任务名称 15 | TaskType string `gorm:"column:task_type; type: varchar(45)" json:"task_type" form:"task_type"` // 任务类型 16 | Content string `gorm:"column:content; type: longtext" json:"content" form:"content"` // 任务内容 17 | Creator int `gorm:"column:creator; type: int(11)" json:"creator" form:"creator"` // 创建者 18 | Remarks string `gorm:"column:remarks; type: longtext" json:"remarks" form:"remarks"` // 备注 19 | } 20 | 21 | func (TaskInfo) TableName() string { 22 | return "p_task_info" 23 | } 24 | -------------------------------------------------------------------------------- /models/process/tpl.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import ( 4 | "encoding/json" 5 | "ferry/models/base" 6 | ) 7 | 8 | /* 9 | @Author : lanyulei 10 | */ 11 | 12 | // 模板 13 | type TplInfo struct { 14 | base.Model 15 | Name string `gorm:"column:name; type: varchar(128)" json:"name" form:"name" binding:"required"` // 模板名称 16 | FormStructure json.RawMessage `gorm:"column:form_structure; type: json" json:"form_structure" form:"form_structure" binding:"required"` // 表单结构 17 | Creator int `gorm:"column:creator; type: int(11)" json:"creator" form:"creator"` // 创建者 18 | Remarks string `gorm:"column:remarks; type: longtext" json:"remarks" form:"remarks"` // 备注 19 | } 20 | 21 | func (TplInfo) TableName() string { 22 | return "p_tpl_info" 23 | } 24 | -------------------------------------------------------------------------------- /models/process/tplData.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import ( 4 | "encoding/json" 5 | "ferry/models/base" 6 | ) 7 | 8 | /* 9 | @Author : lanyulei 10 | */ 11 | 12 | // 工单绑定模版数据 13 | type TplData struct { 14 | base.Model 15 | WorkOrder int `gorm:"column:work_order; type: int(11)" json:"work_order" form:"work_order"` // 工单ID 16 | FormStructure json.RawMessage `gorm:"column:form_structure; type: json" json:"form_structure" form:"form_structure"` // 表单结构 17 | FormData json.RawMessage `gorm:"column:form_data; type: json" json:"form_data" form:"form_data"` // 表单数据 18 | } 19 | 20 | func (TplData) TableName() string { 21 | return "p_work_order_tpl_data" 22 | } 23 | -------------------------------------------------------------------------------- /models/process/workOrder.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import ( 4 | "encoding/json" 5 | "ferry/models/base" 6 | ) 7 | 8 | /* 9 | @Author : lanyulei 10 | */ 11 | 12 | // 工单 13 | type WorkOrderInfo struct { 14 | base.Model 15 | Title string `gorm:"column:title; type:varchar(128)" json:"title" form:"title"` // 工单标题 16 | Priority int `gorm:"column:priority; type:int(11)" json:"priority" form:"priority"` // 工单优先级 1,正常 2,紧急 3,非常紧急 17 | Process int `gorm:"column:process; type:int(11)" json:"process" form:"process"` // 流程ID 18 | Classify int `gorm:"column:classify; type:int(11)" json:"classify" form:"classify"` // 分类ID 19 | IsEnd int `gorm:"column:is_end; type:int(11); default:0" json:"is_end" form:"is_end"` // 是否结束, 0 未结束,1 已结束 20 | IsDenied int `gorm:"column:is_denied; type:int(11); default:0" json:"is_denied" form:"is_denied"` // 是否被拒绝, 0 没有,1 有 21 | State json.RawMessage `gorm:"column:state; type:json" json:"state" form:"state"` // 状态信息 22 | RelatedPerson json.RawMessage `gorm:"column:related_person; type:json" json:"related_person" form:"related_person"` // 工单所有处理人 23 | Creator int `gorm:"column:creator; type:int(11)" json:"creator" form:"creator"` // 创建人 24 | UrgeCount int `gorm:"column:urge_count; type:int(11); default:0" json:"urge_count" form:"urge_count"` // 催办次数 25 | UrgeLastTime int `gorm:"column:urge_last_time; type:int(11); default:0" json:"urge_last_time" form:"urge_last_time"` // 上一次催促时间 26 | } 27 | 28 | func (WorkOrderInfo) TableName() string { 29 | return "p_work_order_info" 30 | } 31 | -------------------------------------------------------------------------------- /models/system/casbinrule.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | /* 4 | @Author : lanyulei 5 | */ 6 | 7 | //casbin_rule 8 | type CasbinRule struct { 9 | PType string `json:"p_type" gorm:"type:varchar(100);"` 10 | V0 string `json:"v0" gorm:"type:varchar(100);"` 11 | V1 string `json:"v1" gorm:"type:varchar(100);"` 12 | V2 string `json:"v2" gorm:"type:varchar(100);"` 13 | V3 string `json:"v3" gorm:"type:varchar(100);"` 14 | V4 string `json:"v4" gorm:"type:varchar(100);"` 15 | V5 string `json:"v5" gorm:"type:varchar(100);"` 16 | Id int `gorm:"primary_key;AUTO_INCREMENT;column:id" json:"id" form:"id"` 17 | BaseModel 18 | } 19 | 20 | func (CasbinRule) TableName() string { 21 | return "casbin_rule" 22 | } 23 | -------------------------------------------------------------------------------- /models/system/initdb.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "ferry/global/orm" 5 | "fmt" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | /* 11 | @Author : lanyulei 12 | */ 13 | 14 | func InitDb() error { 15 | filePath := "config/db.sql" 16 | sql, err := Ioutil(filePath) 17 | if err != nil { 18 | fmt.Println("数据库基础数据初始化脚本读取失败!原因:", err.Error()) 19 | return err 20 | } 21 | sqlList := strings.Split(sql, ";") 22 | for _, sql := range sqlList { 23 | if strings.Contains(sql, "--") { 24 | fmt.Println(sql) 25 | continue 26 | } 27 | sqlValue := strings.Replace(sql+";", "\n", "", 1) 28 | if err = orm.Eloquent.Exec(sqlValue).Error; err != nil { 29 | if !strings.Contains(err.Error(), "Query was empty") { 30 | return err 31 | } 32 | } 33 | } 34 | return nil 35 | } 36 | 37 | func Ioutil(name string) (string, error) { 38 | if contents, err := os.ReadFile(name); err == nil { 39 | //因为contents是[]byte类型,直接转换成string类型后会多一行空格,需要使用strings.Replace替换换行符 40 | result := strings.Replace(string(contents), "\n", "", 1) 41 | return result, nil 42 | } else { 43 | return "", err 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /models/system/login.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "ferry/global/orm" 5 | "ferry/tools" 6 | ) 7 | 8 | /* 9 | @Author : lanyulei 10 | */ 11 | 12 | type Login struct { 13 | Username string `form:"UserName" json:"username" binding:"required"` 14 | Password string `form:"Password" json:"password" binding:"required"` 15 | Code string `form:"Code" json:"code"` 16 | UUID string `form:"UUID" json:"uuid"` 17 | LoginType int `form:"LoginType" json:"loginType"` 18 | } 19 | 20 | func (u *Login) GetUser() (user SysUser, role SysRole, e error) { 21 | 22 | e = orm.Eloquent.Table("sys_user").Where("username = ? ", u.Username).Find(&user).Error 23 | if e != nil { 24 | return 25 | } 26 | 27 | // 验证密码 28 | if u.LoginType == 0 { 29 | _, e = tools.CompareHashAndPassword(user.Password, u.Password) 30 | if e != nil { 31 | return 32 | } 33 | } 34 | 35 | e = orm.Eloquent.Table("sys_role").Where("role_id = ? ", user.RoleId).First(&role).Error 36 | if e != nil { 37 | return 38 | } 39 | return 40 | } 41 | -------------------------------------------------------------------------------- /models/system/model.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | /* 4 | @Author : lanyulei 5 | */ 6 | import ( 7 | "time" 8 | ) 9 | 10 | type BaseModel struct { 11 | CreatedAt time.Time `gorm:"column:create_time" json:"create_time" form:"create_time"` 12 | UpdatedAt time.Time `gorm:"column:update_time" json:"update_time" form:"update_time"` 13 | DeletedAt *time.Time `gorm:"column:delete_time" sql:"index" json:"-"` 14 | } 15 | -------------------------------------------------------------------------------- /models/system/roledept.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "ferry/global/orm" 5 | "fmt" 6 | ) 7 | 8 | /* 9 | @Author : lanyulei 10 | */ 11 | 12 | //sys_role_dept 13 | type SysRoleDept struct { 14 | RoleId int `gorm:"type:int(11)"` 15 | DeptId int `gorm:"type:int(11)"` 16 | Id int `gorm:"primary_key;AUTO_INCREMENT;column:id" json:"id" form:"id"` 17 | } 18 | 19 | func (SysRoleDept) TableName() string { 20 | return "sys_role_dept" 21 | } 22 | 23 | func (rm *SysRoleDept) Insert(roleId int, deptIds []int) (bool, error) { 24 | //ORM不支持批量插入所以需要拼接 sql 串 25 | sql := "INSERT INTO `sys_role_dept` (`role_id`,`dept_id`) VALUES " 26 | 27 | for i := 0; i < len(deptIds); i++ { 28 | if len(deptIds)-1 == i { 29 | //最后一条数据 以分号结尾 30 | sql += fmt.Sprintf("(%d,%d);", roleId, deptIds[i]) 31 | } else { 32 | sql += fmt.Sprintf("(%d,%d),", roleId, deptIds[i]) 33 | } 34 | } 35 | orm.Eloquent.Exec(sql) 36 | 37 | return true, nil 38 | } 39 | 40 | func (rm *SysRoleDept) DeleteRoleDept(roleId int) (bool, error) { 41 | if err := orm.Eloquent.Table("sys_role_dept").Where("role_id = ?", roleId).Delete(&rm).Error; err != nil { 42 | return false, err 43 | } 44 | var role SysRole 45 | if err := orm.Eloquent.Table("sys_role").Where("role_id = ?", roleId).First(&role).Error; err != nil { 46 | return false, err 47 | } 48 | 49 | return true, nil 50 | 51 | } 52 | -------------------------------------------------------------------------------- /models/system/settings.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "encoding/json" 5 | "ferry/models/base" 6 | ) 7 | 8 | /* 9 | @Author : lanyulei 10 | */ 11 | 12 | // 配置信息 13 | type Settings struct { 14 | base.Model 15 | Classify int `gorm:"column:classify; type:int(11)" json:"classify" form:"classify"` // 设置分类,1 配置信息,2 Ldap配置 16 | Content json.RawMessage `gorm:"column:content; type:json" json:"content" form:"content"` // 配置内容 17 | } 18 | 19 | func (Settings) TableName() string { 20 | return "sys_settings" 21 | } 22 | -------------------------------------------------------------------------------- /pkg/casbin/mycasbin.go: -------------------------------------------------------------------------------- 1 | package mycasbin 2 | 3 | import ( 4 | "ferry/global/orm" 5 | "ferry/pkg/logger" 6 | "ferry/tools/config" 7 | 8 | "github.com/casbin/casbin/v2" 9 | gormadapter "github.com/casbin/gorm-adapter/v2" 10 | "github.com/go-kit/kit/endpoint" 11 | _ "github.com/go-sql-driver/mysql" 12 | ) 13 | 14 | var _ endpoint.Middleware 15 | 16 | func Casbin() (*casbin.Enforcer, error) { 17 | conn := orm.MysqlConn 18 | Apter, err := gormadapter.NewAdapter(config.DatabaseConfig.Dbtype, conn, true) 19 | if err != nil { 20 | return nil, err 21 | } 22 | e, err := casbin.NewEnforcer("config/rbac_model.conf", Apter) 23 | if err != nil { 24 | return nil, err 25 | } 26 | if err := e.LoadPolicy(); err == nil { 27 | return e, err 28 | } else { 29 | logger.Infof("casbin rbac_model or policy init error, message: %v \r\n", err.Error()) 30 | return nil, err 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /pkg/jsonTime/JSONTime.go: -------------------------------------------------------------------------------- 1 | /* 2 | @Author : lanyulei 3 | */ 4 | 5 | package jsonTime 6 | 7 | import ( 8 | "database/sql/driver" 9 | "fmt" 10 | "time" 11 | ) 12 | 13 | // 重写MarshalJSON实现models json返回的时间格式 14 | type JSONTime struct { 15 | time.Time 16 | } 17 | 18 | func (t JSONTime) MarshalJSON() ([]byte, error) { 19 | formatted := fmt.Sprintf("\"%s\"", t.Format("2006-01-02 15:04:05")) 20 | return []byte(formatted), nil 21 | } 22 | 23 | func (t JSONTime) Value() (driver.Value, error) { 24 | var zeroTime time.Time 25 | if t.Time.UnixNano() == zeroTime.UnixNano() { 26 | return nil, nil 27 | } 28 | return t.Time, nil 29 | } 30 | 31 | func (t *JSONTime) Scan(v interface{}) error { 32 | value, ok := v.(time.Time) 33 | if ok { 34 | *t = JSONTime{Time: value} 35 | return nil 36 | } 37 | return fmt.Errorf("无法转换 %v 的时间格式", v) 38 | } 39 | -------------------------------------------------------------------------------- /pkg/ldap/connection.go: -------------------------------------------------------------------------------- 1 | package ldap 2 | 3 | import ( 4 | "crypto/tls" 5 | "errors" 6 | "ferry/pkg/logger" 7 | "fmt" 8 | "time" 9 | 10 | "github.com/spf13/viper" 11 | 12 | "github.com/go-ldap/ldap/v3" 13 | ) 14 | 15 | /* 16 | @Author : lanyulei 17 | */ 18 | 19 | var conn *ldap.Conn 20 | 21 | // ldap连接 22 | func ldapConnection() (err error) { 23 | var ldapConn = fmt.Sprintf("%v:%v", viper.GetString("settings.ldap.host"), viper.GetString("settings.ldap.port")) 24 | 25 | if viper.GetBool("settings.ldap.tls") { 26 | tlsConf := &tls.Config{ 27 | InsecureSkipVerify: true, 28 | } 29 | conn, err = ldap.DialTLS("tcp", ldapConn, tlsConf) 30 | } else { 31 | conn, err = ldap.Dial("tcp", ldapConn) 32 | } 33 | if err != nil { 34 | err = errors.New(fmt.Sprintf("无法连接到ldap服务器,%v", err)) 35 | logger.Error(err) 36 | return 37 | } 38 | 39 | //设置超时时间 40 | conn.SetTimeout(5 * time.Second) 41 | 42 | return 43 | } 44 | -------------------------------------------------------------------------------- /pkg/ldap/ldapFieldsMap.go: -------------------------------------------------------------------------------- 1 | package ldap 2 | 3 | import ( 4 | "ferry/models/system" 5 | 6 | "github.com/go-ldap/ldap/v3" 7 | ) 8 | 9 | /* 10 | @Author : lanyulei 11 | */ 12 | 13 | func LdapFieldsMap(ldapUserInfo *ldap.Entry) (userInfo system.SysUser, err error) { 14 | var ( 15 | ldapFields []map[string]string 16 | ) 17 | 18 | ldapFields, err = getLdapFields() 19 | if err != nil { 20 | return 21 | } 22 | 23 | for _, v := range ldapFields { 24 | switch v["local_field_name"] { 25 | case "nick_name": 26 | userInfo.NickName = ldapUserInfo.GetAttributeValue(v["ldap_field_name"]) 27 | case "phone": 28 | userInfo.Phone = ldapUserInfo.GetAttributeValue(v["ldap_field_name"]) 29 | case "avatar": 30 | userInfo.Avatar = ldapUserInfo.GetAttributeValue(v["ldap_field_name"]) 31 | case "sex": 32 | userInfo.Sex = ldapUserInfo.GetAttributeValue(v["ldap_field_name"]) 33 | case "email": 34 | userInfo.Email = ldapUserInfo.GetAttributeValue(v["ldap_field_name"]) 35 | case "remark": 36 | userInfo.Remark = ldapUserInfo.GetAttributeValue(v["ldap_field_name"]) 37 | } 38 | } 39 | 40 | return 41 | } 42 | -------------------------------------------------------------------------------- /pkg/ldap/login.go: -------------------------------------------------------------------------------- 1 | package ldap 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/go-ldap/ldap/v3" 7 | ) 8 | 9 | /* 10 | @Author : lanyulei 11 | */ 12 | 13 | func LdapLogin(username string, password string) (userInfo *ldap.Entry, err error) { 14 | err = ldapConnection() 15 | if err != nil { 16 | return 17 | } 18 | defer conn.Close() 19 | 20 | userInfo, err = searchRequest(username) 21 | if err != nil { 22 | return 23 | } 24 | 25 | err = conn.Bind(userInfo.DN, password) 26 | if err != nil { 27 | return nil, fmt.Errorf("用户或密码不正确。") 28 | } 29 | 30 | return 31 | } 32 | -------------------------------------------------------------------------------- /pkg/ldap/updatePwd.go: -------------------------------------------------------------------------------- 1 | package ldap 2 | 3 | import ( 4 | "ferry/pkg/logger" 5 | "fmt" 6 | 7 | "github.com/go-ldap/ldap/v3" 8 | "golang.org/x/text/encoding/unicode" 9 | 10 | "github.com/spf13/viper" 11 | ) 12 | 13 | /* 14 | @Author : lanyulei 15 | */ 16 | 17 | func LdapUpdatePwd(username string, oldPassword string, newPassword string) (err error) { 18 | err = ldapConnection() 19 | if err != nil { 20 | return 21 | } 22 | defer conn.Close() 23 | 24 | var userDn = fmt.Sprintf("cn=%v,%v", username, viper.GetString("settings.ldap.baseDn")) 25 | 26 | err = conn.Bind(userDn, oldPassword) 27 | if err != nil { 28 | logger.Error("用户或密码错误。", err) 29 | return 30 | } 31 | 32 | sql2 := ldap.NewModifyRequest(userDn, nil) 33 | 34 | utf16 := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM) 35 | pwdEncoded, _ := utf16.NewEncoder().String(newPassword) 36 | 37 | sql2.Replace("unicodePwd", []string{pwdEncoded}) 38 | sql2.Replace("userAccountControl", []string{"512"}) 39 | 40 | if err = conn.Modify(sql2); err != nil { 41 | logger.Error("密码修改失败,%v", err.Error()) 42 | return 43 | } 44 | 45 | return 46 | } 47 | -------------------------------------------------------------------------------- /pkg/notify/email/email.go: -------------------------------------------------------------------------------- 1 | package email 2 | 3 | /* 4 | @Author : lanyulei 5 | @Desc : 发送邮件 6 | */ 7 | 8 | import ( 9 | "ferry/pkg/logger" 10 | "strconv" 11 | 12 | "github.com/spf13/viper" 13 | 14 | "gopkg.in/gomail.v2" 15 | ) 16 | 17 | func server(mailTo []string, ccTo []string, subject, body string, args ...string) error { 18 | //定义邮箱服务器连接信息,如果是网易邮箱 pass填密码,qq邮箱填授权码 19 | mailConn := map[string]string{ 20 | "user": viper.GetString("settings.email.user"), 21 | "pass": viper.GetString("settings.email.pass"), 22 | "host": viper.GetString("settings.email.host"), 23 | "port": viper.GetString("settings.email.port"), 24 | } 25 | 26 | port, _ := strconv.Atoi(mailConn["port"]) //转换端口类型为int 27 | 28 | m := gomail.NewMessage() 29 | 30 | m.SetHeader("From", m.FormatAddress(mailConn["user"], viper.GetString("settings.email.alias"))) //这种方式可以添加别名,即“XX官方” 31 | m.SetHeader("To", mailTo...) //发送给多个用户 32 | m.SetHeader("Cc", ccTo...) //发送给多个用户 33 | m.SetHeader("Subject", subject) //设置邮件主题 34 | m.SetBody("text/html", body) //设置邮件正文 35 | 36 | d := gomail.NewDialer(mailConn["host"], port, mailConn["user"], mailConn["pass"]) 37 | err := d.DialAndSend(m) 38 | return err 39 | 40 | } 41 | 42 | func SendMail(mailTo []string, ccTo []string, subject, body string) { 43 | err := server(mailTo, ccTo, subject, body) 44 | if err != nil { 45 | logger.Info(err) 46 | return 47 | } 48 | logger.Info("send successfully") 49 | } 50 | -------------------------------------------------------------------------------- /pkg/pagination/params.go: -------------------------------------------------------------------------------- 1 | package pagination 2 | 3 | import ( 4 | "ferry/pkg/logger" 5 | 6 | "github.com/gin-gonic/gin" 7 | ) 8 | 9 | /* 10 | @Author : lanyulei 11 | */ 12 | 13 | func RequestParams(c *gin.Context) map[string]interface{} { 14 | params := make(map[string]interface{}, 10) 15 | 16 | if c.Request.Form == nil { 17 | if err := c.Request.ParseMultipartForm(32 << 20); err != nil { 18 | logger.Error(err) 19 | } 20 | } 21 | 22 | if len(c.Request.Form) > 0 { 23 | for key, value := range c.Request.Form { 24 | if key == "page" || key == "per_page" || key == "sort" { 25 | continue 26 | } 27 | params[key] = value[0] 28 | } 29 | } 30 | 31 | return params 32 | } 33 | -------------------------------------------------------------------------------- /pkg/service/getState.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | /* 8 | @Author : lanyulei 9 | @Desc : 获取节点数据 10 | */ 11 | 12 | type ProcessState struct { 13 | Structure map[string][]map[string]interface{} 14 | } 15 | 16 | // 获取节点信息 17 | func (p *ProcessState) GetNode(stateId string) (nodeValue map[string]interface{}, err error) { 18 | for _, node := range p.Structure["nodes"] { 19 | if node["id"] == stateId { 20 | nodeValue = node 21 | } 22 | } 23 | return 24 | } 25 | 26 | // 获取流转信息 27 | func (p *ProcessState) GetEdge(stateId string, classify string) (edgeValue []map[string]interface{}, err error) { 28 | var ( 29 | leftSort int 30 | rightSort int 31 | ) 32 | 33 | for _, edge := range p.Structure["edges"] { 34 | if edge[classify] == stateId { 35 | edgeValue = append(edgeValue, edge) 36 | } 37 | } 38 | 39 | // 排序 40 | if len(edgeValue) > 1 { 41 | for i := 0; i < len(edgeValue)-1; i++ { 42 | for j := i + 1; j < len(edgeValue); j++ { 43 | if t, ok := edgeValue[i]["sort"]; ok { 44 | leftSort, _ = strconv.Atoi(t.(string)) 45 | } 46 | if t, ok := edgeValue[j]["sort"]; ok { 47 | rightSort, _ = strconv.Atoi(t.(string)) 48 | } 49 | if leftSort > rightSort { 50 | edgeValue[j], edgeValue[i] = edgeValue[i], edgeValue[j] 51 | } 52 | } 53 | } 54 | } 55 | 56 | return 57 | } 58 | -------------------------------------------------------------------------------- /pkg/service/getVariableValue.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "ferry/global/orm" 5 | "ferry/models/system" 6 | ) 7 | 8 | /* 9 | @Author : lanyulei 10 | */ 11 | 12 | func GetVariableValue(stateList []interface{}, creator int) (err error) { 13 | var ( 14 | userInfo system.SysUser 15 | deptInfo system.Dept 16 | ) 17 | 18 | // 变量转为实际的数据 19 | for _, stateItem := range stateList { 20 | if stateItem.(map[string]interface{})["process_method"] == "variable" { 21 | for processorIndex, processor := range stateItem.(map[string]interface{})["processor"].([]interface{}) { 22 | if int(processor.(float64)) == 1 { 23 | // 创建者 24 | stateItem.(map[string]interface{})["processor"].([]interface{})[processorIndex] = creator 25 | } else if int(processor.(float64)) == 2 { 26 | // 1. 查询用户信息 27 | err = orm.Eloquent.Model(&userInfo).Where("user_id = ?", creator).Find(&userInfo).Error 28 | if err != nil { 29 | return 30 | } 31 | // 2. 查询部门信息 32 | err = orm.Eloquent.Model(&deptInfo).Where("dept_id = ?", userInfo.DeptId).Find(&deptInfo).Error 33 | if err != nil { 34 | return 35 | } 36 | 37 | // 3. 替换处理人信息 38 | stateItem.(map[string]interface{})["processor"].([]interface{})[processorIndex] = deptInfo.Leader 39 | } 40 | } 41 | stateItem.(map[string]interface{})["process_method"] = "person" 42 | } 43 | } 44 | 45 | return 46 | } 47 | -------------------------------------------------------------------------------- /pkg/service/task.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "ferry/pkg/task" 5 | "fmt" 6 | "strings" 7 | 8 | "github.com/spf13/viper" 9 | ) 10 | 11 | /* 12 | @Author : lanyulei 13 | */ 14 | 15 | func ExecTask(taskList []string, params string) { 16 | for _, taskName := range taskList { 17 | filePath := fmt.Sprintf("%v/%v", viper.GetString("script.path"), taskName) 18 | if strings.HasSuffix(filePath, ".py") { 19 | task.Send("python", filePath, params) 20 | } else if strings.HasSuffix(filePath, ".sh") { 21 | task.Send("shell", filePath, params) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pkg/settings/get_content.go: -------------------------------------------------------------------------------- 1 | package settings 2 | 3 | import ( 4 | "encoding/json" 5 | "ferry/global/orm" 6 | "ferry/models/system" 7 | ) 8 | 9 | func GetContent(classify int) (content map[string]interface{}, err error) { 10 | var ( 11 | settings system.Settings 12 | ) 13 | 14 | err = orm.Eloquent.Where("classify = ?", classify).Find(&settings).Error 15 | if err != nil { 16 | return 17 | } 18 | 19 | err = json.Unmarshal(settings.Content, &content) 20 | if err != nil { 21 | return 22 | } 23 | 24 | return 25 | } 26 | 27 | func GetContentByKey(classify int, key string) (value interface{}, err error) { 28 | var ( 29 | content map[string]interface{} 30 | ) 31 | 32 | content, err = GetContent(classify) 33 | if err != nil { 34 | return 35 | } 36 | 37 | value = content[key] 38 | 39 | return 40 | } 41 | -------------------------------------------------------------------------------- /pkg/task/send.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | /* 4 | @Author : lanyulei 5 | */ 6 | 7 | import ( 8 | "context" 9 | "ferry/pkg/task/worker" 10 | ) 11 | 12 | func Send(classify string, scriptPath string, params string) { 13 | worker.SendTask(context.Background(), classify, scriptPath, params) 14 | } 15 | -------------------------------------------------------------------------------- /pkg/task/server.go: -------------------------------------------------------------------------------- 1 | package task 2 | 3 | /* 4 | @Author : lanyulei 5 | */ 6 | 7 | import ( 8 | "ferry/pkg/logger" 9 | "ferry/pkg/task/worker" 10 | ) 11 | 12 | func Start() { 13 | // 1. 启动服务,连接redis 14 | worker.StartServer() 15 | 16 | // 2. 启动异步调度 17 | taskWorker := worker.NewAsyncTaskWorker(10) 18 | err := taskWorker.Launch() 19 | if err != nil { 20 | logger.Errorf("启动machinery失败,%v", err.Error()) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /pkg/task/worker/worker.go: -------------------------------------------------------------------------------- 1 | package worker 2 | 3 | import ( 4 | "ferry/pkg/logger" 5 | 6 | "github.com/spf13/viper" 7 | 8 | "github.com/RichardKnop/machinery/v1" 9 | taskConfig "github.com/RichardKnop/machinery/v1/config" 10 | "github.com/RichardKnop/machinery/v1/tasks" 11 | ) 12 | 13 | var AsyncTaskCenter *machinery.Server 14 | 15 | func StartServer() { 16 | tc, err := NewTaskCenter() 17 | if err != nil { 18 | panic(err) 19 | } 20 | AsyncTaskCenter = tc 21 | } 22 | 23 | func NewTaskCenter() (*machinery.Server, error) { 24 | cnf := &taskConfig.Config{ 25 | Broker: viper.GetString("settings.redis.url"), 26 | DefaultQueue: "ServerTasksQueue", 27 | ResultBackend: "eager", 28 | } 29 | server, err := machinery.NewServer(cnf) 30 | if err != nil { 31 | return nil, err 32 | } 33 | initAsyncTaskMap() 34 | return server, server.RegisterTasks(asyncTaskMap) 35 | } 36 | 37 | func NewAsyncTaskWorker(concurrency int) *machinery.Worker { 38 | consumerTag := "TaskWorker" 39 | worker := AsyncTaskCenter.NewWorker(consumerTag, concurrency) 40 | errorHandler := func(err error) { 41 | logger.Error("执行失败: ", err) 42 | } 43 | preTaskHandler := func(signature *tasks.Signature) { 44 | logger.Info("开始执行: ", signature.Name) 45 | } 46 | postTaskHandler := func(signature *tasks.Signature) { 47 | logger.Info("执行结束: ", signature.Name) 48 | } 49 | worker.SetPostTaskHandler(postTaskHandler) 50 | worker.SetErrorHandler(errorHandler) 51 | worker.SetPreTaskHandler(preTaskHandler) 52 | return worker 53 | } 54 | -------------------------------------------------------------------------------- /pkg/utils/file.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "io/ioutil" 5 | "mime/multipart" 6 | "os" 7 | "path" 8 | ) 9 | 10 | // 获取文件大小 11 | func GetSize(f multipart.File) (int, error) { 12 | content, err := ioutil.ReadAll(f) 13 | 14 | return len(content), err 15 | } 16 | 17 | // 获取文件后缀 18 | func GetExt(fileName string) string { 19 | return path.Ext(fileName) 20 | } 21 | 22 | //检查文件是否存在 23 | func CheckExist(src string) bool { 24 | _, err := os.Stat(src) 25 | 26 | return os.IsNotExist(err) 27 | } 28 | 29 | // 检查文件权限 30 | func CheckPermission(src string) bool { 31 | _, err := os.Stat(src) 32 | 33 | return os.IsPermission(err) 34 | } 35 | 36 | //如果不存在则新建文件夹 37 | func IsNotExistMkDir(src string) error { 38 | if exist := CheckExist(src); exist == false { 39 | if err := MkDir(src); err != nil { 40 | return err 41 | } 42 | } 43 | 44 | return nil 45 | } 46 | 47 | //新建文件夹 48 | func MkDir(src string) error { 49 | err := os.MkdirAll(src, os.ModePerm) 50 | if err != nil { 51 | return err 52 | } 53 | 54 | return nil 55 | } 56 | 57 | // 打开文件 58 | func Open(name string, flag int, perm os.FileMode) (*os.File, error) { 59 | f, err := os.OpenFile(name, flag, perm) 60 | if err != nil { 61 | return nil, err 62 | } 63 | 64 | return f, nil 65 | } 66 | -------------------------------------------------------------------------------- /router/dashboard/dashboard.go: -------------------------------------------------------------------------------- 1 | package dashboard 2 | 3 | import ( 4 | "ferry/apis/dashboard" 5 | "ferry/middleware" 6 | jwt "ferry/pkg/jwtauth" 7 | 8 | "github.com/gin-gonic/gin" 9 | ) 10 | 11 | /* 12 | @Author : lanyulei 13 | */ 14 | 15 | func RegisterDashboardRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { 16 | classify := v1.Group("/dashboard").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) 17 | { 18 | classify.GET("", dashboard.InitData) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /router/init_router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "ferry/handler" 5 | "ferry/middleware" 6 | _ "ferry/pkg/jwtauth" 7 | "ferry/tools" 8 | config2 "ferry/tools/config" 9 | 10 | "github.com/gin-gonic/gin" 11 | ) 12 | 13 | func InitRouter() *gin.Engine { 14 | 15 | r := gin.New() 16 | if config2.ApplicationConfig.IsHttps { 17 | r.Use(handler.TlsHandler()) 18 | } 19 | middleware.InitMiddleware(r) 20 | // the jwt middleware 21 | authMiddleware, err := middleware.AuthInit() 22 | tools.HasError(err, "JWT Init Error", 500) 23 | 24 | // 注册系统路由 25 | InitSysRouter(r, authMiddleware) 26 | 27 | return r 28 | } 29 | -------------------------------------------------------------------------------- /router/process/classify.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | /* 4 | @Author : lanyulei 5 | */ 6 | 7 | import ( 8 | "ferry/apis/process" 9 | "ferry/middleware" 10 | jwt "ferry/pkg/jwtauth" 11 | 12 | "github.com/gin-gonic/gin" 13 | ) 14 | 15 | func RegisterClassifyRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { 16 | classify := v1.Group("/classify").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) 17 | { 18 | classify.GET("", process.ClassifyList) 19 | classify.POST("", process.CreateClassify) 20 | classify.PUT("", process.UpdateClassify) 21 | classify.DELETE("", process.DeleteClassify) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /router/process/process.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | /* 4 | @Author : lanyulei 5 | */ 6 | 7 | import ( 8 | "ferry/apis/process" 9 | "ferry/middleware" 10 | jwt "ferry/pkg/jwtauth" 11 | 12 | "github.com/gin-gonic/gin" 13 | ) 14 | 15 | func RegisterProcessRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { 16 | processRouter := v1.Group("/process").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) 17 | { 18 | processRouter.GET("/classify", process.ClassifyProcessList) 19 | processRouter.GET("", process.ProcessList) 20 | processRouter.POST("", process.CreateProcess) 21 | processRouter.PUT("", process.UpdateProcess) 22 | processRouter.DELETE("", process.DeleteProcess) 23 | processRouter.GET("/details", process.ProcessDetails) 24 | processRouter.POST("/clone/:id", process.CloneProcess) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /router/process/task.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import ( 4 | "ferry/apis/process" 5 | "ferry/middleware" 6 | jwt "ferry/pkg/jwtauth" 7 | 8 | "github.com/gin-gonic/gin" 9 | ) 10 | 11 | /* 12 | @Author : lanyulei 13 | */ 14 | 15 | func RegisterTaskRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { 16 | taskRouter := v1.Group("/task").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) 17 | { 18 | taskRouter.GET("", process.TaskList) 19 | taskRouter.GET("/details", process.TaskDetails) 20 | taskRouter.POST("", process.CreateTask) 21 | taskRouter.PUT("", process.UpdateTask) 22 | taskRouter.DELETE("", process.DeleteTask) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /router/process/tpl.go: -------------------------------------------------------------------------------- 1 | /* 2 | @Author : lanyulei 3 | */ 4 | 5 | package process 6 | 7 | import ( 8 | "ferry/apis/process" 9 | "ferry/middleware" 10 | 11 | //"ferry/apis/process" 12 | //"ferry/middleware" 13 | jwt "ferry/pkg/jwtauth" 14 | 15 | "github.com/gin-gonic/gin" 16 | ) 17 | 18 | func RegisterTplRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { 19 | tplRouter := v1.Group("/tpl").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) 20 | { 21 | tplRouter.GET("", process.TemplateList) 22 | tplRouter.POST("", process.CreateTemplate) 23 | tplRouter.PUT("", process.UpdateTemplate) 24 | tplRouter.DELETE("", process.DeleteTemplate) 25 | tplRouter.GET("/details", process.TemplateDetails) 26 | tplRouter.POST("/clone/:id", process.CloneTemplate) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /router/process/workOrder.go: -------------------------------------------------------------------------------- 1 | /* 2 | @Author : lanyulei 3 | */ 4 | 5 | package process 6 | 7 | import ( 8 | "ferry/apis/process" 9 | "ferry/middleware" 10 | jwt "ferry/pkg/jwtauth" 11 | 12 | "github.com/gin-gonic/gin" 13 | ) 14 | 15 | func RegisterWorkOrderRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { 16 | workOrderRouter := v1.Group("/work-order").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) 17 | { 18 | workOrderRouter.GET("/process-structure", process.ProcessStructure) 19 | workOrderRouter.POST("/create", process.CreateWorkOrder) 20 | workOrderRouter.GET("/list", process.WorkOrderList) 21 | workOrderRouter.POST("/handle", process.ProcessWorkOrder) 22 | workOrderRouter.GET("/unity", process.UnityWorkOrder) 23 | workOrderRouter.POST("/inversion", process.InversionWorkOrder) 24 | workOrderRouter.GET("/urge", process.UrgeWorkOrder) 25 | workOrderRouter.PUT("/active-order/:id", process.ActiveOrder) 26 | workOrderRouter.DELETE("/delete/:id", process.DeleteWorkOrder) 27 | workOrderRouter.POST("/reopen/:id", process.ReopenWorkOrder) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /static/scripts/echo_test-4171bc7f4a05-admin.sh: -------------------------------------------------------------------------------- 1 | echo "test" -------------------------------------------------------------------------------- /static/scripts/print_hello_world-d266ee2a8029-admin.py: -------------------------------------------------------------------------------- 1 | print("Hello, World!") -------------------------------------------------------------------------------- /static/template/email.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ferry 6 | 7 | 8 |
9 | {{ .Description }}: 10 |
11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
标题:{{ .Title }}
申请人:{{ .Creator }}
优先级:{{ .PriorityValue }}
申请时间:{{ .CreatedAt }}
30 | 31 |
32 | 点击此处跳转到工单详情 33 | 34 | 44 | -------------------------------------------------------------------------------- /static/web/036680d9c1d332cf478c5823cd2a47db.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/groovy"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/06d453ace473034cd357edb758d539ab.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/csound_document",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "# \n\ 5 | snippet synth\n\ 6 | \n\ 7 | \n\ 8 | ${1}\n\ 9 | \n\ 10 | \n\ 11 | e\n\ 12 | \n\ 13 | \n\ 14 | "; 15 | exports.scope = "csound_document"; 16 | 17 | }); (function() { 18 | ace.require(["ace/snippets/csound_document"], function(m) { 19 | if (typeof module == "object" && typeof exports == "object" && module) { 20 | module.exports = m; 21 | } 22 | }); 23 | })(); 24 | -------------------------------------------------------------------------------- /static/web/0870bcf868f8d64dc9a6226a6c8b341d.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/snippets",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "# snippets for making snippets :)\n\ 5 | snippet snip\n\ 6 | snippet ${1:trigger}\n\ 7 | ${2}\n\ 8 | snippet msnip\n\ 9 | snippet ${1:trigger} ${2:description}\n\ 10 | ${3}\n\ 11 | snippet v\n\ 12 | {VISUAL}\n\ 13 | "; 14 | exports.scope = "snippets"; 15 | 16 | }); (function() { 17 | ace.require(["ace/snippets/snippets"], function(m) { 18 | if (typeof module == "object" && typeof exports == "object" && module) { 19 | module.exports = m; 20 | } 21 | }); 22 | })(); 23 | -------------------------------------------------------------------------------- /static/web/0c2b3b3b66a73e289e2ca47cf22ef150.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/csp"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/0dc486b4415f7cbd7ddde8f32b6f12f1.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/drools",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "\n\ 5 | snippet rule\n\ 6 | rule \"${1?:rule_name}\"\n\ 7 | when\n\ 8 | ${2:// when...} \n\ 9 | then\n\ 10 | ${3:// then...}\n\ 11 | end\n\ 12 | \n\ 13 | snippet query\n\ 14 | query ${1?:query_name}\n\ 15 | ${2:// find} \n\ 16 | end\n\ 17 | \n\ 18 | snippet declare\n\ 19 | declare ${1?:type_name}\n\ 20 | ${2:// attributes} \n\ 21 | end\n\ 22 | \n\ 23 | "; 24 | exports.scope = "drools"; 25 | 26 | }); (function() { 27 | ace.require(["ace/snippets/drools"], function(m) { 28 | if (typeof module == "object" && typeof exports == "object" && module) { 29 | module.exports = m; 30 | } 31 | }); 32 | })(); 33 | -------------------------------------------------------------------------------- /static/web/0dd0f45c3dde9af3fcf9706e6a2a1edd.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/slim"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/119d8ff08e82b0f391f59f1fe657130f.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/verilog"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/1295d4470d348d3ff8ea442b1dcef3d3.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/maze",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "snippet >\n\ 5 | description assignment\n\ 6 | scope maze\n\ 7 | -> ${1}= ${2}\n\ 8 | \n\ 9 | snippet >\n\ 10 | description if\n\ 11 | scope maze\n\ 12 | -> IF ${2:**} THEN %${3:L} ELSE %${4:R}\n\ 13 | "; 14 | exports.scope = "maze"; 15 | 16 | }); (function() { 17 | ace.require(["ace/snippets/maze"], function(m) { 18 | if (typeof module == "object" && typeof exports == "object" && module) { 19 | module.exports = m; 20 | } 21 | }); 22 | })(); 23 | -------------------------------------------------------------------------------- /static/web/13b157cfddcb9a76ae0800b47a8f0122.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/handlebars"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/142d258626093a8c3187029538e32bbc.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/stylus"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/144991c48dbba89bfe10e886aaaed32a.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/sql",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "snippet tbl\n\ 5 | create table ${1:table} (\n\ 6 | ${2:columns}\n\ 7 | );\n\ 8 | snippet col\n\ 9 | ${1:name} ${2:type} ${3:default ''} ${4:not null}\n\ 10 | snippet ccol\n\ 11 | ${1:name} varchar2(${2:size}) ${3:default ''} ${4:not null}\n\ 12 | snippet ncol\n\ 13 | ${1:name} number ${3:default 0} ${4:not null}\n\ 14 | snippet dcol\n\ 15 | ${1:name} date ${3:default sysdate} ${4:not null}\n\ 16 | snippet ind\n\ 17 | create index ${3:$1_$2} on ${1:table}(${2:column});\n\ 18 | snippet uind\n\ 19 | create unique index ${1:name} on ${2:table}(${3:column});\n\ 20 | snippet tblcom\n\ 21 | comment on table ${1:table} is '${2:comment}';\n\ 22 | snippet colcom\n\ 23 | comment on column ${1:table}.${2:column} is '${3:comment}';\n\ 24 | snippet addcol\n\ 25 | alter table ${1:table} add (${2:column} ${3:type});\n\ 26 | snippet seq\n\ 27 | create sequence ${1:name} start with ${2:1} increment by ${3:1} minvalue ${4:1};\n\ 28 | snippet s*\n\ 29 | select * from ${1:table}\n\ 30 | "; 31 | exports.scope = "sql"; 32 | 33 | }); (function() { 34 | ace.require(["ace/snippets/sql"], function(m) { 35 | if (typeof module == "object" && typeof exports == "object" && module) { 36 | module.exports = m; 37 | } 38 | }); 39 | })(); 40 | -------------------------------------------------------------------------------- /static/web/155500be4d3113e94dca99f997defb7a.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/sparql"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/17c85759d562794da4d2ff11f1b9b3bd.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/julia"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/1840080076c4078d157a5b05d0d95551.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/objectivec"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/18a893070398343ab529fdb7b62f1b6d.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/less"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/1afe87852eca4b28294075c659ff8c45.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/apex"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/1c9874850164cfdaa7e1d212d09124a7.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/tsx"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/1cb8df3a3416707163473b1ee9268faf.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/livescript"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/1f1abd5e247cf6b2e9a3db6303277572.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/batchfile"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/2031467f3d02be43b638c5e3ccba3996.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/scala"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/20f8061729d26f9786679bbf7af0b87a.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/gherkin"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/214a729dcea91ee8a56f8ef43e17243a.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/cobol"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/21dca974f7343f200597e43a55766c6e.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/mushcode"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/21fab653998af15bced8d4890e41bebc.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/perl6"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/242fb5a92733d151e9ca303fcd3ae7ff.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/scss"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/2681042a598b029b51d51f7669b81c4d.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/text"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/28f7c5b28bbad7b0bac0cc3cc5b89bad.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/red"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/2ac58492ad5a1b5244deb0fef1e5a773.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/sass"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/2bba99eb717e1aa22e45284a964ca73f.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/pig"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/31459a657ac30dcaa54765c6d76d8c81.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/soy_template"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/318f90759f2ff0d2a437350e87578172.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/dot"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/31bcb02e59d84ce2e38b85616a0b44db.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/redshift"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/31f3f1c32b27587832d28b634351325c.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/forth"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/330543be2120b9dcc9bec41ba5e05805.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/json5"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/34f05dc84111ffe37a1d5b5aacff7488.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/jade"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/35858a47038a7be957df49854e8e5eea.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/elixir"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/35dc4119f9e28cb9baba1475537460bb.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/visualforce"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/37e37aa178d97ffcd94eeee1e1a25967.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/abc",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "\n\ 5 | snippet zupfnoter.print\n\ 6 | %%%%hn.print {\"startpos\": ${1:pos_y}, \"t\":\"${2:title}\", \"v\":[${3:voices}], \"s\":[[${4:syncvoices}1,2]], \"f\":[${5:flowlines}], \"sf\":[${6:subflowlines}], \"j\":[${7:jumplines}]}\n\ 7 | \n\ 8 | snippet zupfnoter.note\n\ 9 | %%%%hn.note {\"pos\": [${1:pos_x},${2:pos_y}], \"text\": \"${3:text}\", \"style\": \"${4:style}\"}\n\ 10 | \n\ 11 | snippet zupfnoter.annotation\n\ 12 | %%%%hn.annotation {\"id\": \"${1:id}\", \"pos\": [${2:pos}], \"text\": \"${3:text}\"}\n\ 13 | \n\ 14 | snippet zupfnoter.lyrics\n\ 15 | %%%%hn.lyrics {\"pos\": [${1:x_pos},${2:y_pos}]}\n\ 16 | \n\ 17 | snippet zupfnoter.legend\n\ 18 | %%%%hn.legend {\"pos\": [${1:x_pos},${2:y_pos}]}\n\ 19 | \n\ 20 | \n\ 21 | \n\ 22 | snippet zupfnoter.target\n\ 23 | \"^:${1:target}\"\n\ 24 | \n\ 25 | snippet zupfnoter.goto\n\ 26 | \"^@${1:target}@${2:distance}\"\n\ 27 | \n\ 28 | snippet zupfnoter.annotationref\n\ 29 | \"^#${1:target}\"\n\ 30 | \n\ 31 | snippet zupfnoter.annotation\n\ 32 | \"^!${1:text}@${2:x_offset},${3:y_offset}\"\n\ 33 | \n\ 34 | \n\ 35 | "; 36 | exports.scope = "abc"; 37 | 38 | }); (function() { 39 | ace.require(["ace/snippets/abc"], function(m) { 40 | if (typeof module == "object" && typeof exports == "object" && module) { 41 | module.exports = m; 42 | } 43 | }); 44 | })(); 45 | -------------------------------------------------------------------------------- /static/web/38528de2a5c097da375fd0a076667441.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/matlab"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/3baeab62d681338ba3287f0a50e5dad1.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/gitignore"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/3c58f68d787710c79906a2cd6d248295.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/yaml"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/3cab7110c6a090f72c540dcc1cfbe3b5.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/csound_score"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/3cce0c7e1a8e1148f97de59a4b1ee73f.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/lisp"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/3cf64ec91a700bfa1dece0957c49c7dc.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/autohotkey"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/3e6808cd6eefd1be1040403985581374.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/prolog"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/40505d6c2f34fc08502d3e596573c7f8.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/xml"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/41f85ea0c545f0539b6ae2753eb1f79c.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/smarty"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/43a9bcfc200d80676bc68fe9a3c8ab6d.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/mysql"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/4705b919138245a5b454d25f8e418435.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/rst",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "# rst\n\ 5 | \n\ 6 | snippet :\n\ 7 | :${1:field name}: ${2:field body}\n\ 8 | snippet *\n\ 9 | *${1:Emphasis}*\n\ 10 | snippet **\n\ 11 | **${1:Strong emphasis}**\n\ 12 | snippet _\n\ 13 | \\`${1:hyperlink-name}\\`_\n\ 14 | .. _\\`$1\\`: ${2:link-block}\n\ 15 | snippet =\n\ 16 | ${1:Title}\n\ 17 | =====${2:=}\n\ 18 | ${3}\n\ 19 | snippet -\n\ 20 | ${1:Title}\n\ 21 | -----${2:-}\n\ 22 | ${3}\n\ 23 | snippet cont:\n\ 24 | .. contents::\n\ 25 | \n\ 26 | "; 27 | exports.scope = "rst"; 28 | 29 | }); (function() { 30 | ace.require(["ace/snippets/rst"], function(m) { 31 | if (typeof module == "object" && typeof exports == "object" && module) { 32 | module.exports = m; 33 | } 34 | }); 35 | })(); 36 | -------------------------------------------------------------------------------- /static/web/47cd5c7d174e6b624e55510c4e503600.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/fsl",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText =undefined; 5 | exports.scope = ""; 6 | 7 | }); (function() { 8 | ace.require(["ace/snippets/fsl"], function(m) { 9 | if (typeof module == "object" && typeof exports == "object" && module) { 10 | module.exports = m; 11 | } 12 | }); 13 | })(); 14 | -------------------------------------------------------------------------------- /static/web/4cbd6f8a4f52821c1d3476139078797d.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/powershell"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/4d694d41a0c1b3eaad752a8352c5661c.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/logtalk"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/5094b30d2471cc7312746173d8a4bb25.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/plain_text"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/51e6918f996813eafa4b1491d9dd343b.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/mode/plain_text",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/text_highlight_rules","ace/mode/behaviour"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | var oop = require("../lib/oop"); 5 | var TextMode = require("./text").Mode; 6 | var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; 7 | var Behaviour = require("./behaviour").Behaviour; 8 | 9 | var Mode = function() { 10 | this.HighlightRules = TextHighlightRules; 11 | this.$behaviour = new Behaviour(); 12 | }; 13 | 14 | oop.inherits(Mode, TextMode); 15 | 16 | (function() { 17 | this.type = "text"; 18 | this.getNextLineIndent = function(state, line, tab) { 19 | return ''; 20 | }; 21 | this.$id = "ace/mode/plain_text"; 22 | }).call(Mode.prototype); 23 | 24 | exports.Mode = Mode; 25 | }); (function() { 26 | ace.require(["ace/mode/plain_text"], function(m) { 27 | if (typeof module == "object" && typeof exports == "object" && module) { 28 | module.exports = m; 29 | } 30 | }); 31 | })(); 32 | -------------------------------------------------------------------------------- /static/web/51e6ccd3ea9d7443949b155b113eebd5.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/puppet"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/540bba54b49ea7a6ec513270449132db.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/php_laravel_blade"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/553aa6bb3b625428f4df57f5885d50f3.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/hjson"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/57c2d2eb6a844a8c9ecd932c6d4067b0.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/assembly_x86"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/5bd58f2ebad7e63ff72a891fb43e2b38.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/svg"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/5eeee1acc01b04328cf42db0715bb7f5.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/pgsql"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/5f6f5026d13b2a9b884a8144a119cf9e.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/vbscript"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/60fc15a66fa7ba74ccd248f85b50fbe5.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/aql"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/64f93b6b093bba4147485023263cf65f.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/ada"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/68cf9a0e1eaff7cc991e970a855108f8.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/nim"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/697c2df91bf7c729d317c620a3cd77bd.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/scad"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/6e88d3943f4c3a068493aad131cd4898.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/gcode"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/6e9ca56e0fa3e784eab3da45f8d0d8ac.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/rust"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/6f0543453c605ea6d673a3bd31dd1090.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/rhtml"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/727184c92f9da8d8b0c013fd79cf32fe.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/haxe"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/74973bbb728e661679e49a16773535a4.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/haml",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "snippet t\n\ 5 | %table\n\ 6 | %tr\n\ 7 | %th\n\ 8 | ${1:headers}\n\ 9 | %tr\n\ 10 | %td\n\ 11 | ${2:headers}\n\ 12 | snippet ul\n\ 13 | %ul\n\ 14 | %li\n\ 15 | ${1:item}\n\ 16 | %li\n\ 17 | snippet =rp\n\ 18 | = render :partial => '${1:partial}'\n\ 19 | snippet =rpl\n\ 20 | = render :partial => '${1:partial}', :locals => {}\n\ 21 | snippet =rpc\n\ 22 | = render :partial => '${1:partial}', :collection => @$1\n\ 23 | \n\ 24 | "; 25 | exports.scope = "haml"; 26 | 27 | }); (function() { 28 | ace.require(["ace/snippets/haml"], function(m) { 29 | if (typeof module == "object" && typeof exports == "object" && module) { 30 | module.exports = m; 31 | } 32 | }); 33 | })(); 34 | -------------------------------------------------------------------------------- /static/web/7af5865535fb306e7d0364a9ff81f389.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/diff",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "# DEP-3 (http://dep.debian.net/deps/dep3/) style patch header\n\ 5 | snippet header DEP-3 style header\n\ 6 | Description: ${1}\n\ 7 | Origin: ${2:vendor|upstream|other}, ${3:url of the original patch}\n\ 8 | Bug: ${4:url in upstream bugtracker}\n\ 9 | Forwarded: ${5:no|not-needed|url}\n\ 10 | Author: ${6:`g:snips_author`}\n\ 11 | Reviewed-by: ${7:name and email}\n\ 12 | Last-Update: ${8:`strftime(\"%Y-%m-%d\")`}\n\ 13 | Applied-Upstream: ${9:upstream version|url|commit}\n\ 14 | \n\ 15 | "; 16 | exports.scope = "diff"; 17 | 18 | }); (function() { 19 | ace.require(["ace/snippets/diff"], function(m) { 20 | if (typeof module == "object" && typeof exports == "object" && module) { 21 | module.exports = m; 22 | } 23 | }); 24 | })(); 25 | -------------------------------------------------------------------------------- /static/web/7cef38946c33fa981d6d2c86c62428e0.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/fsharp"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/7d46cd8e5efaac33d5bf823ed4268841.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/c9search"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/7e98c4d98664d6f7bcc52a07f21a1f9f.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/html_elixir"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/7f10fe526aec57bd522af77ea6ac2b62.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/dockerfile"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/817d52a47a4657b8a4dab79e057f5fb0.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/cirru"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/833b242747fd7b098d46011e4289bc3f.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/abap"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/83ea78d42f1a8e5f7346f3a30140ebfb.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/apache_conf"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/867fb2b26eef123915aff8634c0bbf4a.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/glsl"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/8681f562786fa45bebe8ee7ed2461026.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/textile",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "# Jekyll post header\n\ 5 | snippet header\n\ 6 | ---\n\ 7 | title: ${1:title}\n\ 8 | layout: post\n\ 9 | date: ${2:date} ${3:hour:minute:second} -05:00\n\ 10 | ---\n\ 11 | \n\ 12 | # Image\n\ 13 | snippet img\n\ 14 | !${1:url}(${2:title}):${3:link}!\n\ 15 | \n\ 16 | # Table\n\ 17 | snippet |\n\ 18 | |${1}|${2}\n\ 19 | \n\ 20 | # Link\n\ 21 | snippet link\n\ 22 | \"${1:link text}\":${2:url}\n\ 23 | \n\ 24 | # Acronym\n\ 25 | snippet (\n\ 26 | (${1:Expand acronym})${2}\n\ 27 | \n\ 28 | # Footnote\n\ 29 | snippet fn\n\ 30 | [${1:ref number}] ${3}\n\ 31 | \n\ 32 | fn$1. ${2:footnote}\n\ 33 | \n\ 34 | "; 35 | exports.scope = "textile"; 36 | 37 | }); (function() { 38 | ace.require(["ace/snippets/textile"], function(m) { 39 | if (typeof module == "object" && typeof exports == "object" && module) { 40 | module.exports = m; 41 | } 42 | }); 43 | })(); 44 | -------------------------------------------------------------------------------- /static/web/8833a126ef9d8892bfb372d227f7f088.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/lucene"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/8870430db332faf22d90e12f1620ee84.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/turtle"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/89859a411a50c90f1e669deaf8a6775f.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/jssm"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/89a47a0051ac0b3885ef8af2476526f0.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/asl"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/90643b9da87302fef490f3f48af806e2.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/asciidoc"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/92cf63e9a949f08d97a74d9ed17392ed.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/qml"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/94a0179602c94d55621a35e41c97ed5c.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/haskell_cabal"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/985b400088bf5e23fb83e70d9948eccb.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/nix"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/998c5f13555e18b42e9bf826578b2e16.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/praat"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/9c202aefac35a5ff49d3d3795e9932bc.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/html_ruby"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/9d0f4f65be2f50ad54488089f126feda.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/eiffel"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/9e357a97da26127713394684a51946b8.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/nunjucks"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/9e69cb39701c3578226b39536edd4dd7.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/twig"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/a26463d029a2515171748a1ebcca53c3.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/ocaml"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/a311e02008e0f00a37305a12d479159a.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/coldfusion"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/aa2f98073a8d9f266f3928b5d9c457d1.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/lua",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "snippet #!\n\ 5 | #!/usr/bin/env lua\n\ 6 | $1\n\ 7 | snippet local\n\ 8 | local ${1:x} = ${2:1}\n\ 9 | snippet fun\n\ 10 | function ${1:fname}(${2:...})\n\ 11 | ${3:-- body}\n\ 12 | end\n\ 13 | snippet for\n\ 14 | for ${1:i}=${2:1},${3:10} do\n\ 15 | ${4:print(i)}\n\ 16 | end\n\ 17 | snippet forp\n\ 18 | for ${1:i},${2:v} in pairs(${3:table_name}) do\n\ 19 | ${4:-- body}\n\ 20 | end\n\ 21 | snippet fori\n\ 22 | for ${1:i},${2:v} in ipairs(${3:table_name}) do\n\ 23 | ${4:-- body}\n\ 24 | end\n\ 25 | "; 26 | exports.scope = "lua"; 27 | 28 | }); (function() { 29 | ace.require(["ace/snippets/lua"], function(m) { 30 | if (typeof module == "object" && typeof exports == "object" && module) { 31 | module.exports = m; 32 | } 33 | }); 34 | })(); 35 | -------------------------------------------------------------------------------- /static/web/ab16c1237e6e04bbf0024ee2bae42130.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/d"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/acc30207efba7ab5b7b509b599f37e6f.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/nsis"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/acc7448b80728a73c9a4046b3ec4407f.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/golang"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/adbb57fa182dce548204311d3be6dffa.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/jack"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/b02513e1d0cc664936e1ba9cb5a923af.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/logiql"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/b131314d1ea62fa7bba91a4da8360298.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/zeek"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/b26738d581e044c69f7a4392906e6843.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/makefile",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "snippet ifeq\n\ 5 | ifeq (${1:cond0},${2:cond1})\n\ 6 | ${3:code}\n\ 7 | endif\n\ 8 | "; 9 | exports.scope = "makefile"; 10 | 11 | }); (function() { 12 | ace.require(["ace/snippets/makefile"], function(m) { 13 | if (typeof module == "object" && typeof exports == "object" && module) { 14 | module.exports = m; 15 | } 16 | }); 17 | })(); 18 | -------------------------------------------------------------------------------- /static/web/b435aebcb57d65080cfd510e0a9d5d9d.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/prisma"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/b830d88aa22a866a208be27af90526a7.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/swift"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/bae95bdb1bbcc0969e0e40fb72539df3.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/applescript"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/bbd62124f6d03e01eb4332f55ead999d.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/ext/error_marker"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/bc26ab0797e975ba01e701683935864b.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/fortran"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/bd98610e395f3b4c7915cf3fbe854f6f.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/csound_orchestra",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "# else\n\ 5 | snippet else\n\ 6 | else\n\ 7 | ${1:/* statements */}\n\ 8 | # elseif\n\ 9 | snippet elseif\n\ 10 | elseif ${1:/* condition */} then\n\ 11 | ${2:/* statements */}\n\ 12 | # if\n\ 13 | snippet if\n\ 14 | if ${1:/* condition */} then\n\ 15 | ${2:/* statements */}\n\ 16 | endif\n\ 17 | # instrument block\n\ 18 | snippet instr\n\ 19 | instr ${1:name}\n\ 20 | ${2:/* statements */}\n\ 21 | endin\n\ 22 | # i-time while loop\n\ 23 | snippet iwhile\n\ 24 | i${1:Index} = ${2:0}\n\ 25 | while i${1:Index} < ${3:/* count */} do\n\ 26 | ${4:/* statements */}\n\ 27 | i${1:Index} += 1\n\ 28 | od\n\ 29 | # k-rate while loop\n\ 30 | snippet kwhile\n\ 31 | k${1:Index} = ${2:0}\n\ 32 | while k${1:Index} < ${3:/* count */} do\n\ 33 | ${4:/* statements */}\n\ 34 | k${1:Index} += 1\n\ 35 | od\n\ 36 | # opcode\n\ 37 | snippet opcode\n\ 38 | opcode ${1:name}, ${2:/* output types */ 0}, ${3:/* input types */ 0}\n\ 39 | ${4:/* statements */}\n\ 40 | endop\n\ 41 | # until loop\n\ 42 | snippet until\n\ 43 | until ${1:/* condition */} do\n\ 44 | ${2:/* statements */}\n\ 45 | od\n\ 46 | # while loop\n\ 47 | snippet while\n\ 48 | while ${1:/* condition */} do\n\ 49 | ${2:/* statements */}\n\ 50 | od\n\ 51 | "; 52 | exports.scope = "csound_orchestra"; 53 | 54 | }); (function() { 55 | ace.require(["ace/snippets/csound_orchestra"], function(m) { 56 | if (typeof module == "object" && typeof exports == "object" && module) { 57 | module.exports = m; 58 | } 59 | }); 60 | })(); 61 | -------------------------------------------------------------------------------- /static/web/be2fbe775b19bdc18e4f78de18beb433.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/velocity",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "# macro\n\ 5 | snippet #macro\n\ 6 | #macro ( ${1:macroName} ${2:\\$var1, [\\$var2, ...]} )\n\ 7 | ${3:## macro code}\n\ 8 | #end\n\ 9 | # foreach\n\ 10 | snippet #foreach\n\ 11 | #foreach ( ${1:\\$item} in ${2:\\$collection} )\n\ 12 | ${3:## foreach code}\n\ 13 | #end\n\ 14 | # if\n\ 15 | snippet #if\n\ 16 | #if ( ${1:true} )\n\ 17 | ${0}\n\ 18 | #end\n\ 19 | # if ... else\n\ 20 | snippet #ife\n\ 21 | #if ( ${1:true} )\n\ 22 | ${2}\n\ 23 | #else\n\ 24 | ${0}\n\ 25 | #end\n\ 26 | #import\n\ 27 | snippet #import\n\ 28 | #import ( \"${1:path/to/velocity/format}\" )\n\ 29 | # set\n\ 30 | snippet #set\n\ 31 | #set ( $${1:var} = ${0} )\n\ 32 | "; 33 | exports.scope = "velocity"; 34 | exports.includeScopes = ["html", "javascript", "css"]; 35 | 36 | }); (function() { 37 | ace.require(["ace/snippets/velocity"], function(m) { 38 | if (typeof module == "object" && typeof exports == "object" && module) { 39 | module.exports = m; 40 | } 41 | }); 42 | })(); 43 | -------------------------------------------------------------------------------- /static/web/c23b1f80ab9746b425f3848bdaacc144.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/rdoc"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/c38a3226f3858a47ba9fb788dc7b44fc.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/ini"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/c3b0cd15adcc12a549e7ac5d165ac1f4.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/vhdl"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/c6d4a590e14107a8a5ad505d66241032.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/csharp"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/c6f608398c43e25821557ee65cda5e58.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/pascal"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/c7d3b0afe7600a632fbf44ee8d84996e.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/mixal"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/c7fb0ccebacccfb5c2f7b2f6023ebe4a.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/graphqlschema",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "# Type Snippet\n\ 5 | trigger type\n\ 6 | snippet type\n\ 7 | type ${1:type_name} {\n\ 8 | ${2:type_siblings}\n\ 9 | }\n\ 10 | \n\ 11 | # Input Snippet\n\ 12 | trigger input\n\ 13 | snippet input\n\ 14 | input ${1:input_name} {\n\ 15 | ${2:input_siblings}\n\ 16 | }\n\ 17 | \n\ 18 | # Interface Snippet\n\ 19 | trigger interface\n\ 20 | snippet interface\n\ 21 | interface ${1:interface_name} {\n\ 22 | ${2:interface_siblings}\n\ 23 | }\n\ 24 | \n\ 25 | # Interface Snippet\n\ 26 | trigger union\n\ 27 | snippet union\n\ 28 | union ${1:union_name} = ${2:type} | ${3: type}\n\ 29 | \n\ 30 | # Enum Snippet\n\ 31 | trigger enum\n\ 32 | snippet enum\n\ 33 | enum ${1:enum_name} {\n\ 34 | ${2:enum_siblings}\n\ 35 | }\n\ 36 | "; 37 | exports.scope = "graphqlschema"; 38 | 39 | }); (function() { 40 | ace.require(["ace/snippets/graphqlschema"], function(m) { 41 | if (typeof module == "object" && typeof exports == "object" && module) { 42 | module.exports = m; 43 | } 44 | }); 45 | })(); 46 | -------------------------------------------------------------------------------- /static/web/ca1483809659f6c87cc6f588891d2bd4.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/mel"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/cf0a04afa21ac9ba23a1de0416a03105.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/scheme"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/css/chunk-05a99c67.b1dd7a76.css: -------------------------------------------------------------------------------- 1 | .errPage-container[data-v-35ca77fc]{width:800px;max-width:100%;margin:100px auto}.errPage-container .pan-back-btn[data-v-35ca77fc]{background:#008489;color:#fff;border:none!important}.errPage-container .pan-gif[data-v-35ca77fc]{margin:0 auto;display:block}.errPage-container .pan-img[data-v-35ca77fc]{display:block;margin:0 auto;width:100%}.errPage-container .text-jumbo[data-v-35ca77fc]{font-size:60px;font-weight:700;color:#484848}.errPage-container .list-unstyled[data-v-35ca77fc]{font-size:14px}.errPage-container .list-unstyled li[data-v-35ca77fc]{padding-bottom:5px}.errPage-container .list-unstyled a[data-v-35ca77fc]{color:#008489;text-decoration:none}.errPage-container .list-unstyled a[data-v-35ca77fc]:hover{text-decoration:underline} -------------------------------------------------------------------------------- /static/web/d465c0a35c6ef244bf587b0e6bdb4019.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/terraform"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/d750a8dbf9dd09c0a33b9986e79e3c8c.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/mediawiki"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/d754905fe54aac6f3c350df34f51a0b6.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/ejs"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/d7889907dbb51f58ceadb3e1eec03a5d.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/mask"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/dd40dfc7840568927fdef65087a233ed.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/properties"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/e0e2b1267a5d4acb4dda3a4a598cd8a5.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/curly"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/e1dbe800b2d3f5d74b2b5480ea2b897a.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/razor",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText = "snippet if\n\ 5 | (${1} == ${2}) {\n\ 6 | ${3}\n\ 7 | }"; 8 | exports.scope = "razor"; 9 | 10 | }); (function() { 11 | ace.require(["ace/snippets/razor"], function(m) { 12 | if (typeof module == "object" && typeof exports == "object" && module) { 13 | module.exports = m; 14 | } 15 | }); 16 | })(); 17 | -------------------------------------------------------------------------------- /static/web/e2792218bae78a6aef6764de4e61fd82.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/json"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/e4d51c8b4202d444cb39db4e7642d7d9.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/crystal"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/e745f8fb4f054a3f5b66ccad100a1217.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/latex"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/efc508c36f4e417ec6bd5ec72989443b.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/ftl"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/f2195d2eae3dbef7e3798e115209dcd7.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/nginx"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/f2cfc0e604350e23bfcd7c78165b1411.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/jsx"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/f3a0f6e7e442de2ae51eddbf4eb98d97.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/mode/text"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/f50d7c4ce743ce495230d19bd33fefab.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/space"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/f5292be525fc36a337ce7bfb792070de.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/luapage"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/f61f1aaed3f32a7dabd977a6f47ecd5f.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/protobuf"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/f7443e8232a7e4289b9f2ed4a512750c.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/kotlin"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/f80c6eb0f52a68464b21211240e3d6e6.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/elm"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/f88127ad8950e3c94c3af6c65a7120fa.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/toml"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/fa1618cda4da7d5362c381ea2d5f7321.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/typescript"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/faf460076b3383fdc3ecc224068964cf.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/sjs"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/favicon.ico -------------------------------------------------------------------------------- /static/web/fffbc895129cdb3efeafa5b234743aa0.js: -------------------------------------------------------------------------------- 1 | 2 | ; (function() { 3 | ace.require(["ace/snippets/alda"], function(m) { 4 | if (typeof module == "object" && typeof exports == "object" && module) { 5 | module.exports = m; 6 | } 7 | }); 8 | })(); 9 | -------------------------------------------------------------------------------- /static/web/fonts/eiconfont.016bbe3f.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/fonts/eiconfont.016bbe3f.woff -------------------------------------------------------------------------------- /static/web/fonts/eiconfont.0ff67604.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/fonts/eiconfont.0ff67604.ttf -------------------------------------------------------------------------------- /static/web/fonts/eiconfont.ae6bc167.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/fonts/eiconfont.ae6bc167.eot -------------------------------------------------------------------------------- /static/web/fonts/element-icons.535877f5.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/fonts/element-icons.535877f5.woff -------------------------------------------------------------------------------- /static/web/fonts/element-icons.732389de.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/fonts/element-icons.732389de.ttf -------------------------------------------------------------------------------- /static/web/fonts/fontawesome-webfont.674f50d2.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/fonts/fontawesome-webfont.674f50d2.eot -------------------------------------------------------------------------------- /static/web/fonts/fontawesome-webfont.af7ae505.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/fonts/fontawesome-webfont.af7ae505.woff2 -------------------------------------------------------------------------------- /static/web/fonts/fontawesome-webfont.b06871f2.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/fonts/fontawesome-webfont.b06871f2.ttf -------------------------------------------------------------------------------- /static/web/fonts/fontawesome-webfont.fee66e71.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/fonts/fontawesome-webfont.fee66e71.woff -------------------------------------------------------------------------------- /static/web/fonts/iconfont.34ea3475.34ea3475.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/fonts/iconfont.34ea3475.34ea3475.woff -------------------------------------------------------------------------------- /static/web/fonts/iconfont.34ea3475.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/fonts/iconfont.34ea3475.woff -------------------------------------------------------------------------------- /static/web/fonts/iconfont.4d5a9051.4d5a9051.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/fonts/iconfont.4d5a9051.4d5a9051.ttf -------------------------------------------------------------------------------- /static/web/fonts/iconfont.4d5a9051.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/fonts/iconfont.4d5a9051.ttf -------------------------------------------------------------------------------- /static/web/fonts/iconfont.8efbc988.8efbc988.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/fonts/iconfont.8efbc988.8efbc988.eot -------------------------------------------------------------------------------- /static/web/fonts/iconfont.8efbc988.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/fonts/iconfont.8efbc988.eot -------------------------------------------------------------------------------- /static/web/img/401.089007e7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/img/401.089007e7.gif -------------------------------------------------------------------------------- /static/web/img/404.a57b6f31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/img/404.a57b6f31.png -------------------------------------------------------------------------------- /static/web/img/404_cloud.0f4bc32b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/img/404_cloud.0f4bc32b.png -------------------------------------------------------------------------------- /static/web/img/end.9687f898.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | end_1 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /static/web/img/exclusive-gateway.56b82dfd.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | decision_1 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /static/web/img/icon_java.d3cc233a.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/web/img/icon_mail.0f68d5c7.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/web/img/icon_message.01031aed.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/web/img/icon_receive.a6c46918.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/web/img/icon_script.07c7423e.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/web/img/icon_signal.0e96b3b6.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/web/img/icon_timer.b4fcbba6.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/web/img/icon_user.2b39cf22.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/web/img/login.ede1cdb8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lanyulei/ferry/fbffecffcbacc0e0572a312656cde8f28af8035b/static/web/img/login.ede1cdb8.png -------------------------------------------------------------------------------- /static/web/img/parallel-gateway.dfb4ebaf.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | decision_1 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /static/web/img/receive-task.e1131038.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | task_1 10 | 11 | 13 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /static/web/img/start.894f1842.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | start_1 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /static/web/img/user-task.90bd34cf.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | task_1 10 | 11 | 12 | 14 | 15 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /static/web/js/chunk-2d2105d3.b54ad484.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d2105d3"],{b829:function(n,e,o){"use strict";o.r(e);o("386d");var t,c,a={name:"AuthRedirect",created:function(){var n=window.location.search.slice(1);window.localStorage&&(window.localStorage.setItem("x-admin-oauth-code",n),window.close())},render:function(n){return n()}},d=a,i=o("2877"),l=Object(i["a"])(d,t,c,!1,null,null,null);e["default"]=l.exports}}]); -------------------------------------------------------------------------------- /static/web/js/chunk-2d230fe7.19def69d.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d230fe7"],{ef3c:function(e,r,n){"use strict";n.r(r);n("a481");var t,u,a={created:function(){var e=this.$route,r=e.params,n=e.query,t=r.path;this.$router.replace({path:"/"+t,query:n})},render:function(e){return e()}},c=a,o=n("2877"),p=Object(o["a"])(c,t,u,!1,null,null,null);r["default"]=p.exports}}]); -------------------------------------------------------------------------------- /static/web/js/chunk-39b1e937.3a2314ea.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-39b1e937"],{"1db4":function(t,s,i){"use strict";i.r(s);var a=function(){var t=this,s=t.$createElement,i=t._self._c||s;return i("div",{staticClass:"wscn-http404-container"},[i("div",{staticClass:"wscn-http404"},[t._m(0),t._v(" "),i("div",{staticClass:"bullshit"},[i("div",{staticClass:"bullshit__oops"},[t._v("OOPS!")]),t._v(" "),i("div",{staticClass:"bullshit__headline"},[t._v(t._s(t.message))]),t._v(" "),i("div",{staticClass:"bullshit__info"},[t._v("请检查您访问的地址是否正确,通常在切换用户时,若您的用户没有上个用户退出时的页面权限,也会触发此报错,请知悉,或者点击一下按钮返回首页。")]),t._v(" "),i("a",{staticClass:"bullshit__return-home",attrs:{href:""}},[t._v("返回首页")])])])])},c=[function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"pic-404"},[a("img",{staticClass:"pic-404__parent",attrs:{src:i("a36b"),alt:"404"}}),t._v(" "),a("img",{staticClass:"pic-404__child left",attrs:{src:i("26fc"),alt:"404"}}),t._v(" "),a("img",{staticClass:"pic-404__child mid",attrs:{src:i("26fc"),alt:"404"}}),t._v(" "),a("img",{staticClass:"pic-404__child right",attrs:{src:i("26fc"),alt:"404"}})])}],l={name:"Page404",computed:{message:function(){return"抱歉,您找的页面不存在。"}}},e=l,n=(i("3f88"),i("2877")),_=Object(n["a"])(e,a,c,!1,null,"171d498a",null);s["default"]=_.exports},"26fc":function(t,s,i){t.exports=i.p+"static/web/img/404_cloud.0f4bc32b.png"},"3f88":function(t,s,i){"use strict";i("6b50")},"6b50":function(t,s,i){},a36b:function(t,s,i){t.exports=i.p+"static/web/img/404.a57b6f31.png"}}]); -------------------------------------------------------------------------------- /template/js.go.template: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询{{.ClassName}}列表 4 | export function list{{.ClassName}}(query) { 5 | return request({ 6 | url: '/api/v1/{{.ModuleName}}List', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询{{.ClassName}}详细 13 | export function get{{.ClassName}} ({{.PkJsonField}}) { 14 | return request({ 15 | url: '/api/v1/{{.ModuleName}}/' + {{.PkJsonField}}, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | 21 | // 新增{{.ClassName}} 22 | export function add{{.ClassName}}(data) { 23 | return request({ 24 | url: '/api/v1/{{.ModuleName}}', 25 | method: 'post', 26 | data: data 27 | }) 28 | } 29 | 30 | // 修改{{.ClassName}} 31 | export function update{{.ClassName}}(data) { 32 | return request({ 33 | url: '/api/v1/{{.ModuleName}}', 34 | method: 'put', 35 | data: data 36 | }) 37 | } 38 | 39 | // 删除{{.ClassName}} 40 | export function del{{.ClassName}}({{.PkJsonField}}) { 41 | return request({ 42 | url: '/api/v1/{{.ModuleName}}/' + {{.PkJsonField}}, 43 | method: 'delete' 44 | }) 45 | } 46 | 47 | -------------------------------------------------------------------------------- /template/router.go.template: -------------------------------------------------------------------------------- 1 | 2 | // 需认证的路由代码 3 | func register{{.ClassName}}Router(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { 4 | 5 | r := v1.Group("/{{.ModuleName}}").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) 6 | { 7 | r.GET("/:{{.PkJsonField}}", {{.ModuleName}}.Get{{.ClassName}}) 8 | r.POST("", {{.ModuleName}}.Insert{{.ClassName}}) 9 | r.PUT("", {{.ModuleName}}.Update{{.ClassName}}) 10 | r.DELETE("/:{{.PkJsonField}}", {{.ModuleName}}.Delete{{.ClassName}}) 11 | } 12 | 13 | l := v1.Group("").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) 14 | { 15 | l.GET("/{{.ModuleName}}List",{{.ModuleName}}.Get{{.ClassName}}List) 16 | } 17 | 18 | } 19 | 20 | // 无需认证的路由代码 21 | func register{{.ClassName}}Router(v1 *gin.RouterGroup) { 22 | 23 | v1.GET("/{{.ModuleName}}List",{{.ModuleName}}.Get{{.ClassName}}List) 24 | 25 | r := v1.Group("/{{.ModuleName}}") 26 | { 27 | r.GET("/:{{.PkJsonField}}", {{.ModuleName}}.Get{{.ClassName}}) 28 | r.POST("", {{.ModuleName}}.Insert{{.ClassName}}) 29 | r.PUT("", {{.ModuleName}}.Update{{.ClassName}}) 30 | r.DELETE("/:{{.PkJsonField}}", {{.ModuleName}}.Delete{{.ClassName}}) 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /tools/app/model.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | type Response struct { 4 | // 代码 5 | Code int `json:"code" example:"200"` 6 | // 数据集 7 | Data interface{} `json:"data"` 8 | // 消息 9 | Msg string `json:"msg"` 10 | } 11 | 12 | type Page struct { 13 | List interface{} `json:"list"` 14 | Count int `json:"count"` 15 | PageIndex int `json:"pageIndex"` 16 | PageSize int `json:"pageSize"` 17 | } 18 | 19 | type PageResponse struct { 20 | // 代码 21 | Code int `json:"code" example:"200"` 22 | // 数据集 23 | Data Page `json:"data"` 24 | // 消息 25 | Msg string `json:"msg"` 26 | } 27 | 28 | 29 | func (res *Response) ReturnOK() *Response { 30 | res.Code = 200 31 | return res 32 | } 33 | 34 | func (res *Response) ReturnError(code int) *Response { 35 | res.Code = code 36 | return res 37 | } 38 | 39 | 40 | func (res *PageResponse) ReturnOK() *PageResponse { 41 | res.Code = 200 42 | return res 43 | } 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /tools/app/msg/message.go: -------------------------------------------------------------------------------- 1 | package msg 2 | 3 | var ( 4 | CreatedSuccess = "创建成功!" 5 | UpdatedSuccess = "更新成功!" 6 | DeletedSuccess = "删除成功!" 7 | GetSuccess = "查询成功!" 8 | NotFound = "未找到相关内容或者数据为空!" 9 | ) 10 | -------------------------------------------------------------------------------- /tools/app/return.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "ferry/pkg/logger" 5 | "net/http" 6 | 7 | "github.com/gin-gonic/gin" 8 | ) 9 | 10 | // 失败数据处理 11 | func Error(c *gin.Context, code int, err error, msg string) { 12 | var res Response 13 | res.Msg = err.Error() 14 | if msg != "" { 15 | res.Msg = msg 16 | } 17 | logger.Error(res.Msg) 18 | c.JSON(http.StatusOK, res.ReturnError(code)) 19 | } 20 | 21 | // 通常成功数据处理 22 | func OK(c *gin.Context, data interface{}, msg string) { 23 | var res Response 24 | res.Data = data 25 | if msg != "" { 26 | res.Msg = msg 27 | } 28 | c.JSON(http.StatusOK, res.ReturnOK()) 29 | } 30 | 31 | // 分页数据处理 32 | func PageOK(c *gin.Context, result interface{}, count int, pageIndex int, pageSize int, msg string) { 33 | var res PageResponse 34 | res.Data.List = result 35 | res.Data.Count = count 36 | res.Data.PageIndex = pageIndex 37 | res.Data.PageSize = pageSize 38 | if msg != "" { 39 | res.Msg = msg 40 | } 41 | c.JSON(http.StatusOK, res.ReturnOK()) 42 | } 43 | 44 | // 兼容函数 45 | func Custum(c *gin.Context, data gin.H) { 46 | c.JSON(http.StatusOK, data) 47 | } 48 | -------------------------------------------------------------------------------- /tools/captcha/captcha.go: -------------------------------------------------------------------------------- 1 | package captcha 2 | 3 | import ( 4 | "github.com/google/uuid" 5 | "github.com/mojocn/base64Captcha" 6 | ) 7 | 8 | var store = base64Captcha.DefaultMemStore 9 | 10 | // configJsonBody json request body. 11 | type configJsonBody struct { 12 | Id string 13 | CaptchaType string 14 | VerifyValue string 15 | DriverAudio *base64Captcha.DriverAudio 16 | DriverString *base64Captcha.DriverString 17 | DriverChinese *base64Captcha.DriverChinese 18 | DriverMath *base64Captcha.DriverMath 19 | DriverDigit *base64Captcha.DriverDigit 20 | } 21 | 22 | func DriverDigitFunc() (id, b64s, answer string, err error) { 23 | e := configJsonBody{} 24 | e.Id = uuid.New().String() 25 | e.DriverDigit = base64Captcha.NewDriverDigit(80, 240, 4, 0.7, 80) 26 | driver := e.DriverDigit 27 | captcha := base64Captcha.NewCaptcha(driver, store) 28 | return captcha.Generate() 29 | } 30 | -------------------------------------------------------------------------------- /tools/config/application.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "github.com/spf13/viper" 4 | 5 | type Application struct { 6 | ReadTimeout int 7 | WriterTimeout int 8 | Host string 9 | Port string 10 | Name string 11 | JwtSecret string 12 | Mode string 13 | DemoMsg string 14 | Domain string 15 | IsHttps bool 16 | } 17 | 18 | func InitApplication(cfg *viper.Viper) *Application { 19 | return &Application{ 20 | ReadTimeout: cfg.GetInt("readTimeout"), 21 | WriterTimeout: cfg.GetInt("writerTimeout"), 22 | Host: cfg.GetString("host"), 23 | Port: portDefault(cfg), 24 | Name: cfg.GetString("name"), 25 | JwtSecret: viper.GetString("settings.jwt.secret"), 26 | Mode: cfg.GetString("mode"), 27 | DemoMsg: cfg.GetString("demoMsg"), 28 | Domain: cfg.GetString("domain"), 29 | IsHttps: cfg.GetBool("ishttps"), 30 | } 31 | } 32 | 33 | var ApplicationConfig = new(Application) 34 | 35 | func portDefault(cfg *viper.Viper) string { 36 | if cfg.GetString("port") == "" { 37 | return "8000" 38 | } else { 39 | return cfg.GetString("port") 40 | } 41 | } 42 | 43 | func isHttpsDefault(cfg *viper.Viper) bool { 44 | if cfg.GetString("ishttps") == "" || cfg.GetBool("ishttps") == false { 45 | return false 46 | } else { 47 | return true 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tools/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "ferry/pkg/logger" 5 | "fmt" 6 | "os" 7 | "strings" 8 | 9 | "github.com/spf13/viper" 10 | ) 11 | 12 | var cfgDatabase *viper.Viper 13 | var cfgApplication *viper.Viper 14 | var cfgJwt *viper.Viper 15 | var cfgSsl *viper.Viper 16 | 17 | // ConfigSetup 载入配置文件 18 | func ConfigSetup(path string) { 19 | viper.SetConfigFile(path) 20 | content, err := os.ReadFile(path) 21 | if err != nil { 22 | logger.Fatal(fmt.Sprintf("Read config file fail: %s", err.Error())) 23 | } 24 | 25 | //Replace environment variables 26 | err = viper.ReadConfig(strings.NewReader(os.ExpandEnv(string(content)))) 27 | if err != nil { 28 | logger.Fatal(fmt.Sprintf("Parse config file fail: %s", err.Error())) 29 | } 30 | 31 | // 数据库初始化 32 | cfgDatabase = viper.Sub("settings.database") 33 | if cfgDatabase == nil { 34 | panic("config not found settings.database") 35 | } 36 | DatabaseConfig = InitDatabase(cfgDatabase) 37 | 38 | // 启动参数 39 | cfgApplication = viper.Sub("settings.application") 40 | if cfgApplication == nil { 41 | panic("config not found settings.application") 42 | } 43 | ApplicationConfig = InitApplication(cfgApplication) 44 | 45 | // Jwt初始化 46 | cfgJwt = viper.Sub("settings.jwt") 47 | if cfgJwt == nil { 48 | panic("config not found settings.jwt") 49 | } 50 | JwtConfig = InitJwt(cfgJwt) 51 | 52 | // ssl 配置 53 | cfgSsl = viper.Sub("settings.ssl") 54 | if cfgSsl == nil { 55 | panic("config not found settings.ssl") 56 | } 57 | SslConfig = InitSsl(cfgSsl) 58 | 59 | // 日志配置 60 | logger.Init() 61 | } 62 | 63 | func SetConfig(configPath string, key string, value interface{}) { 64 | viper.AddConfigPath(configPath) 65 | viper.Set(key, value) 66 | _ = viper.WriteConfig() 67 | } 68 | -------------------------------------------------------------------------------- /tools/config/database.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "github.com/spf13/viper" 4 | 5 | type Database struct { 6 | Dbtype string 7 | Host string 8 | Port int 9 | Name string 10 | Username string 11 | Password string 12 | } 13 | 14 | func InitDatabase(cfg *viper.Viper) *Database { 15 | return &Database{ 16 | Port: cfg.GetInt("port"), 17 | Dbtype: cfg.GetString("dbType"), 18 | Host: cfg.GetString("host"), 19 | Name: cfg.GetString("name"), 20 | Username: cfg.GetString("username"), 21 | Password: cfg.GetString("password"), 22 | } 23 | } 24 | 25 | var DatabaseConfig = new(Database) 26 | -------------------------------------------------------------------------------- /tools/config/jwt.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/spf13/viper" 5 | ) 6 | 7 | type Jwt struct { 8 | Secret string 9 | Timeout int64 10 | } 11 | 12 | func InitJwt(cfg *viper.Viper) *Jwt { 13 | return &Jwt{ 14 | Secret: cfg.GetString("secret"), 15 | Timeout: cfg.GetInt64("timeout"), 16 | } 17 | } 18 | 19 | var JwtConfig = new(Jwt) 20 | -------------------------------------------------------------------------------- /tools/config/ssl.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "github.com/spf13/viper" 4 | 5 | type Ssl struct { 6 | KeyStr string 7 | Pem string 8 | } 9 | 10 | func InitSsl(cfg *viper.Viper) *Ssl { 11 | return &Ssl{ 12 | KeyStr: cfg.GetString("key"), 13 | Pem: cfg.GetString("pem"), 14 | } 15 | } 16 | 17 | var SslConfig = new(Ssl) 18 | -------------------------------------------------------------------------------- /tools/env.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | type ( 4 | Mode string 5 | ) 6 | 7 | const ( 8 | ModeDev Mode = "dev" //开发模式 9 | ModeTest Mode = "test" //测试模式 10 | ModeProd Mode = "prod" //生产模式 11 | Mysql = "mysql" //mysql数据库标识 12 | ) 13 | -------------------------------------------------------------------------------- /tools/float64.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import "strconv" 4 | 5 | func Float64ToString(e float64) string { 6 | return strconv.FormatFloat(e, 'E', -1, 64) 7 | } -------------------------------------------------------------------------------- /tools/int.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import "strconv" 4 | 5 | func IntToString(e int) string { 6 | return strconv.Itoa(e) 7 | } -------------------------------------------------------------------------------- /tools/int64.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import "strconv" 4 | 5 | func Int64ToString(e int64) string { 6 | return strconv.FormatInt(e, 10) 7 | } -------------------------------------------------------------------------------- /tools/ip.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | 9 | "github.com/spf13/viper" 10 | ) 11 | 12 | func GetLocation(ip string) string { 13 | var address = "已关闭位置获取" 14 | if viper.GetBool("settings.public.isLocation") { 15 | if ip == "127.0.0.1" || ip == "localhost" { 16 | return "内部IP" 17 | } 18 | resp, err := http.Get("https://restapi.amap.com/v3/ip?ip=" + ip + "&key=3fabc36c20379fbb9300c79b19d5d05e") 19 | if err != nil { 20 | panic(err) 21 | } 22 | defer resp.Body.Close() 23 | s, err := ioutil.ReadAll(resp.Body) 24 | 25 | m := make(map[string]string) 26 | 27 | err = json.Unmarshal(s, &m) 28 | if err != nil { 29 | fmt.Println("Umarshal failed:", err) 30 | } 31 | if m["province"] == "" { 32 | return "未知位置" 33 | } 34 | address = m["province"] + "-" + m["city"] 35 | } 36 | return address 37 | } 38 | -------------------------------------------------------------------------------- /tools/string.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/gin-gonic/gin" 7 | "io/ioutil" 8 | "strconv" 9 | "time" 10 | ) 11 | 12 | func StringToInt64(e string) (int64, error) { 13 | return strconv.ParseInt(e, 10, 64) 14 | } 15 | 16 | func StringToInt(e string) (int, error) { 17 | return strconv.Atoi(e) 18 | } 19 | 20 | 21 | func GetCurrntTimeStr() string { 22 | return time.Now().Format("2006/01/02 15:04:05") 23 | } 24 | 25 | func GetCurrntTime() time.Time { 26 | return time.Now() 27 | } 28 | 29 | 30 | func StructToJsonStr(e interface{}) (string, error) { 31 | if b, err := json.Marshal(e); err == nil { 32 | return string(b), err 33 | } else { 34 | return "", err 35 | } 36 | } 37 | 38 | func GetBodyString(c *gin.Context) (string, error) { 39 | body, err := ioutil.ReadAll(c.Request.Body) 40 | if err != nil { 41 | fmt.Printf("read body err, %v\n", err) 42 | return string(body), nil 43 | } else { 44 | return "", err 45 | } 46 | } 47 | 48 | func JsonStrToMap(e string) (map[string]interface{}, error) { 49 | var dict map[string]interface{} 50 | if err := json.Unmarshal([]byte(e), &dict); err == nil { 51 | return dict, err 52 | } else { 53 | return nil, err 54 | } 55 | } 56 | 57 | func StructToMap(data interface{}) (map[string]interface{}, error) { 58 | dataBytes, err := json.Marshal(data) 59 | if err != nil { 60 | return nil, err 61 | } 62 | mapData := make(map[string]interface{}) 63 | err = json.Unmarshal(dataBytes, &mapData) 64 | if err != nil { 65 | return nil, err 66 | } 67 | return mapData, nil 68 | } 69 | -------------------------------------------------------------------------------- /tools/url.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "strings" 6 | ) 7 | 8 | //获取URL中批量id并解析 9 | func IdsStrToIdsIntGroup(key string, c *gin.Context) []int { 10 | return idsStrToIdsIntGroup(c.Param(key)) 11 | } 12 | 13 | 14 | func idsStrToIdsIntGroup(keys string) []int { 15 | IDS := make([]int, 0) 16 | ids := strings.Split(keys, ",") 17 | for i := 0; i < len(ids); i++ { 18 | ID, _ := StringToInt(ids[i]) 19 | IDS = append(IDS, ID) 20 | } 21 | return IDS 22 | } -------------------------------------------------------------------------------- /tools/user.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | jwt "ferry/pkg/jwtauth" 5 | "ferry/pkg/logger" 6 | "fmt" 7 | 8 | "github.com/gin-gonic/gin" 9 | ) 10 | 11 | func ExtractClaims(c *gin.Context) jwt.MapClaims { 12 | claims, exists := c.Get("JWT_PAYLOAD") 13 | if !exists { 14 | return make(jwt.MapClaims) 15 | } 16 | 17 | return claims.(jwt.MapClaims) 18 | } 19 | 20 | func GetUserId(c *gin.Context) int { 21 | data := ExtractClaims(c) 22 | if data["identity"] != nil { 23 | return int((data["identity"]).(float64)) 24 | } 25 | logger.Info("********** 路径:" + c.Request.URL.Path + " 请求方法:" + c.Request.Method + " 说明:缺少identity") 26 | return 0 27 | } 28 | 29 | func GetUserIdStr(c *gin.Context) string { 30 | data := ExtractClaims(c) 31 | if data["identity"] != nil { 32 | return Int64ToString(int64((data["identity"]).(float64))) 33 | } 34 | logger.Info("********** 路径:" + c.Request.URL.Path + " 请求方法:" + c.Request.Method + " 缺少identity") 35 | return "" 36 | } 37 | 38 | func GetUserName(c *gin.Context) string { 39 | data := ExtractClaims(c) 40 | if data["nice"] != nil { 41 | return (data["nice"]).(string) 42 | } 43 | fmt.Println("********** 路径:" + c.Request.URL.Path + " 请求方法:" + c.Request.Method + " 缺少nice") 44 | return "" 45 | } 46 | 47 | func GetRoleName(c *gin.Context) string { 48 | data := ExtractClaims(c) 49 | if data["rolekey"] != nil { 50 | return (data["rolekey"]).(string) 51 | } 52 | fmt.Println("********** 路径:" + c.Request.URL.Path + " 请求方法:" + c.Request.Method + " 缺少rolekey") 53 | return "" 54 | } 55 | 56 | func GetRoleId(c *gin.Context) int { 57 | data := ExtractClaims(c) 58 | if data["roleid"] != nil { 59 | i := int((data["roleid"]).(float64)) 60 | return i 61 | } 62 | fmt.Println("********** 路径:" + c.Request.URL.Path + " 请求方法:" + c.Request.Method + " 缺少roleid") 63 | return 0 64 | } 65 | -------------------------------------------------------------------------------- /tools/utils.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import ( 4 | "ferry/pkg/logger" 5 | "strconv" 6 | 7 | "golang.org/x/crypto/bcrypt" 8 | ) 9 | 10 | func StrToInt(err error, index string) int { 11 | result, err := strconv.Atoi(index) 12 | if err != nil { 13 | HasError(err, "string to int error"+err.Error(), -1) 14 | } 15 | return result 16 | } 17 | 18 | func CompareHashAndPassword(e string, p string) (bool, error) { 19 | err := bcrypt.CompareHashAndPassword([]byte(e), []byte(p)) 20 | if err != nil { 21 | logger.Info(err.Error()) 22 | return false, err 23 | } 24 | return true, nil 25 | } 26 | 27 | // Assert 条件断言 28 | // 当断言条件为 假 时触发 panic 29 | // 对于当前请求不会再执行接下来的代码,并且返回指定格式的错误信息和错误码 30 | func Assert(condition bool, msg string, code ...int) { 31 | if !condition { 32 | statusCode := 200 33 | if len(code) > 0 { 34 | statusCode = code[0] 35 | } 36 | panic("CustomError#" + strconv.Itoa(statusCode) + "#" + msg) 37 | } 38 | } 39 | 40 | // HasError 错误断言 41 | // 当 error 不为 nil 时触发 panic 42 | // 对于当前请求不会再执行接下来的代码,并且返回指定格式的错误信息和错误码 43 | // 若 msg 为空,则默认为 error 中的内容 44 | func HasError(err error, msg string, code ...int) { 45 | if err != nil { 46 | statusCode := 200 47 | if len(code) > 0 { 48 | statusCode = code[0] 49 | } 50 | if msg == "" { 51 | msg = err.Error() 52 | } 53 | logger.Info(err) 54 | panic("CustomError#" + strconv.Itoa(statusCode) + "#" + msg) 55 | } 56 | } 57 | --------------------------------------------------------------------------------