feat-0330: init object
3
.browserslistrc
Normal file
@ -0,0 +1,3 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
5
.env.development
Normal file
@ -0,0 +1,5 @@
|
||||
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
|
||||
NODE_ENV = 'development'
|
||||
VUE_APP_TITLE = '悦读馆'
|
||||
# 开发环境
|
||||
VUE_APP_API_BASE_URL=http://localhost:8101/api
|
4
.env.production
Normal file
@ -0,0 +1,4 @@
|
||||
NODE_ENV = 'production'
|
||||
VUE_APP_TITLE = '悦读馆'
|
||||
#线上环境
|
||||
VUE_APP_API_BASE_URL=https://backend.xiaobaitiao.icu:443/api
|
23
.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
405
LICENSE
Normal file
@ -0,0 +1,405 @@
|
||||
<<<<<<< HEAD
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"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.
|
||||
=======
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"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.
|
||||
>>>>>>> remotes/github/main
|
827
README.md
Normal file
@ -0,0 +1,827 @@
|
||||
# 智能图书馆开源文档
|
||||
|
||||
>作者:[程序员小白条](https://luoye6.github.io/)
|
||||
>
|
||||
>[Gitee 主页](https://gitee.com/falle22222n-leaves)
|
||||
>
|
||||
>[GitHub 主页](https://github.com/luoye6)
|
||||
|
||||
Language:**[English](README_en.md)**| **[中文](README.md).**
|
||||
|
||||
## ☀️新手必读
|
||||
|
||||
+ 本项目拥有完整的API后台接口文档(文尾)(重点⭐)
|
||||
+ 项目部署视频正在录制
|
||||
+ 如果项目对您有所帮助,可以Star⭐一下,受到鼓励的我会继续加油。
|
||||
+ [项目在线演示地址](https://www.xiaobaitiao.top)
|
||||
+ [项目前端地址](https://gitee.com/falle22222n-leaves/vue_-book-manage-system)
|
||||
+ [项目后端地址](https://gitee.com/falle22222n-leaves/vue_-book-manage-system_backend)
|
||||
+ [项目部署视频](https://www.bilibili.com/video/BV1Zh4y1z7QE/?spm_id_from=333.999.0.0)
|
||||
|
||||
[](https://gitee.com/falle22222n-leaves/vue_-book-manage-system) [](https://gitee.com/falle22222n-leaves) [](https://github.com/luoye6)
|
||||
|
||||
## ☀️个人介绍
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## ☀️项目介绍
|
||||
|
||||
**AI 智能图书馆**(AI Intelligent Library)是一个利用 AI 模型和数据分析对用户所喜欢的图书进行精准推荐的系统,并且提供了 AIGC 的在线生成借阅量分析的 BI 图表功能,能够起到一个数据分析师的作用。其主要有三大使用者:用户(借阅人)、图书管理员、系统管理员。
|
||||
|
||||
> Ps:如果你想要简易和新颖,那么这个项目将会是不错的选择~
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## ☀️功能和特性
|
||||
|
||||
### 用户功能
|
||||
|
||||
1)图书查询功能:分页构造器缓解数据过大压力,后端可设置请求数防止爬虫请求数过大,服务器负载过大。模糊查询进行字段搜索。表格均**可导出 PDF 和 EXCEL**。
|
||||
|
||||
2)读者规则功能:查询现有的借阅规则,借阅规则包括:借阅编号,可借阅图书数量,可借阅天数,可借阅图书馆,过期扣费/天。
|
||||
|
||||
3)查看公告: 可以查询图书管理员发布的公告列表,**文字滑动效果**。
|
||||
|
||||
4)个人信息: 可以查看个人的借阅证编号,借阅证姓名,规则编号,状态,可以修改个人账户的密码。
|
||||
|
||||
5)借阅信息: 可以查看自身借阅过的图书记录和归还情况。
|
||||
|
||||
6)违章信息: 可以查询自身归还的图书是否有违章信息。
|
||||
|
||||
7)读者留言: 实现留言功能并以**弹幕形式**显示。
|
||||
|
||||
8)**智能推荐**用户输入自己的偏好,AI 根据数据库书籍列表和用户偏好,给用户推荐书籍。
|
||||
|
||||
### 图书管理员功能
|
||||
|
||||
1)借阅图书: 图书管理员输入借阅证号(用户)和要借的图书编号和当前的时间,点击借阅。
|
||||
|
||||
2)归还图书: 输入图书编号查看图书是否逾期,并且可以设置违规信息,然后选择是否归还图书。
|
||||
|
||||
3)借书报表: 用于查询已经借阅并归还的书籍列表,同样使用分页构造器和模糊查询字段,显示借阅证编号,图书编号,借阅日期,截止日期,归还日期,违章信息,处理人。
|
||||
|
||||
4)还书报表: 用于查询已经借阅但是还未归还的书籍列表,显示借阅证编号,图书编号,借阅日期,截止日期。
|
||||
|
||||
5)发布公告: 可以查询当前发布的公告列表,并进行删除,修改,增加功能,分页构造器用于缓解数据量大的情况。
|
||||
|
||||
### 系统管理员功能
|
||||
|
||||
1)书籍管理: 可以查询当前的所有图书,显示图书编号,图书昵称,作者,图书馆,分类,位置,状态,描述。可以进行添加,修改,删除图书。利用分页构造器实现批量查询。利用模糊查询实现图书搜索功能。**利用插件实现 PDF 和 EXCEL 导出**。
|
||||
|
||||
2)书籍类型: 显示查询当前的所有图书类型,可以进行添加,修改,删除图书类型,利用分页构造器实现批量查询,缓解数据压力。
|
||||
|
||||
3)借阅证管理: 可以查询当前的所有借阅证列表,也就是用户数量,可以进行添加,修改,删除操作。同样实现分页。
|
||||
|
||||
4)借阅信息查询: 可以查询当前已经完成借阅和归还的记录,显示借阅证号,书籍编号,借阅日期,截止日期,归还日期,违章信息,处理人。分页功能,PDF 和 EXCEL 导出。
|
||||
|
||||
5)借阅规则管理: 可以查询当前所有的借阅规则,显示限制借阅天数,限制本数,限制图书馆,逾期费用,可以进行添加、删除、修改操作。
|
||||
|
||||
6)图书管理员管理: 显示当前的图书管理员列表,显示账号,姓名,邮箱,可以进行添加、删除、修改操作。
|
||||
|
||||
7)系统管理: 可以查询一个月内的借阅量,以一周为时间间隔,计算借阅量,**用 Echarts 实现各种图表的展示**。
|
||||
|
||||
8)系统分析:可以上传某个时间段的借阅量和日期,并且输入分析目标和想要生成的图表类型,等待一段时间后,**AI 将会给出分析结论和可视化图表**。
|
||||
|
||||
### 特性(亮点)
|
||||
|
||||
1)本项目采用前后端分离的模式,前端构建页面,后端作数据接口,前端调用后端数据接口得到数据,重新渲染页面。
|
||||
|
||||
2)前端在 Authorization 字段提供 Token 令牌,API 认证使用 Token 认证,使用 HTTP Status Code 表示状态,数据返回格式使用 JSON。
|
||||
|
||||
3)后端已开启 CORS 跨域支持,采用权限拦截器进行权限校验,并检查登录情况。
|
||||
|
||||
4)添加全局异常处理机制,捕获异常,增强系统健壮性。
|
||||
|
||||
5)前端用 Echarts 可视化库实现了图书借阅的分析图标(折线图、饼图),并通过 Loading 配置提高加载体验。
|
||||
|
||||
6)留言组件采用弹幕形式,贴合用户的喜好。
|
||||
|
||||
7)引入 knife4j 依赖,使用 Swagger + Knife4j 自动生成 OpenAPI 规范的接口文档,前端可以在此基础上使用插件自动生成接口请求代码,降低前后端协作成本
|
||||
|
||||
8)使用 ElementUI 组件库进行前端界面搭建,快速实现页面生成,并实现了前后端统一权限管理,多环境切换等能力。
|
||||
|
||||
9)基于 MyBatis Plus 框架的 QueryWrapper 实现对 MySQL 数据库的灵活查询,并配合 MyBatisX 插件自动生成后端 CRUD 基础代码,减少重复工作。
|
||||
|
||||
10)前端路由懒加载、CDN 静态资源缓存优化、图片懒加载效果。
|
||||
|
||||
## ☀️运行方式
|
||||
|
||||
### 2 分钟快速上手使用项目
|
||||
|
||||
1)找到 SpringBoot 启动类,点击运行
|
||||
|
||||

|
||||
|
||||
2)打开 Knife4J 注册用户,或者可以直接找我拿数据库模拟数据(简易)。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
3)前端输入表单内容后点击登录即可成功,开始愉快使用功能~
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## ☀️部署方式
|
||||
|
||||
### 前置条件
|
||||
|
||||
**前端**
|
||||
|
||||
软件:Vscode 或者 Webstorm(推荐)
|
||||
|
||||
环境:Node 版本 16 或者 18(推荐) **注:千万别选 18 以上的版本!**
|
||||
|
||||
**后端**
|
||||
|
||||
软件:Eclipse 或者 IDEA(推荐)
|
||||
|
||||
环境:MySQL 5.7 或者 8.0(推荐)Redis(可选)
|
||||
|
||||
### 前端部署
|
||||
|
||||
1)点击克隆/下载项目,会使用 Git 进行版本控制的,推荐 Git Clone,不会的小伙伴可以选择下载一个 Zip 压缩包,然后解压到自己电脑的 D 盘,推荐直接 Star,后续直接向我拿数据库模拟文件和 API 接口文档。
|
||||
|
||||

|
||||
|
||||
2)利用 Vscode 或者 Webstorm 打开前端页面,配置 Configuration。配置 Node 环境和包管理工具即可,我这边选择的包管理工具是 Npm,其他包管理工具如:Yarn、Cnpm、Pnpm 皆可。 **注:注意更改 Npm 的镜像地址为淘宝的新镜像地址,否则会出现 Npm Install 一直卡进度条的情况。**
|
||||
|
||||
3)直接点击 dev 的运行,或者打开控制台,输入 npm run serve 即可成功启动前端项目。
|
||||
|
||||
```shell
|
||||
npm config set registry https://registry.npmmirror.com/
|
||||
```
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
4)将图片链接进行自定义切换,可以切换为你自己的图床的图片链接,比如七牛云、GitHub 等,也可以寻找在线图片,复制百度文库图片链接(多试几次,有些图片有防盗链)。**更换背景后,可以看到右下角的权限切换小图标。**
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 后端部署
|
||||
|
||||
1)点击克隆/下载项目,会使用 Git 进行版本控制的,推荐 Git Clone,不会的小伙伴可以选择下载一个 Zip 压缩包,然后解压到自己电脑的 D 盘,推荐直接 Star,后续直接向我拿数据库模拟文件和 API 接口文档。
|
||||
|
||||

|
||||
|
||||
2)领取数据库模拟文件后,利用 Navicat 或者 SQLYog 等软件导入数据库文件,记得先建立一个名为 bms_boot 的数据库,然后右键点击运行 SQL 文件即可,运行成功,无报错后,重新打开数据库,检查是否有数据,如果有数据,表明导入成功。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
3)用 IDEA 打开后端项目,找到 application-dev.yml 文件,修改其中的 MySQL 配置,保证用户名和密码正确,注:密码不能以数字 0 开头。
|
||||
|
||||

|
||||
|
||||
4)导入 Maven 依赖,注意看自己的 Maven 版本是否正确,建议选择跟我一样的,3.8以上的版本,发现依赖导入很慢,是因为没有配置国内镜像,默认连接的是国外服务器,因此阿里云镜像配置可以看这篇博客。[CSDN Maven 配置教程](https://blog.csdn.net/lianghecai52171314/article/details/102625184?ops_request_misc=&request_id=&biz_id=102&utm_term=Maven)
|
||||
|
||||

|
||||
|
||||
5)找到 SpringBoot 启动类,我建议用 Debug 模式启动项目,更好排查错误。
|
||||
|
||||

|
||||
|
||||
6)如果遇到错误,大概率可能是 JDK 版本问题,我项目用的是 JDK 8,建议选择与我相同版本。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
7)成功启动项目效果展示如下
|
||||
|
||||

|
||||
|
||||
### 前后端联调
|
||||
|
||||
1)如果需要修改端口和前缀(比如/api),需要同时修改前端和后端。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## ☀️技术选型
|
||||
|
||||
### 前端
|
||||
|
||||
| **技术** | **作用** | **版本** |
|
||||
| ---------------------------- | ------------------------------------------------------------ | ---------------------------------------------------- |
|
||||
| Vue | 提供前端交互 | 2.6.14 |
|
||||
| Vue-Router | 路由式编程导航 | 3.5.1 |
|
||||
| Element-UI | 模块组件库,绘制界面 | 2.4.5 |
|
||||
| Axios | 发送ajax请求给后端请求数据 | 1.2.1 |
|
||||
| core-js | 兼容性更强,浏览器适配 | 3.8.3 |
|
||||
| swiper | 轮播图插件(快速实现) | 3.4.2 |
|
||||
| vue-baberrage | vue弹幕插件(实现留言功能) | 3.2.4 |
|
||||
| vue-json-excel | 表格导出Excel | 0.3.0 |
|
||||
| html2canvas+jspdf | 表格导出PDF | 1.4.1 2.5.1 |
|
||||
| node-polyfill-webpack-plugin | webpack5中移除了nodejs核心模块的polyfill自动引入 | 2.0.1 |
|
||||
| default-passive-events | **Chrome** 增加了新的事件捕获机制 **Passive Event Listeners**(被动事件侦听器) | 让页面滑动更加流畅,主要用于提升移动端滑动行为的性能 |
|
||||
| nprogress | 发送请求显示进度条(人机交互友好) | 0.2.0 |
|
||||
| echarts | 数据转图标的好工具(功能强大) | 5.4.1 |
|
||||
| less lessloader | 方便样式开发 | 4.1.3 11.1.0 |
|
||||
|
||||
### 后端
|
||||
|
||||
| **技术及版本** | **作用** | **版本** |
|
||||
| ------------------------------------ | ------------------------------------------------------------ | --------------------------------- |
|
||||
| SpringBoot | 应用开发框架 | 2.7.8 |
|
||||
| JDK | Java 开发包 | 1.8 |
|
||||
| MySQL | 提供后端数据库 | 8.0.23 |
|
||||
| MyBatisPlus | 提供连接数据库和快捷的增删改查 | 3.5.1 |
|
||||
| SpringBoot-Configuration-processor | 配置处理器 定义的类和配置文件绑定一般没有提示,因此可以添加配置处理器,产生相对应的提示. | |
|
||||
| SpringBoot-Starter-Web | 后端集成Tomcat MVC | 用于和前端连接 |
|
||||
| SpringBoot-starter-test | Junit4单元测试前端在调用接口前,后端先调用单元测试进行增删改查,注意Junit4和5的问题,注解@RunWith是否添加 | |
|
||||
| Lombok | 实体类方法的快速生成 简化代码 | |
|
||||
| mybatis-plus-generator | 代码生成器 | 3.5.1 |
|
||||
| MyBatisX | MyBatisPlus插件直接生成mapper,实体类,service | |
|
||||
| jjwt | token工具包 | 0.9.0 |
|
||||
| fastjson | 阿里巴巴的 JSON 工具类 | 1.2.83 |
|
||||
| hutool | hutool工具包(简化开发工具类) | [文档](https://hutool.cn/docs/#/) |
|
||||
| knife4j-openapi2-spring-boot-starter | Knife4j 在线接口文档测试工具 | 4.0.0 |
|
||||
| gson | 谷歌的 JSON 工具类 | 2.8.5 |
|
||||
| Java-WebSocket | 讯飞星火 AI 配置 | 1.3.8 |
|
||||
| okhttp | 讯飞星火 AI 配置 | 4.10.0 |
|
||||
| okio | 讯飞星火 AI 配置 | 2.10.0 |
|
||||
| jsoup | 简易爬虫工具 | 1.15.3 |
|
||||
| guava | 谷歌工具类 | 30.1-jre |
|
||||
| spring-boot-starter-data-redis | Redis 的 Starter | |
|
||||
| broadscope-bailian-sdk-java | 阿里云 AI 模型 | 1.1.7 |
|
||||
| spring-boot-starter-websocket | WebSocket 的 Starter | |
|
||||
|
||||
## ☀️架构
|
||||
|
||||

|
||||
|
||||
## ☀️核心设计
|
||||
|
||||
### 智能推荐功能
|
||||
|
||||
1)用户输入自己的图书偏爱信息。
|
||||
|
||||
2)前端发送 Axios 请求。
|
||||
|
||||
3)后端先判断文本是否违法(为空或者文本字数过长)。
|
||||
|
||||
4)查看接口是否存在。
|
||||
|
||||
5)查看 AI 接口调用次数是否充足。
|
||||
|
||||
6)GuavaRateLimiter 进行单体限流,判断请求次数是否超出正常业务频次。
|
||||
|
||||
7)给 AI 模型人工预设,并且查询数据库中的书籍列表进行拼接。
|
||||
|
||||
8)查询 AI 模型与该用户最近的五条历史记录,用于上下文关联。
|
||||
|
||||
9)FutureTask 同步调用获取 AI 结果,并设置超时时间(超时抛出异常)
|
||||
|
||||
10)获取 AI 模型推荐信息后进行持久化,并且减少接口调用次数(判断是否成功)
|
||||
|
||||
11)返回处理好的 AI 推荐信息给前端,并设置响应状态码为 200 即可。
|
||||
|
||||
### 智能分析功能
|
||||
|
||||
1)用户输入分析目标、图标名称、选择图标类型、上传 Excel 文件,点击提交,发送 Axios 请求至后端。
|
||||
|
||||
2)校验文件是否为空、名称是否过长、文件大小检验、文件后缀校验
|
||||
|
||||
3)获取管理员 ID,从接口信息表查询管理员 ID 拥有的接口,接口判空。
|
||||
|
||||
4)判断 AI 接口调用次数是否足够
|
||||
|
||||
5)GuavaRateLimiter 进行单体限流,判断请求次数是否超出正常业务频次。
|
||||
|
||||
6)构造 AI 模型的提示词和角色
|
||||
|
||||
7)构造用户输入,拼接用户输入信息,并用工具类将 Excel 转为 CSV 字符串数据。
|
||||
|
||||
8)利用讯飞星火 AI 模型,传入调用者 ID 和输入参数,利用 FutureTask 同步获取,并设置超时时间(超时抛出异常)
|
||||
|
||||
9)对 AI 生成结果进行判断,格式错误就返回前端错误信息,并提示重新调用(后续考虑 RabbitMQ 进行重试和补偿机制)
|
||||
|
||||
10)将 AI 生成结果持久化到数据库,并更新接口调用次数(判断是否成功),动态给前端返回图标和数据结论。
|
||||
|
||||
## ☀️学完这个项目你能得到什么
|
||||
|
||||
1)简单地调用 AI 模型(讯飞星火 | 阿里百炼)获取自定义文本内容。
|
||||
|
||||
2)简单的 JWT 权限校验 ,利用后端拦截器进行登录校验。
|
||||
|
||||
3)上传 Excel 文件,Excel 文件转换为 CSV 数据,AIGC 在线生成可视化图表。
|
||||
|
||||
4)Jousp 批量爬取图书列表,可结合 SpringSchedule 定时任务执行。
|
||||
|
||||
5)简单的增删改查系统,前后端是如何联调协作的。
|
||||
|
||||
6)前端路由懒加载、CDN 静态资源缓存优化、图片懒加载是如何实现的
|
||||
|
||||
7)利用 Lodash 进行节流控制,尽量降低无效的恶意刷留言情况。
|
||||
|
||||
8)利用自定义线程池和 FutureTask 进行超时请求处理。
|
||||
|
||||
9)利用Google 的 GuavaRateLimiter 进行单体限流控制。
|
||||
|
||||
10)定时任务结合 Redis 做一个缓存预热,加快查询效率,提高用户体验。
|
||||
|
||||
## ☀️项目简介
|
||||
|
||||
+ 主要使用Vue2和SpringBoot2实现
|
||||
+ 项目权限控制分别为:用户借阅,图书管理员,系统管理员
|
||||
+ 开发工具:IDEA2022.1.3(真不推荐用eclipse开发,IDEA项目可以导出为eclipse项目,二者不影响,但需要自己学教程)
|
||||
+ [IDEA->Eclipse](https://blog.csdn.net/HD202202/article/details/128076400)
|
||||
+ [Eclipse->IDEA](https://blog.csdn.net/q20010619/article/details/125096051)
|
||||
|
||||
+ 学校老师硬性要求软件的话,还是按要求来。可以先问一下是否可以选择其他软件开发。
|
||||
+ 用户账号密码: 相思断红肠 123456
|
||||
+ 图书管理员账号密码: admin 123456
|
||||
+ 系统管理员账号密码: root 123456
|
||||
+ [前端样式参考](https://gitee.com/mingyuefusu/tushuguanlixitong) 感谢原作者**明月复苏**
|
||||
|
||||
+ 遇到交互功能错误,或者页面无法打开,请用开发者工具F12查看请求和响应状态码情况,当然可能小白不懂,那也没关系,可以加我**QQ:909088445**。白天上课,晚上有空才能回答,感谢体谅!⭐⭐⭐
|
||||
|
||||
## ☀️项目详细介绍(亮点)
|
||||
|
||||
+ 本项目采用前后端分离的模式,前端构建页面,后端作数据接口,前端调用后端数据接口得到数据,重新渲染页面。
|
||||
+ 后端已开启 CORS 跨域支持
|
||||
+ API 认证使用 Token 认证
|
||||
+ 前端在 Authorization 字段提供 Token 令牌
|
||||
+ 使用 HTTP Status Code 表示状态
|
||||
+ 数据返回格式使用 JSON
|
||||
+ 后端采用权限拦截器进行权限校验,并检查登录情况
|
||||
+ 添加全局异常处理机制,捕获异常,增强系统健壮性
|
||||
+ 前端用 Echarts 可视化库实现了图书借阅的分析图标(折线图、饼图),并通过 Loading 配置提高加载体验。
|
||||
+ 留言组件采用弹幕形式,贴合用户的喜好。
|
||||
+ 引入 knife4j 依赖,使用 Swagger + Knife4j 自动生成 OpenAPI 规范的接口文档,前端可以在此基础上使用插件自动生成接口请求代码,降低前后端协作成本
|
||||
+ 使用 ElementUI 组件库进行前端界面搭建,快速实现页面生成,并实现了前后端统一权限管理,多环境切换等能力。
|
||||
+ 基于 MyBatis Plus 框架的 QueryWrapper 实现对 MySQL 数据库的灵活查询,并配合 MyBatisX 插件自动生成后端 CRUD 基础代码,减少重复工作。
|
||||
+ 前端路由懒加载、CDN 静态资源缓存优化、图片懒加载效果。
|
||||
|
||||
### ⭐用户模块功能介绍
|
||||
|
||||

|
||||
|
||||
+ 图书查询功能:分页构造器缓解数据过大压力,后端可设置请求数防止爬虫请求数过大,服务器负载过大。模糊查询进行字段搜索。表格均可导出PDF和EXCEL。
|
||||
+ 读者规则功能:查询现有的借阅规则,借阅规则包括:借阅编号,可借阅图书数量,可借阅天数,可借阅图书馆,过期扣费/天。
|
||||
+ 查看公告: 可以查询图书管理员发布的公告列表,文字滑动效果。
|
||||
|
||||
+ 个人信息: 可以查看个人的借阅证编号,借阅证姓名,规则编号,状态,可以修改个人账户的密码。
|
||||
|
||||
+ 借阅信息: 可以查看自身借阅过的图书记录和归还情况。
|
||||
+ 违章信息: 可以查询自身归还的图书是否有违章信息。
|
||||
+ 读者留言: 实现留言功能并以弹幕形式显示。
|
||||
|
||||
### ⭐图书管理员模块功能介绍
|
||||
|
||||

|
||||
|
||||
+ 借阅图书: 图书管理员输入借阅证号(用户)和要借的图书编号和当前的时间,点击借阅。
|
||||
+ 归还图书: 输入图书编号查看图书是否逾期,并且可以设置违规信息,然后选择是否归还图书
|
||||
+ 借书报表: 用于查询已经借阅并归还的书籍列表,同样使用分页构造器和模糊查询字段,显示借阅证编号,图书编号,借阅日期,截止日期,归还日期,违章信息,处理人。
|
||||
+ 还书报表: 用于查询已经借阅但是还未归还的书籍列表,显示借阅证编号,图书编号,借阅日期,截止日期。
|
||||
|
||||
+ 发布公告: 可以查询当前发布的公告列表,并进行删除,修改,增加功能,分页构造器用于缓解数据量大的情况。
|
||||
|
||||
### ⭐系统管理员模块功能介绍
|
||||
|
||||

|
||||
|
||||
+ 书籍管理: 可以查询当前的所有图书,显示图书编号,图书昵称,作者,图书馆,分类,位置,状态,描述。可以进行添加,修改,删除图书。利用分页构造器实现批量查询。利用模糊查询实现图书搜索功能。利用插件实现PDF和EXCEL导出。
|
||||
+ 书籍类型: 显示查询当前的所有图书类型,可以进行添加,修改,删除图书类型,利用分页构造器实现批量查询,缓解数据压力。
|
||||
+ 借阅证管理: 可以查询当前的所有借阅证列表,也就是用户数量,可以进行添加,修改,删除操作。同样实现分页。
|
||||
+ 借阅信息查询: 可以查询当前已经完成借阅和归还的记录,显示借阅证号,书籍编号,借阅日期,截止日期,归还日期,违章信息,处理人。分页功能,PDF和EXCEL导出。
|
||||
+ 借阅规则管理: 可以查询当前所有的借阅规则,显示限制借阅天数,限制本数,限制图书馆,逾期费用,可以进行添加、删除、修改操作。
|
||||
+ 图书管理员管理: 显示当前的图书管理员列表,显示账号,姓名,邮箱,可以进行添加、删除、修改操作。
|
||||
+ 系统管理: 可以查询一个月内的借阅量,以一周为时间间隔,计算借阅量,用Echarts实现折线图的展示。
|
||||
|
||||
## ☀️数据库表设计
|
||||
|
||||
### t_users表
|
||||
|
||||
| 列名 | 数据类型以及长度 | 备注 |
|
||||
| ----------- | ---------------- | ------------------------------------------------- |
|
||||
| user_id | int(11) | 主键 非空 自增 用户表的唯一标识 |
|
||||
| username | varchar(32) | 用户名 非空 |
|
||||
| password | varchar(32) | 密码(MD5加密) 非空 |
|
||||
| card_name | varchar(10) | 真实姓名 非空 |
|
||||
| card_number | Bigint(11) | 借阅证编号 固定 11位随机生成 非空(后文都改BigInt) |
|
||||
| rule_number | int(11) | 规则编号 可以自定义 也就是权限功能 |
|
||||
| status | int(1) | 1表示可用 0表示禁用 |
|
||||
| create_time | datetime | 创建时间 Java注解 JsonFormatter |
|
||||
| update_time | datetime | 更新时间 Java注解 JsonFormatter |
|
||||
|
||||
### t_admins表
|
||||
|
||||
| 列名 | 数据类型以及长度 | 备注 |
|
||||
| ----------- | ---------------- | --------------------------------- |
|
||||
| admin_id | int(11) | 主键 非空 自增 管理员表的唯一标识 |
|
||||
| username | varchar(32) | 用户名 非空 |
|
||||
| password | varchar(32) | 密码(MD5加密) 非空 |
|
||||
| admin_name | varchar(10) | 管理员真实姓名 非空 |
|
||||
| status | int(1) | 1表示可用 0表示禁用 |
|
||||
| create_time | datetime | 创建时间 Java注解 JsonFormatter |
|
||||
| update_time | datetime | 更新时间 Java注解 JsonFormatter |
|
||||
|
||||
### t_book_admins表
|
||||
|
||||
| 列名 | 数据类型以及长度 | 备注 |
|
||||
| --------------- | ---------------- | ------------------------------- |
|
||||
| book_admin_id | int(11) | 主键 非空 自增 管理表的唯一标识 |
|
||||
| username | varchar(32) | 用户名 非空 |
|
||||
| password | varchar(32) | 密码(MD5加密)非空 |
|
||||
| book_admin_name | varchar(10) | 图书管理员真实姓名 非空 |
|
||||
| status | int(1) | 1表示可用 0表示禁用 |
|
||||
| email | varchar(255) | 电子邮箱 |
|
||||
| create_time | datetime | 创建时间 Java注解 JsonFormatter |
|
||||
| update_time | datetime | 更新时间 Java注解 JsonFormatter |
|
||||
|
||||
### t_books表
|
||||
|
||||
| 列名 | 数据类型以及长度 | 备注 |
|
||||
| ---------------- | ---------------- | ------------------------------- |
|
||||
| book_id | int(11) | 主键 自增 非空 图书表的唯一标识 |
|
||||
| book_number | int(11) | 图书编号 非空 图书的唯一标识 |
|
||||
| book_name | varchar(32) | 图书名称 非空 |
|
||||
| book_author | varchar(32) | 图书作者 非空 |
|
||||
| book_library | varchar(32) | 图书所在图书馆的名称 非空 |
|
||||
| book_type | varchar(32) | 图书类别 非空 |
|
||||
| book_location | varchar(32) | 图书位置 非空 |
|
||||
| book_status | varchar(32) | 图书状态(未借出/已借出) |
|
||||
| book_description | varchar(100) | 图书描述 |
|
||||
| create_time | datetime | 创建时间 Java注解 JsonFormatter |
|
||||
| update_time | datetime | 更新时间 Java注解 JsonFormatter |
|
||||
|
||||
### t_books_borrow表
|
||||
|
||||
| 列名 | 数据类型以及长度 | 备注 |
|
||||
| ----------- | ---------------- | ------------------------------------------------------------ |
|
||||
| borrow_id | int(11) | 主键 自增 非空 借阅表的唯一标识 |
|
||||
| card_number | int(11) | 借阅证编号 固定 11位随机生成 非空 用户与图书关联的的唯一标识 |
|
||||
| book_number | int(11) | 图书编号 非空 图书的唯一标识 |
|
||||
| borrow_date | datetime | 借阅日期 Java注解 JsonFormatter |
|
||||
| close_date | datetime | 截止日期 Java注解 JsonFormatter |
|
||||
| return_date | datetime | 归还日期 Java注解 JsonFormatter |
|
||||
| create_time | datetime | 创建时间 Java注解 JsonFormatter |
|
||||
| update_time | datetime | 更新时间 Java注解 JsonFormatter |
|
||||
|
||||
### t_notice表
|
||||
|
||||
| 列名 | 数据类型以及长度 | 备注 |
|
||||
| --------------- | ---------------- | ----------------------------------- |
|
||||
| notice_id | int(11) | 主键 非空 自增 公告表记录的唯一标识 |
|
||||
| notice_title | varchar(32) | 公告的题目 非空 |
|
||||
| notice_content | varchar(255) | 公告的内容 非空 |
|
||||
| notice_admin_id | int(11) | 发布公告的管理员的id |
|
||||
| create_time | datetime | 创建时间 Java注解 JsonFormatter |
|
||||
| update_time | datetime | 更新时间 Java注解 JsonFormatter |
|
||||
|
||||
### t_violation表
|
||||
|
||||
| 列名 | 数据类型以及长度 | 备注 |
|
||||
| ------------------ | ---------------- | ----------------------------------- |
|
||||
| violation_id | int(11) | 主键 非空 自增 违章表记录的唯一标识 |
|
||||
| card_number | int(11) | 借阅证编号 固定 11位随机生成 非空 |
|
||||
| book_number | int(11) | 图书编号 非空 图书的唯一标识 |
|
||||
| borrow_date | datetime | 借阅日期 Java注解 JsonFormatter |
|
||||
| close_date | datetime | 截止日期 Java注解 JsonFormatter |
|
||||
| return_date | datetime | 归还日期 Java注解 JsonFormatter |
|
||||
| violation_message | varchar(100) | 违章信息 非空 |
|
||||
| violation_admin_id | int(11) | 违章信息管理员的id |
|
||||
| create_time | datetime | 创建时间 Java注解 JsonFormatter |
|
||||
| update_time | datetime | 更新时间 Java注解 JsonFormatter |
|
||||
|
||||
### t_comment表
|
||||
|
||||
| 列名 | 数据类型以及长度 | 备注 |
|
||||
| --------------------- | ---------------- | ----------------------------------- |
|
||||
| comment_id | int(11) | 主键 非空 自增 留言表记录的唯一标识 |
|
||||
| comment_avatar | varchar(255) | 留言的头像 |
|
||||
| comment_barrage_style | varchar(32) | 弹幕的高度 |
|
||||
| comment_message | varchar(255) | 留言的内容 |
|
||||
| comment_time | int(11) | 留言的时间(控制速度) |
|
||||
| create_time | datetime | 创建时间 Java注解 JsonFormatter |
|
||||
| update_time | datetime | 更新时间 Java注解 JsonFormatter |
|
||||
|
||||
### t_book_rule表
|
||||
|
||||
| 列名 | 数据类型以及长度 | 备注 |
|
||||
| ------------------ | ---------------- | ------------------------------------- |
|
||||
| rule_id | int(11) | 主键 非空 自增 借阅规则记录的唯一标识 |
|
||||
| book_rule_id | int(11) | 借阅规则编号 非空 |
|
||||
| book_days | int(11) | 借阅天数 非空 |
|
||||
| book_limit_number | int(11) | 限制借阅的本数 非空 |
|
||||
| book_limit_library | varchar(255) | 限制的图书馆 非空 |
|
||||
| book_overdue_fee | double | 图书借阅逾期后每天费用 非空 |
|
||||
| create_time | datetime | 创建时间 Java注解 JsonFormatter |
|
||||
| update_time | datetime | 更新时间 Java注解 JsonFormatter |
|
||||
|
||||
### t_book_type表
|
||||
|
||||
| 列名 | 数据类型以及长度 | 备注 |
|
||||
| ------------ | ---------------- | ------------------------------------- |
|
||||
| type_id | int(11) | 主键 非空 自增 图书类别记录的唯一标识 |
|
||||
| type_name | varchar(32) | 借阅类别的昵称 非空 |
|
||||
| type_content | varchar(255) | 借阅类别的描述 非空 |
|
||||
| create_time | datetime | 创建时间 Java注解 JsonFormatter |
|
||||
| update_time | datetime | 更新时间 Java注解 JsonFormatter |
|
||||
|
||||
## 🐼功能演示图
|
||||
|
||||
### 用户模块功能图
|
||||
|
||||
**首页轮播图演示**
|
||||
|
||||

|
||||
|
||||
**图书查询演示**
|
||||
|
||||

|
||||
|
||||
**读者规则演示**
|
||||
|
||||

|
||||
|
||||
**查看公告演示**
|
||||
|
||||

|
||||
|
||||
**个人信息演示**
|
||||
|
||||

|
||||
|
||||
**借阅信息演示**
|
||||
|
||||

|
||||
|
||||
**违章信息演示**
|
||||
|
||||

|
||||
|
||||
**读者留言演示**
|
||||
|
||||

|
||||
|
||||
**智能推荐演示**
|
||||
|
||||

|
||||
|
||||
### 图书管理员功能图
|
||||
|
||||
**借阅图书演示**
|
||||
|
||||

|
||||
|
||||
**归还图书演示**
|
||||
|
||||

|
||||
|
||||
**借书报表演示**
|
||||
|
||||

|
||||
|
||||
**还书报表演示**
|
||||
|
||||

|
||||
|
||||
**发布公告演示**
|
||||
|
||||

|
||||
|
||||
### 系统管理员功能图
|
||||
|
||||
+ 由于篇幅受限,系统功能展示主要功能。
|
||||
|
||||
**系统管理演示**
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
**智能分析演示**
|
||||
|
||||

|
||||
|
||||
## 🐼部署项目
|
||||
|
||||

|
||||
|
||||
+ 可以下载ZIP压缩包或者使用克隆(Git clone)
|
||||
+ 复制http或者ssh的链接(github建议ssh,gittee都可以)
|
||||
+ 在D盘新建一个文件夹,点击进入该文件夹,右键Git Bash Here
|
||||
|
||||

|
||||
|
||||
+ 还没有下载Git或者不会Git的建议先看基础教程(30分钟左右)
|
||||
|
||||
+ 输入git init 初始化git项目 然后出现一个.git文件夹
|
||||
+ 输入git remote add origin xxxxxx(xxx为刚刚复制的http或者ssh链接)
|
||||
|
||||
+ 输入git pull origin master 从远程代码托管仓库拉取代码
|
||||
+ 成功拉取项目(前端后端都是如此)
|
||||
+ 前端项目注意依赖下载使用npm install 或者 yarn install (Vscode或者Webstorm)
|
||||
+ 后端项目注意maven依赖下载(IDEA(推荐)或者Ecplise)
|
||||
+ 前端npm 镜像源建议淘宝镜像源,后端maven镜像源推荐阿里云镜像源(非必选,但更换后下载快速)
|
||||
|
||||
## 🐼部署项目问题
|
||||
|
||||
⭐
|
||||
|
||||
+ 乱码问题 项目采用的UFT-8
|
||||
+ 一般出现乱码就是UTF-8和GBK二者相反
|
||||
+ 请百度IDEA乱码和Eclipse乱码问题(描述清楚即可)
|
||||
|
||||
⭐
|
||||
|
||||
+ 点击交互按钮,没有发生反应。
|
||||
+ 很明显,请求失败,浏览器打开开发者工具,Edge浏览器直接ctrl+shift+i,其他浏览器按F12
|
||||
+ 查看红色的请求和响应状态码问题
|
||||
|
||||
⭐
|
||||
|
||||
+ 先阅读文档再进行问题的查询或者提问
|
||||
+ 提问有技巧,模糊的发言,让高级架构师找BUG也无从下手
|
||||
|
||||
⭐
|
||||
|
||||
+ **QQ:909088445**
|
||||
+ 一般晚上在线,建议先自己寻找问题!!!
|
||||
+ 开源免费, 定制化和调试项目付费。
|
||||
|
||||
## 🐼需求分析和设计
|
||||
|
||||
需求分析和设计文档,有(**付费**)需求的可以加 QQ:909088445,适合走毕设和课设的小伙伴,图省事的可以找我。
|
||||
|
||||

|
||||
|
||||
## 🐼项目API接口文档
|
||||
|
||||
+ 接口文档篇幅过大
|
||||
+ 本来想完全采用RESTFUL风格,做到一半忘记了
|
||||
+ 看清楚文档的基准地址
|
||||
+ 要API后端接口文档详细内容和数据库结构+内容一起的,将前后端**star**⭐的截图加我QQ:**909088445**发我即可领取~感谢支持
|
||||
|
||||
#### **数据库领取截图示例(Gitee&GitHub):**
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 🐷其他
|
||||
|
||||
+ 个人博客地址: https://luoye6.github.io/
|
||||
+ 个人博客采用Hexo+Github托管
|
||||
+ 采用butterfly主题可以实现定制化
|
||||
+ 推荐有空闲时间的,可以花1-2天搭建个人博客用于记录笔记。
|
||||
|
||||
## ☕请我喝咖啡
|
||||
|
||||
如果本项目对您有所帮助,不妨请作者我喝杯咖啡 :)
|
||||
|
||||
<div><img src="https://pic.yupi.icu/5563/202312191854931.png" style="height:300px;width:300px"></img> <img src="https://pic.yupi.icu/5563/202312191859536.png" style="height:300px;width:300px"></img></div>
|
||||
|
||||
## **版本迭代**
|
||||
|
||||
### 2023-3-19
|
||||
|
||||
1.引入knife4j依赖,使用 Swagger + Knife4j 自动生成 OpenAPI 规范的接口文档,前端可以在此基础上使用插件自动生成接口请求代码,降低前后端协作成本。
|
||||
|
||||
2.引入jsoup依赖可以自定义添加爬虫功能,可以批量添加图书并且是比较真实的数据。
|
||||
|
||||
3.添加事务管理器,可以进行用@Transactional指定异常类型回滚和事务传播行为。
|
||||
|
||||
### 2023-4-13
|
||||
|
||||
1.手动在增加和删除逻辑较为复杂的数据库操作上,添加了@Transactional注解,遇到运行时异常直接回滚数据库,防止借书和还书出现逻辑错误。
|
||||
|
||||
2.修复11位图书编号无法借书的Bug,其原因是因为11位超出了Integer的2147483647(10位)。解决方法:数据库改为BigInt,Java改为Long。
|
||||
|
||||
3.**注意**:不要随便删除用户和公告!!!会导致其他人体验的时候出现逻辑错误!!!请明白了项目逻辑再去做删除操作!!!感谢配合!!!
|
||||
|
||||
4.下一期准备优化图表的展示,逾期图书后告警通知之类的功能,感谢大家的支持,我会继续维护和优化功能,有Bug可以加我QQ或者提出issue,勿要恶意利用bug,再次鸣谢。
|
||||
|
||||
5.劳动节准备录一期部署项目的视频会发到b站,到时候会将部署讲清楚,方便大家课设或者毕设的完成,此项目有数据库表设计、API接口文档、内容功能介绍、亮点介绍,唯一缺少的可能是数据流图、ER图之类的,star的人多了,我会添加上去。
|
||||
|
||||
### 2023-5-1
|
||||
|
||||
1.添加“系统管理员”权限的系统管理功能,**添加借书类型分析统计图(饼图)**采用Echarts。
|
||||
|
||||
2.优化请求在没有收到数据时的显示卡顿的情况,添加“加载中”状态,**使用v-loading**(ElementUI组件库),**优化用户人机交互体验**,在服务器调用接口缓慢的情况下,给予**良好的交互**。
|
||||
|
||||
3.轮播图优化:**压缩图片体积**,另外使用Swiper的**懒加载**,实现图片加载中状态,然后图片完全加载完成后才显示图片,**优化用户体验过程**。
|
||||
|
||||
4.后端**新增自定义错误码枚举类**,可以自定义状态码进行返回,保留原有枚举类。
|
||||
|
||||
5.前端优化部分表格内容展示,当纵向内容过长,**设置了表格最大高度**,超出就会显示滑动窗口。优化表格列宽度,**提高表格美观度**。
|
||||
|
||||
6.**添加**书籍管理组件的**批量删除图书**功能,优化管理员体验,不用单个删除图书,**提高效率**。
|
||||
|
||||
7.Jmeter进行压力测试,服务器接口在**100个用户并发**发送请求的情况下,**QPS达到50**以上。
|
||||
|
||||
### 2023-5-20
|
||||
|
||||
**后端更新情况**
|
||||
|
||||
1.~~防止前端抓包被获取明文密码,前端输入密码,进行md5加密(混合盐值,防止碰撞),后端直接与数据库加密后的密码比较,相等代表登录成功。提高系统**安全性**!~~。
|
||||
|
||||
2.整改Controller层,**将业务代码全部放入Service层**,由Controller调用Service服务,并修改了@Transactional注解位置到业务层,减少耦合度,让Controller减少臃肿。做到对扩展开放,对修改关闭。后续考虑运用**设计模式**进行优化代码和**多线程**知识提高在**高并发**下接口响应的速度。
|
||||
|
||||
3.对照阿里巴巴手册进行代码修改,将警告进行减少,代码更加**优雅、规范**。
|
||||
|
||||
4.**修复BUG**: 借阅时间为空,造成服务器被击穿。归还日期为空,仍然显示借书成功。(解决方法:时间参数进行校验,判断是否为空)
|
||||
|
||||
5.**工具类增加情况**:SQLUtils(防止SQL注入),NetUtils(网络工具类)
|
||||
|
||||
**前端更新情况**
|
||||
|
||||
1.将路由加载方式,改为懒加载,利用懒加载可以有效分担首页加载压力,**减少首页加载用时**。
|
||||
|
||||
2.添加404页面,当用户访问请求地址不存在的页面,直接跳转到404页面,**提高用户体验度**。
|
||||
|
||||
3.添加按钮的加载中状态,**优化人机交互**,提升用户体验度。修改按钮:登录按钮,其他按钮如果有需要可以自定义去修改,增加:loading="loading"即可。
|
||||
|
||||
**Bug修复情况**
|
||||
|
||||
1.11位图书编号可以借,但却**无法进行逾期检查**,发现方法参数还是Integer,上次把借书和还书的改成Long了,逾期查看还没改成Long,因此出现问题,现在已经修复。
|
||||
|
||||
### 2023-6-10
|
||||
|
||||
**前端更新情况**
|
||||
|
||||
1.在某些页面添加全屏功能按钮,**方便用户放大查看表格数据**。
|
||||
|
||||
2.增加了GitHub和Gitee的地址图标,**方便进行项目拉取和克隆**。
|
||||
|
||||
3.读者留言组件,留言功能进行强化,防止无意义的数字、字母、空格出现在数据,后续考虑
|
||||
|
||||
4.读者留言组件,**利用lodash进行节流**,5秒内只可发送一次网络请求,防止恶意刷无效留言。
|
||||
|
||||
**后端更新情况**
|
||||
|
||||
1.后端添加利用EasyExcel进行图书的**批量导入功能**,实现与实际生活中利用Excel存储一些图书数据的交互功能,**提高导入效率**,和爬虫功能效果相同,都可以实现大数据量情况下的导入,推荐利用EasyExcel进行批量导入,时间会比爬虫会更快。
|
||||
|
||||
**Bug修复情况**
|
||||
|
||||
1.修改用户页面的修改密码功能,因为上次更新已经加了盐值,但是后端代码逻辑没有进行更改,本次修复"在修改密码后无法登录的情况",原因是因为后端没有加盐值,已修复。
|
||||
|
||||
2.修复系统管理员修改借阅证的密码然后就登录不上了,原因跟第一条Bug是一样的,因为后端的盐值没有进行添加,已修复。
|
||||
|
||||
3.修复系统管理员在书籍管理功能时候,直接点击修改书籍,发现书籍的分类是错误的,因为前端只在添加书籍的对话框发了获取分类的请求,修改对话框的时候忘记添加了获取分类的请求,已修复。
|
||||
|
||||
### 2023-9
|
||||
|
||||
**前端更新情况**
|
||||
|
||||
1.增加**智能推荐页面**,能够与AI进行交流,**用户输入自己喜欢xxx类的书籍,AI能够在现有数据库中进行分析**,然后给用户作出推荐,调用的是国内AI模型,底层是OpenAI。
|
||||
|
||||
2.增加**智能分析页面**,输入分析目标和图标类型和Excel文件,AI生成分析结论和可视化图标,大大提高效率,**减少人力分析成本**。
|
||||
|
||||
3.增加系统管理员可以利用在前端**利用Excel文件批量上传图书**的功能(测试中),仅供参考。
|
||||
|
||||
**后端更新情况**
|
||||
|
||||
1.增加智能分析的接口和获取最近5条聊天记录的接口,利用**线程池**和**Future**进行**超时请求处理**,如果接口调用超过40秒直接返回错误信息。
|
||||
|
||||
2.利用Google的Guava中的RateLimiter进行限流控制,**每秒钟只允许一个请求通过**,防止刷量行为。
|
||||
|
||||
### 2023-11
|
||||
|
||||
**后端更新情况**
|
||||
|
||||
1.将用户聊天的AI模型切换为阿里的通义千问Plus模型,并且**支持多轮会话的历史记录**,**不再使用讯飞星火的AI模型**,但仍保留工具类。主要是为了可以更快的得到响应,而且阿里的**文档更加详细**,可以**定制话术**,在用户输入无关图书推荐的内容时候,直接**拒绝回答**。
|
||||
|
||||
2.添加一个 IncSyncDeleteAIMessage **定时任务**,每天将会**删除由于系统错误等原因AI回复失败**,导致内容为空的记录,并且会为这些用户**恢复接口的次数**,**后续可能会选择 RabbitMQ**,将失败的消息放入消息队列,然后**确保失败的消息被消费**。
|
||||
|
||||
3.登录加密由前端改到后端,由于前端可以被撞库,因此加密依然放到后端。**方案:**前端传输,用 HTTPS 进行密文加密,后端采用盐值+算法进行加密,数据库存密文。
|
||||
|
||||
4.将留言页面存放在 Redis 中,**减少数据库的 IO 查询**,QPS 是原来的数百倍!
|
||||
|
||||
**前端更新情况**
|
||||
|
||||
1.将三个登录页面的背景图和头像改为存储在 assets 文件夹的 images 中,**主要是为使用项目的人考虑**,很多人不懂图床技术,我这边暂时将登录页面改成静态图。
|
||||
|
||||
2.权限切换的提示优化,**在图标上面现在有登录权限切换的文字样式**,提示用户有多个登录页面可以切换。
|
||||
|
||||
3.登录加密由前端改到后端,由于前端可以被撞库,因此加密依然放到后端。**方案**:前端传输,用 HTTPS 进行密文加密,后端采用盐值+算法进行加密,数据库存密文。
|
||||
|
||||
### 2024-3
|
||||
|
||||
**后端更新情况**
|
||||
|
||||
1)为 Knife4J 添加 @ ApiOperation 注解,标注每个接口的作用,**方便开发者阅读和测试接口**。
|
14
babel.config.js
Normal file
@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
"presets": [
|
||||
"@vue/cli-plugin-babel/preset"
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"component",
|
||||
{
|
||||
"libraryName": "element-ui",
|
||||
"styleLibraryName": "theme-chalk"
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
19
jsconfig.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "esnext",
|
||||
"baseUrl": "./",
|
||||
"moduleResolution": "node",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"scripthost"
|
||||
]
|
||||
}
|
||||
}
|
20149
package-lock.json
generated
Normal file
40
package.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "book_manage_system",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"dev": "npm run serve",
|
||||
"npm-build": "npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.2.1",
|
||||
"core-js": "^3.8.3",
|
||||
"default-passive-events": "^2.0.0",
|
||||
"echarts": "^5.4.1",
|
||||
"element-ui": "^2.4.5",
|
||||
"html2canvas": "^1.4.1",
|
||||
"jspdf": "^2.5.1",
|
||||
"lodash": "^4.17.21",
|
||||
"nanoid": "^4.0.0",
|
||||
"node-polyfill-webpack-plugin": "^2.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"swiper": "^3.4.2",
|
||||
"vue": "^2.6.14",
|
||||
"vue-baberrage": "^3.2.4",
|
||||
"vue-json-excel": "^0.3.0",
|
||||
"vue-router": "^3.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~5.0.0",
|
||||
"@vue/cli-plugin-router": "~5.0.0",
|
||||
"@vue/cli-service": "~5.0.0",
|
||||
"babel-plugin-component": "^1.1.1",
|
||||
"less": "^4.1.3",
|
||||
"less-loader": "^11.1.0",
|
||||
"vue-cli-plugin-element": "^1.0.1",
|
||||
"vue-particles": "^1.0.9",
|
||||
"vue-template-compiler": "^2.6.14"
|
||||
}
|
||||
}
|
BIN
public/favicon.ico
Normal file
After Width: | Height: | Size: 4.2 KiB |
25
public/index.html
Normal file
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- 开启移动端的理想端口 -->
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<!-- <link rel="stylesheet" href="../node_modules/swiper/dist/css/swiper.min.css">
|
||||
<script src="../node_modules/swiper/dist/js/swiper.min.js"></script> -->
|
||||
|
||||
<title>基于ollama的图书推荐系统</title>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
20
src/App.vue
Normal file
@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<!-- 路由占位符 -->
|
||||
<router-view></router-view>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
111
src/assets/css/global.css
Normal file
@ -0,0 +1,111 @@
|
||||
/* 全局样式表 */
|
||||
* {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-width: 1366px;
|
||||
}
|
||||
|
||||
/* body {
|
||||
cursor:url(../images/konglong.ico),auto;
|
||||
} */
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.el-breadcrumb {
|
||||
margin-bottom: 15px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.el-card {
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
|
||||
.el-table {
|
||||
margin-top: 15px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.el-pagination {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.el-cascader-menu {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.el-steps {
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.el-step__title {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.ql-editor {
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
body {
|
||||
position: relative;
|
||||
/* cursor: url(https://cdn.jsdelivr.net/gh/sviptzk/HexoStaticFile@latest/Hexo/img/default.cur), default; */
|
||||
}
|
||||
|
||||
.el-main {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.yibai {
|
||||
margin-top: 100px;
|
||||
}
|
||||
|
||||
.erbai {
|
||||
margin-top: 120px;
|
||||
}
|
||||
|
||||
.sanbai {
|
||||
margin-top: 140px;
|
||||
}
|
||||
|
||||
.sibai {
|
||||
margin-top: 160px;
|
||||
}
|
||||
|
||||
.wubai {
|
||||
margin-top: 180px;
|
||||
}
|
||||
|
||||
.liubai {
|
||||
margin-top: 200px;
|
||||
}
|
||||
|
||||
.qibai {
|
||||
margin-top: 220px;
|
||||
}
|
||||
|
||||
.babai {
|
||||
margin-top: 240px;
|
||||
}
|
||||
|
||||
.jiubai {
|
||||
margin-top: 260px;
|
||||
}
|
||||
|
||||
.yiqian {
|
||||
margin-top: 300px;
|
||||
}
|
539
src/assets/fonts/demo.css
Normal file
@ -0,0 +1,539 @@
|
||||
/* Logo 字体 */
|
||||
@font-face {
|
||||
font-family: "iconfont logo";
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-family: "iconfont logo";
|
||||
font-size: 160px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* tabs */
|
||||
.nav-tabs {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-more {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#tabs {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
#tabs li {
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
border-bottom: 2px solid transparent;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-bottom: -1px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
|
||||
#tabs .active {
|
||||
border-bottom-color: #f00;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.tab-container .content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 页面布局 */
|
||||
.main {
|
||||
padding: 30px 100px;
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.main .logo {
|
||||
color: #333;
|
||||
text-align: left;
|
||||
margin-bottom: 30px;
|
||||
line-height: 1;
|
||||
height: 110px;
|
||||
margin-top: -50px;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.main .logo a {
|
||||
font-size: 160px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.helps {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.helps pre {
|
||||
padding: 20px;
|
||||
margin: 10px 0;
|
||||
border: solid 1px #e7e1cd;
|
||||
background-color: #fffdef;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.icon_lists {
|
||||
width: 100% !important;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.icon_lists li {
|
||||
width: 100px;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 20px;
|
||||
text-align: center;
|
||||
list-style: none !important;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.icon_lists li .code-name {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.icon_lists .icon {
|
||||
display: block;
|
||||
height: 100px;
|
||||
line-height: 100px;
|
||||
font-size: 42px;
|
||||
margin: 10px auto;
|
||||
color: #333;
|
||||
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
-moz-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
transition: font-size 0.25s linear, width 0.25s linear;
|
||||
}
|
||||
|
||||
.icon_lists .icon:hover {
|
||||
font-size: 100px;
|
||||
}
|
||||
|
||||
.icon_lists .svg-icon {
|
||||
/* 通过设置 font-size 来改变图标大小 */
|
||||
width: 1em;
|
||||
/* 图标和文字相邻时,垂直对齐 */
|
||||
vertical-align: -0.15em;
|
||||
/* 通过设置 color 来改变 SVG 的颜色/fill */
|
||||
fill: currentColor;
|
||||
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
|
||||
normalize.css 中也包含这行 */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.icon_lists li .name,
|
||||
.icon_lists li .code-name {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* markdown 样式 */
|
||||
.markdown {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.markdown img {
|
||||
vertical-align: middle;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
color: #404040;
|
||||
font-weight: 500;
|
||||
line-height: 40px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown h2,
|
||||
.markdown h3,
|
||||
.markdown h4,
|
||||
.markdown h5,
|
||||
.markdown h6 {
|
||||
color: #404040;
|
||||
margin: 1.6em 0 0.6em 0;
|
||||
font-weight: 500;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.markdown h2 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.markdown h3 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.markdown h4 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.markdown h5 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown h6 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown hr {
|
||||
height: 1px;
|
||||
border: 0;
|
||||
background: #e9e9e9;
|
||||
margin: 16px 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown p {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown>p,
|
||||
.markdown>blockquote,
|
||||
.markdown>.highlight,
|
||||
.markdown>ol,
|
||||
.markdown>ul {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.markdown ul>li {
|
||||
list-style: circle;
|
||||
}
|
||||
|
||||
.markdown>ul li,
|
||||
.markdown blockquote ul>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown>ul li p,
|
||||
.markdown>ol li p {
|
||||
margin: 0.6em 0;
|
||||
}
|
||||
|
||||
.markdown ol>li {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
.markdown>ol li,
|
||||
.markdown blockquote ol>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown code {
|
||||
margin: 0 3px;
|
||||
padding: 0 5px;
|
||||
background: #eee;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.markdown strong,
|
||||
.markdown b {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown>table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0px;
|
||||
empty-cells: show;
|
||||
border: 1px solid #e9e9e9;
|
||||
width: 95%;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown>table th {
|
||||
white-space: nowrap;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown>table th,
|
||||
.markdown>table td {
|
||||
border: 1px solid #e9e9e9;
|
||||
padding: 8px 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.markdown>table th {
|
||||
background: #F7F7F7;
|
||||
}
|
||||
|
||||
.markdown blockquote {
|
||||
font-size: 90%;
|
||||
color: #999;
|
||||
border-left: 4px solid #e9e9e9;
|
||||
padding-left: 0.8em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown blockquote p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.markdown .anchor {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.markdown .waiting {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.markdown h1:hover .anchor,
|
||||
.markdown h2:hover .anchor,
|
||||
.markdown h3:hover .anchor,
|
||||
.markdown h4:hover .anchor,
|
||||
.markdown h5:hover .anchor,
|
||||
.markdown h6:hover .anchor {
|
||||
opacity: 1;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.markdown>br,
|
||||
.markdown>p>br {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
background: white;
|
||||
padding: 0.5em;
|
||||
color: #333333;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-meta {
|
||||
color: #969896;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-strong,
|
||||
.hljs-emphasis,
|
||||
.hljs-quote {
|
||||
color: #df5000;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag,
|
||||
.hljs-type {
|
||||
color: #a71d5d;
|
||||
}
|
||||
|
||||
.hljs-literal,
|
||||
.hljs-symbol,
|
||||
.hljs-bullet,
|
||||
.hljs-attribute {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-section,
|
||||
.hljs-name {
|
||||
color: #63a35c;
|
||||
}
|
||||
|
||||
.hljs-tag {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-attr,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-pseudo {
|
||||
color: #795da3;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
color: #55a532;
|
||||
background-color: #eaffea;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
color: #bd2c00;
|
||||
background-color: #ffecec;
|
||||
}
|
||||
|
||||
.hljs-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 代码高亮 */
|
||||
/* PrismJS 1.15.0
|
||||
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
|
||||
/**
|
||||
* prism.js default theme for JavaScript, CSS and HTML
|
||||
* Based on dabblet (http://dabblet.com)
|
||||
* @author Lea Verou
|
||||
*/
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: black;
|
||||
background: none;
|
||||
text-shadow: 0 1px white;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection,
|
||||
pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection,
|
||||
code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection,
|
||||
pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection,
|
||||
code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
@media print {
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre)>code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #f5f2f0;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre)>code[class*="language-"] {
|
||||
padding: .1em;
|
||||
border-radius: .3em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: slategray;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #905;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #690;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #9a6e3a;
|
||||
background: hsla(0, 0%, 100%, .5);
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: #07a;
|
||||
}
|
||||
|
||||
.token.function,
|
||||
.token.class-name {
|
||||
color: #DD4A68;
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: #e90;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
510
src/assets/fonts/demo_index.html
Normal file
@ -0,0 +1,510 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>iconfont Demo</title>
|
||||
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
|
||||
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
|
||||
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
|
||||
<link rel="stylesheet" href="demo.css">
|
||||
<link rel="stylesheet" href="iconfont.css">
|
||||
<script src="iconfont.js"></script>
|
||||
<!-- jQuery -->
|
||||
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
|
||||
<!-- 代码高亮 -->
|
||||
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
|
||||
<style>
|
||||
.main .logo {
|
||||
margin-top: 0;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.main .logo a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.main .logo .sub-title {
|
||||
margin-left: 0.5em;
|
||||
font-size: 22px;
|
||||
color: #fff;
|
||||
background: linear-gradient(-45deg, #3967FF, #B500FE);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main">
|
||||
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
|
||||
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
|
||||
|
||||
</a></h1>
|
||||
<div class="nav-tabs">
|
||||
<ul id="tabs" class="dib-box">
|
||||
<li class="dib active"><span>Unicode</span></li>
|
||||
<li class="dib"><span>Font class</span></li>
|
||||
<li class="dib"><span>Symbol</span></li>
|
||||
</ul>
|
||||
|
||||
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=3820793" target="_blank" class="nav-more">查看项目</a>
|
||||
|
||||
</div>
|
||||
<div class="tab-container">
|
||||
<div class="content unicode" style="display: block;">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">管理员认证</div>
|
||||
<div class="code-name">&#xeacc;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">好友</div>
|
||||
<div class="code-name">&#xe602;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">管理员</div>
|
||||
<div class="code-name">&#xe681;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">密码(关)</div>
|
||||
<div class="code-name">&#xe638;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">天猫公告</div>
|
||||
<div class="code-name">&#xe600;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">首页_fill</div>
|
||||
<div class="code-name">&#xe6ca;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">搜索小</div>
|
||||
<div class="code-name">&#xe8d6;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">图书期刊</div>
|
||||
<div class="code-name">&#xe618;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">留言</div>
|
||||
<div class="code-name">&#xe614;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">退出</div>
|
||||
<div class="code-name">&#xe606;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">个人信息</div>
|
||||
<div class="code-name">&#xe601;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">公告</div>
|
||||
<div class="code-name">&#xe8c4;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">规则设置</div>
|
||||
<div class="code-name">&#xe6dc;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">违章查询</div>
|
||||
<div class="code-name">&#xe607;</div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<div class="article markdown">
|
||||
<h2 id="unicode-">Unicode 引用</h2>
|
||||
<hr>
|
||||
|
||||
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
|
||||
<ul>
|
||||
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
|
||||
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
|
||||
</blockquote>
|
||||
<p>Unicode 使用步骤如下:</p>
|
||||
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
|
||||
<pre><code class="language-css"
|
||||
>@font-face {
|
||||
font-family: 'iconfont';
|
||||
src: url('iconfont.woff2?t=1672483284386') format('woff2'),
|
||||
url('iconfont.woff?t=1672483284386') format('woff'),
|
||||
url('iconfont.ttf?t=1672483284386') format('truetype');
|
||||
}
|
||||
</code></pre>
|
||||
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
||||
<pre><code class="language-css"
|
||||
>.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
</code></pre>
|
||||
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
|
||||
<pre>
|
||||
<code class="language-html"
|
||||
><span class="iconfont">&#x33;</span>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content font-class">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-guanliyuanrenzheng"></span>
|
||||
<div class="name">
|
||||
管理员认证
|
||||
</div>
|
||||
<div class="code-name">.icon-guanliyuanrenzheng
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-haoyou"></span>
|
||||
<div class="name">
|
||||
好友
|
||||
</div>
|
||||
<div class="code-name">.icon-haoyou
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-guanliyuan"></span>
|
||||
<div class="name">
|
||||
管理员
|
||||
</div>
|
||||
<div class="code-name">.icon-guanliyuan
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-tianchongxing-"></span>
|
||||
<div class="name">
|
||||
密码(关)
|
||||
</div>
|
||||
<div class="code-name">.icon-tianchongxing-
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-gonggao"></span>
|
||||
<div class="name">
|
||||
天猫公告
|
||||
</div>
|
||||
<div class="code-name">.icon-gonggao
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-shouyefill"></span>
|
||||
<div class="name">
|
||||
首页_fill
|
||||
</div>
|
||||
<div class="code-name">.icon-shouyefill
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-sousuoxiao"></span>
|
||||
<div class="name">
|
||||
搜索小
|
||||
</div>
|
||||
<div class="code-name">.icon-sousuoxiao
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-tushuqikan"></span>
|
||||
<div class="name">
|
||||
图书期刊
|
||||
</div>
|
||||
<div class="code-name">.icon-tushuqikan
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-liuyan"></span>
|
||||
<div class="name">
|
||||
留言
|
||||
</div>
|
||||
<div class="code-name">.icon-liuyan
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-tuichu"></span>
|
||||
<div class="name">
|
||||
退出
|
||||
</div>
|
||||
<div class="code-name">.icon-tuichu
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-gerenxinxi"></span>
|
||||
<div class="name">
|
||||
个人信息
|
||||
</div>
|
||||
<div class="code-name">.icon-gerenxinxi
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-gonggao1"></span>
|
||||
<div class="name">
|
||||
公告
|
||||
</div>
|
||||
<div class="code-name">.icon-gonggao1
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-guizeshezhi"></span>
|
||||
<div class="name">
|
||||
规则设置
|
||||
</div>
|
||||
<div class="code-name">.icon-guizeshezhi
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icon-weizhangchaxun"></span>
|
||||
<div class="name">
|
||||
违章查询
|
||||
</div>
|
||||
<div class="code-name">.icon-weizhangchaxun
|
||||
</div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<div class="article markdown">
|
||||
<h2 id="font-class-">font-class 引用</h2>
|
||||
<hr>
|
||||
|
||||
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
|
||||
<p>与 Unicode 使用方式相比,具有如下特点:</p>
|
||||
<ul>
|
||||
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
|
||||
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
|
||||
</ul>
|
||||
<p>使用步骤如下:</p>
|
||||
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
|
||||
<pre><code class="language-html"><link rel="stylesheet" href="./iconfont.css">
|
||||
</code></pre>
|
||||
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
|
||||
<pre><code class="language-html"><span class="iconfont icon-xxx"></span>
|
||||
</code></pre>
|
||||
<blockquote>
|
||||
<p>"
|
||||
iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content symbol">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-guanliyuanrenzheng"></use>
|
||||
</svg>
|
||||
<div class="name">管理员认证</div>
|
||||
<div class="code-name">#icon-guanliyuanrenzheng</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-haoyou"></use>
|
||||
</svg>
|
||||
<div class="name">好友</div>
|
||||
<div class="code-name">#icon-haoyou</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-guanliyuan"></use>
|
||||
</svg>
|
||||
<div class="name">管理员</div>
|
||||
<div class="code-name">#icon-guanliyuan</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-tianchongxing-"></use>
|
||||
</svg>
|
||||
<div class="name">密码(关)</div>
|
||||
<div class="code-name">#icon-tianchongxing-</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-gonggao"></use>
|
||||
</svg>
|
||||
<div class="name">天猫公告</div>
|
||||
<div class="code-name">#icon-gonggao</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-shouyefill"></use>
|
||||
</svg>
|
||||
<div class="name">首页_fill</div>
|
||||
<div class="code-name">#icon-shouyefill</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-sousuoxiao"></use>
|
||||
</svg>
|
||||
<div class="name">搜索小</div>
|
||||
<div class="code-name">#icon-sousuoxiao</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-tushuqikan"></use>
|
||||
</svg>
|
||||
<div class="name">图书期刊</div>
|
||||
<div class="code-name">#icon-tushuqikan</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-liuyan"></use>
|
||||
</svg>
|
||||
<div class="name">留言</div>
|
||||
<div class="code-name">#icon-liuyan</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-tuichu"></use>
|
||||
</svg>
|
||||
<div class="name">退出</div>
|
||||
<div class="code-name">#icon-tuichu</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-gerenxinxi"></use>
|
||||
</svg>
|
||||
<div class="name">个人信息</div>
|
||||
<div class="code-name">#icon-gerenxinxi</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-gonggao1"></use>
|
||||
</svg>
|
||||
<div class="name">公告</div>
|
||||
<div class="code-name">#icon-gonggao1</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-guizeshezhi"></use>
|
||||
</svg>
|
||||
<div class="name">规则设置</div>
|
||||
<div class="code-name">#icon-guizeshezhi</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-weizhangchaxun"></use>
|
||||
</svg>
|
||||
<div class="name">违章查询</div>
|
||||
<div class="code-name">#icon-weizhangchaxun</div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<div class="article markdown">
|
||||
<h2 id="symbol-">Symbol 引用</h2>
|
||||
<hr>
|
||||
|
||||
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
|
||||
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
|
||||
<ul>
|
||||
<li>支持多色图标了,不再受单色限制。</li>
|
||||
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
|
||||
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
|
||||
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
|
||||
</ul>
|
||||
<p>使用步骤如下:</p>
|
||||
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
|
||||
<pre><code class="language-html"><script src="./iconfont.js"></script>
|
||||
</code></pre>
|
||||
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
|
||||
<pre><code class="language-html"><style>
|
||||
.icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
</code></pre>
|
||||
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
|
||||
<pre><code class="language-html"><svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#icon-xxx"></use>
|
||||
</svg>
|
||||
</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.tab-container .content:first').show()
|
||||
|
||||
$('#tabs li').click(function (e) {
|
||||
var tabContent = $('.tab-container .content')
|
||||
var index = $(this).index()
|
||||
|
||||
if ($(this).hasClass('active')) {
|
||||
return
|
||||
} else {
|
||||
$('#tabs li').removeClass('active')
|
||||
$(this).addClass('active')
|
||||
|
||||
tabContent.hide().eq(index).fadeIn()
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
80
src/assets/fonts/iconfont.css
Normal file
@ -0,0 +1,80 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 3820793 */
|
||||
src: url('iconfont.woff2?t=1672483284386') format('woff2'),
|
||||
url('iconfont.woff?t=1672483284386') format('woff'),
|
||||
url('iconfont.ttf?t=1672483284386') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-guanliyuanrenzheng:before {
|
||||
content: "\eacc";
|
||||
font-size: 48px !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.icon-haoyou:before {
|
||||
content: "\e602";
|
||||
font-size: 48px !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.icon-guanliyuan:before {
|
||||
content: "\e681";
|
||||
font-size: 48px !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.icon-tianchongxing-:before {
|
||||
content: "\e638";
|
||||
}
|
||||
|
||||
.icon-gonggao:before {
|
||||
content: "\e600";
|
||||
}
|
||||
|
||||
.icon-shouyefill:before {
|
||||
content: "\e6ca";
|
||||
}
|
||||
|
||||
.icon-sousuoxiao:before {
|
||||
content: "\e8d6";
|
||||
}
|
||||
|
||||
.icon-tushuqikan:before {
|
||||
content: "\e618";
|
||||
}
|
||||
|
||||
.icon-liuyan:before {
|
||||
content: "\e614";
|
||||
}
|
||||
|
||||
.icon-tuichu:before {
|
||||
content: "\e606";
|
||||
}
|
||||
|
||||
.icon-gerenxinxi:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.icon-gonggao1:before {
|
||||
content: "\e8c4";
|
||||
}
|
||||
|
||||
.icon-guizeshezhi:before {
|
||||
content: "\e6dc";
|
||||
}
|
||||
|
||||
.icon-weizhangchaxun:before {
|
||||
content: "\e607";
|
||||
}
|
||||
|
||||
.icon-zhinengfenxi:before {
|
||||
content: "\e699";
|
||||
}
|
1
src/assets/fonts/iconfont.js
Normal file
108
src/assets/fonts/iconfont.json
Normal file
@ -0,0 +1,108 @@
|
||||
{
|
||||
"id": "3820793",
|
||||
"name": "BookManageIcons",
|
||||
"font_family": "iconfont",
|
||||
"css_prefix_text": "icon-",
|
||||
"description": "图书管理系统的图标库",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "5387410",
|
||||
"name": "管理员认证",
|
||||
"font_class": "guanliyuanrenzheng",
|
||||
"unicode": "eacc",
|
||||
"unicode_decimal": 60108
|
||||
},
|
||||
{
|
||||
"icon_id": "1260",
|
||||
"name": "好友",
|
||||
"font_class": "haoyou",
|
||||
"unicode": "e602",
|
||||
"unicode_decimal": 58882
|
||||
},
|
||||
{
|
||||
"icon_id": "11810477",
|
||||
"name": "管理员",
|
||||
"font_class": "guanliyuan",
|
||||
"unicode": "e681",
|
||||
"unicode_decimal": 59009
|
||||
},
|
||||
{
|
||||
"icon_id": "6446244",
|
||||
"name": "密码(关)",
|
||||
"font_class": "tianchongxing-",
|
||||
"unicode": "e638",
|
||||
"unicode_decimal": 58936
|
||||
},
|
||||
{
|
||||
"icon_id": "54854",
|
||||
"name": "天猫公告",
|
||||
"font_class": "gonggao",
|
||||
"unicode": "e600",
|
||||
"unicode_decimal": 58880
|
||||
},
|
||||
{
|
||||
"icon_id": "673798",
|
||||
"name": "首页_fill",
|
||||
"font_class": "shouyefill",
|
||||
"unicode": "e6ca",
|
||||
"unicode_decimal": 59082
|
||||
},
|
||||
{
|
||||
"icon_id": "2076426",
|
||||
"name": "搜索小",
|
||||
"font_class": "sousuoxiao",
|
||||
"unicode": "e8d6",
|
||||
"unicode_decimal": 59606
|
||||
},
|
||||
{
|
||||
"icon_id": "2129721",
|
||||
"name": "图书期刊",
|
||||
"font_class": "tushuqikan",
|
||||
"unicode": "e618",
|
||||
"unicode_decimal": 58904
|
||||
},
|
||||
{
|
||||
"icon_id": "3267400",
|
||||
"name": "留言",
|
||||
"font_class": "liuyan",
|
||||
"unicode": "e614",
|
||||
"unicode_decimal": 58900
|
||||
},
|
||||
{
|
||||
"icon_id": "7738011",
|
||||
"name": "退出",
|
||||
"font_class": "tuichu",
|
||||
"unicode": "e606",
|
||||
"unicode_decimal": 58886
|
||||
},
|
||||
{
|
||||
"icon_id": "10359979",
|
||||
"name": "个人信息",
|
||||
"font_class": "gerenxinxi",
|
||||
"unicode": "e601",
|
||||
"unicode_decimal": 58881
|
||||
},
|
||||
{
|
||||
"icon_id": "11372764",
|
||||
"name": "公告",
|
||||
"font_class": "gonggao1",
|
||||
"unicode": "e8c4",
|
||||
"unicode_decimal": 59588
|
||||
},
|
||||
{
|
||||
"icon_id": "13584358",
|
||||
"name": "规则设置",
|
||||
"font_class": "guizeshezhi",
|
||||
"unicode": "e6dc",
|
||||
"unicode_decimal": 59100
|
||||
},
|
||||
{
|
||||
"icon_id": "16102269",
|
||||
"name": "违章查询",
|
||||
"font_class": "weizhangchaxun",
|
||||
"unicode": "e607",
|
||||
"unicode_decimal": 58887
|
||||
},
|
||||
|
||||
]
|
||||
}
|
BIN
src/assets/fonts/iconfont.ttf
Normal file
BIN
src/assets/fonts/iconfont.woff
Normal file
BIN
src/assets/fonts/iconfont.woff2
Normal file
BIN
src/assets/images/404.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
src/assets/images/CarAndSkyMin.jpg
Normal file
After Width: | Height: | Size: 372 KiB |
BIN
src/assets/images/animeboySkyMin.jpg
Normal file
After Width: | Height: | Size: 448 KiB |
BIN
src/assets/images/book1.jpg
Normal file
After Width: | Height: | Size: 418 KiB |
BIN
src/assets/images/book2.jpg
Normal file
After Width: | Height: | Size: 308 KiB |
BIN
src/assets/images/book3.jpg
Normal file
After Width: | Height: | Size: 373 KiB |
BIN
src/assets/images/digitalCityMin.jpg
Normal file
After Width: | Height: | Size: 458 KiB |
BIN
src/assets/images/dinosaur.jpg
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
src/assets/images/landScapeAndNightMin.jpg
Normal file
After Width: | Height: | Size: 637 KiB |
BIN
src/assets/images/police.png
Normal file
After Width: | Height: | Size: 11 KiB |
16
src/components/404/404.vue
Normal file
@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
<style>
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background: url(https://xxx.xiaobaitiao.icu/img/icu/202312211243626.png) no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
84
src/components/Admin/AdminManage.vue
Normal file
@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 面包屑导航区域 -->
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item>系统管理</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>借阅量查询</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<div style="width: 100%; height: 500px">
|
||||
<ChartLine ref="chart_line_one" />
|
||||
</div>
|
||||
<div style="width: 100%; height: 500px; margin-top: 50px">
|
||||
<PieChart ref="chart_pie_one"></PieChart>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ChartLine from "../Chart/ChartLint.vue";
|
||||
import PieChart from "../Chart/PieChart.vue";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
name: "借阅量",
|
||||
xData: ["", "2020-03", "2020-04", "2020-05"],
|
||||
yData: [30, 132, 80, 134],
|
||||
allData: {
|
||||
xData: ["", "2020-03", "2020-04", "2020-05"],
|
||||
yData: [30, 132, 80, 134],
|
||||
},
|
||||
pieData: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// async getBorrowData() {
|
||||
// console.log(res);
|
||||
// },
|
||||
},
|
||||
// created() {
|
||||
// this.getBorrowData();
|
||||
// },
|
||||
async mounted() {
|
||||
// console.log(this.$refs);
|
||||
const { data: res } = await this.$http.get("admin/get_borrowdata");
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 800,
|
||||
});
|
||||
const { data: res2 } = await this.$http.get(
|
||||
"admin/get_borrowtype_statistics"
|
||||
);
|
||||
if (res2.status !== 200) {
|
||||
return this.$message.error(res2.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res2.msg,
|
||||
duration: 800,
|
||||
});
|
||||
console.log(res2);
|
||||
for (var element of res2.data) {
|
||||
this.pieData.push({
|
||||
name: element.bookTypes,
|
||||
value: element.borrowNumbers,
|
||||
});
|
||||
}
|
||||
this.allData.xData = res.data.borrowDates;
|
||||
this.allData.yData = res.data.borrowNumber;
|
||||
this.$refs.chart_line_one.initChart(
|
||||
this.name,
|
||||
this.allData.xData,
|
||||
this.allData.yData
|
||||
);
|
||||
this.$refs.chart_pie_one.initChart(this.pieData);
|
||||
},
|
||||
components: {
|
||||
ChartLine,
|
||||
PieChart,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
427
src/components/Admin/BookAdminManage.vue
Normal file
@ -0,0 +1,427 @@
|
||||
<template>
|
||||
<div class="search_container">
|
||||
<!-- 面包屑导航区域 -->
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item>首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>图书管理员管理</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<el-card shadow="always">
|
||||
<!-- 搜索内容和导出区域 -->
|
||||
<el-row>
|
||||
<el-col :span="4">
|
||||
<el-button type="primary" @click="showAddDialog()">
|
||||
<i class="el-icon-plus"></i> 添加管理员</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<download-excel
|
||||
class="export-excel-wrapper"
|
||||
:data="tableData"
|
||||
:fields="json_fields"
|
||||
:header="title"
|
||||
name="图书管理员.xls"
|
||||
>
|
||||
<!-- 上面可以自定义自己的样式,还可以引用其他组件button -->
|
||||
<el-button type="primary" class="el-icon-printer" size="mini"
|
||||
>导出Excel</el-button
|
||||
>
|
||||
</download-excel>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<el-button
|
||||
type="primary"
|
||||
class="el-icon-printer"
|
||||
size="mini"
|
||||
@click="downLoad"
|
||||
>导出PDF</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
|
||||
<el-button type="success" class="el-icon-full-screen" size="mini" @click="fullScreen"
|
||||
>全屏</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 表格区域 -->
|
||||
<el-table
|
||||
:data="tableData"
|
||||
border
|
||||
style="width: 100%"
|
||||
stripe
|
||||
id="pdfDom"
|
||||
:default-sort="{ prop: 'bookAdminId', order: 'ascending' }"
|
||||
v-loading="loading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)"
|
||||
>
|
||||
<el-table-column prop="bookAdminId" label="ID" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="username" label="账号"> </el-table-column>
|
||||
<el-table-column prop="bookAdminName" label="姓名"> </el-table-column>
|
||||
<el-table-column prop="email" label="邮箱"> </el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template slot-scope="scope">
|
||||
<!-- 修改按钮 -->
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="修改"
|
||||
placement="top"
|
||||
:enterable="false"
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
@click="showEditDialog(scope.row.bookAdminId)"
|
||||
></el-button
|
||||
></el-tooltip>
|
||||
|
||||
<!-- 删除按钮 -->
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="删除"
|
||||
placement="top"
|
||||
:enterable="false"
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
@click="removeUserById(scope.row.bookAdminId)"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页查询区域 -->
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="queryInfo.pageNum"
|
||||
:page-sizes="[1, 2, 3, 4, 5]"
|
||||
:page-size="queryInfo.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="this.total"
|
||||
>
|
||||
</el-pagination>
|
||||
<!-- 修改公告的对话框 -->
|
||||
<el-dialog
|
||||
title="修改管理员"
|
||||
:visible.sync="editDialogVisible"
|
||||
width="50%"
|
||||
@close="editDialogClosed"
|
||||
>
|
||||
<el-form
|
||||
:model="editForm"
|
||||
ref="editFormRef"
|
||||
:rules="editFormRules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="姓名" prop="bookAdminName">
|
||||
<el-input v-model="editForm.bookAdminName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="账号" prop="username">
|
||||
<el-input v-model="editForm.username"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input
|
||||
v-model="editForm.password"
|
||||
type="password"
|
||||
show-password
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="editForm.email"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="editDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="updateBookAdmin">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<!-- 添加管理员的对话框 -->
|
||||
<el-dialog
|
||||
title="添加管理员"
|
||||
:visible.sync="addDialogVisible"
|
||||
width="50%"
|
||||
@close="addDialogClosed"
|
||||
>
|
||||
<el-form
|
||||
:model="addForm"
|
||||
ref="addFormRef"
|
||||
:rules="addFormRules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="姓名" prop="bookAdminName">
|
||||
<el-input v-model="addForm.bookAdminName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="账号" prop="username">
|
||||
<el-input v-model="addForm.username"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input v-model="addForm.password"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="addForm.email"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="addDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="addBookAdmin">添加管理员</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
editDialogVisible: false,
|
||||
editForm: {
|
||||
username: "",
|
||||
password: "",
|
||||
email: "",
|
||||
bookAdminName: "",
|
||||
},
|
||||
editFormRules: {
|
||||
username: [
|
||||
{ required: true, message: "请输入账号", trigger: "blur" },
|
||||
{
|
||||
min: 5,
|
||||
max: 30,
|
||||
message: "长度在5到30个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: "请输入密码", trigger: "blur" },
|
||||
{
|
||||
min: 6,
|
||||
max: 50,
|
||||
message: "长度在6到50个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
email: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入正确的邮箱",
|
||||
trigger: "blur",
|
||||
type: "email",
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 50,
|
||||
message: "长度在6到50个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
bookAdminName: [
|
||||
{ required: true, message: "请输入姓名", trigger: "blur" },
|
||||
],
|
||||
},
|
||||
addDialogVisible: false,
|
||||
addForm: {
|
||||
username: "",
|
||||
password: "",
|
||||
email: "",
|
||||
bookAdminName: "",
|
||||
},
|
||||
addFormRules: {
|
||||
username: [
|
||||
{ required: true, message: "请输入账号", trigger: "blur" },
|
||||
{
|
||||
min: 5,
|
||||
max: 30,
|
||||
message: "长度在5到30个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: "请输入密码", trigger: "blur" },
|
||||
{
|
||||
min: 6,
|
||||
max: 50,
|
||||
message: "长度在6到50个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
email: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入正确的邮箱",
|
||||
trigger: "blur",
|
||||
type: "email",
|
||||
},
|
||||
{
|
||||
min: 6,
|
||||
max: 50,
|
||||
message: "长度在6到50个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
bookAdminName: [
|
||||
{ required: true, message: "请输入姓名", trigger: "blur" },
|
||||
],
|
||||
},
|
||||
queryInfo: {
|
||||
pageNum: 1,
|
||||
pageSize: 5,
|
||||
},
|
||||
total: 0,
|
||||
title: "图书管理员",
|
||||
json_fields: {
|
||||
图书管理员编号: "bookAdminId",
|
||||
用户名: "username",
|
||||
姓名: "bookAdminName",
|
||||
邮箱: "email",
|
||||
},
|
||||
loading:true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(val) {
|
||||
this.queryInfo.pageSize = val;
|
||||
this.getBookAdminList();
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.queryInfo.pageNum = val;
|
||||
this.getBookAdminList();
|
||||
},
|
||||
//让修改公告的对话框可见,并从数据库中回显数据
|
||||
async showEditDialog(id) {
|
||||
const { data: res } = await this.$http.get("admin/get_bookadmin/" + id);
|
||||
console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.editForm = res.data;
|
||||
// 让修改公告的对话框可见
|
||||
this.editDialogVisible = true;
|
||||
},
|
||||
//监听修改对话框的关闭,一旦对话框关闭,就重置表单,回显数据
|
||||
editDialogClosed() {
|
||||
this.$refs.editFormRef.resetFields();
|
||||
},
|
||||
//删除公告
|
||||
async removeUserById(id) {
|
||||
//弹框,询问用户是否删除数据
|
||||
const confirmResult = await this.$confirm(
|
||||
"此操作将永久删除该公告, 是否继续?",
|
||||
"提示",
|
||||
{
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}
|
||||
).catch((error) => {
|
||||
return error;
|
||||
});
|
||||
//如果用户确认删除,则返回值为字符串confirm
|
||||
//如果用户取消删除,则返回值为字符串cancel
|
||||
// console.log(confirmResult);
|
||||
if (confirmResult !== "confirm") {
|
||||
return this.$message.info("已经取消删除");
|
||||
}
|
||||
//如果用户确认删除,那么下一步就是发送axios请求,检查响应状态码是否成功,成功则返回删除成功,否则返回删除失败
|
||||
const { data: res } = await this.$http.delete(
|
||||
"admin/delete_bookadmin/" + id
|
||||
);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1000,
|
||||
});
|
||||
this.getBookAdminList();
|
||||
},
|
||||
//监听添加公告对话框的关闭,一旦对话框关闭,就重置表单
|
||||
addDialogClosed() {
|
||||
this.$refs.addFormRef.resetFields();
|
||||
},
|
||||
//当用户点击发送新公告时,让添加对话框的visible改为true
|
||||
showAddDialog() {
|
||||
this.addDialogVisible = true;
|
||||
},
|
||||
// 获取图书管理员列表
|
||||
async getBookAdminList() {
|
||||
this.loading = true;
|
||||
const { data: res } = await this.$http.post(
|
||||
"admin/get_bookadminlist",
|
||||
this.queryInfo
|
||||
);
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
this.loading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1000,
|
||||
});
|
||||
this.tableData = res.data.records;
|
||||
this.total = parseInt(res.data.total);
|
||||
this.loading = false;
|
||||
},
|
||||
async addBookAdmin() {
|
||||
const { data: res } = await this.$http.post(
|
||||
"admin/add_bookadmin",
|
||||
this.addForm
|
||||
);
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1500,
|
||||
});
|
||||
this.getBookAdminList();
|
||||
this.addDialogVisible = false;
|
||||
},
|
||||
async updateBookAdmin() {
|
||||
const { data: res } = await this.$http.put(
|
||||
"admin/update_bookadmin",
|
||||
this.editForm
|
||||
);
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1500,
|
||||
});
|
||||
this.getBookAdminList();
|
||||
this.editDialogVisible = false;
|
||||
},
|
||||
downLoad() {
|
||||
this.getPdf(this.title); //参数是下载的pdf文件名
|
||||
},
|
||||
fullScreen(){
|
||||
// Dom对象的一个属性: 可以用来判断当前是否为全屏模式(trueORfalse)
|
||||
let full = document.fullscreenElement;
|
||||
// 切换为全屏模式
|
||||
if(!full){
|
||||
// 文档根节点的方法requestFullscreen实现全屏模式
|
||||
document.documentElement.requestFullscreen();
|
||||
}else{
|
||||
// 退出全屏模式
|
||||
document.exitFullscreen();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getBookAdminList();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
537
src/components/Admin/BookManage.vue
Normal file
@ -0,0 +1,537 @@
|
||||
<template>
|
||||
<div class="search_container">
|
||||
<!-- 面包屑导航区域 -->
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item>首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>书籍管理</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<el-card shadow="always">
|
||||
<!-- 搜索内容和导出区域 -->
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="6">条件搜索:<el-select v-model="queryInfo.condition" filterable placeholder="请选择"
|
||||
style="margin-left: 15px">
|
||||
<el-option v-for="item in searchs" :key="item.value" :label="item.label" :value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-input placeholder="请输入内容" v-model="queryInfo.query" class="input-with-select"
|
||||
@keyup.enter.native="getBookList">
|
||||
<el-button slot="append" icon="el-icon-search" @click="getBookList"></el-button> </el-input></el-col>
|
||||
<el-col :span="2">
|
||||
<el-button type="primary" @click="showAddDialog()" size="default">
|
||||
<i class="el-icon-plus"></i> 添加书籍</el-button>
|
||||
</el-col>
|
||||
<el-col :span="3" style="float:right">
|
||||
<el-upload class="upload-demo" ref="upload" name="files" action="http://localhost:8889/api/admin/updown"
|
||||
:on-preview="handlePreview" :on-remove="handleRemove" :headers="headers"
|
||||
:file-list="fileList"
|
||||
:on-success="onSuccess"
|
||||
:auto-upload="false">
|
||||
<el-button slot="trigger" size="mini" type="primary" title="从Excel批量导入图书">选取文件</el-button>
|
||||
<el-button size="mini" type="success" @click="submitUpload" style="margin-left: 5px;">上传</el-button>
|
||||
</el-upload>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<download-excel class="export-excel-wrapper" :data="tableData" :fields="json_fields" :header="title"
|
||||
name="书籍管理.xls">
|
||||
<!-- 上面可以自定义自己的样式,还可以引用其他组件button -->
|
||||
<el-button type="primary" class="el-icon-printer" size="mini">导出Excel</el-button>
|
||||
</download-excel>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<el-button type="primary" class="el-icon-printer" size="mini" @click="downLoad">导出PDF</el-button>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<el-button type="warning" @click="removeBatch()" size="mini">
|
||||
<i class="el-icon-delete"></i>批量删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
|
||||
<el-button type="success" class="el-icon-full-screen" size="mini" @click="fullScreen">全屏</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 表格区域 -->
|
||||
<el-table :data="tableData" border height="520" style="width: 100%" stripe id="pdfDom"
|
||||
:default-sort="{ prop: 'bookNumber', order: 'ascending' }" v-loading="loading" element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading" element-loading-background="rgba(0, 0, 0, 0.8)"
|
||||
@selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55"> </el-table-column>
|
||||
<el-table-column type="index"></el-table-column>
|
||||
<el-table-column prop="bookNumber" label="图书编号" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="bookName" label="书名" width="80px">
|
||||
</el-table-column>
|
||||
<el-table-column prop="bookAuthor" label="作者" width="80px">
|
||||
</el-table-column>
|
||||
<el-table-column prop="bookLibrary" label="图书馆" width="80px">
|
||||
</el-table-column>
|
||||
<el-table-column prop="bookType" label="分类" width="80px">
|
||||
</el-table-column>
|
||||
<el-table-column prop="bookLocation" label="位置" sortable width="80px">
|
||||
</el-table-column>
|
||||
<el-table-column prop="bookStatus" label="状态" sortable width="80px">
|
||||
</el-table-column>
|
||||
<el-table-column prop="bookDescription" label="描述" width="400px">
|
||||
</el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template slot-scope="scope">
|
||||
<!-- 修改按钮 -->
|
||||
<el-tooltip effect="dark" content="修改" placement="top" :enterable="false">
|
||||
<el-button type="primary" icon="el-icon-edit" size="mini"
|
||||
@click="showEditDialog(scope.row.bookId)"></el-button></el-tooltip>
|
||||
|
||||
<!-- 删除按钮 -->
|
||||
<el-tooltip effect="dark" content="删除" placement="top" :enterable="false">
|
||||
<el-button type="danger" icon="el-icon-delete" size="mini"
|
||||
@click="removeUserById(scope.row.bookId)"></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页查询区域 -->
|
||||
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
|
||||
:current-page="queryInfo.pageNum" :page-sizes="[1, 2, 3, 4, 5]" :page-size="queryInfo.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper" :total="this.total">
|
||||
</el-pagination>
|
||||
<!-- 修改规则的对话框 -->
|
||||
<el-dialog title="修改书籍" :visible.sync="editDialogVisible" width="50%" @close="editDialogClosed">
|
||||
<el-form :model="editForm" ref="editFormRef" :rules="editFormRules" label-width="120px">
|
||||
<el-form-item label="书名" prop="bookName">
|
||||
<el-input v-model="editForm.bookName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="作者" prop="bookAuthor">
|
||||
<el-input v-model="editForm.bookAuthor"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="图书馆">
|
||||
<el-radio-group v-model="editForm.bookLibrary">
|
||||
<el-radio-button label="南图"></el-radio-button>
|
||||
<el-radio-button label="北图"></el-radio-button>
|
||||
<el-radio-button label="教师之家"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="分类">
|
||||
<el-select v-model="editForm.bookType" placeholder="请选择">
|
||||
<el-option v-for="item in types" :key="item.typeId" :label="item.typeName" :value="item.typeId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="位置" prop="bookLocation">
|
||||
<el-input v-model="editForm.bookLocation"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="bookStatus">
|
||||
<el-radio-group v-model="editForm.bookStatus">
|
||||
<el-radio label="已借出">已借出</el-radio>
|
||||
<el-radio label="未借出">未借出</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="书籍简介" prop="bookDescription">
|
||||
<el-input type="textarea" v-model="editForm.bookDescription"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="editDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="updateBook">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<!-- 添加书籍的对话框 -->
|
||||
<el-dialog title="添加书籍" :visible.sync="addDialogVisible" width="50%" @close="addDialogClosed">
|
||||
<el-form :model="addForm" ref="addFormRef" :rules="addFormRules" label-width="120px">
|
||||
<el-form-item label="书名" prop="bookName">
|
||||
<el-input v-model="addForm.bookName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="作者" prop="bookAuthor">
|
||||
<el-input v-model="addForm.bookAuthor"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="图书馆">
|
||||
<el-radio-group v-model="addForm.bookLibrary">
|
||||
<el-radio-button label="南图"></el-radio-button>
|
||||
<el-radio-button label="北图"></el-radio-button>
|
||||
<el-radio-button label="教师之家"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="分类">
|
||||
<el-select v-model="addForm.bookTypeNumber" placeholder="请选择">
|
||||
<el-option v-for="item in types" :key="item.typeId" :label="item.typeName" :value="item.typeId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="位置" prop="bookLocation">
|
||||
<el-input v-model="addForm.bookLocation"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="bookStatus">
|
||||
<el-radio-group v-model="addForm.bookStatus">
|
||||
<el-radio label="已借出">已借出</el-radio>
|
||||
<el-radio label="未借出">未借出</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="书籍简介" prop="bookDescription">
|
||||
<el-input type="textarea" v-model="addForm.bookDescription"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="addDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="addBook">添加书籍</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
|
||||
editDialogVisible: false,
|
||||
editForm: {
|
||||
bookName: "",
|
||||
bookAuthor: "",
|
||||
bookLibrary: "南图",
|
||||
bookType: "",
|
||||
bookLocation: "",
|
||||
bookStatus: "",
|
||||
bookDescription: "",
|
||||
},
|
||||
editFormRules: {
|
||||
bookName: [
|
||||
{ required: true, message: "图书名称不能为空", trigger: "blur" },
|
||||
],
|
||||
bookAuthor: [
|
||||
{ required: true, message: "图书作者不能为空", trigger: "blur" },
|
||||
],
|
||||
bookLocation: [
|
||||
{ required: true, message: "图书位置不能为空", trigger: "blur" },
|
||||
],
|
||||
bookDescription: [
|
||||
{ required: true, message: "图书介绍不能为空", trigger: "blur" },
|
||||
],
|
||||
},
|
||||
addDialogVisible: false,
|
||||
addForm: {
|
||||
bookName: "",
|
||||
bookAuthor: "",
|
||||
bookLibrary: "南图",
|
||||
bookTypeNumber: "",
|
||||
bookLocation: "",
|
||||
bookStatus: "",
|
||||
bookDescription: "",
|
||||
},
|
||||
addFormRules: {
|
||||
bookName: [
|
||||
{ required: true, message: "图书名称不能为空", trigger: "blur" },
|
||||
],
|
||||
bookAuthor: [
|
||||
{ required: true, message: "图书作者不能为空", trigger: "blur" },
|
||||
],
|
||||
bookLocation: [
|
||||
{ required: true, message: "图书位置不能为空", trigger: "blur" },
|
||||
],
|
||||
bookDescription: [
|
||||
{ required: true, message: "图书介绍不能为空", trigger: "blur" },
|
||||
],
|
||||
},
|
||||
searchs: [
|
||||
{
|
||||
value: "book_number",
|
||||
label: "图书编号",
|
||||
},
|
||||
{
|
||||
value: "book_name",
|
||||
label: "书名",
|
||||
},
|
||||
{
|
||||
value: "book_author",
|
||||
label: "作者",
|
||||
},
|
||||
{
|
||||
value: "book_library",
|
||||
label: "图书馆",
|
||||
},
|
||||
{
|
||||
value: "book_location",
|
||||
label: "位置",
|
||||
},
|
||||
{
|
||||
value: "book_status",
|
||||
label: "状态",
|
||||
},
|
||||
{
|
||||
value: "book_description",
|
||||
label: "描述",
|
||||
},
|
||||
],
|
||||
queryInfo: {
|
||||
pageNum: 1,
|
||||
pageSize: 5,
|
||||
condition: "",
|
||||
query: "",
|
||||
},
|
||||
total: 0,
|
||||
types: [
|
||||
{
|
||||
typeId: "童话",
|
||||
typeName: "童话",
|
||||
},
|
||||
{
|
||||
typeId: "文学",
|
||||
typeName: "文学",
|
||||
},
|
||||
{
|
||||
typeId: "散文",
|
||||
typeName: "散文",
|
||||
},
|
||||
],
|
||||
title: "书籍管理",
|
||||
json_fields: {
|
||||
图书编号: "bookNumber",
|
||||
图书名称: "bookName",
|
||||
作者: "bookAuthor",
|
||||
图书馆: "bookLibrary",
|
||||
分类: "bookType",
|
||||
位置: "bookLocation",
|
||||
状态: "bookStatus",
|
||||
描述: "bookDescription",
|
||||
},
|
||||
loading: true,
|
||||
multipleSelection: [],
|
||||
fileList: []
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(val) {
|
||||
this.queryInfo.pageSize = val;
|
||||
this.getBookList();
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.queryInfo.pageNum = val;
|
||||
this.getBookList();
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val;
|
||||
},
|
||||
//让修改图书的对话框可见,并从数据库中回显数据
|
||||
async showEditDialog(id) {
|
||||
// 发送axios请求 获取数据库中的书籍分类信息
|
||||
const { data: res1 } = await this.$http.get("admin/get_type");
|
||||
if (res1.status !== 200) {
|
||||
return this.$message.error(res1.msg);
|
||||
}
|
||||
this.types = res1.data;
|
||||
// 让修改公告的对话框可见
|
||||
this.editDialogVisible = true;
|
||||
const { data: res } = await this.$http.get(
|
||||
"admin/get_bookinformation/" + id
|
||||
);
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.editForm = res.data;
|
||||
},
|
||||
//监听修改对话框的关闭,一旦对话框关闭,就重置表单,回显数据
|
||||
editDialogClosed() {
|
||||
this.$refs.editFormRef.resetFields();
|
||||
},
|
||||
//删除单个图书
|
||||
async removeUserById(id) {
|
||||
//弹框,询问用户是否删除数据
|
||||
const confirmResult = await this.$confirm(
|
||||
"此操作将永久删除该书籍, 是否继续?",
|
||||
"提示",
|
||||
{
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}
|
||||
).catch((error) => {
|
||||
return error;
|
||||
});
|
||||
//如果用户确认删除,则返回值为字符串confirm
|
||||
//如果用户取消删除,则返回值为字符串cancel
|
||||
// console.log(confirmResult);
|
||||
if (confirmResult !== "confirm") {
|
||||
return this.$message.info("已经取消删除");
|
||||
}
|
||||
//如果用户确认删除,那么下一步就是发送axios请求,检查响应状态码是否成功,成功则返回删除成功,否则返回删除失败
|
||||
const { data: res } = await this.$http.get("admin/delete_book/" + id);
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success(res.msg);
|
||||
// 防止删除出现数据显示错误
|
||||
this.queryInfo.pageNum = 1;
|
||||
this.queryInfo.pageSize = 5;
|
||||
this.getBookList();
|
||||
},
|
||||
//监听添加公告对话框的关闭,一旦对话框关闭,就重置表单
|
||||
addDialogClosed() {
|
||||
this.$refs.addFormRef.resetFields();
|
||||
},
|
||||
//当用户点击发送新公告时,让添加对话框的visible改为true
|
||||
async showAddDialog() {
|
||||
// 发送axios请求 获取数据库中的书籍分类信息
|
||||
const { data: res } = await this.$http.get("admin/get_type");
|
||||
console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.types = res.data;
|
||||
this.addDialogVisible = true;
|
||||
},
|
||||
async getBookList() {
|
||||
this.loading = true;
|
||||
const { data: res } = await this.$http.post(
|
||||
"admin/get_booklist",
|
||||
this.queryInfo
|
||||
);
|
||||
this.tableData = [];
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
this.total = 0;
|
||||
this.loading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1000,
|
||||
});
|
||||
this.tableData = res.data.records;
|
||||
this.total = parseInt(res.data.total);
|
||||
this.loading = false;
|
||||
},
|
||||
async addBook() {
|
||||
const { data: res } = await this.$http.post(
|
||||
"admin/add_book",
|
||||
this.addForm
|
||||
);
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success(res.msg);
|
||||
this.getBookList();
|
||||
this.addDialogVisible = false;
|
||||
},
|
||||
async updateBook() {
|
||||
this.$refs.editFormRef.validate(async (valid) => {
|
||||
// console.log(valid);
|
||||
//如果表单验证无效,直接返回
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// 验证成功 发送axios请求
|
||||
const { data: res } = await this.$http.post(
|
||||
"admin/update_book",
|
||||
this.editForm
|
||||
);
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success(res.msg);
|
||||
this.getBookList();
|
||||
this.editDialogVisible = false;
|
||||
});
|
||||
},
|
||||
downLoad() {
|
||||
this.getPdf(this.title); //参数是下载的pdf文件名
|
||||
},
|
||||
fullScreen() {
|
||||
// Dom对象的一个属性: 可以用来判断当前是否为全屏模式(trueORfalse)
|
||||
let full = document.fullscreenElement;
|
||||
// 切换为全屏模式
|
||||
if (!full) {
|
||||
// 文档根节点的方法requestFullscreen实现全屏模式
|
||||
document.documentElement.requestFullscreen();
|
||||
} else {
|
||||
// 退出全屏模式
|
||||
document.exitFullscreen();
|
||||
}
|
||||
},
|
||||
// 批量删除图书
|
||||
async removeBatch() {
|
||||
//弹框,询问用户是否删除数据
|
||||
const confirmResult = await this.$confirm(
|
||||
"此操作将永久删除这些书籍, 是否继续?",
|
||||
"提示",
|
||||
{
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}
|
||||
).catch((error) => {
|
||||
return error;
|
||||
});
|
||||
//如果用户确认删除,则返回值为字符串confirm
|
||||
//如果用户取消删除,则返回值为字符串cancel
|
||||
// console.log(confirmResult);
|
||||
if (confirmResult !== "confirm") {
|
||||
return this.$message.info("已经取消删除");
|
||||
}
|
||||
// 判断multipleSelection数组是否为空,为空的话进行提示
|
||||
if (this.multipleSelection.length == 0) {
|
||||
return this.$message.error({
|
||||
message: "选中项为空,无法进行批量删除",
|
||||
duration: 1000
|
||||
});
|
||||
}
|
||||
//如果用户确认删除,那么下一步就是发送axios请求,检查响应状态码是否成功,成功则返回删除成功,否则返回删除失败
|
||||
// const { data: res } = await this.$http.get("admin/delete_book/" + id);
|
||||
const { data: res } = await this.$http.delete("admin/delete_book_batch", {
|
||||
data: this.multipleSelection
|
||||
});
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error({
|
||||
message: res.msg,
|
||||
duration: 1000
|
||||
});
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1000
|
||||
});
|
||||
// 防止删除出现数据显示错误
|
||||
this.queryInfo.pageNum = 1;
|
||||
this.queryInfo.pageSize = 5;
|
||||
this.getBookList();
|
||||
},
|
||||
submitUpload() {
|
||||
console.log(this.$refs.upload.data);
|
||||
this.$refs.upload.submit();
|
||||
this.$message.success({
|
||||
duration: 1500,
|
||||
message: "Excel批量导入图书成功"
|
||||
})
|
||||
},
|
||||
handleRemove(file, fileList) {
|
||||
console.log(file,fileList);
|
||||
},
|
||||
handlePreview(file) {
|
||||
console.log(file);
|
||||
},
|
||||
onSuccess(response, file, fileList){
|
||||
// console.log(response);
|
||||
// console.log(file);
|
||||
// console.log(fileList);
|
||||
}
|
||||
|
||||
},
|
||||
created() {
|
||||
this.getBookList();
|
||||
},
|
||||
computed: {
|
||||
headers() {
|
||||
return {
|
||||
"Authorization": "Bearer " + window.sessionStorage.getItem('token')
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
354
src/components/Admin/BookType.vue
Normal file
@ -0,0 +1,354 @@
|
||||
<template>
|
||||
<div class="search_container">
|
||||
<!-- 面包屑导航区域 -->
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item>首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>书籍类型</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<el-card shadow="always">
|
||||
<!-- 搜索内容和导出区域 -->
|
||||
<el-row>
|
||||
<el-col :span="4">
|
||||
<el-button type="primary" @click="showAddDialog()">
|
||||
<i class="el-icon-plus"></i>添加分类</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<download-excel
|
||||
class="export-excel-wrapper"
|
||||
:data="tableData"
|
||||
:fields="json_fields"
|
||||
:header="title"
|
||||
name="书籍类型.xls"
|
||||
>
|
||||
<!-- 上面可以自定义自己的样式,还可以引用其他组件button -->
|
||||
<el-button type="primary" class="el-icon-printer" size="mini"
|
||||
>导出Excel</el-button
|
||||
>
|
||||
</download-excel>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<el-button
|
||||
type="primary"
|
||||
class="el-icon-printer"
|
||||
size="mini"
|
||||
@click="downLoad"
|
||||
>导出PDF</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
|
||||
<el-button type="success" class="el-icon-full-screen" size="mini" @click="fullScreen"
|
||||
>全屏</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 表格区域 -->
|
||||
<el-table :data="tableData" border style="width: 100%" stripe id="pdfDom" :default-sort = "{prop: 'typeId', order: 'ascending'}"
|
||||
v-loading="loading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)">
|
||||
<el-table-column prop="typeId" label="ID" sortable> </el-table-column>
|
||||
<el-table-column prop="typeName" label="分类名"> </el-table-column>
|
||||
<el-table-column prop="typeContent" label="描述"> </el-table-column>
|
||||
<el-table-column label="操作">
|
||||
|
||||
<template slot-scope="scope">
|
||||
<!-- 修改按钮 -->
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="修改"
|
||||
placement="top"
|
||||
:enterable="false"
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
@click="showEditDialog(scope.row.typeId)"
|
||||
></el-button
|
||||
></el-tooltip>
|
||||
|
||||
<!-- 删除按钮 -->
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="删除"
|
||||
placement="top"
|
||||
:enterable="false"
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
@click="removeUserById(scope.row.typeId)"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页查询区域 -->
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="queryInfo.pageNum"
|
||||
:page-sizes="[1, 2, 3, 4, 5]"
|
||||
:page-size="queryInfo.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="this.total"
|
||||
>
|
||||
</el-pagination>
|
||||
<!-- 修改规则的对话框 -->
|
||||
<el-dialog
|
||||
title="修改分类"
|
||||
:visible.sync="editDialogVisible"
|
||||
width="50%"
|
||||
@close="editDialogClosed"
|
||||
>
|
||||
<el-form
|
||||
:model="editForm"
|
||||
ref="editFormRef"
|
||||
:rules="editFormRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<el-form-item label="分类名" prop="typeName">
|
||||
<el-input v-model="editForm.typeName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="分类描述" prop="typeContent">
|
||||
<el-input v-model="editForm.typeContent" type="textarea"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="editDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="updateBookType"
|
||||
>确 定</el-button
|
||||
>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<!-- 添加规则的对话框 -->
|
||||
<el-dialog
|
||||
title="添加分类"
|
||||
:visible.sync="addDialogVisible"
|
||||
width="50%"
|
||||
@close="addDialogClosed"
|
||||
>
|
||||
<el-form
|
||||
:model="addForm"
|
||||
ref="addFormRef"
|
||||
:rules="addFormRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<el-form-item label="分类名" prop="typeName">
|
||||
<el-input v-model="addForm.typeName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="分类描述" prop="typeContent">
|
||||
<el-input v-model="addForm.typeContent" type="textarea"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="addDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="addBookType">添加分类</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tableData: [
|
||||
{
|
||||
typeId: 183,
|
||||
typeName: "童话",
|
||||
typeContent: "孩子的世界",
|
||||
},
|
||||
],
|
||||
|
||||
editDialogVisible: false,
|
||||
editForm: {
|
||||
typeName: "",
|
||||
typeContent: "",
|
||||
},
|
||||
editFormRules: {
|
||||
typeName: [
|
||||
{ required: true, message: "请输入分类名", trigger: "blur" },
|
||||
],
|
||||
typeContent: [
|
||||
{ required: true, message: "请输入分类描述", trigger: "blur" },
|
||||
],
|
||||
},
|
||||
addDialogVisible: false,
|
||||
addForm: {
|
||||
typeName: "",
|
||||
typeContent: "",
|
||||
},
|
||||
addFormRules: {
|
||||
typeName: [
|
||||
{ required: true, message: "请输入分类名", trigger: "blur" },
|
||||
],
|
||||
typeContent: [
|
||||
{ required: true, message: "请输入分类描述", trigger: "blur" },
|
||||
],
|
||||
},
|
||||
queryInfo: {
|
||||
pageNum: 1,
|
||||
pageSize: 5,
|
||||
},
|
||||
total: 0,
|
||||
title: "书籍类型",
|
||||
json_fields: {
|
||||
类别编号: "typeId",
|
||||
类别昵称: "typeName",
|
||||
类别概述: "typeContent",
|
||||
},
|
||||
loading:true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(val) {
|
||||
this.queryInfo.pageSize = val;
|
||||
this.getBookTypeList();
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.queryInfo.pageNum = val;
|
||||
this.getBookTypeList();
|
||||
},
|
||||
//让修改公告的对话框可见,并从数据库中回显数据
|
||||
async showEditDialog(id) {
|
||||
// 让修改公告的对话框可见
|
||||
this.editDialogVisible = true;
|
||||
const { data: res } = await this.$http.get("admin/get_booktype/" + id);
|
||||
console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.editForm = res.data;
|
||||
},
|
||||
//监听修改对话框的关闭,一旦对话框关闭,就重置表单,回显数据
|
||||
editDialogClosed() {
|
||||
this.$refs.editFormRef.resetFields();
|
||||
this.editForm.checkList = ["南图", "北图", "教师之家"];
|
||||
},
|
||||
//删除公告
|
||||
async removeUserById(id) {
|
||||
//弹框,询问用户是否删除数据
|
||||
const confirmResult = await this.$confirm(
|
||||
"此操作将永久删除该公告, 是否继续?",
|
||||
"提示",
|
||||
{
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}
|
||||
).catch((error) => {
|
||||
return error;
|
||||
});
|
||||
//如果用户确认删除,则返回值为字符串confirm
|
||||
//如果用户取消删除,则返回值为字符串cancel
|
||||
// console.log(confirmResult);
|
||||
if (confirmResult !== "confirm") {
|
||||
return this.$message.info("已经取消删除");
|
||||
}
|
||||
//如果用户确认删除,那么下一步就是发送axios请求,检查响应状态码是否成功,成功则返回删除成功,否则返回删除失败
|
||||
const {data:res } = await this.$http.get('admin/delete_booktype/'+id)
|
||||
console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success(res.msg)
|
||||
// 防止删除出现数据显示错误
|
||||
this.queryInfo.pageNum= 1;
|
||||
this.queryInfo.pageSize= 5;
|
||||
this.getBookTypeList();
|
||||
},
|
||||
//监听添加公告对话框的关闭,一旦对话框关闭,就重置表单
|
||||
addDialogClosed() {
|
||||
this.$refs.addFormRef.resetFields();
|
||||
},
|
||||
//当用户点击发送新公告时,让添加对话框的visible改为true
|
||||
showAddDialog() {
|
||||
this.addDialogVisible = true;
|
||||
},
|
||||
async getBookTypeList() {
|
||||
this.loading = true;
|
||||
const { data: res } = await this.$http.post(
|
||||
"admin/get_booktype_page",
|
||||
this.queryInfo
|
||||
);
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
this.loading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success(
|
||||
{
|
||||
message:res.msg,
|
||||
duration:1000
|
||||
}
|
||||
)
|
||||
this.tableData = res.data.records;
|
||||
this.total = parseInt(res.data.total);
|
||||
this.loading = false;
|
||||
},
|
||||
async addBookType() {
|
||||
this.$refs.addFormRef.validate(async (valid) => {
|
||||
// console.log(valid);
|
||||
//如果表单验证无效,直接返回
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// 发送axios请求
|
||||
const { data: res } = await this.$http.post(
|
||||
"admin/add_booktype",
|
||||
this.addForm
|
||||
);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1500,
|
||||
});
|
||||
this.getBookTypeList();
|
||||
this.addDialogVisible = false;
|
||||
});
|
||||
},
|
||||
async updateBookType(){
|
||||
const {data:res} = await this.$http.post('admin/update_booktype',this.editForm)
|
||||
console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message:res.msg,
|
||||
duration:1500
|
||||
})
|
||||
this.getBookTypeList();
|
||||
this.editDialogVisible = false;
|
||||
},
|
||||
downLoad() {
|
||||
this.getPdf(this.title); //参数是下载的pdf文件名
|
||||
},
|
||||
fullScreen(){
|
||||
// Dom对象的一个属性: 可以用来判断当前是否为全屏模式(trueORfalse)
|
||||
let full = document.fullscreenElement;
|
||||
// 切换为全屏模式
|
||||
if(!full){
|
||||
// 文档根节点的方法requestFullscreen实现全屏模式
|
||||
document.documentElement.requestFullscreen();
|
||||
}else{
|
||||
// 退出全屏模式
|
||||
document.exitFullscreen();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getBookTypeList();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
231
src/components/Admin/IntelligentAnalysis.vue
Normal file
@ -0,0 +1,231 @@
|
||||
<template>
|
||||
<div class="intelligent_analysis">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-card header="智能分析">
|
||||
<el-form
|
||||
ref="form"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="90px"
|
||||
enctype="multipart/form-data"
|
||||
>
|
||||
<el-form-item label="分析目标: " prop="goal">
|
||||
<el-input type="textarea" v-model="form.goal"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="图表名称: " prop="name">
|
||||
<el-input v-model="form.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="图表类型: " prop="chartType">
|
||||
<el-select v-model="form.chartType" placeholder="请选择图表类型">
|
||||
<el-option label="折线图" value="折线图"></el-option>
|
||||
<el-option label="柱状图" value="柱状图"></el-option>
|
||||
<el-option label="堆叠图" value="堆叠图"></el-option>
|
||||
<el-option label="饼图" value="饼图"></el-option>
|
||||
<el-option label="雷达图" value="雷达图"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="原始数据: ">
|
||||
<el-upload
|
||||
class="upload-demo"
|
||||
action="https://jsonplaceholder.typicode.com/posts/"
|
||||
:on-remove="handleRemove"
|
||||
:on-change="handleChange"
|
||||
multiple
|
||||
:limit="1"
|
||||
:on-exceed="handleExceed"
|
||||
name="file"
|
||||
:file-list="fileList"
|
||||
ref="upload"
|
||||
:auto-upload="false"
|
||||
>
|
||||
<el-button size="small" type="success" icon="el-icon-upload2"
|
||||
>上传Excel文件</el-button
|
||||
>
|
||||
<div slot="tip" class="el-upload__tip">
|
||||
只能上传xls/xlsx文件,且不超过1MB
|
||||
</div>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="onSubmit"
|
||||
v-loading="submitting"
|
||||
:disabled="submitting"
|
||||
>提交</el-button
|
||||
>
|
||||
<el-button @click="resetForm" :disabled="submitting"
|
||||
>重置</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card header="分析结论" v-loading="submitting">
|
||||
<div v-if="chart.genResult" style="white-space: pre-wrap">
|
||||
{{ chart.genResult }}
|
||||
<!-- 根据具体的需求来显示生成结果 -->
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-if="!submitting">请先在左侧进行提交</div>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-divider></el-divider>
|
||||
<el-card header="可视化图表" v-loading="submitting">
|
||||
<div v-show="chart.genChart">
|
||||
<div
|
||||
ref="chartContainer"
|
||||
style="width: 100%; height: 50vh"
|
||||
class="chartContainer"
|
||||
></div>
|
||||
</div>
|
||||
<div v-show="!chart.genChart">
|
||||
<div v-if="!submitting" @click="createChart()">
|
||||
请先在左侧进行提交
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import * as echarts from "echarts";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
goal: "",
|
||||
name: "",
|
||||
chartType: "",
|
||||
adminId: undefined,
|
||||
},
|
||||
file: {},
|
||||
rules: {
|
||||
goal: [
|
||||
{ required: true, message: "请输入分析目标", trigger: "blur" },
|
||||
{
|
||||
min: 5,
|
||||
max: 100,
|
||||
message: "长度在 5 到 100 个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
},
|
||||
chart: {
|
||||
genChart: "",
|
||||
genResult: "",
|
||||
chartId: "",
|
||||
},
|
||||
resultChart: {},
|
||||
fileList: [],
|
||||
submitting: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// 文件数量超过限制
|
||||
handleExceed(files, fileList) {
|
||||
this.$message.info({
|
||||
message: "最多只能上传一个文件",
|
||||
duration: 1500,
|
||||
});
|
||||
},
|
||||
// 文件状态发生改变回调(添加文件、上传成功和上传失败时都会被调用)
|
||||
handleChange(file, fileList) {
|
||||
// 1. 检查文件类型 只能为xls或者xlsx\
|
||||
// 第一种是xls 第二种是xlsx
|
||||
const acceptTypeList = [
|
||||
"application/vnd.ms-excel",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
];
|
||||
// 表示用户上传的文件类型不在允许范围内
|
||||
if (acceptTypeList.indexOf(file.raw.type) === -1) {
|
||||
this.$message.info({
|
||||
message: "只允许xls或者xlsx格式的文件上传",
|
||||
duration: 1500,
|
||||
});
|
||||
this.handleRemove(file);
|
||||
return;
|
||||
}
|
||||
// 2.检查文件大小是否大于1MB
|
||||
const acceptSize = 1 * 1024 * 1024;
|
||||
if (file.raw.size > acceptSize) {
|
||||
this.$message.info({
|
||||
message: "只允许文件大小在1MB之内的Excel文件",
|
||||
duration: 1500,
|
||||
});
|
||||
this.handleRemove(file);
|
||||
return;
|
||||
}
|
||||
this.file = file.raw;
|
||||
},
|
||||
async onSubmit() {
|
||||
if (this.submitting) {
|
||||
return;
|
||||
}
|
||||
this.submitting = true;
|
||||
const formData = new FormData();
|
||||
|
||||
if (this.file) {
|
||||
formData.append("file", this.file);
|
||||
}
|
||||
this.form.adminId = parseInt(window.sessionStorage.getItem("adminId"));
|
||||
for (const key in this.form) {
|
||||
formData.append(key, this.form[key]);
|
||||
}
|
||||
this.$message.info({
|
||||
message: "接口调用花费时间在30秒左右,AI模型暂时不稳定",
|
||||
duration: 2500,
|
||||
});
|
||||
const { data: res } = await this.$http.post("/admin/gen", formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
});
|
||||
if (res.status !== 200) {
|
||||
this.submitting = false;
|
||||
return this.$message.error({
|
||||
message: res.msg,
|
||||
duration: 1500,
|
||||
});
|
||||
}
|
||||
this.chart = res.data;
|
||||
this.resultChart = res.map.genChart;
|
||||
this.createChart();
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1500,
|
||||
});
|
||||
this.submitting = false;
|
||||
},
|
||||
createChart() {
|
||||
const chartOption = this.resultChart;
|
||||
if (!chartOption) {
|
||||
return this.$message.error({
|
||||
message: "图表代码解析错误",
|
||||
duration: 1500,
|
||||
});
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
const chart = echarts.init(this.$refs.chartContainer);
|
||||
chart.setOption(chartOption);
|
||||
});
|
||||
},
|
||||
resetForm() {
|
||||
this.$refs.form.resetFields();
|
||||
this.handleRemove();
|
||||
},
|
||||
handleRemove(file, fileList) {
|
||||
this.fileList = fileList;
|
||||
this.fileList = [];
|
||||
this.file = {};
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="less"></style>
|
237
src/components/Admin/LoginAdmin.vue
Normal file
@ -0,0 +1,237 @@
|
||||
<template>
|
||||
<div class="login_container">
|
||||
<div class="login_title">系统管理员登录界面</div>
|
||||
<div class="login_box">
|
||||
<!-- 头像区域 -->
|
||||
<div class="avatar_box">
|
||||
<img src="https://xxx.xiaobaitiao.icu/img/icu/202312211243634.jpg" alt=""/>
|
||||
</div>
|
||||
<!-- 登录表单区域 -->
|
||||
<el-form
|
||||
ref="loginFormRef"
|
||||
:model="loginForm"
|
||||
:rules="loginFormRules"
|
||||
label-width="0px"
|
||||
class="login_form"
|
||||
>
|
||||
<!-- 用户名 -->
|
||||
<el-form-item prop="username">
|
||||
<el-input
|
||||
v-model.trim="loginForm.username"
|
||||
prefix-icon="iconfont icon-gerenxinxi"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<!-- 密码 -->
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
v-model="loginForm.password"
|
||||
prefix-icon="iconfont icon-tianchongxing-"
|
||||
type="password"
|
||||
@keyup.enter.native="login"
|
||||
:show-password="true"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<!-- 按钮区域 -->
|
||||
<el-form-item class="btns">
|
||||
<el-button type="primary" @click="login" :loading="loginLoading">登录</el-button>
|
||||
<el-button type="info" @click="resetLoginForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<vue-particles
|
||||
class="login-bg"
|
||||
color="#39AFFD"
|
||||
:particleOpacity="0.7"
|
||||
:particlesNumber="100"
|
||||
shapeType="circle"
|
||||
:particleSize="4"
|
||||
linesColor="#8DD1FE"
|
||||
:linesWidth="1"
|
||||
:lineLinked="true"
|
||||
:lineOpacity="0.4"
|
||||
:linesDistance="150"
|
||||
:moveSpeed="3"
|
||||
:hoverEffect="true"
|
||||
hoverMode="grab"
|
||||
:clickEffect="true"
|
||||
clickMode="push"
|
||||
>
|
||||
</vue-particles>
|
||||
<div class="footer">
|
||||
<span style="font-weight: bold;color:white;margin-bottom: 10px">
|
||||
登录页面切换
|
||||
</span>
|
||||
<span><i class="iconfont icon-haoyou" @click="goUser"></i></span>
|
||||
|
||||
</div>
|
||||
<div class="footer2">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
//登录表单
|
||||
loginForm: {
|
||||
username: "root",
|
||||
password: "123456",
|
||||
},
|
||||
//登录表单规则的验证对象
|
||||
loginFormRules: {
|
||||
username: [
|
||||
{required: true, message: "用户名不能为空", trigger: "blur"},
|
||||
{
|
||||
min: 3,
|
||||
max: 20,
|
||||
message: "长度在 3 到 20 个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
password: [
|
||||
{required: true, message: "密码不能为空", trigger: "blur"},
|
||||
{
|
||||
min: 6,
|
||||
max: 15,
|
||||
message: "长度在 6 到 15 个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
},
|
||||
loginLoading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
resetLoginForm() {
|
||||
this.$refs.loginFormRef.resetFields();
|
||||
},
|
||||
login() {
|
||||
this.$refs.loginFormRef.validate(async (valid) => {
|
||||
// console.log(valid);
|
||||
//如果表单验证无效,直接返回
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
this.loginLoading = true;
|
||||
const username = this.loginForm.username;
|
||||
const password = this.loginForm.password;
|
||||
//向数据库发送axios请求,如果登录成功,就跳转
|
||||
const {data: res} = await this.$http.post(
|
||||
"admin/login",
|
||||
{
|
||||
username,
|
||||
password
|
||||
}
|
||||
);
|
||||
if (res.status !== 200) {
|
||||
this.loginLoading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success("登录成功");
|
||||
this.loginLoading = false;
|
||||
// console.log(res);
|
||||
window.sessionStorage.setItem("token", res.map.token);
|
||||
window.sessionStorage.setItem("adminId", res.map.id);
|
||||
this.$router.push("/homeadmin");
|
||||
});
|
||||
},
|
||||
goUser() {
|
||||
this.$router.push("/login");
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.footer2 {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 35%;
|
||||
color: #ccc;
|
||||
|
||||
a {
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
.login_container {
|
||||
// background-color: #2b4b6b;
|
||||
background: url(https://xxx.xiaobaitiao.icu/img/icu/202312211236280.jpg) no-repeat 0px 0px;
|
||||
background-size: cover;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.login_box {
|
||||
height: 300px;
|
||||
width: 450px;
|
||||
background-color: #fff;
|
||||
border-radius: 3px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
.avatar_box {
|
||||
width: 130px;
|
||||
height: 130px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 50%;
|
||||
padding: 10px;
|
||||
box-shadow: 0 0 10px #ddd;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: #fff;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login_form {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
padding: 0 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.btns {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.login_title {
|
||||
position: relative;
|
||||
top: 5%;
|
||||
font-size: 36px;
|
||||
color: white;
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
//控制字体间距
|
||||
letter-spacing: 10px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
flex-direction: column;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 100px;
|
||||
height: 120px;
|
||||
// background-color: pink;
|
||||
span {
|
||||
// width: 100%;
|
||||
// background-color: red;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
429
src/components/Admin/StatementManage.vue
Normal file
@ -0,0 +1,429 @@
|
||||
<template>
|
||||
<div class="search_container">
|
||||
<!-- 面包屑导航区域 -->
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item>首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>借阅证管理</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<el-card shadow="always">
|
||||
<!-- 搜索内容和导出区域 -->
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="6"
|
||||
>条件搜索:<el-select
|
||||
v-model="queryInfo.condition"
|
||||
filterable
|
||||
placeholder="请选择"
|
||||
style="margin-left: 15px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in searchs"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-input
|
||||
placeholder="请输入内容"
|
||||
v-model="queryInfo.query"
|
||||
class="input-with-select"
|
||||
@keyup.enter.native="getStatementList"
|
||||
>
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-search"
|
||||
@click="getStatementList"
|
||||
></el-button> </el-input
|
||||
></el-col>
|
||||
<el-col :span="4">
|
||||
<el-button type="primary" @click="showAddDialog()">
|
||||
<i class="el-icon-plus"></i> 添加借阅证</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<download-excel
|
||||
class="export-excel-wrapper"
|
||||
:data="tableData"
|
||||
:fields="json_fields"
|
||||
:header="title"
|
||||
name="借阅证管理.xls"
|
||||
>
|
||||
<!-- 上面可以自定义自己的样式,还可以引用其他组件button -->
|
||||
<el-button type="primary" class="el-icon-printer" size="mini"
|
||||
>导出Excel</el-button
|
||||
>
|
||||
</download-excel>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<el-button
|
||||
type="primary"
|
||||
class="el-icon-printer"
|
||||
size="mini"
|
||||
@click="downLoad"
|
||||
>导出PDF</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
|
||||
<el-button type="success" class="el-icon-full-screen" size="mini" @click="fullScreen"
|
||||
>全屏</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 表格区域 -->
|
||||
<el-table :data="tableData" border style="width: 100%" stripe id="pdfDom" :default-sort = "{prop: 'cardNumber', order: 'ascending'}"
|
||||
v-loading="loading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)">
|
||||
<el-table-column prop="cardNumber" label="借阅证编号" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="username" label="用户名"> </el-table-column>
|
||||
<el-table-column prop="ruleNumber" label="借阅规则" sortable> </el-table-column>
|
||||
<el-table-column prop="status" label="状态" sortable> </el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template slot-scope="scope">
|
||||
<!-- 修改按钮 -->
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="修改"
|
||||
placement="top"
|
||||
:enterable="false"
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
@click="showEditDialog(scope.row.userId)"
|
||||
></el-button
|
||||
></el-tooltip>
|
||||
|
||||
<!-- 删除按钮 -->
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="删除"
|
||||
placement="top"
|
||||
:enterable="false"
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
@click="removeUserById(scope.row.userId)"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页查询区域 -->
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="queryInfo.pageNum"
|
||||
:page-sizes="[1, 2, 3, 4, 5]"
|
||||
:page-size="queryInfo.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="this.total"
|
||||
>
|
||||
</el-pagination>
|
||||
<!-- 修改规则的对话框 -->
|
||||
<el-dialog
|
||||
title="修改书籍"
|
||||
:visible.sync="editDialogVisible"
|
||||
width="50%"
|
||||
@close="editDialogClosed"
|
||||
>
|
||||
<el-form
|
||||
:model="editForm"
|
||||
ref="editFormRef"
|
||||
:rules="editFormRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<el-form-item label="账号" prop="username">
|
||||
<el-input v-model="editForm.username"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input v-model="editForm.password" type="password"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="规则" prop="ruleNumber">
|
||||
<el-select v-model="editForm.ruleNumber" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in bookRuleIdLists"
|
||||
:key="item.ruleId"
|
||||
:label="item.bookRuleId"
|
||||
:value="item.bookRuleId"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="userStatus">
|
||||
<el-radio-group v-model="editForm.userStatus">
|
||||
<el-radio label="可用">可用</el-radio>
|
||||
<el-radio label="挂失">挂失</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="editDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="updateStatement">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<!-- 添加书籍的对话框 -->
|
||||
<el-dialog
|
||||
title="添加借书证"
|
||||
:visible.sync="addDialogVisible"
|
||||
width="50%"
|
||||
@close="addDialogClosed"
|
||||
>
|
||||
<el-form
|
||||
:model="addForm"
|
||||
ref="addFormRef"
|
||||
:rules="addFormRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<el-form-item label="账号" prop="username">
|
||||
<el-input v-model="addForm.username"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input v-model="addForm.password"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="规则" prop="ruleNumber">
|
||||
<el-select v-model="addForm.ruleNumber" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in bookRuleIdLists"
|
||||
:key="item.ruleId"
|
||||
:label="item.bookRuleId"
|
||||
:value="item.bookRuleId"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="userStatus">
|
||||
<el-radio-group v-model="addForm.userStatus">
|
||||
<el-radio label="可用">可用</el-radio>
|
||||
<el-radio label="禁用">禁用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="addDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="addStatement">添加借阅证</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
|
||||
editDialogVisible: false,
|
||||
editForm: {
|
||||
username: "",
|
||||
password: "",
|
||||
ruleNumber: "",
|
||||
status: "",
|
||||
userStatus: "",
|
||||
},
|
||||
editFormRules: {},
|
||||
addDialogVisible: false,
|
||||
addForm: {
|
||||
username: "",
|
||||
password: "",
|
||||
ruleNumber: "",
|
||||
userStatus: "",
|
||||
},
|
||||
addFormRules: {},
|
||||
searchs: [
|
||||
{
|
||||
value: "card_number",
|
||||
label: "借阅证编号",
|
||||
},
|
||||
{
|
||||
value: "username",
|
||||
label: "用户名",
|
||||
},
|
||||
{
|
||||
value: "rule_number",
|
||||
label: "借阅规则",
|
||||
},
|
||||
{
|
||||
value: "status",
|
||||
label: "状态",
|
||||
},
|
||||
],
|
||||
bookRuleIdLists: [
|
||||
{
|
||||
ruleId: "18",
|
||||
bookRuleId: "18",
|
||||
},
|
||||
{
|
||||
ruleId: "357",
|
||||
bookRuleId: "357",
|
||||
},
|
||||
],
|
||||
queryInfo: {
|
||||
pageNum: 1,
|
||||
pageSize: 5,
|
||||
condition: "",
|
||||
query: "",
|
||||
},
|
||||
total: 0,
|
||||
title: "借阅证管理",
|
||||
json_fields: {
|
||||
借阅证遍号: "cardNumber",
|
||||
用户名: "username",
|
||||
借阅规则: "ruleNumber",
|
||||
状态: "status",
|
||||
},
|
||||
loading:true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(val) {
|
||||
this.queryInfo.pageSize = val;
|
||||
this.getStatementList();
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.queryInfo.pageNum = val;
|
||||
this.getStatementList();
|
||||
},
|
||||
//让修改公告的对话框可见,并从数据库中回显数据
|
||||
async showEditDialog(id) {
|
||||
// 让修改公告的对话框可见
|
||||
const { data: res } = await this.$http.get("admin/get_statement/" + id);
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
// 发送axios请求回显规则列表
|
||||
const { data: res2 } = await this.$http.get("user/get_rulelist");
|
||||
this.bookRuleIdLists = res2.data;
|
||||
this.editForm = res.data;
|
||||
this.editDialogVisible = true;
|
||||
},
|
||||
//监听修改对话框的关闭,一旦对话框关闭,就重置表单,回显数据
|
||||
editDialogClosed() {
|
||||
this.$refs.editFormRef.resetFields();
|
||||
this.editForm.checkList = ["南图", "北图", "教师之家"];
|
||||
},
|
||||
//删除公告
|
||||
async removeUserById(id) {
|
||||
//弹框,询问用户是否删除数据
|
||||
const confirmResult = await this.$confirm(
|
||||
"此操作将永久删除该书籍, 是否继续?",
|
||||
"提示",
|
||||
{
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}
|
||||
).catch((error) => {
|
||||
return error;
|
||||
});
|
||||
//如果用户确认删除,则返回值为字符串confirm
|
||||
//如果用户取消删除,则返回值为字符串cancel
|
||||
// console.log(confirmResult);
|
||||
if (confirmResult !== "confirm") {
|
||||
return this.$message.info("已经取消删除");
|
||||
}
|
||||
//如果用户确认删除,那么下一步就是发送axios请求,检查响应状态码是否成功,成功则返回删除成功,否则返回删除失败
|
||||
const { data: res } = await this.$http.delete(
|
||||
"admin/delete_statement/" + id
|
||||
);
|
||||
console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success(res.msg);
|
||||
this.getStatementList();
|
||||
},
|
||||
//监听添加公告对话框的关闭,一旦对话框关闭,就重置表单
|
||||
addDialogClosed() {
|
||||
this.$refs.addFormRef.resetFields();
|
||||
},
|
||||
//当用户点击发送新公告时,让添加对话框的visible改为true
|
||||
async showAddDialog() {
|
||||
// 发送axios请求回显规则列表
|
||||
const { data: res } = await this.$http.get("user/get_rulelist");
|
||||
this.bookRuleIdLists = res.data;
|
||||
this.addDialogVisible = true;
|
||||
},
|
||||
async getStatementList() {
|
||||
this.loading = true;
|
||||
const { data: res } = await this.$http.post(
|
||||
"admin/get_statementlist",
|
||||
this.queryInfo
|
||||
);
|
||||
// console.log(res);
|
||||
this.tableData = [];
|
||||
if (res.status !== 200) {
|
||||
this.total = 0;
|
||||
this.loading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1000,
|
||||
});
|
||||
this.tableData = res.data.records;
|
||||
this.total = parseInt(res.data.total);
|
||||
this.loading = false;
|
||||
},
|
||||
async addStatement() {
|
||||
const { data: res } = await this.$http.post(
|
||||
"admin/add_statement",
|
||||
this.addForm
|
||||
);
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
|
||||
this.$message.success(res.msg);
|
||||
this.addDialogVisible = false;
|
||||
this.getStatementList();
|
||||
},
|
||||
async updateStatement() {
|
||||
const { data: res } = await this.$http.post(
|
||||
"admin/update_statement",
|
||||
this.editForm
|
||||
);
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success(res.msg);
|
||||
this.getStatementList();
|
||||
this.editDialogVisible = false;
|
||||
},
|
||||
downLoad() {
|
||||
this.getPdf(this.title); //参数是下载的pdf文件名
|
||||
},
|
||||
fullScreen(){
|
||||
// Dom对象的一个属性: 可以用来判断当前是否为全屏模式(trueORfalse)
|
||||
let full = document.fullscreenElement;
|
||||
// 切换为全屏模式
|
||||
if(!full){
|
||||
// 文档根节点的方法requestFullscreen实现全屏模式
|
||||
document.documentElement.requestFullscreen();
|
||||
}else{
|
||||
// 退出全屏模式
|
||||
document.exitFullscreen();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getStatementList();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
415
src/components/Admin/StatementRuleManage.vue
Normal file
@ -0,0 +1,415 @@
|
||||
<template>
|
||||
<div class="search_container">
|
||||
<!-- 面包屑导航区域 -->
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item>首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>借阅规则管理</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<el-card shadow="always">
|
||||
<!-- 搜索内容和导出区域 -->
|
||||
<el-row>
|
||||
<el-col :span="4">
|
||||
<el-button type="primary" @click="showAddDialog()">
|
||||
<i class="el-icon-plus"></i> 添加</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<download-excel
|
||||
class="export-excel-wrapper"
|
||||
:data="tableData"
|
||||
:fields="json_fields"
|
||||
:header="title"
|
||||
name="借阅规则.xls"
|
||||
>
|
||||
<!-- 上面可以自定义自己的样式,还可以引用其他组件button -->
|
||||
<el-button type="primary" class="el-icon-printer" size="mini"
|
||||
>导出Excel</el-button
|
||||
>
|
||||
</download-excel>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<el-button
|
||||
type="primary"
|
||||
class="el-icon-printer"
|
||||
size="mini"
|
||||
@click="downLoad"
|
||||
>导出PDF</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
|
||||
<el-button type="success" class="el-icon-full-screen" size="mini" @click="fullScreen"
|
||||
>全屏</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 表格区域 -->
|
||||
<el-table :data="tableData" border style="width: 100%" stripe id="pdfDom" :default-sort = "{prop: 'bookRuleId', order: 'ascending'}"
|
||||
v-loading="loading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)">
|
||||
<el-table-column prop="bookRuleId" label="ID" sortable> </el-table-column>
|
||||
<el-table-column prop="bookDays" label="限制天数" sortable> </el-table-column>
|
||||
<el-table-column prop="bookLimitNumber" label="限制本数" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="bookLimitLibrary" label="限制图书馆">
|
||||
</el-table-column>
|
||||
<el-table-column prop="bookOverdueFee" label="逾期费用" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template slot-scope="scope">
|
||||
<!-- 修改按钮 -->
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="修改"
|
||||
placement="top"
|
||||
:enterable="false"
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
@click="showEditDialog(scope.row.ruleId)"
|
||||
></el-button
|
||||
></el-tooltip>
|
||||
|
||||
<!-- 删除按钮 -->
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="删除"
|
||||
placement="top"
|
||||
:enterable="false"
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
@click="removeUserById(scope.row.ruleId)"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页查询区域 -->
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="queryInfo.pageNum"
|
||||
:page-sizes="[1, 2, 3, 4, 5]"
|
||||
:page-size="queryInfo.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="this.total"
|
||||
>
|
||||
</el-pagination>
|
||||
<!-- 修改规则的对话框 -->
|
||||
<el-dialog
|
||||
title="修改规则"
|
||||
:visible.sync="editDialogVisible"
|
||||
width="50%"
|
||||
@close="editDialogClosed"
|
||||
>
|
||||
<el-form
|
||||
:model="editForm"
|
||||
ref="editFormRef"
|
||||
:rules="editFormRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<el-form-item label="限制天数" prop="bookDays">
|
||||
<el-input v-model="editForm.bookDays"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="限制数量" prop="bookLimitNumber">
|
||||
<el-input v-model="editForm.bookLimitNumber"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="限制图书馆">
|
||||
<el-checkbox-group v-model="editForm.checkList">
|
||||
<el-checkbox label="南图"></el-checkbox>
|
||||
<el-checkbox label="北图"></el-checkbox>
|
||||
<el-checkbox label="教师之家"></el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="逾期每天费用" prop="bookOverdueFee">
|
||||
<el-input v-model="editForm.bookOverdueFee"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="editDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="updateRule"
|
||||
>确 定</el-button
|
||||
>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<!-- 添加规则的对话框 -->
|
||||
<el-dialog
|
||||
title="添加规则"
|
||||
:visible.sync="addDialogVisible"
|
||||
width="50%"
|
||||
@close="addDialogClosed"
|
||||
>
|
||||
<el-form
|
||||
:model="addForm"
|
||||
ref="addFormRef"
|
||||
:rules="addFormRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<el-form-item label="限制天数" prop="bookDays">
|
||||
<el-input v-model="addForm.bookDays"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="限制数量" prop="bookLimitNumber">
|
||||
<el-input v-model="addForm.bookLimitNumber"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="限制图书馆">
|
||||
<el-checkbox-group v-model="addForm.checkList">
|
||||
<el-checkbox label="南图"></el-checkbox>
|
||||
<el-checkbox label="北图"></el-checkbox>
|
||||
<el-checkbox label="教师之家"></el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="逾期每天费用" prop="bookOverdueFee">
|
||||
<el-input v-model="addForm.bookOverdueFee"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="addDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="addRule">添加规则</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tableData: [
|
||||
{
|
||||
bookRuleId: 183,
|
||||
bookDays: 60,
|
||||
bookLimitNumber: 1000,
|
||||
bookLimitLibrary: "1、2、3",
|
||||
bookOverdueFee: 3.0,
|
||||
},
|
||||
{
|
||||
bookRuleId: 183,
|
||||
bookDays: 60,
|
||||
bookLimitNumber: 1000,
|
||||
bookLimitLibrary: "1、2、3",
|
||||
bookOverdueFee: 3.0,
|
||||
},
|
||||
{
|
||||
bookRuleId: 183,
|
||||
bookDays: 60,
|
||||
bookLimitNumber: 1000,
|
||||
bookLimitLibrary: "1、2、3",
|
||||
bookOverdueFee: 3.0,
|
||||
},
|
||||
{
|
||||
bookRuleId: 183,
|
||||
bookDays: 60,
|
||||
bookLimitNumber: 1000,
|
||||
bookLimitLibrary: "1、2、3",
|
||||
bookOverdueFee: 3.0,
|
||||
},
|
||||
],
|
||||
|
||||
editDialogVisible: false,
|
||||
editForm: {
|
||||
bookDays: "",
|
||||
bookLimitNumber: "",
|
||||
checkList: ["南图", "北图", "教师之家"],
|
||||
bookOverdueFee: 0,
|
||||
bookLimitLibrary: "",
|
||||
},
|
||||
editFormRules: {
|
||||
bookLimitDays: [
|
||||
{ required: true, message: "请输入限制天数", trigger: "blur" },
|
||||
],
|
||||
bookLimitNumber: [
|
||||
{ required: true, message: "请输入限制数量", trigger: "blur" },
|
||||
],
|
||||
bookOverdueFee: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入正确的逾期每天费用",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
},
|
||||
addDialogVisible: false,
|
||||
addForm: {
|
||||
bookDays: "",
|
||||
bookLimitNumber: "",
|
||||
checkList: ["南图", "北图", "教师之家"],
|
||||
bookOverdueFee: 0,
|
||||
bookLimitLibrary: "",
|
||||
},
|
||||
addFormRules: {
|
||||
bookLimitDays: [
|
||||
{ required: true, message: "请输入限制天数", trigger: "blur" },
|
||||
],
|
||||
bookLimitNumber: [
|
||||
{ required: true, message: "请输入限制数量", trigger: "blur" },
|
||||
],
|
||||
bookOverdueFee: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入正确的逾期每天费用",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
},
|
||||
queryInfo: {
|
||||
pageNum: 1,
|
||||
pageSize: 5,
|
||||
},
|
||||
total: 0,
|
||||
title: "借阅规则",
|
||||
json_fields: {
|
||||
规则编号: "bookRuleId",
|
||||
限制天数: "bookDays",
|
||||
限制本数: "bookLimitNumber",
|
||||
限制图书馆: "bookLimitLibrary",
|
||||
逾期费用: "bookOverdueFee",
|
||||
},
|
||||
loading:true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(val) {
|
||||
this.queryInfo.pageSize = val;
|
||||
this.getRuleList();
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.queryInfo.pageNum = val;
|
||||
this.getRuleList();
|
||||
},
|
||||
//让修改公告的对话框可见,并从数据库中回显数据
|
||||
async showEditDialog(id) {
|
||||
// 让修改公告的对话框可见
|
||||
const {data:res} = await this.$http.get('admin/get_rule_ruleid/'+id)
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
|
||||
this.editForm = res.data
|
||||
this.editDialogVisible = true;
|
||||
},
|
||||
//监听修改对话框的关闭,一旦对话框关闭,就重置表单,回显数据
|
||||
editDialogClosed() {
|
||||
this.$refs.editFormRef.resetFields();
|
||||
this.editForm.checkList = ["南图", "北图", "教师之家"];
|
||||
},
|
||||
//删除公告
|
||||
async removeUserById(id) {
|
||||
//弹框,询问用户是否删除数据
|
||||
const confirmResult = await this.$confirm(
|
||||
"此操作将永久删除该公告, 是否继续?",
|
||||
"提示",
|
||||
{
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}
|
||||
).catch((error) => {
|
||||
return error;
|
||||
});
|
||||
//如果用户确认删除,则返回值为字符串confirm
|
||||
//如果用户取消删除,则返回值为字符串cancel
|
||||
// console.log(confirmResult);
|
||||
if (confirmResult !== "confirm") {
|
||||
return this.$message.info("已经取消删除");
|
||||
}
|
||||
//如果用户确认删除,那么下一步就是发送axios请求,检查响应状态码是否成功,成功则返回删除成功,否则返回删除失败
|
||||
const {data:res} = await this.$http.delete('admin/delete_rule/'+id);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1500,
|
||||
});
|
||||
this.getRuleList();
|
||||
},
|
||||
//监听添加公告对话框的关闭,一旦对话框关闭,就重置表单
|
||||
addDialogClosed() {
|
||||
this.$refs.addFormRef.resetFields();
|
||||
this.addForm.checkList = ["南图", "北图", "教师之家"];
|
||||
},
|
||||
//当用户点击发送新公告时,让添加对话框的visible改为true
|
||||
showAddDialog() {
|
||||
this.addDialogVisible = true;
|
||||
},
|
||||
async getRuleList() {
|
||||
this.loading = true;
|
||||
const { data: res } = await this.$http.post(
|
||||
"admin/get_rulelist_page",
|
||||
this.queryInfo
|
||||
);
|
||||
if (res.status !== 200) {
|
||||
this.loading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1000,
|
||||
});
|
||||
this.tableData = res.data.records;
|
||||
this.total = parseInt(res.data.total);
|
||||
this.loading = false;
|
||||
},
|
||||
async addRule() {
|
||||
const libraryList = this.addForm.checkList.join(',')
|
||||
this.addForm.bookLimitLibrary = libraryList;
|
||||
const { data: res } = await this.$http.post(
|
||||
"admin/add_rule",
|
||||
this.addForm
|
||||
);
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1500,
|
||||
});
|
||||
this.addDialogVisible = false;
|
||||
this.getRuleList();
|
||||
},
|
||||
async updateRule(){
|
||||
const {data:res} = await this.$http.put('admin/update_rule',this.editForm)
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1500,
|
||||
});
|
||||
this.getRuleList();
|
||||
this.editDialogVisible = false;
|
||||
},
|
||||
downLoad() {
|
||||
this.getPdf(this.title); //参数是下载的pdf文件名
|
||||
},
|
||||
fullScreen(){
|
||||
// Dom对象的一个属性: 可以用来判断当前是否为全屏模式(trueORfalse)
|
||||
let full = document.fullscreenElement;
|
||||
// 切换为全屏模式
|
||||
if(!full){
|
||||
// 文档根节点的方法requestFullscreen实现全屏模式
|
||||
document.documentElement.requestFullscreen();
|
||||
}else{
|
||||
// 退出全屏模式
|
||||
document.exitFullscreen();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getRuleList();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
203
src/components/Admin/StatementSearch.vue
Normal file
@ -0,0 +1,203 @@
|
||||
<template>
|
||||
<div class="search_container">
|
||||
<!-- 面包屑导航区域 -->
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item>首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>借阅信息查询</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<el-card shadow="always">
|
||||
<!-- 搜索内容和导出区域 -->
|
||||
<el-row>
|
||||
<el-col :span="6"
|
||||
>条件搜索:<el-select
|
||||
v-model="queryInfo.condition"
|
||||
filterable
|
||||
placeholder="请选择"
|
||||
style="margin-left: 15px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-input
|
||||
placeholder="请输入内容"
|
||||
v-model="queryInfo.query"
|
||||
class="input-with-select"
|
||||
@keyup.enter.native = "getBorrowStatement"
|
||||
>
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-search"
|
||||
@click="getBorrowStatement"
|
||||
></el-button> </el-input
|
||||
></el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<download-excel
|
||||
class="export-excel-wrapper"
|
||||
:data="tableData"
|
||||
:fields="json_fields"
|
||||
:header="title"
|
||||
name="借阅信息查询.xls"
|
||||
>
|
||||
<!-- 上面可以自定义自己的样式,还可以引用其他组件button -->
|
||||
<el-button type="primary" class="el-icon-printer" size="mini"
|
||||
>导出Excel</el-button
|
||||
>
|
||||
</download-excel>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<el-button
|
||||
type="primary"
|
||||
class="el-icon-printer"
|
||||
size="mini"
|
||||
@click="downLoad"
|
||||
>导出PDF</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
|
||||
<el-button type="success" class="el-icon-full-screen" size="mini" @click="fullScreen"
|
||||
>全屏</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 表格区域 -->
|
||||
<el-table :data="tableData" border style="width: 100%" stripe id="pdfDom" :default-sort = "{prop: 'violationId', order: 'ascending'}"
|
||||
v-loading="loading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)">
|
||||
<el-table-column prop="violationId" label="ID" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="cardNumber" label="借阅证号" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="bookNumber" label="书籍ID" sortable> </el-table-column>
|
||||
<el-table-column prop="borrowDate" label="借阅时间" sortable> </el-table-column>
|
||||
<el-table-column prop="closeDate" label="截止时间" sortable> </el-table-column>
|
||||
<el-table-column prop="returnDate" label="归还时间" sortable> </el-table-column>
|
||||
<el-table-column prop="violationMessage" label="违章信息"> </el-table-column>
|
||||
<el-table-column prop="violationAdmin" label="处理人"> </el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页查询区域 -->
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="queryInfo.pageNum"
|
||||
:page-sizes="[1, 2, 3, 4,5]"
|
||||
:page-size="queryInfo.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="this.total">
|
||||
</el-pagination>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{
|
||||
value: "card_number",
|
||||
label: "借阅证号",
|
||||
},
|
||||
{
|
||||
value: "book_number",
|
||||
label: "书籍ID",
|
||||
},
|
||||
{
|
||||
value: "borrow_date",
|
||||
label: "借阅时间",
|
||||
},
|
||||
{
|
||||
value: "close_date",
|
||||
label: "截止时间",
|
||||
},
|
||||
{
|
||||
value: "return_date",
|
||||
label: "归还时间",
|
||||
},
|
||||
{
|
||||
value: "violation_message",
|
||||
label: "违章信息",
|
||||
},
|
||||
],
|
||||
tableData: [],
|
||||
queryInfo: {
|
||||
pageNum: 1,
|
||||
pageSize: 5,
|
||||
condition: "",
|
||||
query: "",
|
||||
},
|
||||
total: 0,
|
||||
title: "借阅信息查询",
|
||||
json_fields: {
|
||||
ID: "violationId",
|
||||
借阅证编号: "cardNumber",
|
||||
书籍编号: "bookNumber",
|
||||
借阅日期: "borrowDate",
|
||||
截止日期: "closeDate",
|
||||
归还日期:"returnDate",
|
||||
违章信息:"violationMessage",
|
||||
处理人:"violationAdmin"
|
||||
},
|
||||
loading:true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(val) {
|
||||
this.queryInfo.pageSize = val;
|
||||
this.getBorrowStatement();
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.queryInfo.pageNum = val;
|
||||
this.getBorrowStatement();
|
||||
},
|
||||
async getBorrowStatement(){
|
||||
this.loading = true;
|
||||
const {data:res} = await this.$http.post('bookadmin/get_borrow_statement',this.queryInfo)
|
||||
// console.log(res);
|
||||
this.tableData = [];
|
||||
if (res.status !== 200) {
|
||||
this.total = 0;
|
||||
this.loading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1000,
|
||||
});
|
||||
this.tableData = res.data.records;
|
||||
this.total = parseInt(res.data.total);
|
||||
this.loading = false;
|
||||
},
|
||||
downLoad() {
|
||||
this.getPdf(this.title); //参数是下载的pdf文件名
|
||||
},
|
||||
fullScreen(){
|
||||
// Dom对象的一个属性: 可以用来判断当前是否为全屏模式(trueORfalse)
|
||||
let full = document.fullscreenElement;
|
||||
// 切换为全屏模式
|
||||
if(!full){
|
||||
// 文档根节点的方法requestFullscreen实现全屏模式
|
||||
document.documentElement.requestFullscreen();
|
||||
}else{
|
||||
// 退出全屏模式
|
||||
document.exitFullscreen();
|
||||
}
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.getBorrowStatement();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
163
src/components/BookManage/BookExpire.vue
Normal file
@ -0,0 +1,163 @@
|
||||
<template>
|
||||
<div class="expire_container">
|
||||
<div class="header">
|
||||
<p>归还图书</p>
|
||||
</div>
|
||||
<div class="banner">
|
||||
<div class="expireDays">
|
||||
<p>还剩{{this.expireInfo.expireDays}}天</p>
|
||||
</div>
|
||||
<div class="bookNumber">
|
||||
<el-input v-model="expireInfo.bookNumber" :readonly="true">
|
||||
<template slot="prepend">图书编号</template>
|
||||
<el-button slot="prepend" icon="el-icon-collection"> </el-button>
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="closeDate">
|
||||
<el-input v-model="expireInfo.closeDate" :readonly="true">
|
||||
<template slot="prepend">截止日期</template>
|
||||
<el-button slot="prepend" icon="el-icon-date"></el-button
|
||||
></el-input>
|
||||
</div>
|
||||
|
||||
<div class="violationMsg">
|
||||
<el-input
|
||||
v-model="returnInfo.violationMessage"
|
||||
placeholder="若无违章信息,则不填"
|
||||
>
|
||||
<template slot="prepend">违章信息</template>
|
||||
<el-button
|
||||
slot="prepend"
|
||||
icon="iconfont icon-weizhangchaxun"
|
||||
></el-button
|
||||
></el-input>
|
||||
</div>
|
||||
<div class="adminId">
|
||||
|
||||
<el-input v-model="expireInfo.bookAdminId" :readonly="true">
|
||||
<template slot="prepend">管理员编号</template>
|
||||
<el-button slot="prepend" icon="el-icon-s-custom"></el-button
|
||||
></el-input>
|
||||
</div>
|
||||
<div class="returnDate">
|
||||
<el-date-picker
|
||||
v-model="returnInfo.returnDate"
|
||||
type="datetime"
|
||||
placeholder="选择归还日期时间"
|
||||
default-time="12:00:00"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
prefix-icon="el-icon-date"
|
||||
>
|
||||
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="return_button">
|
||||
<el-button type="warning" @click="returnBook">归还</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
returnInfo: {
|
||||
returnDate: "",
|
||||
violationMessage: "",
|
||||
bookNumber:0,
|
||||
violationAdminId:0
|
||||
},
|
||||
expireInfo:{
|
||||
expireDays:47,
|
||||
bookNumber: 192,
|
||||
closeDate: "",
|
||||
bookAdminId:0
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async getExpireInfo(){
|
||||
// 先获取路由传参中的图书编号
|
||||
const bookNumber = this.$route.query.bookNumber;
|
||||
// 发送axios请求
|
||||
const {data:res} = await this.$http.get('bookadmin/query_expire/'+bookNumber);
|
||||
// console.log(res);
|
||||
if(res.status !== 200){
|
||||
return this.$message.error(res.msg)
|
||||
}
|
||||
this.$message.success(
|
||||
{
|
||||
message:res.msg,
|
||||
duration:1000
|
||||
}
|
||||
)
|
||||
this.expireInfo = res.data;
|
||||
const id = window.sessionStorage.getItem('bookAdminId')
|
||||
this.expireInfo.bookAdminId = parseInt(id);
|
||||
this.returnInfo.bookNumber = this.expireInfo.bookNumber;
|
||||
},
|
||||
async returnBook(){
|
||||
// 对表单参数进行校验
|
||||
if(this.returnInfo.returnDate===""){
|
||||
this.$message.error({
|
||||
message:"归还日期不能为空",
|
||||
duration:1000
|
||||
})
|
||||
return;
|
||||
}
|
||||
this.returnInfo.violationAdminId = parseInt(window.sessionStorage.getItem('bookAdminId'))
|
||||
const {data:res} = await this.$http.post('bookadmin/return_book',this.returnInfo)
|
||||
// console.log(res);
|
||||
if(res.status !== 200){
|
||||
return this.$message.error(res.msg)
|
||||
}
|
||||
this.$message.success(
|
||||
{
|
||||
message:res.msg,
|
||||
duration:1000
|
||||
}
|
||||
)
|
||||
this.$router.push('/returnbook');
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.getExpireInfo();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.header {
|
||||
text-align: center;
|
||||
height: 100px;
|
||||
// background-color: pink;
|
||||
p {
|
||||
font-size: 30px;
|
||||
line-height: 100px;
|
||||
}
|
||||
}
|
||||
.banner {
|
||||
height: 680px;
|
||||
// background-color:brown;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.expireDays {
|
||||
margin-top: 20px;
|
||||
width: 700px;
|
||||
height: 100px;
|
||||
border: 2px solid #ccc;
|
||||
text-align: center;
|
||||
p {
|
||||
line-height: 100px;
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
div:nth-child(n + 2) {
|
||||
margin-top: 25px;
|
||||
}
|
||||
}
|
||||
</style>
|
104
src/components/BookManage/BorrowBook.vue
Normal file
@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<div class="borrowbook_container">
|
||||
<div class="header"><p>借阅图书</p></div>
|
||||
<div class="banner">
|
||||
<div class="card_number">
|
||||
<el-input placeholder="请输入借阅证号" v-model.number="borrowInfo.cardNumber">
|
||||
<el-button slot="prepend" icon="el-icon-notebook-2"></el-button>
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="book_number">
|
||||
<el-input placeholder="请输入图书编号" v-model.number="borrowInfo.bookNumber">
|
||||
<el-button slot="prepend" icon="el-icon-collection"></el-button
|
||||
></el-input>
|
||||
</div>
|
||||
<div class="borrow_date">
|
||||
<el-date-picker
|
||||
v-model="borrowInfo.borrowDate"
|
||||
type="datetime"
|
||||
placeholder="选择日期时间"
|
||||
default-time="12:00:00"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
>
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="borrow_button">
|
||||
<el-button type="primary" @click="borrowBook">借阅</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
borrowInfo: {
|
||||
cardNumber: "",
|
||||
bookNumber: "",
|
||||
borrowDate: "",
|
||||
bookAdminId:0
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async borrowBook(){
|
||||
// console.log(this.borrowInfo.borrowDate);
|
||||
if(this.borrowInfo.borrowDate=== ""){
|
||||
return this.$message.error({
|
||||
message:"借阅时间不能为空",
|
||||
duration:1000
|
||||
})
|
||||
}
|
||||
this.borrowInfo.bookAdminId = parseInt(window.sessionStorage.getItem('bookAdminId'))
|
||||
const {data:res} = await this.$http.post('bookadmin/borrow_book',this.borrowInfo)
|
||||
if(res.status !== 200){
|
||||
return this.$message.error(res.msg)
|
||||
}
|
||||
this.$message.success(res.msg)
|
||||
// 清空数据
|
||||
this.borrowInfo.bookNumber = "";
|
||||
this.borrowInfo.cardNumber = "";
|
||||
this.borrowInfo.borrowDate = "";
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.borrowbook_container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.header {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
// background-color: pink;
|
||||
p {
|
||||
color: black;
|
||||
font-size: 30px;
|
||||
text-align: center;
|
||||
line-height: 60px;
|
||||
}
|
||||
}
|
||||
.banner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 60%;
|
||||
height: 400px;
|
||||
// background-color: brown;
|
||||
div {
|
||||
margin-top: 15px;
|
||||
// margin-left: ;
|
||||
}
|
||||
.borrow_date {
|
||||
margin-left: 8px;
|
||||
}
|
||||
.borrow_button {
|
||||
margin-top: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
219
src/components/BookManage/BorrowStatement.vue
Normal file
@ -0,0 +1,219 @@
|
||||
<template>
|
||||
<div class="search_container">
|
||||
<!-- 面包屑导航区域 -->
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item>首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>借书报表</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<el-card shadow="always">
|
||||
<!-- 搜索内容和导出区域 -->
|
||||
<el-row>
|
||||
<el-col :span="6"
|
||||
>条件搜索:<el-select
|
||||
v-model="queryInfo.condition"
|
||||
filterable
|
||||
placeholder="请选择"
|
||||
style="margin-left: 15px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-input
|
||||
placeholder="请输入内容"
|
||||
v-model="queryInfo.query"
|
||||
class="input-with-select"
|
||||
@keyup.enter.native="getBorrowStatement"
|
||||
>
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-search"
|
||||
@click="getBorrowStatement"
|
||||
></el-button> </el-input
|
||||
></el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<download-excel
|
||||
class="export-excel-wrapper"
|
||||
:data="tableData"
|
||||
:fields="json_fields"
|
||||
:header="title"
|
||||
name="借书报表.xls"
|
||||
>
|
||||
<!-- 上面可以自定义自己的样式,还可以引用其他组件button -->
|
||||
<el-button type="primary" class="el-icon-printer" size="mini"
|
||||
>导出Excel</el-button
|
||||
>
|
||||
</download-excel>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<el-button
|
||||
type="primary"
|
||||
class="el-icon-printer"
|
||||
size="mini"
|
||||
@click="downLoad"
|
||||
>导出PDF</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
|
||||
<el-button type="success" class="el-icon-full-screen" size="mini" @click="fullScreen"
|
||||
>全屏</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 表格区域 -->
|
||||
<el-table
|
||||
:data="tableData"
|
||||
border
|
||||
style="width: 100%"
|
||||
stripe
|
||||
id="pdfDom"
|
||||
:default-sort="{ prop: 'cardNumber', order: 'ascending' }"
|
||||
v-loading="loading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)"
|
||||
>
|
||||
<el-table-column prop="cardNumber" label="借阅证编号" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="bookNumber" label="图书编号" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="borrowDate" label="借阅日期" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="closeDate" label="截止日期" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="returnDate" label="归还日期" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="violationMessage" label="违章信息">
|
||||
</el-table-column>
|
||||
<el-table-column prop="violationAdmin" label="处理人">
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页查询区域 -->
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="queryInfo.pageNum"
|
||||
:page-sizes="[1, 2, 3, 4, 5]"
|
||||
:page-size="queryInfo.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="this.total"
|
||||
>
|
||||
</el-pagination>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{
|
||||
value: "card_number",
|
||||
label: "借阅证号",
|
||||
},
|
||||
{
|
||||
value: "book_number",
|
||||
label: "图书编号",
|
||||
},
|
||||
{
|
||||
value: "borrow_date",
|
||||
label: "借阅日期",
|
||||
},
|
||||
{
|
||||
value: "close_date",
|
||||
label: "截止日期",
|
||||
},
|
||||
{
|
||||
value: "return_date",
|
||||
label: "归还日期",
|
||||
},
|
||||
{
|
||||
value: "violation_message",
|
||||
label: "违章信息",
|
||||
},
|
||||
],
|
||||
tableData: [],
|
||||
queryInfo: {
|
||||
pageNum: 1,
|
||||
pageSize: 5,
|
||||
condition: "",
|
||||
query: "",
|
||||
},
|
||||
total: 0,
|
||||
title: "借书报表",
|
||||
json_fields: {
|
||||
借阅证编号: "cardNumber",
|
||||
图书编号: "bookNumber",
|
||||
借阅日期: "borrowDate",
|
||||
截止日期: "closeDate",
|
||||
归还日期: "returnDate",
|
||||
违章信息: "violationMessage",
|
||||
处理人: "violationAdmin",
|
||||
},
|
||||
loading:true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(val) {
|
||||
this.queryInfo.pageSize = val;
|
||||
|
||||
this.getBorrowStatement();
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.queryInfo.pageNum = val;
|
||||
|
||||
this.getBorrowStatement();
|
||||
},
|
||||
async getBorrowStatement() {
|
||||
this.loading = true;
|
||||
const { data: res } = await this.$http.post(
|
||||
"bookadmin/get_borrow_statement",
|
||||
this.queryInfo
|
||||
);
|
||||
// console.log(res);
|
||||
this.tableData = [];
|
||||
if (res.status !== 200) {
|
||||
this.total = 0;
|
||||
this.loading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1000,
|
||||
});
|
||||
this.tableData = res.data.records;
|
||||
this.total = parseInt(res.data.total);
|
||||
this.loading = false;
|
||||
},
|
||||
downLoad() {
|
||||
this.getPdf(this.title); //参数是下载的pdf文件名
|
||||
},
|
||||
fullScreen(){
|
||||
// Dom对象的一个属性: 可以用来判断当前是否为全屏模式(trueORfalse)
|
||||
let full = document.fullscreenElement;
|
||||
// 切换为全屏模式
|
||||
if(!full){
|
||||
// 文档根节点的方法requestFullscreen实现全屏模式
|
||||
document.documentElement.requestFullscreen();
|
||||
}else{
|
||||
// 退出全屏模式
|
||||
document.exitFullscreen();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getBorrowStatement();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
248
src/components/BookManage/LoginBookManage.vue
Normal file
@ -0,0 +1,248 @@
|
||||
<template>
|
||||
<div class="login_container">
|
||||
<div class="login_title">图书管理员登录界面</div>
|
||||
<div class="login_box">
|
||||
<!-- 头像区域 -->
|
||||
<div class="avatar_box">
|
||||
<img
|
||||
src="https://xxx.xiaobaitiao.icu/img/icu/202312211243634.jpg"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<!-- 登录表单区域 -->
|
||||
<el-form
|
||||
ref="loginFormRef"
|
||||
:model="loginForm"
|
||||
:rules="loginFormRules"
|
||||
label-width="0px"
|
||||
class="login_form"
|
||||
>
|
||||
<!-- 用户名 -->
|
||||
<el-form-item prop="username">
|
||||
<el-input
|
||||
v-model.trim="loginForm.username"
|
||||
prefix-icon="iconfont icon-gerenxinxi"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<!-- 密码 -->
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
v-model="loginForm.password"
|
||||
prefix-icon="iconfont icon-tianchongxing-"
|
||||
type="password"
|
||||
@keyup.enter.native="login"
|
||||
:show-password="true"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<!-- 按钮区域 -->
|
||||
<el-form-item class="btns">
|
||||
<el-button type="primary" @click="login" :loading="loginLoading"
|
||||
>登录
|
||||
</el-button>
|
||||
<el-button type="info" @click="resetLoginForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<vue-particles
|
||||
class="login-bg"
|
||||
color="#39AFFD"
|
||||
:particleOpacity="0.7"
|
||||
:particlesNumber="100"
|
||||
shapeType="circle"
|
||||
:particleSize="4"
|
||||
linesColor="#8DD1FE"
|
||||
:linesWidth="1"
|
||||
:lineLinked="true"
|
||||
:lineOpacity="0.4"
|
||||
:linesDistance="150"
|
||||
:moveSpeed="3"
|
||||
:hoverEffect="true"
|
||||
hoverMode="grab"
|
||||
:clickEffect="true"
|
||||
clickMode="push"
|
||||
>
|
||||
</vue-particles>
|
||||
<div class="footer">
|
||||
<span style="font-weight: bold;color:white;">
|
||||
登录页面切换
|
||||
</span>
|
||||
<span><i class="iconfont icon-haoyou" @click="goUser"></i></span>
|
||||
<span>
|
||||
<i class="iconfont icon-guanliyuanrenzheng" @click="goAdmin"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="footer2">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
//登录表单
|
||||
loginForm: {
|
||||
username: "admin",
|
||||
password: "123456",
|
||||
},
|
||||
//登录表单规则的验证对象
|
||||
loginFormRules: {
|
||||
username: [
|
||||
{ required: true, message: "用户名不能为空", trigger: "blur" },
|
||||
{
|
||||
min: 3,
|
||||
max: 20,
|
||||
message: "长度在 3 到 20 个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: "密码不能为空", trigger: "blur" },
|
||||
{
|
||||
min: 6,
|
||||
max: 15,
|
||||
message: "长度在 6 到 15 个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
},
|
||||
loginLoading: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
resetLoginForm() {
|
||||
this.$refs.loginFormRef.resetFields();
|
||||
},
|
||||
login() {
|
||||
this.$refs.loginFormRef.validate(async (valid) => {
|
||||
// console.log(valid);
|
||||
//如果表单验证无效,直接返回
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
this.loginLoading = true;
|
||||
// 进行md5加密
|
||||
const username = this.loginForm.username;
|
||||
const password = this.loginForm.password;
|
||||
//向数据库发送axios请求,如果登录成功,就跳转
|
||||
const { data: res } = await this.$http.post("bookadmin/login", {
|
||||
username,
|
||||
password,
|
||||
});
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
this.loginLoading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success("登录成功");
|
||||
this.loginLoading = false;
|
||||
window.sessionStorage.setItem("token", res.map.token);
|
||||
window.sessionStorage.setItem("bookAdminId", res.map.id);
|
||||
this.$router.push("/homemange");
|
||||
// window.sessionStorage.setItem("token", token);
|
||||
// this.$router.push("/home"); //跳转到home页面下
|
||||
});
|
||||
},
|
||||
goUser() {
|
||||
this.$router.push("/login");
|
||||
},
|
||||
goAdmin() {
|
||||
this.$router.push("/loginadmin");
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.footer2 {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 35%;
|
||||
color: #ccc;
|
||||
|
||||
a {
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
.login_container {
|
||||
// background-color: #2b4b6b;
|
||||
background: url(https://xxx.xiaobaitiao.icu/img/icu/202312211236280.jpg) no-repeat
|
||||
0px 0px;
|
||||
background-size: cover;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.login_box {
|
||||
height: 300px;
|
||||
width: 450px;
|
||||
background-color: #fff;
|
||||
border-radius: 3px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
.avatar_box {
|
||||
width: 130px;
|
||||
height: 130px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 50%;
|
||||
padding: 10px;
|
||||
box-shadow: 0 0 10px #ddd;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: #fff;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login_form {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
padding: 0 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.btns {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.login_title {
|
||||
position: relative;
|
||||
top: 5%;
|
||||
font-size: 36px;
|
||||
color: white;
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
//控制字体间距
|
||||
letter-spacing: 10px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
flex-direction: column;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 100px;
|
||||
height: 120px;
|
||||
// background-color: pink;
|
||||
span {
|
||||
// width: 100%;
|
||||
// background-color: red;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
317
src/components/BookManage/NoticeManage.vue
Normal file
@ -0,0 +1,317 @@
|
||||
<template>
|
||||
<div class="search_container">
|
||||
<!-- 面包屑导航区域 -->
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item>首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>发布公告</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<el-card shadow="always">
|
||||
<!-- 搜索内容和导出区域 -->
|
||||
<el-row>
|
||||
<el-col :span="4">
|
||||
<el-button type="primary" @click="showAddDialog()">
|
||||
<i class="el-icon-s-promotion"></i> 发布新公告</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 表格区域 -->
|
||||
<el-table :data="tableData" border style="width: 100%" stripe
|
||||
v-loading="loading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)">
|
||||
<el-table-column prop="noticeId" label="ID"> </el-table-column>
|
||||
<el-table-column prop="noticeTitle" label="标题"> </el-table-column>
|
||||
<el-table-column prop="noticeContent" label="公告"> </el-table-column>
|
||||
<el-table-column prop="createTime" label="发布日期"> </el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template slot-scope="scope">
|
||||
<!-- 修改按钮 -->
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="修改"
|
||||
placement="top"
|
||||
:enterable="false"
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
@click="showEditDialog(scope.row.noticeId)"
|
||||
></el-button
|
||||
></el-tooltip>
|
||||
|
||||
<!-- 删除按钮 -->
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="删除"
|
||||
placement="top"
|
||||
:enterable="false"
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
@click="removeUserById(scope.row.noticeId)"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页查询区域 -->
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="queryInfo.pageNum"
|
||||
:page-sizes="[1, 2, 3, 4,5]"
|
||||
:page-size="queryInfo.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="this.total"
|
||||
>
|
||||
</el-pagination>
|
||||
<!-- 修改公告的对话框 -->
|
||||
<el-dialog
|
||||
title="修改公告"
|
||||
:visible.sync="editDialogVisible"
|
||||
width="50%"
|
||||
@close="editDialogClosed"
|
||||
>
|
||||
<el-form
|
||||
:model="editForm"
|
||||
ref="editFormRef"
|
||||
:rules="editFormRules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="公告标题" prop="noticeTitle">
|
||||
<el-input v-model="editForm.noticeTitle"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="公告内容" prop="noticeContent">
|
||||
<el-input
|
||||
type="textarea"
|
||||
v-model="editForm.noticeContent"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="editDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="editNoticeById"
|
||||
>确 定</el-button
|
||||
>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<!-- 添加公告的对话框 -->
|
||||
<el-dialog
|
||||
title="添加公告"
|
||||
:visible.sync="addDialogVisible"
|
||||
width="50%"
|
||||
@close="addDialogClosed"
|
||||
>
|
||||
<el-form
|
||||
:model="addForm"
|
||||
ref="addFormRef"
|
||||
:rules="addFormRules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="公告标题" prop="noticeTitle">
|
||||
<el-input v-model="addForm.noticeTitle"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="公告内容" prop="noticeContent">
|
||||
<el-input
|
||||
type="textarea"
|
||||
v-model="addForm.noticeContent"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="addDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="addNotice"
|
||||
>添加公告</el-button
|
||||
>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
|
||||
tableData: [],
|
||||
|
||||
editDialogVisible: false,
|
||||
editForm: {
|
||||
noticeTitle: "",
|
||||
noticeContent: "",
|
||||
},
|
||||
editFormRules: {
|
||||
noticeTitle: [
|
||||
{ required: true, message: "请输入公告标题", trigger: "blur" },
|
||||
{
|
||||
min: 6,
|
||||
max: 30,
|
||||
message: "长度在6到30个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
noticeContent: [
|
||||
{ required: true, message: "请输入公告内容", trigger: "blur" },
|
||||
],
|
||||
},
|
||||
addDialogVisible:false,
|
||||
addForm:{
|
||||
noticeTitle:"",
|
||||
noticeContent:"",
|
||||
noticeAdminId:0
|
||||
},
|
||||
addFormRules:{
|
||||
noticeTitle: [
|
||||
{ required: true, message: "请输入公告标题", trigger: "blur" },
|
||||
{
|
||||
min: 6,
|
||||
max: 30,
|
||||
message: "长度在6到30个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
noticeContent: [
|
||||
{ required: true, message: "请输入公告内容", trigger: "blur" },
|
||||
],
|
||||
},
|
||||
queryInfo: {
|
||||
pageNum: 1,
|
||||
pageSize: 5,
|
||||
},
|
||||
total: 0,
|
||||
loading:true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(val) {
|
||||
this.queryInfo.pageSize = val;
|
||||
|
||||
this.getNoticeList();
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.queryInfo.pageNum = val;
|
||||
|
||||
this.getNoticeList();
|
||||
},
|
||||
//让修改公告的对话框可见,并从数据库中回显数据
|
||||
async showEditDialog(id) {
|
||||
this.loading = true;
|
||||
const {data:res} = await this.$http.get('bookadmin/get_notice/'+id);
|
||||
if(res.status !== 200){
|
||||
|
||||
return this.$message.error(res.msg)
|
||||
}
|
||||
// console.log(res);
|
||||
this.editForm = res.data;
|
||||
// 让修改公告的对话框可见
|
||||
this.editDialogVisible = true;
|
||||
|
||||
},
|
||||
//监听修改对话框的关闭,一旦对话框关闭,就重置表单,回显数据
|
||||
editDialogClosed() {
|
||||
this.$refs.editFormRef.resetFields();
|
||||
},
|
||||
// 修改公告根据公告id
|
||||
async editNoticeById(){
|
||||
const {data:res} = await this.$http.put('bookadmin/update_notice/'+this.editForm.noticeId,{
|
||||
noticeTitle:this.editForm.noticeTitle,
|
||||
noticeContent:this.editForm.noticeContent
|
||||
})
|
||||
if(res.status !== 200){
|
||||
return this.$message.error(res.msg)
|
||||
}
|
||||
// 对话框不可见
|
||||
this.editDialogVisible = false;
|
||||
this.getNoticeList();
|
||||
this.$message.success(res.msg)
|
||||
},
|
||||
//删除公告
|
||||
async removeUserById(id) {
|
||||
//弹框,询问用户是否删除数据
|
||||
const confirmResult = await this.$confirm(
|
||||
"此操作将永久删除该公告, 是否继续?",
|
||||
"提示",
|
||||
{
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}
|
||||
).catch((error) => {
|
||||
return error;
|
||||
});
|
||||
//如果用户确认删除,则返回值为字符串confirm
|
||||
//如果用户取消删除,则返回值为字符串cancel
|
||||
// console.log(confirmResult);
|
||||
if (confirmResult !== "confirm") {
|
||||
return this.$message.info("已经取消删除");
|
||||
}
|
||||
//如果用户确认删除,那么下一步就是发送axios请求,检查响应状态码是否成功,成功则返回删除成功,否则返回删除失败
|
||||
const {data:res} = await this.$http.get('bookadmin/delete_notice/'+id)
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1500,
|
||||
});
|
||||
this.getNoticeList();
|
||||
},
|
||||
//监听添加公告对话框的关闭,一旦对话框关闭,就重置表单
|
||||
addDialogClosed(){
|
||||
this.$refs.addFormRef.resetFields();
|
||||
},
|
||||
//当用户点击发送新公告时,让添加对话框的visible改为true
|
||||
showAddDialog(){
|
||||
this.addDialogVisible = true;
|
||||
},
|
||||
async getNoticeList(){
|
||||
this.loading = true;
|
||||
const {data:res} = await this.$http.post('bookadmin/get_noticelist',this.queryInfo)
|
||||
// console.log(res);
|
||||
|
||||
this.tableData = [];
|
||||
if (res.status !== 200) {
|
||||
this.total = 0;
|
||||
this.loading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1000,
|
||||
});
|
||||
this.tableData = res.data.records;
|
||||
this.total = parseInt(res.data.total);
|
||||
this.loading = false;
|
||||
},
|
||||
async addNotice(){
|
||||
// 取消可见性
|
||||
this.addDialogVisible = false;
|
||||
// 获取图书管理员id
|
||||
this.addForm.noticeAdminId = parseInt(window.sessionStorage.getItem('bookAdminId'))
|
||||
// 发送axios请求添加公告
|
||||
const {data:res} = await this.$http.post('bookadmin/add_notice',this.addForm)
|
||||
console.log(res);
|
||||
if(res.status!== 200){
|
||||
return this.$message.error(res.msg)
|
||||
}
|
||||
this.$message.success({
|
||||
message:res.msg,
|
||||
duration:1000
|
||||
})
|
||||
this.getNoticeList();
|
||||
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.getNoticeList();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
86
src/components/BookManage/ReturnBook.vue
Normal file
@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div class="borrowbook_container">
|
||||
<div class="header"><p>查看图书是否逾期</p></div>
|
||||
<div class="banner">
|
||||
<div class="book_number">
|
||||
<el-input placeholder="请输入图书编号" v-model="bookNumber">
|
||||
<el-button slot="prepend" icon="el-icon-collection"></el-button
|
||||
></el-input>
|
||||
</div>
|
||||
<div class="query_button">
|
||||
<el-button type="warning" @click="goExpire">查询</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
bookNumber: "",
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async goExpire() {
|
||||
// 发送axios请求,携带图书编号 如果返回状态码为成功 跳转逾期的页面 否则提示未借出图书
|
||||
const { data: res } = await this.$http.get(
|
||||
"bookadmin/query_book/" + this.bookNumber
|
||||
);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(
|
||||
{
|
||||
message:res.msg,
|
||||
duration:1000
|
||||
}
|
||||
);
|
||||
}
|
||||
// console.log(res);
|
||||
// this.$message.success(res.msg);
|
||||
this.$router.push({
|
||||
name:"bookexpire",
|
||||
query:{
|
||||
bookNumber:this.bookNumber
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.borrowbook_container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.header {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
// background-color: pink;
|
||||
p {
|
||||
color: black;
|
||||
font-size: 30px;
|
||||
text-align: center;
|
||||
line-height: 60px;
|
||||
}
|
||||
}
|
||||
.banner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 60%;
|
||||
height: 400px;
|
||||
// background-color: brown;
|
||||
div {
|
||||
margin-top: 15px;
|
||||
// margin-left: ;
|
||||
}
|
||||
.borrow_date {
|
||||
margin-left: 8px;
|
||||
}
|
||||
.query_button {
|
||||
margin-top: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
208
src/components/BookManage/ReturnStatement.vue
Normal file
@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<div class="search_container">
|
||||
<!-- 面包屑导航区域 -->
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item>首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>还书报表</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<el-card shadow="always">
|
||||
<!-- 搜索内容和导出区域 -->
|
||||
<el-row>
|
||||
<el-col :span="6"
|
||||
>条件搜索:<el-select
|
||||
v-model="queryInfo.condition"
|
||||
filterable
|
||||
placeholder="请选择"
|
||||
style="margin-left: 15px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-input
|
||||
placeholder="请输入内容"
|
||||
v-model="queryInfo.query"
|
||||
class="input-with-select"
|
||||
@keyup.enter.native="getRuturnStatement"
|
||||
>
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-search"
|
||||
@click="getRuturnStatement"
|
||||
></el-button> </el-input
|
||||
></el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<download-excel
|
||||
class="export-excel-wrapper"
|
||||
:data="tableData"
|
||||
:fields="json_fields"
|
||||
:header="title"
|
||||
name="还书报表.xls"
|
||||
>
|
||||
<!-- 上面可以自定义自己的样式,还可以引用其他组件button -->
|
||||
<el-button type="primary" class="el-icon-printer" size="mini"
|
||||
>导出Excel</el-button
|
||||
>
|
||||
</download-excel>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<el-button
|
||||
type="primary"
|
||||
class="el-icon-printer"
|
||||
size="mini"
|
||||
@click="downLoad"
|
||||
>导出PDF</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
|
||||
<el-button type="success" class="el-icon-full-screen" size="mini" @click="fullScreen"
|
||||
>全屏</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 表格区域 -->
|
||||
<el-table
|
||||
:data="tableData"
|
||||
border
|
||||
style="width: 100%"
|
||||
stripe
|
||||
id="pdfDom"
|
||||
:default-sort="{ prop: 'cardNumber', order: 'ascending' }"
|
||||
v-loading="loading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)"
|
||||
>
|
||||
<el-table-column prop="cardNumber" label="借阅证编号" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="bookNumber" label="图书编号" sortable> </el-table-column>
|
||||
<el-table-column prop="borrowDate" label="借阅日期" sortable> </el-table-column>
|
||||
<el-table-column prop="closeDate" label="截止日期" sortable> </el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页查询区域 -->
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="queryInfo.pageNum"
|
||||
:page-sizes="[1, 2, 3, 4, 5]"
|
||||
:page-size="queryInfo.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="this.total"
|
||||
>
|
||||
</el-pagination>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{
|
||||
value: "card_number",
|
||||
label: "借阅证号",
|
||||
},
|
||||
{
|
||||
value: "book_number",
|
||||
label: "图书编号",
|
||||
},
|
||||
{
|
||||
value: "borrow_date",
|
||||
label: "借阅日期",
|
||||
},
|
||||
{
|
||||
value: "close_date",
|
||||
label: "截止日期",
|
||||
},
|
||||
],
|
||||
tableData: [
|
||||
{
|
||||
cardNumber: Number,
|
||||
bookNumber: Number,
|
||||
borrowDate: "",
|
||||
closeDate: "",
|
||||
},
|
||||
],
|
||||
|
||||
queryInfo: {
|
||||
pageNum: 1,
|
||||
pageSize: 5,
|
||||
condition: "",
|
||||
query: "",
|
||||
},
|
||||
total: 0,
|
||||
title: "借书报表",
|
||||
json_fields: {
|
||||
借阅证号: "cardNumber",
|
||||
图书编号: "bookNumber",
|
||||
借阅日期: "borrowDate",
|
||||
截止日期: "closeDate",
|
||||
},
|
||||
loading:true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(val) {
|
||||
this.queryInfo.pageSize = val;
|
||||
|
||||
this.getRuturnStatement();
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.queryInfo.pageNum = val;
|
||||
|
||||
this.getRuturnStatement();
|
||||
},
|
||||
async getRuturnStatement() {
|
||||
this.loading = true;
|
||||
const { data: res } = await this.$http.post(
|
||||
"bookadmin/get_return_statement",
|
||||
this.queryInfo
|
||||
);
|
||||
// console.log(res);
|
||||
|
||||
this.tableData = [];
|
||||
if (res.status !== 200) {
|
||||
this.total = 0;
|
||||
this.loading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1000,
|
||||
});
|
||||
this.tableData = res.data.records;
|
||||
this.total = parseInt(res.data.total);
|
||||
this.loading = false;
|
||||
},
|
||||
downLoad() {
|
||||
this.getPdf(this.title); //参数是下载的pdf文件名
|
||||
},
|
||||
fullScreen(){
|
||||
// Dom对象的一个属性: 可以用来判断当前是否为全屏模式(trueORfalse)
|
||||
let full = document.fullscreenElement;
|
||||
// 切换为全屏模式
|
||||
if(!full){
|
||||
// 文档根节点的方法requestFullscreen实现全屏模式
|
||||
document.documentElement.requestFullscreen();
|
||||
}else{
|
||||
// 退出全屏模式
|
||||
document.exitFullscreen();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getRuturnStatement();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
62
src/components/Chart/ChartLint.vue
Normal file
@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div id="echart-line" :style="{ width: '100%', height: '100%' }"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from "echarts";
|
||||
export default {
|
||||
methods: {
|
||||
initChart(name, xData, yData) {
|
||||
// echarts.init('根元素','主题')
|
||||
let getchart = echarts.init(document.getElementById("echart-line"));
|
||||
var option = {
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: { type: "cross" },
|
||||
},
|
||||
legend: {
|
||||
data: [name],
|
||||
bottom: "0%",
|
||||
|
||||
},
|
||||
grid: {
|
||||
//调整图表上下左右位置
|
||||
top: "10%",
|
||||
left: "10%",
|
||||
right: "10%",
|
||||
bottom: "10%",
|
||||
containLabel: true,
|
||||
},
|
||||
|
||||
xAxis: {
|
||||
type: "category",
|
||||
boundaryGap: false,
|
||||
data: xData,
|
||||
axisLabel: {
|
||||
formatter: "{value}",
|
||||
align: "center",
|
||||
// ...
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: name,
|
||||
type: "line",
|
||||
data: yData,
|
||||
barWidth: "20%",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
getchart.setOption(option);
|
||||
//随着屏幕大小调节图表
|
||||
window.addEventListener("resize", () => {
|
||||
getchart.resize();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
49
src/components/Chart/PieChart.vue
Normal file
@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<div id="echart-pie" :style="{ width: '100%', height: '100%' }"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from "echarts";
|
||||
|
||||
export default {
|
||||
methods: {
|
||||
initChart(pieData) {
|
||||
var chartDom = document.getElementById("echart-pie");
|
||||
var myChart = echarts.init(chartDom);
|
||||
var option = {
|
||||
title: {
|
||||
text: "借书类型分析统计图",
|
||||
left: "center",
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
},
|
||||
legend: {
|
||||
orient: "vertical",
|
||||
left: "left",
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "借书类型分析统计图",
|
||||
type: "pie",
|
||||
radius: "50%",
|
||||
data:pieData,
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: "rgba(0, 0, 0, 0.5)",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
option && myChart.setOption(option);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
230
src/components/Home/Home.vue
Normal file
@ -0,0 +1,230 @@
|
||||
<template>
|
||||
<el-container class="home-container">
|
||||
<!-- 头部区域 -->
|
||||
<el-header>
|
||||
<div>
|
||||
<!-- <img src="../assets/heima.png" alt="" /> -->
|
||||
<span>欢迎登录图书管理系统</span>
|
||||
<span style="color: #ccc; font-size: 16px">借阅者界面</span>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
<div>
|
||||
<el-avatar src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" :size="35"
|
||||
style="margin-right: 10px"></el-avatar>
|
||||
</div>
|
||||
|
||||
<div class="user">用户:{{ this.user.cardName }}</div>
|
||||
<el-button type="info" @click="logout">退出</el-button>
|
||||
</div>
|
||||
</el-header>
|
||||
<!-- 页面主体区域 -->
|
||||
<el-container>
|
||||
<!-- 侧边栏 -->
|
||||
<el-aside :width="isCollapse ? '64px' : '200px'">
|
||||
<div class="toggle-button" @click="toggleCollapse">|||</div>
|
||||
<!-- 侧边栏菜单区域 -->
|
||||
<el-menu :default-active="activePath" class="el-menu-vertical-demo" background-color="#fff" text-color="black"
|
||||
active-text-color="#ffd04b" :router="true" :collapse="isCollapse" :collapse-transition="false">
|
||||
<el-menu-item index="index" @click="saveNavState('index')">
|
||||
<i class="iconfont icon-shouyefill"></i>
|
||||
<span slo="title">首页</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="search" @click="saveNavState('search')">
|
||||
<i class="iconfont icon-sousuoxiao"></i>
|
||||
<span slot="title">图书查询</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="rule" @click="saveNavState('rule')">
|
||||
<i class="iconfont icon-guizeshezhi"></i>
|
||||
<span slot="title">读者规则</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="notice" @click="saveNavState('notice')">
|
||||
<i class="iconfont icon-gonggao1"></i>
|
||||
<span slot="title">查看公告</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="information" @click="saveNavState('information')">
|
||||
<i class="iconfont icon-gerenxinxi"></i>
|
||||
<span slot="title">个人信息</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="borrow" @click="saveNavState('borrow')">
|
||||
<i class="iconfont icon-tushuqikan"></i>
|
||||
<span slot="title">借阅信息</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="violation" @click="saveNavState('violation')">
|
||||
<i class="iconfont icon-weizhangchaxun"></i>
|
||||
<span slot="title">违章信息</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="comment" @click="saveNavState('comment')">
|
||||
<i class="iconfont icon-liuyan"></i>
|
||||
<span slot="title">读者留言</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="intelligent" @click="saveNavState('intelligent')">
|
||||
<i class="el-icon-monitor"></i>
|
||||
<span slot="title">智能推荐</span>
|
||||
</el-menu-item>
|
||||
<!-- <el-menu-item index="chat" @click="saveNavState('chat')">-->
|
||||
<!-- <i class="el-icon-monitor"></i>-->
|
||||
<!-- <span slot="title">图书反馈</span>-->
|
||||
<!-- </el-menu-item>-->
|
||||
</el-menu>
|
||||
</el-aside>
|
||||
<!-- 右侧内容主体 -->
|
||||
<el-main>
|
||||
<!-- 路由占位符 -->
|
||||
<router-view></router-view>
|
||||
<div class="footer">
|
||||
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
//左侧菜单数据
|
||||
menulist: [],
|
||||
iconsObj: {
|
||||
125: "iconfont icon-user",
|
||||
103: "iconfont icon-tijikongjian",
|
||||
101: "iconfont icon-shangpin",
|
||||
102: "iconfont icon-danju",
|
||||
145: "iconfont icon-baobiao",
|
||||
},
|
||||
//是否折叠
|
||||
isCollapse: false,
|
||||
//被激活的链接地址
|
||||
activePath: "",
|
||||
user: {
|
||||
userId: Number,
|
||||
cardNumber: Number,
|
||||
ruleNumber: Number,
|
||||
status: Number,
|
||||
cardName: "",
|
||||
username: "",
|
||||
password: "",
|
||||
createTime: "",
|
||||
updateTime: "",
|
||||
},
|
||||
};
|
||||
},
|
||||
async created() {
|
||||
// this.getMenuList();
|
||||
this.activePath = window.sessionStorage.getItem("activePath");
|
||||
// console.log(this.activePath)
|
||||
// 先获取sessionStorage中的id
|
||||
const stringId = window.sessionStorage.getItem("userId");
|
||||
const id = parseInt(stringId);
|
||||
this.user.userId = id;
|
||||
const { data: res } = await this.$http.post("user/getData", this.user);
|
||||
console.log(res);
|
||||
window.sessionStorage.setItem('cardNumber', res.data.cardNumber)
|
||||
this.user = res.data;
|
||||
},
|
||||
async mounted() { },
|
||||
methods: {
|
||||
logout() {
|
||||
window.sessionStorage.clear();
|
||||
this.$router.push("/login");
|
||||
},
|
||||
|
||||
|
||||
//点击按钮,切换菜单的折叠与展开
|
||||
toggleCollapse() {
|
||||
this.isCollapse = !this.isCollapse;
|
||||
},
|
||||
//保存链接的激活状态
|
||||
saveNavState(activePath) {
|
||||
// console.log("first")
|
||||
window.sessionStorage.setItem("activePath", activePath);
|
||||
this.activePath = activePath;
|
||||
// console.log(this.activePath);
|
||||
},
|
||||
toGitee() {
|
||||
console.log(1123);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
left: 40%;
|
||||
color: #ccc;
|
||||
|
||||
a {
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
.home-container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.el-header {
|
||||
background-color: rgb(34, 34, 34);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-left: 0px;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
border-radius: 10px;
|
||||
|
||||
>div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-aside {
|
||||
background-color: #fff;
|
||||
|
||||
.el-menu {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
|
||||
.el-main {
|
||||
background-color: #eaedf1;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.toggle-button {
|
||||
background-color: #4a5064;
|
||||
font-size: 10px;
|
||||
line-height: 24px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
//设置文字之间的间距
|
||||
letter-spacing: 0.2em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.user {
|
||||
margin-right: 15px;
|
||||
color: #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.el-menu-item:hover {
|
||||
background-color: rgb(51, 122, 183) !important;
|
||||
}
|
||||
|
||||
// .el-menu-item{
|
||||
// color:rgb(135, 206, 235) !important;
|
||||
// }</style>
|
227
src/components/Home/HomeAdmin.vue
Normal file
@ -0,0 +1,227 @@
|
||||
<template>
|
||||
<el-container class="home-container">
|
||||
<!-- 头部区域 -->
|
||||
<el-header>
|
||||
<div>
|
||||
<!-- <img src="../assets/heima.png" alt="" /> -->
|
||||
<span>欢迎登录图书管理系统</span>
|
||||
<span style="color: #ccc; font-size: 16px">系统管理人员页面</span>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
<div>
|
||||
<el-avatar
|
||||
src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"
|
||||
:size="35"
|
||||
style="margin-right: 10px"
|
||||
></el-avatar>
|
||||
</div>
|
||||
<div class="user">管理员:{{ this.admin.adminName }}</div>
|
||||
<el-button type="info" @click="logout">退出</el-button>
|
||||
</div>
|
||||
</el-header>
|
||||
<!-- 页面主体区域 -->
|
||||
<el-container>
|
||||
<!-- 侧边栏 -->
|
||||
<el-aside :width="isCollapse ? '64px' : '200px'">
|
||||
<div class="toggle-button" @click="toggleCollapse">|||</div>
|
||||
<!-- 侧边栏菜单区域 -->
|
||||
<el-menu
|
||||
:default-active="activePath"
|
||||
class="el-menu-vertical-demo"
|
||||
background-color="#fff"
|
||||
text-color="black"
|
||||
active-text-color="#ffd04b"
|
||||
:router="true"
|
||||
:collapse="isCollapse"
|
||||
:collapse-transition="false"
|
||||
>
|
||||
<el-menu-item index="bookmanage" @click="saveNavState('bookmanage')">
|
||||
<i class="el-icon-notebook-1"></i>
|
||||
<span slo="title">书籍管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="booktype" @click="saveNavState('booktype')">
|
||||
<i class="el-icon-notebook-2"></i>
|
||||
<span slot="title">书籍类型</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item
|
||||
index="statementmanage"
|
||||
@click="saveNavState('statementmanage')"
|
||||
>
|
||||
<i class="el-icon-bank-card"></i>
|
||||
<span slot="title">借阅证管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item
|
||||
index="statementsearch"
|
||||
@click="saveNavState('statementsearch')"
|
||||
>
|
||||
<i class="el-icon-search"></i>
|
||||
<span slot="title">借阅信息查询</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item
|
||||
index="statementrulemanage"
|
||||
@click="saveNavState('statementrulemanage')"
|
||||
>
|
||||
<i class="el-icon-key"></i>
|
||||
<span slot="title">借阅规则管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item
|
||||
index="bookadminmanage"
|
||||
@click="saveNavState('bookadminmanage')"
|
||||
>
|
||||
<i class="el-icon-user-solid"></i>
|
||||
<span slot="title">图书管理员管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item
|
||||
index="adminmanage"
|
||||
@click="saveNavState('adminmanage')"
|
||||
>
|
||||
<i class="el-icon-s-tools"></i>
|
||||
<span slot="title">系统管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item
|
||||
index="intelligent_analysis"
|
||||
@click="saveNavState('intelligent_analysis')"
|
||||
>
|
||||
<i class="el-icon-data-line"></i>
|
||||
<span slot="title">智能分析</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
</el-aside>
|
||||
<!-- 右侧内容主体 -->
|
||||
<el-main>
|
||||
<!-- 路由占位符 -->
|
||||
<router-view></router-view>
|
||||
<div class="footer">
|
||||
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
//左侧菜单数据
|
||||
menulist: [],
|
||||
iconsObj: {
|
||||
125: "iconfont icon-user",
|
||||
103: "iconfont icon-tijikongjian",
|
||||
101: "iconfont icon-shangpin",
|
||||
102: "iconfont icon-danju",
|
||||
145: "iconfont icon-baobiao",
|
||||
},
|
||||
//是否折叠
|
||||
isCollapse: false,
|
||||
//被激活的链接地址
|
||||
activePath: "",
|
||||
admin: {
|
||||
adminId: Number,
|
||||
status: Number,
|
||||
adminName: "",
|
||||
username: "",
|
||||
password: "",
|
||||
createTime: "",
|
||||
updateTime: "",
|
||||
},
|
||||
};
|
||||
},
|
||||
async created() {
|
||||
// this.getMenuList();
|
||||
this.activePath = window.sessionStorage.getItem("activePath");
|
||||
// console.log(this.activePath)
|
||||
// 先获取sessionStorage中的id
|
||||
const stringId = window.sessionStorage.getItem("adminId");
|
||||
const id = parseInt(stringId);
|
||||
this.admin.adminId = id;
|
||||
const { data: res } = await this.$http.post("admin/getData", this.admin);
|
||||
this.admin = res.data;
|
||||
},
|
||||
methods: {
|
||||
logout() {
|
||||
window.sessionStorage.clear();
|
||||
this.$router.push("/loginadmin");
|
||||
},
|
||||
|
||||
//点击按钮,切换菜单的折叠与展开
|
||||
toggleCollapse() {
|
||||
this.isCollapse = !this.isCollapse;
|
||||
},
|
||||
//保存链接的激活状态
|
||||
saveNavState(activePath) {
|
||||
// console.log("first")
|
||||
window.sessionStorage.setItem("activePath", activePath);
|
||||
this.activePath = activePath;
|
||||
// console.log(this.activePath);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
left: 40%;
|
||||
color:#ccc;
|
||||
a {
|
||||
color:#ccc;
|
||||
}
|
||||
}
|
||||
.home-container {
|
||||
height: 100%;
|
||||
}
|
||||
.el-header {
|
||||
background-color: rgb(34, 34, 34);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-left: 0px;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
border-radius: 10px;
|
||||
> div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
span {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-aside {
|
||||
background-color: #fff;
|
||||
.el-menu {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
.el-main {
|
||||
background-color: #eaedf1;
|
||||
padding: 20px;
|
||||
}
|
||||
.iconfont {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.toggle-button {
|
||||
background-color: #4a5064;
|
||||
font-size: 10px;
|
||||
line-height: 24px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
//设置文字之间的间距
|
||||
letter-spacing: 0.2em;
|
||||
cursor: pointer;
|
||||
}
|
||||
.user {
|
||||
margin-right: 15px;
|
||||
color: #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
.el-menu-item:hover {
|
||||
background-color: rgb(51, 122, 183) !important;
|
||||
}
|
||||
// .el-menu-item{
|
||||
// color:rgb(135, 206, 235) !important;
|
||||
// }
|
||||
</style>
|
209
src/components/Home/HomeManage.vue
Normal file
@ -0,0 +1,209 @@
|
||||
<template>
|
||||
<el-container class="home-container">
|
||||
<!-- 头部区域 -->
|
||||
<el-header>
|
||||
<div>
|
||||
<!-- <img src="../assets/heima.png" alt="" /> -->
|
||||
<span>欢迎登录图书管理系统</span>
|
||||
<span style="color: #ccc; font-size: 16px">图书馆管理人员页面</span>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
<div>
|
||||
<el-avatar
|
||||
src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"
|
||||
:size="35"
|
||||
style="margin-right: 10px"
|
||||
></el-avatar>
|
||||
</div>
|
||||
<div class="user">管理员:{{ this.bookAdmin.bookAdminName }}</div>
|
||||
<el-button type="info" @click="logout">退出</el-button>
|
||||
</div>
|
||||
</el-header>
|
||||
<!-- 页面主体区域 -->
|
||||
<el-container>
|
||||
<!-- 侧边栏 -->
|
||||
<el-aside :width="isCollapse ? '64px' : '200px'">
|
||||
<div class="toggle-button" @click="toggleCollapse">|||</div>
|
||||
<!-- 侧边栏菜单区域 -->
|
||||
<el-menu
|
||||
:default-active="activePath"
|
||||
class="el-menu-vertical-demo"
|
||||
background-color="#fff"
|
||||
text-color="black"
|
||||
active-text-color="#ffd04b"
|
||||
:router="true"
|
||||
:collapse="isCollapse"
|
||||
:collapse-transition="false"
|
||||
>
|
||||
<el-menu-item index="borrowbook" @click="saveNavState('borrowbook')">
|
||||
<i class="el-icon-collection"></i>
|
||||
<span slo="title">借阅图书</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="returnbook" @click="saveNavState('returnbook')">
|
||||
<i class="el-icon-collection"></i>
|
||||
<span slot="title">归还图书</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item
|
||||
index="borrowstatement"
|
||||
@click="saveNavState('borrowstatement')"
|
||||
>
|
||||
<i class="el-icon-folder-checked"></i>
|
||||
<span slot="title">借书报表</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item
|
||||
index="returnstatement"
|
||||
@click="saveNavState('returnstatement')"
|
||||
>
|
||||
<i class="el-icon-folder-checked"></i>
|
||||
<span slot="title">还书报表</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item
|
||||
index="noticemanage"
|
||||
@click="saveNavState('noticemanage')"
|
||||
>
|
||||
<i class="el-icon-s-promotion"></i>
|
||||
<span slot="title">发布公告</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
</el-aside>
|
||||
<!-- 右侧内容主体 -->
|
||||
<el-main>
|
||||
<!-- 路由占位符 -->
|
||||
<router-view></router-view>
|
||||
<div class="footer">
|
||||
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
//左侧菜单数据
|
||||
menulist: [],
|
||||
iconsObj: {
|
||||
125: "iconfont icon-user",
|
||||
103: "iconfont icon-tijikongjian",
|
||||
101: "iconfont icon-shangpin",
|
||||
102: "iconfont icon-danju",
|
||||
145: "iconfont icon-baobiao",
|
||||
},
|
||||
//是否折叠
|
||||
isCollapse: false,
|
||||
//被激活的链接地址
|
||||
activePath: "",
|
||||
bookAdmin:{
|
||||
bookAdminId:Number,
|
||||
status:Number,
|
||||
username:"",
|
||||
password:"",
|
||||
bookAdminName:"",
|
||||
email:"",
|
||||
createTime:"",
|
||||
updateTime:""
|
||||
}
|
||||
};
|
||||
},
|
||||
async created() {
|
||||
// this.getMenuList();
|
||||
this.activePath = window.sessionStorage.getItem("activePath");
|
||||
// console.log(this.activePath)
|
||||
// 先获取sessionStorage中的id
|
||||
const stringId = window.sessionStorage.getItem("bookAdminId");
|
||||
const id = parseInt(stringId);
|
||||
this.bookAdmin.bookAdminId = id;
|
||||
const { data: res } = await this.$http.post("bookadmin/getData", this.bookAdmin);
|
||||
// console.log(res);
|
||||
this.bookAdmin = res.data;
|
||||
},
|
||||
methods: {
|
||||
logout() {
|
||||
window.sessionStorage.clear();
|
||||
this.$router.push("/loginmanage");
|
||||
},
|
||||
|
||||
//点击按钮,切换菜单的折叠与展开
|
||||
toggleCollapse() {
|
||||
this.isCollapse = !this.isCollapse;
|
||||
},
|
||||
//保存链接的激活状态
|
||||
saveNavState(activePath) {
|
||||
// console.log("first")
|
||||
window.sessionStorage.setItem("activePath", activePath);
|
||||
this.activePath = activePath;
|
||||
// console.log(this.activePath);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
left: 40%;
|
||||
color:#ccc;
|
||||
a {
|
||||
color:#ccc;
|
||||
}
|
||||
}
|
||||
.home-container {
|
||||
height: 100%;
|
||||
}
|
||||
.el-header {
|
||||
background-color: rgb(34, 34, 34);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-left: 0px;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
border-radius: 10px;
|
||||
> div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
span {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-aside {
|
||||
background-color: #fff;
|
||||
.el-menu {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
.el-main {
|
||||
background-color: #eaedf1;
|
||||
padding: 20px;
|
||||
}
|
||||
.iconfont {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.toggle-button {
|
||||
background-color: #4a5064;
|
||||
font-size: 10px;
|
||||
line-height: 24px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
//设置文字之间的间距
|
||||
letter-spacing: 0.2em;
|
||||
cursor: pointer;
|
||||
}
|
||||
.user {
|
||||
margin-right: 15px;
|
||||
color: #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
.el-menu-item:hover {
|
||||
background-color: rgb(51, 122, 183) !important;
|
||||
}
|
||||
// .el-menu-item{
|
||||
// color:rgb(135, 206, 235) !important;
|
||||
// }
|
||||
</style>
|
20
src/components/Index/Index.vue
Normal file
@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<div class="index">
|
||||
<swiperVue />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import swiperVue from "../../components/Swiper/swiper.vue"
|
||||
export default {
|
||||
name: "index",
|
||||
components:{
|
||||
swiperVue
|
||||
},
|
||||
created() {
|
||||
// const {data:res} = await this.$http.get('/user/test');
|
||||
// console.log(res);
|
||||
},
|
||||
|
||||
};
|
||||
</script>
|
215
src/components/Login.vue
Normal file
@ -0,0 +1,215 @@
|
||||
<template>
|
||||
<div class="login_container">
|
||||
<div class="login_title">用户登录界面</div>
|
||||
<div class="login_box">
|
||||
<!-- 头像区域 -->
|
||||
<div class="avatar_box">
|
||||
<img src="../assets/images/dinosaur.jpg" alt="" />
|
||||
</div>
|
||||
<!-- 登录表单区域 -->
|
||||
<el-form ref="loginFormRef" :model="loginForm" :rules="loginFormRules" label-width="0px" class="login_form">
|
||||
<!-- 用户名 -->
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model.trim="loginForm.username" prefix-icon="iconfont icon-gerenxinxi"></el-input>
|
||||
</el-form-item>
|
||||
<!-- 密码 -->
|
||||
<el-form-item prop="password">
|
||||
<el-input v-model="loginForm.password" prefix-icon="iconfont icon-tianchongxing-" type="password"
|
||||
@keyup.enter.native="login" :show-password="true"></el-input>
|
||||
</el-form-item>
|
||||
<!-- 按钮区域 -->
|
||||
<el-form-item class="btns">
|
||||
<el-button type="primary" @click="login" :loading="loginLoading">登录</el-button>
|
||||
<el-button type="info" @click="resetLoginForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<!-- 粒子插件特效-->
|
||||
<vue-particles class="login-bg" color="#39AFFD" :particleOpacity="0.7" :particlesNumber="100" shapeType="circle"
|
||||
:particleSize="4" linesColor="#8DD1FE" :linesWidth="1" :lineLinked="true" :lineOpacity="0.4" :linesDistance="150"
|
||||
:moveSpeed="3" :hoverEffect="true" hoverMode="grab" :clickEffect="true" clickMode="push">
|
||||
</vue-particles>
|
||||
<div class="footer">
|
||||
<span style="font-weight: bold;color:white;margin-bottom: 10px">
|
||||
登录页面切换
|
||||
<!-- <i class="iconfont icon-haoyou " @click="goUser"></i> -->
|
||||
</span>
|
||||
<span>
|
||||
<i class="iconfont icon-guanliyuan" @click="goManage"></i>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
//登录表单
|
||||
loginForm: {
|
||||
username: "yangzhen",
|
||||
password: "123456",
|
||||
},
|
||||
|
||||
//登录表单规则的验证对象
|
||||
loginFormRules: {
|
||||
username: [
|
||||
{ required: true, message: "用户名不能为空", trigger: "blur" },
|
||||
{
|
||||
min: 3,
|
||||
max: 20,
|
||||
message: "长度在 3 到 20 个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: "密码不能为空", trigger: "blur" },
|
||||
{
|
||||
min: 6,
|
||||
max: 15,
|
||||
message: "长度在 6 到 15 个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
},
|
||||
loginLoading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
resetLoginForm() {
|
||||
this.$refs.loginFormRef.resetFields();
|
||||
},
|
||||
login() {
|
||||
this.$refs.loginFormRef.validate(async (valid) => {
|
||||
// console.log(valid);
|
||||
//如果表单验证无效,直接返回
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
this.loginLoading = true;
|
||||
// 进行md5加密
|
||||
const salt = "xiaobaitiao";
|
||||
const username = this.loginForm.username;
|
||||
const password = this.loginForm.password;
|
||||
//向数据库发送axios请求,如果登录成功,就跳转
|
||||
const { data: res } = await this.$http.post(
|
||||
"user/login",
|
||||
{
|
||||
username,
|
||||
password
|
||||
}
|
||||
);
|
||||
if (res.status !== 200) {
|
||||
this.loginLoading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
// console.log(res);
|
||||
this.$message.success("登录成功");
|
||||
this.loginLoading = false;
|
||||
window.sessionStorage.setItem("token", res.map.token);
|
||||
window.sessionStorage.setItem("userId", res.map.id);
|
||||
this.$router.push("/home"); //跳转到home页面下
|
||||
});
|
||||
},
|
||||
goUser() {
|
||||
this.$router.push("/login");
|
||||
},
|
||||
goManage() {
|
||||
this.$router.push("/loginmanage");
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.footer2 {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 35%;
|
||||
color: #ccc;
|
||||
|
||||
a {
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
.login_container {
|
||||
// background-color: #2b4b6b;
|
||||
background: url(https://xxx.xiaobaitiao.icu/img/icu/202312211236280.jpg) no-repeat 0px 0px;
|
||||
background-size: cover;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.login_box {
|
||||
height: 300px;
|
||||
width: 450px;
|
||||
background-color: #fff;
|
||||
border-radius: 3px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
.avatar_box {
|
||||
width: 130px;
|
||||
height: 130px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 50%;
|
||||
padding: 10px;
|
||||
box-shadow: 0 0 10px #ddd;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: #fff;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login_form {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
padding: 0 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.btns {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.login_title {
|
||||
position: relative;
|
||||
top: 5%;
|
||||
font-size: 36px;
|
||||
color: white;
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
//控制字体间距
|
||||
letter-spacing: 10px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
flex-direction: column;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 100px;
|
||||
height: 120px;
|
||||
|
||||
// background-color: pink;
|
||||
span {
|
||||
// width: 100%;
|
||||
// background-color: red;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
98
src/components/Swiper/swiper.vue
Normal file
@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<!--基础存放容器-->
|
||||
<div class="swiper-container">
|
||||
<!-- 需要进行轮播的部分 -->
|
||||
<div class="swiper-wrapper">
|
||||
<!-- 每个节点 -->
|
||||
<div class="swiper-slide">
|
||||
<img
|
||||
data-src="https://pic.yupi.icu/5563/202311091857319.jpg"
|
||||
src="https://pic.yupi.icu/5563/202311091902481.gif"
|
||||
alt="书籍1"
|
||||
class="swiper-lazy"
|
||||
/>
|
||||
</div>
|
||||
<div class="swiper-slide">
|
||||
<img
|
||||
data-src="https://pic.yupi.icu/5563/202311091857306.jpg"
|
||||
src="https://pic.yupi.icu/5563/202311091902481.gif"
|
||||
alt="书籍2"
|
||||
class="swiper-lazy"
|
||||
/>
|
||||
<div class="swiper-lazy-preloader"></div>
|
||||
</div>
|
||||
<div class="swiper-slide">
|
||||
<img
|
||||
data-src="https://pic.yupi.icu/5563/202311091857330.jpg"
|
||||
src="https://pic.yupi.icu/5563/202311091902481.gif"
|
||||
alt="书籍3"
|
||||
class="swiper-lazy"
|
||||
/>
|
||||
<div class="swiper-lazy-preloader"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--如果需要使用分页器-->
|
||||
<div class="swiper-pagination swiper-pagination-white"></div>
|
||||
|
||||
<!-- 如果需要使用前进后退按钮 -->
|
||||
<div class="swiper-button-prev swiper-button-white"></div>
|
||||
<div class="swiper-button-next swiper-button-white"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import swiper from "swiper";
|
||||
|
||||
export default {
|
||||
name: "",
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
mounted() {
|
||||
this.initSwiper();
|
||||
},
|
||||
methods: {
|
||||
initSwiper() {
|
||||
new Swiper(".swiper-container", {
|
||||
//设置轮播的循环方式
|
||||
loop: true,
|
||||
|
||||
//设置自动播放间隔时间
|
||||
autoplay: 2000,
|
||||
|
||||
// 轮播效果,默认为平滑轮播
|
||||
effect: "slide",
|
||||
|
||||
//分页器
|
||||
pagination: ".swiper-pagination",
|
||||
|
||||
//前进后退按钮
|
||||
prevButton: ".swiper-button-prev",
|
||||
nextButton: ".swiper-button-next",
|
||||
|
||||
// 用户中断轮播后续播
|
||||
autoplayDisableOnInteraction: false,
|
||||
//懒加载
|
||||
lazyLoading: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import "../../../node_modules/swiper/dist/css/swiper.css";
|
||||
|
||||
.swiper-container {
|
||||
width: 1000px;
|
||||
height: 650px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.swiper-slide img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
</style>
|
218
src/components/User/Borrow.vue
Normal file
@ -0,0 +1,218 @@
|
||||
<template>
|
||||
<div class="search_container">
|
||||
<!-- 面包屑导航区域 -->
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item>首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>借阅信息</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<el-card shadow="always">
|
||||
<!-- 搜索内容和导出区域 -->
|
||||
<el-row>
|
||||
<el-col :span="6"
|
||||
>条件搜索:<el-select
|
||||
v-model="queryInfo.condition"
|
||||
filterable
|
||||
placeholder="请选择"
|
||||
style="margin-left: 15px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-input
|
||||
placeholder="请输入内容"
|
||||
v-model="queryInfo.query"
|
||||
class="input-with-select"
|
||||
@keyup.enter.native="searchBookBorrowByPage"
|
||||
>
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-search"
|
||||
@click="searchBookBorrowByPage"
|
||||
></el-button> </el-input
|
||||
></el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<download-excel
|
||||
class="export-excel-wrapper"
|
||||
:data="tableData"
|
||||
:fields="json_fields"
|
||||
:header="title"
|
||||
name="图书借阅表格.xls"
|
||||
>
|
||||
<!-- 上面可以自定义自己的样式,还可以引用其他组件button -->
|
||||
<el-button type="primary" class="el-icon-printer" size="mini"
|
||||
>导出Excel</el-button
|
||||
>
|
||||
</download-excel>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<el-button
|
||||
type="primary"
|
||||
class="el-icon-printer"
|
||||
size="mini"
|
||||
@click="downLoad"
|
||||
>导出PDF</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
|
||||
<el-button type="success" class="el-icon-full-screen" size="mini" @click="fullScreen"
|
||||
>全屏</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 表格区域 -->
|
||||
<el-table
|
||||
:data="tableData"
|
||||
border
|
||||
style="width: 100%"
|
||||
stripe
|
||||
id="pdfDom"
|
||||
:default-sort="{ prop: 'cardNumber', order: 'ascending' }"
|
||||
v-loading="loading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)"
|
||||
>
|
||||
<el-table-column prop="cardNumber" label="借阅编号" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="bookNumber" label="图书编号" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="borrowDate" label="借阅日期" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="closeDate" label="截止日期" sortable>
|
||||
</el-table-column>
|
||||
<el-table-column prop="returnDate" label="归还日期" sortable>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页查询区域 -->
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="this.queryInfo.pageNum"
|
||||
:page-sizes="[1, 2, 3, 4, 5]"
|
||||
:page-size="this.queryInfo.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="this.total"
|
||||
>
|
||||
</el-pagination>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{
|
||||
value: "book_number",
|
||||
label: "图书编号",
|
||||
},
|
||||
{
|
||||
value: "borrow_date",
|
||||
label: "借阅日期",
|
||||
},
|
||||
{
|
||||
value: "close_date",
|
||||
label: "截止日期",
|
||||
},
|
||||
{
|
||||
value: "return_date",
|
||||
label: "归还日期",
|
||||
},
|
||||
],
|
||||
tableData: [
|
||||
{
|
||||
cardNumber: Number,
|
||||
bookNumber: Number,
|
||||
borrowId: Number,
|
||||
borrowDate: "",
|
||||
closeDate: "",
|
||||
returnDate: "",
|
||||
createTime: "",
|
||||
updateTime: "",
|
||||
},
|
||||
],
|
||||
queryInfo: {
|
||||
pageNum: 1,
|
||||
pageSize: 5,
|
||||
condition: "",
|
||||
query: "",
|
||||
cardNumber: window.sessionStorage.getItem("cardNumber"),
|
||||
},
|
||||
total: 0,
|
||||
title: "图书借阅表格",
|
||||
json_fields: {
|
||||
借阅编号: "cardNumber",
|
||||
图书编号: "bookNumber",
|
||||
借阅日期: "borrowDate",
|
||||
截止日期: "closeDate",
|
||||
归还日期: "returnDate",
|
||||
},
|
||||
loading: true,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(val) {
|
||||
this.queryInfo.pageSize = val;
|
||||
|
||||
this.searchBookBorrowByPage();
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.queryInfo.pageNum = val;
|
||||
|
||||
this.searchBookBorrowByPage();
|
||||
},
|
||||
async searchBookBorrowByPage() {
|
||||
this.loading = true;
|
||||
const { data: res } = await this.$http.post(
|
||||
"user/get_bookborrow",
|
||||
this.queryInfo
|
||||
);
|
||||
|
||||
this.tableData = [];
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
this.total = 0;
|
||||
this.loading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1000,
|
||||
});
|
||||
this.tableData = res.data.records;
|
||||
this.total = parseInt(res.data.total);
|
||||
this.loading = false;
|
||||
},
|
||||
downLoad() {
|
||||
this.getPdf(this.title); //参数是下载的pdf文件名
|
||||
},
|
||||
fullScreen(){
|
||||
// Dom对象的一个属性: 可以用来判断当前是否为全屏模式(trueORfalse)
|
||||
let full = document.fullscreenElement;
|
||||
// 切换为全屏模式
|
||||
if(!full){
|
||||
// 文档根节点的方法requestFullscreen实现全屏模式
|
||||
document.documentElement.requestFullscreen();
|
||||
}else{
|
||||
// 退出全屏模式
|
||||
document.exitFullscreen();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.searchBookBorrowByPage();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
229
src/components/User/Chat.vue
Normal file
@ -0,0 +1,229 @@
|
||||
<template>
|
||||
<div class="chat_container" style="height: 100%">
|
||||
<div
|
||||
style="
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: red;
|
||||
|
||||
"
|
||||
>
|
||||
<el-row style="height: 100%">
|
||||
<el-col :span="5" style="background-color: grey; height: inherit">
|
||||
<div>
|
||||
<!-- <div style="position: relative; top: 10px; left: 20px; width: 90%">-->
|
||||
<!-- <el-input class="search_input" placeholder="搜索"></el-input>-->
|
||||
<!-- </div>-->
|
||||
<el-row style="height: 60px;background-color:rgb(240, 197, 168);border: 1px solid #eee"
|
||||
v-for="item in friendList" key="item.username">
|
||||
<el-col :span="6">
|
||||
<el-avatar src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" :size="35"
|
||||
style="margin: 10px 30px">
|
||||
|
||||
</el-avatar>
|
||||
</el-col>
|
||||
<el-col :span="18">
|
||||
<el-row>
|
||||
<el-col :span="14">
|
||||
<div style="margin:10px 0px 5px 0px">{{ item.username }}</div>
|
||||
<div class="ellipsis">{{ item.text }}</div>
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<div style="font-size: 10px;margin:10px 0px">
|
||||
{{ item.date }}
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="19" style="background-color: blue; height: inherit">
|
||||
<div style="background-color: yellowgreen; height: 600px;">
|
||||
<el-row style="height: 60px;background-color:red;display: flex;align-items: center;">
|
||||
<el-row style="margin-left: 20px;color:rgb(88, 88, 88);font-size:24px">
|
||||
王二离
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-row
|
||||
v-for="message in messages"
|
||||
:key="message.id"
|
||||
:class="{'left-message': message.role === 'user', 'right-message': message.role === 'me'}"
|
||||
>
|
||||
<!-- 用户或者对方的单行消息包括头像和消息-->
|
||||
<el-row style="float:left;">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<el-avatar v-if="message.role === 'user'"
|
||||
src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"
|
||||
:size="35"></el-avatar>
|
||||
<p :class="{'message-backgroudcolor':true,'left-message-content':message.role==='user','right-message-content':message.role ==='me'}" v-if="message.role === 'user'"> {{ message.content }}</p>
|
||||
</div>
|
||||
</el-row>
|
||||
|
||||
<el-row style="float: right;margin-top:10px">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<span :class="{'message-backgroudcolor':true,'left-message-content':message.role==='user','right-message-content':message.role ==='me'}" v-if="message.role === 'me'"> {{ message.content }}</span>
|
||||
<el-avatar v-if="message.role === 'me'"
|
||||
src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"
|
||||
:size="35"></el-avatar>
|
||||
</div>
|
||||
|
||||
|
||||
</el-row>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</div>
|
||||
<!-- 聊天框区域-->
|
||||
<el-row style="background-color:purple; height: 150px;box-sizing: border-box">
|
||||
<el-row style="height: 30px;background-color:red;display: flex; align-items: center;">
|
||||
<div style="margin-left: 20px">
|
||||
<span>表情</span>
|
||||
<span style="margin-left: 20px">文件</span>
|
||||
</div>
|
||||
|
||||
</el-row>
|
||||
<el-row style="height: 200px">
|
||||
<el-input
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 5, maxRows: 5}"
|
||||
>
|
||||
</el-input>
|
||||
</el-row>
|
||||
</el-row>
|
||||
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
//引入socket对象
|
||||
import {socket} from "@/components/Utils/websocket";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
websocketCount: -1,
|
||||
//查询条件
|
||||
queryCondition: {
|
||||
"toId": 2,
|
||||
"text": "你好",
|
||||
"chatType": 1,
|
||||
"isAdmin": false
|
||||
},
|
||||
messages: [
|
||||
{
|
||||
id: 1, content: "你好23222222222222222222222222222哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈222222222222222222222222222222222222222222222222222222222222222222", role: "user",
|
||||
},
|
||||
{
|
||||
id: 2, content: "你好红红火火恍恍惚惚哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈红红火火恍恍惚惚哈哈哈哈哈哈哈哈哈哈哈", role: "me",
|
||||
},
|
||||
{
|
||||
id: 3, content: "你好23222222222222222222222222222哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈222222222222222222222222222222222222222222222222222222222222222222", role: "user",
|
||||
},
|
||||
{
|
||||
id: 4, content: "你好", role: "me",
|
||||
},
|
||||
],
|
||||
friendList: [
|
||||
{
|
||||
username: "王二离",
|
||||
text: "最后一条聊天记录:你好",
|
||||
date: "2024年3月1日"
|
||||
},
|
||||
{
|
||||
username: "礼喆",
|
||||
text: "最后一条聊天记录:你好",
|
||||
date: "2024年12月24日"
|
||||
},
|
||||
|
||||
],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
//初始化websocket对象
|
||||
//window.location.host获取ip和端口,
|
||||
//process.env.VUE_APP_WEBSOCKET_BASE_API获取请求前缀
|
||||
// socket.initWebSocket(`ws://localhost:8889/api/websocket/` + 1923);
|
||||
//绑定接收消息方法
|
||||
// socket.websocket.onmessage = this.websocketOnMessage;
|
||||
},
|
||||
methods: {
|
||||
backgroundColor() {
|
||||
return backgroundColor
|
||||
},
|
||||
init() {
|
||||
this.queryCondition.type = "message";
|
||||
socket.sendMsg(JSON.stringify(this.queryCondition));
|
||||
},
|
||||
websocketOnMessage(event) {
|
||||
//初始化界面时,主动向后台发送一次消息,获取数据
|
||||
this.websocketCount += 1;
|
||||
if (this.websocketCount === 0) {
|
||||
this.init();
|
||||
}
|
||||
let info = event.data;
|
||||
this.messages.push(info);
|
||||
switch (info.type) {
|
||||
case "PONG":
|
||||
socket.websocketState = true;
|
||||
break;
|
||||
case "message":
|
||||
this.loading = true;
|
||||
this.$nextTick(() => {
|
||||
this.consumeMessage(info);
|
||||
});
|
||||
break;
|
||||
case "error":
|
||||
console.log("错误");
|
||||
this.loading = false;
|
||||
break;
|
||||
}
|
||||
},
|
||||
consumeMessage(info) {
|
||||
//拿到最新数据重新渲染界面
|
||||
console.log(info);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.chat_container {
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
font-size: 12px;
|
||||
color: rgb(127, 76, 69);
|
||||
white-space: nowrap; /* 不换行 */
|
||||
overflow: hidden; /* 超出部分隐藏 */
|
||||
text-overflow: ellipsis; /* 显示省略号 */
|
||||
width: 100px; /* 设置元素宽度 */
|
||||
}
|
||||
|
||||
.left-message {
|
||||
text-align: left;
|
||||
margin-left: 10px;
|
||||
margin-right:10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.right-message {
|
||||
text-align: right;
|
||||
margin-right: 10px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.message-backgroudcolor {
|
||||
background-color: #e7f7ff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.left-message-content {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.right-message-content {
|
||||
margin-right:10px;
|
||||
}
|
||||
</style>
|
143
src/components/User/Comment.vue
Normal file
@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<div class="comment_container">
|
||||
<div class="backgroundImg">
|
||||
<img
|
||||
src="https://xxx.xiaobaitiao.icu/img/icu/202312211243628.jpg"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<div class="barrages-drop">
|
||||
<vue-baberrage
|
||||
:isShow="barrageIsShow"
|
||||
:barrageList="barrageList"
|
||||
:maxWordCount="maxWordCount"
|
||||
:throttleGap="throttleGap"
|
||||
:loop="barrageLoop"
|
||||
:boxHeight="boxHeight"
|
||||
:boxWidth="boxWidth"
|
||||
:messageHeight="messageHeight"
|
||||
:lanesCount="lanesCount"
|
||||
style="width: 1330px; height: 750px"
|
||||
>
|
||||
</vue-baberrage>
|
||||
<div class="addMain">
|
||||
<el-input
|
||||
placeholder="请输入内容"
|
||||
v-model.trim="input"
|
||||
class="input-with-select"
|
||||
@keyup.enter.native="addContent"
|
||||
>
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-edit"
|
||||
@click="addContent"
|
||||
></el-button>
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import { MESSAGE_TYPE } from "vue-baberrage";
|
||||
import { nanoid, random } from "nanoid";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
barrageIsShow: true, //是否展示弹幕
|
||||
messageHeight: 3, //消息高度(测试不生效)
|
||||
barrageLoop: false, //是否循环播放
|
||||
maxWordCount: 2, //弹幕字数(测试不生效)
|
||||
lanesCount: 1, //固定弹幕(测试不生效)
|
||||
boxWidth: 1600, //弹幕宽度
|
||||
boxHeight: 200, //弹幕高度(测试不生效)
|
||||
throttleGap: 3000, //消息间隔
|
||||
input: "",
|
||||
//弹幕列表,格式为数组
|
||||
barrageList: [],
|
||||
barrage: {
|
||||
id: "",
|
||||
avatar:
|
||||
"https://img0.baidu.com/it/u=825023390,3429989944&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
|
||||
msg: "",
|
||||
time: "",
|
||||
type: MESSAGE_TYPE.NORMAL,
|
||||
barrageStyle: "",
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
addContent:_.throttle(async function(){
|
||||
// 先判断文本内容是否为空或者是无意义的数字,如果是提示用户信息
|
||||
if(this.input.trim()===''||/^\d+$/.test(this.input)||/^[a-zA-Z]+$/.test(this.input)){
|
||||
this.$message.info({
|
||||
message: "请不要输入无意义的内容",
|
||||
duration:1000
|
||||
})
|
||||
return;
|
||||
}
|
||||
// 文本框中内容赋值给barrage
|
||||
this.barrage.msg = this.input;
|
||||
//向数据库发送请求 addComment
|
||||
const {data:res} = await this.$http.post('user/add_comment',this.barrage);
|
||||
if(res.status !== 200){
|
||||
return this.$message.error(res.msg)
|
||||
}
|
||||
//调用获取新的留言列表
|
||||
this.getCommentList();
|
||||
//重置内容框
|
||||
this.input = "";
|
||||
this.$message.success(res.msg);
|
||||
},5000,{ trailing: false }),
|
||||
async getCommentList() {
|
||||
// 发送axios请求
|
||||
const { data: res } = await this.$http.get("user/get_commentlist");
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success(res.msg);
|
||||
this.barrageList = res.data
|
||||
//添加空对象,数组更新,组件更新
|
||||
this.barrageList.push({})
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
mounted(){
|
||||
this.getCommentList();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
.comment_container {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.backgroundImg {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
.barrages-drop {
|
||||
position: relative;
|
||||
}
|
||||
.addMain {
|
||||
position: absolute;
|
||||
width: 300px;
|
||||
height: 100%;
|
||||
background-color: pink;
|
||||
top: 450px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
</style>
|
231
src/components/User/Information.vue
Normal file
@ -0,0 +1,231 @@
|
||||
<template>
|
||||
<div class="information_container">
|
||||
<div class="backgroundImg">
|
||||
<img
|
||||
src="https://xxx.xiaobaitiao.icu/img/icu/202312211243635.jpg"
|
||||
alt="背景图片"
|
||||
/>
|
||||
</div>
|
||||
<div class="information_header">
|
||||
<p>个人信息</p>
|
||||
<p>
|
||||
<i class="el-icon-s-flag"></i> By reading we enrich the mind, by
|
||||
conversation we polish it.
|
||||
</p>
|
||||
</div>
|
||||
<div class="information_banner"
|
||||
v-loading="loading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)">
|
||||
<div class="information_banner_left" >
|
||||
<div class="banner_left_main" v-if="show">
|
||||
<div class="number">
|
||||
<i class="el-icon-collection-tag"></i> 借阅证编号:
|
||||
{{ this.user.cardNumber }}
|
||||
</div>
|
||||
<div class="name">
|
||||
<i class="iconfont icon-gerenxinxi"></i> 借阅证姓名:
|
||||
{{ this.user.cardName }}
|
||||
</div>
|
||||
<div class="rule">
|
||||
<i class="iconfont icon-guizeshezhi"></i> 规则编号:
|
||||
{{ this.user.ruleNumber }}
|
||||
</div>
|
||||
<div class="status">
|
||||
<i class="el-icon-refresh"></i> 状态:
|
||||
{{ this.user.status === 1 ? "可用" : "禁用" }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="information_banner_right">
|
||||
<el-button type="primary" class="changePWD" @click="showEditDialog" v-if="show"
|
||||
>修改密码</el-button
|
||||
>
|
||||
</div>
|
||||
<el-dialog
|
||||
title="修改密码"
|
||||
:visible.sync="editDialogVisible"
|
||||
width="50%"
|
||||
@close="editDialogClosed"
|
||||
>
|
||||
<el-form
|
||||
:model="editForm"
|
||||
ref="editFormRef"
|
||||
:rules="editFormRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<el-form-item label="新密码" prop="password">
|
||||
<el-input v-model="editForm.password" type="password" placeholder="请输入新密码"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码" prop="confirmPassword">
|
||||
<el-input v-model="editForm.confirmPassword" type="password" placeholder="请再次输入新密码"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="editDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="changePassword"
|
||||
>确 定</el-button
|
||||
>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
var validatePass2 = (rule, value, callback) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请再次输入密码'));
|
||||
} else if (value !== this.editForm.password) {
|
||||
callback(new Error('两次输入密码不一致!'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
user: {
|
||||
ruleNumber: Number,
|
||||
cardNumber: Number,
|
||||
status: Number,
|
||||
userId: Number,
|
||||
cardName: "",
|
||||
username: "",
|
||||
password: "",
|
||||
createTime: "",
|
||||
updateTime: "",
|
||||
},
|
||||
editForm: {
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
},
|
||||
editFormRules:{
|
||||
password:[
|
||||
{required:true,message:"请输入新密码",trigger:"blur"},
|
||||
{min:6,max:15,message:"新密码长度在6-15个字符",trigger:"blur"}
|
||||
],
|
||||
confirmPassword:[
|
||||
{validator:validatePass2,trigger:"blur"}
|
||||
]
|
||||
|
||||
},
|
||||
editDialogVisible: false,
|
||||
show:false,
|
||||
loading:true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
//让修改公告的对话框可见,并从数据库中回显数据
|
||||
showEditDialog() {
|
||||
// 让修改公告的对话框可见
|
||||
this.editDialogVisible = true;
|
||||
},
|
||||
//监听修改对话框的关闭,一旦对话框关闭,就重置表单,回显数据
|
||||
editDialogClosed() {
|
||||
this.$refs.editFormRef.resetFields();
|
||||
},
|
||||
async getUserInformaton() {
|
||||
// 先从sessionStorage中获取用户id
|
||||
const userId = window.sessionStorage.getItem("userId");
|
||||
// 发送axios请求,携带用户id,获取个人信息
|
||||
this.loading = true;
|
||||
const { data: res } = await this.$http.get(
|
||||
"user/get_information/" + userId
|
||||
);
|
||||
if (res.status !== 200) {
|
||||
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1000,
|
||||
});
|
||||
this.user = res.data;
|
||||
this.show = true;
|
||||
this.loading = false;
|
||||
|
||||
},
|
||||
async changePassword(){
|
||||
|
||||
const {data:res} = await this.$http.post('user/update_password',{
|
||||
password:this.editForm.password,
|
||||
userId:window.sessionStorage.getItem('userId')
|
||||
})
|
||||
if(res.status !== 200){
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success(res.msg)
|
||||
this.editDialogVisible = false;
|
||||
this.$refs.editFormRef.resetFields();
|
||||
window.sessionStorage.clear();
|
||||
this.$router.push("/login");
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getUserInformaton();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.information_container {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
.backgroundImg {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
.information_header {
|
||||
height: 200px;
|
||||
// background-color: pink;
|
||||
text-align: center;
|
||||
p:nth-child(1) {
|
||||
line-height: 140px;
|
||||
color: black;
|
||||
font-size: 36px;
|
||||
}
|
||||
p:nth-child(2) {
|
||||
color: black;
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
.information_banner {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 400px;
|
||||
// background-color: pink;
|
||||
.information_banner_left {
|
||||
flex: 0.5;
|
||||
// background-color: brown;
|
||||
text-align: center;
|
||||
}
|
||||
.information_banner_right {
|
||||
flex: 0.5;
|
||||
// background-color: skyblue;
|
||||
text-align: left;
|
||||
line-height: 400px;
|
||||
}
|
||||
}
|
||||
.banner_left_main {
|
||||
margin-top: 120px;
|
||||
color: black;
|
||||
font-size: 20px;
|
||||
div {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
.changePWD {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
}
|
||||
</style>
|
170
src/components/User/Intelligent.vue
Normal file
@ -0,0 +1,170 @@
|
||||
<template>
|
||||
<div class="chat-container">
|
||||
<h2 style="text-align: center;color:deepskyblue;">llama3 智能推荐 </h2>
|
||||
<el-card class="chat" style="margin-top:10px;height: 80vh;border-radius: 15px;border-color: #ccc;">
|
||||
<el-card class="main_chat">
|
||||
<div v-for="item in messages" :key="message.id" class="message">
|
||||
<div v-if="item.inputMessage!=null&&item.inputMessage!==''" class="user-message">
|
||||
{{ item.inputMessage }}
|
||||
</div>
|
||||
<div v-if="item.aiResult!=null&&item.aiResult!==''" class="bot-message">{{ item.aiResult }}</div>
|
||||
</div>
|
||||
|
||||
</el-card>
|
||||
<el-input
|
||||
placeholder="请输入内容,例如:我喜欢动物类的书籍,请给我推荐"
|
||||
v-model.trim="inputMessage"
|
||||
:disabled="loading"
|
||||
@keyup.enter.native="sendMessage"
|
||||
>
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-s-promotion"
|
||||
v-loading="loading"
|
||||
@click="sendMessage"
|
||||
:disabled="loading"
|
||||
></el-button>
|
||||
</el-input
|
||||
>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
messages: [],
|
||||
inputMessage: "",
|
||||
message: {
|
||||
inputMessage: "",
|
||||
aiResult: "",
|
||||
userId: null
|
||||
},
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 发送消息,接受AI结果
|
||||
* @returns {Promise<ElMessageComponent>}
|
||||
*/
|
||||
async sendMessage() {
|
||||
// 将用户输入的消息添加到消息列表中
|
||||
if (this.inputMessage.trim() === "") {
|
||||
return this.$message.info({
|
||||
message: "文本不能为空",
|
||||
duration: 1500
|
||||
})
|
||||
}
|
||||
// 先判断文本内容是否为空或者是无意义的数字,如果是提示用户信息
|
||||
if (/[\da-zA-Z]/.test(this.inputMessage)) {
|
||||
this.$message.info({
|
||||
message: "请不要输入无意义的内容",
|
||||
duration: 1000
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (this.inputMessage.trim() !== "") {
|
||||
var userId = window.sessionStorage.getItem("userId");
|
||||
this.messages.push({
|
||||
id: Date.now(),
|
||||
inputMessage: this.inputMessage,
|
||||
userId: parseInt(userId)
|
||||
});
|
||||
// 这里可以是调用 GPT API 的逻辑
|
||||
this.message.inputMessage = this.inputMessage.trim();
|
||||
this.message.userId = userId;
|
||||
// 清空输入框
|
||||
this.inputMessage = "";
|
||||
this.loading = true;
|
||||
this.$message.info({
|
||||
message:"文本输入越长,接口调用时间越长,请耐心等待10秒左右",
|
||||
duration:2500
|
||||
})
|
||||
const {data: res} = await this.$http.post("user/ai_intelligent", this.message)
|
||||
|
||||
if (res.status !== 200) {
|
||||
this.loading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1500
|
||||
})
|
||||
this.messages.push({
|
||||
id: Date.now(),
|
||||
aiResult: res.data,
|
||||
userId: userId
|
||||
});
|
||||
this.loading = false;
|
||||
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 获取最近五条该用户和AI交流的信息
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async getHistoryRecords() {
|
||||
var userId = window.sessionStorage.getItem("userId");
|
||||
const {data: res} = await this.$http.get("user/ai_list_information/" + userId)
|
||||
if (res.status !== 200) {
|
||||
return this.$message.error(res.msg)
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1500
|
||||
})
|
||||
res.data.forEach((item) => {
|
||||
this.messages.push(item);
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getHistoryRecords();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
//.chat-container {
|
||||
// display: flex;
|
||||
// flex-direction: column;
|
||||
// height: 100vh;
|
||||
//}
|
||||
.main_chat {
|
||||
margin-bottom: 10px;
|
||||
height: 70vh;
|
||||
background-size: cover;
|
||||
background: url(https://xxx.xiaobaitiao.icu/img/icu/202312211243632.jpg) no-repeat 0px 0px;
|
||||
border-radius: 10px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.message {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.user-message {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #e7f7ff;
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
align-self: flex-end;
|
||||
text-align: right;
|
||||
margin-top: 10px;
|
||||
|
||||
}
|
||||
|
||||
.bot-message {
|
||||
background-color: #f4f6f8;
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
text-align: left;
|
||||
align-self: flex-start;
|
||||
margin-top: 10px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
173
src/components/User/Notice.vue
Normal file
@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<div class="notice_container">
|
||||
<div class="header">
|
||||
<div class="scroll-text" ref="scrollText">
|
||||
<i class="el-icon-s-opportunity"></i> {{ text }}
|
||||
<i class="el-icon-s-opportunity"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="banner">
|
||||
<div class="banner_header"><p>近期公告</p></div>
|
||||
<div class="banner_main"
|
||||
v-loading="loading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)">
|
||||
<div class="banner_main_item" v-for="item in noticeList" :key="item.noticeId">
|
||||
<div class="banner_main_item_header"> <p> {{ item.noticeTitle }} {{ item.createTime }}</p></div>
|
||||
|
||||
<div class="banner_main_item_main">
|
||||
<p>{{ item.noticeContent }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
text: "图书馆公告栏,记得查收公告呀!小项目请勿恶意攻击,谢谢",
|
||||
noticeList:[
|
||||
{
|
||||
noticeId:0,
|
||||
noticeAdminId:Number,
|
||||
noticeTitle:"",
|
||||
noticeContent:"",
|
||||
createTime:"",
|
||||
updateTime:""
|
||||
}
|
||||
],
|
||||
loading:true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async getRuleList(){
|
||||
this.loading = true;
|
||||
const {data:res} = await this.$http.get('user/get_noticelist')
|
||||
if(res.status!== 200){
|
||||
this.loading = false;
|
||||
return this.$message.error(res.msg)
|
||||
}
|
||||
this.$message.success({
|
||||
message:res.msg,
|
||||
duration:1000
|
||||
})
|
||||
this.noticeList = res.data;
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const containerWidth = this.$refs.scrollText.offsetWidth;
|
||||
const textWidth = this.$refs.scrollText.scrollWidth;
|
||||
|
||||
// If the text is longer than the container, start the animation
|
||||
if (textWidth > containerWidth) {
|
||||
this.$refs.scrollText.style.animation = "scroll 10s linear infinite";
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.getRuleList();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.notice_container {
|
||||
overflow: hidden;
|
||||
}
|
||||
.header {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
background-color: rgb(70, 130, 180);
|
||||
border-radius: 15px;
|
||||
// box-shadow: 0px 0px 5px 5px rgb(66, 142, 5);
|
||||
color: white;
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
font-size: 24px;
|
||||
}
|
||||
.scroll-text {
|
||||
white-space: nowrap;
|
||||
animation: scroll 10s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes scroll {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
to {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
}
|
||||
.banner {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// background-color: pink;
|
||||
margin-top:30px;
|
||||
}
|
||||
.banner_header {
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
// background-color: brown;
|
||||
|
||||
p {
|
||||
color:black;
|
||||
font-size: 30px;
|
||||
text-align: center;
|
||||
line-height: 80px;
|
||||
}
|
||||
}
|
||||
.banner_main{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color:skyblue;
|
||||
|
||||
}
|
||||
|
||||
.banner_main_item:nth-child(n+2) {
|
||||
margin-top: 30px;
|
||||
}
|
||||
.banner_main_item:nth-child(n+2){
|
||||
background-color: #D1EEEE;
|
||||
}
|
||||
.banner_main_item:nth-child(1){
|
||||
background-color: pink;
|
||||
}
|
||||
|
||||
.banner_main_item {
|
||||
width: 80%;
|
||||
height: 120px;
|
||||
// background-color: aqua;
|
||||
.banner_main_item_header {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
// background-color: pink;
|
||||
border:1px solid skyblue;
|
||||
box-sizing: border-box;
|
||||
p {
|
||||
color:rgb(175, 129, 143);
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
.banner_main_item_main{
|
||||
width: 100%;
|
||||
height: 70px;
|
||||
background-color: white;
|
||||
border:1px solid skyblue;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
p {
|
||||
line-height: 70px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
114
src/components/User/Rule.vue
Normal file
@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div class="rule_container">
|
||||
<div class="header">
|
||||
<p>读者规则信息查看</p>
|
||||
</div>
|
||||
<div class="banner">
|
||||
<el-tooltip
|
||||
v-for="item in ruleList"
|
||||
v-loading="loading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)"
|
||||
:key="item.ruleId"
|
||||
effect="dark"
|
||||
placement="right"
|
||||
>
|
||||
<div slot="content" class="content_tip">可借阅数量: {{ item.bookLimitNumber }}<br/>可借阅天数: {{ item.bookDays }}
|
||||
<br/>可借阅图书馆: {{ item.bookLimitLibrary }}<br/>过期扣费/天: {{ item.bookOverdueFee }}</div>
|
||||
<el-button style="font-size:16px">借阅证规则编号: {{ item.bookRuleId }}</el-button>
|
||||
</el-tooltip>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Loading } from 'element-ui';
|
||||
export default {
|
||||
data(){
|
||||
return {
|
||||
ruleList:[
|
||||
{
|
||||
ruleId:0,
|
||||
bookRuleId:Number,
|
||||
bookDays:Number,
|
||||
bookLimitNumber:Number,
|
||||
bookOverdueFee:Number,
|
||||
bookLimitLibrary:"",
|
||||
createTime:"",
|
||||
updateTime:"",
|
||||
|
||||
}
|
||||
|
||||
],
|
||||
loading:true
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
async getRuleList(){
|
||||
const {data:res} = await this.$http.get("user/get_rulelist")
|
||||
if(res.status !== 200){
|
||||
this.loading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message:res.msg,
|
||||
duration:1000
|
||||
})
|
||||
this.loading = false;
|
||||
this.ruleList = res.data
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.getRuleList()
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.rule_container {
|
||||
position: relative;
|
||||
}
|
||||
.header {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translate(-50%);
|
||||
p {
|
||||
font-size: 36px;
|
||||
color: rgb(70, 130, 180);
|
||||
}
|
||||
}
|
||||
.banner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position:absolute;
|
||||
left:50%;
|
||||
transform: translate(-50%);
|
||||
|
||||
}
|
||||
.el-tooltip{
|
||||
width: 500px;
|
||||
font-size: 16px;
|
||||
color:white;
|
||||
}
|
||||
.el-tooltip:hover{
|
||||
color:black;
|
||||
}
|
||||
.el-tooltip:nth-child(1){
|
||||
margin-top:100px;
|
||||
}
|
||||
.el-tooltip:nth-child(n+2){
|
||||
margin-top:50px;
|
||||
margin-left:0px;
|
||||
}
|
||||
.el-tooltip:nth-child(odd){
|
||||
background-color: pink;
|
||||
}
|
||||
.el-tooltip:nth-child(even){
|
||||
background-color: rgb(49, 176, 213)
|
||||
}
|
||||
.content_tip {
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
228
src/components/User/Search.vue
Normal file
@ -0,0 +1,228 @@
|
||||
<template>
|
||||
<div class="search_container">
|
||||
<!-- 面包屑导航区域 -->
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item>首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>图书查询</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<el-card shadow="always">
|
||||
<!-- 搜索内容和导出区域 -->
|
||||
<el-row>
|
||||
<el-col :span="6"
|
||||
>条件搜索:
|
||||
<el-select
|
||||
v-model="queryInfo.condition"
|
||||
filterable
|
||||
placeholder="请选择"
|
||||
style="margin-left: 15px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-input
|
||||
placeholder="请输入内容"
|
||||
v-model="queryInfo.query"
|
||||
class="input-with-select"
|
||||
@keyup.enter.native="searchBookByPage"
|
||||
>
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-search"
|
||||
@click="searchBookByPage"
|
||||
></el-button>
|
||||
</el-input>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<download-excel
|
||||
class="export-excel-wrapper"
|
||||
:data="tableData"
|
||||
:fields="json_fields"
|
||||
:header="title"
|
||||
name="图书查询表格.xls"
|
||||
>
|
||||
<!-- 上面可以自定义自己的样式,还可以引用其他组件button -->
|
||||
<el-button type="primary" class="el-icon-printer" size="mini"
|
||||
>导出Excel
|
||||
</el-button>
|
||||
</download-excel>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<el-button
|
||||
type="primary"
|
||||
class="el-icon-printer"
|
||||
size="mini"
|
||||
@click="downLoad"
|
||||
>导出PDF
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<el-button
|
||||
type="success"
|
||||
class="el-icon-full-screen"
|
||||
size="mini"
|
||||
@click="fullScreen"
|
||||
>全屏
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 表格区域 -->
|
||||
<el-table
|
||||
:data="tableData"
|
||||
height="520"
|
||||
border
|
||||
style="width: 100%; font-size: 14px"
|
||||
v-loading="loading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)"
|
||||
id="pdfDom"
|
||||
:default-sort="{ prop: 'bookNumber', order: 'ascending' }"
|
||||
stripe
|
||||
>
|
||||
<el-table-column
|
||||
prop="bookNumber"
|
||||
label="图书编号"
|
||||
sortable
|
||||
></el-table-column>
|
||||
<el-table-column prop="bookName" label="图书名称"></el-table-column>
|
||||
<el-table-column prop="bookAuthor" label="作者"></el-table-column>
|
||||
<el-table-column prop="bookLibrary" label="图书馆"></el-table-column>
|
||||
<el-table-column prop="bookType" label="分类"></el-table-column>
|
||||
<el-table-column
|
||||
prop="bookLocation"
|
||||
label="位置"
|
||||
sortable
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="bookStatus"
|
||||
label="状态"
|
||||
sortable
|
||||
></el-table-column>
|
||||
<el-table-column prop="bookDescription" label="描述" width="600px">
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页查询区域 -->
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="this.queryInfo.pageNum"
|
||||
:page-sizes="[1, 2, 3, 4, 5]"
|
||||
:page-size="this.queryInfo.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="this.total"
|
||||
>
|
||||
</el-pagination>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{
|
||||
value: "book_number",
|
||||
label: "图书编号",
|
||||
},
|
||||
{
|
||||
value: "book_name",
|
||||
label: "图书名称",
|
||||
},
|
||||
{
|
||||
value: "book_author",
|
||||
label: "作者",
|
||||
},
|
||||
{
|
||||
value: "book_location",
|
||||
label: "位置",
|
||||
},
|
||||
{
|
||||
value: "book_description",
|
||||
label: "描述",
|
||||
},
|
||||
],
|
||||
tableData: [],
|
||||
queryInfo: {
|
||||
pageNum: 1,
|
||||
pageSize: 5,
|
||||
condition: "",
|
||||
query: "",
|
||||
},
|
||||
total: 0,
|
||||
|
||||
title: "图书查询表格",
|
||||
json_fields: {
|
||||
图书编号: "bookNumber",
|
||||
图书名称: "bookName",
|
||||
作者: "bookAuthor",
|
||||
图书馆: "bookLibrary",
|
||||
分类: "bookType",
|
||||
位置: "bookLocation",
|
||||
状态: "bookStatus",
|
||||
描述: "bookDescription",
|
||||
},
|
||||
loading: true,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.searchBookByPage();
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(val) {
|
||||
this.queryInfo.pageSize = val;
|
||||
|
||||
this.searchBookByPage();
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.queryInfo.pageNum = val;
|
||||
|
||||
this.searchBookByPage();
|
||||
},
|
||||
async searchBookByPage() {
|
||||
this.loading = true;
|
||||
const { data: res } = await this.$http.post(
|
||||
"user/search_book_page",
|
||||
this.queryInfo
|
||||
);
|
||||
this.tableData = [];
|
||||
if (res.status !== 200) {
|
||||
this.total = 0;
|
||||
this.loading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1000,
|
||||
});
|
||||
this.loading = false;
|
||||
this.tableData = res.data.records;
|
||||
this.total = parseInt(res.data.total);
|
||||
},
|
||||
downLoad() {
|
||||
this.getPdf(this.title); //参数是下载的pdf文件名
|
||||
},
|
||||
fullScreen() {
|
||||
// Dom对象的一个属性: 可以用来判断当前是否为全屏模式(trueORfalse)
|
||||
let full = document.fullscreenElement;
|
||||
// 切换为全屏模式
|
||||
if (!full) {
|
||||
// 文档根节点的方法requestFullscreen实现全屏模式
|
||||
document.documentElement.requestFullscreen();
|
||||
} else {
|
||||
// 退出全屏模式
|
||||
document.exitFullscreen();
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css"></style>
|
215
src/components/User/Violation.vue
Normal file
@ -0,0 +1,215 @@
|
||||
<template>
|
||||
<div class="search_container">
|
||||
<!-- 面包屑导航区域 -->
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item>首页</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>违章信息</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<el-card shadow="always">
|
||||
<!-- 搜索内容和导出区域 -->
|
||||
<el-row>
|
||||
<el-col :span="6"
|
||||
>条件搜索:<el-select
|
||||
v-model="queryInfo.condition"
|
||||
filterable
|
||||
placeholder="请选择"
|
||||
style="margin-left: 15px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-input
|
||||
placeholder="请输入内容"
|
||||
v-model="queryInfo.query"
|
||||
class="input-with-select"
|
||||
@keyup.enter.native="searchViolationByPage"
|
||||
>
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-search"
|
||||
@click="searchViolationByPage"
|
||||
></el-button> </el-input
|
||||
></el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<download-excel
|
||||
class="export-excel-wrapper"
|
||||
:data="tableData"
|
||||
:fields="json_fields"
|
||||
:header="title"
|
||||
name="图书违章表格.xls"
|
||||
>
|
||||
<!-- 上面可以自定义自己的样式,还可以引用其他组件button -->
|
||||
<el-button type="primary" class="el-icon-printer" size="mini"
|
||||
>导出Excel</el-button
|
||||
>
|
||||
</download-excel>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
<el-button
|
||||
type="primary"
|
||||
class="el-icon-printer"
|
||||
size="mini"
|
||||
@click="downLoad"
|
||||
>导出PDF</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="2" style="float: right">
|
||||
|
||||
<el-button type="success" class="el-icon-full-screen" size="mini" @click="fullScreen"
|
||||
>全屏</el-button
|
||||
>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 表格区域 -->
|
||||
<el-table :data="tableData" border style="width: 100%" stripe id="pdfDom" :default-sort = "{prop: 'cardNumber', order: 'ascending'}"
|
||||
v-loading="loading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)">
|
||||
<el-table-column prop="cardNumber" label="借阅证号" sortable> </el-table-column>
|
||||
<el-table-column prop="bookNumber" label="图书编号" sortable> </el-table-column>
|
||||
<el-table-column prop="borrowDate" label="借阅日期" sortable> </el-table-column>
|
||||
<el-table-column prop="closeDate" label="截止日期" sortable> </el-table-column>
|
||||
<el-table-column prop="returnDate" label="归还日期" sortable> </el-table-column>
|
||||
<el-table-column prop="violationMessage" label="违章信息">
|
||||
</el-table-column>
|
||||
<el-table-column prop="violationAdmin" label="处理人">
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页查询区域 -->
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="this.queryInfo.pageNum"
|
||||
:page-sizes="[1, 2, 3, 4, 5]"
|
||||
:page-size="this.queryInfo.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="this.total"
|
||||
>
|
||||
</el-pagination>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
options: [
|
||||
{
|
||||
value: "book_number",
|
||||
label: "图书编号",
|
||||
},
|
||||
{
|
||||
value: "borrow_date",
|
||||
label: "借阅日期",
|
||||
},
|
||||
{
|
||||
value: "close_date",
|
||||
label: "截止日期",
|
||||
},
|
||||
{
|
||||
value: "return_date",
|
||||
label: "归还日期",
|
||||
},
|
||||
{
|
||||
value: "violation_message",
|
||||
label: "违章信息",
|
||||
},
|
||||
],
|
||||
tableData: [
|
||||
{
|
||||
cardNumber: Number,
|
||||
bookNumber: Number,
|
||||
borrowDate: "",
|
||||
closeDate: "",
|
||||
returnDate: "",
|
||||
violationMessage: "",
|
||||
violationAdmin: "",
|
||||
},
|
||||
],
|
||||
queryInfo: {
|
||||
pageNum: 1,
|
||||
pageSize: 5,
|
||||
condition: "",
|
||||
query: "",
|
||||
cardNumber: window.sessionStorage.getItem("cardNumber"),
|
||||
},
|
||||
total: 0,
|
||||
title: "图书违章表格",
|
||||
json_fields: {
|
||||
借阅证号: "cardNumber",
|
||||
图书编号: "bookNumber",
|
||||
借阅日期: "borrowDate",
|
||||
截止日期: "closeDate",
|
||||
归还日期: "returnDate",
|
||||
违章信息:"violationMessage",
|
||||
处理人:"violationAdmin"
|
||||
},
|
||||
loading:true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(val) {
|
||||
this.queryInfo.pageSize = val;
|
||||
|
||||
this.searchViolationByPage();
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.queryInfo.pageNum = val;
|
||||
|
||||
this.searchViolationByPage();
|
||||
},
|
||||
async searchViolationByPage() {
|
||||
this.loading = true;
|
||||
const { data: res } = await this.$http.post(
|
||||
"user/get_violation",
|
||||
this.queryInfo
|
||||
);
|
||||
|
||||
this.tableData = [];
|
||||
// console.log(res);
|
||||
if (res.status !== 200) {
|
||||
this.total = 0;
|
||||
this.loading = false;
|
||||
return this.$message.error(res.msg);
|
||||
}
|
||||
this.$message.success({
|
||||
message: res.msg,
|
||||
duration: 1000,
|
||||
});
|
||||
this.tableData = res.data.records;
|
||||
this.total = parseInt(res.data.total);
|
||||
this.loading = false;
|
||||
},
|
||||
downLoad() {
|
||||
this.getPdf(this.title); //参数是下载的pdf文件名
|
||||
},
|
||||
fullScreen(){
|
||||
// Dom对象的一个属性: 可以用来判断当前是否为全屏模式(trueORfalse)
|
||||
let full = document.fullscreenElement;
|
||||
// 切换为全屏模式
|
||||
if(!full){
|
||||
// 文档根节点的方法requestFullscreen实现全屏模式
|
||||
document.documentElement.requestFullscreen();
|
||||
}else{
|
||||
// 退出全屏模式
|
||||
document.exitFullscreen();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.searchViolationByPage();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
34
src/components/Utils/htmlToPdf.js
Normal file
@ -0,0 +1,34 @@
|
||||
import html2canvas from 'html2canvas'
|
||||
import jsPDF from 'jspdf'
|
||||
export default{
|
||||
install (Vue, options) {
|
||||
Vue.prototype.getPdf = function (htmlTitle,currentTime) {
|
||||
var element = document.getElementById("pdfDom");
|
||||
html2canvas(element, {
|
||||
logging:false
|
||||
}).then(function(canvas) {
|
||||
var pdf = new jsPDF('p', 'mm', 'a4'); //A4纸,纵向
|
||||
var ctx = canvas.getContext('2d'),
|
||||
a4w = 190, a4h = 277, //A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
|
||||
imgHeight = Math.floor(a4h * canvas.width / a4w), //按A4显示比例换算一页图像的像素高度
|
||||
renderedHeight = 0;
|
||||
|
||||
while(renderedHeight < canvas.height) {
|
||||
var page = document.createElement("canvas");
|
||||
page.width = canvas.width;
|
||||
page.height = Math.min(imgHeight, canvas.height - renderedHeight);//可能内容不足一页
|
||||
|
||||
//用getImageData剪裁指定区域,并画到前面创建的canvas对象中
|
||||
page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0);
|
||||
pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width)); //添加图像到页面,保留10mm边距
|
||||
|
||||
renderedHeight += imgHeight;
|
||||
if(renderedHeight < canvas.height)
|
||||
pdf.addPage();//如果后面还有内容,添加一个空页
|
||||
}
|
||||
|
||||
pdf.save(htmlTitle);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
83
src/components/Utils/websocket.js
Normal file
@ -0,0 +1,83 @@
|
||||
//暴露自定义websocket对象
|
||||
export const socket = {
|
||||
//后台请求路径
|
||||
url: "",
|
||||
//websocket对象
|
||||
websocket: null,
|
||||
//websocket状态
|
||||
websocketState: false,
|
||||
//重新连接次数
|
||||
reconnectNum: 0,
|
||||
//重连锁状态,保证重连按顺序执行
|
||||
lockReconnect: false,
|
||||
//定时器信息
|
||||
timeout: null,
|
||||
clientTimeout: null,
|
||||
serverTimeout: null,
|
||||
//初始化方法,根据url创建websocket对象封装基本连接方法,并重置心跳检测
|
||||
initWebSocket(newUrl) {
|
||||
socket.url = newUrl;
|
||||
socket.websocket = new WebSocket(socket.url);
|
||||
socket.websocket.onopen = socket.websocketOnOpen;
|
||||
socket.websocket.onerror = socket.websocketOnError;
|
||||
socket.websocket.onclose = socket.websocketOnClose;
|
||||
this.resetHeartbeat()
|
||||
},
|
||||
reconnect() {
|
||||
//判断连接状态
|
||||
if (socket.lockReconnect) return;
|
||||
socket.reconnectNum += 1;
|
||||
//重新连接三次还未成功调用连接关闭方法
|
||||
if (socket.reconnectNum === 3) {
|
||||
socket.reconnectNum = 0;
|
||||
socket.websocket.onclose()
|
||||
return;
|
||||
}
|
||||
//等待本次重连完成后再进行下一次
|
||||
socket.lockReconnect = true;
|
||||
//5s后进行重新连接
|
||||
socket.timeout = setTimeout(() => {
|
||||
socket.initWebSocket(socket.url);
|
||||
socket.lockReconnect = false;
|
||||
}, 5000);
|
||||
},
|
||||
//重置心跳检测
|
||||
resetHeartbeat() {
|
||||
socket.heartbeat();
|
||||
},
|
||||
//心跳检测
|
||||
heartbeat() {
|
||||
socket.clientTimeout = setTimeout(() => {
|
||||
if (socket.websocket) {
|
||||
//向后台发送消息进行心跳检测
|
||||
socket.websocketState = false;
|
||||
//一分钟内服务器不响应则关闭连接
|
||||
socket.serverTimeout = setTimeout(() => {
|
||||
if (!socket.websocketState) {
|
||||
console.log("无响应,我要关闭")
|
||||
socket.websocket.onclose()
|
||||
} else {
|
||||
this.resetHeartbeat()
|
||||
}
|
||||
}, 10 * 1000);
|
||||
}
|
||||
}, 3 * 1000);
|
||||
},
|
||||
//发送消息
|
||||
sendMsg(message) {
|
||||
socket.websocket.send(message);
|
||||
},
|
||||
websocketOnOpen(event) {
|
||||
//连接开启后向后台发送消息进行一次心跳检测
|
||||
console.log("WebSocket 启动")
|
||||
socket.sendMsg("PING");
|
||||
},
|
||||
websocketOnError(error) {
|
||||
console.log(error);
|
||||
socket.reconnect();
|
||||
},
|
||||
websocketOnClose() {
|
||||
socket.websocket.close();
|
||||
},
|
||||
};
|
||||
|
81
src/main-dev.js
Normal file
@ -0,0 +1,81 @@
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
//引入路由组件
|
||||
import router from './router'
|
||||
//引入element ui 组件库
|
||||
import './plugins/element.js'
|
||||
//引入粒子插件
|
||||
import VueParticles from 'vue-particles'
|
||||
//引入全局样式表
|
||||
import './assets/css/global.css'
|
||||
//引入图书管理系统的图标和字体库
|
||||
import './assets/fonts/iconfont.css'
|
||||
|
||||
// 引入swiper的样式
|
||||
// import 'swiper/css/swiper.css'
|
||||
//单独引入Message axios拦截器需要
|
||||
import {Message} from 'element-ui'
|
||||
// 引入表格导出excel插件
|
||||
import JsonExcel from 'vue-json-excel'
|
||||
Vue.component('downloadExcel', JsonExcel)
|
||||
// 导入pdf插件
|
||||
import htmlToPdf from './components/Utils/htmlToPdf.js'
|
||||
Vue.use(htmlToPdf)
|
||||
// 引入echarts
|
||||
import * as echarts from 'echarts'
|
||||
// 引入Chrome PassiveEventListeners优化页面性能
|
||||
import 'default-passive-events'
|
||||
// 引入lodash
|
||||
import _ from 'lodash'
|
||||
Vue.prototype._ = _ //全局导入的挂载方式
|
||||
// 设置全局变量
|
||||
Vue.prototype.$echarts = echarts
|
||||
|
||||
//注册粒子插件
|
||||
Vue.use(VueParticles)
|
||||
//main.js:
|
||||
import { vueBaberrage } from 'vue-baberrage'
|
||||
//使用弹幕插件
|
||||
Vue.use(vueBaberrage)
|
||||
//导入axios
|
||||
import axios from 'axios'
|
||||
//配置请求的根路径
|
||||
axios.defaults.baseURL = 'http://localhost:8889/api/'
|
||||
Vue.prototype.$http = axios
|
||||
// const CancelToken = axios.CancelToken;
|
||||
// const source = CancelToken.source();
|
||||
// export {source}
|
||||
//导入NProgress包对应的js和CSS
|
||||
import NProgress from 'nprogress'
|
||||
import 'nprogress/nprogress.css'
|
||||
//在request拦截器中,展示进度条NProgress.start()
|
||||
axios.interceptors.request.use(config => {
|
||||
NProgress.start()
|
||||
// console.log(config);
|
||||
// 为请求头对象,添加Token验证的Authorization字段
|
||||
config.headers.Authorization = "Bearer "+window.sessionStorage.getItem('token');
|
||||
return config;
|
||||
})
|
||||
//在response拦截器中,隐藏进度条NProgress.done()
|
||||
axios.interceptors.response.use(response => {
|
||||
NProgress.done()
|
||||
// 登录校验 响应状态码为401时拦截
|
||||
if(response.data.status === 401) {
|
||||
Message.error("未登录或登录过期,请重新登录");
|
||||
// 清除过期的token和原来保存的用户id
|
||||
window.sessionStorage.clear();
|
||||
// 跳转到登录页面
|
||||
router.replace('/login')
|
||||
}
|
||||
// }else if (response.data.status === 404){
|
||||
// Message.error('访问的资源或地址不存在');
|
||||
// router.replace('/404');
|
||||
// }
|
||||
return response
|
||||
})
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
76
src/main-prod.js
Normal file
@ -0,0 +1,76 @@
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
//引入路由组件
|
||||
import router from './router'
|
||||
//引入element ui 组件库
|
||||
import './plugins/element.js'
|
||||
//引入粒子插件
|
||||
import VueParticles from 'vue-particles'
|
||||
//引入全局样式表
|
||||
import './assets/css/global.css'
|
||||
//引入图书管理系统的图标和字体库
|
||||
import './assets/fonts/iconfont.css'
|
||||
// 引入swiper的样式
|
||||
// import 'swiper/css/swiper.css'
|
||||
//单独引入Message axios拦截器需要
|
||||
import {Message} from 'element-ui'
|
||||
// 引入表格导出excel插件
|
||||
import JsonExcel from 'vue-json-excel'
|
||||
Vue.component('downloadExcel', JsonExcel)
|
||||
// 导入pdf插件
|
||||
import htmlToPdf from './components/Utils/htmlToPdf.js'
|
||||
Vue.use(htmlToPdf)
|
||||
// 引入echarts
|
||||
import * as echarts from 'echarts'
|
||||
// 引入Chrome PassiveEventListeners优化页面性能
|
||||
import 'default-passive-events'
|
||||
// 设置全局变量
|
||||
Vue.prototype.$echarts = echarts
|
||||
|
||||
//注册粒子插件
|
||||
Vue.use(VueParticles)
|
||||
//main.js:
|
||||
import { vueBaberrage } from 'vue-baberrage'
|
||||
//使用弹幕插件
|
||||
Vue.use(vueBaberrage)
|
||||
//导入axios
|
||||
import axios from 'axios'
|
||||
//配置请求的根路径
|
||||
axios.defaults.baseURL = 'http://abc.xiaobaitiao.top:443/api/'
|
||||
Vue.prototype.$http = axios
|
||||
// const CancelToken = axios.CancelToken;
|
||||
// const source = CancelToken.source();
|
||||
// export {source}
|
||||
//导入NProgress包对应的js和CSS
|
||||
import NProgress from 'nprogress'
|
||||
import 'nprogress/nprogress.css'
|
||||
// 引入lodash
|
||||
import _ from 'lodash'
|
||||
Vue.prototype._ = _ //全局导入的挂载方式
|
||||
//在request拦截器中,展示进度条NProgress.start()
|
||||
axios.interceptors.request.use(config => {
|
||||
NProgress.start()
|
||||
// console.log(config);
|
||||
// 为请求头对象,添加Token验证的Authorization字段
|
||||
config.headers.Authorization = "Bearer "+window.sessionStorage.getItem('token');
|
||||
return config;
|
||||
})
|
||||
//在response拦截器中,隐藏进度条NProgress.done()
|
||||
axios.interceptors.response.use(response => {
|
||||
NProgress.done()
|
||||
// 登录校验 响应状态码为401时拦截
|
||||
if(response.data.status === 401){
|
||||
Message.error("未登录或登录过期,请重新登录");
|
||||
// 清除过期的token和原来保存的用户id
|
||||
window.sessionStorage.clear();
|
||||
// 跳转到登录页面
|
||||
router.replace('/login')
|
||||
}
|
||||
return response
|
||||
})
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
100
src/plugins/element.js
Normal file
@ -0,0 +1,100 @@
|
||||
import Vue from 'vue'
|
||||
// import { Button } from 'element-ui'
|
||||
// import {Form,FormItem} from 'element-ui'
|
||||
// import {Input} from 'element-ui'
|
||||
// //导入弹框提示组件
|
||||
// import {Message} from 'element-ui'
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
Message,
|
||||
Container,
|
||||
Header,
|
||||
Aside,
|
||||
Main,
|
||||
Menu,
|
||||
Submenu,
|
||||
MenuItem,
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
Card,
|
||||
Row,
|
||||
Col,
|
||||
Table,
|
||||
TableColumn,
|
||||
Switch,
|
||||
Tooltip,
|
||||
Pagination,
|
||||
Dialog,
|
||||
MessageBox,
|
||||
Tag,
|
||||
Tree,
|
||||
Select,
|
||||
Option,
|
||||
Cascader,
|
||||
Alert,
|
||||
Tabs,
|
||||
TabPane,
|
||||
Steps,
|
||||
Step,
|
||||
CheckboxGroup,
|
||||
Checkbox,
|
||||
Upload,
|
||||
Avatar,
|
||||
Loading,
|
||||
Divider,
|
||||
DatePicker,
|
||||
RadioGroup,
|
||||
RadioButton,
|
||||
Radio,
|
||||
Popover
|
||||
} from 'element-ui'
|
||||
Vue.use(Button)
|
||||
Vue.use(Form)
|
||||
Vue.use(FormItem)
|
||||
Vue.use(Input)
|
||||
Vue.use(Container)
|
||||
Vue.use(Header)
|
||||
Vue.use(Aside)
|
||||
Vue.use(Main)
|
||||
Vue.use(Menu)
|
||||
Vue.use(Main)
|
||||
Vue.use(Submenu)
|
||||
Vue.use(MenuItem)
|
||||
Vue.use(Breadcrumb)
|
||||
Vue.use(BreadcrumbItem)
|
||||
Vue.use(Card)
|
||||
Vue.use(Row)
|
||||
Vue.use(Col)
|
||||
Vue.use(Table)
|
||||
Vue.use(TableColumn)
|
||||
Vue.use(Switch)
|
||||
Vue.use(Tooltip)
|
||||
Vue.use(Pagination)
|
||||
Vue.use(Dialog)
|
||||
Vue.use(Tag)
|
||||
Vue.use(Tree)
|
||||
Vue.use(Select)
|
||||
Vue.use(Option)
|
||||
Vue.use(Cascader)
|
||||
Vue.use(Alert)
|
||||
Vue.use(TabPane)
|
||||
Vue.use(Tabs)
|
||||
Vue.use(Step)
|
||||
Vue.use(Steps)
|
||||
Vue.use(CheckboxGroup)
|
||||
Vue.use(Checkbox)
|
||||
Vue.use(Upload)
|
||||
Vue.use(Avatar)
|
||||
Vue.use(Loading)
|
||||
Vue.use(Divider)
|
||||
Vue.use(DatePicker)
|
||||
Vue.use(RadioGroup)
|
||||
Vue.use(RadioButton)
|
||||
Vue.use(Radio)
|
||||
Vue.use(Popover)
|
||||
//把Message挂载到vue的原型对象上,可以通过this.$message获取
|
||||
Vue.prototype.$message = Message
|
||||
Vue.prototype.$confirm = MessageBox.confirm
|
164
src/router/index.js
Normal file
@ -0,0 +1,164 @@
|
||||
import Vue from "vue";
|
||||
import VueRouter from "vue-router";
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
const routes = [
|
||||
{ path: "/", redirect: "/login" },
|
||||
{ path: "/login", component: () => import("@/components/Login.vue") },
|
||||
{
|
||||
path: "/loginmanage",
|
||||
component: () => import("@/components/BookManage/LoginBookManage.vue"),
|
||||
},
|
||||
{
|
||||
path: "/home",
|
||||
component: () => import("@/components/Home/Home.vue"),
|
||||
redirect: "/index",
|
||||
children: [
|
||||
{
|
||||
path: "/index",
|
||||
component: () => import("@/components/Index/Index.vue"),
|
||||
meta: {
|
||||
title: "首页",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/search",
|
||||
component: () => import("@/components/User/Search.vue"),
|
||||
},
|
||||
{ path: "/rule", component: () => import("@/components/User/Rule.vue") },
|
||||
{
|
||||
path: "/notice",
|
||||
component: () => import("@/components/User/Notice.vue"),
|
||||
},
|
||||
{
|
||||
path: "/information",
|
||||
component: () => import("@/components/User/Information.vue"),
|
||||
},
|
||||
{
|
||||
path: "/borrow",
|
||||
component: () => import("@/components/User/Borrow.vue"),
|
||||
},
|
||||
{
|
||||
path: "/violation",
|
||||
component: () => import("@/components/User/Violation.vue"),
|
||||
},
|
||||
{
|
||||
path: "/comment",
|
||||
component: () => import("@/components/User/Comment.vue"),
|
||||
},
|
||||
{
|
||||
path: "/intelligent",
|
||||
component: () => import("@/components/User/Intelligent.vue"),
|
||||
},
|
||||
// { path: "/chat", component: () => import("@/components/User/Chat") },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/homemange",
|
||||
component: () => import("@/components/Home/HomeManage.vue"),
|
||||
children: [
|
||||
{
|
||||
path: "/borrowbook",
|
||||
component: () => import("@/components/BookManage/BorrowBook.vue"),
|
||||
},
|
||||
{
|
||||
path: "/returnbook",
|
||||
component: () => import("@/components/BookManage/ReturnBook.vue"),
|
||||
},
|
||||
{
|
||||
path: "/borrowstatement",
|
||||
component: () => import("@/components/BookManage/BorrowStatement.vue"),
|
||||
},
|
||||
{
|
||||
path: "/returnstatement",
|
||||
component: () => import("@/components/BookManage/ReturnStatement.vue"),
|
||||
},
|
||||
{
|
||||
path: "/noticemanage",
|
||||
component: () => import("@/components/BookManage/NoticeManage.vue"),
|
||||
},
|
||||
{
|
||||
path: "/bookexpire",
|
||||
name: "bookexpire",
|
||||
component: () => import("@/components/BookManage/BookExpire.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/loginadmin",
|
||||
component: () => import("@/components/Admin/LoginAdmin.vue"),
|
||||
},
|
||||
{
|
||||
path: "/homeadmin",
|
||||
component: () => import("@/components/Home/HomeAdmin.vue"),
|
||||
children: [
|
||||
{
|
||||
path: "/bookmanage",
|
||||
component: () => import("@/components/Admin/BookManage.vue"),
|
||||
},
|
||||
{
|
||||
path: "/booktype",
|
||||
component: () => import("@/components/Admin/BookType.vue"),
|
||||
},
|
||||
{
|
||||
path: "/statementmanage",
|
||||
component: () => import("@/components/Admin/StatementManage.vue"),
|
||||
},
|
||||
{
|
||||
path: "/statementsearch",
|
||||
component: () => import("@/components/Admin/StatementSearch.vue"),
|
||||
},
|
||||
{
|
||||
path: "/statementrulemanage",
|
||||
component: () => import("@/components/Admin/StatementRuleManage.vue"),
|
||||
},
|
||||
{
|
||||
path: "/bookadminmanage",
|
||||
component: () => import("@/components/Admin/BookAdminManage.vue"),
|
||||
},
|
||||
{
|
||||
path: "/adminmanage",
|
||||
component: () => import("@/components/Admin/AdminManage.vue"),
|
||||
},
|
||||
{
|
||||
path: "/intelligent_analysis",
|
||||
component: () => import("@/components/Admin/IntelligentAnalysis.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/404",
|
||||
component: () => import("@/components/404/404.vue"),
|
||||
},
|
||||
{
|
||||
path: "/:pathMatch(.*)*",
|
||||
redirect: "/404",
|
||||
},
|
||||
];
|
||||
|
||||
const router = new VueRouter({
|
||||
routes,
|
||||
});
|
||||
// //挂载路由导航守卫
|
||||
router.beforeEach((to, from, next) => {
|
||||
//to将要访问的路径
|
||||
//from代表从哪个路径跳转而来
|
||||
//next是一个函数表示放行
|
||||
const tokenStr = window.sessionStorage.getItem("token");
|
||||
if (tokenStr) {
|
||||
next();
|
||||
} else {
|
||||
// 用户未登录判断
|
||||
if (
|
||||
to.path === "/login" ||
|
||||
to.path === "/loginmanage" ||
|
||||
to.path === "/loginadmin"
|
||||
) {
|
||||
next();
|
||||
} else {
|
||||
next({ path: "/login" });
|
||||
}
|
||||
}
|
||||
});
|
||||
export default router
|
43
vue.config.js
Normal file
@ -0,0 +1,43 @@
|
||||
const { defineConfig } = require('@vue/cli-service')
|
||||
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin')
|
||||
const path = require('path')
|
||||
module.exports = defineConfig({
|
||||
configureWebpack: {
|
||||
plugins: [new NodePolyfillPlugin()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve("./src") // 相对路径别名配置,使用 @ 代替 src
|
||||
}
|
||||
},
|
||||
},
|
||||
transpileDependencies: true,
|
||||
lintOnSave: false,
|
||||
devServer: {
|
||||
host: '0.0.0.0',
|
||||
port: 8081,
|
||||
client: {
|
||||
webSocketURL: 'ws://0.0.0.0/ws',
|
||||
},
|
||||
},
|
||||
|
||||
chainWebpack:config =>{
|
||||
//发布模式
|
||||
config.when(process.env.NODE_ENV === 'production',config =>{
|
||||
config.entry('app').clear().add('./src/main-prod.js')
|
||||
|
||||
config.plugin('html').tap(args => {
|
||||
args[0].isProd = true
|
||||
return args
|
||||
})
|
||||
|
||||
})
|
||||
//开发模式
|
||||
config.when(process.env.NODE_ENV === 'development',config =>{
|
||||
config.entry('app').clear().add('./src/main-dev.js')
|
||||
config.plugin('html').tap(args => {
|
||||
args[0].isProd = false
|
||||
return args
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|