262 Commits

Author SHA1 Message Date
lr
7419ceb502 Merge branch 'hotfix/uploads' 2022-12-30 11:20:01 +08:00
lr
84c4b305d1 增加uploads目录 2022-12-30 11:18:55 +08:00
TinyAnts
56de8a32f1 Merge branch 'release/1.3.6' 2022-12-30 10:02:13 +08:00
TinyAnts
dbdeed946e 调整SQL文件 2022-12-30 09:53:07 +08:00
Jason
42892bcb8b Merge tag 'wjx202212300933' into develop
no message

# Conflicts:
#	frontend/assets/403.f0c419d0.js
#	frontend/assets/404.a1c8cef0.js
#	frontend/assets/add-nav.78e0236c.js
#	frontend/assets/add-nav.vue_vue_type_script_setup_true_lang.856419ed.js
#	frontend/assets/article.74bca9b5.js
#	frontend/assets/attr-setting.vue_vue_type_script_setup_true_lang.3f964a14.js
#	frontend/assets/attr.049f48d5.js
#	frontend/assets/attr.0b7b7c99.js
#	frontend/assets/attr.303c1d3b.js
#	frontend/assets/attr.80ca5719.js
#	frontend/assets/attr.a9a313fb.js
#	frontend/assets/attr.vue_vue_type_script_setup_true_lang.6d0a5dbb.js
#	frontend/assets/attr.vue_vue_type_script_setup_true_lang.8e9dd23e.js
#	frontend/assets/attr.vue_vue_type_script_setup_true_lang.9aec2f99.js
#	frontend/assets/attr.vue_vue_type_script_setup_true_lang.ab98fda4.js
#	frontend/assets/attr.vue_vue_type_script_setup_true_lang.b7d84074.js
#	frontend/assets/auth.f2a07a12.js
#	frontend/assets/auth.vue_vue_type_script_setup_true_lang.7ef0ba85.js
#	frontend/assets/cache.4c254d80.js
#	frontend/assets/code-preview.326ed395.js
#	frontend/assets/code-preview.vue_vue_type_script_setup_true_lang.136e5f05.js
#	frontend/assets/code.e8685cc5.js
#	frontend/assets/config.a5e3522c.js
#	frontend/assets/consumer.7aec82d3.js
#	frontend/assets/content.3563b530.js
#	frontend/assets/content.3f7be8fd.js
#	frontend/assets/content.54b8d1d4.js
#	frontend/assets/content.6bac01bd.js
#	frontend/assets/content.a0ce4144.js
#	frontend/assets/content.b9dac3a5.js
#	frontend/assets/content.d207a2aa.js
#	frontend/assets/content.ddf02ef6.js
#	frontend/assets/content.vue_vue_type_script_setup_true_lang.3bb51b7a.js
#	frontend/assets/content.vue_vue_type_script_setup_true_lang.afe6098d.js
#	frontend/assets/content.vue_vue_type_script_setup_true_lang.b304c701.js
#	frontend/assets/data-table.17275e70.js
#	frontend/assets/data-table.vue_vue_type_script_setup_true_lang.4be18121.js
#	frontend/assets/decoration-img.480c1d38.js
#	frontend/assets/decoration.c4bfe19f.js
#	frontend/assets/default_reply.30cc1448.js
#	frontend/assets/department.05a11643.js
#	frontend/assets/detail.0f743553.js
#	frontend/assets/dict.ce868610.js
#	frontend/assets/edit.2dbf5ac2.js
#	frontend/assets/edit.2e9c7282.js
#	frontend/assets/edit.4baeb334.js
#	frontend/assets/edit.6d9ae951.js
#	frontend/assets/edit.95929423.js
#	frontend/assets/edit.96767b58.js
#	frontend/assets/edit.9ccb2ea8.js
#	frontend/assets/edit.9ed6b70f.js
#	frontend/assets/edit.aeab9105.js
#	frontend/assets/edit.b84537ff.js
#	frontend/assets/edit.c7f85044.js
#	frontend/assets/edit.d2275167.js
#	frontend/assets/edit.d460b056.js
#	frontend/assets/edit.fcd83473.js
#	frontend/assets/edit.vue_vue_type_script_setup_true_lang.0af81f90.js
#	frontend/assets/edit.vue_vue_type_script_setup_true_lang.113cbdf9.js
#	frontend/assets/edit.vue_vue_type_script_setup_true_lang.2b98166e.js
#	frontend/assets/edit.vue_vue_type_script_setup_true_lang.4905cd93.js
#	frontend/assets/edit.vue_vue_type_script_setup_true_lang.4f65e8a1.js
#	frontend/assets/edit.vue_vue_type_script_setup_true_lang.59ff2825.js
#	frontend/assets/edit.vue_vue_type_script_setup_true_lang.74776acb.js
#	frontend/assets/edit.vue_vue_type_script_setup_true_lang.7ea5a852.js
#	frontend/assets/edit.vue_vue_type_script_setup_true_lang.8b4e0ec3.js
#	frontend/assets/edit.vue_vue_type_script_setup_true_lang.f8f78045.js
#	frontend/assets/edit.vue_vue_type_script_setup_true_lang.f8f974df.js
#	frontend/assets/environment.da0e74f3.js
#	frontend/assets/error.8fb57bb2.js
#	frontend/assets/filing.9c47550a.js
#	frontend/assets/follow_reply.107a5ac7.js
#	frontend/assets/h5.fea75e1a.js
#	frontend/assets/index.16ada191.js
#	frontend/assets/index.1771e9d1.js
#	frontend/assets/index.1fb47746.js
#	frontend/assets/index.5eb7e5c4.js
#	frontend/assets/index.6c6f898a.js
#	frontend/assets/index.75023305.js
#	frontend/assets/index.77862a69.js
#	frontend/assets/index.79dd911d.js
#	frontend/assets/index.848577dc.js
#	frontend/assets/index.84d368ba.js
#	frontend/assets/index.8982a748.js
#	frontend/assets/index.92011b5f.js
#	frontend/assets/index.9a6fb272.js
#	frontend/assets/index.a5822411.js
#	frontend/assets/index.aa44aaf7.js
#	frontend/assets/index.b7bb2d87.js
#	frontend/assets/index.bd5146fc.js
#	frontend/assets/index.beff7283.js
#	frontend/assets/index.c7812cea.js
#	frontend/assets/index.dc901e48.js
#	frontend/assets/index.ef519870.js
#	frontend/assets/index.f11ab1e9.js
#	frontend/assets/index.f66054e9.js
#	frontend/assets/index.f667cbcd.js
#	frontend/assets/index.fe3d9dae.js
#	frontend/assets/index.vue_vue_type_style_index_0_lang.c87a51a3.js
#	frontend/assets/information.28b9a11e.js
#	frontend/assets/journal.af99cc6e.js
#	frontend/assets/keyword_reply.1fe852e8.js
#	frontend/assets/login.f0fef830.js
#	frontend/assets/login_register.c80d9ed9.js
#	frontend/assets/menu.09d42840.js
#	frontend/assets/menu.0ae9ccbc.js
#	frontend/assets/menu.eae2d8fc.js
#	frontend/assets/message.1e9ad99e.js
#	frontend/assets/oa-attr.7c3cd5f4.js
#	frontend/assets/oa-menu-form-edit.d931b7f0.js
#	frontend/assets/oa-menu-form-edit.vue_vue_type_script_setup_true_lang.2af5db4a.js
#	frontend/assets/oa-menu-form.fff01e76.js
#	frontend/assets/oa-menu-form.vue_vue_type_script_setup_true_lang.f8a3c660.js
#	frontend/assets/oa-phone.85104509.js
#	frontend/assets/picker.6266f853.js
#	frontend/assets/picker.bb543009.js
#	frontend/assets/post.01f561c3.js
#	frontend/assets/preview.7ce5d1df.js
#	frontend/assets/protocol.64ac74bd.js
#	frontend/assets/role.eef9faf9.js
#	frontend/assets/setting.be7e8445.js
#	frontend/assets/setup.d2d0d2bc.js
#	frontend/assets/system.fd9f3942.js
#	frontend/assets/tabbar.777ec1ab.js
#	frontend/assets/useDictOptions.15dee2f9.js
#	frontend/assets/useMenuOa.192cb686.js
#	frontend/assets/user.4c0b4415.js
#	frontend/assets/weapp.1dfe0168.js
#	frontend/assets/website.0825f59c.js
#	frontend/assets/wx_dev.01a9b978.js
#	frontend/assets/wx_oa.1210c1af.js
#	frontend/index.html
#	public/admin/assets/403.be75ce33.js
#	public/admin/assets/403.c7652e24.js
#	public/admin/assets/404.dc53075e.js
#	public/admin/assets/404.ff366785.js
#	public/admin/assets/add-nav.71c25bc4.js
#	public/admin/assets/add-nav.8ff08431.js
#	public/admin/assets/add-nav.vue_vue_type_script_setup_true_lang.215ec6d4.js
#	public/admin/assets/add-nav.vue_vue_type_script_setup_true_lang.8851ce0d.js
#	public/admin/assets/article.38714de2.js
#	public/admin/assets/article.51338dfb.js
#	public/admin/assets/attr-setting.b26b2685.js
#	public/admin/assets/attr-setting.vue_vue_type_script_setup_true_lang.84e61532.js
#	public/admin/assets/attr-setting.vue_vue_type_script_setup_true_lang.c0a78b81.js
#	public/admin/assets/attr.0bf07d6c.js
#	public/admin/assets/attr.1105345f.js
#	public/admin/assets/attr.1a24a3b1.js
#	public/admin/assets/attr.39b6c6f4.js
#	public/admin/assets/attr.65290945.js
#	public/admin/assets/attr.6c55da6b.js
#	public/admin/assets/attr.805fa21f.js
#	public/admin/assets/attr.98b102e5.js
#	public/admin/assets/attr.ac5be732.js
#	public/admin/assets/attr.bc1c3a6a.js
#	public/admin/assets/attr.vue_vue_type_script_setup_true_lang.1024ff07.js
#	public/admin/assets/attr.vue_vue_type_script_setup_true_lang.2e693200.js
#	public/admin/assets/attr.vue_vue_type_script_setup_true_lang.610eeb03.js
#	public/admin/assets/attr.vue_vue_type_script_setup_true_lang.68317d75.js
#	public/admin/assets/attr.vue_vue_type_script_setup_true_lang.7c96b670.js
#	public/admin/assets/attr.vue_vue_type_script_setup_true_lang.9aa3d580.js
#	public/admin/assets/attr.vue_vue_type_script_setup_true_lang.9d5db47c.js
#	public/admin/assets/attr.vue_vue_type_script_setup_true_lang.a51cc6d0.js
#	public/admin/assets/attr.vue_vue_type_script_setup_true_lang.c2c86fa3.js
#	public/admin/assets/attr.vue_vue_type_script_setup_true_lang.dc504eeb.js
#	public/admin/assets/auth.58436929.js
#	public/admin/assets/auth.72ce47e2.js
#	public/admin/assets/auth.vue_vue_type_script_setup_true_lang.9144d151.js
#	public/admin/assets/auth.vue_vue_type_script_setup_true_lang.f2e0efdb.js
#	public/admin/assets/cache.1411bd71.js
#	public/admin/assets/cache.eaaa3b01.js
#	public/admin/assets/code-preview.b3fbdb96.js
#	public/admin/assets/code-preview.cbbe484e.js
#	public/admin/assets/code-preview.vue_vue_type_script_setup_true_lang.417cad3e.js
#	public/admin/assets/code-preview.vue_vue_type_script_setup_true_lang.dece62bb.js
#	public/admin/assets/code.1b609fc8.js
#	public/admin/assets/code.70be45c9.js
#	public/admin/assets/config.67eec5e0.js
#	public/admin/assets/config.72957399.js
#	public/admin/assets/consumer.ac2027e1.js
#	public/admin/assets/consumer.d53e90aa.js
#	public/admin/assets/content.0331f6f6.js
#	public/admin/assets/content.06cd617c.js
#	public/admin/assets/content.0abc6fd8.js
#	public/admin/assets/content.3eb29ea6.js
#	public/admin/assets/content.4392d29d.js
#	public/admin/assets/content.4b82873f.js
#	public/admin/assets/content.4f3df2a4.js
#	public/admin/assets/content.6d4b870e.js
#	public/admin/assets/content.7be5491b.js
#	public/admin/assets/content.7dbaf50d.js
#	public/admin/assets/content.8770db05.js
#	public/admin/assets/content.c073f4f9.js
#	public/admin/assets/content.c942e0cc.js
#	public/admin/assets/content.d57a1119.js
#	public/admin/assets/content.ea750dee.js
#	public/admin/assets/content.f103064c.js
#	public/admin/assets/content.vue_vue_type_script_setup_true_lang.217e9a8e.js
#	public/admin/assets/content.vue_vue_type_script_setup_true_lang.35dd01b2.js
#	public/admin/assets/content.vue_vue_type_script_setup_true_lang.64d77af9.js
#	public/admin/assets/content.vue_vue_type_script_setup_true_lang.96010cac.js
#	public/admin/assets/content.vue_vue_type_script_setup_true_lang.a2c85d60.js
#	public/admin/assets/content.vue_vue_type_script_setup_true_lang.e873fa0c.js
#	public/admin/assets/data-table.07e93a3a.js
#	public/admin/assets/data-table.fb9b752a.js
#	public/admin/assets/data-table.vue_vue_type_script_setup_true_lang.7f9e9084.js
#	public/admin/assets/data-table.vue_vue_type_script_setup_true_lang.f66dc883.js
#	public/admin/assets/decoration-img.4dec7bca.js
#	public/admin/assets/decoration-img.9d7f6da2.js
#	public/admin/assets/decoration.7912193e.js
#	public/admin/assets/decoration.815a1b2b.js
#	public/admin/assets/default_reply.6fdb7d94.js
#	public/admin/assets/default_reply.cf5a89f4.js
#	public/admin/assets/department.48a04152.js
#	public/admin/assets/department.86e3365f.js
#	public/admin/assets/detail.de7ed10a.js
#	public/admin/assets/detail.e67949b0.js
#	public/admin/assets/dict.68f4cb01.js
#	public/admin/assets/dict.7598c3e1.js
#	public/admin/assets/edit.04acf599.js
#	public/admin/assets/edit.1058ab87.js
#	public/admin/assets/edit.19542373.js
#	public/admin/assets/edit.195b6c37.js
#	public/admin/assets/edit.1efad864.js
#	public/admin/assets/edit.2353d155.js
#	public/admin/assets/edit.2c45ecc3.js
#	public/admin/assets/edit.32c4d425.js
#	public/admin/assets/edit.363d1c9c.js
#	public/admin/assets/edit.4a9641ad.js
#	public/admin/assets/edit.4b2283de.js
#	public/admin/assets/edit.4cadd5f2.js
#	public/admin/assets/edit.559ac486.js
#	public/admin/assets/edit.5da54424.js
#	public/admin/assets/edit.66fa646d.js
#	public/admin/assets/edit.68731657.js
#	public/admin/assets/edit.6b367aca.js
#	public/admin/assets/edit.743f4c0c.js
#	public/admin/assets/edit.872eb840.js
#	public/admin/assets/edit.886d9084.js
#	public/admin/assets/edit.8d7da4aa.js
#	public/admin/assets/edit.9a168e9e.js
#	public/admin/assets/edit.b78cf684.js
#	public/admin/assets/edit.c581b19c.js
#	public/admin/assets/edit.c5a5e1ec.js
#	public/admin/assets/edit.dec130d9.js
#	public/admin/assets/edit.e30c9927.js
#	public/admin/assets/edit.e44bdfb6.js
#	public/admin/assets/edit.ee60daaf.js
#	public/admin/assets/edit.f67b0c7d.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.1e2b9cbb.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.2026007c.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.20c72cd4.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.21beb4c8.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.309dc4b4.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.35c06c20.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.401606cd.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.4e0b8a6b.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.4fbfad27.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.4feed0c9.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.6e4cbbd1.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.71edccc3.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.735deee1.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.8031e87f.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.8a9d92ef.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.8ee65651.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.95b7f706.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.964927cf.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.9734ead4.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.a2645652.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.bc00cb19.js
#	public/admin/assets/edit.vue_vue_type_script_setup_true_lang.dec3e455.js
#	public/admin/assets/environment.a1f39ebd.js
#	public/admin/assets/environment.a824f3db.js
#	public/admin/assets/error.3245b397.js
#	public/admin/assets/error.ad96ad67.js
#	public/admin/assets/filing.a511c649.js
#	public/admin/assets/filing.eccc076c.js
#	public/admin/assets/follow_reply.b676d4ee.js
#	public/admin/assets/follow_reply.e30a481b.js
#	public/admin/assets/h5.2a7add8f.js
#	public/admin/assets/h5.afd9020f.js
#	public/admin/assets/index.011bede3.js
#	public/admin/assets/index.04d77970.js
#	public/admin/assets/index.0d2f02aa.js
#	public/admin/assets/index.136be2f4.js
#	public/admin/assets/index.1530a00e.js
#	public/admin/assets/index.16fe56fd.js
#	public/admin/assets/index.1866acee.js
#	public/admin/assets/index.1f81f8b5.js
#	public/admin/assets/index.21b73b19.js
#	public/admin/assets/index.22f8ab12.js
#	public/admin/assets/index.2539f5ae.js
#	public/admin/assets/index.28c53d29.js
#	public/admin/assets/index.2c0a48a6.js
#	public/admin/assets/index.3257f813.js
#	public/admin/assets/index.3745546a.js
#	public/admin/assets/index.3b91d655.js
#	public/admin/assets/index.3fbb5f30.js
#	public/admin/assets/index.4fd20bc9.js
#	public/admin/assets/index.50bcf3eb.js
#	public/admin/assets/index.523e1856.js
#	public/admin/assets/index.565fa41f.js
#	public/admin/assets/index.588358a2.js
#	public/admin/assets/index.58d92e59.js
#	public/admin/assets/index.5a304e0e.js
#	public/admin/assets/index.5cc34703.js
#	public/admin/assets/index.5f24c449.js
#	public/admin/assets/index.64e62b67.js
#	public/admin/assets/index.65cfc9bc.js
#	public/admin/assets/index.6d47c9ed.js
#	public/admin/assets/index.6f04b646.js
#	public/admin/assets/index.73a26a62.js
#	public/admin/assets/index.783c022e.js
#	public/admin/assets/index.7b48eeb3.js
#	public/admin/assets/index.8bcf72cb.js
#	public/admin/assets/index.942364fe.js
#	public/admin/assets/index.963c9b05.js
#	public/admin/assets/index.9ab195d2.js
#	public/admin/assets/index.a80222dc.js
#	public/admin/assets/index.a885a6ae.js
#	public/admin/assets/index.b348b281.js
#	public/admin/assets/index.b7299661.js
#	public/admin/assets/index.c93a1529.js
#	public/admin/assets/index.cdb9f716.js
#	public/admin/assets/index.d1b8bb0d.js
#	public/admin/assets/index.e66cf170.js
#	public/admin/assets/index.eeba4956.js
#	public/admin/assets/index.f040d64d.js
#	public/admin/assets/index.f6838d76.js
#	public/admin/assets/index.fd4cf356.js
#	public/admin/assets/index.fdde7276.js
#	public/admin/assets/index.vue_vue_type_style_index_0_lang.26fd2700.js
#	public/admin/assets/index.vue_vue_type_style_index_0_lang.8a5b07f4.js
#	public/admin/assets/information.5f67d768.js
#	public/admin/assets/information.aef5fed0.js
#	public/admin/assets/journal.64e725be.js
#	public/admin/assets/journal.c7bb9e85.js
#	public/admin/assets/keyword_reply.55add9d3.js
#	public/admin/assets/keyword_reply.57eeee16.js
#	public/admin/assets/login.3e20fdbc.js
#	public/admin/assets/login.dfb02019.js
#	public/admin/assets/login_register.f086e958.js
#	public/admin/assets/login_register.fce39c20.js
#	public/admin/assets/menu.00ecf38c.js
#	public/admin/assets/menu.1480198a.js
#	public/admin/assets/menu.5f3f4c47.js
#	public/admin/assets/menu.7368e3d7.js
#	public/admin/assets/menu.77a3989d.js
#	public/admin/assets/menu.b1b1aaa6.js
#	public/admin/assets/message.15ef96dc.js
#	public/admin/assets/message.8743f2b4.js
#	public/admin/assets/oa-attr.98d5d599.js
#	public/admin/assets/oa-attr.e543aa62.js
#	public/admin/assets/oa-menu-form-edit.045f9ab6.js
#	public/admin/assets/oa-menu-form-edit.6d6a7d14.js
#	public/admin/assets/oa-menu-form-edit.vue_vue_type_script_setup_true_lang.4a94d8c8.js
#	public/admin/assets/oa-menu-form-edit.vue_vue_type_script_setup_true_lang.e36a043a.js
#	public/admin/assets/oa-menu-form.57debade.js
#	public/admin/assets/oa-menu-form.5af7d29e.js
#	public/admin/assets/oa-menu-form.vue_vue_type_script_setup_true_lang.67bb8ea5.js
#	public/admin/assets/oa-menu-form.vue_vue_type_script_setup_true_lang.e41e7bd3.js
#	public/admin/assets/oa-phone.48a76668.js
#	public/admin/assets/oa-phone.66424cfe.js
#	public/admin/assets/picker.0b96d088.js
#	public/admin/assets/picker.5d8eed0a.js
#	public/admin/assets/picker.7fdea6ff.js
#	public/admin/assets/picker.dbcd437c.js
#	public/admin/assets/post.09fddbe1.js
#	public/admin/assets/post.ef78bb4b.js
#	public/admin/assets/preview.02e7bf70.js
#	public/admin/assets/preview.26af8dc8.js
#	public/admin/assets/protocol.1a7d013b.js
#	public/admin/assets/protocol.8e267222.js
#	public/admin/assets/role.86090770.js
#	public/admin/assets/role.b25c198c.js
#	public/admin/assets/setting.2f03e550.js
#	public/admin/assets/setting.5ca7d662.js
#	public/admin/assets/setup.684d6202.js
#	public/admin/assets/setup.e44fd5fe.js
#	public/admin/assets/system.2ead1522.js
#	public/admin/assets/system.35951c5a.js
#	public/admin/assets/tabbar.34f74b99.js
#	public/admin/assets/tabbar.bdd89062.js
#	public/admin/assets/useDictOptions.5cafb1f4.js
#	public/admin/assets/useDictOptions.b34b37f1.js
#	public/admin/assets/useMenuOa.870ab9e1.js
#	public/admin/assets/useMenuOa.d7923d98.js
#	public/admin/assets/user.4d5749bd.js
#	public/admin/assets/user.a9344a7d.js
#	public/admin/assets/weapp.57fd07ba.js
#	public/admin/assets/weapp.7765716e.js
#	public/admin/assets/website.4c8013dc.js
#	public/admin/assets/website.e8828dd2.js
#	public/admin/assets/wx_dev.146ac4c9.js
#	public/admin/assets/wx_dev.649507e0.js
#	public/admin/assets/wx_oa.4f05f86f.js
#	public/admin/assets/wx_oa.bdf9a81f.js
2022-12-30 09:39:13 +08:00
Jason
a7d6b7ce61 Merge branch 'hotfix/wjx202212300933' 2022-12-30 09:38:20 +08:00
Jason
d9f6b66c56 重新打包,移除打包文件 2022-12-30 09:38:09 +08:00
Jason
373bd551d7 Merge tag 'wjx202212291606' into develop
no message
2022-12-29 16:27:16 +08:00
Jason
e5f1ac1231 Merge branch 'hotfix/wjx202212291606' 2022-12-29 16:27:15 +08:00
Jason
c3e0a81b31 打包 2022-12-29 16:27:02 +08:00
Jason
df513e47ec 调整代码生成器设置 2022-12-29 16:04:32 +08:00
TinyAnts
62a3606169 修复代码生成关联表前缀问题 2022-12-29 14:16:54 +08:00
TinyAnts
97202201a2 优化定时任务 2022-12-29 11:59:10 +08:00
TinyAnts
088fffe836 调整获取所有库表不分页 2022-12-29 11:10:54 +08:00
TinyAnts
d59c9de38a 增加所有库表接口 2022-12-29 10:08:03 +08:00
TinyAnts
d63947856b 增加查询所有表接口 2022-12-29 09:43:05 +08:00
全栈程序员钟哥
36b6540a60 修改readme
Signed-off-by: 全栈程序员钟哥 <294687409@qq.com>
2022-12-28 07:34:22 +00:00
Jason
49fd6d3639 后台打包 2022-12-28 10:13:50 +08:00
Jason
3fd832d9e6 代码生成器配置调整 2022-12-28 10:12:33 +08:00
TinyAnts
aabc6205fb 增加返回字段 2022-12-28 10:05:35 +08:00
TinyAnts
4a7fd71da7 增加演示环境 ***** 敏感数据处理 2022-12-27 17:16:40 +08:00
TinyAnts
d7b6dc992f 移除多余代码 2022-12-23 18:11:10 +08:00
TinyAnts
2998041bde 移除多余代码 2022-12-23 17:52:20 +08:00
TinyAnts
2304922b8a 修复公众号授权登录bug 2022-12-23 16:13:30 +08:00
Jason
049209bfca 调整代码生成器模板 2022-12-23 14:50:25 +08:00
TinyAnts
dc5ed4b14b 修改包 2022-12-21 12:06:38 +08:00
TinyAnts
9beff48e28 增加演示环境拦截 2022-12-21 11:21:54 +08:00
TinyAnts
173640af07 微信扫码登录 2022-12-20 17:56:19 +08:00
TinyAnts
919cdc243c Merge branch 'develop' of https://gitee.com/likeadmin/likeadmin_java into develop 2022-12-20 17:33:08 +08:00
TinyAnts
670ac0208c 扫码登录 2022-12-20 17:33:01 +08:00
caijianhao
869c444fa5 Merge branch 'develop' of https://gitee.com/likeadmin/likeadmin_java into develop 2022-12-20 17:09:01 +08:00
caijianhao
8b6b0e5257 调整网站信息设置接口 2022-12-20 17:08:38 +08:00
TinyAnts
8fed83cd15 优化用户端登录代码 2022-12-20 16:13:45 +08:00
caijianhao
864b54951a Merge branch 'develop' of https://gitee.com/likeadmin/likeadmin_java into develop
# Conflicts:
#	server/like-front/src/main/java/com/mdd/front/config/FrontConfig.java
2022-12-20 15:50:21 +08:00
caijianhao
9e89783add pc端首页接口 2022-12-20 15:49:29 +08:00
TinyAnts
3b8e501a0b 优化登录代码 2022-12-20 15:22:17 +08:00
TinyAnts
3e97c2201b 增加开放平台渠道设置管理 2022-12-20 14:53:08 +08:00
TinyAnts
3b5a8ae197 Merge branch 'develop' of https://gitee.com/likeadmin/likeadmin_java into develop
# Conflicts:
#	server/like-front/src/main/java/com/mdd/front/config/FrontConfig.java
2022-12-20 11:56:17 +08:00
TinyAnts
43983deb48 扫码登录二维码 2022-12-20 11:55:21 +08:00
caijianhao
2022859769 Merge branch 'develop' of https://gitee.com/likeadmin/likeadmin_java into develop 2022-12-20 11:36:29 +08:00
DESKTOP-9BP5159\XY-003
bdf79ccb84 pc端配置接口 2022-12-20 11:36:20 +08:00
DESKTOP-9BP5159\XY-003
2a1d803c5f 调整接口 2022-12-20 11:23:26 +08:00
TinyAnts
444ea6b4cb 修复代码生成器bug 2022-12-12 18:03:59 +08:00
TinyAnts
f76a83b918 增加描述 2022-12-08 14:55:06 +08:00
TinyAnts
6e7292b97c Merge branch 'release/1.3.5' 2022-12-07 14:58:33 +08:00
TinyAnts
4281a0f5bc Merge tag '1.3.5' into develop 2022-12-07 14:58:33 +08:00
TinyAnts
933ea5a3dd bug处理 2022-12-07 10:10:54 +08:00
TinyAnts
75c8b03969 Merge branch 'develop' of https://gitee.com/likeadmin/likeadmin_java into develop 2022-12-06 10:20:56 +08:00
TinyAnts
a22fe53275 修复附件管理名称超长问题 2022-12-06 09:40:00 +08:00
TinyAnts
85ba64cd2f 处理日志功能时间线程问题 2022-12-06 09:39:33 +08:00
Jason
1d83523405 定时任务列表添加最后执行时间 2022-12-06 09:32:43 +08:00
xinjie
1ab2ca6b4e 打包 2022-12-02 17:03:56 +08:00
xinjie
5c043df578 完成定时任务对接 2022-12-02 17:01:30 +08:00
TinyAnts
f7a1b14500 修复定时任务新增没有分组 2022-12-02 16:54:46 +08:00
TinyAnts
a1a70346c9 init 2022-12-02 15:01:39 +08:00
TinyAnts
edfbe6ab4c 开放权限 2022-12-02 14:49:01 +08:00
TinyAnts
d593391f62 Merge branch 'develop' of https://gitee.com/likeadmin/likeadmin_java into develop 2022-12-02 14:42:31 +08:00
TinyAnts
5f5026d40c 优化工具类的命名 2022-12-02 14:42:20 +08:00
xinjie
2453b0fc3b 修复上传文件请求头参数错误问题 2022-12-02 14:40:25 +08:00
TinyAnts
0077e75e85 修复管理员搜索bug 2022-12-02 14:18:29 +08:00
TinyAnts
327f0df6a9 增加定时任务管理 2022-12-02 14:14:34 +08:00
TinyAnts
03d09ca7d7 增加定时任务管理 2022-12-01 14:27:19 +08:00
TinyAnts
621e7916dc 计划任务管理 2022-11-30 22:09:27 +08:00
TinyAnts
c2a64e30f5 Merge branch 'develop' of https://gitee.com/likeadmin/likeadmin_java into develop 2022-11-30 15:57:27 +08:00
TinyAnts
698d44696e 接入EasyExel依赖 2022-11-30 15:54:10 +08:00
xinjie
ef350201ca 调整管理员支持多部门多角色 2022-11-29 19:05:29 +08:00
TinyAnts
06bc994b42 修复管理员报错 2022-11-29 18:52:47 +08:00
windy
2c5310ca21 调整 多角色 多部门 多岗位 2022-11-29 16:57:15 +08:00
全栈程序员钟哥
0c5d7641b0 修改文档内容
Signed-off-by: 全栈程序员钟哥 <294687409@qq.com>
2022-11-22 06:21:47 +00:00
xinjie
af92e6209c 微信小程序头像,昵称调整 2022-11-21 15:52:00 +08:00
lr
cab7c3af39 Merge branch 'hotfix/lr-20221120' 2022-11-20 23:23:20 +08:00
lr
c38c46c09f Merge branch 'master' into develop 2022-11-20 23:23:20 +08:00
lr
1805cb1515 调整README信息 2022-11-20 23:23:01 +08:00
TinyAnts
0d086f6198 Merge tag '1.3.4' into develop 2022-11-17 18:55:44 +08:00
TinyAnts
4d43d7cdcc Merge branch 'release/1.3.4' 2022-11-17 18:55:42 +08:00
TinyAnts
8105c877af 安装sql 2022-11-17 18:28:16 +08:00
TinyAnts
ff5b649969 修复管理员编辑bug 2022-11-17 18:07:11 +08:00
Jason
c64d0151b3 打包,调整文件接口路径 2022-11-17 17:45:49 +08:00
Jason
98328e1bb1 打包 2022-11-17 17:33:22 +08:00
TinyAnts
402321fe3c 系统管理员编辑限制 2022-11-17 17:32:29 +08:00
TinyAnts
830c10ea73 增加系统管理员校验 2022-11-17 17:31:13 +08:00
TinyAnts
728a0f6ec5 调整注释 2022-11-17 17:03:25 +08:00
TinyAnts
40df111da7 修复通知设置bug 2022-11-17 16:40:28 +08:00
Jason
1d7c2383c1 调整素材中心按钮权限相关 2022-11-17 16:38:59 +08:00
Jason
3137a59566 Merge branch 'develop' of https://gitee.com/likeshop_gitee/likeadmin-java into develop 2022-11-17 16:25:37 +08:00
Jason
339f63c0c0 调整素材相关接口 2022-11-17 16:25:28 +08:00
TinyAnts
edc5357b8c 调整素材接口 2022-11-17 16:14:51 +08:00
TinyAnts
e22508240d Merge branch 'develop' of https://gitee.com/likeadmin/likeadmin_java into develop 2022-11-17 16:09:06 +08:00
TinyAnts
8480f98f28 调整登录异常监控 2022-11-17 16:09:01 +08:00
Jason
45b11402ce 调整管理员 2022-11-17 16:06:23 +08:00
TinyAnts
ef53643368 修复用户忘记密码bug 2022-11-17 15:42:26 +08:00
TinyAnts
41d372da5f 修复用户修改密码依然是密码错误bug 2022-11-17 15:40:47 +08:00
TinyAnts
aa4ba06be0 修复用户修改密码bug 2022-11-17 15:30:06 +08:00
TinyAnts
aa92623d7c 调整登录时效读配置 2022-11-17 15:27:11 +08:00
TinyAnts
b13523ca5e 优化登录时效配置 2022-11-17 15:18:45 +08:00
TinyAnts
522c698f6c 修复uniapp端更新手机号后createTime被更新 2022-11-17 15:07:32 +08:00
TinyAnts
b1fe1d9d47 Merge branch 'develop' of https://gitee.com/likeadmin/likeadmin_java into develop 2022-11-17 14:59:48 +08:00
TinyAnts
25a85adf9e 处理编辑管理员 2022-11-17 14:59:32 +08:00
Jason
54c58d6ee1 调整后台底部导航,上传文件接口 2022-11-17 14:57:35 +08:00
TinyAnts
52615d1646 sa-token异常拦截 2022-11-17 14:53:29 +08:00
TinyAnts
2cd73748bb 修复底部导航编辑bug 2022-11-17 12:18:53 +08:00
TinyAnts
e23cb64f32 调整上传目录配置 2022-11-17 12:02:04 +08:00
TinyAnts
c639499fbc 修复静态图片404问题 2022-11-17 11:50:27 +08:00
TinyAnts
bd97df6f7b 优化代码 2022-11-17 11:39:14 +08:00
TinyAnts
e211426c1a 优化404拦截写法 2022-11-16 23:21:59 +08:00
TinyAnts
dafaf09011 修复json响应工具 2022-11-16 23:09:33 +08:00
TinyAnts
97b8f7016d 调整代码生成器 2022-11-16 22:59:16 +08:00
TinyAnts
3247a5f7d0 调整代码生成器 2022-11-16 22:06:21 +08:00
TinyAnts
57c88cf773 调整代码生成器 2022-11-16 19:01:45 +08:00
TinyAnts
329734b332 代码生成器 2022-11-16 18:17:59 +08:00
TinyAnts
c622781003 代码生成器调整 2022-11-16 17:54:01 +08:00
xinjie
e89f22cd8c 调整接口的一些字段及接口名称 2022-11-16 16:18:59 +08:00
TinyAnts
6db7255ed3 优化通知驱动类 2022-11-16 16:11:38 +08:00
TinyAnts
7a37ac18ac 修复通知设置bug 2022-11-16 15:01:40 +08:00
TinyAnts
ca9a251176 修复管理员编辑bug 2022-11-16 12:08:09 +08:00
TinyAnts
798d12c16f 修复登录问题 2022-11-16 12:00:43 +08:00
TinyAnts
124b1ff5dd 调整json转换工具 2022-11-16 11:49:39 +08:00
TinyAnts
a5d63d6c96 接入sa-token 2022-11-16 11:35:52 +08:00
TinyAnts
956bf841b3 整体优化代码结构 2022-11-15 22:25:17 +08:00
xinjie
e685304616 移动端-资讯中心下拉导航栏消失问题 2022-11-15 14:59:23 +08:00
xinjie
abbd23e332 可视化装修能拖拽排序 2022-11-15 14:46:12 +08:00
xinjie
37d39503bd 修改工作台二维码图片 2022-11-15 14:30:34 +08:00
xinjie
8055572f19 设置添加面包屑,logo配置 2022-11-15 14:23:03 +08:00
xinjie
7383a145b4 设置添加面包屑,logo配置 2022-11-15 14:18:24 +08:00
TinyAnts
1ab009544f Merge tag '13.3' into develop 2022-10-14 17:09:06 +08:00
TinyAnts
fb9e5c3d49 Merge branch 'release/13.3' 2022-10-14 17:09:06 +08:00
TinyAnts
32232cb604 修改安装SQL 2022-10-14 16:16:20 +08:00
TinyAnts
bd5f7bcad0 修改版本号 2022-10-14 16:14:02 +08:00
Jason
8e5d515e4c 调整版本号 2022-10-14 15:49:14 +08:00
Jason
abf98ee5e7 修复代码生成的页面无法缓存的问题 2022-10-14 15:39:02 +08:00
Jason
61a9a453f4 调整dictvalue组件 2022-10-14 15:28:44 +08:00
Jason
3dd371161b 打包 2022-10-14 14:54:18 +08:00
TinyAnts
88af20071b 修复代码生成器导入小数报错问题 2022-10-14 11:40:10 +08:00
TinyAnts
514b0108a5 修复代码生成器新增bug 2022-10-14 11:33:14 +08:00
TinyAnts
8c2729493d 修复代码生成存在小数的问题 2022-10-14 11:26:40 +08:00
Jason
47e968ddf9 部分输入框添加长度限制 2022-10-14 11:15:47 +08:00
TinyAnts
4d5615f90d 去除调试的注释 2022-10-14 11:09:29 +08:00
TinyAnts
8283695735 调整参数校验 2022-10-14 10:49:37 +08:00
Jason
8432eef4cf 调整所有排序的最大值 2022-10-14 10:47:21 +08:00
TinyAnts
e0407759d4 优化部门排序限制 2022-10-14 10:14:38 +08:00
TinyAnts
2eae8d9e94 优化统一时间写法 2022-10-14 10:00:25 +08:00
Ants
6efc39f902 !24 更新登录信息
Merge pull request !24 from 也曾为你、像超人/N/A
2022-10-14 01:58:27 +00:00
TinyAnts
0a708b79f0 修复登录重复更新信息bug 2022-10-14 09:55:52 +08:00
也曾为你、像超人
36e4725565 更新登录信息
Signed-off-by: 也曾为你、像超人 <1553592282@qq.com>
2022-10-13 13:07:38 +00:00
Jason
5029618235 !21 修复I5TUL1问题
Merge pull request !21 from 2014520/develop
2022-10-13 09:24:45 +00:00
Jason
1595d987ed 路由验权调整 2022-10-13 17:00:50 +08:00
Jason
35cec2a64c 登录页面跳转 2022-10-13 16:59:59 +08:00
Jason
6ee54646a8 调整微信公众号回复管理弹窗点击空白关闭问题 2022-10-13 16:59:34 +08:00
Jason
3deaa814a4 调整后台文案 2022-10-13 16:08:31 +08:00
Jason
4c458aeeac 管理员弹窗因类型问题警告 2022-10-13 15:48:05 +08:00
Jason
a99227d2ef 修复富文本编辑器全屏层级问题 2022-10-13 15:47:31 +08:00
Jason
10c95a0dee 修复h5协议跳转问题 2022-10-13 15:03:11 +08:00
Jason
3094503b17 调整图片选择器 2022-10-13 15:01:12 +08:00
TinyAnts
0e7944bd37 Merge tag '13.2' into develop 2022-09-30 16:32:41 +08:00
TinyAnts
83f57ad01d Merge branch 'release/13.2' 2022-09-30 16:32:37 +08:00
TinyAnts
e05348206e 修复底部导航错误 2022-09-30 16:26:39 +08:00
TinyAnts
f4e4130cab 调整安装SQL 2022-09-30 15:36:20 +08:00
TinyAnts
0817b16615 调整素材 2022-09-30 14:53:46 +08:00
zhangliang
e16fc88e81 修复I5TUL1问题-编辑用户信息字段超长 2022-09-30 14:52:11 +08:00
Jason
f3b10f07b1 打包 2022-09-30 14:13:20 +08:00
Jason
e191fc8d26 公众号回复调整 2022-09-30 14:05:38 +08:00
TinyAnts
8052475e40 修复公众号回复管理 2022-09-30 11:49:03 +08:00
Jason
0cc7c8e7b9 修改环境变量配置,app目录-->uniapp 2022-09-30 10:23:58 +08:00
TinyAnts
9b5b625680 调整SQL文件 2022-09-29 17:11:40 +08:00
Jason
5d06003895 修改代码生气器模板 2022-09-29 15:23:46 +08:00
Jason
061543a191 热门搜索排除空值 2022-09-29 15:18:41 +08:00
Jason
c073cc65a7 只展开一个一级菜单开关 2022-09-29 14:55:04 +08:00
Jason
5b9af90590 修复保存图片错误 2022-09-29 14:41:46 +08:00
Jason
61ef48d446 修复登录账号没有任何权限时跳转到403页面错误 2022-09-29 14:39:56 +08:00
Jason
331997e1e9 上传文件优化 2022-09-29 10:41:33 +08:00
Jason
a4b6b2d6c8 修改搜索栏input框宽度 2022-09-29 10:26:49 +08:00
Jason
140249aca8 修复通知提示bug 2022-09-29 10:26:11 +08:00
Jason
6719e1b4f1 素材中心优化 2022-09-29 10:19:03 +08:00
likeshop技术社区
6bf572a01a add LICENSE.
Signed-off-by: likeshop技术社区 <419339937@qq.com>
2022-09-29 02:17:21 +00:00
Jason
b74724084e 富文本优化 2022-09-29 10:16:59 +08:00
likeshop技术社区
580c06686a 删除文件 LICENSE 2022-09-29 02:16:58 +00:00
TinyAnts
235ab92413 优化代码 2022-09-28 09:38:52 +08:00
TinyAnts
4b58de936c init 2022-09-28 09:25:54 +08:00
TinyAnts
611f59941f 优化代码规范 2022-09-27 19:01:50 +08:00
TinyAnts
8db1cff376 优化代码 2022-09-27 18:54:07 +08:00
TinyAnts
6cb4ad95a7 优化代码 2022-09-27 18:25:24 +08:00
TinyAnts
5e9db85f86 优化调整代码规范 2022-09-27 17:47:32 +08:00
TinyAnts
11c06ec81e 代码生成器 2022-09-26 11:14:36 +08:00
TinyAnts
551a042582 修复代码生成器bug 2022-09-26 11:11:58 +08:00
TinyAnts
eb0ab251d5 优化代码生成器注释生成 2022-09-26 10:43:48 +08:00
TinyAnts
19e2d1c03b 优化代码生成器注释生成 2022-09-26 10:42:34 +08:00
TinyAnts
71066b6d83 修复代码生成器主键有下划线错误 2022-09-26 10:22:02 +08:00
TinyAnts
6f11895f70 修复AOP上传文件记录日志错误 2022-09-26 09:29:31 +08:00
Ants
909b4f03a0 !18 处理文件类型上传导致日志收集失败: I5SYLB
Merge pull request !18 from mlzhang/cherry-pick-1664048747
2022-09-26 01:27:07 +00:00
TinyAnts
48e39fa4f9 阿里云存储文案调整 2022-09-26 09:21:23 +08:00
mlzhang
b20738061e fixed 1d998d1 from https://gitee.com/zmldaniu/likeadmin_java/pulls/17
🐛 增加日志类型、判断文件类型记录文件名称 #I5SYLB
2022-09-24 19:45:49 +00:00
Ants
808cda3277 回退 'Pull Request !8 : 处理iss 优化建议' 2022-09-23 07:00:25 +00:00
Ants
42c7936f40 !8 处理iss 优化建议
Merge pull request !8 from mlzhang/master
2022-09-23 06:10:22 +00:00
Ants
dacded0e7a !15 修复代码生成器导入数据表,编辑字段问题,兼容mysql8
Merge pull request !15 from hawk/master
2022-09-23 06:08:37 +00:00
hawk
b2cf624380 取消更新javaType 2022-09-23 09:40:01 +08:00
hawk
5faf6aa301 Revert "不更新配置"
This reverts commit a70c5f6fc3.
2022-09-23 09:36:26 +08:00
hawk
b66eb35abb Merge branch 'javaType修复'
* javaType修复:
  修复代码生成器编辑数据表,不能保存java类型
2022-09-23 08:49:08 +08:00
hawk
ee8636ec54 修复代码生成器编辑数据表,不能保存java类型 2022-09-23 08:31:46 +08:00
hawk
a6d3ffb016 Revert "修复代码生成器编辑数据表,不能保存java类型"
This reverts commit 04a5d121a8.
2022-09-23 08:11:23 +08:00
hawk
04a5d121a8 修复代码生成器编辑数据表,不能保存java类型 2022-09-23 07:56:15 +08:00
hawk
a70c5f6fc3 不更新配置 2022-09-23 07:55:01 +08:00
TinyAnts
6dc8cc78a2 调整SQL文件 2022-09-22 09:39:24 +08:00
hawk
78db1ace6d 修复代码生成器导入数据表,编辑字段问题,兼容mysql8 2022-09-21 23:20:13 +08:00
TinyAnts
158125c3d0 Merge tag '1.3.1' into develop 2022-09-21 17:42:28 +08:00
TinyAnts
abc001b76b Merge branch 'release/1.3.1' 2022-09-21 17:42:27 +08:00
TinyAnts
4574db504a 调整SQL文件 2022-09-21 17:38:49 +08:00
TinyAnts
dfc50e2623 调整版本号 2022-09-21 17:33:24 +08:00
Jason
04290c78de 打包 2022-09-21 17:24:38 +08:00
Jason
a717ee326c code lint 2022-09-21 16:44:00 +08:00
Jason
5e844a1d38 后台页面调整 2022-09-21 16:42:53 +08:00
Jason
cbdb12f5d7 修改搜索页面样式问题 2022-09-21 14:11:23 +08:00
TinyAnts
a8e08053be 修复素材移动bug 2022-09-21 11:59:22 +08:00
TinyAnts
a70ec891d7 增加基类继承 2022-09-21 11:35:51 +08:00
TinyAnts
d12cae1937 调整验证器增加基类 2022-09-21 11:29:36 +08:00
TinyAnts
78726b8373 增加验证器基类 2022-09-21 11:21:15 +08:00
TinyAnts
5dfea2ad46 修复文章分类删除bug 2022-09-21 10:32:17 +08:00
TinyAnts
6e0f1ade38 修复文章分类删除bug 2022-09-21 10:29:58 +08:00
TinyAnts
f89d34915b 忽略文件 2022-09-21 10:26:42 +08:00
TinyAnts
8db154f01d 增加idea注释 2022-09-21 10:24:50 +08:00
TinyAnts
878f740bda 修复系统管理员账号被可被慕改bug 2022-09-21 10:07:24 +08:00
TinyAnts
1df98b147a 优化配置和静态资源 2022-09-21 09:59:51 +08:00
Jason
cadad25176 菜单调整,资讯图标预览调整 2022-09-20 18:50:08 +08:00
Jason
73984d52c0 Merge branch 'develop' of https://gitee.com/likeshop_gitee/likeadmin-java into develop 2022-09-20 18:49:02 +08:00
Jason
c3ea44292f 视频播放 2022-09-20 18:48:47 +08:00
TinyAnts
02317bee8e 调整视频上传大小限制 2022-09-20 18:43:48 +08:00
Jason
61dc2bf16d 调整登录页面样式 2022-09-20 16:23:29 +08:00
Jason
db45652f28 打包 2022-09-20 15:44:27 +08:00
Jason
51b35b664d 调整备注 2022-09-20 12:15:36 +08:00
Jason
29999f4e4a 调整登录,注册 2022-09-20 12:15:08 +08:00
Jason
77fb6acc2d 个人中心账号复制,切换tab页面时报错 2022-09-20 11:36:41 +08:00
Jason
b512eac708 调整工具函数 2022-09-20 11:06:54 +08:00
Jason
654c7b3c11 后台打包 2022-09-20 11:00:40 +08:00
Jason
fe5522dc2d 多标签tabs 调整 2022-09-20 10:58:38 +08:00
Jason
aee93d81b4 修改部门验证 2022-09-19 15:26:00 +08:00
Jason
56da1c18dd 部分多行文本框添加字数限制 2022-09-19 15:20:43 +08:00
Jason
ccd4747203 修复富文本编辑器样式问题 2022-09-19 14:52:45 +08:00
Jason
5240b89b35 后台打包 2022-09-19 14:04:54 +08:00
Jason
db7a0e3161 后台-岗位-文案错误 2022-09-19 12:13:58 +08:00
Jason
8f52978021 后台-热搜-删除搜索的id 2022-09-19 12:13:26 +08:00
Jason
83469090dd 字典数据无法访问bug 2022-09-19 12:12:40 +08:00
Jason
fa4de3214d Merge branch 'develop' of https://gitee.com/likeshop_gitee/likeadmin-java into develop 2022-09-19 12:12:03 +08:00
Jason
65da3d4a3a 素材中心优化 2022-09-19 12:11:54 +08:00
TinyAnts
a7e50bf511 修复后台上传视频获取不到名称bug 2022-09-19 11:57:35 +08:00
TinyAnts
e40689135f 修复前端默认logo与后台不一致bug 2022-09-19 10:10:43 +08:00
TinyAnts
3560cd45c5 Merge branch 'develop' of https://gitee.com/likeadmin/likeadmin_java into develop 2022-09-19 10:07:44 +08:00
TinyAnts
8d75e4c934 修复微信授权登录都是同一个账号bug 2022-09-19 10:07:27 +08:00
lr
9393de9063 Merge branch 'hotfix/lr-20220818-redeme' 2022-09-18 16:29:40 +08:00
lr
e0f11a53e2 Merge branch 'master' into develop 2022-09-18 16:29:40 +08:00
lr
b142dee20f 调整REMDME信息 2022-09-18 16:29:18 +08:00
lr
3d83b85588 Merge branch 'hotfix/lr-20220818' 2022-09-18 16:27:04 +08:00
lr
18cbb4374c Merge branch 'master' into develop 2022-09-18 16:27:04 +08:00
lr
ba7560b9e2 调整README信息 2022-09-18 16:26:42 +08:00
Jason
b7e010b634 Merge tag 'wjx202209160658' into develop
no message
2022-09-16 18:59:59 +08:00
Jason
370cde09c4 Merge tag 'wjx202209160657' into develop
no message
2022-09-16 18:58:25 +08:00
Jason
8ee7d03ce2 Merge tag 'wjx202209160652' into develop
no message

# Conflicts:
#	h5/assets/account.304e4c09.js
#	h5/assets/index.5ddae38f.js
#	h5/assets/news-card.cacc1bdf.js
#	h5/assets/pages-bind_mobile-bind_mobile.1e39d2a7.js
#	h5/assets/pages-change_password-change_password.5516de7d.js
#	h5/assets/pages-collection-collection.5d101da7.js
#	h5/assets/pages-customer_service-customer_service.35e5d1d2.js
#	h5/assets/pages-forget_pwd-forget_pwd.0cebded6.js
#	h5/assets/pages-index-index.e7cbfcb8.js
#	h5/assets/pages-login-login.3d278588.js
#	h5/assets/pages-news-news.e71c4738.js
#	h5/assets/pages-news_detail-news_detail.32038bef.js
#	h5/assets/pages-register-register.07ea7f19.js
#	h5/assets/pages-search-search.fb4812e5.js
#	h5/assets/pages-user-user.97ccd207.js
#	h5/assets/pages-user_data-user_data.1a85e802.js
#	h5/assets/pages-user_set-user_set.a86f2f01.js
#	h5/assets/pages-webview-webview.320ac922.js
#	h5/assets/tabbar.3ac4b4ec.js
#	h5/assets/u-avatar.aaafa077.js
#	h5/assets/u-button.f89bd070.js
#	h5/assets/u-checkbox.e15726da.js
#	h5/assets/u-form-item.f2bc17f6.js
#	h5/assets/u-form.e908a5a2.js
#	h5/assets/u-icon.947d1557.js
#	h5/assets/u-image.f03d2bad.js
#	h5/assets/u-parse.466924cc.js
#	h5/assets/u-popup.c389a818.js
#	h5/assets/u-search.939c3f7f.js
#	h5/assets/u-verification-code.8f91217a.js
#	h5/assets/uni.fb5f5659.css
#	h5/assets/uni_modules-vk-uview-ui-components-u-avatar-cropper-u-avatar-cropper.e582869e.js
#	h5/assets/z-paging.34848bf3.js
#	h5/index.html
2022-09-16 18:55:34 +08:00
Jason
9be1caf811 Merge tag 'wjx202209160644' into develop
no message

# Conflicts:
#	h5/assets/account.461df912.js
#	h5/assets/index.4cc19f69.js
#	h5/assets/news-card.f9659a05.js
#	h5/assets/news.7d996083.js
#	h5/assets/pages-as_us-as_us.8bc9b466.js
#	h5/assets/pages-bind_mobile-bind_mobile.34dd4d4a.js
#	h5/assets/pages-change_password-change_password.16c95aef.js
#	h5/assets/pages-collection-collection.7f1501b9.js
#	h5/assets/pages-customer_service-customer_service.bd6a8b1f.js
#	h5/assets/pages-forget_pwd-forget_pwd.ed85d829.js
#	h5/assets/pages-index-index.19c7f55a.js
#	h5/assets/pages-login-login.432b5d68.js
#	h5/assets/pages-news-news.b7c7c850.js
#	h5/assets/pages-register-register.b6b6ae54.js
#	h5/assets/pages-search-search.26e01199.js
#	h5/assets/pages-user-user.3fd280ce.js
#	h5/assets/pages-user_data-user_data.6cd74f38.js
#	h5/assets/pages-user_set-user_set.5b8235ee.js
#	h5/assets/pages-webview-webview.d074f33b.js
#	h5/assets/tabbar.32c15533.js
#	h5/assets/u-avatar.40df6bc2.js
#	h5/assets/u-button.eb2fc020.js
#	h5/assets/u-checkbox.a3de132d.js
#	h5/assets/u-form-item.80dd7f49.js
#	h5/assets/u-form.9f54964a.js
#	h5/assets/u-icon.adf02ff2.js
#	h5/assets/u-image.554b827f.js
#	h5/assets/u-parse.a2aa510a.js
#	h5/assets/u-popup.2aaf05d4.js
#	h5/assets/u-search.18076790.js
#	h5/assets/u-verification-code.a41295d0.js
#	h5/assets/uni_modules-vk-uview-ui-components-u-avatar-cropper-u-avatar-cropper.8be1cad8.js
#	h5/assets/z-paging.ae4248a3.js
#	h5/index.html
2022-09-16 18:48:08 +08:00
Jason
53071be070 Merge tag 'wjx202209160640' into develop
no message

# Conflicts:
#	h5/assets/account.304e4c09.js
#	h5/assets/account.9ecc88ea.js
#	h5/assets/account.e236fd55.js
#	h5/assets/index.24de5888.js
#	h5/assets/index.5ddae38f.js
#	h5/assets/index.9d01590f.js
#	h5/assets/news-card.0f53c999.js
#	h5/assets/news-card.c91540ca.js
#	h5/assets/news-card.cacc1bdf.js
#	h5/assets/news.5c5bd132.js
#	h5/assets/news.7d996083.js
#	h5/assets/news.eb80f754.js
#	h5/assets/pages-as_us-as_us.27714390.js
#	h5/assets/pages-as_us-as_us.8bc9b466.js
#	h5/assets/pages-as_us-as_us.a75e6bf4.js
#	h5/assets/pages-bind_mobile-bind_mobile.1e39d2a7.js
#	h5/assets/pages-bind_mobile-bind_mobile.3d1ff6fd.js
#	h5/assets/pages-bind_mobile-bind_mobile.b0b2132a.js
#	h5/assets/pages-change_password-change_password.3e609524.js
#	h5/assets/pages-change_password-change_password.5516de7d.js
#	h5/assets/pages-change_password-change_password.7fcdae1a.js
#	h5/assets/pages-collection-collection.14907c26.js
#	h5/assets/pages-collection-collection.53abd56e.js
#	h5/assets/pages-collection-collection.5d101da7.js
#	h5/assets/pages-customer_service-customer_service.0e4773a4.js
#	h5/assets/pages-customer_service-customer_service.35e5d1d2.js
#	h5/assets/pages-customer_service-customer_service.c942a0bb.js
#	h5/assets/pages-forget_pwd-forget_pwd.0c22cfa7.js
#	h5/assets/pages-forget_pwd-forget_pwd.0cebded6.js
#	h5/assets/pages-forget_pwd-forget_pwd.41860f0c.js
#	h5/assets/pages-index-index.21b55a1c.js
#	h5/assets/pages-index-index.697592e8.js
#	h5/assets/pages-index-index.e7cbfcb8.js
#	h5/assets/pages-login-login.3d278588.js
#	h5/assets/pages-login-login.583742c3.js
#	h5/assets/pages-login-login.cc17b6ae.js
#	h5/assets/pages-news-news.6e6dfc74.js
#	h5/assets/pages-news-news.e71c4738.js
#	h5/assets/pages-news-news.f27837dc.js
#	h5/assets/pages-register-register.07ea7f19.js
#	h5/assets/pages-register-register.127a8342.js
#	h5/assets/pages-register-register.707197f6.js
#	h5/assets/pages-search-search.5bd1eb0e.js
#	h5/assets/pages-search-search.c9a4fc47.js
#	h5/assets/pages-search-search.fb4812e5.js
#	h5/assets/pages-user-user.29445b03.js
#	h5/assets/pages-user-user.97ccd207.js
#	h5/assets/pages-user-user.e6fd2164.js
#	h5/assets/pages-user_data-user_data.1a85e802.js
#	h5/assets/pages-user_data-user_data.2a0211b5.js
#	h5/assets/pages-user_data-user_data.65619aff.js
#	h5/assets/pages-user_set-user_set.9387105d.js
#	h5/assets/pages-user_set-user_set.a86f2f01.js
#	h5/assets/pages-user_set-user_set.d71e173b.js
#	h5/assets/pages-webview-webview.183e0d8c.js
#	h5/assets/pages-webview-webview.320ac922.js
#	h5/assets/pages-webview-webview.c3fa2ff9.js
#	h5/assets/shop.067e3a04.js
#	h5/assets/tabbar.1370a2f3.js
#	h5/assets/tabbar.3ac4b4ec.js
#	h5/assets/tabbar.5a261344.js
#	h5/assets/u-avatar.0975a40c.js
#	h5/assets/u-avatar.665749d0.js
#	h5/assets/u-avatar.aaafa077.js
#	h5/assets/u-button.4291cf3a.js
#	h5/assets/u-button.6324a944.js
#	h5/assets/u-button.f89bd070.js
#	h5/assets/u-checkbox.4a48075d.js
#	h5/assets/u-checkbox.a9e5c7b5.js
#	h5/assets/u-checkbox.e15726da.js
#	h5/assets/u-form-item.8b18cdc2.js
#	h5/assets/u-form-item.e8316076.js
#	h5/assets/u-form-item.f2bc17f6.js
#	h5/assets/u-form.718bda0a.js
#	h5/assets/u-form.9d11b0a8.js
#	h5/assets/u-form.e908a5a2.js
#	h5/assets/u-icon.947d1557.js
#	h5/assets/u-icon.b22654a8.js
#	h5/assets/u-icon.b511ef4e.js
#	h5/assets/u-image.2abefbca.js
#	h5/assets/u-image.dcffbc78.js
#	h5/assets/u-image.f03d2bad.js
#	h5/assets/u-parse.2b02a1d4.js
#	h5/assets/u-parse.466924cc.js
#	h5/assets/u-parse.cd76eaa8.js
#	h5/assets/u-popup.0657d28e.js
#	h5/assets/u-popup.6fa83f64.js
#	h5/assets/u-popup.c389a818.js
#	h5/assets/u-search.939c3f7f.js
#	h5/assets/u-search.9f49742b.js
#	h5/assets/u-search.dad6632d.js
#	h5/assets/u-verification-code.419886b4.js
#	h5/assets/u-verification-code.8f91217a.js
#	h5/assets/u-verification-code.9a7d2ff4.js
#	h5/assets/uni_modules-vk-uview-ui-components-u-avatar-cropper-u-avatar-cropper.75f62b2e.js
#	h5/assets/uni_modules-vk-uview-ui-components-u-avatar-cropper-u-avatar-cropper.859f9abd.js
#	h5/assets/uni_modules-vk-uview-ui-components-u-avatar-cropper-u-avatar-cropper.e582869e.js
#	h5/assets/util.7b793930.js
#	h5/assets/z-paging.34848bf3.js
#	h5/assets/z-paging.51f9fb6d.js
#	h5/assets/z-paging.9a4d68b6.js
#	h5/index.html
2022-09-16 18:43:18 +08:00
TinyAnts
769c1c0ff6 Merge branch 'master' into develop 2022-09-16 18:39:48 +08:00
TinyAnts
b660028a6c Merge branch 'develop' of https://gitee.com/likeadmin/likeadmin_java into develop 2022-09-16 18:33:51 +08:00
TinyAnts
4ee067a1f7 Merge tag '1.3.0' into develop 2022-09-16 18:25:36 +08:00
Jason
3f699d3c7c 打包 2022-09-16 18:23:03 +08:00
zhangml
2db501d36d 优化部门级联和默认 #I5R3QL 2022-09-16 13:42:11 +08:00
1407 changed files with 14674 additions and 8132 deletions

5
.gitignore vendored
View File

@@ -5,5 +5,8 @@
target/
application-dev.yml
application-pro.yml
application-dem.yml
application-prod.yml
application-test.yml
application-test.yml
/public/uploads/*
!/public/uploads/index.html

214
LICENSE
View File

@@ -1,201 +1,21 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
MIT License
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
Copyright (c) 2022 likeshop技术社区
1. Definitions.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,5 +1,5 @@
<h1 align="center">likeadmin通用管理后台Java</h1>
<h4 align="center">🚀快速开发、🛠️ 一键生成代码、📱手机自适应</h4>
<h4 align="center">🚀快速开发、🛠️ 一键生成代码、✅后台多端自适应、📱手机端uniapp前台</h4>
<p align="center">
<a href="https://www.java.com/zh-CN/download/"><img src="https://img.shields.io/badge/JAVA-8-d74f11"> </a><a href="#"> <img src="https://img.shields.io/badge/Spring Boot-2-5ea931"> </a><a href="https://www.tslang.cn/"><img src="https://img.shields.io/badge/TypeScript-3-294e80"></a> <a href="#"><img src="https://img.shields.io/badge/Vue.js-3-4eb883"> </a><a href="#"><img src="https://img.shields.io/badge/vite-2-ffc018"> </a><a href="#"><img src="https://img.shields.io/badge/Element Plus-2-409eff"> </a><a target="_blank" href="https://www.docker.com/"><img src="https://img.shields.io/badge/Docker--139cff"></a>
<div align="center">
@@ -7,9 +7,15 @@
</div>
<br>
## 👀体验后台
## 👀体验
### 管理后台
地址https://demo-java.likeadmin.cn <br>
账号admin 密码123456
### 手机端uniapp前台
<img width="40%" src="https://md.likeshop.cn/server/index.php?s=/api/attachment/visitFile&sign=260c0869d9ba7e692b2db1e216078241" /><br>
### 开发文档
地址:[https://www.likeadmin.cn](https://www.likeadmin.cn "https://www.likeadmin.cn")
## 👨‍💻‍简介
@@ -20,24 +26,30 @@
1.likeadmin已经搭建好前后端分离的底层包含程序安装、登录、登出、工作台、菜单权限控制、角色、管理员、部门管理、岗位管理、素材管理、网站设置、图库管理等基础功能无需重复造轮子。更有开发者工具功能一生成代码大大节省开发时间。<br>
2.可视化系统程序安装界面,可自定义安装数据,开发者可快速扩展发行自己的软件产品。<br>
3.likeadmin定位为通用的软件系统管理后台方便开发者快速开发软件系统文档清晰、代码易懂、简单易用。<br>
4.未来将持续集成通用的微信/支付宝支付,阿里云/腾讯云短信,阿里云/腾讯云OSS等通用模块
4.手机端uniapp前台含导导航配置、微信登录、个人登录等等基础功能方便根据业务开发含手机前台的项目
### 🐙 后端架构方面
1.服务端使用JAVA8开发性能有突破性的提升。<br>
2.使用Spring Boot2.5框架目前国内流行的JAVA框架高性能、简单易用、文档齐全、支持Mave高级项目管理工具、支持Redis等。
### 🐹 前端架构方面
#### 后台
1.使用最流性的前后端分离方案typescript、vue3、vite开发保持了代码的简洁、一致和规范。<br>
2.后台界面使用element-plus UI框架简单精美的后台界面丰富的组件库方便快速开发满足各种后台交互。
<br>
### 前台
手机端uniapp前台可以编译成手机H5网页、微信小程序、安卓App苹果App等客户端。<br>
### 🛠️ 代码生成器
一键生成前后端业务代码,大大提示开发效率。
### 🖥️界面预览
一键生成前后端业务代码,大大提示开发效率。<br>
## 界面预览
### 🖥️后台页面
![](https://md.likeshop.cn/server/index.php?s=/api/attachment/visitFile&sign=9cf02b831e49d6a411bafbc4d79f51d4)<br>
![](https://md.likeshop.cn/server/index.php?s=/api/attachment/visitFile&sign=eb83547d55b4f41f0d92fd6a3e01d87e)
![](https://md.likeshop.cn/server/index.php?s=/api/attachment/visitFile&sign=818d843fb9cba396226e32dad1a58f3c)<br>
![](https://md.likeshop.cn/server/index.php?s=/api/attachment/visitFile&sign=194ab31919cd4dd619e6c453d7a44304)<br>
![](https://md.likeshop.cn/server/index.php?s=/api/attachment/visitFile&sign=f6770e2a8069d7b6ea3d83b91204b9d6)<br>
<br>
### 🪐接口文档
[点击这里进入更多更详细文档。](https://www.likeadmin.cn "点击这里进入更多更详细文档。")
### 📱手机端前台界面
<div class="half">
<img width="30%" src="https://md.likeshop.cn/server/index.php?s=/api/attachment/visitFile&sign=2dbac190afadfb6650a04c8af44980e1" /> <img width="30%" src="https://md.likeshop.cn/server/index.php?s=/api/attachment/visitFile&sign=73adbdb91ff5c43ca3e694a99effae7a" /> <img width="30%" src="https://md.likeshop.cn/server/index.php?s=/api/attachment/visitFile&sign=55b51eaebd7d696f96ccbf60d4694368" />
</div><br>

View File

@@ -1,4 +0,0 @@
NODE_ENV = 'development'
# 请求域名
VITE_APP_BASE_URL='https://likeadmin-java.yixiangonline.com'

View File

@@ -0,0 +1,4 @@
NODE_ENV = 'development'
# 请求域名
VITE_APP_BASE_URL=''

3
admin/.gitignore vendored
View File

@@ -30,3 +30,6 @@ components.d.ts
*.sln
*.sw?
# .env
.env.development
.env.production

View File

@@ -55,6 +55,7 @@
"vite": "^3.0.0",
"vite-plugin-style-import": "^2.0.0",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-vue-setup-extend": "^0.4.0",
"vue-tsc": "^0.38.1"
}
}

View File

@@ -4,7 +4,7 @@ import fsExtra from 'fs-extra'
const { existsSync, remove, copy } = fsExtra
const cwd = process.cwd()
//打包发布路径,谨慎改动
const releaseRelativePath = '../frontend'
const releaseRelativePath = '../public/admin'
const distPath = path.resolve(cwd, 'dist')
const releasePath = path.resolve(cwd, releaseRelativePath)

View File

@@ -2,10 +2,10 @@ import request from '@/utils/request'
// 配置
export function getConfig() {
return request.get({ url: '/common/index/config' })
return request.get({ url: '/index/config' })
}
// 工作台主页
export function getWorkbench() {
return request.get({ url: '/common/index/console' })
return request.get({ url: '/index/console' })
}

View File

@@ -1,4 +1,5 @@
import request from '@/utils/request'
import { firstToUpperCase } from '@/utils/util'
// 微信公众号配置保存
export function setOaConfig(params: any) {
@@ -47,12 +48,11 @@ export function setOaMenuPublish(params: Menu | any) {
}
/**
* @return { Promise }
* @param { string } type
* @description 获取回复列表
* @description 默认回复列表
*/
export function getOaReplyList(params: { type: string }) {
return request.get({ url: '/channel/oaReply/list', params })
export function getOaReplyList(params: any) {
const type = firstToUpperCase(params.type)
return request.get({ url: `/channel/oaReply${type}/list`, params })
}
/**
@@ -60,8 +60,9 @@ export function getOaReplyList(params: { type: string }) {
* @param { number } id
* @description 回复列表删除
*/
export function oaReplyDel(params: { id: number }) {
return request.post({ url: '/channel/oaReply/del', params })
export function oaReplyDel(params: any) {
const type = firstToUpperCase(params.type)
return request.post({ url: `/channel/oaReply${type}/del`, params })
}
/**
@@ -69,8 +70,9 @@ export function oaReplyDel(params: { id: number }) {
* @param { number } id
* @description 回复状态修改
*/
export function changeOaReplyStatus(params: { id: number }) {
return request.post({ url: '/channel/oaReply/status', params })
export function changeOaReplyStatus(params: any) {
const type = firstToUpperCase(params.type)
return request.post({ url: `/channel/oaReply${type}/status`, params })
}
export interface Reply {
@@ -85,25 +87,26 @@ export interface Reply {
}
/**
* @return { Promise }
* @description 回复添加
* @description 默认回复编辑
*/
export function oaReplyAdd(params: Reply) {
return request.post({ url: '/channel/oaReply/add', params })
const type = firstToUpperCase(params.type)
return request.post({ url: `/channel/oaReply${type}/add`, params })
}
/**
* @return { Promise }
* @description 回复编辑
* @description 默认回复编辑
*/
export function oaReplyEdit(params: Reply) {
return request.post({ url: '/channel/oaReply/edit', params })
const type = firstToUpperCase(params.type)
return request.post({ url: `/channel/oaReply${type}/edit`, params })
}
/**
* @return { Promise }
* @param { string } type
* @description 获取回复详情
* @description 默认回复详情
*/
export function getOaReplyDetail(params: { id: number }) {
return request.get({ url: '/channel/oaReply/detail', params })
export function getOaReplyDetail(params: any) {
const type = firstToUpperCase(params.type)
return request.get({ url: `/channel/oaReply${type}/detail`, params })
}

View File

@@ -1,39 +1,39 @@
import request from '@/utils/request'
export function fileCateAdd(params: Record<string, any>) {
return request.post({ url: '/common/album/cateAdd', params })
return request.post({ url: '/albums/cateAdd', params })
}
export function fileCateEdit(params: Record<string, any>) {
return request.post({ url: '/common/album/cateRename', params })
return request.post({ url: '/albums/cateRename', params })
}
// 文件分类删除
export function fileCateDelete(params: Record<string, any>) {
return request.post({ url: '/common/album/cateDel', params })
return request.post({ url: '/albums/cateDel', params })
}
// 文件分类列表
export function fileCateLists(params: Record<string, any>) {
return request.get({ url: '/common/album/cateList', params })
return request.get({ url: '/albums/cateList', params })
}
// 文件列表
export function fileList(params: Record<string, any>) {
return request.get({ url: '/common/album/albumList', params })
return request.get({ url: '/albums/albumList', params })
}
// 文件删除
export function fileDelete(params: Record<string, any>) {
return request.post({ url: '/common/album/albumDel', params })
return request.post({ url: '/albums/albumDel', params })
}
// 文件移动
export function fileMove(params: Record<string, any>) {
return request.post({ url: '/common/album/albumMove', params })
return request.post({ url: '/albums/albumMove', params })
}
// 文件重命名
export function fileRename(params: { id: number; name: string }) {
return request.post({ url: '/common/album/albumRename', params })
return request.post({ url: '/albums/albumRename', params })
}

View File

@@ -14,3 +14,28 @@ export function systemLogLists(params: any) {
export function systemCache() {
return request.get({ url: '/monitor/cache' })
}
// 定时任务列表
export function crontabLists(params: any) {
return request.get({ url: '/crontab/list', params })
}
// 添加定时任务
export function crontabAdd(params: any) {
return request.post({ url: '/crontab/add', params })
}
// 定时任务详情
export function crontabDetail(params: any) {
return request.get({ url: '/crontab/detail', params })
}
// 编辑定时任务
export function crontabEdit(params: any) {
return request.post({ url: '/crontab/edit', params })
}
// 删除定时任务
export function crontabDel(params: any) {
return request.post({ url: '/crontab/del', params })
}

View File

@@ -10,6 +10,11 @@ export function dataTable(params: any) {
return request.get({ url: '/gen/db', params })
}
// 数据表列表接口
export function dataTableAll() {
return request.get({ url: '/gen/dbAll' })
}
//选择要生成代码的数据表
export function selectTable(params: any) {
return request.post(

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -6,10 +6,15 @@
</div>
</template>
<script lang="ts" setup>
const props = defineProps<{
options: any[]
value: any
}>()
const props = withDefaults(
defineProps<{
options: any[]
value: any
}>(),
{
options: () => []
}
)
const values = computed(() => {
if (props.value !== null && typeof props.value !== 'undefined') {

View File

@@ -15,9 +15,10 @@
/>
<material-picker
ref="materialPickerRef"
:type="fileType"
:limit="-1"
hidden-upload
@change="imageSelectChange"
@change="selectChange"
/>
</div>
</template>
@@ -39,12 +40,10 @@ const props = withDefaults(
}>(),
{
modelValue: '',
mode: 'simple',
mode: 'default',
height: '100%',
width: 'auto',
toolbarConfig: () => ({
excludeKeys: ['fullScreen']
})
toolbarConfig: () => ({})
}
)
@@ -55,16 +54,24 @@ const emit = defineEmits<{
// 编辑器实例,必须用 shallowRef
const editorRef = shallowRef()
const materialPickerRef = shallowRef<InstanceType<typeof MaterialPicker>>()
const fileType = ref('')
let insertImageFn: any
let insertFn: any
const editorConfig: Partial<IEditorConfig> = {
MENU_CONF: {
uploadImage: {
customBrowseAndUpload(insertFn: any) {
console.log(insertFn)
customBrowseAndUpload(insert: any) {
fileType.value = 'image'
materialPickerRef.value?.showPopup(-1)
insertImageFn = insertFn
insertFn = insert
}
},
uploadVideo: {
customBrowseAndUpload(insert: any) {
fileType.value = 'video'
materialPickerRef.value?.showPopup(-1)
insertFn = insert
}
}
}
@@ -83,9 +90,9 @@ const valueHtml = computed({
}
})
const imageSelectChange = (image: string[]) => {
image.forEach((url) => {
insertImageFn(url)
const selectChange = (fileUrl: string[]) => {
fileUrl.forEach((url) => {
insertFn(url)
})
}
@@ -100,3 +107,37 @@ const handleCreated = (editor: any) => {
editorRef.value = editor // 记录 editor 实例,重要!
}
</script>
<style lang="scss">
.w-e-full-screen-container {
z-index: 999;
}
.w-e-text-container [data-slate-editor] ul {
list-style: disc;
}
.w-e-text-container [data-slate-editor] ol {
list-style: decimal;
}
h1 {
font-size: 2em;
}
h2 {
font-size: 1.5em;
}
h3 {
font-size: 1.17em;
}
h4 {
font-size: 1em;
}
h5 {
font-size: 0.83em;
}
h1,
h2,
h3,
h4,
h5 {
font-weight: bold;
}
</style>

View File

@@ -20,7 +20,11 @@ const props = defineProps({
type: [String, Number],
default: 0
},
...imageProps
...imageProps,
hideOnClickModal: {
type: Boolean,
default: true
}
})
const styles = computed<CSSProperties>(() => {

View File

@@ -1,8 +1,14 @@
<template>
<div>
<div class="file-item" :style="{ height: fileSize, width: fileSize }">
<div class="file-item relative" :style="{ height: fileSize, width: fileSize }">
<el-image class="image" v-if="type == 'image'" fit="contain" :src="uri"></el-image>
<video class="video" v-else-if="type == 'video'" :src="uri"></video>
<div
v-if="type == 'video'"
class="absolute left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] rounded-full w-5 h-5 flex justify-center items-center bg-[rgba(0,0,0,0.3)]"
>
<icon name="el-icon-CaretRight" :size="18" color="#fff" />
</div>
<slot></slot>
</div>
</div>

View File

@@ -45,8 +45,7 @@ export function useCate(type: number) {
}
// 添加分组
const handleAddCate = async () => {
const { value } = await feedback.prompt('', '添加分组')
const handleAddCate = async (value: string) => {
await fileCateAdd({
type,
name: value,
@@ -56,8 +55,7 @@ export function useCate(type: number) {
}
// 编辑分组
const handleEditCate = async (name: string, id: number) => {
const { value } = await feedback.prompt('', '重命分组', { inputValue: name })
const handleEditCate = async (value: string, id: number) => {
await fileCateEdit({
id,
name: value
@@ -180,8 +178,7 @@ export function useFile(
clearSelect()
}
const handleFileRename = async (name: string, id: number) => {
const { value } = await feedback.prompt('', '重命名', { inputValue: name })
const handleFileRename = async (value: string, id: number) => {
await fileRename({
id,
name: value

View File

@@ -24,24 +24,31 @@
<overflow-tooltip :content="data.name" />
</span>
<el-dropdown
v-perms="[
'common:album:cateRename',
'common:album:cateDel'
]"
v-perms="['albums:cateRename', 'albums:cateDel']"
v-if="data.id > 0"
:hide-on-click="false"
>
<span class="muted m-r-10">···</span>
<template #dropdown>
<el-dropdown-menu>
<div
v-perms="['common:album:cateRename']"
@click="handleEditCate(data.name, data.id)"
<popover-input
v-perms="['albums:cateRename']"
@confirm="handleEditCate($event, data.id)"
size="default"
:value="data.name"
width="400px"
:limit="20"
show-limit
teleported
>
<el-dropdown-item>命名分组</el-dropdown-item>
</div>
<div>
<el-dropdown-item>
命名分组
</el-dropdown-item>
</div>
</popover-input>
<div
v-perms="['common:album:cateDel']"
v-perms="['albums:cateDel']"
@click="handleDeleteCate(data.id)"
>
<el-dropdown-item>删除分组</el-dropdown-item>
@@ -57,9 +64,17 @@
</div>
<div class="flex justify-center p-2 border-t border-br">
<el-button @click="handleAddCate" v-perms="['common:album:cateAdd']">
添加分组
</el-button>
<popover-input
v-perms="['albums:cateAdd']"
@confirm="handleAddCate"
size="default"
width="400px"
:limit="20"
show-limit
teleported
>
<el-button> 添加分组 </el-button>
</popover-input>
</div>
</div>
<div class="material__center flex flex-col">
@@ -67,7 +82,7 @@
<div class="flex-1 flex">
<upload
v-if="type == 'image'"
v-perms="['common:upload:image']"
v-perms="['upload:image']"
class="mr-3"
:data="{ cid: cateId }"
:type="type"
@@ -78,7 +93,7 @@
</upload>
<upload
v-if="type == 'video'"
v-perms="['common:upload:video']"
v-perms="['upload:video']"
class="mr-3"
:data="{ cid: cateId }"
:type="type"
@@ -88,7 +103,7 @@
<el-button type="primary">本地上传</el-button>
</upload>
<el-button
v-perms="['common:album:albumDel']"
v-perms="['albums:albumDel']"
v-if="mode == 'page'"
:disabled="!select.length"
@click.stop="batchFileDelete()"
@@ -97,7 +112,7 @@
</el-button>
<popup
v-perms="['common:album:albumMove']"
v-perms="['albums:albumMove']"
v-if="mode == 'page'"
class="ml-3"
@confirm="batchFileMove"
@@ -195,14 +210,18 @@
<overflow-tooltip class="mt-1" :content="item.name" />
<div class="operation-btns flex items-center">
<el-button
v-perms="['common:album:albumRename']"
type="primary"
link
@click="handleFileRename(item.name, item.id)"
<popover-input
v-perms="['albums:albumRename']"
@confirm="handleFileRename($event, item.id)"
size="default"
:value="item.name"
width="400px"
:limit="50"
show-limit
teleported
>
重命名
</el-button>
<el-button type="primary" link> 重命名 </el-button>
</popover-input>
<el-button type="primary" link @click="handlePreview(item.uri)">
查看
</el-button>
@@ -226,34 +245,40 @@
<el-checkbox :modelValue="isSelect(row.id)" @change="selectFile(row)" />
</template>
</el-table-column>
<el-table-column label="图片" width="60">
<el-table-column label="图片" width="100">
<template #default="{ row }">
<file-item :uri="row.uri" file-size="40px"></file-item>
<file-item :uri="row.uri" file-size="50px" :type="type"></file-item>
</template>
</el-table-column>
<el-table-column label="名称" min-width="100" show-overflow-tooltip>
<template #default="{ row }">
<el-link @click.stop="handlePreview(row.uri)">{{ row.name }}</el-link>
<el-link @click.stop="handlePreview(row.uri)" :underline="false">
{{ row.name }}
</el-link>
</template>
</el-table-column>
<el-table-column prop="createTime" label="上传时间" min-width="100" />
<el-table-column label="操作" width="150" fixed="right">
<template #default="{ row }">
<div class="inline-block" v-perms="['common:album:albumRename']">
<el-button
type="primary"
link
@click.stop="handleFileRename(row.name, row.id)"
<div class="inline-block" v-perms="['albums:albumRename']">
<popover-input
@confirm="handleFileRename($event, row.id)"
size="default"
:value="row.name"
width="400px"
:limit="50"
show-limit
teleported
>
重命名
</el-button>
<el-button type="primary" link> 重命名 </el-button>
</popover-input>
</div>
<div class="inline-block">
<el-button type="primary" link @click.stop="handlePreview(row.uri)">
查看
</el-button>
</div>
<div class="inline-block" v-perms="['common:album:albumDel']">
<div class="inline-block" v-perms="['albums:albumDel']">
<el-button
type="primary"
link
@@ -287,14 +312,14 @@
</el-checkbox>
</span>
<el-button
v-perms="['common:album:albumDel']"
v-perms="['albums:albumDel']"
:disabled="!select.length"
@click="batchFileDelete()"
>
删除
</el-button>
<popup
v-perms="['common:album:albumMove']"
v-perms="['albums:albumMove']"
class="ml-3 inline"
@confirm="batchFileMove"
:disabled="!select.length"

View File

@@ -83,6 +83,7 @@ import FileItem from './file.vue'
import Material from './index.vue'
import Preview from './preview.vue'
import useAppStore from '@/stores/modules/app'
import { useThrottleFn } from '@vueuse/shared'
export default defineComponent({
components: {
Popup,
@@ -170,17 +171,21 @@ export default defineComponent({
if (limit.value == -1) return null
return limit.value - fileList.value.length
})
const handleConfirm = () => {
const selectUri = select.value.map((item) =>
props.excludeDomain ? item.path : item.uri
)
if (!isAdd.value) {
fileList.value.splice(currentIndex.value, 1, selectUri.shift())
} else {
fileList.value = [...fileList.value, ...selectUri]
}
handleChange()
}
const handleConfirm = useThrottleFn(
() => {
const selectUri = select.value.map((item) =>
props.excludeDomain ? item.path : item.uri
)
if (!isAdd.value) {
fileList.value.splice(currentIndex.value, 1, selectUri.shift())
} else {
fileList.value = [...fileList.value, ...selectUri]
}
handleChange()
},
1000,
false
)
const showPopup = (index: number) => {
if (disabled.value) return
if (index >= 0) {
@@ -214,6 +219,7 @@ export default defineComponent({
const handleClose = () => {
nextTick(() => {
if (props.hiddenUpload) fileList.value = []
materialRef.value?.clearSelect()
})
}

View File

@@ -6,16 +6,18 @@
:width="width"
trigger="contextmenu"
class="popover-input"
:teleported="false"
:teleported="teleported"
:persistent="false"
popper-class="!p-0"
>
<div class="flex">
<div class="flex p-3" @click.stop="">
<div class="popover-input__input mr-[10px] flex-1">
<el-select
class="flex-1"
size="small"
:size="size"
v-if="type == 'select'"
v-model="inputValue"
:teleported="false"
:teleported="teleported"
>
<el-option
v-for="item in options"
@@ -27,14 +29,17 @@
<el-input
v-else
v-model.trim="inputValue"
:maxlength="limit"
:show-word-limit="showLimit"
:type="type"
size="small"
:size="size"
clearable
:placeholder="placeholder"
/>
</div>
<div class="popover-input__btns flex-none">
<el-button link @click="visible = false">取消</el-button>
<el-button type="primary" size="small" @click="handleConfirm">确定</el-button>
<el-button link @click="close">取消</el-button>
<el-button type="primary" :size="size" @click="handleConfirm">确定</el-button>
</div>
</div>
<template #reference>
@@ -60,7 +65,7 @@ const props = defineProps({
},
width: {
type: [Number, String],
default: 250
default: '300px'
},
placeholder: String,
disabled: {
@@ -70,6 +75,22 @@ const props = defineProps({
options: {
type: Array as PropType<any[]>,
default: () => []
},
size: {
type: String as PropType<'default' | 'small' | 'large'>,
default: 'default'
},
limit: {
type: Number,
default: 200
},
showLimit: {
type: Boolean,
default: false
},
teleported: {
type: Boolean,
default: true
}
})
const emit = defineEmits(['confirm'])
@@ -99,7 +120,8 @@ watch(
immediate: true
}
)
useEventListener(document.body, 'click', () => {
useEventListener(document.documentElement, 'click', () => {
if (inPopover.value) return
close()
})

View File

@@ -12,6 +12,7 @@
:on-success="handleSuccess"
:on-exceed="handleExceed"
:on-error="handleError"
:accept="getAccept"
>
<slot></slot>
</el-upload>
@@ -78,9 +79,9 @@ export default defineComponent({
setup(props, { emit }) {
const userStore = useUserStore()
const uploadRefs = shallowRef<InstanceType<typeof ElUpload>>()
const action = ref(`${config.baseUrl}${config.urlPrefix}/common/upload/${props.type}`)
const action = ref(`${config.baseUrl}${config.urlPrefix}/upload/${props.type}`)
const headers = computed(() => ({
token: userStore.token,
['like-admin']: userStore.token,
version: config.version
}))
const visible = ref(false)
@@ -110,18 +111,30 @@ export default defineComponent({
emit('error')
}
const handleExceed = () => {
feedback.msgError('超出上传上限,请重新上传')
feedback.msgError(`超出上传上限${props.limit},请重新上传`)
}
const handleClose = () => {
uploadRefs.value?.clearFiles()
visible.value = false
}
const getAccept = computed(() => {
switch (props.type) {
case 'image':
return '.jpj,.png,.gif,.jpeg,.ico,.bmp'
case 'video':
return '.wmv,.avi,.mov,.mp4,.flv,.rmvb'
default:
return '*'
}
})
return {
uploadRefs,
action,
headers,
visible,
fileList,
getAccept,
handleProgress,
handleSuccess,
handleError,

View File

@@ -37,7 +37,7 @@ const options = reactive({
mirror: false, //镜像画面
ligthOff: false, //关灯模式
volume: 0.3, //默认音量大小
control: false, //是否显示控制器
control: true, //是否显示控制器
title: '', //视频名称
poster: '', //封面
...props

View File

@@ -1,10 +1,10 @@
const config = {
terminal: 1,
title: '后台管理系统',
version: '1.1.6',
baseUrl: `${import.meta.env.VITE_APP_BASE_URL}/`,
urlPrefix: 'api',
timeout: 20 * 1000
terminal: 1, //终端
title: '后台管理系统', //网站默认标题
version: '1.3.3', //版本号
baseUrl: `${import.meta.env.VITE_APP_BASE_URL || ''}/`, //请求接口域名
urlPrefix: 'api', //请求默认前缀
timeout: 10 * 1000 //请求超时时长
}
export default config

View File

@@ -1,13 +1,18 @@
const defaultSetting = {
sideWidth: 200,
sideTheme: 'light',
sideDarkColor: '#1d2124',
theme: '#4A5DFF',
openMultipleTabs: true,
successTheme: '#67c23a',
warningTheme: '#e6a23c',
dangerTheme: '#f56c6c',
errorTheme: '#f56c6c',
infoTheme: '#909399'
showCrumb: true, // 是否显示面包屑
showLogo: true, // 是否显示logo
isUniqueOpened: false, //只展开一个一级菜单
sideWidth: 200, //侧边栏宽度
sideTheme: 'light', //侧边栏主题
sideDarkColor: '#1d2124', //侧边栏深色主题颜色
openMultipleTabs: true, // 是否开启多标签tab栏
theme: '#4A5DFF', //主题色
successTheme: '#67c23a', //成功主题色
warningTheme: '#e6a23c', //警告主题色
dangerTheme: '#f56c6c', //危险主题色
errorTheme: '#f56c6c', //错误主题色
infoTheme: '#909399' //信息主题色
}
//以上各种主题色分别对应element-plus的几种行为主题
export default defaultSetting

View File

@@ -0,0 +1,47 @@
import useTabsStore from '@/stores/modules/multipleTabs'
import useSettingStore from '@/stores/modules/setting'
export default function useMultipleTabs() {
const router = useRouter()
const route = useRoute()
const tabsStore = useTabsStore()
const settingStore = useSettingStore()
const tabsLists = computed(() => {
return tabsStore.getTabList
})
const currentTab = computed(() => {
return route.fullPath
})
const addTab = () => {
if (!settingStore.openMultipleTabs) return
tabsStore.addTab(router)
}
const removeTab = (fullPath?: any) => {
if (!settingStore.openMultipleTabs) return
fullPath = fullPath ?? route.fullPath
tabsStore.removeTab(fullPath, router)
}
const removeOtherTab = () => {
if (!settingStore.openMultipleTabs) return
tabsStore.removeOtherTab(route)
}
const removeAllTab = () => {
if (!settingStore.openMultipleTabs) return
tabsStore.removeAllTab(router)
}
return {
tabsLists,
currentTab,
addTab,
removeTab,
removeOtherTab,
removeAllTab
}
}

View File

@@ -8,7 +8,7 @@
<div class="navbar-item">
<refresh />
</div>
<div class="flex items-center px-2" v-if="!isMobile">
<div class="flex items-center px-2" v-if="!isMobile && settingStore.showCrumb">
<breadcrumb />
</div>
</div>

View File

@@ -3,12 +3,12 @@
<div class="flex-1 min-w-0">
<el-tabs
:model-value="currentTab"
:closable="tabsState.length > 1"
:closable="tabsLists.length > 1"
@tab-change="handleChange"
@tab-remove="handleRemove"
@tab-remove="removeTab($event)"
>
<template v-for="item in tabsState" :key="item.path">
<el-tab-pane :label="item.title" :name="item.path"></el-tab-pane>
<template v-for="item in tabsLists" :key="item.fullPath">
<el-tab-pane :label="item.title" :name="item.fullPath"></el-tab-pane>
</template>
</el-tabs>
</div>
@@ -28,40 +28,31 @@
</template>
<script setup lang="ts">
import useMultipleTabs from '@/hooks/useMultipleTabs'
import { useWatchRoute } from '@/hooks/useWatchRoute'
import useTabsStore, { getRouteParams } from '@/stores/modules/multipleTabs'
const router = useRouter()
const tabsStore = useTabsStore()
const { route } = useWatchRoute((route) => {
tabsStore.addTab(route, router)
const { removeOtherTab, addTab, removeAllTab, removeTab, tabsLists, currentTab } = useMultipleTabs()
useWatchRoute(() => {
addTab()
})
const currentTab = computed(() => {
return route.path
})
const tabsState = computed(() => {
return tabsStore.getTabList
})
const handleChange = (path: any) => {
const tabItem = tabsStore.tasMap[path]
const handleChange = (fullPath: any) => {
const tabItem = tabsStore.tasMap[fullPath]
router.push(getRouteParams(tabItem))
}
const handleRemove = (path: any) => {
tabsStore.removeTab(path, router)
}
const handleCommand = (command: any) => {
switch (command) {
case 'closeCurrent':
handleRemove(route.path)
removeTab()
break
case 'closeOther':
tabsStore.removeOtherTab(route.path)
removeOtherTab()
break
case 'closeAll':
tabsStore.removeAllTab(router)
removeAllTab()
break
}
}

View File

@@ -3,7 +3,9 @@
<el-scrollbar>
<div class="p-4">
<router-view v-if="isRouteShow" v-slot="{ Component, route }">
<component :is="Component" :key="route.fullPath" />
<keep-alive :include="includeList" :max="20">
<component :is="Component" :key="route.fullPath" />
</keep-alive>
</router-view>
</div>
</el-scrollbar>
@@ -12,8 +14,13 @@
<script setup lang="ts">
import useAppStore from '@/stores/modules/app'
import useTabsStore from '@/stores/modules/multipleTabs'
import useSettingStore from '@/stores/modules/setting'
const appStore = useAppStore()
const tabsStore = useTabsStore()
const settingStore = useSettingStore()
const isRouteShow = computed(() => appStore.isRouteShow)
const includeList = computed(() => (settingStore.openMultipleTabs ? tabsStore.getCacheTabList : []))
</script>
<style></style>

View File

@@ -47,9 +47,33 @@
/>
</div>
</div>
<div class="setting-item mb-5">
<div class="text-tx-secondary mb-4">菜单栏宽度</div>
<div><el-input-number v-model="sideWidth" :min="180" :max="250" /></div>
<div class="setting-item mb-5 flex justify-between items-center">
<span class="text-tx-secondary">只展开一个一级菜单</span>
<div>
<el-switch
v-model="isUniqueOpened"
:active-value="true"
:inactive-value="false"
/>
</div>
</div>
<div class="setting-item mb-5 flex justify-between items-center">
<div class="text-tx-secondary flex-none mr-3">菜单栏宽度</div>
<div>
<el-input-number v-model="sideWidth" :min="180" :max="250" />
</div>
</div>
<div class="setting-item mb-5 flex justify-between items-center">
<div class="text-tx-secondary flex-none mr-3">显示LOGO</div>
<div>
<el-switch v-model="showLogo" :active-value="true" :inactive-value="false" />
</div>
</div>
<div class="setting-item mb-5 flex justify-between items-center">
<div class="text-tx-secondary flex-none mr-3">显示面包屑</div>
<div>
<el-switch v-model="showCrumb" :active-value="true" :inactive-value="false" />
</div>
</div>
<div class="setting-item mb-5 flex justify-between items-center">
<el-button @click="resetTheme">重置主题</el-button>
@@ -65,7 +89,6 @@ import theme_light from '@/assets/images/theme_white.png'
import theme_dark from '@/assets/images/theme_black.png'
const settingStore = useSettingStore()
const predefineColors = ref(['#409EFF', '#28C76F', '#EA5455', '#FF9F43', '#01CFE8', '#4A5DFF'])
const sideThemeList = [
{
@@ -102,6 +125,18 @@ const openMultipleTabs = computed({
}
})
const isUniqueOpened = computed({
get() {
return settingStore.isUniqueOpened
},
set(value) {
settingStore.setSetting({
key: 'isUniqueOpened',
value
})
}
})
const sideWidth = computed({
get() {
return settingStore.sideWidth
@@ -137,6 +172,30 @@ const theme = computed({
}
})
const showLogo = computed({
get() {
return settingStore.showLogo
},
set(value) {
settingStore.setSetting({
key: 'showLogo',
value
})
}
})
const showCrumb = computed({
get() {
return settingStore.showCrumb
},
set(value) {
settingStore.setSetting({
key: 'showCrumb',
value
})
}
})
const isDark = useDark()
const themeChange = () => {
settingStore.setTheme(isDark.value)

View File

@@ -10,7 +10,7 @@
:default-active="activeMenu"
:collapse="isCollapsed"
mode="vertical"
:unique-opened="true"
:unique-opened="uniqueOpened"
@select="$emit('select')"
>
<menu-item
@@ -41,6 +41,10 @@ const props = defineProps({
type: Boolean,
default: false
},
uniqueOpened: {
type: Boolean,
default: false
},
theme: {
type: String
},

View File

@@ -1,10 +1,11 @@
<template>
<div class="side" :style="sideStyle">
<side-logo :show-title="!isCollapsed" :theme="sideTheme" />
<side-logo v-if="settingStore.showLogo" :show-title="!isCollapsed" :theme="sideTheme" />
<side-menu
:routes="routes"
:isCollapsed="isCollapsed"
:width="settingStore.sideWidth"
:unique-opened="settingStore.isUniqueOpened"
:config="menuProp"
:theme="sideTheme"
@select="handleSelect"

View File

@@ -11,6 +11,7 @@ import { INDEX_ROUTE, INDEX_ROUTE_NAME } from './router/routes'
import { PageEnum } from './enums/pageEnum'
import useTabsStore from './stores/modules/multipleTabs'
import { clearAuthInfo } from './utils/auth'
import config from './config'
// NProgress配置
NProgress.configure({ showSpinner: false })
@@ -22,9 +23,13 @@ const whiteList: string[] = [PageEnum.LOGIN, PageEnum.ERROR_403]
router.beforeEach(async (to, from, next) => {
// 开始 Progress Bar
NProgress.start()
document.title = to.meta.title ?? config.title
const userStore = useUserStore()
const tabsStore = useTabsStore()
if (userStore.token) {
if (whiteList.includes(to.path)) {
// 在免登录白名单,直接进入
next()
} else if (userStore.token) {
// 获取用户信息
const hasGetUserInfo = Object.keys(userStore.userInfo).length !== 0
if (hasGetUserInfo) {
@@ -42,7 +47,7 @@ router.beforeEach(async (to, from, next) => {
const routeName = findFirstValidRoute(routes)
// 没有有效路由跳转到403页面
if (!routeName) {
await userStore.logout()
clearAuthInfo()
next(PageEnum.ERROR_403)
return
}
@@ -69,9 +74,6 @@ router.beforeEach(async (to, from, next) => {
next({ path: loginPath, query: { redirect: to.fullPath } })
}
}
} else if (whiteList.includes(to.path)) {
// 在免登录白名单,直接进入
next()
} else {
next({ path: loginPath, query: { redirect: to.fullPath } })
}

View File

@@ -86,8 +86,8 @@ export function findFirstValidRoute(routes: RouteRecordRaw[]): string | undefine
}
//通过权限字符查询路由路径
export function getRoutePath(perms: string) {
const router = useRouter()
return router.getRoutes().find((item) => item.meta?.perms == perms)?.path || ''
const routerObj = useRouter() || router
return routerObj.getRoutes().find((item) => item.meta?.perms == perms)?.path || ''
}
// 重置路由

View File

@@ -11,6 +11,7 @@ import { PageEnum } from '@/enums/pageEnum'
interface TabItem {
name: RouteRecordName
fullPath: string
path: string
title?: string
query?: LocationQuery
@@ -24,8 +25,8 @@ interface TabsSate {
indexRouteName: RouteRecordName
}
const getHasTabIndex = (path: string, tabList: TabItem[]) => {
return tabList.findIndex((item) => item.path == path)
const getHasTabIndex = (fullPath: string, tabList: TabItem[]) => {
return tabList.findIndex((item) => item.fullPath == fullPath)
}
const isCannotAddRoute = (route: RouteLocationNormalized, router: Router) => {
@@ -39,8 +40,12 @@ const isCannotAddRoute = (route: RouteLocationNormalized, router: Router) => {
return false
}
const findTabsIndex = (path: string, tabList: TabItem[]) => {
return tabList.findIndex((item) => item.path === path)
const findTabsIndex = (fullPath: string, tabList: TabItem[]) => {
return tabList.findIndex((item) => item.fullPath === fullPath)
}
const getComponentName = (route: RouteLocationNormalized) => {
return route.matched.at(-1)?.components?.default?.name
}
export const getRouteParams = (tabItem: TabItem) => {
@@ -63,45 +68,67 @@ const useTabsStore = defineStore({
getters: {
getTabList(): TabItem[] {
return this.tabList
},
getCacheTabList(): string[] {
return Array.from(this.cacheTabList)
}
},
actions: {
setRouteName(name: RouteRecordName) {
this.indexRouteName = name
},
addCache(componentName?: string) {
if (componentName) this.cacheTabList.add(componentName)
},
removeCache(componentName?: string) {
if (componentName && this.cacheTabList.has(componentName)) {
this.cacheTabList.delete(componentName)
}
console.log(this.cacheTabList)
},
clearCache() {
this.cacheTabList.clear()
},
resetState() {
this.cacheTabList = new Set()
this.tabList = []
this.tasMap = {}
this.indexRouteName = ''
},
addTab(route: RouteLocationNormalized, router: Router) {
const { name, path, query, meta, params } = route
addTab(router: Router) {
const route = unref(router.currentRoute)
const { name, query, meta, params, fullPath, path } = route
if (isCannotAddRoute(route, router)) return
const hasTabIndex = getHasTabIndex(path!, this.tabList)
const hasTabIndex = getHasTabIndex(fullPath!, this.tabList)
const componentName = getComponentName(route)
const tabItem = {
name: name!,
path,
fullPath,
title: meta?.title,
query,
params
}
this.tasMap[path] = tabItem
this.tasMap[fullPath] = tabItem
if (meta?.keepAlive) {
this.addCache(componentName)
}
if (hasTabIndex != -1) {
this.tabList.splice(hasTabIndex, 1, tabItem)
return
}
this.tabList.push(tabItem)
},
removeTab(path: string, router: Router) {
removeTab(fullPath: string, router: Router) {
const { currentRoute, push } = router
const index = findTabsIndex(path, this.tabList)
const index = findTabsIndex(fullPath, this.tabList)
// 移除tab
if (this.tabList.length > 1) {
index !== -1 && this.tabList.splice(index, 1)
}
if (path !== currentRoute.value.path) {
const componentName = getComponentName(currentRoute.value)
this.removeCache(componentName)
if (fullPath !== currentRoute.value.fullPath) {
return
}
// 删除选中的tab
@@ -116,17 +143,24 @@ const useTabsStore = defineStore({
const toRoute = getRouteParams(toTab)
push(toRoute)
},
removeOtherTab(path: string) {
this.tabList = this.tabList.filter((item) => item.path == path)
removeOtherTab(route: RouteLocationNormalized) {
this.tabList = this.tabList.filter((item) => item.fullPath == route.fullPath)
const componentName = getComponentName(route)
this.cacheTabList.forEach((name) => {
if (componentName !== name) {
this.removeCache(name)
}
})
},
removeAllTab(router: Router) {
const { push, currentRoute } = router
const { path, name } = unref(currentRoute)
const { name } = unref(currentRoute)
if (name == this.indexRouteName) {
this.removeOtherTab(path)
this.removeOtherTab(currentRoute.value)
return
}
this.tabList = []
this.clearCache()
push(PageEnum.INDEX)
}
}

View File

@@ -32,7 +32,6 @@ const useUserStore = defineStore({
this.token = ''
this.userInfo = {}
this.perms = []
this.menu = []
},
login(playload: any) {
const { account, password } = playload
@@ -54,8 +53,9 @@ const useUserStore = defineStore({
logout() {
return new Promise((resolve, reject) => {
logout()
.then((data) => {
router.push(PageEnum.LOGIN)
.then(async (data) => {
this.token = ''
await router.push(PageEnum.LOGIN)
clearAuthInfo()
resolve(data)
})

View File

@@ -91,7 +91,7 @@
--el-messagebox-width: 350px;
}
.el-date-editor {
--el-date-editor-width: 235px;
--el-date-editor-width: 280px;
.el-range-input {
font-size: var(--el-font-size-small);
}
@@ -115,6 +115,9 @@
.el-image__error {
font-size: 12px;
}
.el-tabs__nav-wrap::after {
height: 1px;
}
}
@media (max-width: 768px) {
.el-pagination > .el-pagination__jump {

View File

@@ -12,7 +12,7 @@ export function clearAuthInfo() {
const userStore = useUserStore()
const tabsStore = useTabsStore()
userStore.resetState()
tabsStore.resetState()
tabsStore.$reset()
cache.remove(TOKEN_KEY)
resetRouter()
}

View File

@@ -71,11 +71,10 @@ export class Axios {
this.removeCancelToken(err.config?.url!)
}
if (err.code == AxiosError.ECONNABORTED) {
setTimeout(() => {
console.log(err)
if (err.code == AxiosError.ECONNABORTED || err.code == AxiosError.ERR_NETWORK) {
return new Promise((resolve) => setTimeout(resolve, 500)).then(() =>
this.retryRequest(err)
}, 500)
)
}
return Promise.reject(err)
}
@@ -103,17 +102,17 @@ export class Axios {
retryRequest(error: AxiosError) {
const config = error.config
const { retryCount, isOpenRetry } = config.requestOptions
if (!isOpenRetry && config.method?.toUpperCase() == RequestMethodsEnum.POST) {
return
if (!isOpenRetry || config.method?.toUpperCase() == RequestMethodsEnum.POST) {
return Promise.reject(error)
}
config.retryCount = config.retryCount ?? 0
if (config.retryCount >= retryCount) {
return
return Promise.reject(error)
}
config.retryCount++
this.axiosInstance.request(config)
return this.axiosInstance.request(config)
}
/**
* @description get请求

View File

@@ -21,7 +21,7 @@ const axiosHooks: AxiosHooks = {
// 添加token
if (withToken) {
const token = getToken()
headers.token = token
headers['like-admin'] = token
}
// POST请求下如果无data则将params视为data
if (

View File

@@ -160,3 +160,12 @@ export const getNonDuplicateID = (length = 8) => {
idStr += Math.random().toString(36).substring(3, length)
return idStr
}
/**
* @description 单词首字母大写
* @param { String } str
* @return { String } id
*/
export const firstToUpperCase = (str = '') => {
return str.toLowerCase().replace(/( |^)[a-z]/g, ($1) => $1.toUpperCase())
}

View File

@@ -6,7 +6,7 @@
<image-contain :src="config.webBackdrop" :width="400" height="100%" />
</div>
<div
class="login-form bg-body flex flex-col px-10 pt-10 md:w-[400px] w-[375px] flex-none mx-auto"
class="login-form bg-body flex flex-col justify-center px-10 py-10 md:w-[400px] w-[375px] flex-none mx-auto"
>
<div class="text-center text-3xl font-medium mb-8">{{ config.webName }}</div>
<el-form ref="formRef" :model="formData" size="large" :rules="rules">
@@ -17,7 +17,7 @@
@keyup.enter="handleEnter"
>
<template #prepend>
<icon name="el-icon-Avatar" />
<icon name="el-icon-User" />
</template>
</el-input>
</el-form-item>
@@ -99,7 +99,7 @@ const handleLogin = async () => {
// 记住账号,缓存
cache.set(ACCOUNT_KEY, {
remember: remAccount.value,
account: formData.account
account: remAccount.value ? formData.account : ''
})
await userStore.login(formData)
const {

View File

@@ -14,7 +14,7 @@
</el-form-item>
<el-form-item label="排序" prop="sort">
<div>
<el-input-number v-model="formData.sort" :min="0" />
<el-input-number v-model="formData.sort" :min="0" :max="9999" />
<div class="form-tips">默认为0 数值越大越排前</div>
</div>
</el-form-item>

View File

@@ -65,7 +65,7 @@
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="articleColumn">
import { articleCateDelete, articleCateLists, articleCateStatus } from '@/api/article'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'

View File

@@ -18,6 +18,10 @@
<el-input
v-model="formData.title"
placeholder="请输入文章标题"
type="textarea"
:autosize="{ minRows: 3, maxRows: 3 }"
maxlength="64"
show-word-limit
clearable
/>
</div>
@@ -42,6 +46,10 @@
<el-input
v-model="formData.intro"
placeholder="请输入文章简介"
type="textarea"
:autosize="{ minRows: 3, maxRows: 6 }"
:maxlength="200"
show-word-limit
clearable
/>
</div>
@@ -50,8 +58,10 @@
<div class="w-80">
<el-input
type="textarea"
:rows="6"
:autosize="{ minRows: 6, maxRows: 6 }"
v-model="formData.summary"
maxlength="200"
show-word-limit
clearable
/>
</div>
@@ -71,7 +81,7 @@
</el-form-item>
<el-form-item label="排序" prop="sort">
<div>
<el-input-number v-model="formData.sort" :min="0" />
<el-input-number v-model="formData.sort" :min="0" :max="9999" />
<div class="form-tips">默认为0 数值越大越排前</div>
</div>
</el-form-item>
@@ -101,11 +111,12 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="articleListsEdit">
import type { FormInstance } from 'element-plus'
import feedback from '@/utils/feedback'
import { useDictOptions } from '@/hooks/useDictOptions'
import { articleCateAll, articleDetail, articleEdit, articleAdd } from '@/api/article'
import useMultipleTabs from '@/hooks/useMultipleTabs'
const route = useRoute()
const router = useRouter()
@@ -123,6 +134,7 @@ const formData = reactive({
summary: ''
})
const { removeTab } = useMultipleTabs()
const formRef = shallowRef<FormInstance>()
const rules = reactive({
title: [{ required: true, message: '请输入文章标题', trigger: 'blur' }],
@@ -155,6 +167,7 @@ const handleSave = async () => {
await articleAdd(formData)
}
feedback.msgSuccess('操作成功')
removeTab()
router.back()
}

View File

@@ -4,14 +4,14 @@
<el-form ref="formRef" class="mb-[-16px]" :model="queryParams" :inline="true">
<el-form-item label="文章标题">
<el-input
class="w-56"
class="w-[280px]"
v-model="queryParams.title"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="栏目名称">
<el-select class="w-56" v-model="queryParams.cid">
<el-select class="w-[280px]" v-model="queryParams.cid">
<el-option label="全部" value />
<el-option
v-for="item in optionsData.articleCate"
@@ -22,7 +22,7 @@
</el-select>
</el-form-item>
<el-form-item label="文章状态">
<el-select class="w-56" v-model="queryParams.isShow">
<el-select class="w-[280px]" v-model="queryParams.isShow">
<el-option label="全部" value />
<el-option label="显示" :value="1" />
<el-option label="隐藏" :value="0" />
@@ -37,9 +37,9 @@
<el-card class="!border-none mt-4" shadow="never">
<div>
<router-link
v-perms="['article:add']"
v-perms="['article:add', 'article:add/edit']"
:to="{
path: getRoutePath('article:edit')
path: getRoutePath('article:add/edit')
}"
>
<el-button type="primary" class="mb-4">
@@ -54,10 +54,11 @@
<el-table-column label="ID" prop="id" min-width="80" />
<el-table-column label="封面" min-width="100">
<template #default="{ row }">
<el-image
<image-contain
v-if="row.image"
:src="row.image"
class="w-[60px] h-[45px]"
:width="60"
:height="45"
:preview-src-list="[row.image]"
preview-teleported
fit="contain"
@@ -88,10 +89,10 @@
<el-table-column label="发布时间" prop="createTime" min-width="120" />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button v-perms="['article:edit']" type="primary" link>
<el-button v-perms="['article:edit','article:add/edit']" type="primary" link>
<router-link
:to="{
path: getRoutePath('article:edit'),
path: getRoutePath('article:add/edit'),
query: {
id: row.id
}
@@ -117,7 +118,7 @@
</el-card>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="articleLists">
import { articleLists, articleDelete, articleStatus, articleCateAll } from '@/api/article'
import { useDictOptions } from '@/hooks/useDictOptions'
import { usePaging } from '@/hooks/usePaging'
@@ -159,5 +160,9 @@ const handleDelete = async (id: number) => {
getLists()
}
onActivated(() => {
getLists()
})
getLists()
</script>

View File

@@ -32,7 +32,7 @@
</footer-btns>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="h5Config">
import { getH5Config, setH5Config } from '@/api/channel/h5'
import feedback from '@/utils/feedback'

View File

@@ -140,7 +140,7 @@
</footer-btns>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="weappConfig">
import { getWeappConfig, setWeappConfig } from '@/api/channel/weapp'
import feedback from '@/utils/feedback'

View File

@@ -35,7 +35,7 @@
</footer-btns>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="wxDevConfig">
import { getWxDevConfig, setWxDevConfig } from '@/api/channel/wx_dev'
import feedback from '@/utils/feedback'

View File

@@ -156,7 +156,7 @@
</footer-btns>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="wxOaConfig">
import { getOaConfig, setOaConfig } from '@/api/channel/wx_oa'
import feedback from '@/utils/feedback'
import { useClipboard } from '@vueuse/core'

View File

@@ -1,4 +1,4 @@
<script setup lang="ts">
<script setup lang="ts" name="wxOaMenu">
import OaPhone from './menu_com/oa-phone.vue'
import OaAttr from './menu_com/oa-attr.vue'
import { useMenuOa } from './menu_com/useMenuOa'

View File

@@ -44,6 +44,12 @@ export const rules = reactive<FormRules>({
required: true,
message: '必填项不能为空',
trigger: ['blur', 'change']
},
{
pattern:
/^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~\/])+$/,
message: '请输入合法的网址链接',
trigger: ['blur', 'change']
}
],
appId: [
@@ -121,7 +127,6 @@ export const useMenuOa = (ref: any) => {
await refs[i].menuFormRef.validate()
} catch (error) {
menuIndex.value = i
feedback.msgError(`菜单${i + 1}必填项不能为空~`)
return
}
}
@@ -137,7 +142,6 @@ export const useMenuOa = (ref: any) => {
await refs[i].menuFormRef.validate()
} catch (error) {
menuIndex.value = i
feedback.msgError(`菜单${i + 1}必填项不能为空~`)
return
}
}

View File

@@ -10,24 +10,30 @@
</el-card>
<el-card class="!border-none mt-4" shadow="never">
<div>
<el-button class="mb-4" type="primary" @click="handleAdd()">
<el-button
v-perms="['channel:oaReplyDefault:add']"
class="mb-4"
type="primary"
@click="handleAdd()"
>
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button>
</div>
<el-table size="large" :data="lists">
<el-table size="large" :data="pager.lists" v-loading="pager.loading">
<el-table-column label="规则名称" prop="name" min-width="120" />
<el-table-column label="回复类型" min-width="120">
<template #default="{ row }">
{{ getContentType(1) }}
{{ getContentType(row.contentType) }}
</template>
</el-table-column>
<el-table-column label="回复内容" prop="content" min-width="120" />
<el-table-column label="状态" min-width="120">
<template #default="{ row }">
<el-switch
v-perms="['channel:oaReplyDefault:status']"
v-model="row.status"
:active-value="1"
:inactive-value="0"
@@ -38,25 +44,40 @@
<el-table-column label="排序" prop="sort" min-width="120" />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="handleEdit(row)"> 编辑 </el-button>
<el-button type="danger" link @click="handleDelete(row.id)">
<el-button
v-perms="['channel:oaReplyDefault:edit']"
type="primary"
link
@click="handleEdit(row)"
>
编辑
</el-button>
<el-button
v-perms="['channel:oaReplyDefault:del']"
type="danger"
link
@click="handleDelete(row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<div class="flex justify-end mt-4">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
</div>
</template>
<script lang="ts" setup>
import { oaReplyDel, getOaReplyList, changeOaReplyStatus } from '@/api/channel/wx_oa'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'
import EditPopup from './edit.vue'
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
const showEdit = ref(false)
const lists = ref()
const type = 'default'
const getContentType = computed(() => {
return (val: number) => {
switch (val) {
@@ -66,33 +87,36 @@ const getContentType = computed(() => {
}
})
const getLists = async () => {
lists.value = await getOaReplyList({ type: 'default' })
}
const { pager, getLists } = usePaging({
fetchFun: getOaReplyList,
params: {
type
}
})
const handleAdd = async () => {
showEdit.value = true
await nextTick()
editRef.value?.open('add', 'default')
editRef.value?.open('add', type)
}
const handleEdit = async (data: any) => {
showEdit.value = true
await nextTick()
editRef.value?.open('edit', 'default')
editRef.value?.open('edit', type)
editRef.value?.getDetail(data)
}
const handleDelete = async (id: number) => {
await feedback.confirm('确定要删除?')
await oaReplyDel({ id })
await oaReplyDel({ id, type })
feedback.msgSuccess('删除成功')
getLists()
}
const changeStatus = async (id: number) => {
try {
await changeOaReplyStatus({ id })
await changeOaReplyStatus({ id, type })
feedback.msgSuccess('修改成功')
getLists()
} catch (error) {

View File

@@ -5,7 +5,6 @@
:title="popupTitle"
:async="true"
width="500px"
:clickModalClose="true"
@confirm="handleSubmit"
@close="handleClose"
>
@@ -56,6 +55,8 @@
v-model="formData.content"
:autosize="{ minRows: 4, maxRows: 4 }"
type="textarea"
maxlength="200"
show-word-limit
placeholder="请输入回复内容"
/>
</div>
@@ -70,7 +71,7 @@
</el-form-item> -->
<el-form-item label="排序">
<div class="flex-1">
<el-input v-model="formData.sort" placeholder="请输入" />
<el-input-number v-model="formData.sort" :min="0" :max="9999" />
</div>
</el-form-item>
<el-form-item label="启用状态">
@@ -170,7 +171,8 @@ const setFormData = (data: Record<any, any>) => {
const getDetail = async (row: Record<string, any>) => {
const data = await getOaReplyDetail({
id: row.id
id: row.id,
type: formData.type
})
setFormData(data)
}

View File

@@ -10,14 +10,19 @@
</el-card>
<el-card class="!border-none mt-4" shadow="never">
<div>
<el-button class="mb-4" type="primary" @click="handleAdd()">
<el-button
v-perms="['channel:oaReplyFollow:add']"
class="mb-4"
type="primary"
@click="handleAdd()"
>
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button>
</div>
<el-table size="large" :data="lists">
<el-table size="large" :data="pager.lists" v-loading="pager.loading">
<el-table-column label="规则名称" prop="name" min-width="120" />
<el-table-column label="回复类型" min-width="120">
<template #default="{ row }">
@@ -28,6 +33,7 @@
<el-table-column label="状态" min-width="120">
<template #default="{ row }">
<el-switch
v-perms="['channel:oaReplyFollow:status']"
v-model="row.status"
:active-value="1"
:inactive-value="0"
@@ -38,25 +44,41 @@
<el-table-column label="排序" prop="sort" min-width="120" />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="handleEdit(row)"> 编辑 </el-button>
<el-button type="danger" link @click="handleDelete(row.id)">
<el-button
v-perms="['channel:oaReplyFollow:edit']"
type="primary"
link
@click="handleEdit(row)"
>
编辑
</el-button>
<el-button
v-perms="['channel:oaReplyFollow:del']"
type="danger"
link
@click="handleDelete(row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<div class="flex justify-end mt-4">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
</div>
</template>
<script lang="ts" setup>
import { oaReplyDel, getOaReplyList, changeOaReplyStatus } from '@/api/channel/wx_oa'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'
import EditPopup from './edit.vue'
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
const showEdit = ref(false)
const lists = ref()
const type = 'follow'
const getContentType = computed(() => {
return (val: number) => {
switch (val) {
@@ -66,33 +88,36 @@ const getContentType = computed(() => {
}
})
const getLists = async () => {
lists.value = await getOaReplyList({ type: 'follow' })
}
const { pager, getLists } = usePaging({
fetchFun: getOaReplyList,
params: {
type
}
})
const handleAdd = async () => {
showEdit.value = true
await nextTick()
editRef.value?.open('add', 'follow')
editRef.value?.open('add', type)
}
const handleEdit = async (data: any) => {
showEdit.value = true
await nextTick()
editRef.value?.open('edit', 'follow')
editRef.value?.open('edit', type)
editRef.value?.getDetail(data)
}
const handleDelete = async (id: number) => {
await feedback.confirm('确定要删除?')
await oaReplyDel({ id })
await oaReplyDel({ id, type })
feedback.msgSuccess('删除成功')
getLists()
}
const changeStatus = async (id: number) => {
try {
await changeOaReplyStatus({ id })
await changeOaReplyStatus({ id, type })
feedback.msgSuccess('修改成功')
getLists()
} catch (error) {

View File

@@ -10,14 +10,19 @@
</el-card>
<el-card class="!border-none mt-4" shadow="never">
<div>
<el-button class="mb-4" type="primary" @click="handleAdd()">
<el-button
v-perms="['channel:oaReplyKeyword:add']"
class="mb-4"
type="primary"
@click="handleAdd()"
>
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button>
</div>
<el-table size="large" :data="lists">
<el-table size="large" :data="pager.lists" v-loading="pager.loading">
<el-table-column label="规则名称" prop="name" min-width="120" />
<el-table-column label="关键词" prop="keyword" min-width="120" />
@@ -34,6 +39,7 @@
<el-table-column label="状态" min-width="120">
<template #default="{ row }">
<el-switch
v-perms="['channel:oaReplyKeyword:status']"
v-model="row.status"
:active-value="1"
:inactive-value="0"
@@ -44,24 +50,39 @@
<el-table-column label="排序" prop="sort" min-width="120" />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="handleEdit(row)"> 编辑 </el-button>
<el-button type="danger" link @click="handleDelete(row.id)">
<el-button
v-perms="['channel:oaReplyKeyword:edit']"
type="primary"
link
@click="handleEdit(row)"
>
编辑
</el-button>
<el-button
v-perms="['channel:oaReplyKeyword:del']"
type="danger"
link
@click="handleDelete(row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<div class="flex justify-end mt-4">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
</div>
</template>
<script lang="ts" setup>
import { oaReplyDel, getOaReplyList, changeOaReplyStatus } from '@/api/channel/wx_oa'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'
import EditPopup from './edit.vue'
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
const showEdit = ref(false)
const lists = ref()
const getMatchingType = computed(() => {
return (val: number) => {
@@ -82,34 +103,37 @@ const getContentType = computed(() => {
}
}
})
const getLists = async () => {
lists.value = await getOaReplyList({ type: 'keyword' })
}
const type = 'keyword'
const { pager, getLists } = usePaging({
fetchFun: getOaReplyList,
params: {
type
}
})
const handleAdd = async () => {
showEdit.value = true
await nextTick()
editRef.value?.open('add', 'keyword')
editRef.value?.open('add', type)
}
const handleEdit = async (data: any) => {
showEdit.value = true
await nextTick()
editRef.value?.open('edit', 'keyword')
editRef.value?.open('edit', type)
editRef.value?.getDetail(data)
}
const handleDelete = async (id: number) => {
await feedback.confirm('确定要删除?')
await oaReplyDel({ id })
await oaReplyDel({ id, type })
feedback.msgSuccess('删除成功')
getLists()
}
const changeStatus = async (id: number) => {
try {
await changeOaReplyStatus({ id })
await changeOaReplyStatus({ id, type })
feedback.msgSuccess('修改成功')
getLists()
} catch (error) {

View File

@@ -15,7 +15,11 @@
</el-form-item>
<el-form-item label="账号:">
{{ formData.username }}
<popover-input class="ml-[10px]" @confirm="handleEdit($event, 'username')">
<popover-input
class="ml-[10px]"
:limit="32"
@confirm="handleEdit($event, 'username')"
>
<el-button type="primary" link v-perms="['user:edit']">
<icon name="el-icon-EditPen" />
</el-button>
@@ -23,7 +27,11 @@
</el-form-item>
<el-form-item label="真实姓名:">
{{ formData.realName || '-' }}
<popover-input class="ml-[10px]" @confirm="handleEdit($event, 'realName')">
<popover-input
class="ml-[10px]"
:limit="32"
@confirm="handleEdit($event, 'realName')"
>
<el-button type="primary" link v-perms="['user:edit']">
<icon name="el-icon-EditPen" />
</el-button>
@@ -75,7 +83,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="consumerDetail">
import type { FormInstance } from 'element-plus'
import { getUserDetail, userEdit } from '@/api/consumer'
import feedback from '@/utils/feedback'

View File

@@ -4,7 +4,7 @@
<el-form ref="formRef" class="mb-[-16px]" :model="queryParams" :inline="true">
<el-form-item label="用户信息">
<el-input
class="w-56"
class="w-[280px]"
v-model="queryParams.keyword"
placeholder="用户编号/昵称/手机号码"
clearable
@@ -18,7 +18,7 @@
/>
</el-form-item>
<el-form-item label="注册来源">
<el-select class="w-56" v-model="queryParams.channel">
<el-select class="w-[280px]" v-model="queryParams.channel">
<el-option
v-for="(item, key) in ClientMap"
:key="key"
@@ -70,7 +70,7 @@
</el-card>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="consumerLists">
import { usePaging } from '@/hooks/usePaging'
import { getRoutePath } from '@/router'
import { getUserList } from '@/api/consumer'
@@ -86,6 +86,9 @@ const { pager, getLists, resetPage, resetParams } = usePaging({
fetchFun: getUserList,
params: queryParams
})
onActivated(() => {
getLists()
})
getLists()
</script>

View File

@@ -1,37 +1,36 @@
<template>
<div>
<div>
<del-wrap
class="max-w-[400px]"
v-for="(item, index) in modelValue"
:key="index"
@close="handleDelete(index)"
>
<div class="bg-fill-light flex items-center w-full p-4 mb-4">
<material-picker
v-model="item.image"
upload-class="bg-body"
size="60px"
exclude-domain
>
<template #upload>
<div class="upload-btn w-[60px] h-[60px]">
<icon name="el-icon-Plus" :size="20" />
<draggable class="draggable" v-model="navLists" animation="300">
<template v-slot:item="{ element: item, index }">
<del-wrap class="max-w-[400px]" :key="index" @close="handleDelete(index)">
<div class="bg-fill-light flex items-center w-full p-4 mb-4 cursor-move">
<material-picker
v-model="item.image"
upload-class="bg-body"
size="60px"
exclude-domain
>
<template #upload>
<div class="upload-btn w-[60px] h-[60px]">
<icon name="el-icon-Plus" :size="20" />
</div>
</template>
</material-picker>
<div class="ml-3 flex-1">
<div class="flex">
<span class="text-tx-regular flex-none mr-3">名称</span>
<el-input v-model="item.name" placeholder="请输入名称" />
</div>
<div class="flex mt-[18px]">
<span class="text-tx-regular flex-none mr-3">链接</span>
<link-picker v-model="item.link" />
</div>
</div>
</template>
</material-picker>
<div class="ml-3 flex-1">
<div class="flex">
<span class="text-tx-regular flex-none mr-3">名称</span>
<el-input v-model="item.name" placeholder="请输入名称" />
</div>
<div class="flex mt-[18px]">
<span class="text-tx-regular flex-none mr-3">链接</span>
<link-picker v-model="item.link" />
</div>
</div>
</div>
</del-wrap>
</del-wrap>
</template>
</draggable>
</div>
<div>
<el-button type="primary" @click="handleAdd">添加</el-button>
@@ -41,7 +40,7 @@
<script lang="ts" setup>
import feedback from '@/utils/feedback'
import type { PropType } from 'vue'
import Draggable from 'vuedraggable'
const props = defineProps({
modelValue: {
type: Array as PropType<any[]>,
@@ -57,9 +56,19 @@ const props = defineProps({
}
})
const emit = defineEmits(['update:modelValue'])
const navLists = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
}
})
const handleAdd = () => {
if (props.modelValue?.length < props.max) {
props.modelValue.push({
navLists.value.push({
image: '',
name: '导航名称',
link: {}
@@ -72,7 +81,7 @@ const handleDelete = (index: number) => {
if (props.modelValue?.length <= props.min) {
return feedback.msgError(`最少保留${props.min}`)
}
props.modelValue.splice(index, 1)
navLists.value.splice(index, 1)
}
</script>

View File

@@ -1,7 +1,7 @@
<template>
<div>
<el-form label-width="70px">
<el-form-item label="是否启用">
<el-form-item label="是否启用" v-if="type == 'mobile'">
<el-radio-group v-model="content.enabled">
<el-radio :label="1">开启</el-radio>
<el-radio :label="0">停用</el-radio>
@@ -10,28 +10,36 @@
<el-form-item label="图片设置">
<div class="flex-1">
<div class="form-tips">最多添加5张建议图片尺寸750px*340px</div>
<del-wrap
v-for="(item, index) in content.data"
:key="index"
@close="handleDelete(index)"
class="max-w-[400px]"
>
<div class="bg-fill-light flex items-center w-full p-4 mt-4">
<material-picker
v-model="item.image"
upload-class="bg-body"
exclude-domain
/>
<div class="ml-3 flex-1">
<el-form-item label="图片名称">
<el-input v-model="item.name" placeholder="请输入名称" />
</el-form-item>
<el-form-item class="mt-[18px]" label="图片链接">
<link-picker v-model="item.link" />
</el-form-item>
</div>
</div>
</del-wrap>
<draggable class="draggable" v-model="content.data" animation="300">
<template v-slot:item="{ element: item, index }">
<del-wrap
:key="index"
@close="handleDelete(index)"
class="max-w-[400px]"
>
<div
class="bg-fill-light flex items-center w-full p-4 mt-4 cursor-move"
>
<material-picker
v-model="item.image"
upload-class="bg-body"
exclude-domain
/>
<div class="ml-3 flex-1">
<el-form-item label="图片名称">
<el-input
v-model="item.name"
placeholder="请输入名称"
/>
</el-form-item>
<el-form-item class="mt-[18px]" label="图片链接">
<link-picker v-model="item.link" />
</el-form-item>
</div>
</div>
</del-wrap>
</template>
</draggable>
</div>
</el-form-item>
<el-form-item v-if="content.data?.length < limit">
@@ -44,6 +52,7 @@
import feedback from '@/utils/feedback'
import type { PropType } from 'vue'
import type options from './options'
import Draggable from 'vuedraggable'
const limit = 5
type OptionsType = ReturnType<typeof options>
const props = defineProps({

View File

@@ -10,28 +10,36 @@
<el-form-item label="图片设置">
<div class="flex-1">
<div class="form-tips">最多添加5张建议图片尺寸750px*200px</div>
<del-wrap
v-for="(item, index) in content.data"
:key="index"
@close="handleDelete(index)"
class="max-w-[400px]"
>
<div class="bg-fill-light flex items-center w-full p-4 mt-4">
<material-picker
v-model="item.image"
upload-class="bg-body"
exclude-domain
/>
<div class="ml-3 flex-1">
<el-form-item label="图片名称">
<el-input v-model="item.name" placeholder="请输入名称" />
</el-form-item>
<el-form-item class="mt-[18px]" label="图片链接">
<link-picker v-model="item.link" />
</el-form-item>
</div>
</div>
</del-wrap>
<draggable class="draggable" v-model="content.data" animation="300">
<template v-slot:item="{ element: item, index }">
<del-wrap
:key="index"
@close="handleDelete(index)"
class="max-w-[400px]"
>
<div
class="bg-fill-light flex items-center w-full p-4 mt-4 cursor-move"
>
<material-picker
v-model="item.image"
upload-class="bg-body"
exclude-domain
/>
<div class="ml-3 flex-1">
<el-form-item label="图片名称">
<el-input
v-model="item.name"
placeholder="请输入名称"
/>
</el-form-item>
<el-form-item class="mt-[18px]" label="图片链接">
<link-picker v-model="item.link" />
</el-form-item>
</div>
</div>
</del-wrap>
</template>
</draggable>
</div>
</el-form-item>
<el-form-item v-if="content.data?.length < limit">
@@ -44,6 +52,7 @@
import feedback from '@/utils/feedback'
import type { PropType } from 'vue'
import type options from './options'
import Draggable from 'vuedraggable'
const limit = 5
type OptionsType = ReturnType<typeof options>
const props = defineProps({

View File

@@ -12,7 +12,7 @@
</footer-btns>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="decorationPages">
import Menu from '../component/pages/menu.vue'
import Preview from '../component/pages/preview.vue'
import AttrSetting from '../component/pages/attr-setting.vue'
@@ -47,7 +47,7 @@ const menus: Record<
[pagesTypeEnum.HOME]: {
id: 1,
pageType: 1,
name: '商城首页',
name: '首页装修',
pageData: generatePageData(['search', 'banner', 'nav', 'news'])
},
[pagesTypeEnum.USER]: {

View File

@@ -132,7 +132,7 @@
</footer-btns>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="decorationTabbar">
import { getDecorateTabbar, setDecorateTabbar } from '@/api/decoration'
import feedback from '@/utils/feedback'
import Draggable from 'vuedraggable'
@@ -188,7 +188,7 @@ const onMove = (e: any) => {
const getData = async () => {
const data = await getDecorateTabbar()
tabbar.list = data.list.map((item: any) => ({ ...item, link: JSON.parse(item.link) }))
tabbar.list = data.list
tabbar.style = data.style
}
const setData = async () => {

View File

@@ -8,7 +8,7 @@
ref="formRef"
class="ls-form"
:model="formData"
label-width="100px"
label-width="130px"
:rules="rules"
>
<el-tabs v-model="activeName">
@@ -18,6 +18,7 @@
<el-input
v-model="formData.base.tableName"
placeholder="请输入表名称"
clearable
/>
</div>
</el-form-item>
@@ -26,6 +27,7 @@
<el-input
v-model="formData.base.tableComment"
placeholder="请输入表描述"
clearable
/>
</div>
</el-form-item>
@@ -34,6 +36,7 @@
<el-input
v-model="formData.base.entityName"
placeholder="请输入实体类名称"
clearable
/>
</div>
</el-form-item>
@@ -43,6 +46,7 @@
<el-input
v-model="formData.base.authorName"
placeholder="请输入作者"
clearable
/>
</div>
</el-form-item>
@@ -50,9 +54,12 @@
<div class="w-80">
<el-input
v-model="formData.base.remarks"
class="el-input"
class="w-full"
type="textarea"
:rows="4"
:autosize="{ minRows: 4, maxRows: 4 }"
maxlength="200"
show-word-limit
clearable
/>
</div>
</el-form-item>
@@ -90,7 +97,7 @@
v-model="row.isRequired"
:true-label="1"
:false-label="0"
></el-checkbox>
/>
</template>
</el-table-column>
<el-table-column label="插入" width="80">
@@ -99,7 +106,7 @@
v-model="row.isInsert"
:true-label="1"
:false-label="0"
></el-checkbox>
/>
</template>
</el-table-column>
<el-table-column label="编辑" width="80">
@@ -108,7 +115,7 @@
v-model="row.isEdit"
:true-label="1"
:false-label="0"
></el-checkbox>
/>
</template>
</el-table-column>
<el-table-column label="列表" width="80">
@@ -117,7 +124,7 @@
v-model="row.isList"
:true-label="1"
:false-label="0"
></el-checkbox>
/>
</template>
</el-table-column>
<el-table-column label="查询" width="80">
@@ -126,7 +133,7 @@
v-model="row.isQuery"
:true-label="1"
:false-label="0"
></el-checkbox>
/>
</template>
</el-table-column>
<el-table-column label="查询方式">
@@ -196,6 +203,7 @@
<el-input
v-model="formData.gen.moduleName"
placeholder="请输入模块名"
clearable
/>
<div class="form-tips">生成文件所在模块名</div>
</div>
@@ -205,6 +213,7 @@
<el-input
v-model="formData.gen.functionName"
placeholder="请输入功能名称"
clearable
/>
</div>
</el-form-item>
@@ -223,6 +232,7 @@
<el-input
v-model="formData.gen.genPath"
placeholder="请输入自定义路径"
clearable
/>
</div>
</el-form-item>
@@ -263,6 +273,37 @@
</el-form-item>
</template>
</el-tab-pane>
<el-tab-pane label="关联配置" name="relation">
<el-form-item label="关联子表的表名" prop="gen.subTableName">
<el-select class="w-80" v-model="formData.gen.subTableName" clearable>
<el-option
v-for="item in optionsData.dataTable"
:key="item.tableName"
:value="item.tableName"
:label="`${item.tableName}${item.tableComment}`"
/>
</el-select>
</el-form-item>
<el-form-item label="子表关联的外键名 " prop="gen.subTableFk">
<el-select class="w-80" v-model="formData.gen.subTableFk" clearable>
<el-option
v-for="item in formData.column"
:key="item.id"
:value="item.columnName"
:label="`${item.columnName}${item.columnComment}`"
/>
</el-select>
</el-form-item>
<el-form-item label="关联表主键 " prop="gen.subTableFr">
<div class="w-80">
<el-input
v-model="formData.gen.subTableFr"
placeholder="请输入关联表主键"
clearable
/>
</div>
</el-form-item>
</el-tab-pane>
</el-tabs>
</el-form>
</el-card>
@@ -272,14 +313,14 @@
</div>
</template>
<script lang="ts" setup>
import { generateEdit, tableDetail } from '@/api/tools/code'
<script lang="ts" setup name="tableEdit">
import { dataTableAll, generateEdit, tableDetail } from '@/api/tools/code'
import { dictTypeAll } from '@/api/setting/dict'
import type { FormInstance } from 'element-plus'
import feedback from '@/utils/feedback'
import { menuLists } from '@/api/perms/menu'
import { useDictOptions } from '@/hooks/useDictOptions'
import useMultipleTabs from '@/hooks/useMultipleTabs'
enum GenTpl {
CRUD = 'crud',
TREE = 'tree'
@@ -292,6 +333,7 @@ enum GenType {
const route = useRoute()
const router = useRouter()
const { removeTab } = useMultipleTabs()
const activeName = ref('column')
const formData = reactive({
base: {
@@ -311,6 +353,7 @@ const formData = reactive({
moduleName: '',
subTableFk: '',
subTableName: '',
subTableFr: '',
treeParent: '',
treePrimary: '',
treeName: ''
@@ -343,6 +386,7 @@ const getDetails = async () => {
const { optionsData } = useDictOptions<{
dictType: any[]
menu: any[]
dataTable: any[]
}>({
dictType: {
api: dictTypeAll
@@ -354,6 +398,9 @@ const { optionsData } = useDictOptions<{
menu.children = data
return menu
}
},
dataTable: {
api: dataTableAll
}
})
@@ -363,6 +410,7 @@ const handleSave = async () => {
const { base, column, gen } = formData
await generateEdit({ ...base, ...gen, column })
feedback.msgSuccess('操作成功')
removeTab()
router.back()
} catch (error: any) {
for (const err in error) {

View File

@@ -3,10 +3,20 @@
<el-card class="!border-none" shadow="never">
<el-form class="mb-[-16px]" :model="formData" inline>
<el-form-item label="表名称">
<el-input class="w-56" v-model="formData.tableName" />
<el-input
class="w-[280px]"
v-model="formData.tableName"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="表描述">
<el-input class="w-56" v-model="formData.tableComment" />
<el-input
class="w-[280px]"
v-model="formData.tableComment"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
@@ -138,7 +148,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="codeGenerate">
import {
generateTable,
syncColumn,
@@ -228,5 +238,9 @@ const handleCommand = (command: any, row: any) => {
}
}
onActivated(() => {
getLists()
})
getLists()
</script>

View File

@@ -13,10 +13,20 @@
</template>
<el-form class="ls-form" :model="formData" inline>
<el-form-item label="表名称">
<el-input class="w-56" v-model="formData.tableName" />
<el-input
class="w-[280px]"
v-model="formData.tableName"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="表描述">
<el-input class="w-56" v-model="formData.tableComment" />
<el-input
class="w-[280px]"
v-model="formData.tableComment"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>

View File

@@ -1,10 +1,12 @@
<template>
<div class="error404">
<error
code="403"
title="您的账号权限不足,请联系管理员添加权限!"
:show-btn="false"
></error>
<error code="403" title="您的账号权限不足,请联系管理员添加权限!" :show-btn="false">
<template #content>
<div class="flex justify-center">
<img class="w-[150px] h-[150px]" src="@/assets/images/no_perms.png" alt="" />
</div>
</template>
</error>
</div>
</template>

View File

@@ -1,8 +1,10 @@
<template>
<div class="error">
<div>
<div class="error-code">{{ code }}</div>
<div class="lg lighter mt-7 mb-7">{{ title }}</div>
<slot name="content">
<div class="error-code">{{ code }}</div>
</slot>
<div class="text-lg text-tx-secondary mt-7 mb-7">{{ title }}</div>
<el-button v-if="showBtn" type="primary" @click="router.go(-1)">
{{ second }} 秒后返回上一页
</el-button>

View File

@@ -23,7 +23,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="materialCenter">
const tabsMap = [
{
type: 'image',

View File

@@ -1,7 +1,7 @@
<template>
<div>
<el-card class="!border-none" shadow="never">
<el-page-header content="编辑通知设置" @back="$router.back()" />
<el-page-header :content="$route.meta.title" @back="$router.back()" />
</el-card>
<el-form
ref="formRef"
@@ -37,16 +37,14 @@
<div class="w-full max-w-[320px]">
<el-input
type="textarea"
:rows="6"
:autosize="{ minRows: 6, maxRows: 6 }"
v-model="formData.smsNotice.content"
/>
</div>
<div class="form-tips">
可选变量 用户昵称:nickname 订单编号:order_sn 支付时间:pay_time
<br />
示例亲爱的${nickname}您的订单${order_sn}已支付成功商家正在快马加鞭为您安排发货
<br />
生效条件1管理后台完成短信设置2第三方短信平台申请模板
<div v-for="(item, index) in formData.smsNotice.tips" :key="index">
{{ item }}
</div>
</div>
</div>
</el-form-item>
@@ -58,10 +56,11 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="noticeEdit">
import type { FormInstance } from 'element-plus'
import feedback from '@/utils/feedback'
import { noticeDetail, setNoticeConfig } from '@/api/message'
import useMultipleTabs from '@/hooks/useMultipleTabs'
const route = useRoute()
const router = useRouter()
@@ -75,7 +74,8 @@ const formData = reactive({
smsNotice: {
status: 0,
templateId: '',
content: ''
content: '',
tips: []
}
})
@@ -95,7 +95,7 @@ const rules = {
}
]
}
const { removeTab } = useMultipleTabs()
const formRef = shallowRef<FormInstance>()
const getDetails = async () => {
@@ -114,6 +114,7 @@ const handleSave = async () => {
await formRef.value?.validate()
await setNoticeConfig(formData)
feedback.msgSuccess('操作成功')
removeTab()
router.back()
}

View File

@@ -47,7 +47,7 @@
</el-card>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="notice">
import { noticeLists } from '@/api/message'
import { getRoutePath } from '@/router'
@@ -87,5 +87,9 @@ const getLists = async () => {
}
}
onActivated(() => {
getLists()
})
getLists()
</script>

View File

@@ -26,7 +26,7 @@
<edit-popup ref="editRef" @success="getLists" />
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="shortLetter">
import { smsLists } from '@/api/message'
import EditPopup from './edit.vue'
const editRef = shallowRef<InstanceType<typeof EditPopup>>()

View File

@@ -26,17 +26,27 @@
/>
</el-form-item>
<el-form-item label="部门名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入部门名称" clearable />
<el-input
v-model="formData.name"
placeholder="请输入部门名称"
clearable
:maxlength="100"
/>
</el-form-item>
<el-form-item label="负责人" prop="duty">
<el-input v-model="formData.duty" placeholder="请输入负责人姓名" clearable />
<el-input
v-model="formData.duty"
placeholder="请输入负责人姓名"
clearable
:maxlength="30"
/>
</el-form-item>
<el-form-item label="联系电话" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入联系电话" clearable />
</el-form-item>
<el-form-item label="排序" prop="sort">
<div>
<el-input-number v-model="formData.sort" :min="0" />
<el-input-number v-model="formData.sort" :min="0" :max="9999" />
<div class="form-tips">默认为0 数值越大越排前</div>
</div>
</el-form-item>
@@ -71,7 +81,7 @@ const formData = reactive({
})
const checkMobile = (rule: any, value: any, callback: any) => {
if (!value) {
return callback(new Error('手机号不能为空'))
return callback()
} else {
const reg = /^[1][3,4,5,6,7,8,9][0-9]{9}$/
console.log(reg.test(value))

View File

@@ -4,14 +4,14 @@
<el-form ref="formRef" class="mb-[-16px]" :model="queryParams" :inline="true">
<el-form-item label="部门名称" prop="name">
<el-input
class="w-56"
class="w-[280px]"
v-model="queryParams.name"
clearable
@keyup.enter="getLists"
/>
</el-form-item>
<el-form-item label="部门状态" prop="isStop">
<el-select class="w-56" v-model="queryParams.isStop">
<el-select class="w-[280px]" v-model="queryParams.isStop">
<el-option label="全部" value />
<el-option label="正常" value="0" />
<el-option label="停用" value="1" />
@@ -91,7 +91,7 @@
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="department">
import type { ElTable, FormInstance } from 'element-plus'
import EditPopup from './edit.vue'
import { deptDelete, deptLists } from '@/api/org/department'

View File

@@ -10,14 +10,19 @@
>
<el-form ref="formRef" :model="formData" label-width="84px" :rules="formRules">
<el-form-item label="岗位名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入岗位名称" clearable />
<el-input
v-model="formData.name"
placeholder="请输入岗位名称"
clearable
:maxlength="100"
/>
</el-form-item>
<el-form-item label="岗位编码" prop="code">
<el-input v-model="formData.code" placeholder="请输入岗位编码" clearable />
</el-form-item>
<el-form-item label="排序" prop="sort">
<div>
<el-input-number v-model="formData.sort" :min="0" />
<el-input-number v-model="formData.sort" :min="0" :max="9999" />
<div class="form-tips">默认为0 数值越大越排前</div>
</div>
</el-form-item>
@@ -27,6 +32,8 @@
placeholder="请输入备注"
type="textarea"
:autosize="{ minRows: 4, maxRows: 6 }"
maxlength="200"
show-word-limit
/>
</el-form-item>
<el-form-item label="岗位状态" prop="isStop">

View File

@@ -4,7 +4,7 @@
<el-form ref="formRef" class="mb-[-16px]" :model="queryParams" :inline="true">
<el-form-item label="岗位编码">
<el-input
class="w-56"
class="w-[280px]"
v-model="queryParams.code"
clearable
@keyup.enter="resetPage"
@@ -12,14 +12,14 @@
</el-form-item>
<el-form-item label="岗位名称">
<el-input
class="w-56"
class="w-[280px]"
v-model="queryParams.name"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="岗位状态">
<el-select class="w-56" v-model="queryParams.isStop">
<el-select class="w-[280px]" v-model="queryParams.isStop">
<el-option label="全部" value />
<el-option label="正常" :value="0" />
<el-option label="停用" :value="1" />
@@ -51,7 +51,7 @@
show-overflow-tooltip
/>
<el-table-column label="添加时间" prop="createTime" min-width="180" />
<el-table-column label="部门状态" prop="isStop" min-width="100">
<el-table-column label="岗位状态" prop="isStop" min-width="100">
<template #default="{ row }">
<el-tag class="ml-2" :type="row.isStop ? 'danger' : ''">
{{ row.isStop ? '停用' : '正常' }}
@@ -86,7 +86,7 @@
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="post">
import { postDelete, postLists } from '@/api/org/post'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'

View File

@@ -28,18 +28,19 @@
<el-form-item label="名称" prop="nickname">
<el-input v-model="formData.nickname" placeholder="请输入名称" clearable />
</el-form-item>
<el-form-item label="归属部门" prop="deptId">
<el-form-item label="归属部门" prop="deptIds">
<el-tree-select
class="flex-1"
v-model="formData.deptId"
v-model="formData.deptIds"
:data="optionsData.dept"
clearable
node-key="id"
multiple
:props="{
value: 'id',
label: 'name',
disabled(data: any) {
return data.isStop
return !!data.isStop
}
}"
check-strictly
@@ -47,11 +48,12 @@
placeholder="请选择上级部门"
/>
</el-form-item>
<el-form-item label="岗位" prop="deptId">
<el-form-item label="岗位" prop="postIds">
<el-select
class="flex-1"
clearable
v-model="formData.postId"
multiple
v-model="formData.postIds"
placeholder="请选择岗位"
>
<el-option
@@ -63,10 +65,11 @@
</el-select>
</el-form-item>
<el-form-item label="角色" prop="role">
<el-form-item label="角色" prop="roleIds">
<el-select
v-model="formData.role"
v-model="formData.roleIds"
:disabled="isRoot"
multiple
class="flex-1"
clearable
placeholder="请选择角色"
@@ -76,7 +79,7 @@
v-for="(item, index) in optionsData.role"
:key="index"
:label="item.name"
:value="String(item.id)"
:value="item.id"
/>
</el-select>
</el-form-item>
@@ -135,12 +138,12 @@ const popupTitle = computed(() => {
})
const formData = reactive({
id: '',
id: 0,
username: '',
nickname: '',
deptId: '',
postId: '',
role: '',
deptIds: [],
postIds: [],
roleIds: [],
avatar: '',
password: '',
passwordConfirm: '',
@@ -149,7 +152,7 @@ const formData = reactive({
})
const isRoot = computed(() => {
return formData.role == '0'
return formData.id == 1
})
const passwordConfirmValidator = (rule: object, value: string, callback: any) => {
@@ -174,8 +177,9 @@ const formRules = reactive({
trigger: ['blur']
}
],
role: [
roleIds: [
{
type: 'array',
required: true,
message: '请选择角色',
trigger: ['blur']
@@ -231,6 +235,13 @@ const open = (type = 'add') => {
}
const setFormData = async (row: any) => {
formRules.password = []
formRules.passwordConfirm = [
{
validator: passwordConfirmValidator,
trigger: 'blur'
}
]
const data = await adminDetail({
id: row.id
})
@@ -239,16 +250,7 @@ const setFormData = async (row: any) => {
//@ts-ignore
formData[key] = data[key]
}
Number(formData.deptId) == 0 && (formData.deptId = '')
Number(formData.postId) == 0 && (formData.postId = '')
}
formRules.password = []
formRules.passwordConfirm = [
{
validator: passwordConfirmValidator,
trigger: 'blur'
}
]
}
const handleClose = () => {

View File

@@ -5,7 +5,7 @@
<el-form-item label="管理员账号">
<el-input
v-model="formData.username"
class="w-56"
class="w-[280px]"
clearable
@keyup.enter="resetPage"
/>
@@ -13,13 +13,13 @@
<el-form-item label="管理员名称">
<el-input
v-model="formData.nickname"
class="w-56"
class="w-[280px]"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="管理员角色">
<el-select class="w-56" v-model="formData.role">
<el-select class="w-[280px]" v-model="formData.role">
<el-option label="全部" value="" />
<el-option
v-for="(item, index) in optionsData.role"
@@ -52,8 +52,18 @@
</el-table-column>
<el-table-column label="账号" prop="username" min-width="100" />
<el-table-column label="名称" prop="nickname" min-width="100" />
<el-table-column label="角色" prop="role" min-width="100" />
<el-table-column label="部门" prop="dept" min-width="100" />
<el-table-column
label="角色"
prop="role"
show-tooltip-when-overflow
min-width="100"
/>
<el-table-column
label="部门"
prop="dept"
show-tooltip-when-overflow
min-width="100"
/>
<el-table-column label="创建时间" prop="createTime" min-width="180" />
<el-table-column label="最近登录时间" prop="lastLoginTime" min-width="180" />
<el-table-column label="最近登录IP" prop="lastLoginIp" min-width="120" />
@@ -100,7 +110,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="admin">
import { adminLists, adminDelete, adminStatus } from '@/api/perms/admin'
import { roleAll } from '@/api/perms/role'
import { useDictOptions } from '@/hooks/useDictOptions'

View File

@@ -73,7 +73,11 @@
</div>
</div>
</el-form-item>
<el-form-item label="选中菜单" prop="p" v-if="formData.menuType == MenuEnum.MENU">
<el-form-item
label="选中菜单"
prop="selected"
v-if="formData.menuType == MenuEnum.MENU"
>
<div class="flex-1">
<el-input
v-model="formData.selected"
@@ -116,20 +120,20 @@
</div>
</div>
</el-form-item>
<!-- <el-form-item
v-if="formData.menuType == MenuEnum.MENU"
label="是否缓存"
prop="isCache"
required
>
<div>
<el-radio-group v-model="formData.isCache">
<el-radio :label="1">缓存</el-radio>
<el-radio :label="0">不缓存</el-radio>
</el-radio-group>
<div class="form-tips">选择缓存则会被`keep-alive`缓存</div>
</div>
</el-form-item> -->
<el-form-item
v-if="formData.menuType == MenuEnum.MENU"
label="是否缓存"
prop="isCache"
required
>
<div>
<el-radio-group v-model="formData.isCache">
<el-radio :label="1">缓存</el-radio>
<el-radio :label="0">不缓存</el-radio>
</el-radio-group>
<div class="form-tips">选择缓存则会被`keep-alive`缓存</div>
</div>
</el-form-item>
<el-form-item
v-if="formData.menuType != MenuEnum.BUTTON"
label="是否显示"
@@ -162,7 +166,7 @@
</el-form-item>
<el-form-item label="菜单排序" prop="menuSort">
<div>
<el-input-number v-model="formData.menuSort" />
<el-input-number v-model="formData.menuSort" :max="9999" />
<div class="form-tips">数值越大越排前</div>
</div>
</el-form-item>
@@ -259,15 +263,12 @@ const formRules = {
}
const menuOptions = ref<any[]>([])
const pageOptions = ref<any[]>([])
const getMenu = async () => {
const data: any = await menuLists()
const menu = { id: 0, menuName: '顶级', children: [] }
pageOptions.value = arrayToTree(
const menu: any = { id: 0, menuName: '顶级', children: [] }
menu.children = arrayToTree(
treeToArray(data).filter((item) => item.menuType != MenuEnum.BUTTON)
)
menu.children = data
menuOptions.value.push(menu)
}

View File

@@ -90,7 +90,7 @@
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="menu">
import { menuDelete, menuLists } from '@/api/perms/menu'
import type { ElTable } from 'element-plus'
import { MenuEnum } from '@/enums/appEnums'

View File

@@ -27,8 +27,10 @@
<el-input
v-model="formData.remark"
type="textarea"
:rows="4"
:autosize="{ minRows: 4, maxRows: 6 }"
placeholder="请输入备注"
maxlength="200"
show-word-limit
/>
</el-form-item>
<el-form-item label="排序" prop="sort">

View File

@@ -63,7 +63,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="role">
import { roleLists, roleDelete } from '@/api/perms/role'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'

View File

@@ -31,7 +31,7 @@
</el-form-item>
<el-form-item label="排序" prop="sort">
<div>
<el-input-number v-model="formData.sort" />
<el-input-number v-model="formData.sort" :min="0" :max="9999" />
<div class="form-tips">数值越大越排前</div>
</div>
</el-form-item>
@@ -42,7 +42,14 @@
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" type="textarea" rows="4" clearable />
<el-input
v-model="formData.remark"
type="textarea"
:autosize="{ minRows: 4, maxRows: 6 }"
clearable
maxlength="200"
show-word-limit
/>
</el-form-item>
</el-form>
</popup>

View File

@@ -4,7 +4,7 @@
<el-page-header class="mb-4" content="数据管理" @back="$router.back()" />
<el-form ref="formRef" class="mb-[-16px]" :model="queryParams" inline>
<el-form-item label="字典名称">
<el-select class="w-56" v-model="queryParams.dictType" @change="getLists">
<el-select class="w-[280px]" v-model="queryParams.dictType" @change="getLists">
<el-option
v-for="item in optionsData.dictType"
:label="item.dictName"
@@ -15,14 +15,14 @@
</el-form-item>
<el-form-item label="数据名称">
<el-input
class="w-56"
class="w-[280px]"
v-model="queryParams.name"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="数据状态">
<el-select class="w-56" v-model="queryParams.status">
<el-select class="w-[280px]" v-model="queryParams.status">
<el-option label="全部" value />
<el-option label="正常" :value="1" />
<el-option label="停用" :value="0" />
@@ -71,7 +71,12 @@
<el-tag v-else type="danger">停用</el-tag>
</template>
</el-table-column>
<el-table-column label="备注" prop="remark" min-width="120" />
<el-table-column
label="备注"
prop="remark"
min-width="120"
show-tooltip-when-overflow
/>
<el-table-column label="排序" prop="sort" />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
@@ -104,7 +109,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="dictData">
import { dictDataDelete, dictDataLists, dictTypeAll } from '@/api/setting/dict'
import { useDictOptions } from '@/hooks/useDictOptions'
import { usePaging } from '@/hooks/usePaging'

View File

@@ -28,7 +28,14 @@
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="dictRemark">
<el-input v-model="formData.dictRemark" type="textarea" rows="4" clearable />
<el-input
v-model="formData.dictRemark"
type="textarea"
:autosize="{ minRows: 4, maxRows: 6 }"
clearable
maxlength="200"
show-word-limit
/>
</el-form-item>
</el-form>
</popup>

View File

@@ -4,7 +4,7 @@
<el-form ref="formRef" class="mb-[-16px]" :model="queryParams" inline>
<el-form-item label="字典名称">
<el-input
class="w-56"
class="w-[280px]"
v-model="queryParams.dictName"
clearable
@keyup.enter="resetPage"
@@ -12,14 +12,14 @@
</el-form-item>
<el-form-item label="字典类型">
<el-input
class="w-56"
class="w-[280px]"
v-model="queryParams.dictType"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="状态">
<el-select class="w-56" v-model="queryParams.dictStatus">
<el-select class="w-[280px]" v-model="queryParams.dictStatus">
<el-option label="全部" value />
<el-option label="正常" :value="1" />
<el-option label="停用" :value="0" />
@@ -68,7 +68,11 @@
<el-tag v-else type="danger">停用</el-tag>
</template>
</el-table-column>
<el-table-column label="备注" prop="dictRemark" />
<el-table-column
label="备注"
prop="dictRemark"
show-tooltip-when-overflow
/>
<el-table-column label="创建时间" prop="createTime" min-width="180" />
<el-table-column label="操作" width="190" fixed="right">
<template #default="{ row }">
@@ -80,20 +84,17 @@
>
编辑
</el-button>
<el-button
v-perms="['setting:dict:data:list']"
type="primary"
link
@click="
$router.push({
<el-button v-perms="['setting:dict:data:list']" type="primary" link>
<router-link
:to="{
path: getRoutePath('setting:dict:data:list'),
query: {
type: row.dictType
}
})
"
>
数据管理
}"
>
数据管理
</router-link>
</el-button>
<el-button
v-perms="['setting:dict:type:del']"
@@ -116,7 +117,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="dictType">
import { dictTypeDelete, dictTypeLists } from '@/api/setting/dict'
import { usePaging } from '@/hooks/usePaging'
import { getRoutePath } from '@/router'

View File

@@ -9,30 +9,36 @@
<el-radio :label="0">关闭</el-radio>
</el-radio-group>
<div class="form-tips">默认开关闭则前端不显示该功能</div>
<div class="form-tips">默认开关闭则前端不显示该功能</div>
</div>
</el-form-item>
</el-form>
</el-card>
<el-card class="!border-none mt-4" shadow="never">
<div class="flex">
<div class="flex-1 w-3/5">
<el-button type="primary" class="mb-4" @click="handleAdd">添加</el-button>
<div class="lg:flex">
<div class="flex-1 min-w-0">
<el-button type="primary" class="mb-4" @click="handleAdd">
<template #icon>
<icon name="el-icon-Plus" />
</template>
添加
</el-button>
<el-table size="large" :data="formData.list">
<el-table-column label="ID" prop="id" width="120">
<template #default="{ $index }">
{{ $index }}
<el-table-column label="关键词" prop="describe" min-width="200">
<template #default="{ row }">
<el-input
v-model.trim="row.name"
clearable
placeholder="请输入关键字"
show-word-limit
maxlength="30"
/>
</template>
</el-table-column>
<el-table-column label="关键词" prop="describe" min-width="160">
<el-table-column label="排序" prop="describe" min-width="80">
<template #default="{ row }">
<el-input v-model="row.name" clearable />
</template>
</el-table-column>
<el-table-column label="排序" prop="describe" min-width="160">
<template #default="{ row }">
<el-input v-model="row.sort" type="number" />
<el-input v-model="row.sort" type="number" clearable />
</template>
</el-table-column>
<el-table-column label="操作" min-width="80" fixed="right">
@@ -50,8 +56,8 @@
</el-table>
</div>
<div class="w-2/5 hot-search-phone">
<span class="mb-4">- 热搜预览图 -</span>
<div class="flex-none hot-search-phone mt-4 lg:mt-0 lg:ml-4">
<div class="mb-4 text-center">- 热搜预览图 -</div>
<div class="hot-search-phone-content">
<!-- 搜索框 -->
<div class="search-com">
@@ -63,7 +69,12 @@
<!-- 热门搜索 -->
<div class="hot-search-title">热门搜索</div>
<div class="hot-search-text">
<span v-for="(text, index) in list" :key="index">{{ text.name }}</span>
<span
class="truncate max-w-full"
v-for="(text, index) in list"
:key="index"
>{{ text.name }}</span
>
</div>
</div>
</div>
@@ -76,7 +87,7 @@
</div>
</template>
<script setup lang="ts">
<script setup lang="ts" name="search">
import { getSearch, setSearch } from '@/api/setting/search'
import type { Search } from '@/api/setting/search'
import feedback from '@/utils/feedback'
@@ -87,7 +98,7 @@ const formData = reactive<Search>({
})
const list = computed(() => {
return [...formData.list].sort((v1, v2) => v2.sort - v1.sort)
return formData.list.filter((item) => item.name).sort((v1, v2) => v2.sort - v1.sort)
})
// 获取登录注册数据
@@ -105,7 +116,7 @@ const getData = async () => {
const handleAdd = () => {
formData.list.push({
name: '关键字',
name: '',
sort: 0
})
}
@@ -130,12 +141,10 @@ getData()
<style lang="scss" scoped>
.hot-search {
.hot-search-phone {
margin-left: 20px;
@apply flex flex-col items-center;
width: 300px;
&-content {
width: 280px;
height: 494px;
width: 100%;
height: 530px;
padding: 12px 12px;
border-radius: 10px;
border: 1px solid #e6e6e6;

View File

@@ -35,7 +35,7 @@
<edit-popup ref="editRef" @success="getLists" />
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="storage">
import { storageLists } from '@/api/setting/storage'
import EditPopup from './edit.vue'
const editRef = shallowRef<InstanceType<typeof EditPopup>>()

View File

@@ -136,7 +136,7 @@
</div>
</template>
<script setup lang="ts">
<script setup lang="ts" name="cache">
import { systemCache } from '@/api/setting/system'
import vCharts from 'vue-echarts'
import { reactive } from 'vue'

View File

@@ -113,7 +113,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="environment">
import { systemInfo } from '@/api/setting/system'
const loading = ref(false)
const info = ref({

View File

@@ -4,22 +4,34 @@
<el-card class="!border-none" shadow="never">
<el-form class="ls-form" :model="formData" inline>
<el-form-item label="管理员">
<el-input class="w-56" placeholder="请输入" v-model="formData.username" />
<el-input
class="w-[280px]"
placeholder="请输入"
v-model="formData.username"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="访问方式">
<el-select class="w-56" v-model="formData.type" placeholder="请选择">
<el-select class="w-[280px]" v-model="formData.type" placeholder="请选择">
<el-option
v-for="(item, index) in visitType"
:key="index"
:label="item.label"
:value="item.value"
></el-option>
/>
</el-select>
</el-form-item>
<el-form-item label="来源IP">
<el-input class="w-56" placeholder="请输入" v-model="formData.ip" />
<el-input
class="w-[280px]"
placeholder="请输入"
v-model="formData.ip"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item label="访问时间">
@@ -30,7 +42,13 @@
</el-form-item>
<el-form-item label="访问链接">
<el-input class="w-56" placeholder="请输入" v-model="formData.url" />
<el-input
class="w-[280px]"
placeholder="请输入"
v-model="formData.url"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item>
@@ -61,7 +79,7 @@
</div>
</template>
<script setup lang="ts">
<script setup lang="ts" name="journal">
import { systemLogLists } from '@/api/setting/system'
import { usePaging } from '@/hooks/usePaging'

View File

@@ -0,0 +1,142 @@
<template>
<div class="article-edit">
<el-card class="!border-none" shadow="never">
<el-page-header :content="$route.meta.title" @back="$router.back()" />
</el-card>
<el-card class="mt-4 !border-none" shadow="never">
<el-form
ref="formRef"
class="ls-form"
:model="formData"
label-width="96px"
:rules="rules"
>
<el-form-item label="任务名称" prop="name">
<div class="w-80">
<el-input
v-model="formData.name"
placeholder="请输入任务名称"
maxlength="30"
clearable
/>
</div>
</el-form-item>
<el-form-item label="任务分组" prop="groups">
<el-select
class="w-80"
v-model="formData.groups"
clearable
placeholder="请选择任务分组"
>
<el-option label="默认" value="default" />
<el-option label="系统" value="system" />
</el-select>
</el-form-item>
<el-form-item label="调用方法" prop="command">
<div class="w-80">
<el-input
v-model="formData.command"
placeholder="请输入调用目标字符串"
clearable
/>
</div>
</el-form-item>
<el-form-item label="cron表达式" prop="rules">
<div class="w-80">
<el-input v-model="formData.rules" placeholder="请输入cron执行表达式" />
</div>
</el-form-item>
<el-form-item label="备注" prop="remark">
<div class="w-80">
<el-input
v-model="formData.remark"
type="textarea"
:autosize="{ minRows: 3, maxRows: 6 }"
:maxlength="200"
show-word-limit
clearable
/>
</div>
</el-form-item>
<el-form-item label="执行策略" prop="groups">
<el-radio-group v-model="formData.strategy">
<el-radio :label="1"> 立即执行 </el-radio>
<el-radio :label="2"> 执行一次 </el-radio>
<el-radio :label="3"> 放弃执行 </el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="是否并发" prop="concurrent">
<el-radio-group v-model="formData.concurrent">
<el-radio :label="1"> 允许 </el-radio>
<el-radio :label="0"> 禁止 </el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="状态">
<el-switch v-model="formData.status" :active-value="1" :inactive-value="2" />
</el-form-item>
</el-form>
</el-card>
<footer-btns>
<el-button type="primary" @click="handleSave">保存</el-button>
</footer-btns>
</div>
</template>
<script lang="ts" setup name="scheduledTaskEdit">
import type { FormInstance } from 'element-plus'
import { crontabAdd, crontabEdit, crontabDetail } from '@/api/setting/system'
import useMultipleTabs from '@/hooks/useMultipleTabs'
import feedback from '@/utils/feedback'
const route = useRoute()
const router = useRouter()
const formData = reactive({
id: '',
name: '',
groups: '',
command: '',
rules: '',
status: 1,
strategy: 1,
concurrent: 0,
remark: ''
})
const { removeTab } = useMultipleTabs()
const formRef = shallowRef<FormInstance>()
const rules = reactive({
name: [{ required: true, message: '请输入任务名称' }],
command: [{ required: true, message: '请输入调用目标字符串' }],
rules: [{ required: true, message: '请输入cron执行表达式' }]
})
const getDetails = async () => {
const data = await crontabDetail({
id: route.query.id
})
Object.keys(formData).forEach((key) => {
//@ts-ignore
formData[key] = data[key]
})
}
const handleSave = async () => {
await formRef.value?.validate()
if (route.query.id) {
await crontabEdit(formData)
} else {
await crontabAdd(formData)
}
feedback.msgSuccess('操作成功')
removeTab()
router.back()
}
onMounted(async () => {
if (!route.query.id) {
return
}
await getDetails()
})
</script>

View File

@@ -0,0 +1,111 @@
<template>
<div>
<el-card shadow="never" class="!border-none">
<router-link
v-perms="['crontab/add', 'crontab/add:edit']"
:to="getRoutePath('crontab/add:edit')"
>
<el-button type="primary" class="mb-[16px]">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button>
</router-link>
<el-table
ref="paneTable"
class="m-t-24"
:data="pager.lists"
v-loading="pager.loading"
style="width: 100%"
>
<el-table-column prop="name" label="名称" min-width="120" />
<el-table-column prop="groups" label="分组" min-width="100">
<template #default="{ row }">
<dict-value
:value="row.groups"
:options="[
{
name: '默认',
value: 'default'
},
{
name: '系统',
value: 'system'
}
]"
/>
</template>
</el-table-column>
<el-table-column prop="command" label="调用目标字符串" min-width="100" />
<el-table-column prop="rules" label="cron表达式" min-width="100" />
<el-table-column prop="status" label="状态" min-width="100">
<template #default="{ row }">
<el-tag v-if="row.status == 1" type="success">运行中</el-tag>
<el-tag v-if="row.status == 2" type="info">已停止</el-tag>
<el-tag v-if="row.status == 3" type="danger">错误</el-tag>
</template>
</el-table-column>
<el-table-column prop="error" label="错误信息" min-width="120" />
<el-table-column label="最后执行时间" prop="endTime" min-width="180" />
<el-table-column prop="taskTime" label="执行耗时ms" min-width="100" />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<div class="flex">
<el-button type="primary" link>
<router-link
v-perms="['crontab/edit', 'crontab/add:edit']"
:to="{
path: getRoutePath('crontab/add:edit'),
query: {
id: row.id
}
}"
>
<el-button type="primary" link> 编辑 </el-button>
</router-link>
</el-button>
<el-button
v-perms="['crontab/delete']"
type="danger"
link
@click="handleDelete(row.id)"
>
删除
</el-button>
</div>
</template>
</el-table-column>
</el-table>
<div class="flex justify-end mt-4">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
</div>
</template>
<script lang="ts" setup name="scheduledTask">
import { crontabLists, crontabDel } from '@/api/setting/system'
import { usePaging } from '@/hooks/usePaging'
import { getRoutePath } from '@/router'
import feedback from '@/utils/feedback'
const { pager, getLists } = usePaging({
fetchFun: crontabLists,
params: {}
})
const handleDelete = async (id: number) => {
await feedback.confirm('确定要删除?')
await crontabDel({ id })
feedback.msgSuccess('删除成功')
getLists()
}
getLists()
</script>
<style lang="scss"></style>

View File

@@ -98,7 +98,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="loginRegister">
import type { LoginSetup } from '@/api/setting/user'
import { getLogin, setLogin } from '@/api/setting/user'
import feedback from '@/utils/feedback'

View File

@@ -25,7 +25,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="userSetup">
import { getUserSetup, setUserSetup } from '@/api/setting/user'
import feedback from '@/utils/feedback'
// import type { FormInstance } from 'element-plus'

View File

@@ -50,7 +50,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="webFilling">
import { getCopyright, setCopyright } from '@/api/setting/website'
import feedback from '@/utils/feedback'
// 表单数据
@@ -84,7 +84,9 @@ const handleDelete = (index: number) => {
// 设置备案信息
const handleSubmit = async () => {
await setCopyright(formData.value)
await setCopyright({
list: formData.value
})
feedback.msgSuccess('操作成功')
getData()
}

View File

@@ -34,7 +34,7 @@
</el-form-item>
</el-card>
<el-card shadow="never" class="!border-none mt-4">
<div class="text-xl font-medium mb-[20px]">商城设置</div>
<div class="text-xl font-medium mb-[20px]">前台设置</div>
<el-form-item label="商城名称" prop="shopName">
<div class="w-80">
<el-input
@@ -59,7 +59,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="webInformation">
import { getWebsite, setWebsite } from '@/api/setting/website'
import useAppStore from '@/stores/modules/app'
import feedback from '@/utils/feedback'

View File

@@ -30,7 +30,7 @@
</footer-btns>
</template>
<script setup lang="ts">
<script setup lang="ts" naem="webProtocol">
import { getProtocol, setProtocol } from '@/api/setting/website'
import feedback from '@/utils/feedback'

Some files were not shown because too many files have changed in this diff Show More