提交 dfcefd42 authored 作者: 王鹏飞's avatar 王鹏飞

chore: update

上级 81f68bb5
VITE_API_URL_WORD = https://zijingebook.ezijing.com/file/ VITE_API_URL_WORD = https://zijingebook.ezijing.com/api
VITE_API_URL_WORD = https://book-admin-web.ezijing.com/api
# VITE_API_URL_WORD = http://ebook-pc.ezijing.com:7419 # VITE_API_URL_WORD = http://ebook-pc.ezijing.com:7419
VITE_API_BASE_API_PREFFIX = /api VITE_API_BASE_API_PREFFIX = /api
VITE_API_WEBSOCKET_URL = wss://zijingebook.ezijing.com VITE_API_WEBSOCKET_URL = wss://zijingebook.ezijing.com
......
module.exports = { module.exports = {
extends: [require.resolve('@umijs/lint/dist/config/eslint')], root: true,
globals: { env: { browser: true, es2020: true },
page: true, extends: ['eslint:recommended', 'plugin:react/recommended', 'plugin:react/jsx-runtime', 'plugin:react-hooks/recommended'],
REACT_APP_ENV: true, parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
}, settings: { react: { version: '18.2' } }
}; }
{
"extends": [
"development"
],
"hints": {
"meta-viewport": "off"
}
}
\ No newline at end of file
{
"*.{js,jsx,ts,tsx,json}": ["prettier --write", "eslint --fix"],
"*.css": ["stylelint --fix", "prettier --write"]
}
# .prettierignore
**/*.svg
package.json
/dist
.dockerignore
.DS_Store
.eslintignore
*.png
*.toml
docker
.editorconfig
Dockerfile*
.gitignore
.prettierignore
LICENSE
.eslintcache
*.lock
yarn-error.log
.history
CNAME
/build
/public
const fabric = require('@umijs/fabric');
module.exports = {
// 一行最多 120 字符
printWidth: 120,
// 使用 2 个空格缩进
tabWidth: 2,
// 不使用缩进符,而使用空格
useTabs: false,
// 行尾需要有分号
semi: true,
// 使用单引号
singleQuote: true,
// 对象的 key 仅在必要时用引号
quoteProps: "as-needed",
// jsx 不使用单引号,而使用双引号
jsxSingleQuote: true,
// 末尾需要有逗号
trailingComma: "all",
// 大括号内的首尾需要空格
bracketSpacing: true,
// jsx 标签的反尖括号需要换行
jsxBracketSameLine: false,
// 箭头函数,只有一个参数的时候,也需要括号
arrowParens: "always",
// 每个文件格式化的范围是文件的全部内容
rangeStart: 0,
rangeEnd: Infinity,
// 不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 使用默认的折行标准
proseWrap: "preserve",
// 根据显示样式决定 html 要不要折行
htmlWhitespaceSensitivity: "css",
// vue 文件中的 script 和 style 内不用缩进
vueIndentScriptAndStyle: false,
// 换行符使用 lf
endOfLine: "lf",
// 格式化嵌入的内容
embeddedLanguageFormatting: "auto",
// 组件或者标签的属性是否控制一行只显示一个属性
singleAttributePerLine: false,
...fabric.prettier,
};
const fabric = require('@umijs/fabric');
module.exports = {
"extends": "stylelint-config-standard",
"rules": {
"string-quotes": "single",
"value-keyword-case": null,
"declaration-block-trailing-semicolon": "always",
"no-invalid-position-at-import-rule": null,
"selector-class-pattern": "^(?:(?:o|c|u|t|s|is|has|_|js|qa)-)?[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*(?:__[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:--[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:\\[.+\\])?$",
"property-no-unknown": [
true,
{
"ignoreProperties": ["composes"]
}
],
"selector-pseudo-class-no-unknown": [
true,
{
"ignorePseudoClasses": ["global"]
}
]
},
...fabric.stylelint,
};
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -49,15 +49,14 @@ ...@@ -49,15 +49,14 @@
"devDependencies": { "devDependencies": {
"@types/react": "^18.3.3", "@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",
"@umijs/fabric": "^4.0.1",
"@umijs/lint": "^4.0.88",
"@vitejs/plugin-react-swc": "^3.7.0", "@vitejs/plugin-react-swc": "^3.7.0",
"eslint": "^8.53.0", "eslint": "^8.57.0",
"eslint-plugin-react": "^7.34.2",
"eslint-plugin-react-hooks": "^4.6.2",
"husky": "^8.0.3", "husky": "^8.0.3",
"less": "^4.2.0", "less": "^4.2.0",
"lint-staged": "^15.1.0", "lint-staged": "^15.1.0",
"prettier": "^3.1.0", "prettier": "^3.3.1",
"stylelint-config-standard": "^34.0.0",
"vite": "^5.2.12", "vite": "^5.2.12",
"vite-plugin-mkcert": "^1.17.5" "vite-plugin-mkcert": "^1.17.5"
}, },
......
import { useEffect, useState } from 'react'; import { ErrorBoundary } from 'react-error-boundary'
import { ErrorBoundary } from 'react-error-boundary'; import { Button } from 'antd'
import { Button } from 'antd'; import './App.less'
import './App.less';
import { GetroutesDyamic } from '@/routes/index'; import { GetroutesDyamic } from '@/routes/index'
function fallbackRender({ error, resetErrorBoundary }) { function fallbackRender({ error, resetErrorBoundary }) {
return ( return (
<div role='alert'> <div role="alert">
<p>出错啦:</p> <p>出错啦:</p>
<pre style={{ color: 'red' }}>{error.message}</pre> <pre style={{ color: 'red' }}>{error.message}</pre>
<Button type='link' onClick={resetErrorBoundary}> <Button type="link" onClick={resetErrorBoundary}>
Try again Try again
</Button> </Button>
</div> </div>
); )
} }
function App() { function App() {
const [token, setToken] = useState('');
useEffect(() => {
const userToken = localStorage.getItem('kiwi.token');
if (userToken) {
setToken(userToken);
} else {
setToken('');
}
}, []);
return ( return (
<ErrorBoundary fallbackRender={fallbackRender}> <ErrorBoundary fallbackRender={fallbackRender}>
<GetroutesDyamic /> <GetroutesDyamic />
</ErrorBoundary> </ErrorBoundary>
); )
} }
export default App; export default App
import axios from '@/utils/axios'
export function getSTSToken(data) {
return axios.post('/api/common/OssUpload/getUploadToken', data)
}
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react'
import { Spin } from 'antd'; import { Spin } from 'antd'
import { Editor, Toolbar } from '@wangeditor/editor-for-react'; import { Editor, Toolbar } from '@wangeditor/editor-for-react'
import '@wangeditor/editor/dist/css/style.css'; // 引入 css import '@wangeditor/editor/dist/css/style.css' // 引入 css
import AliOSS from 'ali-oss'; import AliOSS from 'ali-oss'
import { getAliOSSSTSToken } from '@/pages/setting/help/addedit/requet'; import { getAliOSSSTSToken } from '@/pages/setting/help/addedit/requet'
import add from '@/assets/images/icon/add.png'; import add from '@/assets/images/icon/add.png'
import dayjs from 'dayjs'; import dayjs from 'dayjs'
import './index.less'; import './index.less'
const EditorReader = (props) => { const EditorReader = props => {
const { form, fieldName, content, loadLoading } = props; const { form, fieldName, content, loadLoading } = props
// oss // oss
const [ossClient, setOssClient] = useState(null); // oss 操作 const [ossClient, setOssClient] = useState(null) // oss 操作
const [STSToken, setSTSToken] = useState(null); // oss 过期设置 const [STSToken, setSTSToken] = useState(null) // oss 过期设置
const [file, setFile] = useState({}); // oss 过期设置 const [file, setFile] = useState({}) // oss 过期设置
const [uploading, setUploading] = useState(false); const [uploading, setUploading] = useState(false)
// editor 实例 // editor 实例
const [editor, setEditor] = useState(null); const [editor, setEditor] = useState(null)
// 编辑器内容 // 编辑器内容
const [html, setHtml] = useState(content); const [html, setHtml] = useState(content)
const [loading, setLoading] = useState(loadLoading || false); const [loading, setLoading] = useState(loadLoading || false)
const getStsAuthToken = async () => { const getStsAuthToken = async () => {
const data = await getAliOSSSTSToken(); const data = await getAliOSSSTSToken()
if (data) { if (data) {
window.sessionStorage.setItem('sts', JSON.stringify(data)); window.sessionStorage.setItem('sts', JSON.stringify(data))
setSTSToken(data); setSTSToken(data)
const ossClientTemp = await new AliOSS({ const ossClientTemp = await new AliOSS({
accessKeyId: data.AccessKeyId, accessKeyId: data.AccessKeyId,
accessKeySecret: data.AccessKeySecret, accessKeySecret: data.AccessKeySecret,
...@@ -37,18 +37,18 @@ const EditorReader = (props) => { ...@@ -37,18 +37,18 @@ const EditorReader = (props) => {
timeout: 180000, timeout: 180000,
refreshSTSToken: async () => { refreshSTSToken: async () => {
const info = await getAliOSSSTSToken(); const info = await getAliOSSSTSToken()
return { return {
AccessKeyId: info.AccessKeyId, AccessKeyId: info.AccessKeyId,
AccessKeySecret: info.AccessKeySecret, AccessKeySecret: info.AccessKeySecret,
SecurityToken: info.SecurityToken, SecurityToken: info.SecurityToken
}; }
}, },
refreshSTSTokenInterval: 14 * 60 * 1000, refreshSTSTokenInterval: 14 * 60 * 1000
}); })
setOssClient(ossClientTemp); setOssClient(ossClientTemp)
} }
}; }
// 工具栏配置 // 工具栏配置
const toolbarConfig = { const toolbarConfig = {
...@@ -65,9 +65,9 @@ const EditorReader = (props) => { ...@@ -65,9 +65,9 @@ const EditorReader = (props) => {
'fullScreen', 'fullScreen',
'insertLink', 'insertLink',
'headerSelect', 'headerSelect',
'todo', 'todo'
], //删除工具栏 ] //删除工具栏
}; // JS 语法 } // JS 语法
// 编辑器配置 // 编辑器配置
const editorConfig = { const editorConfig = {
...@@ -92,14 +92,14 @@ const EditorReader = (props) => { ...@@ -92,14 +92,14 @@ const EditorReader = (props) => {
{ name: '六号', value: '10px' }, { name: '六号', value: '10px' },
{ name: '小六', value: '8px' }, { name: '小六', value: '8px' },
{ name: '七号', value: '7px' }, { name: '七号', value: '7px' },
{ name: '八号', value: '6px' }, { name: '八号', value: '6px' }
], ]
}, },
fontFamily: { fontFamily: {
fontFamilyList: ['思源黑体', '思源宋体', '黑体', '宋体', '楷体', '仿宋'], fontFamilyList: ['思源黑体', '思源宋体', '黑体', '宋体', '楷体', '仿宋']
}, },
lineHeight: { lineHeight: {
lineHeightList: ['1', '1.25', '1.5', '2', '2.5', '3'], lineHeightList: ['1', '1.25', '1.5', '2', '2.5', '3']
}, },
// 配置上传图片 // 配置上传图片
uploadImage: { uploadImage: {
...@@ -108,29 +108,29 @@ const EditorReader = (props) => { ...@@ -108,29 +108,29 @@ const EditorReader = (props) => {
fieldName: 'image', fieldName: 'image',
headers: { headers: {
'Content-Type': 'multipart/form-data', 'Content-Type': 'multipart/form-data',
Authorization: 'Bearer ' + localStorage.getItem('token') || '', Authorization: 'Bearer ' + localStorage.getItem('token') || ''
}, },
maxFileSize: 10 * 1024 * 1024, // 10M maxFileSize: 10 * 1024 * 1024, // 10M
base64LimitSize: 5 * 1024, // 5kb 以下插入 base64 // 用户自定义上传图片 base64LimitSize: 5 * 1024, // 5kb 以下插入 base64 // 用户自定义上传图片
customUpload: async (file, insertFn) => { customUpload: async (file, insertFn) => {
setLoading(true); setLoading(true)
if (!ossClient) { if (!ossClient) {
console.error('ossClient还未初始化', ossClient); console.error('ossClient还未初始化', ossClient)
return false; return false
} }
const fileExt = file.name.substring(file.name.lastIndexOf('.')); const fileExt = file.name.substring(file.name.lastIndexOf('.'))
const fileName = `banner-${dayjs().valueOf()}-${Math.random().toString(36).substring(2)}${fileExt}`; const fileName = `banner-${dayjs().valueOf()}-${Math.random().toString(36).substring(2)}${fileExt}`
const filePath = `${dayjs().format('YYYY/MM/DD')}/${fileName}`; const filePath = `${dayjs().format('YYYY/MM/DD')}/${fileName}`
const result = await ossClient.put(filePath, file); const result = await ossClient.put(filePath, file)
console.log('result', result); console.log('result', result)
insertFn(result.url, '题库图片'); insertFn(result.url, '题库图片')
// const { url } = await uploadFiles({ file, file_type: 'question' }); // const { url } = await uploadFiles({ file, file_type: 'question' });
// insertFn(url, '题库图片'); // insertFn(url, '题库图片');
setLoading(false); setLoading(false)
}, }
}, },
uploadVideo: { uploadVideo: {
...@@ -139,75 +139,70 @@ const EditorReader = (props) => { ...@@ -139,75 +139,70 @@ const EditorReader = (props) => {
fieldName: 'video', fieldName: 'video',
headers: { headers: {
'Content-Type': 'multipart/form-data', 'Content-Type': 'multipart/form-data',
Authorization: 'Bearer ' + localStorage.getItem('token') || '', Authorization: 'Bearer ' + localStorage.getItem('token') || ''
}, },
maxFileSize: 10 * 1024 * 1024, // 10M maxFileSize: 10 * 1024 * 1024, // 10M
base64LimitSize: 5 * 1024, // 5kb 以下插入 base64 // 用户自定义上传图片 base64LimitSize: 5 * 1024, // 5kb 以下插入 base64 // 用户自定义上传图片
customUpload: async (file, insertFn) => { customUpload: async (file, insertFn) => {
setLoading(true); setLoading(true)
if (!ossClient) { if (!ossClient) {
console.error('ossClient还未初始化', ossClient); console.error('ossClient还未初始化', ossClient)
return false; return false
} }
const result = await ossClient.put(file.name, file); const result = await ossClient.put(file.name, file)
console.log('result', result); console.log('result', result)
insertFn(result.url, '题库视频'); insertFn(result.url, '题库视频')
// const { url } = await uploadFiles({ file, file_type: 'question' }); // const { url } = await uploadFiles({ file, file_type: 'question' });
// insertFn(url, '题库视频'); // insertFn(url, '题库视频');
setLoading(false); setLoading(false)
}, }
}, }
}, }
}; }
useEffect(() => { useEffect(() => {
getStsAuthToken(); getStsAuthToken()
}, []); }, [])
// 及时销毁 editor ,重要! // 及时销毁 editor ,重要!
useEffect(() => { useEffect(() => {
return () => { return () => {
if (editor === null) return; if (editor === null) return
editor.destroy(); editor.destroy()
setEditor(null); setEditor(null)
}; }
}, [editor]); }, [editor])
useEffect(() => { useEffect(() => {
if (editor && ossClient) { if (editor && ossClient) {
editor.setHtml(content); editor.setHtml(content)
} }
}, [editor, content, ossClient]); }, [editor, content, ossClient])
return ( return (
<div className='editor_customer_simple'> <div className="editor_customer_simple">
<div className='editor-box' style={{ border: '1px solid #ccc', zIndex: 100 }}> <div className="editor-box" style={{ border: '1px solid #ccc', zIndex: 100 }}>
<Toolbar <Toolbar editor={editor} defaultConfig={toolbarConfig} mode="default" style={{ borderBottom: '1px solid #ccc' }} />
editor={editor}
defaultConfig={toolbarConfig}
mode='default'
style={{ borderBottom: '1px solid #ccc' }}
/>
<Spin spinning={loading}> <Spin spinning={loading}>
{ossClient && ( {ossClient && (
<Editor <Editor
defaultConfig={editorConfig} defaultConfig={editorConfig}
value={html} value={html}
onCreated={setEditor} onCreated={setEditor}
onChange={(editor) => { onChange={editor => {
form.setFieldValue(fieldName, editor.getHtml()); form.setFieldValue(fieldName, editor.getHtml())
setHtml(editor.getHtml()); setHtml(editor.getHtml())
}} }}
mode='default' mode="default"
className='w-e-text' className="w-e-text"
style={{ height: '400px', overflowY: 'hidden' }} style={{ height: '400px', overflowY: 'hidden' }}
/> />
)} )}
</Spin> </Spin>
</div> </div>
</div> </div>
); )
}; }
export default EditorReader; export default EditorReader
import '@wangeditor/editor/dist/css/style.css'; // 引入 css import { useState, useEffect } from 'react'
import { Editor, Toolbar } from '@wangeditor/editor-for-react'
import React, { useState, useEffect } from 'react'; import '@wangeditor/editor/dist/css/style.css' // 引入 css
import { Editor, Toolbar } from '@wangeditor/editor-for-react';
function MyEditor() { function MyEditor() {
// editor 实例 // editor 实例
const [editor, setEditor] = useState(null); // JS 语法 const [editor, setEditor] = useState(null) // JS 语法
// 编辑器内容 // 编辑器内容
const [html, setHtml] = useState('<p>hello</p>'); const [html, setHtml] = useState('<p>hello</p>')
// 模拟 ajax 请求,异步设置 html // 模拟 ajax 请求,异步设置 html
useEffect(() => { useEffect(() => {
setTimeout(() => { setTimeout(() => {
setHtml('<p>hello world</p>'); setHtml('<p>hello world</p>')
}, 1500); }, 1500)
}, []); }, [])
// 工具栏配置 // 工具栏配置
const toolbarConfig = {}; const toolbarConfig = {}
// 编辑器配置 // 编辑器配置
const editorConfig = { const editorConfig = {
placeholder: '请输入内容...', placeholder: '请输入内容...'
}; }
useEffect(() => { useEffect(() => {
return () => { return () => {
if (editor === null) return; if (editor === null) return
editor.destroy(); editor.destroy()
setEditor(null); setEditor(null)
}; }
}, [editor]); }, [editor])
return ( return (
<> <>
<div style={{ border: '1px solid #ccc', zIndex: 100 }}> <div style={{ border: '1px solid #ccc', zIndex: 100 }}>
<Toolbar <Toolbar editor={editor} defaultConfig={toolbarConfig} mode="default" style={{ borderBottom: '1px solid #ccc' }} />
editor={editor}
defaultConfig={toolbarConfig}
mode='default'
style={{ borderBottom: '1px solid #ccc' }}
/>
<Editor <Editor
defaultConfig={editorConfig} defaultConfig={editorConfig}
value={html} value={html}
onCreated={setEditor} onCreated={setEditor}
onChange={(editor) => setHtml(editor.getHtml())} onChange={editor => setHtml(editor.getHtml())}
mode='default' mode="default"
style={{ height: '500px', overflowY: 'hidden' }} style={{ height: '500px', overflowY: 'hidden' }}
/> />
</div> </div>
<div style={{ marginTop: '15px' }}>{html}</div>
</> </>
); )
} }
export default MyEditor; export default MyEditor
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react'
import { Layout, Spin } from 'antd'; import { Layout, Spin } from 'antd'
import { Outlet, useNavigate, Link } from 'react-router-dom'; import { Outlet, useNavigate, Link } from 'react-router-dom'
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux'
import { setMenuRouter, setOperationPermissionsList } from '@/store/modules/user'; import { setMenuRouter, setOperationPermissionsList } from '@/store/modules/user'
import UserInfo from './components/userinfo'; import UserInfo from './components/userinfo'
import UserMenu from './components/menu'; import UserMenu from './components/menu'
import BreadCrumbMenu from './components/breadMenu'; import BreadCrumbMenu from './components/breadMenu'
import './index.less'; import './index.less'
import logo from '@/assets/images/logo.png'; import logo from '@/assets/images/logo.png'
import { getMenuList, checkSSOLogin } from './request'; import { getMenuList, checkSSOLogin } from './request'
import { generateToAntdMenus } from '@/utils/breadCrumb'; import { generateToAntdMenus } from '@/utils/breadCrumb'
const { Header, Content, Footer } = Layout; const { Header, Content, Footer } = Layout
const LayoutComponent = () => { const LayoutComponent = () => {
const dispatch = useDispatch(); const dispatch = useDispatch()
const navigate = useNavigate(); const navigate = useNavigate()
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false)
const [menuList, setMenuList] = useState([]); const [menuList, setMenuList] = useState([])
const [menuRole, setMenuRole] = useState([]); const [menuRole, setMenuRole] = useState([])
const [isSSOToken, setIsSSOToken] = useState(false); const [isSSOToken, setIsSSOToken] = useState(false)
const getSSOToken = async () => { const getSSOToken = async () => {
const data = await checkSSOLogin(); const data = await checkSSOLogin()
if (data && data.token) { if (data && data.token) {
localStorage.setItem('kiwi.token', data.token); localStorage.setItem('kiwi.token', data.token)
setIsSSOToken(data.token); setIsSSOToken(data.token)
} }
}; }
// 获取菜单 // 获取菜单
const getMenu = async () => { const getMenu = async () => {
setLoading(true); setLoading(true)
// 获取菜单内容 // 获取菜单内容
const { data, operation_permissions_list } = await getMenuList(); const { data, operation_permissions_list } = await getMenuList()
if (data && data.length) { if (data && data.length) {
setMenuRole(data); setMenuRole(data)
const menus = generateToAntdMenus(data, 'name', 'front_url', 'childs', 1); const menus = generateToAntdMenus(data, 'name', 'front_url', 'childs', 1)
setMenuList(menus); setMenuList(menus)
dispatch(setMenuRouter(menus)); dispatch(setMenuRouter(menus))
} }
// 获取操作权限内容 // 获取操作权限内容
if (operation_permissions_list && operation_permissions_list.length) { if (operation_permissions_list && operation_permissions_list.length) {
dispatch(setOperationPermissionsList(operation_permissions_list)); dispatch(setOperationPermissionsList(operation_permissions_list))
} }
setLoading(false); setLoading(false)
}; }
useEffect(() => { useEffect(() => {
(async () => { ;(async () => {
await getSSOToken(); await getSSOToken()
await getMenu(); await getMenu()
})(); })()
}, []); }, [])
useEffect(() => { useEffect(() => {
if (menuRole.length > 0 && location.pathname === '/') { if (menuRole.length > 0 && location.pathname === '/') {
setLoading(true); setLoading(true)
setTimeout(() => { setTimeout(() => {
if (menuRole.length) { if (menuRole.length) {
navigate(menuRole[0].front_url); navigate(menuRole[0].front_url)
} }
setLoading(false); setLoading(false)
}, 1000); }, 1000)
} }
}, [location.pathname, menuRole]); }, [location.pathname, menuRole])
return ( return (
<Layout className='layout-container'> <Layout className="layout-container">
<Spin spinning={loading}> <Spin spinning={loading}>
<Header className='layout-header'> <Header className="layout-header">
<div className='header-logo'> <div className="header-logo">
<Link to='/'> <Link to="/">
<img src={logo} /> <img src={logo} />
</Link> </Link>
</div> </div>
<UserMenu menuList={menuList} /> <UserMenu menuList={menuList} />
{menuList && menuList.length && <UserInfo />} {menuList && menuList.length && <UserInfo />}
</Header> </Header>
<Content className='layout-content'> <Content className="layout-content">
<div className='crumb'> <div className="crumb">
<BreadCrumbMenu /> <BreadCrumbMenu />
</div> </div>
<div className='content-sandbox'> <div className="content-sandbox">
<div className='content-pro' style={{ padding: 20 }}> <div className="content-pro" style={{ padding: 20 }}>
<Outlet aa={2} /> <Outlet aa={2} />
</div> </div>
</div> </div>
</Content> </Content>
</Spin> </Spin>
</Layout> </Layout>
); )
}; }
export default LayoutComponent; export default LayoutComponent
import React from 'react'; // import { StrictMode } from 'react'
import ReactDOM from 'react-dom/client'; import { createRoot } from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'; import { Provider } from 'react-redux'
import { PersistGate } from 'redux-persist/integration/react'; import { PersistGate } from 'redux-persist/integration/react'
import store, { persistor } from '@/store'; import store, { persistor } from '@/store'
import { ConfigProvider, App } from 'antd'; import { ConfigProvider, App } from 'antd'
import zhCN from 'antd/locale/zh_CN'; import 'dayjs/locale/zh-cn'
import zhCN from 'antd/locale/zh_CN'
// import 'dayjs/locale/zh-cn'; import MyApp from './App.jsx'
// import dayjs from 'dayjs';
// // 汉化
// dayjs.locale('zh-cn');
import MyApp from './App.jsx'; createRoot(document.getElementById('root')).render(
// <StrictMode>
import 'dayjs/locale/zh-cn';
ReactDOM.createRoot(document.getElementById('root')).render(
// <React.StrictMode>
<Provider store={store}> <Provider store={store}>
<PersistGate loading={null} persistor={persistor}> <PersistGate loading={null} persistor={persistor}>
<ConfigProvider locale={zhCN} theme={{ token: { colorPrimary: '#ab1941' } }}> <ConfigProvider locale={zhCN} theme={{ token: { colorPrimary: '#ab1941' } }}>
...@@ -30,6 +24,6 @@ ReactDOM.createRoot(document.getElementById('root')).render( ...@@ -30,6 +24,6 @@ ReactDOM.createRoot(document.getElementById('root')).render(
</App> </App>
</ConfigProvider> </ConfigProvider>
</PersistGate> </PersistGate>
</Provider>, </Provider>
// </React.StrictMode>, // </StrictMode>
); )
import { fetchEventSource } from '@fortaine/fetch-event-source'; import { fetchEventSource } from '@fortaine/fetch-event-source'
function getToken() { function getToken() {
return window.localStorage.getItem('kiwi.token') ? window.localStorage.getItem('kiwi.token') : ''; return window.localStorage.getItem('kiwi.token') ? window.localStorage.getItem('kiwi.token') : ''
} }
export default async function fetchEventSourceFn(url, options) { export default async function fetchEventSourceFn(url, options) {
const token = getToken(); const token = getToken()
// 应用设置 // 应用设置
const appId = 'TzEU5jPk2tu80266'; const appId = 'TzEU5jPk2tu80266'
const appSecret = '0a006048a4480481b18fef1405120b83'; const appSecret = '0a006048a4480481b18fef1405120b83'
const timestamp = Math.floor(Date.now() / 1000); const timestamp = Math.floor(Date.now() / 1000)
const defaultHeaders = { const defaultHeaders = {
Authorization: token, Authorization: token,
AppId: appId, AppId: appId,
AppSecret: appSecret, AppSecret: appSecret,
Timestamp: timestamp, Timestamp: timestamp,
'Content-Type': 'application/json', 'Content-Type': 'application/json'
}; }
const defaultOptions = { const defaultOptions = {
method: 'POST', method: 'POST',
headers: { ...defaultHeaders }, headers: { ...defaultHeaders },
async onopen(response) { async onopen(response) {
if (response.ok) { if (response.ok) {
return response; return response
} else { } else {
throw response; throw response
} }
}, },
onmessage(res) { onmessage(res) {
const message = JSON.parse(res.data); const message = JSON.parse(res.data)
console.log(res.data); console.log(res.data)
}, }
}; }
await fetchEventSource(url, { ...defaultOptions, ...options }); await fetchEventSource(url, { ...defaultOptions, ...options })
} }
import OSS from 'ali-oss'
import { getSTSToken } from '@/api/base'
// 获取token
export async function getToken() {
const { data } = await getSTSToken()
return { ...data, accessKeyId: data.AccessKeyId, accessKeySecret: data.AccessKeySecret, stsToken: data.SecurityToken }
}
// 创建oss
export async function createOSS() {
const store = new OSS({
bucket: 'zxts-book-file',
...(await getToken()),
refreshSTSToken: async () => {
return await getToken()
},
refreshSTSTokenInterval: 14 * 60 * 1000
})
return store
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论