Browse Source

PC项目

master
MYW 2 years ago
parent
commit
6e653f39f3
  1. 18
      react-pc-project/craco.config.js
  2. 560
      react-pc-project/package-lock.json
  3. 4
      react-pc-project/package.json
  4. 42
      react-pc-project/public/index.html
  5. 21
      react-pc-project/src/App.js
  6. 8
      react-pc-project/src/components/Bar/index.js
  7. 38
      react-pc-project/src/components/Bar/line.js
  8. 32
      react-pc-project/src/pages/Article/index.js
  9. 24
      react-pc-project/src/pages/Home/index.js
  10. 5
      react-pc-project/src/pages/Layout/index.js
  11. 154
      react-pc-project/src/pages/Publish/index.js
  12. 5
      react-pc-project/src/utils/index.js

18
react-pc-project/craco.config.js

@ -1,14 +1,14 @@
// 配置别名路径
// 添加自定义对于webpack的配置
// 添加自定义对于 webpack 的配置
const path = require('path')
module.exports = {
// webpack 配置
webpack: {
// 配置别名
alias: {
'@': path.resolve(__dirname, 'src')
}
}
// webpack 配置
webpack: {
// 配置别名
alias: {
// 约定:使用 @ 表示 src 文件所在路径
'@': path.resolve(__dirname, 'src')
},
}
}

560
react-pc-project/package-lock.json

@ -22,6 +22,7 @@
"react-quill": "^1.3.5",
"react-router-dom": "^6.3.0",
"react-scripts": "^4.0.0",
"source-map-explorer": "^2.5.2",
"web-vitals": "^2.1.4"
},
"devDependencies": {
@ -5529,6 +5530,17 @@
"node-int64": "^0.4.0"
}
},
"node_modules/btoa": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
"bin": {
"btoa": "bin/btoa.js"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/buffer": {
"version": "4.9.2",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
@ -9229,6 +9241,33 @@
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"optional": true
},
"node_modules/filelist": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
"integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
"dependencies": {
"minimatch": "^5.0.1"
}
},
"node_modules/filelist/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/filelist/node_modules/minimatch": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
"integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=10"
}
},
"node_modules/filesize": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
@ -11246,6 +11285,92 @@
"node": ">=8"
}
},
"node_modules/jake": {
"version": "10.8.5",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz",
"integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==",
"dependencies": {
"async": "^3.2.3",
"chalk": "^4.0.2",
"filelist": "^1.0.1",
"minimatch": "^3.0.4"
},
"bin": {
"jake": "bin/cli.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/jake/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/jake/node_modules/async": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ=="
},
"node_modules/jake/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/jake/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/jake/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/jake/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/jake/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/jest": {
"version": "26.6.0",
"resolved": "https://registry.npmjs.org/jest/-/jest-26.6.0.tgz",
@ -19252,6 +19377,183 @@
"node": ">= 8"
}
},
"node_modules/source-map-explorer": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/source-map-explorer/-/source-map-explorer-2.5.2.tgz",
"integrity": "sha512-gBwOyCcHPHcdLbgw6Y6kgoH1uLKL6hN3zz0xJcNI2lpnElZliIlmSYAjUVwAWnc7+HscoTyh1ScR7ITtFuEnxg==",
"dependencies": {
"btoa": "^1.2.1",
"chalk": "^4.1.0",
"convert-source-map": "^1.7.0",
"ejs": "^3.1.5",
"escape-html": "^1.0.3",
"glob": "^7.1.6",
"gzip-size": "^6.0.0",
"lodash": "^4.17.20",
"open": "^7.3.1",
"source-map": "^0.7.3",
"temp": "^0.9.4",
"yargs": "^16.2.0"
},
"bin": {
"sme": "bin/cli.js",
"source-map-explorer": "bin/cli.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/source-map-explorer/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/source-map-explorer/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/source-map-explorer/node_modules/cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^7.0.0"
}
},
"node_modules/source-map-explorer/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/source-map-explorer/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/source-map-explorer/node_modules/ejs": {
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz",
"integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==",
"dependencies": {
"jake": "^10.8.5"
},
"bin": {
"ejs": "bin/cli.js"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-explorer/node_modules/gzip-size": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz",
"integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==",
"dependencies": {
"duplexer": "^0.1.2"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/source-map-explorer/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/source-map-explorer/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/source-map-explorer/node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/source-map-explorer/node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"engines": {
"node": ">=10"
}
},
"node_modules/source-map-explorer/node_modules/yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dependencies": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
},
"engines": {
"node": ">=10"
}
},
"node_modules/source-map-explorer/node_modules/yargs-parser": {
"version": "20.2.9",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"engines": {
"node": ">=10"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
@ -20014,6 +20316,18 @@
"node": ">=10"
}
},
"node_modules/temp": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz",
"integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==",
"dependencies": {
"mkdirp": "^0.5.1",
"rimraf": "~2.6.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/temp-dir": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz",
@ -20022,6 +20336,17 @@
"node": ">=4"
}
},
"node_modules/temp/node_modules/rimraf": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
}
},
"node_modules/tempy": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/tempy/-/tempy-0.3.0.tgz",
@ -26917,6 +27242,11 @@
"node-int64": "^0.4.0"
}
},
"btoa": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g=="
},
"buffer": {
"version": "4.9.2",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
@ -29734,6 +30064,32 @@
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"optional": true
},
"filelist": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
"integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
"requires": {
"minimatch": "^5.0.1"
},
"dependencies": {
"brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"requires": {
"balanced-match": "^1.0.0"
}
},
"minimatch": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
"integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
"requires": {
"brace-expansion": "^2.0.1"
}
}
}
},
"filesize": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
@ -31225,6 +31581,67 @@
"istanbul-lib-report": "^3.0.0"
}
},
"jake": {
"version": "10.8.5",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz",
"integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==",
"requires": {
"async": "^3.2.3",
"chalk": "^4.0.2",
"filelist": "^1.0.1",
"minimatch": "^3.0.4"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"requires": {
"color-convert": "^2.0.1"
}
},
"async": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ=="
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"jest": {
"version": "26.6.0",
"resolved": "https://registry.npmjs.org/jest/-/jest-26.6.0.tgz",
@ -37420,6 +37837,130 @@
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="
},
"source-map-explorer": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/source-map-explorer/-/source-map-explorer-2.5.2.tgz",
"integrity": "sha512-gBwOyCcHPHcdLbgw6Y6kgoH1uLKL6hN3zz0xJcNI2lpnElZliIlmSYAjUVwAWnc7+HscoTyh1ScR7ITtFuEnxg==",
"requires": {
"btoa": "^1.2.1",
"chalk": "^4.1.0",
"convert-source-map": "^1.7.0",
"ejs": "^3.1.5",
"escape-html": "^1.0.3",
"glob": "^7.1.6",
"gzip-size": "^6.0.0",
"lodash": "^4.17.20",
"open": "^7.3.1",
"source-map": "^0.7.3",
"temp": "^0.9.4",
"yargs": "^16.2.0"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^7.0.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"ejs": {
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz",
"integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==",
"requires": {
"jake": "^10.8.5"
}
},
"gzip-size": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz",
"integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==",
"requires": {
"duplexer": "^0.1.2"
}
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"requires": {
"has-flag": "^4.0.0"
}
},
"wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
}
},
"y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
},
"yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"requires": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
}
},
"yargs-parser": {
"version": "20.2.9",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="
}
}
},
"source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
@ -38031,6 +38572,25 @@
}
}
},
"temp": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz",
"integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==",
"requires": {
"mkdirp": "^0.5.1",
"rimraf": "~2.6.2"
},
"dependencies": {
"rimraf": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"requires": {
"glob": "^7.1.3"
}
}
}
},
"temp-dir": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz",

4
react-pc-project/package.json

@ -17,13 +17,15 @@
"react-quill": "^1.3.5",
"react-router-dom": "^6.3.0",
"react-scripts": "^4.0.0",
"source-map-explorer": "^2.5.2",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject"
"eject": "react-scripts eject",
"report": "source-map-explorer 'build/static/js/*.js'"
},
"eslintConfig": {
"extends": [

42
react-pc-project/public/index.html

@ -1,21 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Web site created using create-react-app" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
@ -24,12 +22,13 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
@ -39,5 +38,6 @@
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
</body>
</html>

21
react-pc-project/src/App.js

@ -1,18 +1,25 @@
import { unstable_HistoryRouter, BrowserRouter as HistoryRouter, Routes, Route} from 'react-router-dom'
import { unstable_HistoryRouter as HistoryRouter, Routes, Route} from 'react-router-dom'
import { history } from './utils/history'
import Layout from '@/pages/Layout'
import Login from '@/pages/Login'
import Home from '@/pages/Home'
import Article from '@/pages/Article'
import Publish from '@/pages/Publish'
import { AuthComponent } from '@/components/AuthComponent'
import './App.css'
import { lazy, Suspense } from 'react'
import { Spin } from 'antd'
const Login = lazy(() => import('./pages/Login'))
const Layout = lazy(() => import('./pages/Layout'))
const Home = lazy(() => import('./pages/Home'))
const Article = lazy(() => import('./pages/Article'))
const Publish = lazy(() => import('./pages/Publish'))
function App() {
return (
// 路由配置
<HistoryRouter history={history}>
<div className="App">
<Suspense
fallback={
<div style={{textAlign: 'center', marginTop: 500}}>{<Spin />}</div>
}>
<Routes>
{/* 创建路由 path 和组件对应关系 */}
{/* Layout 需要鉴权处理, 这里的 Layout 一定不能写死,要根据是否登录进行判断 */}
@ -20,12 +27,14 @@ function App() {
<AuthComponent><Layout/></AuthComponent>
}>
<Route index element={<Home/>}></Route>
<Route path='home' element={<Home/>}></Route>
<Route path='article' element={<Article/>}></Route>
<Route path='publish' element={<Publish/>}></Route>
</Route>
<Route path='/login' element={<Login/>}></Route>
</Routes>
</Suspense>
</div>
</HistoryRouter>
);

8
react-pc-project/src/components/Bar/index.js

@ -3,7 +3,7 @@
import * as echarts from 'echarts'
import { useEffect, useRef } from 'react';
function Bar ({title, xData, yData, style}) {
function Bar({ title, xData, yData, style }) {
// 获取一个 DOM 元素
const domRef = useRef()
@ -22,7 +22,7 @@ function Bar ({title, xData, yData, style}) {
yAxis: {},
series: [
{
name: '销量',
name: '满意度',
type: 'bar',
data: yData
}
@ -30,9 +30,11 @@ function Bar ({title, xData, yData, style}) {
});
}
// 执行初始化函数
useEffect(() => {
chartInit()
chartInit();
}, [])
return (

38
react-pc-project/src/components/Bar/line.js

@ -0,0 +1,38 @@
import * as echarts from 'echarts'
import { useEffect, useRef } from 'react';
function Line ({ title, xData, yData, style }) {
const domRef = useRef()
const charLine = () => {
const MychartLine = echarts.init(domRef.current)
MychartLine.setOption({
title: {
text: title
},
xAxis: {
data: xData
},
yAxis: {},
series: [
{
name: '满意度',
data: yData,
type: 'line'
}
]
})
}
useEffect(() => {
charLine()
}, [])
return (
<div>
<div ref={domRef} style={style}></div>
</div>
)
}
export default Line

32
react-pc-project/src/pages/Article/index.js

@ -56,23 +56,24 @@ const Article = () => {
loadList()
}, [params])
// 筛选
// 表单筛选
const onFinish = (values) => {
console.log(values)
const { channel_id, date, status } = values
// 数据处理
const _params = {}
if (status !== -1) {
_params.status = status
}
_params.status = status
// 初始化频道
if (channel_id) {
_params.channel_id = channel_id
}
// 初始化时间
if (date) {
// 开始日期
_params.begin_pubdate = date[0].format('YYY-MM-DD')
_params.begin_pubdate = date[0].format('YYYY-MM-DD')
// 结束日期
_params.end_pubdate = date[1].format('YYY-MM-DD')
_params.end_pubdate = date[1].format('YYYY-MM-DD')
}
// 修改 params 数据,引起接口的重新发送,数据的字段是做一个对象的合并,对象的合并是一个整体的覆盖,改变了对象的整体应用
// 以下是不覆盖整体对象:
@ -90,6 +91,14 @@ const Article = () => {
})
}
const formatStatus = (type) => {
const TYPES = {
1: <Tag color="red">审核失败</Tag>,
2: <Tag color="green">审核成功</Tag>
}
return TYPES[type]
}
// 删除
const delArticle = async (data) => {
await http.delete(`/mp/articles/${data.id}`)
@ -124,7 +133,7 @@ const Article = () => {
{
title: '状态',
dataIndex: 'status',
render: data => <Tag color="green">审核通过</Tag>
render: data => formatStatus(data)
},
{
title: '发布时间',
@ -173,7 +182,8 @@ const Article = () => {
</Popconfirm>
</Space>
)
}
},
fixed: 'right'
}
]
@ -210,7 +220,7 @@ const Article = () => {
style={{ width: 120 }}
>
{channelStore.channelList.map(channel => <Option key={channel.id} value="channel.id">{channel.name}</Option>)}
{channelStore.channelList.map(channel => <Option key={channel.id} value={channel.id}>{channel.name}</Option>)}
</Select>
</Form.Item>
@ -237,8 +247,10 @@ const Article = () => {
pagination={{
pageSize: params.per_page,
total: articleData.count,
onChange: pageChange
onChange: pageChange,
current: params.page
}}
bordered
/>
</Card>
</div>

24
react-pc-project/src/pages/Home/index.js

@ -7,23 +7,25 @@ import './index.scss'
* 3.按照需求哪些参数需要自定义抽象出来
*/
import Bar from '@/components/Bar'
import Bar from '@/components/Bar/index'
import Line from '@/components/Bar/line'
function Home() {
return (
<div>
{/* 渲染 Bar 组件 */}
<Bar
title='主流框架使用满意的度'
xData={['react', 'vue', 'angular']}
yData={[30, 40, 50]}
style={{ width: '500px', height: '400px' }}/>
<Bar
title='主流语言使用满意的度'
xData={['JavaScript', 'C++', 'Java', 'PHP', 'Python']}
yData={[30, 40, 50, 20, 40, 60]}
style={{ width: '500px', height: '400px', float: 'left' }} />
<Bar
title='主流框架使用满意的度2'
xData={['react', 'vue', 'angular']}
yData={[60, 70, 80]}
style={{ width: '300px', height: '200px' }}/>
<Line
title='主流语言使用满意的度'
xData={['JavaScript', 'C++', 'Java', 'PHP', 'Python']}
yData={[30, 40, 50, 20, 40, 60]}
style={{ width: '500px', height: '400px', marginLeft: '800px' }}
/>
</div>
)
}

5
react-pc-project/src/pages/Layout/index.js

@ -49,10 +49,15 @@ const GeekLayout = () => {
<Layout>
<Sider width={200} className="site-layout-background">
{/* 高亮原理: defaultSelectedKeys 对应 Item 的 key,需要获取当前激活的 path 路径 */}
{/*
defaultSelectedKeys: 初始化渲染的时候生效一次
selectedKeys: 每次有值更新时都会重新渲染视图
*/}
<Menu
mode="inline"
theme="dark"
defaultSelectedKeys={[pathname]}
selectedKeys = {pathname}
style={{ height: '100%', borderRight: 0 }}
>
<Menu.Item icon={<HomeOutlined />} key="/">

154
react-pc-project/src/pages/Publish/index.js

@ -7,16 +7,18 @@ import {
Input,
Upload,
Space,
Select
Select,
message
} from 'antd'
import { PlusOutlined } from '@ant-design/icons'
import { Link } from 'react-router-dom'
import { Link, useNavigate, useSearchParams } from 'react-router-dom'
import './index.scss'
import ReactQuill from 'react-quill'
import 'react-quill/dist/quill.snow.css'
import { useStore } from '@/store'
import { observer } from 'mobx-react-lite'
import { useState } from 'react'
import { useState, useRef, useEffect } from 'react'
import { http } from '@/utils'
const { Option } = Select
@ -24,14 +26,111 @@ const Publish = () => {
const { channelStore } = useStore()
// 存放上传图片的列表
const { fileList, setFileList } = useState([])
const [fileList, setFileList] = useState([])
const onUploadChange = ({fileList}) => {
console.log(fileList)
// 采取受控的写法,在最后一次 log 里 response,最终 react state fileList 中存放的数据有 response.data.url
setFileList(fileList)
// 使用 useRef 声明一个暂存仓库
const cacheImgList = useRef([])
// 这个函数的执行分阶段,是从 updating 到 done 的过程,这个过程只要上传图片内容发生变化就会不断执行,直到全部上传完毕
const onUploadChange = ({ fileList }) => {
// 需要做数据格式化
const formatList = fileList.map(file => {
// 上传完毕,做数据处理
if (file.response) {
return {
url: file.response.data.url
}
}
return file
})
setFileList(formatList)
// 同时把图片列表存入仓库一份
cacheImgList.current = fileList
}
// 切换图片
const [imgCount, setImageCount] = useState(1)
const radioChange = (e) => {
console.log(e.target.value)
// 这里的判断依据是采取原始值,不采取经过 useState 方法修改之后的数据(因为 useState 修改之后的数据,无法同步获取修改之后的新值)
const rawValue = e.target.value
setImageCount(rawValue)
// 从仓库里面取对应的图片数量,交给用来渲染图片列表的 fileList
// 通过调用 setFileList,进行一个数据的变化
if (cacheImgList.current.length === 0) {
return false
}
// 如果是单图模式,就从仓库里取第一张图,以数组的形式存入fileList
if (rawValue === 1) {
const img = cacheImgList.current ? cacheImgList.current[0] : []
setFileList([img])
// 如果是三图模式,就把仓库里所有的图片,以数组的形式存入fileList
} else if (rawValue === 3) {
setFileList(cacheImgList.current)
}
}
// 提交表单
const navigate = useNavigate()
const onFinish = async (values) => {
console.log(values)
// 数据的二次处理,重点是处理 cover 字段
const { channel_id, content, title, type } = values
const params = {
channel_id,
content,
title,
type,
cover: {
type: type,
images: fileList.map(item => item.url)
}
}
// 判断接口
if (id) {
// 编辑
await http.put(`/mp/articles/${id}?draft=false`, params)
} else {
// 新增
await http.post('/mp/articles?draft=false', params)
}
// 跳转列表,提示用户
navigate('/article')
message.success(`${id ? '更新成功' : '发布成功'}`)
}
// 编辑功能
// 文案适配:通过路由参数 id 作为判断条件
const [params] = useSearchParams()
const id = params.get('id')
console.log('route:', id)
// 数据回填:id 调用接口 1.表单回填 2.暂存列表 3.Upload 组件 fileList
const form = useRef(null)
useEffect(() => {
const loadDetail = async () => {
const res = await http.get(`/mp/articles/${id}`)
const data = res.data
// 表单数据回填 实例方法
form.current.setFieldsValue({ ...data, type: data.cover.type })
// 调用 setFileList 方法回填 upload 图片
const formatImgList = data.cover.images.map(url => {
return {
url
}
})
setFileList(formatImgList)
// 暂存列表里也存一份
cacheImgList.current = formatImgList
}
// 必须是编辑状态才可以发送请求
if (id) {
loadDetail()
console.log(form.current)
}
}, [id])
return (
<div className="publish">
<Card
@ -40,7 +139,7 @@ const Publish = () => {
<Breadcrumb.Item>
<Link to="/home">首页</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>发布文章</Breadcrumb.Item>
<Breadcrumb.Item>{id ? '编辑' : '发布'}文章</Breadcrumb.Item>
</Breadcrumb>
}
>
@ -48,6 +147,8 @@ const Publish = () => {
labelCol={{ span: 4 }}
wrapperCol={{ span: 16 }}
initialValues={{ type: 1, content: 'this is content' }}
onFinish={onFinish}
ref={form}
>
<Form.Item
label="标题"
@ -56,7 +157,6 @@ const Publish = () => {
>
<Input placeholder="请输入文章标题" style={{ width: 400 }} />
</Form.Item>
<Form.Item
label="频道"
name="channel_id"
@ -71,25 +171,29 @@ const Publish = () => {
<Form.Item label="封面">
<Form.Item name="type">
<Radio.Group>
<Radio.Group onChange={radioChange}>
<Radio value={1}>单图</Radio>
<Radio value={3}>三图</Radio>
<Radio value={0}>无图</Radio>
</Radio.Group>
</Form.Item>
<Upload
name="image"
listType="picture-card"
className="avatar-uploader"
showUploadList
action="http://geek.itheima.net/v1_0/upload"
fileList={fileList}
onChange={onUploadChange}
>
<div style={{ marginTop: 8 }}>
<PlusOutlined />
</div>
</Upload>
{imgCount > 0 && ( // 图片的数量大于0才显示
<Upload
name="image"
listType="picture-card"
className="avatar-uploader"
showUploadList
action="http://geek.itheima.net/v1_0/upload"
fileList={fileList}
onChange={onUploadChange}
multiple={imgCount > 1} // 图片数量大于 1 才支持多传
maxCount={imgCount} // maxCount 是控制最大上传数量
>
<div style={{ marginTop: 8 }}>
<PlusOutlined />
</div>
</Upload>
)}
</Form.Item>
{/* 这里的富文本组件,已经被 Form.Item 控制,它的输入内容会在 onFinished 回调中收集起来 */}
@ -108,7 +212,7 @@ const Publish = () => {
<Form.Item wrapperCol={{ offset: 4 }}>
<Space>
<Button size="large" type="primary" htmlType="submit">
发布文章
{id ? '更新' : '发布'}文章
</Button>
</Space>
</Form.Item>

5
react-pc-project/src/utils/index.js

@ -7,9 +7,12 @@ import {
removeToken
} from './token'
import { history } from './history'
export {
http,
setToken,
getToken,
removeToken
removeToken,
history
}
Loading…
Cancel
Save