diff --git a/package-lock.json b/package-lock.json index d7e2c1d..f776188 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "antd": "^5.19.3", "apexcharts": "^3.41.0", + "axios": "^1.7.2", "flatpickr": "^4.6.13", "headlessui": "^0.0.0", "jsvectormap": "^1.5.3", @@ -24,7 +25,8 @@ "sass": "^1.77.8", "sort-by": "^0.0.2", "vditor": "^3.10.4", - "vite-plugin-sass-dts": "^1.3.25" + "vite-plugin-sass-dts": "^1.3.25", + "zustand": "^4.5.4" }, "devDependencies": { "@types/react": "^18.2.17", @@ -1108,13 +1110,13 @@ "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true + "devOptional": true }, "node_modules/@types/react": { "version": "18.2.17", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.17.tgz", "integrity": "sha512-u+e7OlgPPh+aryjOm5UJMX32OvB2E3QASOAqVMY6Ahs90djagxwv2ya0IctglNbNTexC12qCSMZG47KPfy1hAA==", - "dev": true, + "devOptional": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -1134,7 +1136,7 @@ "version": "0.16.3", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", - "dev": true + "devOptional": true }, "node_modules/@vitejs/plugin-react": { "version": "4.0.3", @@ -1475,6 +1477,11 @@ "resolved": "https://registry.npmmirror.com/array-tree-filter/-/array-tree-filter-2.1.0.tgz", "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/autoprefixer": { "version": "10.4.14", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", @@ -1508,6 +1515,16 @@ "postcss": "^8.1.0" } }, + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmmirror.com/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1706,6 +1723,17 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -1779,6 +1807,14 @@ } } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -2021,6 +2057,38 @@ "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.13.tgz", "integrity": "sha512-97PMG/aywoYpB4IvbvUJi0RQi8vearvU0oov1WW3k0WZPBMrTQVqekSX5CjSG/M4Q3i6A/0FKXC7RyAoAUUSPw==" }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fraction.js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", @@ -2426,7 +2494,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -2435,7 +2502,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -2820,6 +2886,11 @@ "react-is": "^16.13.1" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -4111,6 +4182,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -4288,6 +4367,33 @@ "engines": { "node": ">= 14" } + }, + "node_modules/zustand": { + "version": "4.5.4", + "resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.5.4.tgz", + "integrity": "sha512-/BPMyLKJPtFEvVL0E9E9BTUM63MNyhPGlvxk1XjrfWTUlV+BR8jufjsovHzrtR6YNcBEcL7cMHovL1n9xHawEg==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index b4acb49..f43eff8 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "dependencies": { "antd": "^5.19.3", "apexcharts": "^3.41.0", + "axios": "^1.7.2", "flatpickr": "^4.6.13", "headlessui": "^0.0.0", "jsvectormap": "^1.5.3", @@ -30,7 +31,8 @@ "sass": "^1.77.8", "sort-by": "^0.0.2", "vditor": "^3.10.4", - "vite-plugin-sass-dts": "^1.3.25" + "vite-plugin-sass-dts": "^1.3.25", + "zustand": "^4.5.4" }, "devDependencies": { "@types/react": "^18.2.17", diff --git a/src/pages/Create/components/VditorMD/index.tsx b/src/pages/Create/components/VditorMD/index.tsx index eb89769..56a949c 100644 --- a/src/pages/Create/components/VditorMD/index.tsx +++ b/src/pages/Create/components/VditorMD/index.tsx @@ -3,7 +3,11 @@ import Vditor from "vditor"; import "vditor/dist/index.css"; import "./index.scss" -const VditorEditor = () => { +interface VditorProps { + getValue: (value: string) => void +} + +const VditorEditor = ({ getValue }: VditorProps) => { const [vd, setVd] = useState(); useEffect(() => { const vditor = new Vditor("vditor", { @@ -12,9 +16,13 @@ const VditorEditor = () => { // enable: true, // position: 'left' // }, + input: (value) => { + // 把数据传给父组件 + getValue(value) + }, after: () => { vditor.setValue("`Vditor` 最小代码示例"); - vditor.setTheme("classic","","github") + setVd(vditor); } }) @@ -25,8 +33,8 @@ const VditorEditor = () => { setVd(undefined); }; }, []); - - return
; + + return
; }; export default VditorEditor; diff --git a/src/pages/Create/index.tsx b/src/pages/Create/index.tsx index 43da6df..74dfa5d 100644 --- a/src/pages/Create/index.tsx +++ b/src/pages/Create/index.tsx @@ -10,6 +10,11 @@ const Create = () => { const [content, setContent] = useState(''); const [publishOpen, setPublishOpen] = useState(false) + // 获取编辑器的内容 + const getVditorData = (value: string) => { + console.log(111, value); + } + useEffect(() => { console.log(content); }, [content]) @@ -22,7 +27,7 @@ const Create = () => { 保存
- + void; + quitLogin: () => void +} + +export default create((set) => ({ + token: "", + user: {} as User, + setData: (data: User) => set(() => ({ user: data })), + // 退出登录 + quitLogin: () => set(() => { + localStorage.clear() + sessionStorage.clear() + location.href = "/login" + + return { + user: {} as User, + token: "" + } + }) +})) \ No newline at end of file diff --git a/src/types/response.d.ts b/src/types/response.d.ts new file mode 100644 index 0000000..d28b6f8 --- /dev/null +++ b/src/types/response.d.ts @@ -0,0 +1,15 @@ +interface Response { + code: number, + message: string + data: T +} + +interface Paginate { + next: boolean, + prev: boolean, + page: number, + size: number, + pages: number, + total: number, + result: T +} \ No newline at end of file diff --git a/src/types/user.d.ts b/src/types/user.d.ts new file mode 100644 index 0000000..0e624bf --- /dev/null +++ b/src/types/user.d.ts @@ -0,0 +1,26 @@ +interface Login { + username: string, + password: string +} + +interface UserInfo { + id?: number, + name: string, + email: string, + avatar: string, + info: string, + role?: string +} + +type User = Login & UserInfo + +interface account { + token: string, + user: User +} + +interface editUser { + username: string, + oldPassword: string, + newPassword: string +} \ No newline at end of file diff --git a/src/utils/request.ts b/src/utils/request.ts new file mode 100644 index 0000000..c7a88bb --- /dev/null +++ b/src/utils/request.ts @@ -0,0 +1,87 @@ +import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from "axios"; +import { useUserStore } from "@/stores"; +import { Modal, notification } from "antd"; + +// 配置项目API域名 +export const baseURL = "http://localhost:5000/api"; + +// 创建 axios 实例 +export const instance = axios.create({ + // 项目API根路径 + baseURL, + // 请求超时的时间 + timeout: 5000, +}); + +// 请求拦截 +instance.interceptors.request.use( + (config: InternalAxiosRequestConfig) => { + const token = useUserStore((state) => state.token) + + // 如果有token就把赋值给请求头 + if (token) config.headers["Authorization"] = `Bearer ${token}`; + + return config; + }, + (err: AxiosError) => { + notification.error({ + message: '程序异常', + description: err.message, + }) + + return Promise.reject(err); + } +); + +// 响应拦截 +instance.interceptors.response.use( + (res: AxiosResponse) => { + // 如果code为401就证明认证失败 + if (res.data.code === 401) { + const quitLogin = useUserStore((state) => state.quitLogin) + + return Modal.error({ + title: '暂无权限', + content: '🔒️ 登录已过期,是否重新登录?', + okText: "去登录", + onOk: () => { + quitLogin(); + } + }); + } + + // 只要code不等于200, 就相当于响应失败 + if (res.data?.code !== 200) { + notification.error({ + message: '程序异常', + description: res.data?.message || "未知错误", + }) + + return Promise.reject(res.data); + } + + return res.data; + }, + (err: AxiosError) => { + // 服务器异常:网络错误、请求超时、状态码不在200-299之间等等 + notification.error({ + message: '服务器异常', + description: err.message || "未知错误", + }) + + return Promise.reject(err); + } +); + +// 如果是GET传参就自动识别为query,POST为data +const Request = (method: string, url: string, reqParams?: object) => { + if (!method) method = "GET"; + + return instance.request>({ + method, + url, + [method.toLocaleUpperCase() === "GET" ? "params" : "data"]: reqParams, + }); +}; + +export default Request; \ No newline at end of file