mirror of
https://gitee.com/likeadmin/likeadmin_java.git
synced 2026-06-11 16:54:40 +08:00
Compare commits
280 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bacda99c59 | ||
|
|
8718c22cee | ||
|
|
c10464d873 | ||
|
|
f6589a8e33 | ||
|
|
9223b88a72 | ||
|
|
6cdc2b82e1 | ||
|
|
84cded01f2 | ||
|
|
f2038fa7af | ||
|
|
ecd5abbd05 | ||
|
|
8481c63ef2 | ||
|
|
20b7c760fd | ||
|
|
9595769d46 | ||
|
|
9e5bd06e37 | ||
|
|
f51fab1deb | ||
|
|
70fb9d4b9b | ||
|
|
a8559f0d70 | ||
|
|
b2bfaca816 | ||
|
|
f2bbfffe10 | ||
|
|
803a50cf3c | ||
|
|
c46903a210 | ||
|
|
2f161aa3fe | ||
|
|
22e7aa77cd | ||
|
|
18360d43e5 | ||
|
|
b360bb7485 | ||
|
|
ded1cabf1e | ||
|
|
f4b6179336 | ||
|
|
35b485c0a7 | ||
|
|
f39417f9b9 | ||
|
|
313121b2ab | ||
|
|
a6ad0a2feb | ||
|
|
e20fe09db4 | ||
|
|
bf31eff2e0 | ||
|
|
8b450e991f | ||
|
|
86c8697a0f | ||
|
|
16fbaa8b4e | ||
|
|
0f08a3ec04 | ||
|
|
54fd266103 | ||
|
|
b4dadbee38 | ||
|
|
45645668ef | ||
|
|
79a3959a17 | ||
|
|
678c5a5fb6 | ||
|
|
b081a2b3e5 | ||
|
|
21866eb315 | ||
|
|
5880ea48af | ||
|
|
ae398bf417 | ||
|
|
96ce0b284c | ||
|
|
5d056280b0 | ||
|
|
712538213b | ||
|
|
97518d66d3 | ||
|
|
570198d9bc | ||
|
|
f48116e8d1 | ||
|
|
d6bd188203 | ||
|
|
144fe94ecb | ||
|
|
667b92265f | ||
|
|
964e9c5bd7 | ||
|
|
0daebef757 | ||
|
|
691786b478 | ||
|
|
93aafd2dbe | ||
|
|
8f936f2df4 | ||
|
|
27bcde0da0 | ||
|
|
1f193e7850 | ||
|
|
55ee7d8a47 | ||
|
|
c45df35bd9 | ||
|
|
853e64fee5 | ||
|
|
f2450bc615 | ||
|
|
ed6b24c677 | ||
|
|
7a71bcf238 | ||
|
|
22bebdf804 | ||
|
|
6f8e8442c0 | ||
|
|
b693e829f9 | ||
|
|
8d37e36395 | ||
|
|
7419ceb502 | ||
|
|
f6491d1ba0 | ||
|
|
84c4b305d1 | ||
|
|
5f3260c586 | ||
|
|
c5781cd796 | ||
|
|
9d4964af1b | ||
|
|
56de8a32f1 | ||
|
|
dbdeed946e | ||
|
|
42892bcb8b | ||
|
|
a7d6b7ce61 | ||
|
|
d9f6b66c56 | ||
|
|
373bd551d7 | ||
|
|
e5f1ac1231 | ||
|
|
c3e0a81b31 | ||
|
|
df513e47ec | ||
|
|
62a3606169 | ||
|
|
97202201a2 | ||
|
|
088fffe836 | ||
|
|
d59c9de38a | ||
|
|
d63947856b | ||
|
|
36b6540a60 | ||
|
|
49fd6d3639 | ||
|
|
3fd832d9e6 | ||
|
|
aabc6205fb | ||
|
|
4a7fd71da7 | ||
|
|
d7b6dc992f | ||
|
|
2998041bde | ||
|
|
2304922b8a | ||
|
|
049209bfca | ||
|
|
dc5ed4b14b | ||
|
|
9beff48e28 | ||
|
|
173640af07 | ||
|
|
919cdc243c | ||
|
|
670ac0208c | ||
|
|
869c444fa5 | ||
|
|
8b6b0e5257 | ||
|
|
8fed83cd15 | ||
|
|
864b54951a | ||
|
|
9e89783add | ||
|
|
3b8e501a0b | ||
|
|
3e97c2201b | ||
|
|
3b5a8ae197 | ||
|
|
43983deb48 | ||
|
|
2022859769 | ||
|
|
bdf79ccb84 | ||
|
|
2a1d803c5f | ||
|
|
444ea6b4cb | ||
|
|
f76a83b918 | ||
|
|
6e7292b97c | ||
|
|
4281a0f5bc | ||
|
|
933ea5a3dd | ||
|
|
75c8b03969 | ||
|
|
a22fe53275 | ||
|
|
85ba64cd2f | ||
|
|
1d83523405 | ||
|
|
1ab2ca6b4e | ||
|
|
5c043df578 | ||
|
|
f7a1b14500 | ||
|
|
a1a70346c9 | ||
|
|
edfbe6ab4c | ||
|
|
d593391f62 | ||
|
|
5f5026d40c | ||
|
|
2453b0fc3b | ||
|
|
0077e75e85 | ||
|
|
327f0df6a9 | ||
|
|
03d09ca7d7 | ||
|
|
621e7916dc | ||
|
|
c2a64e30f5 | ||
|
|
698d44696e | ||
|
|
ef350201ca | ||
|
|
06bc994b42 | ||
|
|
2c5310ca21 | ||
|
|
0c5d7641b0 | ||
|
|
af92e6209c | ||
|
|
cab7c3af39 | ||
|
|
c38c46c09f | ||
|
|
1805cb1515 | ||
|
|
0d086f6198 | ||
|
|
4d43d7cdcc | ||
|
|
8105c877af | ||
|
|
ff5b649969 | ||
|
|
c64d0151b3 | ||
|
|
98328e1bb1 | ||
|
|
402321fe3c | ||
|
|
830c10ea73 | ||
|
|
728a0f6ec5 | ||
|
|
40df111da7 | ||
|
|
1d7c2383c1 | ||
|
|
3137a59566 | ||
|
|
339f63c0c0 | ||
|
|
edc5357b8c | ||
|
|
e22508240d | ||
|
|
8480f98f28 | ||
|
|
45b11402ce | ||
|
|
ef53643368 | ||
|
|
41d372da5f | ||
|
|
aa4ba06be0 | ||
|
|
aa92623d7c | ||
|
|
b13523ca5e | ||
|
|
522c698f6c | ||
|
|
b1fe1d9d47 | ||
|
|
25a85adf9e | ||
|
|
54c58d6ee1 | ||
|
|
52615d1646 | ||
|
|
2cd73748bb | ||
|
|
e23cb64f32 | ||
|
|
c639499fbc | ||
|
|
bd97df6f7b | ||
|
|
e211426c1a | ||
|
|
dafaf09011 | ||
|
|
97b8f7016d | ||
|
|
3247a5f7d0 | ||
|
|
57c88cf773 | ||
|
|
329734b332 | ||
|
|
c622781003 | ||
|
|
e89f22cd8c | ||
|
|
6db7255ed3 | ||
|
|
7a37ac18ac | ||
|
|
ca9a251176 | ||
|
|
798d12c16f | ||
|
|
124b1ff5dd | ||
|
|
a5d63d6c96 | ||
|
|
956bf841b3 | ||
|
|
e685304616 | ||
|
|
abbd23e332 | ||
|
|
37d39503bd | ||
|
|
8055572f19 | ||
|
|
7383a145b4 | ||
|
|
1ab009544f | ||
|
|
fb9e5c3d49 | ||
|
|
32232cb604 | ||
|
|
bd5f7bcad0 | ||
|
|
8e5d515e4c | ||
|
|
abf98ee5e7 | ||
|
|
61a9a453f4 | ||
|
|
3dd371161b | ||
|
|
88af20071b | ||
|
|
514b0108a5 | ||
|
|
8c2729493d | ||
|
|
47e968ddf9 | ||
|
|
4d5615f90d | ||
|
|
8283695735 | ||
|
|
8432eef4cf | ||
|
|
e0407759d4 | ||
|
|
2eae8d9e94 | ||
|
|
6efc39f902 | ||
|
|
0a708b79f0 | ||
|
|
36e4725565 | ||
|
|
5029618235 | ||
|
|
1595d987ed | ||
|
|
35cec2a64c | ||
|
|
6ee54646a8 | ||
|
|
3deaa814a4 | ||
|
|
4c458aeeac | ||
|
|
a99227d2ef | ||
|
|
10c95a0dee | ||
|
|
3094503b17 | ||
|
|
0e7944bd37 | ||
|
|
83f57ad01d | ||
|
|
e05348206e | ||
|
|
f4e4130cab | ||
|
|
0817b16615 | ||
|
|
e16fc88e81 | ||
|
|
f3b10f07b1 | ||
|
|
e191fc8d26 | ||
|
|
8052475e40 | ||
|
|
0cc7c8e7b9 | ||
|
|
9b5b625680 | ||
|
|
5d06003895 | ||
|
|
061543a191 | ||
|
|
c073cc65a7 | ||
|
|
5b9af90590 | ||
|
|
61ef48d446 | ||
|
|
331997e1e9 | ||
|
|
a4b6b2d6c8 | ||
|
|
140249aca8 | ||
|
|
6719e1b4f1 | ||
|
|
6bf572a01a | ||
|
|
b74724084e | ||
|
|
580c06686a | ||
|
|
235ab92413 | ||
|
|
4b58de936c | ||
|
|
611f59941f | ||
|
|
8db1cff376 | ||
|
|
6cb4ad95a7 | ||
|
|
5e9db85f86 | ||
|
|
11c06ec81e | ||
|
|
551a042582 | ||
|
|
eb0ab251d5 | ||
|
|
19e2d1c03b | ||
|
|
71066b6d83 | ||
|
|
6f11895f70 | ||
|
|
909b4f03a0 | ||
|
|
48e39fa4f9 | ||
|
|
b20738061e | ||
|
|
808cda3277 | ||
|
|
42c7936f40 | ||
|
|
dacded0e7a | ||
|
|
b2cf624380 | ||
|
|
5faf6aa301 | ||
|
|
b66eb35abb | ||
|
|
ee8636ec54 | ||
|
|
a6d3ffb016 | ||
|
|
04a5d121a8 | ||
|
|
a70c5f6fc3 | ||
|
|
6dc8cc78a2 | ||
|
|
78db1ace6d | ||
|
|
158125c3d0 | ||
|
|
2db501d36d |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -7,4 +7,6 @@ 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
214
LICENSE
@@ -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.
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
账号: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")
|
||||
|
||||
|
||||
## 👨💻简介
|
||||
@@ -52,6 +53,3 @@
|
||||
<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>
|
||||
|
||||
### 🪐接口文档
|
||||
[点击这里进入更多更详细文档。](https://www.likeadmin.cn "点击这里进入更多更详细文档。")
|
||||
@@ -1,4 +0,0 @@
|
||||
NODE_ENV = 'development'
|
||||
|
||||
# 请求域名
|
||||
VITE_APP_BASE_URL='https://likeadmin-java.yixiangonline.com'
|
||||
4
admin/.env.development.example
Normal file
4
admin/.env.development.example
Normal file
@@ -0,0 +1,4 @@
|
||||
NODE_ENV = 'development'
|
||||
|
||||
# 请求域名
|
||||
VITE_APP_BASE_URL=''
|
||||
3
admin/.gitignore
vendored
3
admin/.gitignore
vendored
@@ -30,3 +30,6 @@ components.d.ts
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# .env
|
||||
.env.development
|
||||
.env.production
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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' })
|
||||
}
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ import request from '@/utils/request'
|
||||
|
||||
// 微信开发平台配置保存
|
||||
export function setWxDevConfig(params: any) {
|
||||
return request.post({ url: '/channel/wx/save', params })
|
||||
return request.post({ url: '/channel/op/save', params })
|
||||
}
|
||||
|
||||
// 微信开发平台配置详情
|
||||
export function getWxDevConfig() {
|
||||
return request.get({ url: '/channel/wx/detail' })
|
||||
return request.get({ url: '/channel/op/detail' })
|
||||
}
|
||||
@@ -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 })
|
||||
}
|
||||
|
||||
@@ -14,3 +14,33 @@ 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 })
|
||||
}
|
||||
|
||||
// 获取登录日志列表
|
||||
export function loginLogLists(params: any) {
|
||||
return request.get({ url: '/system/log/login', params })
|
||||
}
|
||||
|
||||
@@ -10,6 +10,15 @@ export function dataTable(params: any) {
|
||||
return request.get({ url: '/gen/db', params })
|
||||
}
|
||||
|
||||
// 数据表所有列表接口
|
||||
export function dataTableAll() {
|
||||
return request.get({ url: '/gen/dbAll' })
|
||||
}
|
||||
|
||||
//表名查字段
|
||||
export function dataTableToColumn(params: any) {
|
||||
return request.get({ url: '/gen/dbColumn', params })
|
||||
}
|
||||
//选择要生成代码的数据表
|
||||
export function selectTable(params: any) {
|
||||
return request.post(
|
||||
|
||||
@@ -6,6 +6,11 @@ export function login(params: Record<string, any>) {
|
||||
return request.post({ url: '/system/login', params: { ...params, terminal: config.terminal } })
|
||||
}
|
||||
|
||||
// 登录
|
||||
export function loginCaptcha() {
|
||||
return request.get({ url: '/system/captcha' })
|
||||
}
|
||||
|
||||
// 退出登录
|
||||
export function logout() {
|
||||
return request.post({ url: '/system/logout' })
|
||||
|
||||
BIN
admin/src/assets/images/no_perms.png
Normal file
BIN
admin/src/assets/images/no_perms.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -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') {
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
/>
|
||||
<material-picker
|
||||
ref="materialPickerRef"
|
||||
:type="fileType"
|
||||
:limit="-1"
|
||||
hidden-upload
|
||||
@change="imageSelectChange"
|
||||
@change="selectChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -42,9 +43,7 @@ const props = withDefaults(
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -102,6 +109,9 @@ const handleCreated = (editor: any) => {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.w-e-full-screen-container {
|
||||
z-index: 999;
|
||||
}
|
||||
.w-e-text-container [data-slate-editor] ul {
|
||||
list-style: disc;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
@@ -241,21 +260,25 @@
|
||||
<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
|
||||
@@ -289,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"
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const config = {
|
||||
terminal: 1, //终端
|
||||
title: '后台管理系统', //网站默认标题
|
||||
version: '1.2.0', //版本号
|
||||
baseUrl: `${import.meta.env.VITE_APP_BASE_URL}/`, //请求接口域名
|
||||
version: '1.4.0', //版本号
|
||||
baseUrl: `${import.meta.env.VITE_APP_BASE_URL || ''}/`, //请求接口域名
|
||||
urlPrefix: 'api', //请求默认前缀
|
||||
timeout: 10 * 1000 //请求超时时长
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
const defaultSetting = {
|
||||
showCrumb: true, // 是否显示面包屑
|
||||
showLogo: true, // 是否显示logo
|
||||
isUniqueOpened: false, //只展开一个一级菜单
|
||||
sideWidth: 200, //侧边栏宽度
|
||||
sideTheme: 'light', //侧边栏主题
|
||||
sideDarkColor: '#1d2124', //侧边栏深色主题颜色
|
||||
|
||||
@@ -22,6 +22,7 @@ export enum RequestCodeEnum {
|
||||
LOGIN_DISABLE_ERROR = 331, //登陆账号已被禁用
|
||||
TOKEN_EMPTY = 332, // TOKEN参数为空
|
||||
TOKEN_INVALID = 333, // TOKEN参数无效
|
||||
VERIFICATION_CODE_ERROR = 334, // 验证码错误
|
||||
NO_PERMISSTION = 403, //无相关权限
|
||||
REQUEST_404_ERROR = 404, //请求接口不存在
|
||||
SYSTEM_ERROR = 500 //系统错误
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -101,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
|
||||
@@ -136,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)
|
||||
|
||||
@@ -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
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -6,5 +6,6 @@ import './styles/index.scss'
|
||||
import 'virtual:svg-icons-register'
|
||||
|
||||
const app = createApp(App)
|
||||
console.log(app)
|
||||
app.use(install)
|
||||
app.mount('#app')
|
||||
|
||||
@@ -26,7 +26,10 @@ router.beforeEach(async (to, from, next) => {
|
||||
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) {
|
||||
@@ -44,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
|
||||
}
|
||||
@@ -71,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 } })
|
||||
}
|
||||
|
||||
@@ -28,12 +28,19 @@ const useUserStore = defineStore({
|
||||
}),
|
||||
getters: {},
|
||||
actions: {
|
||||
resetState() {
|
||||
this.token = ''
|
||||
this.userInfo = {}
|
||||
this.perms = []
|
||||
},
|
||||
login(playload: any) {
|
||||
const { account, password } = playload
|
||||
const { account, password, code, uuid } = playload
|
||||
return new Promise((resolve, reject) => {
|
||||
login({
|
||||
username: account,
|
||||
password: password
|
||||
password,
|
||||
code,
|
||||
uuid
|
||||
})
|
||||
.then((data) => {
|
||||
this.token = data.token
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export function getToken() {
|
||||
export function clearAuthInfo() {
|
||||
const userStore = useUserStore()
|
||||
const tabsStore = useTabsStore()
|
||||
userStore.$reset()
|
||||
userStore.resetState()
|
||||
tabsStore.$reset()
|
||||
cache.remove(TOKEN_KEY)
|
||||
resetRouter()
|
||||
|
||||
@@ -72,10 +72,9 @@ export class Axios {
|
||||
}
|
||||
|
||||
if (err.code == AxiosError.ECONNABORTED || err.code == AxiosError.ERR_NETWORK) {
|
||||
setTimeout(() => {
|
||||
console.log(err)
|
||||
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请求
|
||||
|
||||
@@ -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 (
|
||||
@@ -69,6 +69,7 @@ const axiosHooks: AxiosHooks = {
|
||||
case RequestCodeEnum.NO_PERMISSTION:
|
||||
case RequestCodeEnum.FAILED:
|
||||
case RequestCodeEnum.SYSTEM_ERROR:
|
||||
case RequestCodeEnum.VERIFICATION_CODE_ERROR:
|
||||
msg && feedback.msgError(msg)
|
||||
return Promise.reject(data)
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -34,6 +34,25 @@
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code">
|
||||
<div class="flex items-center">
|
||||
<el-input
|
||||
v-model="formData.code"
|
||||
placeholder="请输入验证码"
|
||||
@keyup.enter="handleLogin"
|
||||
>
|
||||
<template #prepend>
|
||||
<icon name="local-icon-anquan" />
|
||||
</template>
|
||||
</el-input>
|
||||
<div
|
||||
class="ml-4 w-[100px] flex-none cursor-pointer"
|
||||
@click="getLoginCaptcha"
|
||||
>
|
||||
<img class="w-full" :src="codeImg" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="mb-5">
|
||||
<el-checkbox v-model="remAccount" label="记住账号"></el-checkbox>
|
||||
@@ -58,6 +77,7 @@ import cache from '@/utils/cache'
|
||||
import { ACCOUNT_KEY } from '@/enums/cacheEnums'
|
||||
import { PageEnum } from '@/enums/pageEnum'
|
||||
import { useLockFn } from '@/hooks/useLockFn'
|
||||
import { loginCaptcha } from '@/api/user'
|
||||
const passwordRef = shallowRef<InputInstance>()
|
||||
const formRef = shallowRef<FormInstance>()
|
||||
const appStore = useAppStore()
|
||||
@@ -66,9 +86,12 @@ const route = useRoute()
|
||||
const router = useRouter()
|
||||
const remAccount = ref(false)
|
||||
const config = computed(() => appStore.config)
|
||||
const codeImg = ref()
|
||||
const formData = reactive({
|
||||
account: '',
|
||||
password: ''
|
||||
password: '',
|
||||
code: '',
|
||||
uuid: ''
|
||||
})
|
||||
const rules = {
|
||||
account: [
|
||||
@@ -84,8 +107,21 @@ const rules = {
|
||||
message: '请输入密码',
|
||||
trigger: ['blur']
|
||||
}
|
||||
],
|
||||
code: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入验证码',
|
||||
trigger: ['blur']
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const getLoginCaptcha = async () => {
|
||||
const data = await loginCaptcha()
|
||||
formData.uuid = data.uuid
|
||||
codeImg.value = data.img
|
||||
}
|
||||
// 回车按键监听
|
||||
const handleEnter = () => {
|
||||
if (!formData.password) {
|
||||
@@ -99,9 +135,13 @@ const handleLogin = async () => {
|
||||
// 记住账号,缓存
|
||||
cache.set(ACCOUNT_KEY, {
|
||||
remember: remAccount.value,
|
||||
account: formData.account
|
||||
account: remAccount.value ? formData.account : ''
|
||||
})
|
||||
await userStore.login(formData)
|
||||
try {
|
||||
await userStore.login(formData)
|
||||
} catch (error) {
|
||||
getLoginCaptcha()
|
||||
}
|
||||
const {
|
||||
query: { redirect }
|
||||
} = route
|
||||
@@ -112,6 +152,7 @@ const { isLock, lockFn: lockLogin } = useLockFn(handleLogin)
|
||||
|
||||
onMounted(() => {
|
||||
const value = cache.get(ACCOUNT_KEY)
|
||||
getLoginCaptcha()
|
||||
if (value?.remember) {
|
||||
remAccount.value = value.remember
|
||||
formData.account = value.account
|
||||
@@ -125,6 +166,9 @@ onMounted(() => {
|
||||
@apply min-h-screen bg-no-repeat bg-center bg-cover;
|
||||
.login-card {
|
||||
height: 400px;
|
||||
:deep(.el-input-group__prepend) {
|
||||
padding: 0 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -81,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>
|
||||
|
||||
@@ -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">
|
||||
@@ -89,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
|
||||
}
|
||||
|
||||
@@ -44,6 +44,12 @@ export const rules = reactive<FormRules>({
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: ['blur', 'change']
|
||||
},
|
||||
{
|
||||
pattern:
|
||||
/(http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/,
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
:title="popupTitle"
|
||||
:async="true"
|
||||
width="500px"
|
||||
:clickModalClose="true"
|
||||
@confirm="handleSubmit"
|
||||
@close="handleClose"
|
||||
>
|
||||
@@ -72,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="启用状态">
|
||||
@@ -172,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)
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
<el-card class="!border-none" shadow="never">
|
||||
<el-alert
|
||||
type="warning"
|
||||
title="温馨提示:填写微信开放平台开发配置,请前往微信开放平台创建应用并完成认证;APP应用配置主要用于APP微信登录和微信支付"
|
||||
title="温馨提示:填写微信开放平台开发配置,请前往微信开放平台创建应用并完成认证;网站应用配置主要用于网站微信登录和微信支付"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
</el-card>
|
||||
<el-form ref="formRef" :model="formData" label-width="160px">
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div class="font-medium mb-7">APP应用</div>
|
||||
<div class="font-medium mb-7">网站应用</div>
|
||||
<el-form-item label="AppID" prop="appId">
|
||||
<div class="w-80">
|
||||
<el-input v-model="formData.appId" placeholder="请输入AppID" />
|
||||
@@ -23,20 +23,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div class="form-tips">
|
||||
小程序账号登录微信公众平台,点击开发>开发设置->开发者ID,设置AppID和AppSecret
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
</el-form>
|
||||
<footer-btns v-perms="['channel:wx:save']">
|
||||
<footer-btns v-perms="['channel:op:save']">
|
||||
<el-button type="primary" @click="handelSave">保存</el-button>
|
||||
</footer-btns>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup name="wxDevConfig">
|
||||
import { getWxDevConfig, setWxDevConfig } from '@/api/channel/wx_dev'
|
||||
import { getWxDevConfig, setWxDevConfig } from '@/api/channel/wx_op'
|
||||
import feedback from '@/utils/feedback'
|
||||
|
||||
const formData = reactive({
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
:is="widgets[widget?.name]?.attr"
|
||||
:content="widget?.content"
|
||||
:styles="widget?.styles"
|
||||
:type="type"
|
||||
/>
|
||||
</keep-alive>
|
||||
</div>
|
||||
@@ -23,6 +24,10 @@ const props = defineProps({
|
||||
widget: {
|
||||
type: Object as PropType<Record<string, any>>,
|
||||
default: () => ({})
|
||||
},
|
||||
type: {
|
||||
type: String as PropType<'mobile' | 'pc'>,
|
||||
default: 'mobile'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
67
admin/src/views/decoration/component/pages/preview-pc.vue
Normal file
67
admin/src/views/decoration/component/pages/preview-pc.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div class="pages-preview">
|
||||
<div
|
||||
v-for="(widget, index) in pageData"
|
||||
:key="widget.id"
|
||||
class="relative"
|
||||
:class="{
|
||||
'cursor-pointer': !widget?.disabled
|
||||
}"
|
||||
@click="handleClick(widget, index)"
|
||||
>
|
||||
<div
|
||||
class="absolute w-full h-full z-[100] border-dashed"
|
||||
:class="{
|
||||
select: index == modelValue,
|
||||
'border-[#dcdfe6] border-2': !widget?.disabled
|
||||
}"
|
||||
:style="widget.styles"
|
||||
></div>
|
||||
<slot>
|
||||
<component
|
||||
:is="widgets[widget?.name]?.content"
|
||||
:content="widget.content"
|
||||
:styles="widget.styles"
|
||||
:key="widget.id"
|
||||
/>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import widgets from '../widgets'
|
||||
import type { PropType } from 'vue'
|
||||
|
||||
defineProps({
|
||||
pageData: {
|
||||
type: Array as PropType<any[]>,
|
||||
default: () => []
|
||||
},
|
||||
modelValue: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'update:modelValue', value: number): void
|
||||
}>()
|
||||
|
||||
const handleClick = (widget: any, index: number) => {
|
||||
if (widget.disabled) return
|
||||
emit('update:modelValue', index)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pages-preview {
|
||||
width: 460px;
|
||||
height: 360px;
|
||||
background: url(../../image/pc_index.png);
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
.select {
|
||||
@apply border-primary border-solid;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -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,44 @@
|
||||
<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-if="type == 'mobile'"
|
||||
v-model="item.link"
|
||||
/>
|
||||
<el-input
|
||||
v-if="type == 'pc'"
|
||||
placeholder="请输入链接"
|
||||
v-model="item.link.path"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</del-wrap>
|
||||
</template>
|
||||
</draggable>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="content.data?.length < limit">
|
||||
@@ -44,6 +60,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({
|
||||
@@ -54,6 +71,10 @@ const props = defineProps({
|
||||
styles: {
|
||||
type: Object as PropType<OptionsType['styles']>,
|
||||
default: () => ({})
|
||||
},
|
||||
type: {
|
||||
type: String as PropType<'mobile' | 'pc'>,
|
||||
default: 'mobile'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
<template>
|
||||
<div class="banner">
|
||||
<div class="banner-image">
|
||||
<decoration-img width="100%" height="170px" :src="getImage" fit="contain" />
|
||||
<div class="banner" :style="styles">
|
||||
<div class="banner-image w-full h-full">
|
||||
<decoration-img
|
||||
width="100%"
|
||||
:height="styles.height || height"
|
||||
:src="getImage"
|
||||
fit="contain"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -18,6 +23,10 @@ const props = defineProps({
|
||||
styles: {
|
||||
type: Object as PropType<OptionsType['styles']>,
|
||||
default: () => ({})
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '170px'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -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({
|
||||
|
||||
BIN
admin/src/views/decoration/image/pc_index.png
Normal file
BIN
admin/src/views/decoration/image/pc_index.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 516 KiB |
@@ -47,7 +47,7 @@ const menus: Record<
|
||||
[pagesTypeEnum.HOME]: {
|
||||
id: 1,
|
||||
pageType: 1,
|
||||
name: '商城首页',
|
||||
name: '首页装修',
|
||||
pageData: generatePageData(['search', 'banner', 'nav', 'news'])
|
||||
},
|
||||
[pagesTypeEnum.USER]: {
|
||||
|
||||
90
admin/src/views/decoration/pc.vue
Normal file
90
admin/src/views/decoration/pc.vue
Normal file
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<div class="decoration-pages min-w-[1100px]">
|
||||
<el-card shadow="never" class="!border-none flex-1 flex" :body-style="{ flex: 1 }">
|
||||
<div class="flex h-full items-start">
|
||||
<Menu v-model="activeMenu" :menus="menus" />
|
||||
<preview-pc class="mx-4" v-model="selectWidgetIndex" :pageData="getPageData" />
|
||||
<attr-setting class="flex-1" :widget="getSelectWidget" type="pc" />
|
||||
</div>
|
||||
</el-card>
|
||||
<footer-btns class="mt-4" :fixed="false" v-perms="['decorate:pages:save']">
|
||||
<el-button type="primary" @click="setData">保存</el-button>
|
||||
</footer-btns>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup name="decorationPc">
|
||||
import Menu from './component/pages/menu.vue'
|
||||
import PreviewPc from './component/pages/preview-pc.vue'
|
||||
import AttrSetting from './component/pages/attr-setting.vue'
|
||||
import widgets from './component/widgets'
|
||||
import { getDecoratePages, setDecoratePages } from '@/api/decoration'
|
||||
import { getNonDuplicateID } from '@/utils/util'
|
||||
enum pagesTypeEnum {
|
||||
HOME = '4'
|
||||
}
|
||||
|
||||
const generatePageData = (widgetNames: string[]) => {
|
||||
return widgetNames.map((widgetName) => {
|
||||
const options = {
|
||||
id: getNonDuplicateID(),
|
||||
...(widgets[widgetName]?.options() || {})
|
||||
}
|
||||
return options
|
||||
})
|
||||
}
|
||||
|
||||
const menus: Record<
|
||||
string,
|
||||
{
|
||||
id: number
|
||||
name: string
|
||||
pageData: any[]
|
||||
}
|
||||
> = reactive({
|
||||
[pagesTypeEnum.HOME]: {
|
||||
id: 4,
|
||||
pageType: 4,
|
||||
name: 'pc首页装修',
|
||||
pageData: []
|
||||
}
|
||||
})
|
||||
|
||||
const activeMenu = ref('4')
|
||||
const selectWidgetIndex = ref(0)
|
||||
const getPageData = computed(() => {
|
||||
return menus[activeMenu.value]?.pageData ?? []
|
||||
})
|
||||
const getSelectWidget = computed(() => {
|
||||
return menus[activeMenu.value]?.pageData[selectWidgetIndex.value] ?? ''
|
||||
})
|
||||
|
||||
const getData = async () => {
|
||||
const data = await getDecoratePages({ id: activeMenu.value })
|
||||
menus[String(data.id)].pageData = JSON.parse(data.pageData)
|
||||
selectWidgetIndex.value = getPageData.value.findIndex((item) => !item.disabled)
|
||||
}
|
||||
|
||||
const setData = async () => {
|
||||
await setDecoratePages({
|
||||
...menus[activeMenu.value],
|
||||
pageData: JSON.stringify(menus[activeMenu.value].pageData)
|
||||
})
|
||||
getData()
|
||||
}
|
||||
watch(
|
||||
activeMenu,
|
||||
() => {
|
||||
selectWidgetIndex.value = getPageData.value.findIndex((item) => !item.disabled)
|
||||
getData()
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.decoration-pages {
|
||||
min-height: calc(100vh - var(--navbar-height) - 80px);
|
||||
@apply flex flex-col;
|
||||
}
|
||||
</style>
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
ref="formRef"
|
||||
class="ls-form"
|
||||
:model="formData"
|
||||
label-width="100px"
|
||||
label-width="130px"
|
||||
:rules="rules"
|
||||
>
|
||||
<el-tabs v-model="activeName">
|
||||
@@ -218,11 +218,50 @@
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="生成方式" prop="gen.genType">
|
||||
<el-radio-group v-model="formData.gen.genType">
|
||||
<el-radio :label="GenType.ZIP">压缩包下载</el-radio>
|
||||
<el-radio :label="GenType.CUSTOM_PATH">自定义路径</el-radio>
|
||||
</el-radio-group>
|
||||
<div>
|
||||
<el-radio-group v-model="formData.gen.genType">
|
||||
<el-radio :label="GenType.ZIP">压缩包下载</el-radio>
|
||||
<el-radio :label="GenType.CUSTOM_PATH">自定义路径</el-radio>
|
||||
</el-radio-group>
|
||||
<div class="form-tips">压縮包下载方式暂不支持自动构建菜单权限</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单构建" prop="gen.menuStatus" required>
|
||||
<div>
|
||||
<el-radio-group v-model="formData.gen.menuStatus">
|
||||
<el-radio :label="1">自动构建</el-radio>
|
||||
<el-radio :label="0">手动添加</el-radio>
|
||||
</el-radio-group>
|
||||
<div class="form-tips">
|
||||
自动构建:自动执行生成菜单sql。 手动添加:自行添加菜单
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="父级菜单" prop="gen.menuPid">
|
||||
<el-tree-select
|
||||
class="w-80"
|
||||
v-model="formData.gen.menuPid"
|
||||
:data="optionsData.menu"
|
||||
clearable
|
||||
node-key="id"
|
||||
:props="{
|
||||
label: 'menuName'
|
||||
}"
|
||||
default-expand-all
|
||||
placeholder="请选择父级菜单"
|
||||
check-strictly
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="菜单名称" prop="gen.menuName">
|
||||
<div class="w-80">
|
||||
<el-input
|
||||
v-model="formData.gen.menuName"
|
||||
placeholder="请输入菜单名称"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item
|
||||
v-if="formData.gen.genType == GenType.CUSTOM_PATH"
|
||||
label="自定义路径"
|
||||
@@ -273,6 +312,48 @@
|
||||
</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
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<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
|
||||
:loading="columnLoading"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in tableColumn"
|
||||
:key="item.id"
|
||||
:value="item.columnName"
|
||||
:label="`${item.columnName}:${item.columnComment}`"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="关联表主键 " prop="gen.subTableFr">
|
||||
<el-select class="w-80" v-model="formData.gen.subTableFr" 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-tab-pane>
|
||||
</el-tabs>
|
||||
</el-form>
|
||||
</el-card>
|
||||
@@ -283,7 +364,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="tableEdit">
|
||||
import { generateEdit, tableDetail } from '@/api/tools/code'
|
||||
import { dataTableAll, generateEdit, tableDetail, dataTableToColumn } from '@/api/tools/code'
|
||||
import { dictTypeAll } from '@/api/setting/dict'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import feedback from '@/utils/feedback'
|
||||
@@ -322,9 +403,13 @@ const formData = reactive({
|
||||
moduleName: '',
|
||||
subTableFk: '',
|
||||
subTableName: '',
|
||||
subTableFr: '',
|
||||
treeParent: '',
|
||||
treePrimary: '',
|
||||
treeName: ''
|
||||
treeName: '',
|
||||
menuName: '',
|
||||
menuStatus: 0,
|
||||
menuPid: 0
|
||||
}
|
||||
})
|
||||
|
||||
@@ -345,15 +430,18 @@ const getDetails = async () => {
|
||||
const data = await tableDetail({
|
||||
id: route.query.id
|
||||
})
|
||||
|
||||
Object.keys(formData).forEach((key) => {
|
||||
//@ts-ignore
|
||||
formData[key] = data[key]
|
||||
})
|
||||
getTableColumn()
|
||||
}
|
||||
|
||||
const { optionsData } = useDictOptions<{
|
||||
dictType: any[]
|
||||
menu: any[]
|
||||
dataTable: any[]
|
||||
}>({
|
||||
dictType: {
|
||||
api: dictTypeAll
|
||||
@@ -361,13 +449,29 @@ const { optionsData } = useDictOptions<{
|
||||
menu: {
|
||||
api: menuLists,
|
||||
transformData(data: any) {
|
||||
const menu = { id: 0, name: '顶级', children: [] }
|
||||
const menu = { id: 0, menuName: '顶级', children: [] }
|
||||
menu.children = data
|
||||
return menu
|
||||
return [menu]
|
||||
}
|
||||
},
|
||||
dataTable: {
|
||||
api: dataTableAll
|
||||
}
|
||||
})
|
||||
|
||||
const columnLoading = ref(false)
|
||||
const tableColumn = ref<any[]>([])
|
||||
const getTableColumn = async () => {
|
||||
columnLoading.value = true
|
||||
const res = await dataTableToColumn({ tableName: formData.gen.subTableName })
|
||||
columnLoading.value = false
|
||||
tableColumn.value = res
|
||||
}
|
||||
|
||||
const handleTableChange = () => {
|
||||
formData.gen.subTableFk = ''
|
||||
getTableColumn()
|
||||
}
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
await formRef.value?.validate()
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<el-form class="mb-[-16px]" :model="formData" inline>
|
||||
<el-form-item label="表名称">
|
||||
<el-input
|
||||
class="w-56"
|
||||
class="w-[280px]"
|
||||
v-model="formData.tableName"
|
||||
clearable
|
||||
@keyup.enter="resetPage"
|
||||
@@ -12,7 +12,7 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="表描述">
|
||||
<el-input
|
||||
class="w-56"
|
||||
class="w-[280px]"
|
||||
v-model="formData.tableComment"
|
||||
clearable
|
||||
@keyup.enter="resetPage"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<el-form class="ls-form" :model="formData" inline>
|
||||
<el-form-item label="表名称">
|
||||
<el-input
|
||||
class="w-56"
|
||||
class="w-[280px]"
|
||||
v-model="formData.tableName"
|
||||
clearable
|
||||
@keyup.enter="resetPage"
|
||||
@@ -22,7 +22,7 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="表描述">
|
||||
<el-input
|
||||
class="w-56"
|
||||
class="w-[280px]"
|
||||
v-model="formData.tableComment"
|
||||
clearable
|
||||
@keyup.enter="resetPage"
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
@@ -42,11 +42,9 @@
|
||||
/>
|
||||
</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>
|
||||
@@ -76,7 +74,8 @@ const formData = reactive({
|
||||
smsNotice: {
|
||||
status: 0,
|
||||
templateId: '',
|
||||
content: ''
|
||||
content: '',
|
||||
tips: []
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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 = () => {
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -166,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>
|
||||
@@ -224,7 +224,7 @@ const formData = reactive({
|
||||
//路由参数
|
||||
params: '',
|
||||
//是否缓存 0=否, 1=是
|
||||
isCache: 1,
|
||||
isCache: 0,
|
||||
//是否显示 0=否, 1=是
|
||||
isShow: 1,
|
||||
//是否禁用 0=否, 1=是
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
<el-table-column label="操作" width="160" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
v-if="row.menuType !== MenuEnum.BUTTON"
|
||||
v-perms="['system:menu:add']"
|
||||
type="primary"
|
||||
link
|
||||
|
||||
@@ -31,7 +31,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">数值越大越排前</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<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>
|
||||
@@ -27,7 +27,13 @@
|
||||
<el-table size="large" :data="formData.list">
|
||||
<el-table-column label="关键词" prop="describe" min-width="200">
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.name" clearable maxlength="30" />
|
||||
<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="80">
|
||||
@@ -92,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)
|
||||
})
|
||||
|
||||
// 获取登录注册数据
|
||||
@@ -110,7 +116,7 @@ const getData = async () => {
|
||||
|
||||
const handleAdd = () => {
|
||||
formData.list.push({
|
||||
name: '关键字',
|
||||
name: '',
|
||||
sort: 0
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<el-form class="ls-form" :model="formData" inline>
|
||||
<el-form-item label="管理员">
|
||||
<el-input
|
||||
class="w-56"
|
||||
class="w-[280px]"
|
||||
placeholder="请输入"
|
||||
v-model="formData.username"
|
||||
clearable
|
||||
@@ -14,7 +14,7 @@
|
||||
</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"
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
<el-form-item label="来源IP">
|
||||
<el-input
|
||||
class="w-56"
|
||||
class="w-[280px]"
|
||||
placeholder="请输入"
|
||||
v-model="formData.ip"
|
||||
clearable
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
<el-form-item label="访问链接">
|
||||
<el-input
|
||||
class="w-56"
|
||||
class="w-[280px]"
|
||||
placeholder="请输入"
|
||||
v-model="formData.url"
|
||||
clearable
|
||||
|
||||
81
admin/src/views/setting/system/login_log.vue
Normal file
81
admin/src/views/setting/system/login_log.vue
Normal file
@@ -0,0 +1,81 @@
|
||||
<!-- 系统日志 -->
|
||||
<template>
|
||||
<div class="login-log">
|
||||
<el-card class="!border-none" shadow="never">
|
||||
<el-form class="ls-form" :model="formData" inline>
|
||||
<el-form-item label="用户名称">
|
||||
<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-[280px]" v-model="formData.status" placeholder="请选择">
|
||||
<el-option label="全部" value="" />
|
||||
<el-option label="失败" :value="0" />
|
||||
<el-option label="成功" :value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="登录时间">
|
||||
<daterange-picker
|
||||
v-model:startTime="formData.startTime"
|
||||
v-model:endTime="formData.endTime"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="resetPage">查询</el-button>
|
||||
<el-button @click="resetParams">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="!border-none mt-4" shadow="never" v-loading="pager.loading">
|
||||
<div>
|
||||
<el-table :data="pager.lists" size="large">
|
||||
<el-table-column label="用户名称" prop="username" min-width="120" />
|
||||
<el-table-column label="登录地址" prop="ip" min-width="120" />
|
||||
<el-table-column label="浏览器" prop="browser" min-width="120" />
|
||||
<el-table-column label="摱作系統" prop="os" min-width="120" />
|
||||
<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 == 0" type="danger">失败</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="登录时间" prop="createTime" min-width="180" />
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="flex mt-4 justify-end">
|
||||
<pagination v-model="pager" @change="getLists" />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="journal">
|
||||
import { loginLogLists } from '@/api/setting/system'
|
||||
import { usePaging } from '@/hooks/usePaging'
|
||||
|
||||
// 查询表单
|
||||
const formData = ref({
|
||||
username: '',
|
||||
status: '',
|
||||
startTime: '',
|
||||
endTime: ''
|
||||
})
|
||||
|
||||
const { pager, getLists, resetParams, resetPage } = usePaging({
|
||||
fetchFun: loginLogLists,
|
||||
params: formData.value
|
||||
})
|
||||
|
||||
getLists()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
142
admin/src/views/setting/system/scheduled_task/edit.vue
Normal file
142
admin/src/views/setting/system/scheduled_task/edit.vue
Normal 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>
|
||||
111
admin/src/views/setting/system/scheduled_task/index.vue
Normal file
111
admin/src/views/setting/system/scheduled_task/index.vue
Normal 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>
|
||||
@@ -84,7 +84,9 @@ const handleDelete = (index: number) => {
|
||||
|
||||
// 设置备案信息
|
||||
const handleSubmit = async () => {
|
||||
await setCopyright(formData.value)
|
||||
await setCopyright({
|
||||
list: formData.value
|
||||
})
|
||||
feedback.msgSuccess('操作成功')
|
||||
getData()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -52,6 +52,44 @@
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
<el-card shadow="never" class="!border-none mt-4">
|
||||
<div class="text-xl font-medium mb-[20px]">PC端设置</div>
|
||||
<el-form-item label="PC端LOGO" prop="pcLogo">
|
||||
<div>
|
||||
<material-picker v-model="formData.pcLogo" :limit="1" />
|
||||
<div class="form-tips">建议尺寸:120*28px,支持jpg,jpeg,png格式</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="网站标题" prop="pcTitle">
|
||||
<div class="w-80">
|
||||
<el-input
|
||||
v-model.trim="formData.pcTitle"
|
||||
placeholder="请输入PC端网站标题"
|
||||
maxlength="30"
|
||||
show-word-limit
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="网站图标" prop="pcIco">
|
||||
<div>
|
||||
<material-picker v-model="formData.pcIco" :limit="1" />
|
||||
<div class="form-tips">建议尺寸:100*100像素,支持jpg,jpeg,png格式</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="网站描述" prop="pcDesc">
|
||||
<div class="w-80">
|
||||
<el-input v-model.trim="formData.pcDesc" placeholder="请输入PC端网站描述" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="网站关键词" prop="pcKeywords">
|
||||
<div class="w-80">
|
||||
<el-input
|
||||
v-model.trim="formData.pcKeywords"
|
||||
placeholder="请输入PC端网站关键词"
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
</el-form>
|
||||
<footer-btns v-perms="['setting:website:save']">
|
||||
<el-button type="primary" @click="handleSubmit">保存</el-button>
|
||||
@@ -73,7 +111,12 @@ const formData = reactive({
|
||||
logo: '', // 网站logo
|
||||
backdrop: '', // 登录页广告图
|
||||
shopName: '',
|
||||
shopLogo: ''
|
||||
shopLogo: '',
|
||||
pcDesc: '',
|
||||
pcIco: '',
|
||||
pcKeywords: '',
|
||||
pcLogo: '',
|
||||
pcTitle: ''
|
||||
})
|
||||
|
||||
// 表单验证
|
||||
@@ -119,6 +162,27 @@ const rules = {
|
||||
message: '请选择商城LOGO',
|
||||
trigger: ['change']
|
||||
}
|
||||
],
|
||||
pcLogo: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择PC端LOGO',
|
||||
trigger: ['change']
|
||||
}
|
||||
],
|
||||
pcTitle: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入PC端网站标题',
|
||||
trigger: ['blur']
|
||||
}
|
||||
],
|
||||
pcIco: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择PC端网站图标',
|
||||
trigger: ['change']
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
63
admin/src/views/template/component/file.vue
Normal file
63
admin/src/views/template/component/file.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card header="基础使用" shadow="none" class="!border-none">
|
||||
<div class="flex flex-wrap">
|
||||
<div class="flex m-4">
|
||||
<div class="mr-4">选择图片:</div>
|
||||
<material-picker v-model="state.value1" />
|
||||
</div>
|
||||
<div class="flex m-4">
|
||||
<div class="mr-4">选择视频:</div>
|
||||
<material-picker type="video" v-model="state.value3" />
|
||||
</div>
|
||||
<div class="flex flex-1 m-4">
|
||||
<div class="mr-4">多张图片:</div>
|
||||
<div class="flex-1">
|
||||
<!-- 外层需要有足够的宽度,这样预览图和选择按钮才不会直接换行 -->
|
||||
<material-picker :limit="4" v-model="state.value2" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card header="进阶用法" shadow="none" class="!border-none mt-4">
|
||||
<div class="flex flex-wrap">
|
||||
<div class="flex m-4">
|
||||
<div class="mr-4">自定义选择器大小:</div>
|
||||
<material-picker size="60px" v-model="state.value4" />
|
||||
</div>
|
||||
<div class="flex m-4">
|
||||
<div class="mr-4">使用插槽:</div>
|
||||
<material-picker v-model="state.value5">
|
||||
<template #upload>
|
||||
<el-button>选择文件</el-button>
|
||||
</template>
|
||||
</material-picker>
|
||||
</div>
|
||||
<div class="flex m-4">
|
||||
<div class="mr-4">选出地址不带域名:</div>
|
||||
<material-picker :exclude-domain="true" v-model="state.value6" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex m-4 items-center">
|
||||
<div class="w-20 flex-none">带域名:</div>
|
||||
<el-input class="w-[500px]" :model-value="state.value5" />
|
||||
</div>
|
||||
<div class="flex m-4 items-center">
|
||||
<div class="w-20 flex-none">不带域名:</div>
|
||||
<el-input class="w-[500px]" :model-value="state.value6" />
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
const state = reactive({
|
||||
value1: '',
|
||||
value2: [],
|
||||
value3: '',
|
||||
value4: '',
|
||||
value5: '',
|
||||
value6: ''
|
||||
})
|
||||
</script>
|
||||
64
admin/src/views/template/component/icon.vue
Normal file
64
admin/src/views/template/component/icon.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card header="element-plus图标" shadow="none" class="!border-none">
|
||||
<div class="flex items-center">
|
||||
<icon class="m-4" :size="24" name="el-icon-Search" />
|
||||
<icon class="m-4" :size="24" name="el-icon-Plus" />
|
||||
<icon class="m-4" :size="24" name="el-icon-FullScreen" />
|
||||
<icon class="m-4" :size="24" name="el-icon-Setting" />
|
||||
<icon class="m-4" :size="24" name="el-icon-Warning" />
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card header="本地图标" shadow="none" class="!border-none mt-4">
|
||||
<div class="flex items-center">
|
||||
<icon class="m-4" :size="24" name="local-icon-baoxian" />
|
||||
<icon class="m-4" :size="24" name="local-icon-youhui" />
|
||||
<icon class="m-4" :size="24" name="local-icon-daiyunying" />
|
||||
<icon class="m-4" :size="24" name="local-icon-diancanshezhi" />
|
||||
<icon class="m-4" :size="24" name="local-icon-dianzifapiao" />
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card header="图标选择器" shadow="none" class="!border-none mt-4">
|
||||
<div class="flex items-center">
|
||||
<icon-picker v-model="state.value" />
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card
|
||||
header="element-plus图标库大全(点击复制图标名称)"
|
||||
shadow="none"
|
||||
class="!border-none mt-4"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<div class="flex flex-wrap">
|
||||
<div v-for="item in getElementPlusIconNames()" :key="item" class="m-1">
|
||||
<el-button v-copy="item">
|
||||
<icon :name="item" :size="20" />
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card
|
||||
header="本地图标库大全(点击复制图标名称)"
|
||||
shadow="none"
|
||||
class="!border-none mt-4"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<div class="flex flex-wrap">
|
||||
<div v-for="item in getLocalIconNames()" :key="item" class="m-1">
|
||||
<el-button v-copy="item">
|
||||
<icon :name="item" :size="20" />
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import Icon from '@/components/icon/index.vue'
|
||||
import { getElementPlusIconNames, getLocalIconNames } from '@/components/icon'
|
||||
const state = reactive({
|
||||
value: ''
|
||||
})
|
||||
</script>
|
||||
12
admin/src/views/template/component/link.vue
Normal file
12
admin/src/views/template/component/link.vue
Normal file
@@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card header="基础使用" shadow="none" class="!border-none">
|
||||
<link-picker v-model="state.value1" />
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
const state = reactive({
|
||||
value1: {}
|
||||
})
|
||||
</script>
|
||||
9
admin/src/views/template/component/overflow.vue
Normal file
9
admin/src/views/template/component/overflow.vue
Normal file
@@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card header="基础使用" shadow="none" class="!border-none">
|
||||
<overflow-tooltip class="w-20 m-4" content="超出自动打点,悬浮弹窗显示全部内容" />
|
||||
<overflow-tooltip class="w-60 m-4" content="超出自动打点,悬浮弹窗显示全部内容" />
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup></script>
|
||||
48
admin/src/views/template/component/popover_input.vue
Normal file
48
admin/src/views/template/component/popover_input.vue
Normal file
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card header="基础使用" shadow="none" class="!border-none">
|
||||
<div class="flex flex-wrap">
|
||||
<div class="m-4">
|
||||
<popover-input @confirm="onConfirm">
|
||||
<template #default>
|
||||
<el-button> 点击输入 </el-button>
|
||||
</template>
|
||||
</popover-input>
|
||||
</div>
|
||||
<div class="m-4">
|
||||
<popover-input type="number" @confirm="onConfirm">
|
||||
<template #default>
|
||||
<el-button> 输入数字 </el-button>
|
||||
</template>
|
||||
</popover-input>
|
||||
</div>
|
||||
<div class="m-4">
|
||||
<popover-input size="small" @confirm="onConfirm">
|
||||
<template #default>
|
||||
<el-button> 调整大小 </el-button>
|
||||
</template>
|
||||
</popover-input>
|
||||
</div>
|
||||
<div class="m-4">
|
||||
<popover-input :limit="20" :show-limit="true" @confirm="onConfirm">
|
||||
<template #default>
|
||||
<el-button> 限制输入长度 </el-button>
|
||||
</template>
|
||||
</popover-input>
|
||||
</div>
|
||||
<div class="m-4">
|
||||
<popover-input value="默认值" @confirm="onConfirm">
|
||||
<template #default>
|
||||
<el-button> 默认值 </el-button>
|
||||
</template>
|
||||
</popover-input>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
const onConfirm = (value: string) => {
|
||||
console.log(value)
|
||||
}
|
||||
</script>
|
||||
16
admin/src/views/template/component/rich_text.vue
Normal file
16
admin/src/views/template/component/rich_text.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card header="基础使用" shadow="none" class="!border-none">
|
||||
<editor v-model="state.value1" height="500px" />
|
||||
</el-card>
|
||||
<el-card header="简洁模式" shadow="none" class="!border-none mt-4">
|
||||
<editor v-model="state.value2" height="500px" mode="simple" />
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
const state = reactive({
|
||||
value1: '',
|
||||
value2: ''
|
||||
})
|
||||
</script>
|
||||
65
admin/src/views/template/component/upload.vue
Normal file
65
admin/src/views/template/component/upload.vue
Normal file
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card header="基础使用" shadow="none" class="!border-none">
|
||||
<div class="flex flex-wrap">
|
||||
<div class="m-4">
|
||||
<upload
|
||||
@change="onChange"
|
||||
@success="onSuccess"
|
||||
@error="onError"
|
||||
:show-progress="true"
|
||||
>
|
||||
<el-button type="primary">上传图片</el-button>
|
||||
</upload>
|
||||
</div>
|
||||
<div class="m-4">
|
||||
<upload
|
||||
type="video"
|
||||
@change="onChange"
|
||||
@success="onSuccess"
|
||||
@error="onError"
|
||||
:show-progress="true"
|
||||
>
|
||||
<el-button type="primary">上传视频</el-button>
|
||||
</upload>
|
||||
</div>
|
||||
<div class="m-4">
|
||||
<upload
|
||||
:multiple="false"
|
||||
@change="onChange"
|
||||
@success="onSuccess"
|
||||
@error="onError"
|
||||
:show-progress="true"
|
||||
>
|
||||
<el-button type="primary">取消多选</el-button>
|
||||
</upload>
|
||||
</div>
|
||||
<div class="m-4">
|
||||
<upload
|
||||
:limit="2"
|
||||
@change="onChange"
|
||||
@success="onSuccess"
|
||||
@error="onError"
|
||||
:show-progress="true"
|
||||
>
|
||||
<el-button type="primary">一次最多上传2张</el-button>
|
||||
</upload>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import Upload from '@/components/upload/index.vue'
|
||||
const onChange = (file: any) => {
|
||||
console.log('上传文件的状态发生改变', file)
|
||||
}
|
||||
|
||||
const onSuccess = (file: any) => {
|
||||
console.log('上传文件成功', file)
|
||||
}
|
||||
|
||||
const onError = (file: any) => {
|
||||
console.log('上传文件失败', file)
|
||||
}
|
||||
</script>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 84 KiB |
BIN
admin/src/views/workbench/image/oa_code.png
Normal file
BIN
admin/src/views/workbench/image/oa_code.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 33 KiB |
BIN
admin/src/views/workbench/image/service_code.png
Normal file
BIN
admin/src/views/workbench/image/service_code.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 486 KiB |
@@ -141,8 +141,8 @@ import menu_generator from './image/menu_generator.png'
|
||||
import menu_file from './image/menu_file.png'
|
||||
import menu_auth from './image/menu_auth.png'
|
||||
import menu_web from './image/menu_web.png'
|
||||
import qq_group from './image/qq_group.png'
|
||||
import customer_service from './image/customer_service.png'
|
||||
import oa_code from './image/oa_code.png'
|
||||
import service_code from './image/service_code.png'
|
||||
// 表单数据
|
||||
const workbenchData: any = reactive({
|
||||
version: {
|
||||
@@ -156,12 +156,12 @@ const workbenchData: any = reactive({
|
||||
},
|
||||
support: [
|
||||
{
|
||||
image: qq_group,
|
||||
title: '扫码进入QQ交流群',
|
||||
desc: '疑难疑点 进入QQ群'
|
||||
image: oa_code,
|
||||
title: '官方公众号',
|
||||
desc: '关注官方公众号'
|
||||
},
|
||||
{
|
||||
image: customer_service,
|
||||
image: service_code,
|
||||
title: '添加企业客服微信',
|
||||
desc: '想了解更多请添加客服'
|
||||
}
|
||||
@@ -186,7 +186,7 @@ const workbenchData: any = reactive({
|
||||
{
|
||||
name: '字典管理',
|
||||
image: menu_dict,
|
||||
url: '/setting/dict'
|
||||
url: '/dev_tools/dict'
|
||||
},
|
||||
{
|
||||
name: '代码生成器',
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
|
||||
# 请求域名
|
||||
VITE_APP_BASE_URL='https://likeadmin-java-api.yixiangonline.com'
|
||||
@@ -1 +0,0 @@
|
||||
import o from"./error.a2aa9f80.js";import{d as r,o as t,c as m,V as p}from"./@vue.cab01781.js";import"./element-plus.151049e5.js";import"./@vueuse.724ed0af.js";import"./@element-plus.92b4185f.js";import"./lodash-es.29c53eac.js";import"./dayjs.66926594.js";import"./axios.2d915936.js";import"./async-validator.fb49d0f5.js";import"./@ctrl.82a509e0.js";import"./@popperjs.36402333.js";import"./escape-html.e5dfadb9.js";import"./normalize-wheel-es.8aeb3683.js";import"./vue-router.5046cc50.js";import"./index.7d89aa28.js";import"./lodash.b68d77aa.js";import"./pinia.e85e8286.js";import"./vue-demi.bfae2336.js";import"./css-color-function.a8f9466d.js";import"./color.903ca10f.js";import"./clone.9d64bb7a.js";import"./color-convert.69e17089.js";import"./color-string.e356f5de.js";import"./color-name.e7a4e1d3.js";import"./nprogress.a96d99f2.js";import"./vue-clipboard3.91d4fd5f.js";import"./clipboard.c0a70c0c.js";import"./echarts.6ad8c478.js";import"./zrender.f91f2f01.js";import"./highlight.js.4ebdf9a4.js";import"./@highlightjs.0ab41b7b.js";const i={class:"error404"},L=r({__name:"403",setup(u){return(e,s)=>(t(),m("div",i,[p(o,{code:"403",title:"\u60A8\u7684\u8D26\u53F7\u6743\u9650\u4E0D\u8DB3\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650\uFF01","show-btn":!1})]))}});export{L as default};
|
||||
@@ -1 +0,0 @@
|
||||
import o from"./error.a2aa9f80.js";import{d as r,o as t,c as m,V as p}from"./@vue.cab01781.js";import"./element-plus.151049e5.js";import"./@vueuse.724ed0af.js";import"./@element-plus.92b4185f.js";import"./lodash-es.29c53eac.js";import"./dayjs.66926594.js";import"./axios.2d915936.js";import"./async-validator.fb49d0f5.js";import"./@ctrl.82a509e0.js";import"./@popperjs.36402333.js";import"./escape-html.e5dfadb9.js";import"./normalize-wheel-es.8aeb3683.js";import"./vue-router.5046cc50.js";import"./index.7d89aa28.js";import"./lodash.b68d77aa.js";import"./pinia.e85e8286.js";import"./vue-demi.bfae2336.js";import"./css-color-function.a8f9466d.js";import"./color.903ca10f.js";import"./clone.9d64bb7a.js";import"./color-convert.69e17089.js";import"./color-string.e356f5de.js";import"./color-name.e7a4e1d3.js";import"./nprogress.a96d99f2.js";import"./vue-clipboard3.91d4fd5f.js";import"./clipboard.c0a70c0c.js";import"./echarts.6ad8c478.js";import"./zrender.f91f2f01.js";import"./highlight.js.4ebdf9a4.js";import"./@highlightjs.0ab41b7b.js";const i={class:"error404"},L=r({__name:"404",setup(e){return(u,c)=>(t(),m("div",i,[p(o,{code:"404",title:"\u54CE\u5440\uFF0C\u51FA\u9519\u4E86\uFF01\u60A8\u8BBF\u95EE\u7684\u9875\u9762\u4E0D\u5B58\u5728\u2026"})]))}});export{L as default};
|
||||
@@ -1 +0,0 @@
|
||||
import"./add-nav.vue_vue_type_script_setup_true_lang.1804d4d1.js";import{_ as R}from"./add-nav.vue_vue_type_script_setup_true_lang.1804d4d1.js";import"./element-plus.151049e5.js";import"./@vue.cab01781.js";import"./@vueuse.724ed0af.js";import"./@element-plus.92b4185f.js";import"./lodash-es.29c53eac.js";import"./dayjs.66926594.js";import"./axios.2d915936.js";import"./async-validator.fb49d0f5.js";import"./@ctrl.82a509e0.js";import"./@popperjs.36402333.js";import"./escape-html.e5dfadb9.js";import"./normalize-wheel-es.8aeb3683.js";import"./index.b51e30da.js";import"./index.7d89aa28.js";import"./lodash.b68d77aa.js";import"./vue-router.5046cc50.js";import"./pinia.e85e8286.js";import"./vue-demi.bfae2336.js";import"./css-color-function.a8f9466d.js";import"./color.903ca10f.js";import"./clone.9d64bb7a.js";import"./color-convert.69e17089.js";import"./color-string.e356f5de.js";import"./color-name.e7a4e1d3.js";import"./nprogress.a96d99f2.js";import"./vue-clipboard3.91d4fd5f.js";import"./clipboard.c0a70c0c.js";import"./echarts.6ad8c478.js";import"./zrender.f91f2f01.js";import"./highlight.js.4ebdf9a4.js";import"./@highlightjs.0ab41b7b.js";import"./picker.39386e69.js";import"./index.c62639de.js";import"./picker.b90a9731.js";import"./index.878ae11f.js";import"./usePaging.1512f046.js";import"./vue3-video-play.05975c53.js";import"./vuedraggable.a5db575d.js";import"./vue.de4be77f.js";import"./sortablejs.cd7e2c7e.js";export{R as default};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user