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

chore: update

上级 a29212a5
# VITE_API_URL_WORD = http://ebook-pc.ezijing.com:7419 # VITE_API_URL_WORD = https://book-admin-web.ezijing.com/api
VITE_API_URL_WORD = https://zijingebook.ezijing.com/api VITE_API_URL_WORD = https://zijingebook.ezijing.com/api
VITE_API_BASE_API_PREFFIX = /api VITE_API_BASE_API_PREFFIX = /api
......
...@@ -36,7 +36,8 @@ ...@@ -36,7 +36,8 @@
"react-router-dom": "^6.23.1", "react-router-dom": "^6.23.1",
"redux-persist": "^6.0.0", "redux-persist": "^6.0.0",
"snabbdom": "^3.6.2", "snabbdom": "^3.6.2",
"xml-formatter": "^3.6.2" "xml-formatter": "^3.6.2",
"zustand": "^4.5.5"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.3.5", "@types/react": "^18.3.5",
...@@ -10077,6 +10078,34 @@ ...@@ -10077,6 +10078,34 @@
"dependencies": { "dependencies": {
"tslib": "2.3.0" "tslib": "2.3.0"
} }
},
"node_modules/zustand": {
"version": "4.5.5",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.5.tgz",
"integrity": "sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==",
"license": "MIT",
"dependencies": {
"use-sync-external-store": "1.2.2"
},
"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
}
}
} }
} }
} }
...@@ -39,7 +39,8 @@ ...@@ -39,7 +39,8 @@
"react-router-dom": "^6.23.1", "react-router-dom": "^6.23.1",
"redux-persist": "^6.0.0", "redux-persist": "^6.0.0",
"snabbdom": "^3.6.2", "snabbdom": "^3.6.2",
"xml-formatter": "^3.6.2" "xml-formatter": "^3.6.2",
"zustand": "^4.5.5"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.3.5", "@types/react": "^18.3.5",
......
...@@ -141,7 +141,7 @@ const tabsMenu = [ ...@@ -141,7 +141,7 @@ const tabsMenu = [
storageChange() storageChange()
const WangEditorCustomer = (props, ref) => { const WangEditorCustomer = (props, ref) => {
const { chapterId, bookId, contentId, html, setHtml, saveContent, gData, nowTitle } = props const { chapterId, bookId, contentId, html, setHtml, saveContent, gData, nowTitle, disabled } = props
const dispatch = useDispatch() const dispatch = useDispatch()
// 自动保存时间 // 自动保存时间
...@@ -428,6 +428,7 @@ const WangEditorCustomer = (props, ref) => { ...@@ -428,6 +428,7 @@ const WangEditorCustomer = (props, ref) => {
}, 50) }, 50)
} }
editorConfig.onFocus = () => { editorConfig.onFocus = () => {
clearTimeout(saveRef.current) clearTimeout(saveRef.current)
} }
...@@ -582,13 +583,13 @@ const WangEditorCustomer = (props, ref) => { ...@@ -582,13 +583,13 @@ const WangEditorCustomer = (props, ref) => {
useEffect(() => { useEffect(() => {
if (editor) { if (editor) {
if (gData.length > 0) { if (gData.length > 0 && !disabled) {
editor.enable() editor.enable()
} else { } else {
editor.disable() editor.disable()
} }
} }
}, [gData, editor]) }, [gData, editor, disabled])
const tabKeyChange = key => { const tabKeyChange = key => {
if (key === 'text') { if (key === 'text') {
...@@ -645,19 +646,13 @@ const WangEditorCustomer = (props, ref) => { ...@@ -645,19 +646,13 @@ const WangEditorCustomer = (props, ref) => {
</div> </div>
<span className="time">{autosaveTime > 0 ? `上次保存发生在 ${dayjs(autosaveTime).format('YYYY-MM-DD HH:mm:ss')}` : ''}</span> <span className="time">{autosaveTime > 0 ? `上次保存发生在 ${dayjs(autosaveTime).format('YYYY-MM-DD HH:mm:ss')}` : ''}</span>
</div> </div>
<Button <Button type="primary" icon={<SaveOutlined />} className="view" onClick={saveContent} style={{ color: '#fff' }} disabled={disabled}>
type="primary"
icon={<SaveOutlined />}
className="view"
onClick={saveContent}
style={{ color: '#fff' }}
disabled={bookId && contentId ? false : true}>
保存 保存
</Button> </Button>
<Button icon={<EyeOutlined />} className="history" onClick={previewIt} disabled={bookId && contentId ? false : true}> <Button icon={<EyeOutlined />} className="history" onClick={previewIt}>
预览 预览
</Button> </Button>
<Button icon={<HistoryOutlined />} className="history" onClick={historyIt} disabled={bookId && contentId ? false : true}> <Button icon={<HistoryOutlined />} className="history" onClick={historyIt} disabled={disabled}>
历史 历史
</Button> </Button>
</Space> </Space>
......
...@@ -118,7 +118,6 @@ ...@@ -118,7 +118,6 @@
.layout-content { .layout-content {
background-color: #fff; background-color: #fff;
border-radius: 5px; border-radius: 5px;
box-shadow: 0px 0px 20px 1px rgba(123, 123, 123, 0.2);
height: calc(100vh - 120px); height: calc(100vh - 120px);
padding: 20px; padding: 20px;
} }
......
...@@ -36,7 +36,9 @@ const BookAddEdit = () => { ...@@ -36,7 +36,9 @@ const BookAddEdit = () => {
const onFinish = async values => { const onFinish = async values => {
const editors = values.editors?.map(item => item.value) || [] const editors = values.editors?.map(item => item.value) || []
const res = isEdit ? await updateBook({ id: location.state.id, ...values, img, editors }) : await addBook({ ...values, img, editors }) const params = { ...values, img, editors }
if (editors.length === 0) delete params.editors
const res = isEdit ? await updateBook({ id: location.state.id, ...params }) : await addBook(params)
message.success(res.message) message.success(res.message)
navigate(-1) navigate(-1)
} }
......
import React, { useEffect, useState } from 'react'; import { useState } from 'react'
import { import { Input, Button, Row, Col, Space, DatePicker, Image, Drawer, Form, Select, Modal, Upload, Spin } from 'antd'
Table, const { RangePicker } = DatePicker
Input, const { TextArea } = Input
Button, import { useNavigate } from 'react-router-dom'
Row, import PaginationCom from '@/common/Pagination'
Col, import { getList, delUser, exportBook, releaseExamine, importBook, exportToPdf } from '../request'
Space, import reset from '@/assets/images/icon/reset.png'
DatePicker, import filter from '@/assets/images/icon/filter.png'
Image, import add from '@/assets/images/icon/add.png'
Drawer, import imports from '@/assets/images/icon/import.png'
Form, import reload from '@/assets/images/icon/reload.png'
Select, import dayjs from 'dayjs'
Modal, import TableCom from '@/common/TableCom/index'
Upload, import { useSelector } from 'react-redux'
InputNumber, import { downloadFile } from '@/utils/common'
Spin, import $ from 'jquery'
} from 'antd';
const { RangePicker } = DatePicker;
const { TextArea } = Input;
import { useNavigate } from 'react-router-dom';
import PaginationCom from '@/common/Pagination';
import { getList, delUser, exportBook, releaseExamine, importBook, exportToPdf } from '../request';
import reset from '@/assets/images/icon/reset.png';
import filter from '@/assets/images/icon/filter.png';
import add from '@/assets/images/icon/add.png';
import imports from '@/assets/images/icon/import.png';
import reload from '@/assets/images/icon/reload.png';
import dayjs from 'dayjs';
import TableCom from '@/common/TableCom/index';
import { useSelector } from 'react-redux';
import { downloadFile } from '@/utils/common';
import $ from 'jquery';
const Audit = () => { const Audit = () => {
const [data, setData] = useState([]); const [data, setData] = useState([])
const navigate = useNavigate(); const navigate = useNavigate()
const [page_size, setpage_size] = useState(10); const [page_size, setpage_size] = useState(10)
const [page, setPage] = useState(1); const [page, setPage] = useState(1)
const [total, setTotal] = useState(0); const [total, setTotal] = useState(0)
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true)
const [isEdit, setIsEdit] = useState(false); const [delModal, setDelModal] = useState(false)
const [delMoadal, setDelModal] = useState(false); const [exportModal, setExportModal] = useState(false)
const [exportMoadal, setExportModal] = useState(false); const [importModal, setImportModal] = useState(false)
const [importMoadal, setImportMoadal] = useState(false); const [bookFile, setBookFile] = useState('')
const [bookFile, setBookFile] = useState(''); const [showAudit, setShowAudit] = useState(false)
const [showaudit, setshowaudit] = useState(false); const [id, setId] = useState(0)
const [form] = Form.useForm(); const [filterObj, setFilterObj] = useState({
const [id, setId] = useState(0);
const [filterObj, setfilterObj] = useState({
name: '', name: '',
authors: '', authors: '',
audit_status: null, audit_status: null,
start_time: '', start_time: '',
end_time: '', end_time: ''
}); })
const [dateVal, setDateVal] = useState(''); const [dateVal, setDateVal] = useState('')
// 获取操作权限 // 获取操作权限
const { operationPermissionsList } = useSelector((state) => state.user); const { operationPermissionsList } = useSelector(state => state.user)
const { userInfo } = useSelector(state => state.user)
// 重置 // 重置
const handleReset = () => { const handleReset = () => {
setfilterObj({ name: '', authors: '', audit_status: null }); setFilterObj({ name: '', authors: '', audit_status: null })
setDateVal(''); setDateVal('')
init(); init()
}; }
const init = async (obj = {}) => { const init = async (obj = {}) => {
setLoading(true); setLoading(true)
const { total, list } = await getList({ page, page_size, ...obj }); const { total, list } = await getList({ page, page_size, ...obj })
setTotal(total); setTotal(total)
setData(list); setData(list)
setLoading(false); setLoading(false)
}; }
// 过滤 // 过滤
const handleFilter = (flag, val) => { const handleFilter = (flag, val) => {
if (flag == 'startandend') { if (flag == 'startandend') {
let val2 = val || []; let val2 = val || []
filterObj['start_time'] = parseInt( filterObj['start_time'] = parseInt(new Date(dayjs(val2[0]).format('YYYY-MM-DD') + ' 00:00:00').getTime() / 1000)
new Date(dayjs(val2[0]).format('YYYY-MM-DD') + ' 00:00:00').getTime() / 1000, const endDate = new Date(dayjs(val2[1])).getDate()
); const endTime = parseInt(new Date(dayjs(val2[1]).format('YYYY-MM-') + endDate + ' 23:59:59').getTime() / 1000)
const endDate = new Date(dayjs(val2[1])).getDate(); filterObj['end_time'] = endTime
const endTime = parseInt( setDateVal(val)
new Date(dayjs(val2[1]).format('YYYY-MM-') + endDate + ' 23:59:59').getTime() / 1000,
);
filterObj['end_time'] = endTime;
setDateVal(val);
if (!val2.length) { if (!val2.length) {
delete filterObj['start_time']; delete filterObj['start_time']
delete filterObj['end_time']; delete filterObj['end_time']
} }
} else { } else {
filterObj[flag] = val; filterObj[flag] = val
} }
for (const key in filterObj) { for (const key in filterObj) {
if (!filterObj[key]) { if (!filterObj[key]) {
delete filterObj[key]; delete filterObj[key]
} }
} }
setfilterObj({ ...filterObj }); setFilterObj({ ...filterObj })
if (!val) init(filterObj); if (!val) init(filterObj)
}; }
const delSuccess = async () => { const delSuccess = async () => {
const bool = await delUser({ id }); const bool = await delUser({ id })
bool && init(); bool && init()
setDelModal(false); setDelModal(false)
}; }
const exportSuccess = async () => { const exportSuccess = async () => {
setExportModal(false); setExportModal(false)
setLoading(true); setLoading(true)
const { name, content } = await exportBook({ id }); const { name, content } = await exportBook({ id })
if (!name) return; if (!name) return
const parser = new DOMParser(); const parser = new DOMParser()
const doc = parser.parseFromString(content, "text/html"); const doc = parser.parseFromString(content, 'text/html')
$(doc.body).find(".chapter-gallery-container, .chapter-expand, .chapter-practice, .chapter-item-link, .chapter-item-tooltip, div[data-w-e-type='video']").remove(); $(doc.body)
.find(".chapter-gallery-container, .chapter-expand, .chapter-practice, .chapter-item-link, .chapter-item-tooltip, div[data-w-e-type='video']")
.remove()
const data = await exportToPdf({ name, content: $(doc.body).html()}); const data = await exportToPdf({ name, content: $(doc.body).html() })
setLoading(false); setLoading(false)
downloadFile(`temp/${data.name}`); downloadFile(`temp/${data.name}`)
}; }
const importSuccess = async (obj) => { const importSuccess = async obj => {
setuploading(true); setUploading(true)
const bool = await importBook({ ...obj, file: bookFile }); const bool = await importBook({ ...obj, file: bookFile })
// if (!bool) return; // if (!bool) return;
if (bool) { if (bool) {
window.location.replace(window.location.href); window.location.replace(window.location.href)
} }
setImportMoadal(false); setImportModal(false)
setuploading(false); setUploading(false)
}; }
const UploadProps = { const UploadProps = {
name: 'file', name: 'file',
accept: '.doc , .docx', accept: '.doc , .docx',
showUploadList: false, showUploadList: false,
beforeUpload (file) { beforeUpload(file) {
const suffixArr = ['doc', 'docx']; const suffixArr = ['doc', 'docx']
const suffix = file.name.substring(file.name.lastIndexOf('.') + 1); const suffix = file.name.substring(file.name.lastIndexOf('.') + 1)
if (!suffixArr.includes(suffix)) { if (!suffixArr.includes(suffix)) {
message.error(`请上传以${suffixArr.join('、')}格式的书籍`); message.error(`请上传以${suffixArr.join('、')}格式的书籍`)
return false; return false
} }
setBookFile(file); setBookFile(file)
return false; return false
}, }
}; }
const handleReleaseExamine = async (obj) => { const handleReleaseExamine = async obj => {
const bool = await releaseExamine({ ...obj, id }); const bool = await releaseExamine({ ...obj, id })
if (bool) { if (bool) {
window.location.replace(window.location.href); // 几乎完美 window.location.replace(window.location.href) // 几乎完美
} }
// location.replace(location.pathname + location.search); // 还可以
// document.location.reload(); //页面刷新效果明显 if (!bool) return
// window.location.reload(); //有加载效果 setShowAudit(false)
// window.location.assign(window.location.href); //直接重载页面 init()
// location.href = location.href; // 不推荐,卡顿效果重 }
if (!bool) return;
setshowaudit(false);
init();
};
// 下载模板 // 下载模板
const handleDownload = async () => { const handleDownload = async () => {
downloadFile('书籍导入示例.docx'); downloadFile('书籍导入示例.docx')
}; }
const [flag, setFlag] = useState(true); const [uploading, setUploading] = useState(false)
const [uploading, setuploading] = useState(false);
const columns = [ const columns = [
{ {
title: '书籍名称', title: '书籍名称',
key: 'name', key: 'name',
align: 'center', align: 'center',
dataIndex: 'name', dataIndex: 'name'
}, },
{ {
title: '书籍图片', title: '书籍图片',
...@@ -182,15 +157,15 @@ const Audit = () => { ...@@ -182,15 +157,15 @@ const Audit = () => {
width={80} width={80}
height={80} height={80}
src={img} src={img}
fallback='data:image/png;base64,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' fallback="data:image/png;base64,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"
/> />
), )
}, },
{ {
title: '作者', title: '作者',
key: 'authors', key: 'authors',
align: 'center', align: 'center',
dataIndex: 'authors', dataIndex: 'authors'
}, },
{ {
title: '审核状态', title: '审核状态',
...@@ -201,182 +176,159 @@ const Audit = () => { ...@@ -201,182 +176,159 @@ const Audit = () => {
switch (audit_status) { switch (audit_status) {
case 1: case 1:
return ( return (
<Button type='link' style={{ color: '#000', cursor: 'initial' }}> <Button type="link" style={{ color: '#000', cursor: 'initial' }}>
待发布 待发布
</Button> </Button>
); )
case 2: case 2:
return ( return (
<Button type='link' style={{ color: '#000', cursor: 'initial' }}> <Button type="link" style={{ color: '#000', cursor: 'initial' }}>
审核中 审核中
</Button> </Button>
); )
case 3: case 3:
return ( return (
<Button type='link' style={{ cursor: 'initial' }} danger> <Button type="link" style={{ cursor: 'initial' }} danger>
审核未通过 审核未通过
</Button> </Button>
); )
case 4: case 4:
return ( return (
<Button type='link' style={{ color: '#000', cursor: 'initial' }}> <Button type="link" style={{ color: '#000', cursor: 'initial' }}>
审核通过 审核通过
</Button> </Button>
); )
} }
}, }
}, },
{ {
title: '发布次数', title: '发布次数',
key: 'release_num', key: 'release_num',
dataIndex: 'release_num', dataIndex: 'release_num',
width: 150, width: 150,
align: 'center', align: 'center'
}, },
{ {
title: '创建时间', title: '创建时间',
key: 'create_time', key: 'create_time',
align: 'center', align: 'center',
dataIndex: 'create_time', dataIndex: 'create_time'
}, },
{ {
title: '更新时间', title: '更新时间',
key: 'update_time', key: 'update_time',
align: 'center', align: 'center',
dataIndex: 'update_time', dataIndex: 'update_time'
}, },
{ {
title: '操作', title: '操作',
key: 'handle', key: 'handle',
dataIndex: 'handle', dataIndex: 'handle',
// align:'center',
width: 400, width: 400,
render: (_, { audit_status, id }) => { render: (_, { audit_status, id, user_id }) => {
const showButtons = !( // 审核中
operationPermissionsList.includes('/books/management/release') && audit_status === 2 if (audit_status === 2) return
); // 创建者或者管理员
const hasButton = userInfo.id === user_id || userInfo.type === 1
return ( return (
<Space> <Space>
{showButtons && operationPermissionsList.includes('/books/management/getAllList') && ( {hasButton && operationPermissionsList.includes('/books/management/getAllList') && (
<Button <Button
onClick={() => { onClick={() => {
navigate('/books/management/add-edit', { navigate('/books/management/add-edit', { state: { id: id } })
state: {
id: id,
},
});
}} }}
type='primary' type="primary"
ghost ghost>
>
基本信息 基本信息
</Button> </Button>
)} )}
{showButtons && operationPermissionsList.includes('/books/management/getInfoById') && ( {operationPermissionsList.includes('/books/management/getInfoById') && (
<Button <Button
onClick={() => { onClick={() => {
navigate('/books/management/chapter', { navigate('/books/management/chapter', { state: { id } })
state: { }}>
id,
},
});
}}
>
编辑 编辑
</Button> </Button>
)} )}
{showButtons && operationPermissionsList.includes('/books/management/export') && ( {hasButton && operationPermissionsList.includes('/books/management/export') && (
<Button <Button
onClick={() => { onClick={() => {
setId(id); setId(id)
setExportModal(true); setExportModal(true)
}} }}>
>
导出 导出
</Button> </Button>
)} )}
{showButtons && operationPermissionsList.includes('/books/management/del') && ( {hasButton && operationPermissionsList.includes('/books/management/del') && (
<Button <Button
onClick={() => { onClick={() => {
setId(id); setId(id)
setDelModal(true); setDelModal(true)
}} }}>
>
删除 删除
</Button> </Button>
)} )}
{showButtons && {hasButton && operationPermissionsList.includes('/books/management/release') && audit_status === 1 && (
operationPermissionsList.includes('/books/management/release') && <Button
audit_status === 1 && ( onClick={() => {
<Button setId(id)
onClick={() => { setShowAudit(true)
setId(id); }}>
setshowaudit(true); 发布审核
}} </Button>
> )}
发布审核
</Button>
)}
</Space> </Space>
); )
}, }
}, }
]; ]
return ( return (
<> <>
<Row justify={'space-between'}> <Row justify={'space-between'}>
<Col span={21} className='form-devices-inline'> <Col span={21} className="form-devices-inline">
<Form layout='inline'> <Form layout="inline">
<Form.Item label='书籍名称'> <Form.Item label="书籍名称">
<Input <Input
autoComplete='off' autoComplete="off"
allowClear allowClear
value={filterObj.name} value={filterObj.name}
onChange={(ev) => handleFilter('name', ev.target.value)} onChange={ev => handleFilter('name', ev.target.value)}
placeholder='请输入书籍名称' placeholder="请输入书籍名称"
id='name' id="name"></Input>
></Input>
</Form.Item> </Form.Item>
<Form.Item label='作者'> <Form.Item label="作者">
<Input <Input
autoComplete='off' autoComplete="off"
allowClear allowClear
value={filterObj.authors} value={filterObj.authors}
onChange={(ev) => handleFilter('authors', ev.target.value)} onChange={ev => handleFilter('authors', ev.target.value)}
placeholder='请输入作者' placeholder="请输入作者"
id='author' id="author"></Input>
></Input>
</Form.Item> </Form.Item>
<Form.Item label='审核状态'> <Form.Item label="审核状态">
<Select <Select
style={{ width: 160 }} style={{ width: 160 }}
allowClear allowClear
value={filterObj.audit_status} value={filterObj.audit_status}
onChange={(ev) => handleFilter('audit_status', ev)} onChange={ev => handleFilter('audit_status', ev)}
placeholder='请选择审核状态' placeholder="请选择审核状态"
id='status' id="status">
> <Select.Option value="1">待发布</Select.Option>
<Select.Option value='1'>待发布</Select.Option> <Select.Option value="2">审核中</Select.Option>
<Select.Option value='2'>审核中</Select.Option> <Select.Option value="3">审核未通过</Select.Option>
<Select.Option value='3'>审核未通过</Select.Option> <Select.Option value="4">审核通过</Select.Option>
<Select.Option value='4'>审核通过</Select.Option>
</Select> </Select>
</Form.Item> </Form.Item>
<Form.Item label='创建时间'> <Form.Item label="创建时间">
<RangePicker <RangePicker value={dateVal} onChange={ev => handleFilter('startandend', ev)} id="createTime"></RangePicker>
value={dateVal}
onChange={(ev) => handleFilter('startandend', ev)}
id='createTime'
></RangePicker>
</Form.Item> </Form.Item>
<Space> <Space>
<Button <Button
type='primary' type="primary"
// ghost={flag} // ghost={flag}
ghost ghost
icon={ icon={
...@@ -385,44 +337,37 @@ const Audit = () => { ...@@ -385,44 +337,37 @@ const Audit = () => {
display: 'inline-block', display: 'inline-block',
width: '11px', width: '11px',
height: '10px', height: '10px',
pointerEvents: 'none', pointerEvents: 'none'
}} }}>
>
<Image src={reset} /> <Image src={reset} />
</span> </span>
} }
// onMouseOver={() => { onClick={handleReset}>
// setFlag(!flag);
// }}
onClick={handleReset}
>
重置 重置
</Button> </Button>
<Button <Button
type='primary' type="primary"
icon={ icon={
<span <span
style={{ style={{
display: 'inline-block', display: 'inline-block',
width: '13px', width: '13px',
height: '12px', height: '12px',
pointerEvents: 'none', pointerEvents: 'none'
}} }}>
>
<Image src={filter} /> <Image src={filter} />
</span> </span>
} }
ghost ghost
onClick={() => { onClick={() => {
setPage(1); setPage(1)
console.log(filterObj); console.log(filterObj)
Object.values(filterObj).some((item) => item) ? init(filterObj) : init(); Object.values(filterObj).some(item => item) ? init(filterObj) : init()
}} }}>
>
筛选 筛选
</Button> </Button>
<Button <Button
type='primary' type="primary"
ghost ghost
icon={ icon={
<span <span
...@@ -430,16 +375,14 @@ const Audit = () => { ...@@ -430,16 +375,14 @@ const Audit = () => {
display: 'inline-block', display: 'inline-block',
width: '10px', width: '10px',
height: '12px', height: '12px',
pointerEvents: 'none', pointerEvents: 'none'
}} }}>
>
<Image src={reload} /> <Image src={reload} />
</span> </span>
} }
onClick={() => { onClick={() => {
Object.values(filterObj).some((item) => item) ? init(filterObj) : init(); Object.values(filterObj).some(item => item) ? init(filterObj) : init()
}} }}>
>
刷新 刷新
</Button> </Button>
</Space> </Space>
...@@ -449,43 +392,39 @@ const Audit = () => { ...@@ -449,43 +392,39 @@ const Audit = () => {
<Space> <Space>
{operationPermissionsList.includes('/books/management/import') && ( {operationPermissionsList.includes('/books/management/import') && (
<Button <Button
type='primary' type="primary"
icon={ icon={
<span <span
style={{ style={{
display: 'inline-block', display: 'inline-block',
width: '11px', width: '11px',
height: '12px', height: '12px',
pointerEvents: 'none', pointerEvents: 'none'
}} }}>
>
<Image src={imports} /> <Image src={imports} />
</span> </span>
} }
ghost ghost
onClick={() => setImportMoadal(true)} onClick={() => setImportModal(true)}>
>
导入 导入
</Button> </Button>
)} )}
{operationPermissionsList.includes('/books/management/add') && ( {operationPermissionsList.includes('/books/management/add') && (
<Button <Button
type='primary' type="primary"
icon={ icon={
<span <span
style={{ style={{
display: 'inline-block', display: 'inline-block',
width: '13px', width: '13px',
height: '12px', height: '12px',
pointerEvents: 'none', pointerEvents: 'none'
}} }}>
>
<Image src={add} /> <Image src={add} />
</span> </span>
} }
ghost ghost
onClick={() => navigate('/books/management/add-edit')} onClick={() => navigate('/books/management/add-edit')}>
>
添加 添加
</Button> </Button>
)} )}
...@@ -495,76 +434,63 @@ const Audit = () => { ...@@ -495,76 +434,63 @@ const Audit = () => {
<Modal <Modal
mask={false} mask={false}
centered centered
open={delMoadal} open={delModal}
onOk={delSuccess} onOk={delSuccess}
onCancel={() => setDelModal(false)} onCancel={() => setDelModal(false)}
footer={(_, { OkBtn, CancelBtn }) => { footer={(_, { OkBtn, CancelBtn }) => {
return ( return (
<Row justify={'center'} className='delModal' style={{ marginBottom: '30px' }}> <Row justify={'center'} className="delModal" style={{ marginBottom: '30px' }}>
<Space size={20}> <Space size={20}>
<CancelBtn className='cancel' /> <CancelBtn className="cancel" />
<OkBtn className='true' /> <OkBtn className="true" />
</Space> </Space>
</Row> </Row>
); )
}} }}
okText='确认' okText="确认"
ghost ghost>
>
<p style={{ textAlign: 'center', padding: '30px 0 18px', fontSize: 16 }}>确认删除书籍?</p> <p style={{ textAlign: 'center', padding: '30px 0 18px', fontSize: 16 }}>确认删除书籍?</p>
</Modal> </Modal>
<Modal <Modal
mask={false} mask={false}
centered centered
open={exportMoadal} open={exportModal}
onOk={exportSuccess} onOk={exportSuccess}
onCancel={() => setExportModal(false)} onCancel={() => setExportModal(false)}
footer={(_, { OkBtn, CancelBtn }) => { footer={(_, { OkBtn, CancelBtn }) => {
return ( return (
<Row justify={'center'} className='delModal' style={{ marginBottom: '30px' }}> <Row justify={'center'} className="delModal" style={{ marginBottom: '30px' }}>
<Space size={20}> <Space size={20}>
<CancelBtn className='cancel' /> <CancelBtn className="cancel" />
<OkBtn className='true' /> <OkBtn className="true" />
</Space> </Space>
</Row> </Row>
); )
}} }}
okText='确认' okText="确认">
> <p style={{ textAlign: 'center', padding: '30px 0 18px', fontSize: 16 }}>只能导出文本部分,画廊、音频、视频不支持</p>
<p style={{ textAlign: 'center', padding: '30px 0 18px', fontSize: 16 }}>
只能导出文本部分,画廊、音频、视频不支持
</p>
</Modal> </Modal>
<Drawer <Drawer mask={false} centered open={importModal} onCancel={() => setImportModal(false)} onClose={() => setImportModal(false)} footer={null} okText="确认">
mask={false}
centered
open={importMoadal}
onCancel={() => setImportMoadal(false)}
onClose={() => setImportMoadal(false)}
footer={null}
okText='确认'
>
<Spin spinning={uploading}> <Spin spinning={uploading}>
<Form labelCol={{ span: 8 }} onFinish={importSuccess}> <Form labelCol={{ span: 8 }} onFinish={importSuccess}>
<Form.Item label='下载模板' style={{ marginBottom: 10 }}> <Form.Item label="下载模板" style={{ marginBottom: 10 }}>
<Button ghost type='primary' onClick={handleDownload}> <Button ghost type="primary" onClick={handleDownload}>
下载模板 下载模板
</Button> </Button>
</Form.Item> </Form.Item>
<p <p
className='linetext' className="linetext"
style={{ style={{
fontWeight: 400, fontWeight: 400,
color: '#999999', color: '#999999',
fontSize: 12, fontSize: 12,
marginBottom: 30, marginBottom: 30,
paddingLeft: 75, paddingLeft: 75
}} }}>
>
目录需设置为word中的标题样式或按照示例编写,防止导入失败 目录需设置为word中的标题样式或按照示例编写,防止导入失败
</p> </p>
<Form.Item label='选择书籍' required> <Form.Item label="选择书籍" required>
<Form.Item name='file' rules={[{ required: true, message: '请上传书籍' }]} noStyle> <Form.Item name="file" rules={[{ required: true, message: '请上传书籍' }]} noStyle>
<Upload {...UploadProps}> <Upload {...UploadProps}>
<Button>点击上传</Button> <Button>点击上传</Button>
</Upload> </Upload>
...@@ -572,12 +498,8 @@ const Audit = () => { ...@@ -572,12 +498,8 @@ const Audit = () => {
<p style={{ color: '#999999' }}>{bookFile?.name}</p> <p style={{ color: '#999999' }}>{bookFile?.name}</p>
</Form.Item> </Form.Item>
<Form.Item <Form.Item label="目录结构等级" name="catalog_level" rules={[{ required: true, message: '请选择目录结构等级' }]}>
label='目录结构等级' <Select placeholder="请选择目录结构的等级" style={{ width: 260 }}>
name='catalog_level'
rules={[{ required: true, message: '请选择目录结构等级' }]}
>
<Select placeholder='请选择目录结构的等级' style={{ width: 260 }}>
<Select.Option value={1}>标题1</Select.Option> <Select.Option value={1}>标题1</Select.Option>
<Select.Option value={2}>标题2</Select.Option> <Select.Option value={2}>标题2</Select.Option>
<Select.Option value={3}>标题3</Select.Option> <Select.Option value={3}>标题3</Select.Option>
...@@ -586,14 +508,10 @@ const Audit = () => { ...@@ -586,14 +508,10 @@ const Audit = () => {
</Select> </Select>
</Form.Item> </Form.Item>
<Form.Item> <Form.Item>
<Row <Row justify={'center'} className="delModal" style={{ marginBottom: '30px', marginTop: '0px' }}>
justify={'center'}
className='delModal'
style={{ marginBottom: '30px', marginTop: '0px' }}
>
<Space size={20}> <Space size={20}>
<Button onClick={() => setImportMoadal(false)}>取消</Button> <Button onClick={() => setImportModal(false)}>取消</Button>
<Button type='primary' htmlType='submit'> <Button type="primary" htmlType="submit">
确认 确认
</Button> </Button>
</Space> </Space>
...@@ -602,32 +520,27 @@ const Audit = () => { ...@@ -602,32 +520,27 @@ const Audit = () => {
</Form> </Form>
</Spin> </Spin>
</Drawer> </Drawer>
<Drawer placement='right' onClose={() => setshowaudit(false)} open={showaudit} mask={false}> <Drawer placement="right" onClose={() => setShowAudit(false)} open={showAudit} mask={false}>
<Form labelCol={{ span: 5 }} onFinish={handleReleaseExamine}> <Form labelCol={{ span: 5 }} onFinish={handleReleaseExamine}>
<Form.Item <Form.Item label="发布信息" name="release_mess" rules={[{ max: 255, message: '最大255字符' }]}>
label='发布信息'
name='release_mess'
rules={[{ max: 255, message: '最大255字符' }]}
>
<TextArea <TextArea
placeholder='请输入发布信息' placeholder="请输入发布信息"
autoSize={{ autoSize={{
minRows: 5, minRows: 5,
maxRows: 8, maxRows: 8
}} }}
/> />
</Form.Item> </Form.Item>
<Form.Item wrapperCol={{ offset: 10, span: 16 }}> <Form.Item wrapperCol={{ offset: 10, span: 16 }}>
<Space size={20}> <Space size={20}>
<Button <Button
className='cancel' className="cancel"
onClick={() => { onClick={() => {
setshowaudit(false); setShowAudit(false)
}} }}>
>
取消 取消
</Button> </Button>
<Button className='submit' htmlType='submit'> <Button className="submit" htmlType="submit">
发布 发布
</Button> </Button>
</Space> </Space>
...@@ -637,17 +550,9 @@ const Audit = () => { ...@@ -637,17 +550,9 @@ const Audit = () => {
<br /> <br />
{TableCom({ columns, loading, data })} {TableCom({ columns, loading, data })}
<br /> <br />
<PaginationCom <PaginationCom total={total} page_size={page_size} setpage_size={setpage_size} page={page} setPage={setPage} init={init} filterObj={filterObj} />
total={total}
page_size={page_size}
setpage_size={setpage_size}
page={page}
setPage={setPage}
init={init}
filterObj={filterObj}
/>
</> </>
); )
}; }
export default Audit; export default Audit
import axios from '@/utils/axios' import axios from '@/utils/axios'
// 获取书籍详情
export function getBook(data) {
return axios.post('/api/book/teacher/getInfoById', data)
}
// 获取章节列表
export function getChapterList(data) {
return axios.post('/api/book/teacher/chapter/getAllList', data)
}
// 获取章节详情
export function getChapter(data) {
return axios.post('/api/book/teacher/chapter/getInfoById', data)
}
// 添加章节
export function addChapter(data) {
return axios.post('/api/book/teacher/chapter/add', data)
}
// 修改章节
export function updateChapter(data) {
return axios.post('/api/book/teacher/chapter/edit', data)
}
// 删除章节
export function delChapter(data) {
return axios.post('/api/book/teacher/chapter/del', data)
}
// 章节排序
export function sortChapter(data) {
return axios.post('/api/book/teacher/chapter/dragOrder', data)
}
// 获取章节编辑者信息 // 获取章节编辑者信息
export function getChapterEditors(data) { export function getChapterEditors(data) {
return axios.post('/api/book/teacher/chapter/getEditors', data) return axios.post('/api/book/teacher/chapter/getEditors', data)
......
...@@ -21,11 +21,11 @@ const EditChapterEditors = ({ chapter = {}, onChange, ...props }) => { ...@@ -21,11 +21,11 @@ const EditChapterEditors = ({ chapter = {}, onChange, ...props }) => {
} }
return ( return (
<Modal title="设置章节编写者" {...props} onOk={handleSubmit}> <Modal title="设置章节编写者" centered {...props} onOk={handleSubmit}>
<Form labelCol={{ span: 8 }}> <Form labelCol={{ span: 8 }}>
<Form.Item label="当前章节">{chapter.title}</Form.Item> <Form.Item label="当前章节">{chapter.title}</Form.Item>
<Form.Item label="编写者"> <Form.Item label="编写者">
<Radio.Group value={value} onChange={e => setValue(e.target.value)}> <Radio.Group value={value} onChange={e => setValue(e.target.value)} style={{ marginTop: '6px' }}>
<Space direction="vertical"> <Space direction="vertical">
{editors.map(item => { {editors.map(item => {
return ( return (
......
import { useState, useEffect, useRef } from 'react' import { useState, useEffect, useRef } from 'react'
import { Divider, Button, Row, Col, Descriptions, Tree, Dropdown, Space, Modal, Spin } from 'antd' import { Button, Row, Col, Descriptions, Tree, Dropdown, Modal, Spin, App } from 'antd'
import { EllipsisOutlined, DiffOutlined, MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons' import { EllipsisOutlined, DiffOutlined, MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons'
import WangEditorCustomer from '@/common/wangeditor-customer' import WangEditorCustomer from '@/common/wangeditor-customer'
import { useLocation, useNavigate } from 'react-router-dom' import { useLocation, useNavigate } from 'react-router-dom'
...@@ -12,23 +12,22 @@ import { get } from 'lodash-es' ...@@ -12,23 +12,22 @@ import { get } from 'lodash-es'
import md5 from 'js-md5' import md5 from 'js-md5'
import { convertToAntdTreeData, findTreeElementByKey, findFirstNotHasChildren, findParentLevelOne, findTreeToIndex, findNodeById } from '@/utils/common' import { convertToAntdTreeData, findTreeElementByKey, findFirstNotHasChildren, findParentLevelOne, findTreeToIndex, findNodeById } from '@/utils/common'
import { getAllList, getInfoByChapterId, sectionEdit, chapterDel, dragOrder, getRecordList, getUserInfo, getPowerByRoleId } from './request' import { getAllList, getInfoByChapterId, sectionEdit, chapterDel, dragOrder } from './request'
import './index.less' import './index.less'
const Examine = () => { const Examine = () => {
const { modal } = App.useApp()
const location = useLocation() const location = useLocation()
const id = get(location, 'state.id', '') const id = get(location, 'state.id', '')
const { treeChapter } = useSelector(state => state.user) const { treeChapter, userInfo } = useSelector(state => state.user)
const navigate = useNavigate() const navigate = useNavigate()
const dispatch = useDispatch() const dispatch = useDispatch()
const [gData, setGData] = useState([]) const [gData, setGData] = useState([])
const [chapterId, setChapterId] = useState(0) const [chapterId, setChapterId] = useState(0)
const [bookId, setBookId] = useState(0) const [bookId, setBookId] = useState(0)
const [openDel, setOpenDel] = useState(false)
const [delNode, setDelNode] = useState({})
const [recordList, setRecordList] = useState([])
// 树节点设置 // 树节点设置
const [expandedKeys, setExpandedKeys] = useState([]) const [expandedKeys, setExpandedKeys] = useState([])
...@@ -40,9 +39,7 @@ const Examine = () => { ...@@ -40,9 +39,7 @@ const Examine = () => {
const [parentId, setParentId] = useState(null) const [parentId, setParentId] = useState(null)
const [editValue, setEditValue] = useState('') const [editValue, setEditValue] = useState('')
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [delLoading, setDelLoading] = useState(false)
const [contentMd5, setContentMd5] = useState('') const [contentMd5, setContentMd5] = useState('')
const [quanXian, setQuanXian] = useState(false)
// 设置编者 // 设置编者
const [currentChapter, setCurrentChapter] = useState(null) const [currentChapter, setCurrentChapter] = useState(null)
...@@ -107,15 +104,6 @@ const Examine = () => { ...@@ -107,15 +104,6 @@ const Examine = () => {
setLoading(false) setLoading(false)
} }
//选中了章节管理才展示编辑
const getQuanXian = async () => {
const data = await getUserInfo()
const data1 = await getPowerByRoleId({ role_id: data.id })
if (!data1.includes(37)) {
setQuanXian(true)
}
}
const newChapterChange = (id, title) => { const newChapterChange = (id, title) => {
setChapterId(parseInt(id)) setChapterId(parseInt(id))
setCheckedKeys([parseInt(id)]) setCheckedKeys([parseInt(id)])
...@@ -132,11 +120,12 @@ const Examine = () => { ...@@ -132,11 +120,12 @@ const Examine = () => {
}) })
return keys return keys
} }
const [disabled, setDisabled] = useState(false)
// 获取内容 // 获取内容
const getChapterVal = async () => { const getChapterVal = async () => {
setLoading(true) setLoading(true)
const data = await getInfoByChapterId({ chapter_id: chapterId }) const data = await getInfoByChapterId({ chapter_id: chapterId })
setDisabled(!data.selected_editor_ids.includes(userInfo.id))
dispatch(setTreeChapter({ saveBookId: id, saveChapterId: chapterId })) dispatch(setTreeChapter({ saveBookId: id, saveChapterId: chapterId }))
const { content, id: cId } = data const { content, id: cId } = data
...@@ -198,7 +187,6 @@ const Examine = () => { ...@@ -198,7 +187,6 @@ const Examine = () => {
useEffect(() => { useEffect(() => {
getChapterTreeList() getChapterTreeList()
getQuanXian()
}, []) }, [])
useEffect(() => { useEffect(() => {
if (chapterId) { if (chapterId) {
...@@ -226,29 +214,15 @@ const Examine = () => { ...@@ -226,29 +214,15 @@ const Examine = () => {
return return
} else { } else {
setContentMd5(newMd5) setContentMd5(newMd5)
autoSaveContent(newMd5)
dispatch(setAutosaveTime(Date.now())) dispatch(setAutosaveTime(Date.now()))
} }
} }
} }
} }
// 定时器轮询
const autoSaveContent = newMd5 => {
// clearInterval(saveInterRef.current);
// saveInterRef.current = setInterval(async () => {
// if (!contentMd5 || (newMd5 !== contentMd5 && contentMd5)) {
// // console.log('save', newMd5, '不一样的');
// await saveContent();
// } else {
// // console.log('save', newMd5, '一样的');
// }
// }, 5000);
}
useEffect(() => { useEffect(() => {
if (!loading && contentId) { if (!loading && contentId) {
let newMd5 = md5(html)
clearInterval(saveInterRef.current) clearInterval(saveInterRef.current)
autoSaveContent(newMd5)
} else { } else {
clearInterval(saveInterRef.current) clearInterval(saveInterRef.current)
} }
...@@ -261,7 +235,6 @@ const Examine = () => { ...@@ -261,7 +235,6 @@ const Examine = () => {
} }
const delChapter = async node => { const delChapter = async node => {
setDelLoading(true)
const childInKey = findParentLevelOne(gData, 'key', node.key) const childInKey = findParentLevelOne(gData, 'key', node.key)
let current = null let current = null
if (childInKey && childInKey.children && childInKey.children.length > 0) { if (childInKey && childInKey.children && childInKey.children.length > 0) {
...@@ -297,11 +270,8 @@ const Examine = () => { ...@@ -297,11 +270,8 @@ const Examine = () => {
const data = await chapterDel({ id: node.key }) const data = await chapterDel({ id: node.key })
if (data) { if (data) {
await dispatch(setTreeChapter({ saveBookId: id, saveChapterId: current ? current.key : null })) await dispatch(setTreeChapter({ saveBookId: id, saveChapterId: current ? current.key : null }))
setDelNode({})
setOpenDel(false)
await getChapterTreeList() await getChapterTreeList()
} }
setDelLoading(false)
} }
useEffect(() => { useEffect(() => {
...@@ -344,8 +314,13 @@ const Examine = () => { ...@@ -344,8 +314,13 @@ const Examine = () => {
setEditValue(node.title) setEditValue(node.title)
setParentId(false) setParentId(false)
} else if (parseInt(e.key) === 4) { } else if (parseInt(e.key) === 4) {
setDelNode(node) await modal.confirm({
setOpenDel(true) title: '删除确认',
content: `确认删除子节【${node.title}】?`,
onOk() {
delChapter(node)
}
})
} else if (e.key == 5) { } else if (e.key == 5) {
setEditChapterEditorsIsOpen(true) setEditChapterEditorsIsOpen(true)
} }
...@@ -431,15 +406,13 @@ const Examine = () => { ...@@ -431,15 +406,13 @@ const Examine = () => {
{ {
key: '1', key: '1',
label: ( label: (
<> <Row gutter={5} justify={'space-between'} style={{ alignItems: 'center' }}>
<Row gutter={5} justify={'space-between'} style={{ alignItems: 'center' }}> <Col>章节目录</Col>
<Col>章节目录</Col> <Col>
<Col> <Button type="text" icon={<DiffOutlined />} onClick={addChapterParent}></Button>
<Button type="text" icon={<DiffOutlined />} onClick={addChapterParent}></Button> <Button type="text" icon={<MenuFoldOutlined />} onClick={() => setisCollapse(true)}></Button>
<Button type="text" icon={<MenuFoldOutlined />} onClick={() => setisCollapse(true)}></Button> </Col>
</Col> </Row>
</Row>
</>
) )
} }
]} ]}
...@@ -471,13 +444,11 @@ const Examine = () => { ...@@ -471,13 +444,11 @@ const Examine = () => {
{ {
key: '1', key: '1',
label: ( label: (
<> <Row gutter={5} justify={'space-between'} style={{ alignItems: 'center' }}>
<Row gutter={5} justify={'space-between'} style={{ alignItems: 'center' }}> <Col>
<Col> <Button type="text" icon={<MenuUnfoldOutlined />} onClick={() => setisCollapse(false)}></Button>
<Button type="text" icon={<MenuUnfoldOutlined />} onClick={() => setisCollapse(false)}></Button> </Col>
</Col> </Row>
</Row>
</>
) )
} }
]} ]}
...@@ -498,7 +469,7 @@ const Examine = () => { ...@@ -498,7 +469,7 @@ const Examine = () => {
saveContent={saveContent} saveContent={saveContent}
gData={gData} gData={gData}
nowTitle={nowTitle} nowTitle={nowTitle}
recordList={recordList} disabled={disabled}
/> />
</Spin> </Spin>
</div> </div>
...@@ -534,38 +505,6 @@ const Examine = () => { ...@@ -534,38 +505,6 @@ const Examine = () => {
/> />
</Modal> </Modal>
<Modal
open={openDel}
footer={null}
centered
destroyOnClose
title={'删除确认'}
maskClosable={false}
mask={true}
closeIcon={false} // 添加这一行以隐藏关闭按钮
onCancel={() => setOpenDel(false)}
classNames={{
wrapper: 'chapter-title-modal'
}}>
<Divider />
<div>确认删除子节【{delNode.title}】?</div>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Space>
<Button type="primary" danger loading={delLoading} onClick={() => delChapter(delNode)}>
确定
</Button>
<Button
type="default"
onClick={() => {
setDelNode({})
setOpenDel(false)
}}>
取消
</Button>
</Space>
</div>
</Modal>
{/* 设置章节编写者 */} {/* 设置章节编写者 */}
{currentChapter && editChapterEditorsIsOpen && ( {currentChapter && editChapterEditorsIsOpen && (
<EditChapterEditors <EditChapterEditors
......
.examine { .examine {
height: 100%; height: 100%;
.content-box { .content-box {
padding-top: 14px;
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
overflow: hidden; overflow: hidden;
......
import { create } from 'zustand'
const useUserStore = create((set, get) => ({
user: {},
token: '',
permissions: [],
updateUser: user => set({ user }),
updateToken: token => set({ token }),
updatePermissions: permissions => set({ permissions }),
checkPermissions: permission => {
const { permissions } = get()
return permissions.includes(permission)
}
}))
export default useUserStore
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论