Skip to content

Commit dbf33e4

Browse files
committedJan 2, 2024
✨ Implement day-09
1 parent e26815c commit dbf33e4

File tree

8 files changed

+405
-37
lines changed

8 files changed

+405
-37
lines changed
 

‎day-06/react-jike/craco.config.js

+37
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,46 @@
11
const path = require('path')
2+
const {whenProd, getPlugin, pluginByName} = require('@craco/craco')
23

34
module.exports = {
45
webpack: {
56
alias: {
67
'@': path.resolve(__dirname, 'src')
8+
},
9+
// 配置webpack
10+
// 配置CDN
11+
configure: (webpackConfig) => {
12+
let cdn = {
13+
js: []
14+
}
15+
whenProd(() => {
16+
// key: 不参与打包的包(由dependencies依赖项中的key决定)
17+
// value: cdn文件中 挂载于全局的变量名称 为了替换之前在开发环境下
18+
webpackConfig.externals = {
19+
react: 'React',
20+
'react-dom': 'ReactDOM'
21+
}
22+
// 配置现成的cdn资源地址
23+
// 实际开发的时候 用公司自己花钱买的cdn服务器
24+
cdn = {
25+
js: [
26+
'https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js',
27+
'https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js',
28+
]
29+
}
30+
})
31+
32+
// 通过 htmlWebpackPlugin插件 在public/index.html注入cdn资源url
33+
const {isFound, match} = getPlugin(
34+
webpackConfig,
35+
pluginByName('HtmlWebpackPlugin')
36+
)
37+
38+
if (isFound) {
39+
// 找到了HtmlWebpackPlugin的插件
40+
match.options.files = cdn
41+
}
42+
43+
return webpackConfig
744
}
845
}
946
}

‎day-06/react-jike/package.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
"react-redux": "^9.0.4",
1919
"react-router-dom": "^6.21.1",
2020
"react-scripts": "5.0.1",
21+
"source-map-explorer": "^2.5.3",
2122
"web-vitals": "^2.1.4"
2223
},
2324
"scripts": {
2425
"start": "craco start",
2526
"build": "craco build",
2627
"test": "craco test",
27-
"eject": "react-scripts eject"
28+
"eject": "react-scripts eject",
29+
"analyze": "source-map-explorer 'build/static/js/*.js'"
2830
},
2931
"eslintConfig": {
3032
"extends": [
@@ -45,7 +47,7 @@
4547
]
4648
},
4749
"devDependencies": {
48-
"craco": "^0.0.3",
50+
"@craco/craco": "^7.1.0",
4951
"sass": "^1.69.6"
5052
}
5153
}

‎day-06/react-jike/public/index.html

+4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
<body>
3030
<noscript>You need to enable JavaScript to run this app.</noscript>
3131
<div id="root"></div>
32+
<!-- 加载第三发包的 CDN 链接 -->
33+
<% htmlWebpackPlugin.options.files.js.forEach(cdnURL => { %>
34+
<script src="<%= cdnURL %>"></script>
35+
<% }) %>
3236
<!--
3337
This HTML file is a template.
3438
If you open it directly in the browser, you will see an empty page.

‎day-06/react-jike/src/apis/article.js

+22
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,25 @@ export function getArticleListAPI(params) {
2222
params
2323
})
2424
}
25+
26+
export function delArticleAPI(id) {
27+
return request({
28+
url: `/mp/articles/${id}`,
29+
method: 'DELETE'
30+
})
31+
}
32+
33+
export function getArticleByIdAPI(id) {
34+
return request({
35+
url: `/mp/articles/${id}`,
36+
method: 'GET'
37+
})
38+
}
39+
40+
export function updateArticleAPI(data) {
41+
return request({
42+
url: `/mp/articles/${data.id}?draft=false`,
43+
method: 'PUT',
44+
data
45+
})
46+
}

‎day-06/react-jike/src/pages/Article/index.js

+77-15
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1-
import {Link} from 'react-router-dom'
2-
import {Breadcrumb, Button, Card, DatePicker, Form, Radio, Select, Space, Table, Tag} from 'antd'
1+
import {Link, useNavigate} from 'react-router-dom'
2+
import {Breadcrumb, Button, Card, DatePicker, Form, Popconfirm, Radio, Select, Space, Table, Tag} from 'antd'
33
// 引入时间选择器汉化包
44
import locale from 'antd/es/date-picker/locale/zh_CN'
55
import {DeleteOutlined, EditOutlined} from '@ant-design/icons'
66
import img404 from '@/assets/error.png'
77
import {useChannelList} from "@/hooks/useChannelList"
88
import {useEffect, useState} from "react"
9-
import {getArticleListAPI} from "@/apis/article"
9+
import {delArticleAPI, getArticleListAPI} from "@/apis/article"
1010

1111
const {Option} = Select
1212
const {RangePicker} = DatePicker
1313

1414
const Article = () => {
1515
const {channelList} = useChannelList()
16+
const navigate = useNavigate()
1617

1718
// 定义 status 枚举
1819
const status = {
@@ -62,30 +63,83 @@ const Article = () => {
6263
render: data => {
6364
return (
6465
<Space size="middle">
65-
<Button type="primary" shape="circle" icon={<EditOutlined />} />
66-
<Button
67-
type="primary"
68-
danger
69-
shape="circle"
70-
icon={<DeleteOutlined />}
71-
/>
66+
<Button type="primary" shape="circle" icon={<EditOutlined />}
67+
onClick={() => navigate(`/publish?id=${data.id}`)}/>
68+
<Popconfirm
69+
placement="top"
70+
title="删除文章"
71+
description="确认要删除当前文章吗"
72+
okText="Yes"
73+
cancelText="No"
74+
onConfirm={() => onDelConfirm(data)}
75+
>
76+
<Button
77+
type="primary"
78+
danger
79+
shape="circle"
80+
icon={<DeleteOutlined />}
81+
/>
82+
</Popconfirm>
7283
</Space>
7384
)
7485
}
7586
}
7687
]
7788

89+
// 筛选功能
90+
// 1. 准备参数
91+
const [reqData, setReqData] = useState({
92+
status: '',
93+
channel_id: '',
94+
begin_pubdate: '',
95+
end_pubdate: '',
96+
page: 1,
97+
per_page: 4
98+
})
99+
100+
// 2. 获取筛选数据
101+
const onFinish = (formValue) => {
102+
// 3. 把表单数据放到参数中
103+
setReqData({
104+
...reqData,
105+
channel_id: formValue.channel_id,
106+
status: formValue.status,
107+
begin_pubdate: formValue.date[0].format('YYYY-MM-DD'),
108+
end_pubdate: formValue.date[1].format('YYYY-MM-DD')
109+
})
110+
}
111+
112+
// 4. 重新拉取文章列表 + 渲染 table 逻辑(复用)
113+
// 由 reqData 依赖项变化,重复执行 useEffect
114+
115+
// 分页
116+
const onPageChange = (page) => {
117+
setReqData({
118+
...reqData,
119+
page: page.current
120+
})
121+
}
122+
78123
// 获取文章列表
79124
const [articleList, setArticleList] = useState([])
80125
const [articleCount, setArticleCount] = useState(0)
81126
useEffect(() => {
82127
async function getList() {
83-
const res = await getArticleListAPI()
128+
const res = await getArticleListAPI(reqData)
84129
setArticleList(res.data.results)
85130
setArticleCount(res.data.total_count)
86131
}
132+
87133
getList()
88-
}, []);
134+
}, [reqData])
135+
136+
// 删除
137+
const onDelConfirm = async (data) => {
138+
await delArticleAPI(data['id'])
139+
setReqData({
140+
...reqData
141+
})
142+
}
89143

90144
return (
91145
<div>
@@ -98,7 +152,7 @@ const Article = () => {
98152
}
99153
style={{marginBottom: 20}}
100154
>
101-
<Form initialValues={{status: ''}}>
155+
<Form initialValues={{status: ''}} onFinish={onFinish}>
102156
<Form.Item label="状态" name="status">
103157
<Radio.Group>
104158
<Radio value={''}>全部</Radio>
@@ -110,7 +164,6 @@ const Article = () => {
110164
<Form.Item label="频道" name="channel_id">
111165
<Select
112166
placeholder="请选择文章频道"
113-
defaultValue="lucy"
114167
style={{width: 120}}
115168
>
116169
{channelList.map(item => <Option key={item.id} value={item.id}>{item.name}</Option>)}
@@ -130,7 +183,16 @@ const Article = () => {
130183
</Form>
131184
</Card>
132185
<Card title={`根据筛选条件共查询到 ${articleCount} 条结果:`}>
133-
<Table rowKey="id" columns={columns} dataSource={articleList} />
186+
<Table
187+
rowKey="id"
188+
columns={columns}
189+
pagination={{
190+
total: articleCount,
191+
pageSize: reqData.per_page
192+
}}
193+
onChange={onPageChange}
194+
dataSource={articleList}
195+
/>
134196
</Card>
135197
</div>
136198
)

‎day-06/react-jike/src/pages/Publish/index.js

+49-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import {Breadcrumb, Button, Card, Form, Input, message, Radio, Select, Space, Upload} from 'antd'
2-
import {Link} from 'react-router-dom'
2+
import {Link, useSearchParams} from 'react-router-dom'
33
import './index.scss'
44
import ReactQuill from "react-quill"
55
import 'react-quill/dist/quill.snow.css'
6-
import {useState} from "react"
7-
import {createArticleAPI} from "@/apis/article"
6+
import {useEffect, useState} from "react"
7+
import {createArticleAPI, getArticleByIdAPI, updateArticleAPI} from "@/apis/article"
88
import {PlusOutlined} from "@ant-design/icons"
99
import {useChannelList} from "@/hooks/useChannelList"
10+
import article from "@/pages/Article"
1011

1112
const {Option} = Select
1213

@@ -26,11 +27,24 @@ const Publish = () => {
2627
content,
2728
cover: {
2829
type: imageType,
29-
images: imageList.map(item => item.response.data.url)
30+
images: imageList.map(item => {
31+
if (item.response) {
32+
// 只有新增才能按这个逻辑
33+
return item.response.data.url
34+
} else {
35+
return item.url
36+
}
37+
})
3038
},
3139
channel_id
3240
}
33-
createArticleAPI(reqData)
41+
if (articleId) {
42+
// 编辑
43+
updateArticleAPI({...reqData, id: articleId})
44+
} else {
45+
// 新增
46+
createArticleAPI(reqData)
47+
}
3448
}
3549

3650
// 上传图片回调
@@ -45,13 +59,40 @@ const Publish = () => {
4559
setImageType(e.target.value)
4660
}
4761

62+
// 回填数据
63+
const [searchParams] = useSearchParams()
64+
const articleId = searchParams.get('id')
65+
// 获取实例
66+
const [form] = Form.useForm()
67+
useEffect(() => {
68+
async function getArticleDetail() {
69+
const res = await getArticleByIdAPI(articleId)
70+
const data = res.data
71+
const {cover} = data
72+
form.setFieldsValue({
73+
...data,
74+
type: cover.type,
75+
})
76+
// 为什么现在的写法无法回填封面?
77+
// 数据结构不一样
78+
setImageType(cover.type)
79+
setImageList(cover.images.map(url => {
80+
return {url}
81+
}))
82+
}
83+
// 只有有 id 的时候才调用
84+
if (articleId) {
85+
getArticleDetail()
86+
}
87+
}, [articleId, form]);
88+
4889
return (
4990
<div className="publish">
5091
<Card
5192
title={
5293
<Breadcrumb items={[
5394
{title: <Link to={'/'}>首页</Link>},
54-
{title: '发布文章'},
95+
{title: `${articleId ? '编辑' : '发布'}文章`},
5596
]}
5697
/>
5798
}
@@ -61,6 +102,7 @@ const Publish = () => {
61102
wrapperCol={{span: 16}}
62103
initialValues={{type: 0}}
63104
onFinish={onFinish}
105+
form={form}
64106
>
65107
<Form.Item
66108
label="标题"
@@ -93,6 +135,7 @@ const Publish = () => {
93135
action='http://geek.itheima.net/v1_0/upload'
94136
onChange={onChange}
95137
maxCount={imageType}
138+
fileList={imageList}
96139
>
97140
<div style={{marginTop: 8}}>
98141
<PlusOutlined />

‎day-06/react-jike/src/router/index.js

+13-6
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,16 @@ import {createBrowserRouter} from "react-router-dom"
22
import Login from "@/pages/Login"
33
import Layout from "@/pages/Layout"
44
import {AuthRoute} from "@/compenents/AuthRoute"
5-
import Home from "@/pages/Home"
6-
import Article from "@/pages/Article"
7-
import Publish from "@/pages/Publish"
5+
// import Home from "@/pages/Home"
6+
// import Article from "@/pages/Article"
7+
// import Publish from "@/pages/Publish"
8+
import {lazy, Suspense} from "react"
9+
10+
// 1. lazy 函数对组件进行导入
11+
const Home = lazy(() => import('@/pages/Home'))
12+
const Article = lazy(() => import('@/pages/Article'))
13+
const Publish = lazy(() => import('@/pages/Publish'))
14+
815

916
const router = createBrowserRouter([
1017
{
@@ -13,15 +20,15 @@ const router = createBrowserRouter([
1320
children: [
1421
{
1522
index: '/',
16-
element: <Home />
23+
element: <Suspense fallback={'加载中'}><Home /></Suspense>
1724
},
1825
{
1926
path: 'article',
20-
element: <Article />
27+
element: <Suspense fallback={'加载中'}><Article /></Suspense>
2128
},
2229
{
2330
path: 'publish',
24-
element: <Publish />
31+
element: <Suspense fallback={'加载中'}><Publish /></Suspense>
2532
},
2633
]
2734
},

‎day-06/react-jike/yarn.lock

+199-8
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.