├── .gitignore
├── LICENSE
├── README.md
├── crawler
├── jue_jin_article.py
└── jue_jin_list.py
├── image
├── article.png
├── article__01.png
├── cloud__off.png
├── cloud__on.png
├── comm.png
├── dia.png
├── eye.png
├── fire.png
├── index.png
├── inform-logo-off.png
├── inform-logo-on.png
├── input-1.png
├── input.png
├── juejin-logo.png
├── juejinVip.png
├── jy.png
├── lv-2.png
├── panelFa.png
├── panelLiu.png
├── panelQuan.png
├── panelStar.png
├── panelZan.png
├── paneljing.png
├── pencil.png
├── ping.png
├── user.png
├── userEye.png
├── userZan.png
├── zan__off.png
└── zan__on.png
├── juejin-app
├── babel.config.js
├── jsconfig.json
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
├── src
│ ├── App.vue
│ ├── api
│ │ └── article.js
│ ├── assets
│ │ ├── css
│ │ │ ├── article.css
│ │ │ ├── header.css
│ │ │ └── main.css
│ │ ├── img
│ │ │ ├── article__01.png
│ │ │ ├── cloud__off.png
│ │ │ ├── cloud__on.png
│ │ │ ├── comm.png
│ │ │ ├── day.png
│ │ │ ├── dia.png
│ │ │ ├── eye.png
│ │ │ ├── fire.png
│ │ │ ├── inform-logo-off.png
│ │ │ ├── inform-logo-on.png
│ │ │ ├── input-1.png
│ │ │ ├── input.png
│ │ │ ├── juejin-logo.png
│ │ │ ├── juejinVip.png
│ │ │ ├── jy.png
│ │ │ ├── lv-2.png
│ │ │ ├── panelFa.png
│ │ │ ├── panelLiu.png
│ │ │ ├── panelQuan.png
│ │ │ ├── panelStar.png
│ │ │ ├── panelZan__off.png
│ │ │ ├── panelZan__on.png
│ │ │ ├── paneljing.png
│ │ │ ├── pencil.png
│ │ │ ├── ping.png
│ │ │ ├── top.png
│ │ │ ├── user-top.png
│ │ │ ├── user.png
│ │ │ ├── userEye.png
│ │ │ ├── userZan.png
│ │ │ ├── zan__off.png
│ │ │ └── zan__on.png
│ │ └── js
│ │ │ ├── EventBus.js
│ │ │ └── vue.js
│ ├── components
│ │ └── Header.vue
│ ├── main.js
│ ├── pages
│ │ ├── Detail.vue
│ │ └── Index.vue
│ ├── router
│ │ └── index.js
│ └── utils
│ │ ├── request.js
│ │ └── timeDispose.js
└── vue.config.js
├── juejin-server
├── .gitignore
├── .mvn
│ └── wrapper
│ │ ├── maven-wrapper.jar
│ │ └── maven-wrapper.properties
├── jue_jin.sql
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── edu
│ │ │ └── gdut
│ │ │ └── juejinserver
│ │ │ ├── JuejinServerApplication.java
│ │ │ ├── config
│ │ │ ├── MybatisPlusConfig.java
│ │ │ ├── RedisConfig.java
│ │ │ └── SwaggerConfig.java
│ │ │ ├── controller
│ │ │ ├── ArticleContentController.java
│ │ │ └── ArticleInfoController.java
│ │ │ ├── mapper
│ │ │ ├── ArticleContentMapper.java
│ │ │ ├── ArticleInfoMapper.java
│ │ │ ├── AuthorUserMapper.java
│ │ │ ├── TagsMapper.java
│ │ │ └── xml
│ │ │ │ ├── ArticleContentMapper.xml
│ │ │ │ ├── ArticleInfoMapper.xml
│ │ │ │ ├── AuthorUserMapper.xml
│ │ │ │ └── TagsMapper.xml
│ │ │ ├── pojo
│ │ │ ├── ArticleContent.java
│ │ │ ├── ArticleInfo.java
│ │ │ ├── AuthorUser.java
│ │ │ └── Tags.java
│ │ │ ├── service
│ │ │ ├── ArticleContentService.java
│ │ │ ├── ArticleInfoService.java
│ │ │ ├── AuthorUserService.java
│ │ │ ├── TagsService.java
│ │ │ └── impl
│ │ │ │ ├── ArticleContentServiceImpl.java
│ │ │ │ ├── ArticleInfoServiceImpl.java
│ │ │ │ ├── AuthorUserServiceImpl.java
│ │ │ │ └── TagsServiceImpl.java
│ │ │ ├── utils
│ │ │ ├── JuejinStringUtils.java
│ │ │ ├── Result.java
│ │ │ └── ResultCode.java
│ │ │ └── vo
│ │ │ ├── ArticleDetailVo.java
│ │ │ └── ArticleInfoVo.java
│ └── resources
│ │ └── application.properties
│ └── test
│ └── java
│ └── edu
│ └── gdut
│ └── juejinserver
│ └── CodeGenerator.java
└── project
├── article.css
├── article.html
├── index.html
├── page__header.css
└── page__main.css
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /juejin-app/dist
4 |
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 | *.iml
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 仿掘金官网
2 |
3 | ## 食用
4 |
5 | #### 进入`juejin-app`目录
6 |
7 | ```
8 | cd juejin-app
9 | ```
10 |
11 | #### 安装依赖
12 |
13 | ```
14 | npm install
15 | ```
16 |
17 | #### 启动服务器
18 |
19 | ```
20 | npm run serve
21 | ```
22 |
23 | #### 访问URL
24 |
25 | http://localhost:8080
26 |
27 | ## 演示
28 |
29 | 在线地址:http://106.14.212.78:8080
30 |
31 | - 主页
32 | 
33 | - 文章页
34 | 
35 |
36 |
--------------------------------------------------------------------------------
/crawler/jue_jin_article.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import re
3 | import pymysql
4 |
5 |
6 | def get_detail_content(article_id):
7 | """
8 | 爬取掘金文章内容
9 | :param article_id: 文章ID
10 | :return: 文章内容字符串
11 | """
12 |
13 | url = "https://juejin.cn/post/" + article_id
14 |
15 | headers = {
16 | "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"
17 | }
18 |
19 | resp = requests.get(url, headers=headers)
20 |
21 | text = resp.text
22 |
23 | resp.close()
24 |
25 | li = re.findall(r'article_info:{.*display_count:.*?}', text)
26 |
27 | s = "7016520448204603423" # 如果没有该文章id对应的数据就用这个
28 | if len(li) > 0:
29 | s = li[0]
30 |
31 | # 查找开始位置
32 | start_idx = s.find("mark_content")
33 |
34 | start_idx = start_idx + 14
35 |
36 | # 查找结束位置
37 | end_idx = s.find("display_count")
38 |
39 | end_idx = end_idx - 2
40 |
41 | result = s[start_idx:end_idx]
42 |
43 | return result
44 |
45 |
46 | # test
47 |
48 | # aid = "7130812569043861511"
49 | #
50 | # print(get_detail_content(aid))
51 |
52 | # 连接数据库
53 | host = "....."
54 | port = 3306
55 | user = "...."
56 | password = "....."
57 | charset = "utf8mb4"
58 | db = "jue_jin"
59 | # 返回连接对象
60 | conn = pymysql.connect(host=host, port=port, user=user, password=password, charset=charset, db=db)
61 | # 创建操作对象
62 | cur = conn.cursor()
63 | # 执行sql语句查出所有文章id记录
64 | sql = "select article_id from article_info"
65 | cur.execute(sql)
66 | # 返回执行结果
67 | tup = cur.fetchall()
68 |
69 | for ele in tup:
70 | article_id = ele[0]
71 | # 根据id查询文章内容
72 | article_content = get_detail_content(article_id=article_id)
73 | sql = "insert into article_content(article_id,mark_content) values(%s,%s)"
74 | cur.execute(sql, (article_id, article_content))
75 | conn.commit()
76 |
77 | print("finish")
78 |
79 | # 释放资源
80 | cur.close()
81 | conn.close()
82 |
--------------------------------------------------------------------------------
/crawler/jue_jin_list.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | import pandas as pd
4 | import xlwt
5 | import requests
6 |
7 |
8 | # 处理结果
9 | # 拿到一个list,list里面每个元素是一个dict字典,字典里的article_info里的数据就是需要的
10 | def get_article_info(json_data_list):
11 | result_list = []
12 | for dit in json_data_list:
13 | _dit = dit["item_info"]
14 |
15 | # # article_info
16 | # if "article_info" in _dit:
17 | # result_list.append(_dit["article_info"])
18 | # # author_user_info
19 |
20 | if "author_user_info" in _dit:
21 | result_list.append(_dit["author_user_info"])
22 | # # tags
23 | # if "tags" in _dit:
24 | # # 取到的是一个数组
25 | # temp_list = _dit["tags"]
26 | # if len(temp_list) > 0:
27 | # result_list.append(temp_list[0])
28 |
29 | return result_list
30 |
31 |
32 | # 爬数据
33 | def crawler_jue_jin(current_page):
34 | url = "https://api.juejin.cn/recommend_api/v1/article/recommend_all_feed?aid=2608&uuid=7123759892783040000"
35 |
36 | headers = {
37 | "content-type": "application/json;charset=utf-8",
38 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36',
39 | "origin": "https://juejin.cn",
40 | "referer": "https://juejin.cn/",
41 | "cookie": "_ga=GA1.2.1069960429.1658629609; __tea_cookie_tokens_2608=%257B%2522web_id%2522%253A%25227123759892783040000%2522%252C%2522user_unique_id%2522%253A%25227123759892783040000%2522%252C%2522timestamp%2522%253A1658629609298%257D; _tea_utm_cache_6587={%22utm_source%22:%22jjhd_2021_qxybj%22}; _tea_utm_cache_2608={%22utm_source%22:%22gold_browser_extension%22}; MONITOR_WEB_ID=efc1dda2-8e66-4b1a-95c6-039cdd100710; _gid=GA1.2.164141089.1659063255"
42 | }
43 |
44 | payload = {
45 | "client_type": 2608,
46 | "cursor": str(current_page),
47 | "id_type": 2,
48 | 'limit': 20,
49 | "sort_type": 200
50 | }
51 |
52 | resp = requests.post(url=url, data=json.dumps(payload), headers=headers)
53 |
54 | json_data = resp.json()["data"]
55 |
56 | result = get_article_info(json_data)
57 |
58 | resp.close()
59 |
60 | return result
61 |
62 |
63 | index = 0
64 | data_list = []
65 | while index < 52:
66 | temp = crawler_jue_jin(index)
67 | data_list.extend(temp)
68 | index += 1
69 |
70 |
71 | # 写文件到excel 或 直接存到数据库
72 | def export_excel(export):
73 | # 将字典列表转换为DataFrame
74 | pf = pd.DataFrame(list(export))
75 |
76 | # 生成的excel
77 | file_path = pd.ExcelWriter("juejin_data_users.xlsx")
78 |
79 | pf.to_excel(file_path, encoding="utf-8", index=False)
80 | file_path.save()
81 |
82 |
83 | print("start write data to excel...")
84 | export_excel(data_list)
85 | print("finish!")
86 |
--------------------------------------------------------------------------------
/image/article.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/article.png
--------------------------------------------------------------------------------
/image/article__01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/article__01.png
--------------------------------------------------------------------------------
/image/cloud__off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/cloud__off.png
--------------------------------------------------------------------------------
/image/cloud__on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/cloud__on.png
--------------------------------------------------------------------------------
/image/comm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/comm.png
--------------------------------------------------------------------------------
/image/dia.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/dia.png
--------------------------------------------------------------------------------
/image/eye.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/eye.png
--------------------------------------------------------------------------------
/image/fire.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/fire.png
--------------------------------------------------------------------------------
/image/index.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/index.png
--------------------------------------------------------------------------------
/image/inform-logo-off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/inform-logo-off.png
--------------------------------------------------------------------------------
/image/inform-logo-on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/inform-logo-on.png
--------------------------------------------------------------------------------
/image/input-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/input-1.png
--------------------------------------------------------------------------------
/image/input.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/input.png
--------------------------------------------------------------------------------
/image/juejin-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/juejin-logo.png
--------------------------------------------------------------------------------
/image/juejinVip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/juejinVip.png
--------------------------------------------------------------------------------
/image/jy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/jy.png
--------------------------------------------------------------------------------
/image/lv-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/lv-2.png
--------------------------------------------------------------------------------
/image/panelFa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/panelFa.png
--------------------------------------------------------------------------------
/image/panelLiu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/panelLiu.png
--------------------------------------------------------------------------------
/image/panelQuan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/panelQuan.png
--------------------------------------------------------------------------------
/image/panelStar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/panelStar.png
--------------------------------------------------------------------------------
/image/panelZan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/panelZan.png
--------------------------------------------------------------------------------
/image/paneljing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/paneljing.png
--------------------------------------------------------------------------------
/image/pencil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/pencil.png
--------------------------------------------------------------------------------
/image/ping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/ping.png
--------------------------------------------------------------------------------
/image/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/user.png
--------------------------------------------------------------------------------
/image/userEye.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/userEye.png
--------------------------------------------------------------------------------
/image/userZan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/userZan.png
--------------------------------------------------------------------------------
/image/zan__off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/zan__off.png
--------------------------------------------------------------------------------
/image/zan__on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/image/zan__on.png
--------------------------------------------------------------------------------
/juejin-app/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/juejin-app/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "esnext",
5 | "baseUrl": "./",
6 | "moduleResolution": "node",
7 | "paths": {
8 | "@/*": [
9 | "src/*"
10 | ]
11 | },
12 | "lib": [
13 | "esnext",
14 | "dom",
15 | "dom.iterable",
16 | "scripthost"
17 | ]
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/juejin-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "juejin-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "@bytemd/plugin-frontmatter": "^1.17.2",
12 | "@bytemd/vue": "^1.17.2",
13 | "axios": "^0.27.2",
14 | "bytemd": "^1.17.2",
15 | "core-js": "^3.8.3",
16 | "element-ui": "^2.15.9",
17 | "juejin-markdown-themes": "^1.29.3",
18 | "tb-skeleton": "^0.3.6",
19 | "vue": "^2.6.14",
20 | "vue-loading-skeleton": "^1.1.9",
21 | "vue-router": "^3.5.4",
22 | "vue-wechat-title": "^2.0.7"
23 | },
24 | "devDependencies": {
25 | "@babel/core": "^7.12.16",
26 | "@babel/eslint-parser": "^7.12.16",
27 | "@vue/cli-plugin-babel": "~5.0.0",
28 | "@vue/cli-plugin-eslint": "~5.0.0",
29 | "@vue/cli-service": "~5.0.0",
30 | "babel-plugin-component": "^1.1.1",
31 | "eslint": "^7.32.0",
32 | "eslint-plugin-vue": "^8.0.3",
33 | "vue-template-compiler": "^2.6.14"
34 | },
35 | "eslintConfig": {
36 | "root": true,
37 | "env": {
38 | "node": true
39 | },
40 | "extends": [
41 | "plugin:vue/essential",
42 | "eslint:recommended"
43 | ],
44 | "parserOptions": {
45 | "parser": "@babel/eslint-parser"
46 | },
47 | "rules": {}
48 | },
49 | "browserslist": [
50 | "> 1%",
51 | "last 2 versions",
52 | "not dead"
53 | ]
54 | }
55 |
--------------------------------------------------------------------------------
/juejin-app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/public/favicon.ico
--------------------------------------------------------------------------------
/juejin-app/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
12 | We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/juejin-app/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
30 |
31 |
--------------------------------------------------------------------------------
/juejin-app/src/api/article.js:
--------------------------------------------------------------------------------
1 | import request from "../utils/request"
2 |
3 | export default {
4 | getArticleInfo(current, limit) {
5 | return request({
6 | url: `/juejinserver/index_data/find_article/${current}/${limit}`,
7 | method: "get"
8 | })
9 | },
10 |
11 | getArticleDetailById(articleId) {
12 | return request({
13 | url: `/juejinserver/index_data/findArticleDetail/${articleId}`,
14 | method: "get"
15 | })
16 | },
17 |
18 | getArticleTagsById(articleId) {
19 | return request({
20 | url: `/juejinserver/index_data/findArticleTags/${articleId}`,
21 | method: "get"
22 | })
23 | },
24 |
25 | getArticleContentById(articleId) {
26 | return request({
27 | url: `/juejinserver/article_content/getArticleContent/${articleId}`,
28 | method: "get"
29 | })
30 | }
31 | }
--------------------------------------------------------------------------------
/juejin-app/src/assets/css/article.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | background-color: #f4f5f5;
4 | }
5 |
6 | .page{
7 | width: 98.93vw;
8 | }
9 |
10 | .page__header{
11 | width: 100%;
12 | height: 60px;
13 | }
14 |
15 | .page__main{
16 | max-width: 1140px;
17 | width: 100%;
18 | margin: 0 auto;
19 | position: relative;
20 | margin-top: 81px;
21 | margin-bottom: 80px;
22 | }
23 | .article-main{
24 | width: 100%;
25 | margin: 0 auto;
26 | display: flex;
27 |
28 | }
29 |
30 | .article-area{
31 | width: 820px;
32 | margin-right: 21px;
33 | }
34 | .article{
35 | padding: 32px;
36 | box-sizing: border-box;
37 | background: #fff;
38 | border-radius: 4px;
39 | }
40 | .article>div{
41 | margin-bottom: 20px;
42 | }
43 | .article .article-title{
44 | font-size: 1.9rem;
45 | font-weight: 600;
46 | color: #252933;
47 | word-wrap: break-word;
48 | }
49 | .article .article-info-box{
50 | width: 100%;
51 | height: 48px;
52 | /* background: rgba(0, 0, 0, 0.13); */
53 | display: flex;
54 | align-items: center;
55 | }
56 | .user-photo{
57 | width: 40px;
58 | height: 40px;
59 | border-radius: 50%;
60 | margin-right: 8px;
61 | overflow: hidden;
62 | display: flex;
63 | justify-content: center;
64 | align-items: center;
65 | }
66 | .user-photo img{
67 | height: 100%;
68 | }
69 | .author-info{
70 | flex: 1px;
71 | }
72 | .author-info .author-name{
73 | font-size: 1rem;
74 | font-weight: 500;
75 | color: #515767;
76 | line-height: 2rem;
77 | display: flex;
78 | }
79 | .author-name span{
80 | max-width: 20%;
81 | text-overflow: ellipsis;
82 | overflow: hidden;
83 | white-space: nowrap;
84 | display: block;
85 | margin-right: 5px;
86 | }
87 | .author-name img{
88 | width: 35px;
89 | height: 16px;
90 | }
91 | .author-info .meta-box{
92 | font-size: .9rem;
93 | color: #8a919f;
94 | line-height: 20px;
95 | display: flex;
96 | }
97 | .meta-box span{
98 | margin-right: 15px;
99 | position: relative;
100 | }
101 | .meta-box span:not(:last-child)::after{
102 | content: '·';
103 | position: absolute;
104 | right: -8px;
105 | }
106 | .follow-btn{
107 | width: 70px;
108 | height: 34px;
109 | font-size: 14px;
110 | color: #1e80ff;
111 | background: rgba(30, 128, 255, .05);
112 | border: 1px solid rgba(30, 128, 255, .3);
113 | border-radius: 4px;
114 | }
115 | .article-img{
116 | width: 100%;
117 | height: 425px;
118 | overflow: hidden;
119 | display: flex;
120 | align-items: center;
121 | }
122 | .article-img img{
123 | width: 100%;
124 | }
125 |
126 |
127 | .tag-list-box{
128 | width: 100%;
129 | height: 32px;
130 | display: flex;
131 | /* background: rgba(0, 0, 0, 0.089); */
132 | font-size: .9rem;
133 | line-height: 32px;
134 | color: #515767d8;
135 | }
136 | .tag-list-box .list{
137 | margin-right: 20px;
138 | display: flex;
139 | }
140 | .tag-list-box .list>span{
141 | display: block;
142 | color: #1e80ff;
143 | background: #eaf2ff;
144 | padding: 0 12px;
145 | border-radius: 4px;
146 | margin-right: 5px;
147 | }
148 |
149 | .comment{
150 | width: 100%;
151 | /* height: 176px; */
152 | background: #fff;
153 | margin-top: 21px;
154 | border-radius: 4px;
155 | padding: 0px 32px;
156 | box-sizing: border-box;
157 | /* margin-bottom: 60px; */
158 | }
159 | .comment>div{
160 | padding-top: 24px;
161 | }
162 | .comment-form .form-header{
163 | font-size: 18px;
164 | line-height: 30px;
165 | font-weight: 600;
166 | color: #252933;
167 | margin-bottom: 24px;
168 | }
169 | .comment-form .form-content{
170 | display: flex;
171 | /* height: 74px; */
172 | }
173 | .form-userimg{
174 | width: 40px;
175 | height: 40px;
176 | border-radius: 50%;
177 | overflow: hidden;
178 | display: flex;
179 | justify-content: center;
180 | align-items: center;
181 | margin-right: 16px;
182 | }
183 | .form-userimg>img{
184 | height: 100%;
185 | }
186 | .form-box>textarea{
187 | border: none;
188 | background: #f2f3f5;
189 | border-radius: 4px;
190 | padding: 8px 12px;
191 | box-sizing: border-box;
192 | color: #252933;
193 | line-height: 22px;
194 | font-size: 14px;
195 | }
196 | .form-box>textarea:focus-within{
197 | outline: 1px solid var(--juejin-brand-1-normal);
198 | }
199 | .form-box:focus-within .action-box{
200 | display: flex;
201 | }
202 | .action-box{
203 | height: 36px;
204 |
205 | align-items: center;
206 | margin-top: 8px;
207 | font-size: 13px;
208 | color: #515767;
209 | /* display: flex; */
210 | display: none;
211 | }
212 |
213 | .image-btn{
214 | margin-left: 24px;
215 | }
216 | .submit-box{
217 | flex: 1;
218 | display: flex;
219 | justify-content: flex-end;
220 | font-size: 14px;
221 | color: #86909c;
222 | line-height: 36px;
223 | }
224 | .submit-box .submit{
225 | width: 92px;
226 | height: 36px;
227 | border: none;
228 | font-size: 14px;
229 | color: #fff;
230 | background: #1e80ff;
231 | border-radius: 4px;
232 | margin-left: 16px;
233 | }
234 | .hot-list{
235 | /* height: 600px; */
236 | }
237 | .title{
238 | font-size: 18px;
239 | line-height: 30px;
240 | font-weight: 600;
241 | color: #252933;
242 | margin-bottom: 24px;
243 | display: flex;
244 | align-items: center;
245 | }
246 | .title>img{
247 | width: 20px;
248 | height: 20px;
249 | }
250 |
251 |
252 | /* 一条评论的样式 开始 */
253 | .comment-item{
254 | width: 100%;
255 | display: flex;
256 | padding: 16px 0px;
257 | }
258 | .comment-userImg .userImg{
259 | width: 40px;
260 | height: 40px;
261 | border-radius: 50%;
262 | overflow: hidden;
263 | display: flex;
264 | justify-content: center;
265 | align-items: center;
266 | }
267 | .comment-userImg .userImg>img{
268 | height: 100%;
269 | }
270 | .comment-content{
271 | flex: 1;
272 | margin-left: 16px;
273 | }
274 | .comment-main>div{
275 | margin-bottom: 8px;
276 | }
277 | .user-box span:not(:last-child){
278 | margin-right: 7px;
279 | }
280 | .user-box{
281 | width: 100%;
282 | height: 26px;
283 | display: flex;
284 | align-items: center;
285 | }
286 | .user-box .name{
287 | max-width: 128px;
288 | font-size: 15px;
289 | color: #252933;
290 | line-height: 26px;
291 |
292 | text-overflow: ellipsis;
293 | overflow: hidden;
294 | white-space: nowrap;
295 | }
296 | .user-box .level{
297 | width: 45px;
298 | height: 16px;
299 | }
300 | .user-box .jueyou-level{
301 | width: 45px;
302 | height: 16px;
303 | }
304 | .user-box img{
305 | width: 45px;
306 | height: 16px;
307 | }
308 | .user-box .position{
309 | max-width: 150px;
310 | font-size: 14px;
311 | color: #8a919f;
312 |
313 | text-overflow: ellipsis;
314 | overflow: hidden;
315 | white-space: nowrap;
316 |
317 | margin-left: 10px;
318 | }
319 | .user-box .time{
320 | flex: 1;
321 | font-size: 14px;
322 | color: #8a919f;
323 | text-align: right;
324 | }
325 | .content-main{
326 | font-size: 14px;
327 | line-height: 24px;
328 | color: #515767;
329 | }
330 | .comment-action-box{
331 | display: flex;
332 | font-size: 14px;
333 | color: #8a919f;
334 | }
335 | .comment-action-box div{
336 | display: flex;
337 | align-items: center;
338 | margin-right: 15px;
339 | }
340 | .comment-action-box img{
341 | width: 16px;
342 | height: 16px;
343 | margin-right: 5px;
344 | }
345 | /* 一条评论的样式 结束 */
346 |
347 |
348 |
349 |
350 | /* 侧边栏 开始 */
351 | .sidebar{
352 | position: absolute;
353 | top: 0;
354 | right: 0;
355 | width: 300px;
356 | height: 600px;
357 | flex: 1;
358 | /* background: rgba(146, 231, 77, 0.63); */
359 | /* background: #fff; */
360 |
361 | }
362 | .sidebar>div{
363 | /* width: 100%; */
364 | /* padding: 20px; */
365 | margin-bottom: 20px;
366 | box-sizing: border-box;
367 | border-radius: 4px;
368 | background: #fff;
369 | }
370 |
371 | /* 作者信息栏 */
372 | .author-block{
373 | /* background: #fff; */
374 | padding: 20px;
375 | }
376 | .user-item{
377 | display: flex;
378 | padding-bottom: 17px;
379 | position: relative;
380 | }
381 | .userimg{
382 | width: 48px;
383 | height: 48px;
384 | border-radius: 50%;
385 | overflow: hidden;
386 | display: flex;
387 | justify-content: center;
388 | align-items: center;
389 | }
390 | .userimg>img{
391 | height: 48px;
392 | /* margin-left: 5px; */
393 | }
394 | .info-box{
395 | margin-left: 16px;
396 | }
397 | .info-box>div{
398 | max-width: 196px;
399 | height: 24px;
400 | font-size: 16px;
401 | font-weight: 400;
402 | overflow: hidden;
403 | text-overflow: ellipsis;
404 | white-space: nowrap;
405 | }
406 | .info-box .userName{
407 | color: #252933;
408 | display: flex;
409 | align-items: center;
410 | }
411 | .userName>span{
412 | max-width: 155px;
413 | overflow: hidden;
414 | text-overflow: ellipsis;
415 | white-space: nowrap;
416 | }
417 | .userName>img{
418 | width: 35px;
419 | height: 16px;
420 | }
421 | .info-box .position{
422 | color: #515767;
423 | }
424 |
425 | .stat-item{
426 | margin-top: 17px;
427 | display: flex;
428 | font-size: 15px;
429 | line-height: 25px;
430 | color: #252933;
431 | }
432 | .stat-item>div{
433 | width: 25px;
434 | height: 25px;
435 | border-radius: 50%;
436 | background: #e1efff;
437 | margin-right: 12px;
438 | display: flex;
439 | justify-content: center;
440 | align-items: center;
441 | }
442 | .stat-item img{
443 | width: 16px;
444 | height: 16px;
445 | }
446 | .user-item::after{
447 | content: '';
448 | position: absolute;
449 | bottom: 0;
450 | width: 100%;
451 | height: 1px;
452 | background: rgba(0, 0, 0, 0.178);
453 | transform: scaleY(.5);
454 | }
455 |
456 |
457 | /* 文章目录 */
458 | ul{
459 | list-style: none;
460 | }
461 | a{
462 | text-decoration: none;
463 | color: #515767;
464 | }
465 | .sticky-block-box{
466 | width: 300px;
467 | position: relative;
468 | /* margin-top: 5px; */
469 | }
470 | .activeBox{
471 | transition: all .3s linear;
472 | }
473 | .stickyBoxStatus{
474 | position: fixed;
475 | top: 20px;
476 | }
477 | .sticky-title{
478 | position: relative;
479 | margin: 0 20px;
480 | padding: 16px 0;
481 | }
482 | .sticky-title::after{
483 | content: '';
484 | position: absolute;
485 | bottom: 0px;
486 | left: 0px;
487 | width: 100%;
488 | height: 1px;
489 | background: rgba(0, 0, 0, 0.178);
490 | transform: scaleY(.5);
491 | }
492 | .sticky-content{
493 | width: 100%;
494 | max-height: 460px;
495 | overflow-y: scroll;
496 | padding: 20px 5px;
497 | box-sizing: border-box;
498 | }
499 |
500 | /* 目录滑动条样式 */
501 | .sticky-content::-webkit-scrollbar{
502 | width: 6px;
503 | }
504 | .sticky-content::-webkit-scrollbar-thumb{
505 | border-radius: 10px;
506 | background: #c2c8d19b;
507 | margin-left: 10px;
508 | }
509 |
510 | .sticky-list{
511 | width: 100%;
512 | padding-left: 20px;
513 | box-sizing: border-box;
514 | position: relative;
515 | color: #515767;
516 | }
517 | .a-container{
518 | height: 44px;
519 | border-radius: 4px;
520 | font-size: 14px;
521 | /* color: #515767; */
522 | line-height: 44px;
523 | padding-left: 5px;
524 | box-sizing: border-box;
525 |
526 | text-overflow: ellipsis;
527 | overflow: hidden;
528 | white-space: nowrap;
529 |
530 | }
531 | .a-container:hover{
532 | background: #f7f8fa;
533 | }
534 |
535 | .first{
536 | color: #1e80ff;
537 | }
538 | .first::after{
539 | content: '';
540 | /* border-left: 2 #1e80ff; */
541 | position: absolute;
542 | margin-top: -32px;
543 | /* top: 13px; */
544 | left: 0;
545 | width: 5px;
546 | height: 18px;
547 | background: #1e80ff;
548 | border-radius: 3px;
549 | margin-left: 5px;
550 | }
551 | /* 侧边栏 结束 */
552 |
553 | /* 左侧功能栏 */
554 | .article-suspended-panel{
555 | width: 48px;
556 | height: 300px;
557 | /* background: rgba(0, 0, 0, 0.157); */
558 | position: fixed;
559 | top: 140px;
560 | left: 100px;
561 | }
562 | .panel-btn{
563 | width: 100%;
564 | height: 48px;
565 | border-radius: 50%;
566 | background: #fff;
567 | margin-bottom: 20px;
568 | box-shadow: 1px 1px 20px #dadddd;
569 |
570 | display: flex;
571 | justify-content: center;
572 | align-items: center;
573 | position: relative;
574 |
575 | }
576 | .panel-btn>img{
577 | width: 17px;
578 | height: 17px;
579 | }
580 | .panel-btn:nth-child(4){
581 | margin-bottom: 40px;
582 | position: relative;
583 | }
584 | .panel-btn:nth-child(4)::after{
585 | content: '';
586 | position: absolute;
587 | bottom: -20px;
588 | width: 30px;
589 | height: 1px;
590 | background: rgba(0, 0, 0, 0.157);
591 | transform: scaleY(.5);
592 | }
593 |
594 | .btn-num{
595 | position: absolute;
596 | top: 0;
597 | left: 75%;
598 | height: 17px;
599 | line-height: 17px;
600 | padding: 0 5px;
601 | border-radius: 9px;
602 | font-size: 11px;
603 | text-align: center;
604 | white-space: nowrap;
605 | background-color: #c2c8d1;
606 | color: #fff;
607 | }
608 |
--------------------------------------------------------------------------------
/juejin-app/src/assets/css/header.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | background-color: #f4f5f5;
4 | }
5 |
6 | a {
7 | text-decoration: none;
8 | color: var(--juejin-font-3);
9 | }
10 | a:visited {
11 | color: #86909c;
12 | }
13 |
14 | ul {
15 | list-style: none;
16 | }
17 |
18 | .list__contents a:hover {
19 | color: var(--juejin-font-1);
20 | }
21 | .juejin__page {
22 | width: 100%;
23 | height: 100%;
24 | }
25 |
26 | /* 导航栏部分 */
27 | .page__header {
28 | width: 100%;
29 | height: 106px;
30 | position: fixed;
31 | top: 0;
32 |
33 | z-index: 5;
34 | }
35 | .page__header__box{
36 | width: 100%;
37 | height: 106px;
38 | position: relative;
39 | top: 0px;
40 | }
41 | .activeBox{
42 | transition: all .3s linear;
43 | }
44 |
45 | .page__header__nav {
46 | width: 100%;
47 | height: 60px;
48 | display: flex;
49 | justify-content: center;
50 | position: relative;
51 | top: 0px;
52 | background: rgb(255, 255, 255);
53 | }
54 |
55 | .page__header__nav::after {
56 | content: '';
57 | position: absolute;
58 | bottom: 0;
59 | width: 100%;
60 | height: 1px;
61 | background-color: var(--juejin-font-4);
62 | transform: scaleY(0.5);
63 | }
64 |
65 | /* 标签页面 */
66 | .page__header__tag{
67 | width: 100%;
68 | height: 46px;
69 | background: #fff;
70 | position: relative;
71 | top: 0;
72 | z-index: 3;
73 | }
74 | .page__header__tag::after {
75 | content: '';
76 | position: absolute;
77 | bottom: 0;
78 | width: 100%;
79 | height: 1px;
80 | background-color: var(--juejin-font-4);
81 | transform: scaleY(0.5);
82 | }
83 | .tag__contents{
84 | height: 100%;
85 | /* background: rgba(239, 24, 24, 0.199); */
86 | width: 960px;
87 | margin: 0 auto;
88 | display: flex;
89 | justify-content: space-between;
90 | /* overflow-x: scroll; */
91 | }
92 | .tag__list{
93 | display: flex;
94 | height: 100%;
95 | }
96 | .tag__manage{
97 | display: flex;
98 | align-items: center;
99 | }
100 | .tag__manage > span{
101 | font-size: .9rem;
102 | color: var(--juejin-font-2);
103 | }
104 | .page__header__tag a:hover{
105 | color: var(--juejin-brand-1-normal);
106 | }
107 | .tag__list .list__contents{
108 | margin-left: 0;
109 | }
110 | .tag__list li:nth-child(1){
111 | margin-left: 0;
112 | }
113 |
114 |
115 |
116 | /* 掘金图标 */
117 | .nav__sign {
118 | display: flex;
119 | }
120 |
121 | .logo__img {
122 | width: 107px;
123 | height: 22px;
124 | margin-left: 24px;
125 | margin-top: 20px;
126 | }
127 |
128 | /* 导航按钮 */
129 | .nav__main-list {
130 | height: 100%;
131 | display: flex;
132 | }
133 |
134 | .list-left {
135 | width: 37vw;
136 | }
137 |
138 | .list-left,
139 | .list-right {
140 | display: flex;
141 | }
142 |
143 | .list__contents {
144 | height: 100%;
145 | display: flex;
146 | margin-left: 10px;
147 | }
148 |
149 | .list__contents>li {
150 | display: flex;
151 | font-size: .9rem;
152 | align-items: center;
153 | margin: 0 .65rem;
154 | }
155 |
156 | .list__contents li a {
157 | display: inline-block;
158 | }
159 |
160 | /* 开放社区下拉框 */
161 | li>.community::after {
162 | content: '';
163 | /* 注意这里的伪类要为块级元素才能旋转 */
164 | display: inline-block;
165 | width: 0px;
166 | height: 0px;
167 | border: 4px solid #515761;
168 | border-left-color: transparent;
169 | border-right-color: transparent;
170 | border-bottom-color: transparent;
171 | position: relative;
172 | left: 2px;
173 | transform-origin: 50% 25%;
174 | transition: transform .5s ease-in-out;
175 | }
176 |
177 | .list__contents>li:nth-child(7):hover .community {
178 | color: var(--juejin-brand-1-normal);
179 | }
180 |
181 | .list__contents>li:nth-child(7):hover .community::after {
182 | border: 4px solid var(--juejin-brand-1-normal);
183 | border-left-color: transparent;
184 | border-right-color: transparent;
185 | border-bottom-color: transparent;
186 | transform: rotate(-180deg);
187 | }
188 |
189 | .list__contents>li:nth-child(7):hover .community__list {
190 | display: block;
191 | }
192 | .community__list{
193 | display: none;
194 | position: absolute;
195 | /* width: 200px; */
196 | padding: 5px;
197 | background: #fff;
198 | border-radius: 5px;
199 | box-shadow: 4px 0 70px #8a919f2f, -4px 0 70px #8a919f25, 0 4px 70px #8a919f3c;
200 | top: 52px;
201 | z-index: 10;
202 | }
203 | .community__list li {
204 | display: inline-block;
205 | /* width: 90px; */
206 | height: 26px;
207 | color: var(--juejin-font-2);
208 | line-height: 26px;
209 | padding: 6px 20px 5px 9px;
210 | }
211 |
212 | .community__list li:hover {
213 | background-color: #f2f3f5;
214 | border-radius: 3px;
215 | }
216 |
217 | .community__list span::before {
218 | content: '';
219 | display: inline-block;
220 | position: relative;
221 | top: 4px;
222 | width: 18px;
223 | height: 18px;
224 | margin: 0 12px 0 2px;
225 | }
226 |
227 | .community__list li:nth-child(1) span::before {
228 | background-image: url('../img/comm.png');
229 | background-size: 18px 18px;
230 | }
231 |
232 |
233 | /* 搜索框 */
234 | .input__frame{
235 | height: 36px;
236 | border: 1px solid #86909ccf;
237 | border-radius: 3px;
238 | display: flex;
239 | align-items: center;
240 | }
241 |
242 | .input:focus{
243 | outline: none;
244 | border-radius: 3px;
245 | }
246 | .input__frame:focus-within{
247 | /* width: 400px; */
248 | transform-origin: 0 0;
249 | /* transform: scaleX(1.32); */
250 | outline: 1px solid var(--juejin-brand-1-normal);
251 | }
252 | .input__frame:focus-within .input__sign{
253 | background: var(--juejin-brand-5-light);
254 | }
255 | .input__frame:focus-within .input__typehead{
256 | display: block;
257 | }
258 |
259 | .input__frame .input {
260 | flex: 1;
261 | width: 316px;
262 | height: 12px;
263 | border: none;
264 | padding: 12px 7px;
265 | -webkit-text-fill-color: var(--juejin-font-3);
266 | }
267 |
268 | .input__frame .input__sign {
269 | width: 44px;
270 | height: 30px;
271 | background: #86909c23;
272 | border-radius: 3px;
273 | margin-right: 3px;
274 | /* margin-left: 140px; */
275 | }
276 |
277 | .input__sign .input__img{
278 | width: 16px;
279 | height: 16px;
280 | background-image: url('../img/input.png');
281 | background-size: 16px 16px;
282 | margin: 7px 15px;
283 | }
284 | .input__frame .input__typehead{
285 | display: none;
286 | position: absolute;
287 | top: 52px;
288 | width: auto;
289 | background: #fff;
290 | border: 1px solid #5157613d;
291 | border-radius: 2px;
292 | z-index: 10;
293 | font-size: .8rem;
294 | color: var(--juejin-font-3);
295 | }
296 | .input__typehead .title{
297 | width: 100%;
298 | display: flex;
299 | justify-content: space-between;
300 | position: relative;
301 | }
302 | .input__typehead>.title::after{
303 | content: '';
304 | position: absolute;
305 | width: 100%;
306 | height: 1px;
307 | bottom: 0;
308 | background-color: var(--juejin-font-4);
309 | transform: scaleY(.5);
310 | }
311 | .title>span{
312 | display: inline-block;
313 | margin: 10px;
314 | }
315 | .input__typehead .list .list-item{
316 | width: 342px;
317 | display: flex;
318 | padding: 10px;
319 | }
320 | .list-item:hover{
321 | background-color: #eff2f5;
322 | }
323 |
324 |
325 | /* 创作者中心 */
326 | .creator {
327 | /* width: 115px; */
328 | height: 36px;
329 | display: flex;
330 | }
331 |
332 | .creator .crea-btn {
333 | width: 80px;
334 | height: 100%;
335 | font-size: .8rem;
336 | color: #fff;
337 | background-color: var(--juejin-brand-1-normal);
338 | border: none;
339 | border-radius: 3px 0 0 3px;
340 | position: relative;
341 | }
342 |
343 | .crea-btn::after {
344 | content: '';
345 | position: absolute;
346 | top: 0;
347 | right: 0;
348 | width: 1px;
349 | height: 36px;
350 | background-color: var(--juejin-brand-4-disable);
351 | transform: scaleX(0.3);
352 | }
353 |
354 | .creator .more {
355 | width: 20px;
356 | height: 100%;
357 | background-color: var(--juejin-brand-1-normal);
358 | border-radius: 0 3px 3px 0;
359 | }
360 |
361 | .more:hover,
362 | .crea-btn:hover {
363 | background-color: var(--juejin-brand-2-hover);
364 | }
365 |
366 | #dianj {
367 | display: none;
368 | }
369 |
370 | input:checked~ul {
371 | display: block;
372 | }
373 |
374 | input:checked~label .more__tri {
375 | transform-origin: 55% 75%;
376 | transform: rotateZ(225deg);
377 | }
378 |
379 | .more__tri {
380 | width: 0px;
381 | height: 0px;
382 | border: 4px solid #fff;
383 | border-left-color: transparent;
384 | border-top-color: transparent;
385 | transform: rotateZ(45deg);
386 | position: relative;
387 | top: 12px;
388 | left: 6px;
389 | }
390 |
391 | .more__list {
392 | display: none;
393 | position: absolute;
394 | width: 100px;
395 | padding: 5px;
396 | background: #fff;
397 | border-radius: 5px;
398 | box-shadow: 4px 0 70px #8a919f2f, -4px 0 70px #8a919f25, 0 4px 70px #8a919f3c;
399 | top: 52px;
400 | z-index: 10;
401 | }
402 |
403 | .more__list li {
404 | display: inline-block;
405 | width: 90px;
406 | height: 26px;
407 | color: var(--juejin-font-2);
408 | line-height: 26px;
409 | padding: 6px 1px 5px 9px;
410 | }
411 |
412 | .more__list li:hover {
413 | background-color: #f2f3f5;
414 | border-radius: 3px;
415 | }
416 |
417 | .more__list span::before {
418 | content: '';
419 | display: inline-block;
420 | position: relative;
421 | top: 2px;
422 | width: 18px;
423 | height: 18px;
424 | margin: 0 12px 0 2px;
425 | }
426 |
427 | .more__list li:nth-child(1) span::before {
428 | background-image: url('../img/pencil.png');
429 | background-size: 18px 18px;
430 | }
431 |
432 | .more__list li:nth-child(2) span::before {
433 | background-image: url('../img/dia.png');
434 | background-size: 18px 18px;
435 | }
436 |
437 |
438 |
439 | /* 会员 */
440 | .vip__title {
441 | height: 100%;
442 | display: flex;
443 | align-items: center;
444 | color: var(--juejin-font-3);
445 | }
446 |
447 | .vip__title .vip__img {
448 | width: 24px;
449 | height: 24px;
450 | margin-right: 5px;
451 | }
452 |
453 | /* 通知 */
454 | .inform {
455 | height: 100%;
456 | display: flex;
457 | align-items: center;
458 | }
459 |
460 | .inform__img {
461 | width: 24px;
462 | height: 24px;
463 | background-image: url('../img/inform-logo-off.png');
464 | background-size: 24px 24px;
465 | }
466 |
467 | .inform__img:hover {
468 | background-image: url('../img/inform-logo-on.png');
469 | }
470 |
471 | /* 用户头像 */
472 | .user {
473 | height: 100%;
474 | display: flex;
475 | align-items: center;
476 | }
477 |
478 | .user__img {
479 | width: 36px;
480 | /* transform: scale(1); */
481 | height: 36px;
482 | object-fit: cover;
483 | border-radius: 50%;
484 | }
485 |
486 |
487 | /* 一键回到顶部 */
488 | .page__header__side{
489 | width: 38px;
490 | height: 38px;
491 | background: #fff;
492 | border-radius: 50%;
493 | position: fixed;
494 | bottom: 50px;
495 | right: 50px;
496 | box-shadow: 1px 1px 10px #5157673f;
497 | }
498 | .page__header__side:hover{
499 | box-shadow: 2px 2px 10px #515767;
500 | }
501 | .backTop{
502 | width: 100%;
503 | height: 100%;
504 | display: flex;
505 |
506 | justify-content: center;
507 | align-items: center;
508 | }
509 | .backTop img{
510 | width: 12px;
511 | height: 18px;
512 | margin-top: 4px;
513 | }
514 |
--------------------------------------------------------------------------------
/juejin-app/src/assets/css/main.css:
--------------------------------------------------------------------------------
1 |
2 | .page__main{
3 | width: 98.93vw;
4 | }
5 | .page__main__contents{
6 | /* position: absolute; */
7 | width: 960px;
8 | margin: 0 auto;
9 | /* background: rgba(50, 241, 16, 0.215); */
10 | margin-top: 130px;
11 | position: relative;
12 | }
13 | .contents__list{
14 | width: 700px;
15 | /* height: 100%; */
16 | /* background: rgba(17, 0, 255, 0.142); */
17 | margin-right: 260px;
18 | }
19 | .list__header{
20 | width: 676px;
21 | /* height: 47px; */
22 | background: #fff;
23 | padding: 17px 12px;
24 | position: relative;
25 | }
26 | .list__content{
27 | width: 100%;
28 | /* height: 100vh;
29 | overflow: scroll; */
30 | background: #fff;
31 | }
32 | .article__list{
33 | width: 100%;
34 | }
35 | .list__item{
36 | /* width: 660px;
37 | height: 129px; */
38 | padding: 12px 20px 0 20px;
39 | position: relative;
40 | }
41 | .list__item:hover{
42 | background: #fafafa;
43 | }
44 | .list__header::after{
45 | content: '';
46 | position: absolute;
47 | bottom: 0;
48 | left: 0;
49 | width: 100%;
50 | height: 1px;
51 | background: var(--juejin-font-4);
52 | transform: scaleY(.5);
53 | }
54 | .list__item::after{
55 | content: '';
56 | position: absolute;
57 | bottom: 0;
58 | left: 21px;
59 | width: 94%;
60 | height: 1px;
61 | background: var(--juejin-font-4);
62 | transform: scaleY(.5);
63 | }
64 |
65 | /* 内容头部标签 */
66 | .nav__list{
67 | display: flex;
68 | height: 19px;
69 | }
70 | .nav__list>ul{
71 | display: flex;
72 | }
73 | .nav__list li{
74 | font-size: .9rem;
75 | margin: 0 13px;
76 | position: relative;
77 | }
78 | .nav__list li:not(:last-child)::after{
79 | content: '';
80 | position: absolute;
81 | right: -13px;
82 | top: -5px;
83 | width: 1px;
84 | height: 155%;
85 | background: var(--juejin-font-4);
86 | transform: scaleY(.5);
87 | }
88 |
89 | .tag__a{
90 | display: flex;
91 | }
92 | .tag__name{
93 | position: relative;
94 | margin-right: 16px;
95 | }
96 | .tag__name:not(:last-child)::after{
97 | content: '·';
98 | position: absolute;
99 | right: -8px;
100 | top: 0px;
101 | transform: scale(2);
102 | color: #4e59699a;
103 | }
104 |
105 | .nav__list a:hover{
106 | color: var(--juejin-brand-1-normal);
107 | }
108 |
109 |
110 | /* 文章列表 */
111 | .list__item>.entry{
112 | display: flex;
113 | width: 100%;
114 | height: 100%;
115 | flex-wrap: wrap;
116 | margin: 5px 0;
117 | }
118 | .article__inform{
119 | width: 100%;
120 | height: 22px;
121 | display: flex;
122 | }
123 | .article__content{
124 | width: 100%;
125 | height: 97px;
126 | display: flex;
127 | }
128 | .article__inform>.nav__list li{
129 | font-size: .7rem;
130 | }
131 | .article__inform>.nav__list li:nth-child(1){
132 | margin-left: 0;
133 | }
134 |
135 | .content-main{
136 | width: 200px;
137 | flex: 1 0 auto;
138 | }
139 |
140 | .content-main .title{
141 | font-size: .98rem;
142 |
143 | font-weight: bold;
144 | margin: 8px 0 12px 0;
145 | text-overflow: ellipsis;
146 | overflow: hidden;
147 | white-space: nowrap;
148 | }
149 | .titleColor{
150 | color: #000;
151 | }
152 |
153 | .content-main .abstract{
154 | /* width: 100px; */
155 | font-size: .82rem;
156 | margin-bottom: 10px;
157 | text-overflow: ellipsis;
158 | -webkit-box-orient: vertical;
159 | /* -webkit-line-clamp: 1 */
160 | overflow: hidden;
161 | white-space: nowrap;
162 | }
163 | .action-list{
164 | display: flex;
165 | font-size: 0.8em;
166 | color: var(--juejin-font-2);
167 |
168 | }
169 | .action-list .item{
170 | display: inline-block;
171 | margin-right: 20px;
172 | display: flex;
173 | }
174 | .action-list>li>i{
175 | display: block;
176 | width: 16px;
177 | height: 16px;
178 | background-size: 16px 16px;
179 | margin-right: 4px;
180 | }
181 | .action-list .eye{
182 | background-image: url("../img/eye.png");
183 | }
184 | .action-list .zan{
185 | background-image: url("../img/zan__off.png");
186 | }
187 | .action-list .cloud{
188 | margin-top: 2px;
189 | background-image: url("../img/cloud__off.png");
190 | }
191 | .action-list .zan:hover{
192 | background-image: url("../img/zan__on.png");
193 | }
194 | .action-list .cloud:hover{
195 | /* margin-top: 2px; */
196 | background-image: url("../img/cloud__on.png");
197 | }
198 | .content-img{
199 | width: 120px;
200 | height: 80px;
201 | margin-left: 24px;
202 | flex: 0 0 auto;
203 | border-radius: 2px;
204 | overflow: hidden;
205 | display: flex;
206 | align-items: center;
207 | }
208 | .article__content img{
209 | display: block;
210 | /* transform: translate(0,-50%); */
211 | width: 120px;
212 | /* height: 160px; */
213 | /* margin-left: 24px;
214 | flex: 0 0 auto; */
215 | border-radius: 2px;
216 | transform: scale(1.2);
217 | }
218 |
219 | .sidebar{
220 | width: 240px;
221 | position: absolute;
222 | top: 0;
223 | right: 0;
224 | }
225 | .sidebar>div{
226 | margin-bottom: 16px;
227 | border-radius: 3px;
228 | }
229 | .signin__top{
230 | width: 100%;
231 | height: 96px;
232 | padding: 16px;
233 | box-sizing: border-box;
234 | background: #fff;
235 | display: flex;
236 | flex-direction: column;
237 | justify-content: space-between;
238 | }
239 | .first__line{
240 | display: flex;
241 | justify-content: space-between;
242 |
243 | }
244 | .icon__text{
245 | display: flex;
246 | align-items: center;
247 | font-size: 18px;
248 | font-weight: 500;
249 | }
250 | .icon__text>img{
251 | width: 20px;
252 | height: 20px;
253 | margin-right: 10px;
254 | }
255 | .signedin__btn{
256 | width: 72px;
257 | height: 32px;
258 | border: none;
259 | border-radius: 20px;
260 | font-size: 14px;
261 | color: #1e80ff;
262 | background: #e8f3ff;
263 |
264 | }
265 | .second__line{
266 | font-size: 14px;
267 | display: flex;
268 | justify-content: center;
269 | color: #86909c;
270 | }
271 |
272 |
273 |
274 | .sidebar__block{
275 | width: 100%;
276 | /* height: 200px; */
277 | overflow: hidden;
278 | position: relative;
279 | background: #fff;
280 | }
281 | .sidebar__block>img{
282 | width: 100%;
283 | }
284 | .sidebar__block:not(:last-child)::after{
285 | content: '广告';
286 | position: absolute;
287 | bottom: 10px;
288 | right: 10px;
289 | width: 36px;
290 | height: 19px;
291 | background: rgba(0, 0, 0, 0.151);
292 | border: 1px solid rgb(199, 199, 199);
293 | border-radius: 3px;
294 |
295 | font-size: 8px;
296 | color: #fff;
297 | text-align: center;
298 | line-height: 19px;
299 | }
300 | .block-body{
301 | width: 100%;
302 | padding: 16px;
303 | box-sizing: border-box;
304 | background: #fff;
305 | display: flex;
306 | }
307 | .block-body>img{
308 | width: 50px;
309 | height: 50px;
310 | margin-right: 12px;
311 | }
312 | .block-body-text{
313 | display: flex;
314 | flex-direction: column;
315 | justify-content: space-between;
316 | }
317 | .block-body-text>:first-child{
318 | font-size: 14px;
319 | }
320 | .block-body-text>:last-child{
321 | font-size: 12px;
322 | line-height: 20px;
323 | color: #86909c;
324 | }
325 | .header-block{
326 | padding: 12px 15.6px;
327 | box-sizing: border-box;
328 | font-size: 14px;
329 | color: #333333;
330 | }
331 | .author-list{
332 | font-size: 14px;
333 | color: #007fff;
334 | text-align: center;
335 | padding: 12px 0;
336 | }
337 |
338 | .user-top>div{
339 | position: relative;
340 | }
341 | .user-top>div:not(:last-child)::after{
342 | content: '';
343 | position: absolute;
344 | bottom: 0;
345 | left: 0;
346 | width: 100%;
347 | height: 1px;
348 | background: #e8f3ff;
349 | }
350 | .user-list>.item{
351 | padding: 12px 15.6px;
352 | box-sizing: border-box;
353 | display: flex;
354 | }
355 | .item__img-box{
356 | width: 45.6px;
357 | height: 45.6px;
358 | border-radius: 50%;
359 | overflow: hidden;
360 | display: flex;
361 | align-items: center;
362 | justify-content: center;
363 | margin-right: 6px;
364 | }
365 | .item__img-box>img{
366 | width: 100%;
367 | }
368 | .item__user-info{
369 | height: 100%;
370 | font-size: 14px;
371 | color: #333333;
372 | line-height: 45.6px;
373 | display: flex;
374 | align-items: center;
375 | }
376 | .item__user-info>img{
377 | width: 35px;
378 | height: 16px;
379 | margin-left: 6px;
380 | }
381 | .user-body{
382 | background: #fff;
383 | }
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/article__01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/article__01.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/cloud__off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/cloud__off.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/cloud__on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/cloud__on.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/comm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/comm.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/day.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/day.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/dia.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/dia.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/eye.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/eye.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/fire.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/fire.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/inform-logo-off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/inform-logo-off.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/inform-logo-on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/inform-logo-on.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/input-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/input-1.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/input.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/input.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/juejin-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/juejin-logo.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/juejinVip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/juejinVip.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/jy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/jy.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/lv-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/lv-2.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/panelFa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/panelFa.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/panelLiu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/panelLiu.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/panelQuan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/panelQuan.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/panelStar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/panelStar.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/panelZan__off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/panelZan__off.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/panelZan__on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/panelZan__on.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/paneljing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/paneljing.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/pencil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/pencil.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/ping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/ping.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/top.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/user-top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/user-top.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/user.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/userEye.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/userEye.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/userZan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/userZan.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/zan__off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/zan__off.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/img/zan__on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-app/src/assets/img/zan__on.png
--------------------------------------------------------------------------------
/juejin-app/src/assets/js/EventBus.js:
--------------------------------------------------------------------------------
1 | import Vue from './vue'
2 | export default new Vue()
--------------------------------------------------------------------------------
/juejin-app/src/components/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
137 |
138 |
139 |
240 |
241 |
--------------------------------------------------------------------------------
/juejin-app/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import ElementUI from 'element-ui';
3 | import 'element-ui/lib/theme-chalk/index.css';
4 | import App from './App.vue'
5 | // 引入路由器
6 | import router from './router'
7 | // 设置标题
8 | import VueWechatTitle from 'vue-wechat-title'
9 |
10 | Vue.use(ElementUI);
11 | Vue.use(VueWechatTitle)
12 | Vue.config.productionTip = false
13 |
14 | new Vue({
15 | render: h => h(App),
16 | router,
17 | }).$mount('#app')
18 |
--------------------------------------------------------------------------------
/juejin-app/src/pages/Index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
39 |
40 |
41 |
{{article.title}}
42 |
43 |
44 |
{{article.briefContent}}
45 |
46 |
47 |
48 |
49 | {{article.viewCount}}
50 |
51 |
52 |
53 | {{article.diggCount}}
54 |
55 |
56 |
57 | {{article.commentCount}}
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
198 |
199 |
200 |
201 |
202 |
348 |
349 |
--------------------------------------------------------------------------------
/juejin-app/src/router/index.js:
--------------------------------------------------------------------------------
1 | // 路由配置
2 | import VueRouter from "vue-router";
3 | import Vue from "vue";
4 |
5 | Vue.use(VueRouter);
6 |
7 | export default new VueRouter({
8 | routes: [{
9 | path: "/",
10 | component: () => import("../pages/Index"),
11 | meta: {
12 | title: '掘金'
13 | }
14 | }, {
15 | path: "/detail/:articleId",
16 | component: () => import("../pages/Detail"),
17 | meta: {
18 | title: '文章详情'
19 | }
20 | }]
21 | });
--------------------------------------------------------------------------------
/juejin-app/src/utils/request.js:
--------------------------------------------------------------------------------
1 | import axios from "axios"
2 |
3 | const service = axios.create({
4 | baseURL: 'http://106.14.212.78:9088',
5 | timeout: 18000
6 | })
7 |
8 | export default service
--------------------------------------------------------------------------------
/juejin-app/src/utils/timeDispose.js:
--------------------------------------------------------------------------------
1 | // 时间戳转为距今多久
2 | let timeInterval = function(dateTime){
3 | // 如果为null,则格式化当前时间
4 | if (!dateTime) dateTime = Number(new Date());
5 | // 如果dateTime长度为10或者13,则为秒和毫秒的时间戳,如果超过13位,则为其他的时间格式
6 | if (dateTime.toString().length == 10) dateTime *= 1000;
7 | let timestamp = +new Date(Number(dateTime));
8 |
9 | let timer = (Number(new Date()) - timestamp) / 1000;
10 | // 如果小于5分钟,则返回"刚刚",其他以此类推
11 | let tips = '';
12 | switch (true) {
13 | case timer < 300:
14 | tips = '刚刚';
15 | break;
16 | case timer >= 300 && timer < 3600:
17 | tips = parseInt(timer / 60) + '分钟前';
18 | break;
19 | case timer >= 3600 && timer < 86400:
20 | tips = parseInt(timer / 3600) + '小时前';
21 | break;
22 | case timer >= 86400 && timer < 2592000:
23 | tips = parseInt(timer / 86400) + '天前';
24 | break;
25 | default:
26 | if (timer >= 2592000 && timer < 365 * 86400) {
27 | tips = parseInt(timer / (86400 * 30)) + '个月前';
28 | } else {
29 | tips = parseInt(timer / (86400 * 365)) + '年前';
30 | }
31 | }
32 | return tips;
33 | }
34 |
35 | // 显示上午好 下午好 晚上好
36 | let newTime = function(){
37 | let date = new Date();
38 | let h = date.getHours();
39 | if(h < 12 && h>=6){
40 | return '上午好'
41 | }else if(h < 18 && h>=12){
42 | return '下午好'
43 | }else{
44 | return '晚上好'
45 | }
46 | }
47 |
48 | // 格式化文章时间
49 | let setArticleTiem = function(time){
50 | let date = new Date(time);
51 | let Y = date.getFullYear();
52 | let M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1) : date.getMonth()+1);
53 | let D = date.getDate();
54 | let h = date.getHours() + ':';
55 | let m = date.getMinutes();
56 | return `${Y}年${M}月${D}日 ${h}${m}`;
57 | }
58 |
59 | module.exports = {
60 | timeInterval,
61 | setArticleTiem,
62 | newTime
63 | }
--------------------------------------------------------------------------------
/juejin-app/vue.config.js:
--------------------------------------------------------------------------------
1 | const { defineConfig } = require('@vue/cli-service')
2 | module.exports = defineConfig({
3 | transpileDependencies: true,
4 | lintOnSave: false
5 | })
6 |
--------------------------------------------------------------------------------
/juejin-server/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/juejin-server/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IamTrust/juejin/0bad1b791b5e592ae08bf96c9a27be861ff7924a/juejin-server/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/juejin-server/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar
3 |
--------------------------------------------------------------------------------
/juejin-server/jue_jin.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Navicat Premium Data Transfer
3 |
4 | Source Server : aliyun
5 | Source Server Type : MySQL
6 | Source Server Version : 80018
7 | Source Host : rm-wz9mc28o4x3thxw56bo.mysql.rds.aliyuncs.com:3306
8 | Source Schema : jue_jin
9 |
10 | Target Server Type : MySQL
11 | Target Server Version : 80018
12 | File Encoding : 65001
13 |
14 | Date: 26/08/2022 10:26:15
15 | */
16 |
17 | SET NAMES utf8mb4;
18 | SET FOREIGN_KEY_CHECKS = 0;
19 |
20 | -- ----------------------------
21 | -- Table structure for article_content
22 | -- ----------------------------
23 | DROP TABLE IF EXISTS `article_content`;
24 | CREATE TABLE `article_content` (
25 | `article_id` varchar(255) CHARACTER SET utf8 NOT NULL,
26 | `mark_content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
27 | PRIMARY KEY (`article_id`)
28 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
29 |
30 | -- ----------------------------
31 | -- Table structure for article_info
32 | -- ----------------------------
33 | DROP TABLE IF EXISTS `article_info`;
34 | CREATE TABLE `article_info` (
35 | `article_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
36 | `user_id` varchar(255) DEFAULT NULL,
37 | `category_id` varchar(255) DEFAULT NULL,
38 | `tag_ids` varchar(255) DEFAULT NULL,
39 | `visible_level` int(11) DEFAULT NULL,
40 | `link_url` varchar(255) DEFAULT NULL,
41 | `cover_image` varchar(255) DEFAULT NULL,
42 | `is_gfw` smallint(6) DEFAULT NULL,
43 | `title` varchar(255) DEFAULT NULL,
44 | `brief_content` varchar(255) DEFAULT NULL,
45 | `is_english` smallint(6) DEFAULT NULL,
46 | `is_original` smallint(6) DEFAULT NULL,
47 | `user_index` double DEFAULT NULL,
48 | `original_type` smallint(6) DEFAULT NULL,
49 | `original_author` varchar(255) DEFAULT NULL,
50 | `content` varchar(255) DEFAULT NULL,
51 | `ctime` varchar(255) DEFAULT NULL,
52 | `mtime` varchar(255) DEFAULT NULL,
53 | `rtime` varchar(255) DEFAULT NULL,
54 | `draft_id` varchar(255) DEFAULT NULL,
55 | `view_count` int(11) DEFAULT NULL,
56 | `collect_count` int(11) DEFAULT NULL,
57 | `digg_count` int(11) DEFAULT NULL,
58 | `comment_count` int(11) DEFAULT NULL,
59 | `hot_index` int(11) DEFAULT NULL,
60 | `is_hot` smallint(6) DEFAULT NULL,
61 | `rank_index` double DEFAULT NULL,
62 | `status` smallint(6) DEFAULT NULL,
63 | `verify_status` smallint(6) DEFAULT NULL,
64 | `audit_status` smallint(6) DEFAULT NULL,
65 | `mark_content` varchar(255) DEFAULT NULL,
66 | `display_count` smallint(6) DEFAULT NULL,
67 | PRIMARY KEY (`article_id`)
68 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
69 |
70 | -- ----------------------------
71 | -- Table structure for author_user
72 | -- ----------------------------
73 | DROP TABLE IF EXISTS `author_user`;
74 | CREATE TABLE `author_user` (
75 | `user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
76 | `user_name` varchar(255) DEFAULT NULL,
77 | `company` varchar(255) DEFAULT NULL,
78 | `job_title` varchar(255) DEFAULT NULL,
79 | `avatar_large` varchar(255) DEFAULT NULL,
80 | `level` int(11) DEFAULT NULL,
81 | `description` varchar(255) DEFAULT NULL,
82 | `followee_count` int(11) DEFAULT NULL,
83 | `follower_count` int(11) DEFAULT NULL,
84 | `post_article_count` int(11) DEFAULT NULL,
85 | `digg_article_count` int(11) DEFAULT NULL,
86 | `got_digg_count` int(11) DEFAULT NULL,
87 | `got_view_count` int(11) DEFAULT NULL,
88 | `post_shortmsg_count` int(11) DEFAULT NULL,
89 | `digg_shortmsg_count` int(11) DEFAULT NULL,
90 | `isfollowed` varchar(255) DEFAULT NULL,
91 | `favorable_author` int(11) DEFAULT NULL,
92 | `power` int(11) DEFAULT NULL,
93 | `study_point` int(11) DEFAULT NULL,
94 | `university` varchar(255) DEFAULT NULL,
95 | `major` varchar(255) DEFAULT NULL,
96 | `student_status` int(11) DEFAULT NULL,
97 | `select_event_count` int(11) DEFAULT NULL,
98 | `select_online_course_count` int(11) DEFAULT NULL,
99 | `identity` int(11) DEFAULT NULL,
100 | `is_select_annual` varchar(255) DEFAULT NULL,
101 | `select_annual_rank` int(11) DEFAULT NULL,
102 | `annual_list_type` int(11) DEFAULT NULL,
103 | `extraMap` varchar(255) DEFAULT NULL,
104 | `is_logout` int(11) DEFAULT NULL,
105 | `annual_info` varchar(255) DEFAULT NULL,
106 | `account_amount` int(11) DEFAULT NULL,
107 | `user_growth_info` varchar(255) DEFAULT NULL,
108 | `is_vip` varchar(255) DEFAULT NULL,
109 | PRIMARY KEY (`user_id`)
110 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
111 |
112 | -- ----------------------------
113 | -- Table structure for tags
114 | -- ----------------------------
115 | DROP TABLE IF EXISTS `tags`;
116 | CREATE TABLE `tags` (
117 | `id` varchar(255) NOT NULL,
118 | `tag_id` varchar(255) DEFAULT NULL,
119 | `tag_name` varchar(255) DEFAULT NULL,
120 | `color` varchar(255) DEFAULT NULL,
121 | `icon` varchar(255) DEFAULT NULL,
122 | `back_ground` varchar(255) DEFAULT NULL,
123 | `show_navi` smallint(6) DEFAULT NULL,
124 | `ctime` varchar(255) DEFAULT NULL,
125 | `mtime` varchar(255) DEFAULT NULL,
126 | `id_type` int(11) DEFAULT NULL,
127 | `tag_alias` varchar(255) DEFAULT NULL,
128 | `post_article_count` varchar(255) DEFAULT NULL,
129 | `concern_user_count` varchar(255) DEFAULT NULL,
130 | PRIMARY KEY (`id`)
131 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
132 |
133 | SET FOREIGN_KEY_CHECKS = 1;
134 |
--------------------------------------------------------------------------------
/juejin-server/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # https://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /usr/local/etc/mavenrc ] ; then
40 | . /usr/local/etc/mavenrc
41 | fi
42 |
43 | if [ -f /etc/mavenrc ] ; then
44 | . /etc/mavenrc
45 | fi
46 |
47 | if [ -f "$HOME/.mavenrc" ] ; then
48 | . "$HOME/.mavenrc"
49 | fi
50 |
51 | fi
52 |
53 | # OS specific support. $var _must_ be set to either true or false.
54 | cygwin=false;
55 | darwin=false;
56 | mingw=false
57 | case "`uname`" in
58 | CYGWIN*) cygwin=true ;;
59 | MINGW*) mingw=true;;
60 | Darwin*) darwin=true
61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
63 | if [ -z "$JAVA_HOME" ]; then
64 | if [ -x "/usr/libexec/java_home" ]; then
65 | export JAVA_HOME="`/usr/libexec/java_home`"
66 | else
67 | export JAVA_HOME="/Library/Java/Home"
68 | fi
69 | fi
70 | ;;
71 | esac
72 |
73 | if [ -z "$JAVA_HOME" ] ; then
74 | if [ -r /etc/gentoo-release ] ; then
75 | JAVA_HOME=`java-config --jre-home`
76 | fi
77 | fi
78 |
79 | if [ -z "$M2_HOME" ] ; then
80 | ## resolve links - $0 may be a link to maven's home
81 | PRG="$0"
82 |
83 | # need this for relative symlinks
84 | while [ -h "$PRG" ] ; do
85 | ls=`ls -ld "$PRG"`
86 | link=`expr "$ls" : '.*-> \(.*\)$'`
87 | if expr "$link" : '/.*' > /dev/null; then
88 | PRG="$link"
89 | else
90 | PRG="`dirname "$PRG"`/$link"
91 | fi
92 | done
93 |
94 | saveddir=`pwd`
95 |
96 | M2_HOME=`dirname "$PRG"`/..
97 |
98 | # make it fully qualified
99 | M2_HOME=`cd "$M2_HOME" && pwd`
100 |
101 | cd "$saveddir"
102 | # echo Using m2 at $M2_HOME
103 | fi
104 |
105 | # For Cygwin, ensure paths are in UNIX format before anything is touched
106 | if $cygwin ; then
107 | [ -n "$M2_HOME" ] &&
108 | M2_HOME=`cygpath --unix "$M2_HOME"`
109 | [ -n "$JAVA_HOME" ] &&
110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
111 | [ -n "$CLASSPATH" ] &&
112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
113 | fi
114 |
115 | # For Mingw, ensure paths are in UNIX format before anything is touched
116 | if $mingw ; then
117 | [ -n "$M2_HOME" ] &&
118 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
119 | [ -n "$JAVA_HOME" ] &&
120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
121 | fi
122 |
123 | if [ -z "$JAVA_HOME" ]; then
124 | javaExecutable="`which javac`"
125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
126 | # readlink(1) is not available as standard on Solaris 10.
127 | readLink=`which readlink`
128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
129 | if $darwin ; then
130 | javaHome="`dirname \"$javaExecutable\"`"
131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
132 | else
133 | javaExecutable="`readlink -f \"$javaExecutable\"`"
134 | fi
135 | javaHome="`dirname \"$javaExecutable\"`"
136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
137 | JAVA_HOME="$javaHome"
138 | export JAVA_HOME
139 | fi
140 | fi
141 | fi
142 |
143 | if [ -z "$JAVACMD" ] ; then
144 | if [ -n "$JAVA_HOME" ] ; then
145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
146 | # IBM's JDK on AIX uses strange locations for the executables
147 | JAVACMD="$JAVA_HOME/jre/sh/java"
148 | else
149 | JAVACMD="$JAVA_HOME/bin/java"
150 | fi
151 | else
152 | JAVACMD="`\\unset -f command; \\command -v java`"
153 | fi
154 | fi
155 |
156 | if [ ! -x "$JAVACMD" ] ; then
157 | echo "Error: JAVA_HOME is not defined correctly." >&2
158 | echo " We cannot execute $JAVACMD" >&2
159 | exit 1
160 | fi
161 |
162 | if [ -z "$JAVA_HOME" ] ; then
163 | echo "Warning: JAVA_HOME environment variable is not set."
164 | fi
165 |
166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
167 |
168 | # traverses directory structure from process work directory to filesystem root
169 | # first directory with .mvn subdirectory is considered project base directory
170 | find_maven_basedir() {
171 |
172 | if [ -z "$1" ]
173 | then
174 | echo "Path not specified to find_maven_basedir"
175 | return 1
176 | fi
177 |
178 | basedir="$1"
179 | wdir="$1"
180 | while [ "$wdir" != '/' ] ; do
181 | if [ -d "$wdir"/.mvn ] ; then
182 | basedir=$wdir
183 | break
184 | fi
185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
186 | if [ -d "${wdir}" ]; then
187 | wdir=`cd "$wdir/.."; pwd`
188 | fi
189 | # end of workaround
190 | done
191 | echo "${basedir}"
192 | }
193 |
194 | # concatenates all lines of a file
195 | concat_lines() {
196 | if [ -f "$1" ]; then
197 | echo "$(tr -s '\n' ' ' < "$1")"
198 | fi
199 | }
200 |
201 | BASE_DIR=`find_maven_basedir "$(pwd)"`
202 | if [ -z "$BASE_DIR" ]; then
203 | exit 1;
204 | fi
205 |
206 | ##########################################################################################
207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
208 | # This allows using the maven wrapper in projects that prohibit checking in binary data.
209 | ##########################################################################################
210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
211 | if [ "$MVNW_VERBOSE" = true ]; then
212 | echo "Found .mvn/wrapper/maven-wrapper.jar"
213 | fi
214 | else
215 | if [ "$MVNW_VERBOSE" = true ]; then
216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
217 | fi
218 | if [ -n "$MVNW_REPOURL" ]; then
219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
220 | else
221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
222 | fi
223 | while IFS="=" read key value; do
224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
225 | esac
226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
227 | if [ "$MVNW_VERBOSE" = true ]; then
228 | echo "Downloading from: $jarUrl"
229 | fi
230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
231 | if $cygwin; then
232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
233 | fi
234 |
235 | if command -v wget > /dev/null; then
236 | if [ "$MVNW_VERBOSE" = true ]; then
237 | echo "Found wget ... using wget"
238 | fi
239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
241 | else
242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
243 | fi
244 | elif command -v curl > /dev/null; then
245 | if [ "$MVNW_VERBOSE" = true ]; then
246 | echo "Found curl ... using curl"
247 | fi
248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
249 | curl -o "$wrapperJarPath" "$jarUrl" -f
250 | else
251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
252 | fi
253 |
254 | else
255 | if [ "$MVNW_VERBOSE" = true ]; then
256 | echo "Falling back to using Java to download"
257 | fi
258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
259 | # For Cygwin, switch paths to Windows format before running javac
260 | if $cygwin; then
261 | javaClass=`cygpath --path --windows "$javaClass"`
262 | fi
263 | if [ -e "$javaClass" ]; then
264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
265 | if [ "$MVNW_VERBOSE" = true ]; then
266 | echo " - Compiling MavenWrapperDownloader.java ..."
267 | fi
268 | # Compiling the Java class
269 | ("$JAVA_HOME/bin/javac" "$javaClass")
270 | fi
271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
272 | # Running the downloader
273 | if [ "$MVNW_VERBOSE" = true ]; then
274 | echo " - Running MavenWrapperDownloader.java ..."
275 | fi
276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
277 | fi
278 | fi
279 | fi
280 | fi
281 | ##########################################################################################
282 | # End of extension
283 | ##########################################################################################
284 |
285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
286 | if [ "$MVNW_VERBOSE" = true ]; then
287 | echo $MAVEN_PROJECTBASEDIR
288 | fi
289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
290 |
291 | # For Cygwin, switch paths to Windows format before running java
292 | if $cygwin; then
293 | [ -n "$M2_HOME" ] &&
294 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
295 | [ -n "$JAVA_HOME" ] &&
296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
297 | [ -n "$CLASSPATH" ] &&
298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
299 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
301 | fi
302 |
303 | # Provide a "standardized" way to retrieve the CLI args that will
304 | # work with both Windows and non-Windows executions.
305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
306 | export MAVEN_CMD_LINE_ARGS
307 |
308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
309 |
310 | exec "$JAVACMD" \
311 | $MAVEN_OPTS \
312 | $MAVEN_DEBUG_OPTS \
313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
314 | "-Dmaven.home=${M2_HOME}" \
315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
317 |
--------------------------------------------------------------------------------
/juejin-server/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM https://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM set title of command window
39 | title %0
40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
42 |
43 | @REM set %HOME% to equivalent of $HOME
44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
45 |
46 | @REM Execute a user defined script before this one
47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
51 | :skipRcPre
52 |
53 | @setlocal
54 |
55 | set ERROR_CODE=0
56 |
57 | @REM To isolate internal variables from possible post scripts, we use another setlocal
58 | @setlocal
59 |
60 | @REM ==== START VALIDATION ====
61 | if not "%JAVA_HOME%" == "" goto OkJHome
62 |
63 | echo.
64 | echo Error: JAVA_HOME not found in your environment. >&2
65 | echo Please set the JAVA_HOME variable in your environment to match the >&2
66 | echo location of your Java installation. >&2
67 | echo.
68 | goto error
69 |
70 | :OkJHome
71 | if exist "%JAVA_HOME%\bin\java.exe" goto init
72 |
73 | echo.
74 | echo Error: JAVA_HOME is set to an invalid directory. >&2
75 | echo JAVA_HOME = "%JAVA_HOME%" >&2
76 | echo Please set the JAVA_HOME variable in your environment to match the >&2
77 | echo location of your Java installation. >&2
78 | echo.
79 | goto error
80 |
81 | @REM ==== END VALIDATION ====
82 |
83 | :init
84 |
85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
86 | @REM Fallback to current working directory if not found.
87 |
88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
90 |
91 | set EXEC_DIR=%CD%
92 | set WDIR=%EXEC_DIR%
93 | :findBaseDir
94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
95 | cd ..
96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
97 | set WDIR=%CD%
98 | goto findBaseDir
99 |
100 | :baseDirFound
101 | set MAVEN_PROJECTBASEDIR=%WDIR%
102 | cd "%EXEC_DIR%"
103 | goto endDetectBaseDir
104 |
105 | :baseDirNotFound
106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
107 | cd "%EXEC_DIR%"
108 |
109 | :endDetectBaseDir
110 |
111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
112 |
113 | @setlocal EnableExtensions EnableDelayedExpansion
114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
116 |
117 | :endReadAdditionalConfig
118 |
119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
122 |
123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
124 |
125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
127 | )
128 |
129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
131 | if exist %WRAPPER_JAR% (
132 | if "%MVNW_VERBOSE%" == "true" (
133 | echo Found %WRAPPER_JAR%
134 | )
135 | ) else (
136 | if not "%MVNW_REPOURL%" == "" (
137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
138 | )
139 | if "%MVNW_VERBOSE%" == "true" (
140 | echo Couldn't find %WRAPPER_JAR%, downloading it ...
141 | echo Downloading from: %DOWNLOAD_URL%
142 | )
143 |
144 | powershell -Command "&{"^
145 | "$webclient = new-object System.Net.WebClient;"^
146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
148 | "}"^
149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
150 | "}"
151 | if "%MVNW_VERBOSE%" == "true" (
152 | echo Finished downloading %WRAPPER_JAR%
153 | )
154 | )
155 | @REM End of extension
156 |
157 | @REM Provide a "standardized" way to retrieve the CLI args that will
158 | @REM work with both Windows and non-Windows executions.
159 | set MAVEN_CMD_LINE_ARGS=%*
160 |
161 | %MAVEN_JAVA_EXE% ^
162 | %JVM_CONFIG_MAVEN_PROPS% ^
163 | %MAVEN_OPTS% ^
164 | %MAVEN_DEBUG_OPTS% ^
165 | -classpath %WRAPPER_JAR% ^
166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
168 | if ERRORLEVEL 1 goto error
169 | goto end
170 |
171 | :error
172 | set ERROR_CODE=1
173 |
174 | :end
175 | @endlocal & set ERROR_CODE=%ERROR_CODE%
176 |
177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
181 | :skipRcPost
182 |
183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause
185 |
186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
187 |
188 | cmd /C exit /B %ERROR_CODE%
189 |
--------------------------------------------------------------------------------
/juejin-server/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.7.2
9 |
10 |
11 | edu.gdut
12 | juejin-server
13 | 0.0.1-SNAPSHOT
14 | juejin-server
15 | juejin-server
16 |
17 | 1.8
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-data-jpa
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-jdbc
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-web
31 |
32 |
33 |
34 | com.baomidou
35 | mybatis-plus-boot-starter
36 | 3.0.5
37 |
38 |
39 |
40 | org.apache.velocity
41 | velocity-engine-core
42 | 2.0
43 |
44 |
45 |
46 | io.springfox
47 | springfox-swagger2
48 | 3.0.0
49 |
50 |
51 | junit
52 | junit
53 | test
54 |
55 |
56 |
57 | org.springframework.boot
58 | spring-boot-starter-data-redis
59 |
60 |
61 |
62 | org.apache.commons
63 | commons-pool2
64 |
65 |
66 |
67 | mysql
68 | mysql-connector-java
69 | runtime
70 |
71 |
72 | org.projectlombok
73 | lombok
74 | true
75 |
76 |
77 | org.springframework.boot
78 | spring-boot-starter-test
79 | test
80 |
81 |
82 |
83 |
84 |
85 |
86 | org.springframework.boot
87 | spring-boot-maven-plugin
88 | 2.7.2
89 |
90 |
91 |
92 | org.projectlombok
93 | lombok
94 |
95 |
96 | edu.gdut.juejinserver.JuejinServerApplication
97 |
98 |
99 |
100 |
101 |
102 |
103 | src/main/java
104 |
105 |
106 | **/*.xml
107 | **/*.properties
108 |
109 |
110 |
111 |
112 | src/main/resources
113 |
114 |
115 | **/*.xml
116 | **/*.properties
117 |
118 |
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/JuejinServerApplication.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.annotation.ComponentScan;
6 |
7 | @SpringBootApplication
8 | @ComponentScan("edu.gdut")
9 | public class JuejinServerApplication {
10 |
11 | public static void main(String[] args) {
12 | SpringApplication.run(JuejinServerApplication.class, args);
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/config/MybatisPlusConfig.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.config;
2 |
3 | import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
4 | import org.mybatis.spring.annotation.MapperScan;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 |
8 | @Configuration
9 | @MapperScan("edu.gdut.juejinserver.mapper")
10 | public class MybatisPlusConfig {
11 | /**
12 | *
13 | * 分页查询插件
14 | *
15 | */
16 | @Bean
17 | public PaginationInterceptor paginationInterceptor() {
18 | return new PaginationInterceptor();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/config/RedisConfig.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.config;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAutoDetect;
4 | import com.fasterxml.jackson.annotation.PropertyAccessor;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import org.springframework.cache.CacheManager;
7 | import org.springframework.cache.annotation.CachingConfigurerSupport;
8 | import org.springframework.cache.annotation.EnableCaching;
9 | import org.springframework.context.annotation.Bean;
10 | import org.springframework.context.annotation.Configuration;
11 | import org.springframework.data.redis.cache.RedisCacheConfiguration;
12 | import org.springframework.data.redis.cache.RedisCacheManager;
13 | import org.springframework.data.redis.connection.RedisConnectionFactory;
14 | import org.springframework.data.redis.core.RedisTemplate;
15 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
16 | import org.springframework.data.redis.serializer.RedisSerializationContext;
17 | import org.springframework.data.redis.serializer.RedisSerializer;
18 | import org.springframework.data.redis.serializer.StringRedisSerializer;
19 |
20 | import java.time.Duration;
21 |
22 | /**
23 | * 配置SpringBoot集成Redis
24 | */
25 | @EnableCaching
26 | @Configuration
27 | public class RedisConfig extends CachingConfigurerSupport {
28 | /**
29 | *
30 | * redis模版插件,对redis缓存做相关操作
31 | *
32 | */
33 | @Bean
34 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
35 | RedisTemplate redisTemplate = new RedisTemplate<>();
36 | RedisSerializer redisSerializer = new StringRedisSerializer();
37 | Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
38 | ObjectMapper om = new ObjectMapper();
39 | om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
40 | om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
41 | jackson2JsonRedisSerializer.setObjectMapper(om);
42 | redisTemplate.setConnectionFactory(redisConnectionFactory);
43 | // Key序列化方式
44 | redisTemplate.setKeySerializer(redisSerializer);
45 | // value序列化
46 | redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
47 | // value hashmap序列化
48 | redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
49 | return redisTemplate;
50 | }
51 |
52 | /**
53 | *
54 | * 针对缓存的管理
55 | *
56 | */
57 | @Bean
58 | public CacheManager cacheManager(RedisConnectionFactory factory) {
59 | RedisSerializer redisSerializer = new StringRedisSerializer();
60 | Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
61 | // 解决查询缓存转换异常问题
62 | ObjectMapper om = new ObjectMapper();
63 | om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
64 | om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
65 | jackson2JsonRedisSerializer.setObjectMapper(om);
66 | // 配置序列化,解决乱码问题,设置过期时间,单位秒
67 | RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
68 | .entryTtl(Duration.ofSeconds(600))
69 | .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
70 | .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
71 | .disableCachingNullValues();
72 | RedisCacheManager manager = RedisCacheManager.builder(factory).cacheDefaults(config).build();
73 | return manager;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/config/SwaggerConfig.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.config;
2 |
3 | public class SwaggerConfig {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/controller/ArticleContentController.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.controller;
2 |
3 |
4 | import edu.gdut.juejinserver.service.ArticleContentService;
5 | import edu.gdut.juejinserver.utils.Result;
6 | import org.springframework.web.bind.annotation.*;
7 |
8 | import javax.annotation.Resource;
9 |
10 | /**
11 | *
12 | * 前端控制器
13 | *
14 | *
15 | * @author Trust会长
16 | * @since 2022-08-14
17 | */
18 | @RestController
19 | @RequestMapping("/juejinserver/article_content")
20 | @CrossOrigin
21 | public class ArticleContentController {
22 |
23 | @Resource
24 | private ArticleContentService articleContentService;
25 |
26 | /**
27 | * 根据文章id查询文章内容
28 | * @param articleId 文章id
29 | * @return 结果
30 | */
31 | @GetMapping("/getArticleContent/{articleId}")
32 | public Result getArticleContent(@PathVariable String articleId) {
33 | return Result.success().data("articleContent", articleContentService.getById(articleId).getMarkContent());
34 | }
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/controller/ArticleInfoController.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.controller;
2 |
3 | import edu.gdut.juejinserver.service.ArticleInfoService;
4 | import edu.gdut.juejinserver.utils.Result;
5 | import org.springframework.web.bind.annotation.*;
6 |
7 | import javax.annotation.Resource;
8 |
9 | /**
10 | *
11 | * 前端控制器
12 | *
13 | *
14 | * @author Trust会长
15 | * @since 2022-07-30
16 | */
17 | @RestController
18 | @RequestMapping("/juejinserver/index_data")
19 | @CrossOrigin
20 | public class ArticleInfoController {
21 |
22 | @Resource
23 | private ArticleInfoService articleInfoService;
24 |
25 | /**
26 | * 分页查询首页文章
27 | * @param current 当前页
28 | * @param limit 每页记录数
29 | * @return 统一返回结果
30 | */
31 | @GetMapping("/find_article/{current}/{limit}")
32 | public Result findIndexArticle(@PathVariable Integer current, @PathVariable Integer limit) {
33 | return Result.success().data("article_info", articleInfoService.queryArticleInfoList(current, limit));
34 | }
35 |
36 | @GetMapping("/findArticleDetail/{articleId}")
37 | public Result findArticleDetailById(@PathVariable String articleId) {
38 | return Result.success().data("articleDetail", articleInfoService.getArticleDetailById(articleId));
39 | }
40 |
41 | @GetMapping("/findArticleTags/{articleId}")
42 | public Result findArticleTagsById(@PathVariable String articleId) {
43 | return Result.success().data("tags", articleInfoService.getArticleTagsById(articleId));
44 | }
45 |
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/mapper/ArticleContentMapper.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.mapper;
2 |
3 | import edu.gdut.juejinserver.pojo.ArticleContent;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 |
6 | /**
7 | *
8 | * Mapper 接口
9 | *
10 | *
11 | * @author Trust会长
12 | * @since 2022-08-14
13 | */
14 | public interface ArticleContentMapper extends BaseMapper {
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/mapper/ArticleInfoMapper.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.mapper;
2 |
3 | import edu.gdut.juejinserver.pojo.ArticleInfo;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 | import edu.gdut.juejinserver.vo.ArticleDetailVo;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | *
11 | * Mapper 接口
12 | *
13 | *
14 | * @author Trust会长
15 | * @since 2022-07-30
16 | */
17 | public interface ArticleInfoMapper extends BaseMapper {
18 |
19 | ArticleDetailVo queryArticleInfoById(String articleId);
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/mapper/AuthorUserMapper.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.mapper;
2 |
3 | import edu.gdut.juejinserver.pojo.AuthorUser;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 |
6 | /**
7 | *
8 | * Mapper 接口
9 | *
10 | *
11 | * @author Trust会长
12 | * @since 2022-08-01
13 | */
14 | public interface AuthorUserMapper extends BaseMapper {
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/mapper/TagsMapper.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.mapper;
2 |
3 | import edu.gdut.juejinserver.pojo.Tags;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 |
6 | /**
7 | *
8 | * Mapper 接口
9 | *
10 | *
11 | * @author Trust会长
12 | * @since 2022-08-01
13 | */
14 | public interface TagsMapper extends BaseMapper {
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/mapper/xml/ArticleContentMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/mapper/xml/ArticleInfoMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SELECT
6 | article_info.article_id,
7 | article_info.title,
8 | article_info.cover_image,
9 | article_info.ctime,
10 | article_info.mtime,
11 | article_info.rtime,
12 | article_info.view_count,
13 | article_info.collect_count,
14 | article_info.digg_count,
15 | article_info.comment_count,
16 | author_user.user_id,
17 | author_user.user_name,
18 | author_user.company,
19 | author_user.job_title,
20 | author_user.avatar_large
21 | FROM
22 | article_info,
23 | author_user
24 | WHERE
25 | article_info.article_id = #{articleId}
26 | AND article_info.user_id = author_user.user_id
27 |
28 |
29 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/mapper/xml/AuthorUserMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/mapper/xml/TagsMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/pojo/ArticleContent.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.pojo;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import java.io.Serializable;
6 | import io.swagger.annotations.ApiModel;
7 | import io.swagger.annotations.ApiModelProperty;
8 | import lombok.Data;
9 | import lombok.EqualsAndHashCode;
10 | import lombok.experimental.Accessors;
11 |
12 | /**
13 | *
14 | *
15 | *
16 | *
17 | * @author Trust会长
18 | * @since 2022-08-14
19 | */
20 | @Data
21 | @EqualsAndHashCode(callSuper = false)
22 | @Accessors(chain = true)
23 | @ApiModel(value="ArticleContent对象", description="")
24 | public class ArticleContent implements Serializable {
25 |
26 | private static final long serialVersionUID = 1L;
27 |
28 | @TableId(value = "article_id", type = IdType.ID_WORKER_STR)
29 | private String articleId;
30 |
31 | private String markContent;
32 |
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/pojo/ArticleInfo.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.pojo;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import java.io.Serializable;
6 | import io.swagger.annotations.ApiModel;
7 | import io.swagger.annotations.ApiModelProperty;
8 | import lombok.Data;
9 | import lombok.EqualsAndHashCode;
10 | import lombok.experimental.Accessors;
11 |
12 | /**
13 | *
14 | *
15 | *
16 | *
17 | * @author Trust会长
18 | * @since 2022-07-30
19 | */
20 | @Data
21 | @EqualsAndHashCode(callSuper = false)
22 | @Accessors(chain = true)
23 | @ApiModel(value="ArticleInfo对象", description="")
24 | public class ArticleInfo implements Serializable {
25 |
26 | private static final long serialVersionUID = 1L;
27 |
28 | @TableId(value = "article_id", type = IdType.ID_WORKER_STR)
29 | private String articleId;
30 |
31 | private String userId;
32 |
33 | private String categoryId;
34 |
35 | private String tagIds;
36 |
37 | private Integer visibleLevel;
38 |
39 | private String linkUrl;
40 |
41 | private String coverImage;
42 |
43 | private Integer isGfw;
44 |
45 | private String title;
46 |
47 | private String briefContent;
48 |
49 | private Integer isEnglish;
50 |
51 | private Integer isOriginal;
52 |
53 | private Double userIndex;
54 |
55 | private Integer originalType;
56 |
57 | private String originalAuthor;
58 |
59 | private String content;
60 |
61 | private String ctime;
62 |
63 | private String mtime;
64 |
65 | private String rtime;
66 |
67 | private String draftId;
68 |
69 | private Integer viewCount;
70 |
71 | private Integer collectCount;
72 |
73 | private Integer diggCount;
74 |
75 | private Integer commentCount;
76 |
77 | private Integer hotIndex;
78 |
79 | private Integer isHot;
80 |
81 | private Double rankIndex;
82 |
83 | private Integer status;
84 |
85 | private Integer verifyStatus;
86 |
87 | private Integer auditStatus;
88 |
89 | private String markContent;
90 |
91 | private Integer displayCount;
92 |
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/pojo/AuthorUser.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.pojo;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import com.baomidou.mybatisplus.annotation.TableField;
6 | import java.io.Serializable;
7 | import io.swagger.annotations.ApiModel;
8 | import io.swagger.annotations.ApiModelProperty;
9 | import lombok.Data;
10 | import lombok.EqualsAndHashCode;
11 | import lombok.experimental.Accessors;
12 |
13 | /**
14 | *
15 | *
16 | *
17 | *
18 | * @author Trust会长
19 | * @since 2022-08-01
20 | */
21 | @Data
22 | @EqualsAndHashCode(callSuper = false)
23 | @Accessors(chain = true)
24 | @ApiModel(value="AuthorUser对象", description="")
25 | public class AuthorUser implements Serializable {
26 |
27 | private static final long serialVersionUID = 1L;
28 |
29 | @TableId(value = "user_id", type = IdType.ID_WORKER_STR)
30 | private String userId;
31 |
32 | private String userName;
33 |
34 | private String company;
35 |
36 | private String jobTitle;
37 |
38 | private String avatarLarge;
39 |
40 | private Integer level;
41 |
42 | private String description;
43 |
44 | private Integer followeeCount;
45 |
46 | private Integer followerCount;
47 |
48 | private Integer postArticleCount;
49 |
50 | private Integer diggArticleCount;
51 |
52 | private Integer gotDiggCount;
53 |
54 | private Integer gotViewCount;
55 |
56 | private Integer postShortmsgCount;
57 |
58 | private Integer diggShortmsgCount;
59 |
60 | private String isfollowed;
61 |
62 | private Integer favorableAuthor;
63 |
64 | private Integer power;
65 |
66 | private Integer studyPoint;
67 |
68 | private String university;
69 |
70 | private String major;
71 |
72 | private Integer studentStatus;
73 |
74 | private Integer selectEventCount;
75 |
76 | private Integer selectOnlineCourseCount;
77 |
78 | private Integer identity;
79 |
80 | private String isSelectAnnual;
81 |
82 | private Integer selectAnnualRank;
83 |
84 | private Integer annualListType;
85 |
86 | @TableField("extraMap")
87 | private String extraMap;
88 |
89 | private Integer isLogout;
90 |
91 | private String annualInfo;
92 |
93 | private Integer accountAmount;
94 |
95 | private String userGrowthInfo;
96 |
97 | private String isVip;
98 |
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/pojo/Tags.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.pojo;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import java.io.Serializable;
6 | import io.swagger.annotations.ApiModel;
7 | import io.swagger.annotations.ApiModelProperty;
8 | import lombok.Data;
9 | import lombok.EqualsAndHashCode;
10 | import lombok.experimental.Accessors;
11 |
12 | /**
13 | *
14 | *
15 | *
16 | *
17 | * @author Trust会长
18 | * @since 2022-08-01
19 | */
20 | @Data
21 | @EqualsAndHashCode(callSuper = false)
22 | @Accessors(chain = true)
23 | @ApiModel(value="Tags对象", description="")
24 | public class Tags implements Serializable {
25 |
26 | private static final long serialVersionUID = 1L;
27 |
28 | @TableId(value = "id", type = IdType.ID_WORKER_STR)
29 | private String id;
30 |
31 | private String tagId;
32 |
33 | private String tagName;
34 |
35 | private String color;
36 |
37 | private String icon;
38 |
39 | private String backGround;
40 |
41 | private Integer showNavi;
42 |
43 | private String ctime;
44 |
45 | private String mtime;
46 |
47 | private Integer idType;
48 |
49 | private String tagAlias;
50 |
51 | private String postArticleCount;
52 |
53 | private String concernUserCount;
54 |
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/service/ArticleContentService.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.service;
2 |
3 | import edu.gdut.juejinserver.pojo.ArticleContent;
4 | import com.baomidou.mybatisplus.extension.service.IService;
5 |
6 | /**
7 | *
8 | * 服务类
9 | *
10 | *
11 | * @author Trust会长
12 | * @since 2022-08-14
13 | */
14 | public interface ArticleContentService extends IService {
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/service/ArticleInfoService.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.service;
2 |
3 | import edu.gdut.juejinserver.pojo.ArticleInfo;
4 | import com.baomidou.mybatisplus.extension.service.IService;
5 | import edu.gdut.juejinserver.vo.ArticleDetailVo;
6 | import edu.gdut.juejinserver.vo.ArticleInfoVo;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | *
12 | * 服务类
13 | *
14 | *
15 | * @author Trust会长
16 | * @since 2022-07-30
17 | */
18 | public interface ArticleInfoService extends IService {
19 |
20 | /**
21 | * 分页查询数据
22 | * @param current 当前页
23 | * @param limit 每页记录数
24 | * @return
25 | */
26 | List queryArticleInfoList(int current, int limit);
27 |
28 | /**
29 | * 查询文章和作者详情
30 | * @param articleId 文章id
31 | * @return 文章详情
32 | */
33 | ArticleDetailVo getArticleDetailById(String articleId);
34 |
35 | List getArticleTagsById(String articleId);
36 | }
37 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/service/AuthorUserService.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.service;
2 |
3 | import edu.gdut.juejinserver.pojo.AuthorUser;
4 | import com.baomidou.mybatisplus.extension.service.IService;
5 |
6 | /**
7 | *
8 | * 服务类
9 | *
10 | *
11 | * @author Trust会长
12 | * @since 2022-08-01
13 | */
14 | public interface AuthorUserService extends IService {
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/service/TagsService.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.service;
2 |
3 | import edu.gdut.juejinserver.pojo.Tags;
4 | import com.baomidou.mybatisplus.extension.service.IService;
5 |
6 | /**
7 | *
8 | * 服务类
9 | *
10 | *
11 | * @author Trust会长
12 | * @since 2022-08-01
13 | */
14 | public interface TagsService extends IService {
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/service/impl/ArticleContentServiceImpl.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.service.impl;
2 |
3 | import edu.gdut.juejinserver.pojo.ArticleContent;
4 | import edu.gdut.juejinserver.mapper.ArticleContentMapper;
5 | import edu.gdut.juejinserver.service.ArticleContentService;
6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
7 | import org.springframework.stereotype.Service;
8 |
9 | /**
10 | *
11 | * 服务实现类
12 | *
13 | *
14 | * @author Trust会长
15 | * @since 2022-08-14
16 | */
17 | @Service
18 | public class ArticleContentServiceImpl extends ServiceImpl implements ArticleContentService {
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/service/impl/ArticleInfoServiceImpl.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.service.impl;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
4 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
5 | import edu.gdut.juejinserver.mapper.AuthorUserMapper;
6 | import edu.gdut.juejinserver.mapper.TagsMapper;
7 | import edu.gdut.juejinserver.pojo.ArticleInfo;
8 | import edu.gdut.juejinserver.mapper.ArticleInfoMapper;
9 | import edu.gdut.juejinserver.pojo.AuthorUser;
10 | import edu.gdut.juejinserver.pojo.Tags;
11 | import edu.gdut.juejinserver.service.ArticleInfoService;
12 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
13 | import edu.gdut.juejinserver.utils.JuejinStringUtils;
14 | import edu.gdut.juejinserver.vo.ArticleDetailVo;
15 | import edu.gdut.juejinserver.vo.ArticleInfoVo;
16 | import org.springframework.cache.annotation.Cacheable;
17 | import org.springframework.stereotype.Service;
18 |
19 | import javax.annotation.Resource;
20 | import java.util.ArrayList;
21 | import java.util.Arrays;
22 | import java.util.List;
23 |
24 | /**
25 | *
26 | * 服务实现类
27 | *
28 | *
29 | * @author Trust会长
30 | * @since 2022-07-30
31 | */
32 | @Service
33 | public class ArticleInfoServiceImpl extends ServiceImpl implements ArticleInfoService {
34 |
35 | @Resource
36 | private ArticleInfoMapper articleInfoMapper;
37 | @Resource
38 | private AuthorUserMapper authorUserMapper;
39 | @Resource
40 | private TagsMapper tagsMapper;
41 |
42 | @Override
43 | @Cacheable(value = "juejin", key = "'articleList' + #current + 'Current' + #limit + 'Limit'")
44 | public List queryArticleInfoList(int current, int limit) {
45 | List list = new ArrayList<>();
46 | // 分页查询article数据
47 | Page page = new Page<>(current, limit);
48 | articleInfoMapper.selectPage(page, null);
49 | List articleInfos = null;
50 | if (page.getRecords().size() < limit) {
51 | // 不足limit条记录的时候
52 | // 随机查连续limit条记录
53 | QueryWrapper wrapper = new QueryWrapper<>();
54 | Integer count = articleInfoMapper.selectCount(null);
55 | // 生成一个随机数。范围为 0 —— (count - limit)
56 | int random = (int)(Math.random() * (count - limit));
57 | wrapper.last("limit "+ random +"," + limit);
58 | articleInfos = articleInfoMapper.selectList(wrapper);
59 | } else {
60 | // 足够
61 | articleInfos = page.getRecords();
62 | }
63 | // 根据userId查作者
64 | // 根据tagId查tag
65 | for (ArticleInfo article : articleInfos) {
66 | ArticleInfoVo vo = new ArticleInfoVo();
67 | // 封装数据
68 | vo.setArticleId(article.getArticleId());
69 | vo.setBriefContent(article.getBriefContent());
70 | vo.setCollectCount(article.getCollectCount());
71 | vo.setCommentCount(article.getCommentCount());
72 | vo.setCtime(article.getCtime());
73 | vo.setCoverImage(article.getCoverImage());
74 | vo.setDiggCount(article.getDiggCount());
75 | vo.setMtime(article.getMtime());
76 | vo.setRtime(article.getRtime());
77 | vo.setTitle(article.getTitle());
78 | vo.setUserId(article.getUserId());
79 | vo.setViewCount(article.getViewCount());
80 |
81 | // 二次处理的数据
82 | AuthorUser user = authorUserMapper.selectById(article.getUserId());
83 | vo.setUserName(user.getUserName());
84 |
85 | // tagIds和tagNames
86 | String tagIds = article.getTagIds();
87 | String[] tagIdsArr = JuejinStringUtils.getTagIdsArray(tagIds);
88 | vo.setTagsIds(tagIdsArr);
89 | // 根据tagId查tagName
90 | List tagNames = new ArrayList<>();
91 | for (int i = 0; i < tagIdsArr.length; i++) {
92 | QueryWrapper wrapper = new QueryWrapper<>();
93 | wrapper.eq("tag_id", tagIdsArr[i]);
94 | Tags tag = tagsMapper.selectOne(wrapper);
95 | if (tag != null) tagNames.add(tag.getTagName());
96 | }
97 | // 设置tagNames
98 | vo.setTagNames(tagNames);
99 | list.add(vo);
100 | }
101 | return list;
102 | }
103 |
104 | @Override
105 | public ArticleDetailVo getArticleDetailById(String articleId) {
106 | return articleInfoMapper.queryArticleInfoById(articleId);
107 | }
108 |
109 | @Override
110 | public List getArticleTagsById(String articleId) {
111 | ArticleInfo articleInfo = articleInfoMapper.selectById(articleId);
112 | String tagIds = articleInfo.getTagIds();
113 | String[] tagIdsArray = JuejinStringUtils.getTagIdsArray(tagIds);
114 | List tags = new ArrayList<>();
115 | // 根据tagId查tagName
116 | for (String s : tagIdsArray) {
117 | QueryWrapper wrapper = new QueryWrapper<>();
118 | wrapper.eq("tag_id", s);
119 | Tags tag = tagsMapper.selectOne(wrapper);
120 | if (tag != null) tags.add(tag.getTagName());
121 | }
122 | return tags;
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/service/impl/AuthorUserServiceImpl.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.service.impl;
2 |
3 | import edu.gdut.juejinserver.pojo.AuthorUser;
4 | import edu.gdut.juejinserver.mapper.AuthorUserMapper;
5 | import edu.gdut.juejinserver.service.AuthorUserService;
6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
7 | import org.springframework.stereotype.Service;
8 |
9 | /**
10 | *
11 | * 服务实现类
12 | *
13 | *
14 | * @author Trust会长
15 | * @since 2022-08-01
16 | */
17 | @Service
18 | public class AuthorUserServiceImpl extends ServiceImpl implements AuthorUserService {
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/service/impl/TagsServiceImpl.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.service.impl;
2 |
3 | import edu.gdut.juejinserver.pojo.Tags;
4 | import edu.gdut.juejinserver.mapper.TagsMapper;
5 | import edu.gdut.juejinserver.service.TagsService;
6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
7 | import org.springframework.stereotype.Service;
8 |
9 | /**
10 | *
11 | * 服务实现类
12 | *
13 | *
14 | * @author Trust会长
15 | * @since 2022-08-01
16 | */
17 | @Service
18 | public class TagsServiceImpl extends ServiceImpl implements TagsService {
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/utils/JuejinStringUtils.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.utils;
2 |
3 | public class JuejinStringUtils {
4 | /**
5 | * 解析tagids的字符串变成字符串数组
6 | * @param tagIds [123,456,789] 或 [123]
7 | * @return 字符串数组
8 | */
9 | public static String[] getTagIdsArray(String tagIds) {
10 | // tagIds: [123, 456, 789, 2142]
11 | // 特殊情况:只有一个tag的:[123]
12 | tagIds = tagIds.substring(1, tagIds.length() - 1); // 去掉中括号
13 | // tagIds = tagIds.trim(); // 这个方法只能去除首尾空格
14 | tagIds = tagIds.replace(" ", "");
15 | // 处理特殊情况:[123], 根据有没有逗号来判断
16 | String[] tagIdsArr = null;
17 | if (tagIds.contains(",")) {
18 | tagIdsArr = tagIds.split(",");
19 | } else {
20 | tagIdsArr = new String[]{tagIds};
21 | }
22 | return tagIdsArr;
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/utils/Result.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.utils;
2 |
3 |
4 | import lombok.Data;
5 |
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | @Data
10 | public class Result {
11 |
12 | private Boolean isSuccess;
13 |
14 | private Integer code;
15 |
16 | private String message;
17 |
18 | private Map data;
19 |
20 | /*构造方法私有化*/
21 | private Result() {
22 | data = new HashMap<>();
23 | }
24 |
25 | public static Result success() {
26 | Result result = new Result();
27 | result.isSuccess = true;
28 | result.code = ResultCode.SUCCESS;
29 | return result;
30 | }
31 |
32 | public static Result error() {
33 | Result result = new Result();
34 | result.isSuccess = false;
35 | result.code = ResultCode.ERROR;
36 | return result;
37 | }
38 |
39 | public Result message(String message) {
40 | this.message = message;
41 | return this;
42 | }
43 |
44 | public Result data(String key, Object value) {
45 | this.data.put(key, value);
46 | return this;
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/utils/ResultCode.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.utils;
2 |
3 |
4 | public class ResultCode {
5 |
6 | public static final int SUCCESS = 2000;
7 |
8 | public static final int ERROR = 2001;
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/vo/ArticleDetailVo.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.vo;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class ArticleDetailVo {
7 |
8 | private String articleId;
9 |
10 | private String title;
11 |
12 | private String coverImage;
13 |
14 | private String ctime;
15 |
16 | private String mtime;
17 |
18 | private String rtime;
19 |
20 | private Integer viewCount;
21 |
22 | private Integer collectCount;
23 |
24 | private Integer diggCount;
25 |
26 | private Integer commentCount;
27 |
28 | private String userId;
29 |
30 | private String userName;
31 |
32 | private String company;
33 |
34 | private String jobTitle;
35 |
36 | private String avatarLarge;
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/juejin-server/src/main/java/edu/gdut/juejinserver/vo/ArticleInfoVo.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver.vo;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * 文章数据
9 | */
10 | @Data
11 | public class ArticleInfoVo {
12 |
13 | private String articleId;
14 |
15 | private String userId;
16 |
17 | private String userName;
18 |
19 | private String[] tagsIds;
20 |
21 | private List tagNames;
22 |
23 | private String ctime;
24 |
25 | private String mtime;
26 |
27 | private String rtime;
28 |
29 | private String title;
30 |
31 | private String coverImage;
32 |
33 | private String briefContent;
34 |
35 | private Integer viewCount;
36 |
37 | private Integer collectCount;
38 |
39 | private Integer diggCount;
40 |
41 | private Integer commentCount;
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/juejin-server/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | # 端口
2 | server.port=9088
3 | # 服务名
4 | spring.application.name=juejin-server
5 | # 数据库信息
6 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
7 | spring.datasource.url=自己数据库的url
8 | spring.datasource.username=自己数据库的username
9 | spring.datasource.password=自己数据库的password
10 | # mybatis-plus
11 | mybatis-plus.mapper-locations=classpath:edu/gdut/juejinserver/mapper/xml/*.xml
12 |
13 | # 这是我的本地的虚拟机上的redis地址
14 | # IP redis
15 | spring.redis.host=10.211.55.5
16 | # redis端口号
17 | spring.redis.port=6379
18 | # redis数据库
19 | spring.redis.database=0
20 | # redis密码
21 | spring.redis.password=123456
22 | # redis超时时间
23 | spring.redis.timeout=180000
24 |
--------------------------------------------------------------------------------
/juejin-server/src/test/java/edu/gdut/juejinserver/CodeGenerator.java:
--------------------------------------------------------------------------------
1 | package edu.gdut.juejinserver;
2 |
3 | import com.baomidou.mybatisplus.annotation.DbType;
4 | import com.baomidou.mybatisplus.annotation.IdType;
5 | import com.baomidou.mybatisplus.generator.AutoGenerator;
6 | import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
7 | import com.baomidou.mybatisplus.generator.config.GlobalConfig;
8 | import com.baomidou.mybatisplus.generator.config.PackageConfig;
9 | import com.baomidou.mybatisplus.generator.config.StrategyConfig;
10 | import com.baomidou.mybatisplus.generator.config.rules.DateType;
11 | import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
12 | import org.junit.Test;
13 |
14 | /**
15 | * @author
16 | * @since 2018/12/13
17 | */
18 | public class CodeGenerator {
19 |
20 | @Test
21 | public void run() {
22 |
23 | // 1、创建代码生成器
24 | AutoGenerator mpg = new AutoGenerator();
25 |
26 | // 2、全局配置
27 | GlobalConfig gc = new GlobalConfig();
28 | String projectPath = System.getProperty("user.dir");
29 | gc.setOutputDir("/Users/luorui/dev/projects/juejin/juejin-server/src/main/java/edu/gdut/juejinserver");
30 | gc.setAuthor("Trust会长");
31 | gc.setOpen(false); //生成后是否打开资源管理器
32 | gc.setFileOverride(false); //重新生成时文件是否覆盖
33 | gc.setServiceName("%sService"); //去掉Service接口的首字母I
34 | gc.setIdType(IdType.ID_WORKER_STR); //主键策略
35 | gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
36 | gc.setSwagger2(true);//开启Swagger2模式
37 |
38 | mpg.setGlobalConfig(gc);
39 |
40 | // 3、数据源配置
41 | DataSourceConfig dsc = new DataSourceConfig();
42 | dsc.setUrl("jdbc:mysql://rm-wz9mc28o4x3thxw56bo.mysql.rds.aliyuncs.com:3306/jue_jin");
43 | dsc.setDriverName("com.mysql.cj.jdbc.Driver");
44 | dsc.setUsername("trust");
45 | dsc.setPassword("Trust666");
46 | dsc.setDbType(DbType.MYSQL);
47 | mpg.setDataSource(dsc);
48 |
49 | // 4、包配置
50 | PackageConfig pc = new PackageConfig();
51 | pc.setModuleName("juejinserver"); //模块名
52 | pc.setParent("edu.gdut");
53 | pc.setController("controller");
54 | pc.setEntity("pojo");
55 | pc.setService("service");
56 | pc.setMapper("mapper");
57 | mpg.setPackageInfo(pc);
58 |
59 | // 5、策略配置
60 | StrategyConfig strategy = new StrategyConfig();
61 | strategy.setInclude("article_content");
62 | strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
63 | strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
64 |
65 | strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
66 | strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
67 |
68 | strategy.setRestControllerStyle(true); //restful api风格控制器
69 | strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
70 |
71 | mpg.setStrategy(strategy);
72 |
73 |
74 | // 6、执行
75 | mpg.execute();
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/project/article.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --juejin-brand-1-normal: #1e80ff;
3 | --juejin-brand-2-hover: #1171ee;
4 | --juejin-brand-3-click: #0060dd;
5 | --juejin-brand-4-disable: #abcdff;
6 | --juejin-brand-5-light: #eaf2ff;
7 | --juejin-font-1: #252933;
8 | --juejin-font-2: #515767;
9 | --juejin-font-3: #8a919f;
10 | --juejin-font-4: #c2c8d1;
11 | }
12 |
13 | * {
14 | margin: 0;
15 | padding: 0;
16 | }
17 |
18 | html,
19 | body {
20 | background-color: #f4f5f5;
21 | }
22 |
23 | .page{
24 | width: 98.93vw;
25 | }
26 |
27 | .page__header{
28 | width: 100%;
29 | height: 60px;
30 | background: rgba(144, 243, 78, 0.171);
31 | }
32 |
33 | .page__main{
34 | max-width: 1140px;
35 | width: 100%;
36 | height: 800px;
37 | margin: 0 auto;
38 | position: relative;
39 | margin-top: 21px;
40 | }
41 | .article-main{
42 | width: 100%;
43 | height: 600px;
44 | /* background: rgba(61, 155, 231, 0.219); */
45 | margin: 0 auto;
46 | display: flex;
47 |
48 | }
49 |
50 | .article-area{
51 | /* flex: 1; */
52 | width: 820px;
53 | margin-right: 21px;
54 | }
55 | .article{
56 | /* width: 100%; */
57 | /* height: 400px; */
58 | padding: 32px;
59 | box-sizing: border-box;
60 | background: #fff;
61 | border-radius: 4px;
62 | }
63 | .article>div{
64 | margin-bottom: 20px;
65 | }
66 | .article .article-title{
67 | font-size: 1.9rem;
68 | font-weight: 600;
69 | color: #252933;
70 | word-wrap: break-word;
71 | }
72 | .article .article-info-box{
73 | width: 100%;
74 | height: 48px;
75 | /* background: rgba(0, 0, 0, 0.13); */
76 | display: flex;
77 | align-items: center;
78 | }
79 | .user-photo{
80 | width: 40px;
81 | height: 40px;
82 | border-radius: 50%;
83 | margin-right: 8px;
84 | overflow: hidden;
85 | display: flex;
86 | justify-content: center;
87 | align-items: center;
88 | }
89 | .user-photo img{
90 | height: 100%;
91 | }
92 | .author-info{
93 | flex: 1px;
94 | }
95 | .author-info .author-name{
96 | font-size: 1rem;
97 | font-weight: 500;
98 | color: #515767;
99 | line-height: 2rem;
100 | display: flex;
101 | }
102 | .author-name span{
103 | width: 20%;
104 | text-overflow: ellipsis;
105 | overflow: hidden;
106 | white-space: nowrap;
107 | display: block;
108 | margin-right: 5px;
109 | }
110 | .author-name img{
111 | width: 35px;
112 | height: 16px;
113 | }
114 | .author-info .meta-box{
115 | font-size: .9rem;
116 | color: #8a919f;
117 | line-height: 20px;
118 | display: flex;
119 | }
120 | .meta-box span{
121 | margin-right: 15px;
122 | position: relative;
123 | }
124 | .meta-box span:not(:last-child)::after{
125 | content: '·';
126 | position: absolute;
127 | right: -8px;
128 | }
129 | .follow-btn{
130 | width: 70px;
131 | height: 34px;
132 | font-size: 14px;
133 | color: #1e80ff;
134 | background: rgba(30, 128, 255, .05);
135 | border: 1px solid rgba(30, 128, 255, .3);
136 | border-radius: 4px;
137 | }
138 | .article-img{
139 | width: 100%;
140 | height: 425px;
141 | overflow: hidden;
142 | display: flex;
143 | align-items: center;
144 | }
145 | .article-img img{
146 | width: 100%;
147 | }
148 |
149 |
150 | .tag-list-box{
151 | width: 100%;
152 | height: 32px;
153 | display: flex;
154 | /* background: rgba(0, 0, 0, 0.089); */
155 | font-size: .9rem;
156 | line-height: 32px;
157 | color: #515767d8;
158 | }
159 | .tag-list-box .list{
160 | margin-right: 20px;
161 | display: flex;
162 | }
163 | .tag-list-box .list>span{
164 | display: block;
165 | color: #1e80ff;
166 | background: #eaf2ff;
167 | padding: 0 12px;
168 | border-radius: 4px;
169 | margin-right: 5px;
170 | }
171 |
172 | .comment{
173 | width: 100%;
174 | /* height: 176px; */
175 | background: #fff;
176 | margin-top: 21px;
177 | border-radius: 4px;
178 | padding: 0px 32px;
179 | box-sizing: border-box;
180 | }
181 | .comment>div{
182 | padding-top: 24px;
183 | }
184 | .comment-form .form-header{
185 | font-size: 18px;
186 | line-height: 30px;
187 | font-weight: 600;
188 | color: #252933;
189 | margin-bottom: 24px;
190 | }
191 | .comment-form .form-content{
192 | display: flex;
193 | /* height: 74px; */
194 | }
195 | .form-userimg{
196 | width: 40px;
197 | height: 40px;
198 | border-radius: 50%;
199 | overflow: hidden;
200 | display: flex;
201 | justify-content: center;
202 | align-items: center;
203 | margin-right: 16px;
204 | }
205 | .form-userimg>img{
206 | height: 100%;
207 | }
208 | .form-box>textarea{
209 | border: none;
210 | background: #f2f3f5;
211 | border-radius: 4px;
212 | padding: 8px 12px;
213 | box-sizing: border-box;
214 | color: #252933;
215 | line-height: 22px;
216 | font-size: 14px;
217 | }
218 | .form-box>textarea:focus-within{
219 | outline: 1px solid var(--juejin-brand-1-normal);
220 | }
221 | .form-box:focus-within .action-box{
222 | display: flex;
223 | }
224 | .action-box{
225 | height: 36px;
226 |
227 | align-items: center;
228 | margin-top: 8px;
229 | font-size: 13px;
230 | color: #515767;
231 | /* display: flex; */
232 | display: none;
233 | }
234 |
235 | .image-btn{
236 | margin-left: 24px;
237 | }
238 | .submit-box{
239 | flex: 1;
240 | display: flex;
241 | justify-content: flex-end;
242 | font-size: 14px;
243 | color: #86909c;
244 | line-height: 36px;
245 | }
246 | .submit-box .submit{
247 | width: 92px;
248 | height: 36px;
249 | border: none;
250 | font-size: 14px;
251 | color: #fff;
252 | background: #1e80ff;
253 | border-radius: 4px;
254 | margin-left: 16px;
255 | }
256 | .hot-list{
257 | /* height: 600px; */
258 | }
259 | .title{
260 | font-size: 18px;
261 | line-height: 30px;
262 | font-weight: 600;
263 | color: #252933;
264 | margin-bottom: 24px;
265 | display: flex;
266 | align-items: center;
267 | }
268 | .title>img{
269 | width: 20px;
270 | height: 20px;
271 | }
272 |
273 |
274 | /* 一条评论的样式 开始 */
275 | .comment-item{
276 | width: 100%;
277 | display: flex;
278 | padding: 16px 0px;
279 | }
280 | .comment-userImg .userImg{
281 | width: 40px;
282 | height: 40px;
283 | border-radius: 50%;
284 | overflow: hidden;
285 | display: flex;
286 | justify-content: center;
287 | align-items: center;
288 | }
289 | .comment-userImg .userImg>img{
290 | height: 100%;
291 | }
292 | .comment-content{
293 | flex: 1;
294 | margin-left: 16px;
295 | }
296 | .comment-main>div{
297 | margin-bottom: 8px;
298 | }
299 | .user-box span:not(:last-child){
300 | margin-right: 7px;
301 | }
302 | .user-box{
303 | width: 100%;
304 | height: 26px;
305 | display: flex;
306 | align-items: center;
307 | }
308 | .user-box .name{
309 | max-width: 128px;
310 | font-size: 15px;
311 | color: #252933;
312 | line-height: 26px;
313 |
314 | text-overflow: ellipsis;
315 | overflow: hidden;
316 | white-space: nowrap;
317 | }
318 | .user-box .level{
319 | width: 45px;
320 | height: 16px;
321 | }
322 | .user-box .jueyou-level{
323 | width: 45px;
324 | height: 16px;
325 | }
326 | .user-box img{
327 | width: 45px;
328 | height: 16px;
329 | }
330 | .user-box .position{
331 | max-width: 150px;
332 | font-size: 14px;
333 | color: #8a919f;
334 |
335 | text-overflow: ellipsis;
336 | overflow: hidden;
337 | white-space: nowrap;
338 |
339 | margin-left: 10px;
340 | }
341 | .user-box .time{
342 | flex: 1;
343 | font-size: 14px;
344 | color: #8a919f;
345 | text-align: right;
346 | }
347 | .content-main{
348 | font-size: 14px;
349 | line-height: 24px;
350 | color: #515767;
351 | }
352 | .comment-action-box{
353 | display: flex;
354 | font-size: 14px;
355 | color: #8a919f;
356 | }
357 | .comment-action-box div{
358 | display: flex;
359 | align-items: center;
360 | margin-right: 15px;
361 | }
362 | .comment-action-box img{
363 | width: 16px;
364 | height: 16px;
365 | margin-right: 5px;
366 | }
367 | /* 一条评论的样式 结束 */
368 |
369 |
370 |
371 |
372 | /* 侧边栏 开始 */
373 | .sidebar{
374 | position: absolute;
375 | top: 0;
376 | right: 0;
377 | width: 300px;
378 | height: 600px;
379 | flex: 1;
380 | /* background: rgba(146, 231, 77, 0.63); */
381 | /* background: #fff; */
382 |
383 | }
384 | .sidebar>div{
385 | width: 100%;
386 | /* padding: 20px; */
387 | margin-bottom: 20px;
388 | box-sizing: border-box;
389 | border-radius: 4px;
390 | background: #fff;
391 | }
392 |
393 | /* 作者信息栏 */
394 | .author-block{
395 | /* background: #fff; */
396 | padding: 20px;
397 | }
398 | .user-item{
399 | display: flex;
400 | padding-bottom: 17px;
401 | position: relative;
402 | }
403 | .userimg{
404 | width: 48px;
405 | height: 48px;
406 | border-radius: 50%;
407 | overflow: hidden;
408 | display: flex;
409 | justify-content: center;
410 | align-items: center;
411 | }
412 | .userimg>img{
413 | height: 48px;
414 | margin-left: 5px;
415 | }
416 | .info-box{
417 | margin-left: 16px;
418 | }
419 | .info-box>div{
420 | max-width: 196px;
421 | height: 24px;
422 | font-size: 16px;
423 | font-weight: 400;
424 | overflow: hidden;
425 | text-overflow: ellipsis;
426 | white-space: nowrap;
427 | }
428 | .info-box .userName{
429 | color: #252933;
430 | display: flex;
431 | align-items: center;
432 | }
433 | .userName>span{
434 | max-width: 155px;
435 | overflow: hidden;
436 | text-overflow: ellipsis;
437 | white-space: nowrap;
438 | }
439 | .userName>img{
440 | width: 35px;
441 | height: 16px;
442 | }
443 | .info-box .position{
444 | color: #515767;
445 | }
446 |
447 | .stat-item{
448 | margin-top: 17px;
449 | display: flex;
450 | font-size: 15px;
451 | line-height: 25px;
452 | color: #252933;
453 | }
454 | .stat-item>div{
455 | width: 25px;
456 | height: 25px;
457 | border-radius: 50%;
458 | background: #e1efff;
459 | margin-right: 12px;
460 | display: flex;
461 | justify-content: center;
462 | align-items: center;
463 | }
464 | .stat-item img{
465 | width: 16px;
466 | height: 16px;
467 | }
468 | .user-item::after{
469 | content: '';
470 | position: absolute;
471 | bottom: 0;
472 | width: 100%;
473 | height: 1px;
474 | background: rgba(0, 0, 0, 0.178);
475 | transform: scaleY(.5);
476 | }
477 |
478 |
479 | /* 文章目录 */
480 | ul{
481 | list-style: none;
482 | }
483 | a{
484 | text-decoration: none;
485 | color: #515767;
486 | }
487 | .sticky-block-box{
488 | /* height: 524px; */
489 | }
490 | .sticky-title{
491 | position: relative;
492 | margin: 0 20px;
493 | padding: 16px 0;
494 | }
495 | .sticky-title::after{
496 | content: '';
497 | position: absolute;
498 | bottom: 0px;
499 | left: 0px;
500 | width: 100%;
501 | height: 1px;
502 | background: rgba(0, 0, 0, 0.178);
503 | transform: scaleY(.5);
504 | }
505 |
506 | .sticky-content{
507 | width: 100%;
508 | max-height: 460px;
509 | overflow-y: scroll;
510 | padding: 20px 5px;
511 | box-sizing: border-box;
512 | }
513 |
514 | /* 目录滑动条样式 */
515 | .sticky-content::-webkit-scrollbar{
516 | width: 6px;
517 | }
518 | .sticky-content::-webkit-scrollbar-thumb{
519 | border-radius: 10px;
520 | background: #c2c8d19b;
521 | margin-left: 10px;
522 | }
523 |
524 | .sticky-list{
525 | width: 100%;
526 | padding-left: 20px;
527 | box-sizing: border-box;
528 | position: relative;
529 |
530 | }
531 | .a-container{
532 | height: 44px;
533 | border-radius: 4px;
534 | font-size: 14px;
535 | color: #515767;
536 | line-height: 44px;
537 | padding-left: 5px;
538 | box-sizing: border-box;
539 |
540 | }
541 | .a-container:hover{
542 | background: #f7f8fa;
543 | }
544 |
545 | .first::after{
546 | content: '';
547 | position: absolute;
548 | top: 13px;
549 | /* 距离下一个标签 top增加53px */
550 | left: 0;
551 | width: 5px;
552 | height: 18px;
553 | background: #1e80ff;
554 | border-radius: 3px;
555 | }
556 |
557 | /* 侧边栏 结束 */
558 |
559 |
560 | /* 左侧功能栏 */
561 | .article-suspended-panel{
562 | width: 48px;
563 | height: 300px;
564 | /* background: rgba(0, 0, 0, 0.157); */
565 | position: fixed;
566 | top: 140px;
567 | left: 100px;
568 | }
569 | .panel-btn{
570 | width: 100%;
571 | height: 48px;
572 | border-radius: 50%;
573 | background: #fff;
574 | margin-bottom: 20px;
575 | box-shadow: 1px 1px 20px #dadddd;
576 |
577 | display: flex;
578 | justify-content: center;
579 | align-items: center;
580 |
581 | }
582 | .panel-btn>img{
583 | width: 17px;
584 | height: 17px;
585 | }
586 | .panel-btn:nth-child(4){
587 | margin-bottom: 40px;
588 | position: relative;
589 | }
590 | .panel-btn:nth-child(4)::after{
591 | content: '';
592 | position: absolute;
593 | bottom: -20px;
594 | width: 30px;
595 | height: 1px;
596 | background: rgba(0, 0, 0, 0.157);
597 | transform: scaleY(.5);
598 | }
--------------------------------------------------------------------------------
/project/article.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Document
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
分布式架构下的几个关键问题分布式架构下的几个关键问题分布式架构下的几个关键问题
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
想不到一个好的ID
30 |
31 |
32 |
33 | 2022年08月07日 22:23
34 | 阅读 167
35 |
36 |
37 |
+ 关注
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
分类:
51 | 后端
52 |
53 |
标签:
54 | 后端
55 | 后端
56 | 后端
57 |
58 |
59 |
60 |
61 |
62 |
190 |
191 |
192 |
193 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
--------------------------------------------------------------------------------
/project/page__header.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --juejin-brand-1-normal: #1e80ff;
3 | --juejin-brand-2-hover: #1171ee;
4 | --juejin-brand-3-click: #0060dd;
5 | --juejin-brand-4-disable: #abcdff;
6 | --juejin-brand-5-light: #eaf2ff;
7 | --juejin-font-1: #252933;
8 | --juejin-font-2: #515767;
9 | --juejin-font-3: #8a919f;
10 | --juejin-font-4: #c2c8d1;
11 | }
12 |
13 | * {
14 | margin: 0;
15 | padding: 0;
16 | }
17 |
18 | html,
19 | body {
20 | background-color: #d6d4cb48;
21 | }
22 |
23 | a {
24 | text-decoration: none;
25 | color: var(--juejin-font-3);
26 | }
27 |
28 | ul {
29 | list-style: none;
30 | }
31 |
32 | .list__contents a:hover {
33 | color: var(--juejin-font-1);
34 | }
35 |
36 | .juejin__page {
37 | width: 100%;
38 | height: 100%;
39 | }
40 |
41 | /* 导航栏部分 */
42 | .page__header {
43 | width: 100%;
44 | height: 106px;
45 | position: fixed;
46 | background: rgb(255, 255, 255);
47 | z-index: 5;
48 | }
49 |
50 | .page__header__nav {
51 | width: 100%;
52 | height: 60px;
53 | display: flex;
54 | justify-content: center;
55 | position: relative;
56 | }
57 |
58 | .page__header__nav::after {
59 | content: '';
60 | position: absolute;
61 | bottom: 0;
62 | width: 100%;
63 | height: 1px;
64 | background-color: var(--juejin-font-4);
65 | transform: scaleY(0.5);
66 | }
67 |
68 | /* 掘金图标 */
69 | .nav__sign {
70 | display: flex;
71 | }
72 |
73 | .logo__img {
74 | width: 107px;
75 | height: 22px;
76 | margin-left: 24px;
77 | margin-top: 20px;
78 | }
79 |
80 | /* 导航按钮 */
81 | .nav__main-list {
82 | height: 100%;
83 | display: flex;
84 | }
85 |
86 | .list-left {
87 | width: 37vw;
88 | }
89 |
90 | .list-left,
91 | .list-right {
92 | display: flex;
93 | }
94 |
95 | .list__contents {
96 | height: 100%;
97 | display: flex;
98 | margin-left: 10px;
99 | }
100 |
101 | .list__contents>li {
102 | display: flex;
103 | font-size: .9rem;
104 | align-items: center;
105 | margin: 0 .65rem;
106 | }
107 |
108 | .list__contents li a {
109 | display: inline-block;
110 | }
111 |
112 | /* 开放社区下拉框 */
113 | li>.community::after {
114 | content: '';
115 | /* 注意这里的伪类要为块级元素才能旋转 */
116 | display: inline-block;
117 | width: 0px;
118 | height: 0px;
119 | border: 4px solid #515761;
120 | border-left-color: transparent;
121 | border-right-color: transparent;
122 | border-bottom-color: transparent;
123 | position: relative;
124 | left: 2px;
125 | transform-origin: 50% 25%;
126 | transition: transform .5s ease-in-out;
127 | }
128 |
129 | .list__contents>li:nth-child(7):hover .community {
130 | color: var(--juejin-brand-1-normal);
131 | }
132 |
133 | .list__contents>li:nth-child(7):hover .community::after {
134 | border: 4px solid var(--juejin-brand-1-normal);
135 | border-left-color: transparent;
136 | border-right-color: transparent;
137 | border-bottom-color: transparent;
138 | transform: rotate(-180deg);
139 | }
140 |
141 | .list__contents>li:nth-child(7):hover .community__list {
142 | display: block;
143 | }
144 | .community__list{
145 | display: none;
146 | position: absolute;
147 | /* width: 200px; */
148 | padding: 5px;
149 | background: #fff;
150 | border-radius: 5px;
151 | box-shadow: 4px 0 70px #8a919f2f, -4px 0 70px #8a919f25, 0 4px 70px #8a919f3c;
152 | top: 52px;
153 | z-index: 10;
154 | }
155 | .community__list li {
156 | display: inline-block;
157 | /* width: 90px; */
158 | height: 26px;
159 | color: var(--juejin-font-2);
160 | line-height: 26px;
161 | padding: 6px 20px 5px 9px;
162 | }
163 |
164 | .community__list li:hover {
165 | background-color: #f2f3f5;
166 | border-radius: 3px;
167 | }
168 |
169 | .community__list span::before {
170 | content: '';
171 | display: inline-block;
172 | position: relative;
173 | top: 4px;
174 | width: 18px;
175 | height: 18px;
176 | margin: 0 12px 0 2px;
177 | }
178 |
179 | .community__list li:nth-child(1) span::before {
180 | background-image: url('../image/comm.png');
181 | background-size: 18px 18px;
182 | }
183 |
184 |
185 | /* 搜索框 */
186 | .input__frame{
187 | height: 36px;
188 | border: 1px solid #86909ccf;
189 | border-radius: 3px;
190 | display: flex;
191 | align-items: center;
192 | }
193 |
194 | .input:focus{
195 | outline: none;
196 | border-radius: 3px;
197 | }
198 | .input__frame:focus-within{
199 | /* width: 400px; */
200 | transform-origin: 0 0;
201 | /* transform: scaleX(1.32); */
202 | outline: 1px solid var(--juejin-brand-1-normal);
203 | }
204 | .input__frame:focus-within .input__sign{
205 | background: var(--juejin-brand-5-light);
206 | }
207 | .input__frame:focus-within .input__typehead{
208 | display: block;
209 | }
210 |
211 | .input__frame .input {
212 | flex: 1;
213 | height: 12px;
214 | border: none;
215 | padding: 12px 7px;
216 | -webkit-text-fill-color: var(--juejin-font-3);
217 | }
218 |
219 | .input__frame .input__sign {
220 | width: 44px;
221 | height: 30px;
222 | background: #86909c23;
223 | border-radius: 3px;
224 | margin-right: 3px;
225 | margin-left: 140px;
226 | }
227 |
228 | .input__sign .input__img{
229 | width: 16px;
230 | height: 16px;
231 | background-image: url('../image/input.png');
232 | background-size: 16px 16px;
233 | margin: 7px 15px;
234 | }
235 | .input__frame .input__typehead{
236 | display: none;
237 | position: absolute;
238 | top: 52px;
239 | width: auto;
240 | background: #fff;
241 | border: 1px solid #5157613d;
242 | border-radius: 2px;
243 | z-index: 10;
244 | font-size: .8rem;
245 | color: var(--juejin-font-3);
246 | }
247 | .input__typehead .title{
248 | width: 100%;
249 | display: flex;
250 | justify-content: space-between;
251 | position: relative;
252 | }
253 | .input__typehead>.title::after{
254 | content: '';
255 | position: absolute;
256 | width: 100%;
257 | height: 1px;
258 | bottom: 0;
259 | background-color: var(--juejin-font-4);
260 | transform: scaleY(.5);
261 | }
262 | .title>span{
263 | display: inline-block;
264 | margin: 10px;
265 | }
266 | .input__typehead .list .list-item{
267 | width: 342px;
268 | display: flex;
269 | padding: 10px;
270 | }
271 | .list-item:hover{
272 | background-color: #eff2f5;
273 | }
274 |
275 |
276 | /* 创作者中心 */
277 | .creator {
278 | /* width: 115px; */
279 | height: 36px;
280 | display: flex;
281 | }
282 |
283 | .creator .crea-btn {
284 | width: 80px;
285 | height: 100%;
286 | font-size: .8rem;
287 | color: #fff;
288 | background-color: var(--juejin-brand-1-normal);
289 | border: none;
290 | border-radius: 3px 0 0 3px;
291 | position: relative;
292 | }
293 |
294 | .crea-btn::after {
295 | content: '';
296 | position: absolute;
297 | top: 0;
298 | right: 0;
299 | width: 1px;
300 | height: 36px;
301 | background-color: var(--juejin-brand-4-disable);
302 | transform: scaleX(0.3);
303 | }
304 |
305 | .creator .more {
306 | width: 20px;
307 | height: 100%;
308 | background-color: var(--juejin-brand-1-normal);
309 | border-radius: 0 3px 3px 0;
310 | }
311 |
312 | .more:hover,
313 | .crea-btn:hover {
314 | background-color: var(--juejin-brand-2-hover);
315 | }
316 |
317 | #dianj {
318 | display: none;
319 | }
320 |
321 | input:checked~ul {
322 | display: block;
323 | }
324 |
325 | input:checked~label .more__tri {
326 | transform-origin: 55% 75%;
327 | transform: rotateZ(225deg);
328 | }
329 |
330 | .more__tri {
331 | width: 0px;
332 | height: 0px;
333 | border: 4px solid #fff;
334 | border-left-color: transparent;
335 | border-top-color: transparent;
336 | transform: rotateZ(45deg);
337 | position: relative;
338 | top: 12px;
339 | left: 6px;
340 | }
341 |
342 | .more__list {
343 | display: none;
344 | position: absolute;
345 | width: 100px;
346 | padding: 5px;
347 | background: #fff;
348 | border-radius: 5px;
349 | box-shadow: 4px 0 70px #8a919f2f, -4px 0 70px #8a919f25, 0 4px 70px #8a919f3c;
350 | top: 52px;
351 | z-index: 10;
352 | }
353 |
354 | .more__list li {
355 | display: inline-block;
356 | width: 90px;
357 | height: 26px;
358 | color: var(--juejin-font-2);
359 | line-height: 26px;
360 | padding: 6px 1px 5px 9px;
361 | }
362 |
363 | .more__list li:hover {
364 | background-color: #f2f3f5;
365 | border-radius: 3px;
366 | }
367 |
368 | .more__list span::before {
369 | content: '';
370 | display: inline-block;
371 | position: relative;
372 | top: 2px;
373 | width: 18px;
374 | height: 18px;
375 | margin: 0 12px 0 2px;
376 | }
377 |
378 | .more__list li:nth-child(1) span::before {
379 | background-image: url('../image/pencil.png');
380 | background-size: 18px 18px;
381 | }
382 |
383 | .more__list li:nth-child(2) span::before {
384 | background-image: url('../image/dia.png');
385 | background-size: 18px 18px;
386 | }
387 |
388 |
389 |
390 | /* 会员 */
391 | .vip__title {
392 | height: 100%;
393 | display: flex;
394 | align-items: center;
395 | color: var(--juejin-font-3);
396 | }
397 |
398 | .vip__title .vip__img {
399 | width: 24px;
400 | height: 24px;
401 | margin-right: 5px;
402 | }
403 |
404 | /* 通知 */
405 | .inform {
406 | height: 100%;
407 | display: flex;
408 | align-items: center;
409 | }
410 |
411 | .inform__img {
412 | width: 24px;
413 | height: 24px;
414 | background-image: url('../image/inform-logo-off.png');
415 | background-size: 24px 24px;
416 | }
417 |
418 | .inform__img:hover {
419 | background-image: url('../image/inform-logo-on.png');
420 | }
421 |
422 | /* 用户头像 */
423 | .user {
424 | height: 100%;
425 | display: flex;
426 | align-items: center;
427 | }
428 |
429 | .user__img {
430 | width: 36px;
431 | /* transform: scale(1); */
432 | height: 36px;
433 | object-fit: cover;
434 | border-radius: 50%;
435 | }
436 |
437 | /* 标签页面 */
438 | .page__header__tag{
439 | width: 100%;
440 | height: 46px;
441 | /* background: rgba(17, 244, 96, 0.228); */
442 | }
443 | .page__header__tag::after {
444 | content: '';
445 | position: absolute;
446 | bottom: 0;
447 | width: 100%;
448 | height: 1px;
449 | background-color: var(--juejin-font-4);
450 | transform: scaleY(0.5);
451 | }
452 | .tag__contents{
453 | height: 100%;
454 | /* background: rgba(239, 24, 24, 0.199); */
455 | margin: 0 280px;
456 | display: flex;
457 | justify-content: space-between;
458 | }
459 | .tag__list{
460 | display: flex;
461 | height: 100%;
462 | }
463 | .tag__manage{
464 | display: flex;
465 | align-items: center;
466 | }
467 | .tag__manage > span{
468 | font-size: .9rem;
469 | color: var(--juejin-font-2);
470 | }
471 | .page__header__tag a:hover{
472 | color: var(--juejin-brand-1-normal);
473 | }
474 | .tag__list .list__contents{
475 | margin-left: 0;
476 | }
477 | .tag__list li:nth-child(1){
478 | margin-left: 0;
479 | }
480 |
--------------------------------------------------------------------------------
/project/page__main.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --juejin-brand-1-normal: #1e80ff;
3 | --juejin-brand-2-hover: #1171ee;
4 | --juejin-brand-3-click: #0060dd;
5 | --juejin-brand-4-disable: #abcdff;
6 | --juejin-brand-5-light: #eaf2ff;
7 | --juejin-font-1: #252933;
8 | --juejin-font-2: #515767;
9 | --juejin-font-3: #8a919f;
10 | --juejin-font-4: #c2c8d1;
11 | }
12 | .page__main{
13 | width: 98.93vw;
14 | /* height: 800px; */
15 | display: flex;
16 | /* background: rgba(0, 0, 0, 0.13); */
17 | }
18 | .page__main__contents{
19 | width: 960px;
20 | margin: 0 auto;
21 | /* background: rgba(50, 241, 16, 0.215); */
22 | margin-top: 115px;
23 | }
24 | .contents__list{
25 | width: 700px;
26 | /* height: 100%; */
27 | /* background: rgba(17, 0, 255, 0.142); */
28 | margin-right: 260px;
29 | }
30 | .list__header{
31 | width: 676px;
32 | /* height: 47px; */
33 | background: #fff;
34 | padding: 17px 12px;
35 | position: relative;
36 | }
37 | .list__content{
38 | width: 100%;
39 | /* height: 700px;s */
40 | background: #fff;
41 | }
42 | .article__list{
43 | width: 100%;
44 | }
45 | .list__item{
46 | /* width: 660px;
47 | height: 129px; */
48 | padding: 12px 20px 0 20px;
49 | position: relative;
50 | }
51 | .list__header::after{
52 | content: '';
53 | position: absolute;
54 | bottom: 0;
55 | left: 0;
56 | width: 100%;
57 | height: 1px;
58 | background: var(--juejin-font-4);
59 | transform: scaleY(.5);
60 | }
61 | .list__item::after{
62 | content: '';
63 | position: absolute;
64 | bottom: 0;
65 | left: 21px;
66 | width: 94%;
67 | height: 1px;
68 | background: var(--juejin-font-4);
69 | transform: scaleY(.5);
70 | }
71 |
72 | /* 内容头部标签 */
73 | .nav__list{
74 | display: flex;
75 | height: 19px;
76 | }
77 | .nav__list>ul{
78 | display: flex;
79 | }
80 | .nav__list li{
81 | font-size: .9rem;
82 | margin: 0 13px;
83 | position: relative;
84 | }
85 | .nav__list li:not(:last-child)::after{
86 | content: '';
87 | position: absolute;
88 | right: -13px;
89 | top: -5px;
90 | width: 1px;
91 | height: 155%;
92 | background: var(--juejin-font-4);
93 | transform: scaleY(.5);
94 | }
95 | .nav__list a:hover{
96 | color: var(--juejin-brand-1-normal);
97 | }
98 |
99 |
100 | /* 文章列表 */
101 | .list__item>.entry{
102 | display: flex;
103 | width: 100%;
104 | height: 100%;
105 | flex-wrap: wrap;
106 | }
107 | .article__inform{
108 | width: 100%;
109 | height: 22px;
110 | display: flex;
111 | }
112 | .article__content{
113 | width: 100%;
114 | height: 97px;
115 | display: flex;
116 | /* flex-direction: column; */
117 | }
118 | .article__inform>.nav__list li{
119 | font-size: .7rem;
120 | }
121 | .article__inform>.nav__list li:nth-child(1){
122 | margin-left: 0;
123 | }
124 |
125 | .content-main{
126 | width: 200px;
127 | flex: 1 0 auto;
128 | }
129 |
130 | .content-main .title{
131 | font-size: .9rem;
132 | color: #000;
133 | font-weight: bold;
134 | margin: 10px 0;
135 | }
136 |
137 | .content-main .abstract{
138 | /* width: 100px; */
139 | font-size: .8rem;
140 | color: red;
141 | margin-bottom: 10px;
142 | text-overflow: ellipsis;
143 | -webkit-box-orient: vertical;
144 | /* -webkit-line-clamp: 1 */
145 | overflow: hidden;
146 | white-space: nowrap;
147 | }
148 | .action-list{
149 | display: flex;
150 | font-size: 0.8em;
151 | color: var(--juejin-font-2);
152 |
153 | }
154 | .action-list .item{
155 | display: inline-block;
156 | margin-right: 20px;
157 | display: flex;
158 | }
159 | .action-list>li>i{
160 | display: block;
161 | width: 16px;
162 | height: 16px;
163 | background-size: 16px 16px;
164 | margin-right: 4px;
165 | }
166 | .action-list .eye{
167 | background-image: url("../image/eye.png");
168 | }
169 | .action-list .zan{
170 | background-image: url("../image/zan__off.png");
171 | }
172 | .action-list .cloud{
173 | margin-top: 2px;
174 | background-image: url("../image/cloud__off.png");
175 | }
176 | .action-list .zan:hover{
177 | background-image: url("../image/zan__on.png");
178 | }
179 | .action-list .cloud:hover{
180 | /* margin-top: 2px; */
181 | background-image: url("../image/cloud__on.png");
182 | }
183 |
184 |
185 |
186 | .article__content>img{
187 | width: 120px;
188 | height: 80px;
189 | margin-left: 24px;
190 | flex: 0 0 auto;
191 | border-radius: 2px;
192 | }
--------------------------------------------------------------------------------