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

chore: update

上级 6737d2b7
......@@ -7053,6 +7053,7 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.2.0.tgz",
"integrity": "sha512-9lOQ7kBekEJRdEpScHvtmEtXnAsy+NGDXiRWc2ZVC7QXAazNVbeT4EraQKYwCME8BJLa8Bxqxvs5swwyOepRwg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@rc-component/portal": "^1.1.1",
......@@ -7326,6 +7327,7 @@
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.13.0.tgz",
"integrity": "sha512-oxvx1Q5k5wD30sjN5tqAyWTvJfLNNJn7Oq3IeS4HxWfAiC4BOXMITNAsw7u/fzdtO4MS8Ki8uRLOzcnEuoQiAw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.5",
......
......@@ -53,28 +53,6 @@ dd {
min-width: 475px;
}
.submit {
background: #aa1941;
border-radius: 4px;
color: #ffffff;
font-size: 14px;
&:hover {
color: #ffffff !important;
background: #aa194283 !important;
}
}
// .cancel {
// background: #ffffff;
// border-radius: 4px;
// border: 1px solid #aa1941;
// font-size: 14px;
// color: #aa1941;
// &:hover {
// background: #ffffff7c !important;
// border-color: #aa194283 !important;
// color: #aa194283 !important;
// }
// }
.ant-input-number .ant-input-number-input {
text-align: center;
}
......@@ -84,9 +62,6 @@ dd {
.ant-form-inline .ant-form-item {
margin-inline-end: 20px;
}
// .inline,.ant-space-item{
// display: inline-block !important;
// }
.inline {
display: inline-block !important;
}
......@@ -110,31 +85,6 @@ dd {
}
}
// @font-face {
// font-family: "思源黑体";
// src: url("https://zxts-common-file.zijingebook.com/2024/03/19/video-1710838306427-vhs7ha8w5jj.ttf") format('truetype');
// }
// @font-face {
// font-family: "思源宋体";
// src: url("https://zxts-common-file.zijingebook.com/2024/03/19/video-1710848430762-z2hb59oxz4h.ttf") format('truetype');
// }
// @font-face {
// font-family: "楷体";
// src: url("https://zxts-common-file.zijingebook.com/2024/03/19/video-1710838338781-dxbppd4g6va.ttf") format('truetype');
// }
// @font-face {
// font-family: "仿宋";
// src: url("https://zxts-common-file.zijingebook.com/2024/03/19/video-1710838378832-blsljc5hycd.ttf") format('truetype');
// }
// @font-face {
// font-family: "宋体";
// src: url("https://zxts-common-file.zijingebook.com/2024/03/19/video-1710838324940-8vqbbw0lotx.ttf") format('truetype');
// }
// @font-face {
// font-family: "黑体";
// src: url("https://zxts-common-file.zijingebook.com/2024/03/19/video-1710838356409-40podr4vede.ttf") format('truetype');
// }
@font-face {
font-family: '思源黑体';
src: url('https://zxts-book-file.zijingebook.com/2024/04/03/fonts-1712131326219-q886x58lgm.ttf') format('truetype');
......
......@@ -20,3 +20,13 @@ export function aiGenerateImage(data) {
export function baiduAIChat(data) {
return axios.post('/api/ai/baidubce/chat', data)
}
// 题目分类自动添加(名称存在则返回数据,不存在则创建)
export function addType(data) {
return axios.post('/api/type/autoAdd', data)
}
// 创建试题
export function addQuestion(data) {
return axios.post('/api/question/add', data)
}
......@@ -153,7 +153,7 @@ const tabsMenu = [
storageChange()
const WangEditorCustomer = (props, ref) => {
const { chapterId, bookId, contentId, html, setHtml, saveContent, gData, nowTitle, disabled } = props
const { chapterId, bookId, contentId, html, setHtml, saveContent, gData, nowTitle, disabled, isView = false } = props
const dispatch = useDispatch()
// 自动保存时间
......@@ -444,6 +444,7 @@ const WangEditorCustomer = (props, ref) => {
const toolSettingReplace = () => {
setTimeout(() => {
const editorToolbar = document.querySelector('.editor-toolbar-container')
if (!editorToolbar) return
// 设置菜单模块标题
const dividerElements = editorToolbar.querySelectorAll('.w-e-bar-divider')
const dividerTitles = ['常用格式', '媒体资源', '高级模块', 'AI文本辅助', 'AI试题辅助', '更多AI功能']
......@@ -638,7 +639,9 @@ const WangEditorCustomer = (props, ref) => {
// 预览
const previewIt = async () => {
if (!isView) {
await saveContent()
}
setPreviewVisible(true)
}
......@@ -677,6 +680,8 @@ const WangEditorCustomer = (props, ref) => {
</div>
<div className="right">
<Space>
{!isView && (
<>
<div className="save-time">
<div className="img">
<img src={timesave} /> <span>自动保存</span>
......@@ -694,9 +699,12 @@ const WangEditorCustomer = (props, ref) => {
disabled={disabled || !contentId}>
保存
</Button>
</>
)}
<Button icon={<EyeOutlined />} className="history" onClick={previewIt} disabled={!contentId}>
预览
</Button>
{!isView && (
<Button
icon={<HistoryOutlined />}
className="history"
......@@ -704,6 +712,7 @@ const WangEditorCustomer = (props, ref) => {
disabled={disabled || !contentId}>
历史
</Button>
)}
</Space>
</div>
</div>
......@@ -717,7 +726,7 @@ const WangEditorCustomer = (props, ref) => {
style={{ height: 'calc(100vh - 250px)', overflowY: 'hidden' }}
/>
</div>
{!isView && (
<div className="menu-tabs-key">
<div className="tabs">
{tabsMenu &&
......@@ -766,6 +775,7 @@ const WangEditorCustomer = (props, ref) => {
)}
</div>
</div>
)}
<Modal
open={imageVisible}
footer={null}
......
......@@ -9,7 +9,7 @@ class AIContentInspect extends BaseModalMenu {
this.iconSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M11.5 13.5q.525 0 .988-.137t.912-.413l1.525 1.575q.2.225.513.213t.537-.213q.225-.225.238-.537T16 13.45l-1.55-1.55q.275-.425.413-.9T15 10q0-1.475-1.038-2.488T11.5 6.5T9.037 7.513T8 10t1.038 2.488T11.5 13.5m0-1.5q-.825 0-1.412-.587T9.5 10t.588-1.412T11.5 8q.8 0 1.4.588T13.5 10t-.587 1.413T11.5 12M2 21q-.425 0-.712-.288T1 20t.288-.712T2 19h20q.425 0 .713.288T23 20t-.288.713T22 21zm2-3q-.825 0-1.412-.587T2 16V5q0-.825.588-1.412T4 3h16q.825 0 1.413.588T22 5v11q0 .825-.587 1.413T20 18zm0-2h16V5H4zm0 0V5z"/></svg>`
}
getValue(editor) {
return <AIModal key={Date.now()} editor={editor} docAction="contentInspect"></AIModal>
return <AIModal key={Date.now()} editor={editor} action="contentInspect"></AIModal>
}
}
......
......@@ -15,7 +15,7 @@ class AIExpand extends BaseModalMenu {
</svg>`
}
getValue(editor) {
return <AIModal key={Date.now()} editor={editor} docAction="expand"></AIModal>
return <AIModal key={Date.now()} editor={editor} action="expand"></AIModal>
}
}
......
......@@ -20,7 +20,7 @@ class AIPolishing extends BaseModalMenu {
</svg>`
}
getValue(editor) {
return <AIModal key={Date.now()} editor={editor} docAction="abbreviate"></AIModal>
return <AIModal key={Date.now()} editor={editor} action="abbreviate"></AIModal>
}
}
......
......@@ -9,7 +9,7 @@ class AIPunctuation extends BaseModalMenu {
this.iconSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 1024 1024"><path fill="currentColor" d="M920 416H616c-4.4 0-8 3.6-8 8v112c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-56h60v320h-46c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h164c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8h-46V480h60v56c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V424c0-4.4-3.6-8-8-8M656 296V168c0-4.4-3.6-8-8-8H104c-4.4 0-8 3.6-8 8v128c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-64h168v560h-92c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h264c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8h-92V232h168v64c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8"/></svg>`
}
getValue(editor) {
return <AIModal key={Date.now()} editor={editor} docAction="punctuation"></AIModal>
return <AIModal key={Date.now()} editor={editor} action="punctuation"></AIModal>
}
}
......
// Extend menu
class AIQuestionJudge {
import BaseModalMenu from './common/BaseModalMenu'
import AIQuestionModal from './common/AIQuestionModal'
class AIQuestionJudge extends BaseModalMenu {
constructor() {
super()
this.title = '判断题'
this.iconSvg = `<svg t="1729144923785" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="713" width="200" height="200"><path d="M804.672 27.968H219.328A182.528 182.528 0 0 0 36.672 210.624v585.408a182.528 182.528 0 0 0 182.656 182.592h585.408a182.528 182.528 0 0 0 182.656-182.656V210.624A182.144 182.144 0 0 0 804.672 27.968z m110.08 768a109.952 109.952 0 0 1-110.08 110.08H219.328a109.952 109.952 0 0 1-110.08-110.08V210.624a109.952 109.952 0 0 1 110.08-110.08h585.408a109.952 109.952 0 0 1 110.08 110.08z m-172.096-573.632l-511.04 511.04-4.096 5.248a37.248 37.248 0 0 0 4.096 46.848 36.736 36.736 0 0 0 51.2 0l511.04-511.04 4.096-5.248a37.248 37.248 0 0 0-4.096-46.848 35.712 35.712 0 0 0-51.2 0z m-4.672 468.288l56.192-56.192 4.096-4.672a30.336 30.336 0 0 0-46.848-38.08l-56.192 56.192-56.192-56.192-4.672-4.096a30.336 30.336 0 0 0-38.08 46.848l56.192 56.192-56.192 56.192-4.096 4.672a30.336 30.336 0 0 0 46.848 38.08l56.192-56.192 56.192 56.192 4.672 4.096a30.336 30.336 0 0 0 38.08-46.848z m-459.52-255.36a32.704 32.704 0 0 0 22.272 11.136h1.152a34.496 34.496 0 0 0 22.848-9.344l148.032-148.608 2.368-2.944a35.968 35.968 0 0 0 0-43.328 28.544 28.544 0 0 0-22.272-11.136 36.288 36.288 0 0 0-24 9.344L309.568 359.296l-38.4-62.656-2.368-2.944a30.4 30.4 0 0 0-42.432-4.032 35.392 35.392 0 0 0-8.768 46.272l58.56 96.576 2.368 2.944z" fill="#999999" p-id="714"></path></svg>`
this.tag = 'button'
}
getValue() {
return 'hello, 音频'
}
isActive() {
return false
}
isDisabled() {
return true
}
exec() {
return
getValue(editor) {
return <AIQuestionModal key={Date.now()} editor={editor} action="3"></AIQuestionModal>
}
}
......
// Extend menu
class AIQuestionMultiple {
import BaseModalMenu from './common/BaseModalMenu'
import AIQuestionModal from './common/AIQuestionModal'
class AIQuestionMultiple extends BaseModalMenu {
constructor() {
super()
this.title = '多选题'
this.iconSvg = `<svg t="1729144537633" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4530" width="200" height="200"><path d="M358.4 256h460.8a51.2 51.2 0 0 1 0 102.4H358.4a51.2 51.2 0 1 1 0-102.4zM204.8 358.4a51.2 51.2 0 1 1 0-102.4 51.2 51.2 0 0 1 0 102.4z m0 204.8a51.2 51.2 0 1 1 0-102.4 51.2 51.2 0 0 1 0 102.4z m153.6-102.4h460.8a51.2 51.2 0 0 1 0 102.4H358.4a51.2 51.2 0 0 1 0-102.4z m0 204.8h460.8a51.2 51.2 0 0 1 0 102.4H358.4a51.2 51.2 0 0 1 0-102.4z" fill="#4C4C4C" p-id="4531"></path><path d="M204.8 51.2a153.6 153.6 0 0 0-153.6 153.6v614.4a153.6 153.6 0 0 0 153.6 153.6h614.4a153.6 153.6 0 0 0 153.6-153.6V204.8a153.6 153.6 0 0 0-153.6-153.6H204.8z m0-51.2h614.4a204.8 204.8 0 0 1 204.8 204.8v614.4a204.8 204.8 0 0 1-204.8 204.8H204.8a204.8 204.8 0 0 1-204.8-204.8V204.8a204.8 204.8 0 0 1 204.8-204.8z" fill="#4C4C4C" p-id="4532"></path></svg>`
this.tag = 'button'
}
getValue() {
return 'hello, 音频'
}
isActive() {
return false
}
isDisabled() {
return true
}
exec() {
return
getValue(editor) {
return <AIQuestionModal key={Date.now()} editor={editor} action="2"></AIQuestionModal>
}
}
......
// Extend menu
class AIQuestionSingle {
import BaseModalMenu from './common/BaseModalMenu'
import AIQuestionModal from './common/AIQuestionModal'
class AIQuestionSingle extends BaseModalMenu {
constructor() {
super()
this.title = '单选题'
this.iconSvg = `<svg t="1729144945895" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="860" width="200" height="200"><path d="M358.4 256h460.8a51.2 51.2 0 0 1 0 102.4H358.4a51.2 51.2 0 1 1 0-102.4zM204.8 358.4a51.2 51.2 0 1 1 0-102.4 51.2 51.2 0 0 1 0 102.4z m153.6 102.4h460.8a51.2 51.2 0 0 1 0 102.4H358.4a51.2 51.2 0 0 1 0-102.4z m0 204.8h460.8a51.2 51.2 0 0 1 0 102.4H358.4a51.2 51.2 0 0 1 0-102.4z" fill="#4C4C4C" p-id="861"></path><path d="M204.8 51.2a153.6 153.6 0 0 0-153.6 153.6v614.4a153.6 153.6 0 0 0 153.6 153.6h614.4a153.6 153.6 0 0 0 153.6-153.6V204.8a153.6 153.6 0 0 0-153.6-153.6H204.8z m0-51.2h614.4a204.8 204.8 0 0 1 204.8 204.8v614.4a204.8 204.8 0 0 1-204.8 204.8H204.8a204.8 204.8 0 0 1-204.8-204.8V204.8a204.8 204.8 0 0 1 204.8-204.8z" fill="#4C4C4C" p-id="862"></path></svg>`
this.tag = 'button'
}
getValue() {
return 'hello, 音频'
}
isActive() {
return false
}
isDisabled() {
return true
}
exec() {
return
getValue(editor) {
return <AIQuestionModal key={Date.now()} editor={editor} action="1"></AIQuestionModal>
}
}
......
......@@ -19,7 +19,7 @@ class AIRewrite extends BaseModalMenu {
this.tag = 'button'
}
getValue(editor) {
return <AIModal key={Date.now()} editor={editor} docAction="rewrite"></AIModal>
return <AIModal key={Date.now()} editor={editor} action="rewrite"></AIModal>
}
}
......
......@@ -19,7 +19,7 @@ class AISummary extends BaseModalMenu {
</svg>`
}
getValue(editor) {
return <AIModal key={Date.now()} editor={editor} docAction="summary"></AIModal>
return <AIModal key={Date.now()} editor={editor} action="summary"></AIModal>
}
}
......
......@@ -9,7 +9,7 @@ class AITranslate extends BaseModalMenu {
this.iconSvg = `<svg fill="#000000" viewBox="0 0 32 32" id="icon" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><defs><style>.cls-1{fill:none;}</style></defs><title>translate</title><path d="M27.85,29H30L24,14H21.65l-6,15H17.8l1.6-4h6.85ZM20.2,23l2.62-6.56L25.45,23Z"></path><path d="M18,7V5H11V2H9V5H2V7H12.74a14.71,14.71,0,0,1-3.19,6.18A13.5,13.5,0,0,1,7.26,9H5.16a16.47,16.47,0,0,0,3,5.58A16.84,16.84,0,0,1,3,18l.75,1.86A18.47,18.47,0,0,0,9.53,16a16.92,16.92,0,0,0,5.76,3.84L16,18a14.48,14.48,0,0,1-5.12-3.37A17.64,17.64,0,0,0,14.8,7Z"></path><rect id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>" class="cls-1" width="32" height="32"></rect></g></svg>`
}
getValue(editor) {
return <AIModal key={Date.now()} editor={editor} docAction="translate"></AIModal>
return <AIModal key={Date.now()} editor={editor} action="translate"></AIModal>
}
}
......
......@@ -38,34 +38,34 @@ const actionMap = {
}
}
export default function AIModal({ editor, docAction }) {
export default function AIModal({ editor, action }) {
const [isModalOpen, setIsModalOpen] = useState(true)
const [content, setContent] = useState('')
const { text, fetch, isLoading } = useAIEdit()
const actionText = actionMap[docAction]?.name
const actionText = actionMap[action]?.name
const [selectionText, setSelectionText] = useState('')
useEffect(() => {
const selection = editor.getSelectionText()
if (selection) {
setSelectionText(selection)
setContent(selection)
fetch({ messages: [{ role: 'user', content: actionMap[docAction].prompt + selection }] })
fetch({ messages: [{ role: 'user', content: actionMap[action].prompt + selection }] })
}
}, [docAction, editor, fetch])
}, [action, editor, fetch])
useEffect(() => {
setContent(text)
}, [text])
const handleFetch = () => {
fetch({ messages: [{ role: 'user', content: actionMap[docAction].prompt + selectionText }] })
fetch({ messages: [{ role: 'user', content: actionMap[action].prompt + selectionText }] })
}
const handlePrimary = () => {
let result = content.trim()
// 标点校对结果判断
if (docAction === 'punctuation') {
if (action === 'punctuation') {
if (result.includes('该内容标点符号正常')) {
setIsModalOpen(false)
return
......@@ -76,7 +76,7 @@ export default function AIModal({ editor, docAction }) {
}
}
// 内容检查结果判断
if (docAction === 'contentInspect') {
if (action === 'contentInspect') {
if (result.includes('该内容正常,无敏感词和错别字')) {
setIsModalOpen(false)
return
......@@ -87,7 +87,7 @@ export default function AIModal({ editor, docAction }) {
}
}
// 翻译结果判断
if (docAction === 'translate') {
if (action === 'translate') {
const match = result.match(/翻译结果[::]?\s?([\s\S]*)/)
if (match) {
result = match[1].trim()
......@@ -111,11 +111,6 @@ export default function AIModal({ editor, docAction }) {
title={`以下是AI${actionText}结果:`}
open={isModalOpen}
footer={null}
classNames={{
header: 'editor-header-customer',
body: 'editor-body-customer',
wrapper: 'editor-wrapper-customer'
}}
onOk={handlePrimary}
onCancel={() => setIsModalOpen(false)}>
<Spin spinning={isLoading}>
......@@ -123,14 +118,12 @@ export default function AIModal({ editor, docAction }) {
</Spin>
<br />
<Flex gap="small" justify="center">
<Button type="primary" onClick={handlePrimary}>
替换内容
</Button>
<Button onClick={() => setIsModalOpen(false)}>取消</Button>
<Button type="primary" onClick={handleFetch}>
重新{actionText}
</Button>
<Button type="primary" onClick={() => setIsModalOpen(false)}>
取消
<Button type="primary" onClick={handlePrimary}>
替换内容
</Button>
</Flex>
</Modal>
......
import { useEffect, useState } from 'react'
import { Modal, Input, Button, Flex, Spin, Form, App } from 'antd'
import { useAIEdit } from '@/hooks/useBaiduAI'
import { addType, addQuestion } from '@/api/ai'
import store from '@/store/index'
const { TextArea } = Input
const actionMap = {
1: {
name: '单选题',
prompt: `请根据以下内容,理解之后,出一道单选题,要求如下:
1、包含四个选项。
2、给出正确答案。
输出的内容包含:
1、题目类型:
2、分类:
3、题干:
4、题目解析:
5、题目选项_1:
6、题目选项答案_1:正确为“是”,错误为“否”
7、题目选项_2:
8、题目选项答案_2:正确为“是”,错误为“否”
9、题目选项_3:
10、题目选项答案_3:正确为“是”,错误为“否”
11、题目选项_4:
12、题目选项答案_1:正确为“是”,错误为“否”
待理解内容:`
},
2: {
name: '多选题',
prompt: `请根据以下内容,理解之后,出一道多选题,要求如下:
1、包含四个选项。
2、给出正确答案。
输出的内容包含:
1、题目类型:
2、分类:
3、题干:
4、题目解析:
5、题目选项_1:
6、题目选项答案_1:正确为“是”,错误为“否”
7、题目选项_2:
8、题目选项答案_2:正确为“是”,错误为“否”
9、题目选项_3:
10、题目选项答案_3:正确为“是”,错误为“否”
11、题目选项_4:
12、题目选项答案_1:正确为“是”,错误为“否”
待理解内容:`
},
3: {
name: '判断题',
prompt: `请根据以下内容,理解之后,出一道判断题,要求如下:
1、包含四个选项。
2、给出正确答案。
输出的内容包含:
1、题目类型:
2、分类:
3、题干:
4、题目解析:
5、题目选项_1:
6、题目选项答案_1:正确为“是”,错误为“否”
7、题目选项_2:
8、题目选项答案_2:正确为“是”,错误为“否”
待理解内容:`
}
}
export default function AIQuestionModal({ editor, action }) {
const { message } = App.useApp()
const [isModalOpen, setIsModalOpen] = useState(true)
const [content, setContent] = useState('')
const { text, fetch, isLoading } = useAIEdit()
const actionText = actionMap[action]?.name
const [selectionText, setSelectionText] = useState('')
useEffect(() => {
const selection = editor.getSelectionText()
if (selection) {
setSelectionText(selection)
setContent(selection)
fetch({ messages: [{ role: 'user', content: actionMap[action].prompt + selection }] })
}
}, [action, editor, fetch])
useEffect(() => {
if (text) setQuestion(generateQuestionData(text))
}, [text])
const handleFetch = () => {
fetch({ messages: [{ role: 'user', content: actionMap[action].prompt + selectionText }] })
}
const [question, setQuestion] = useState({
question_style: action,
titles: '',
analysis: '',
question_list: []
})
// 获取A-Z的字母
function getAlphabet(i) {
return String.fromCharCode(65 + i)
}
// 生成试题数据
function generateQuestionData(str) {
// 初始化返回对象
const result = {
titles: '',
analysis: '',
answers: '',
question_list: []
}
// 使用正则表达式提取各个部分
const titleMatch = str.match(/题干:(.+?)\s/)
const analysisMatch = str.match(/题目解析:(.+?)\s/)
// 设置基本信息
if (titleMatch) result.titles = titleMatch[1]
if (analysisMatch) result.analysis = analysisMatch[1]
// 提取选项和答案
const options = []
let currentIndex = 1
// eslint-disable-next-line no-constant-condition
while (true) {
const optionMatch = str.match(new RegExp(`题目选项_${currentIndex}:(.+?)\\s`))
const answerMatch = str.match(new RegExp(`题目选项答案_${currentIndex}:(是|否)`))
console.log(optionMatch, answerMatch, currentIndex)
if (!optionMatch || !answerMatch) break
const option = { option: optionMatch[1], correct: answerMatch[1] === '是', abc: getAlphabet(currentIndex - 1) }
if (option.correct) result.answers += option.abc
options.push(option)
currentIndex++
}
result.question_list = options
return result
}
const { user } = store.getState()
// 提交
const handlePrimary = async () => {
const { data } = await addType({ name: `${user.treeChapter.book_name}/${user.treeChapter.chapter_name}` })
const res = await addQuestion({
...question,
book_id: user.treeChapter.book_id,
type_id: data.type_id,
question_style: action,
question_list: JSON.stringify(question.question_list)
})
message.success(res.message)
setIsModalOpen(false)
}
return (
<Modal
title="AI创建试题"
open={isModalOpen}
footer={null}
width={800}
onOk={handlePrimary}
onCancel={() => setIsModalOpen(false)}>
<Spin spinning={isLoading}>
<Form labelCol={{ span: 2 }}>
<Form.Item label="题目类型">{actionText}</Form.Item>
<Form.Item label="参考内容">
<TextArea autoSize={{ minRows: 4 }} value={content} onChange={e => setContent(e.target.value)} />
</Form.Item>
<Form.Item label="题干">
<div style={{ lineHeight: '32px' }}>
{question.titles}
{question.question_list.map(item => {
return (
<div key={item.abc}>
{item.abc}.{item.option}
</div>
)
})}
</div>
</Form.Item>
<Form.Item label="正确答案">{question.answers}</Form.Item>
<Form.Item label="题目解析">
<div style={{ lineHeight: '32px' }}>{question.analysis}</div>
</Form.Item>
</Form>
</Spin>
<br />
<Flex gap="small" justify="center">
<Button onClick={() => setIsModalOpen(false)}>取消</Button>
<Button type="primary" onClick={handleFetch}>
重新出题
</Button>
<Button type="primary" onClick={handlePrimary}>
确定
</Button>
</Flex>
</Modal>
)
}
......@@ -498,7 +498,7 @@ const CustomerTopic = (props, ref) => {
)}
<Form.Item wrapperCol={{ offset: 5, span: 16 }}>
<Space size={20}>
<Button className="submit" disabled={showAddClass} loading={loading} htmlType="submit">
<Button type="primary" disabled={showAddClass} loading={loading} htmlType="submit">
提交
</Button>
</Space>
......
import React,{useEffect, useState} from "react";
import { Table,Row,DatePicker,Form,Modal ,Switch} from "antd";
const {RangePicker}=DatePicker
import React, { useEffect, useState } from 'react'
import { Table, Row, DatePicker, Form, Modal, Switch } from 'antd'
const { RangePicker } = DatePicker
import PaginationCom from '@/common/Pagination'
import {getPositionList,changeStatus} from './request'
import TableCom from "@/common/TableCom/index";
import { useSelector } from 'react-redux';
const Adsense=()=>{
const [data,setData]=useState([])
const [page_size,setpage_size]=useState(10)
const [page,setPage]=useState(1)
const [total,setTotal]=useState(0)
const [loading,setLoading]=useState(true)
const [isEdit,setIsEdit]=useState(false)
const [delMoadal,setDelModal]=useState(false)
const [form]=Form.useForm()
const [swichDisabled, setSwichDisabled] = useState(false);
import { getPositionList, changeStatus } from './request'
import TableCom from '@/common/TableCom/index'
import { useSelector } from 'react-redux'
const Adsense = () => {
const [data, setData] = useState([])
const [page_size, setpage_size] = useState(10)
const [page, setPage] = useState(1)
const [total, setTotal] = useState(0)
const [loading, setLoading] = useState(true)
const [isEdit, setIsEdit] = useState(false)
const [delMoadal, setDelModal] = useState(false)
const [form] = Form.useForm()
const [swichDisabled, setSwichDisabled] = useState(false)
// 获取操作权限
const { operationPermissionsList } = useSelector((state) => state.user);
const handleStatus=async (status,id)=>{
const bool=await changeStatus({id,status:status?'1':'0'})
bool&&init()
const { operationPermissionsList } = useSelector(state => state.user)
const handleStatus = async (status, id) => {
const bool = await changeStatus({ id, status: status ? '1' : '0' })
bool && init()
}
const onClose=()=>{
const onClose = () => {
setIsEdit(false)
}
const submitForm=(obj)=>{
console.log(obj);
const submitForm = obj => {
console.log(obj)
}
const delSuccess=()=>{
const delSuccess = () => {
setDelModal(false)
}
const init=async(obj={})=>{
const init = async (obj = {}) => {
setLoading(true)
const {total,list}=await getPositionList({page,page_size,...obj})
const { total, list } = await getPositionList({ page, page_size, ...obj })
setTotal(total)
setData(list);
setData(list)
setLoading(false)
}
useEffect(() => {
setSwichDisabled(!operationPermissionsList.includes('/advertisement/adsense/changeStatus'))
});
})
const columns=[
const columns = [
{
title:'广告位位置',
key:'position_name',
dataIndex:'position_name'
title: '广告位位置',
key: 'position_name',
dataIndex: 'position_name'
},
{
title:'广告位大小',
key:'pic_size',
dataIndex:'pic_size'
title: '广告位大小',
key: 'pic_size',
dataIndex: 'pic_size'
},
{
title:'状态',
key:'status',
dataIndex:'status',
render(_,{status,id}){
return (
<Switch defaultChecked={status} onChange={(ev)=>handleStatus(ev,id)} disabled={swichDisabled}/>
)
title: '状态',
key: 'status',
dataIndex: 'status',
render(_, { status, id }) {
return <Switch defaultChecked={status} onChange={ev => handleStatus(ev, id)} disabled={swichDisabled} />
}
}
},
]
return (
<div className="classify">
{TableCom({columns,data,loading})}
<Modal mask={false} centered open={delMoadal} onOk={delSuccess} onCancel={()=>setDelModal(false)} footer={(_,{ OkBtn, CancelBtn })=>{
{TableCom({ columns, data, loading })}
<Modal
mask={false}
centered
open={delMoadal}
onOk={delSuccess}
onCancel={() => setDelModal(false)}
footer={(_, { OkBtn, CancelBtn }) => {
return (
<Row justify={'center'} className="delModal">
<Space>
<CancelBtn className="cancel" />
<OkBtn className="true" />
<CancelBtn />
<OkBtn />
</Space>
</Row>
)
}} okText="确认">
<p style={{textAlign:'center',padding: "50px 0 30px",fontSize:16}}>分类将永久删除,是否继续?</p>
}}
okText="确认">
<p style={{ textAlign: 'center', padding: '50px 0 30px', fontSize: 16 }}>分类将永久删除,是否继续?</p>
</Modal>
<br />
<PaginationCom total={total}
<PaginationCom
total={total}
page_size={page_size}
setpage_size={setpage_size}
page={page}
......@@ -92,4 +97,4 @@ const Adsense=()=>{
)
}
export default Adsense;
\ No newline at end of file
export default Adsense
......@@ -91,7 +91,9 @@ const Audit = () => {
const parser = new DOMParser()
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']")
.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() })
......@@ -272,7 +274,9 @@ const Audit = () => {
</Button>
)}
{isAdminOrCreator && operationPermissionsList.includes('/books/management/release') && audit_status === 1 && (
{isAdminOrCreator &&
operationPermissionsList.includes('/books/management/release') &&
audit_status === 1 && (
<Button
onClick={() => {
setId(id)
......@@ -324,7 +328,10 @@ const Audit = () => {
</Select>
</Form.Item>
<Form.Item label="创建时间">
<RangePicker value={dateVal} onChange={ev => handleFilter('startandend', ev)} id="createTime"></RangePicker>
<RangePicker
value={dateVal}
onChange={ev => handleFilter('startandend', ev)}
id="createTime"></RangePicker>
</Form.Item>
<Space>
<Button
......@@ -441,8 +448,8 @@ const Audit = () => {
return (
<Row justify={'center'} className="delModal" style={{ marginBottom: '30px' }}>
<Space size={20}>
<CancelBtn className="cancel" />
<OkBtn className="true" />
<CancelBtn />
<OkBtn />
</Space>
</Row>
)
......@@ -461,16 +468,25 @@ const Audit = () => {
return (
<Row justify={'center'} className="delModal" style={{ marginBottom: '30px' }}>
<Space size={20}>
<CancelBtn className="cancel" />
<OkBtn className="true" />
<CancelBtn />
<OkBtn />
</Space>
</Row>
)
}}
okText="确认">
<p style={{ textAlign: 'center', padding: '30px 0 18px', fontSize: 16 }}>只能导出文本部分,画廊、音频、视频不支持</p>
<p style={{ textAlign: 'center', padding: '30px 0 18px', fontSize: 16 }}>
只能导出文本部分,画廊、音频、视频不支持
</p>
</Modal>
<Drawer mask={false} centered open={importModal} onCancel={() => setImportModal(false)} onClose={() => setImportModal(false)} footer={null} okText="确认">
<Drawer
mask={false}
centered
open={importModal}
onCancel={() => setImportModal(false)}
onClose={() => setImportModal(false)}
footer={null}
okText="确认">
<Spin spinning={uploading}>
<Form labelCol={{ span: 8 }} onFinish={importSuccess}>
<Form.Item label="下载模板" style={{ marginBottom: 10 }}>
......@@ -498,7 +514,10 @@ const Audit = () => {
<p style={{ color: '#999999' }}>{bookFile?.name}</p>
</Form.Item>
<Form.Item label="目录结构等级" name="catalog_level" rules={[{ required: true, message: '请选择目录结构等级' }]}>
<Form.Item
label="目录结构等级"
name="catalog_level"
rules={[{ required: true, message: '请选择目录结构等级' }]}>
<Select placeholder="请选择目录结构的等级" style={{ width: 260 }}>
<Select.Option value={1}>标题1</Select.Option>
<Select.Option value={2}>标题2</Select.Option>
......@@ -534,13 +553,12 @@ const Audit = () => {
<Form.Item wrapperCol={{ offset: 10, span: 16 }}>
<Space size={20}>
<Button
className="cancel"
onClick={() => {
setShowAudit(false)
}}>
取消
</Button>
<Button className="submit" htmlType="submit">
<Button type="primary" htmlType="submit">
发布
</Button>
</Space>
......@@ -550,7 +568,15 @@ const Audit = () => {
<br />
{TableCom({ columns, loading, data })}
<br />
<PaginationCom total={total} page_size={page_size} setpage_size={setpage_size} page={page} setPage={setPage} init={init} filterObj={filterObj} />
<PaginationCom
total={total}
page_size={page_size}
setpage_size={setpage_size}
page={page}
setPage={setPage}
init={init}
filterObj={filterObj}
/>
</>
)
}
......
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react'
import { Form, Space, Input, Select, Button, Spin, Row, Col, Checkbox, Radio } from 'antd'
import { useState, useEffect, forwardRef, useImperativeHandle } from 'react'
import { Form, Space, Input, Select, Button, Row, Col, Checkbox } from 'antd'
import { MinusOutlined, PlusOutlined } from '@ant-design/icons'
import { useSelector } from 'react-redux'
import { Editor, Toolbar } from '@wangeditor/editor-for-react'
import { DomEditor } from '@wangeditor/editor'
import { questionAdd, typeList, questionAddType, questionEdit, bookNameList } from '@/pages/books/question-bank/request'
import { uploadFiles } from '@/utils/upload'
import { questionAdd, questionAddType, questionEdit } from '@/pages/books/question-bank/request'
import QuestionEditr from '@/pages/books/question-bank/questionEditr'
import './index.less'
import dayjs from 'dayjs'
......@@ -15,7 +13,7 @@ import AliOSS from 'ali-oss'
import { getAliOSSSTSToken } from '@/pages/setting/help/addedit/requet'
const CustomerTopic = (props, ref) => {
const { topicData, isadd, init, getTypeList, typeDate, setShowModal, bookNameData, bookIdList, typeId } = props
const { topicData, isadd, init, getTypeList, typeDate, setShowModal, bookIdList, typeId } = props
// oss
const [ossClient, setOssClient] = useState(null) // oss 操作
const [STSToken, setSTSToken] = useState(null) // oss 过期设置
......@@ -59,12 +57,10 @@ const CustomerTopic = (props, ref) => {
const [form] = Form.useForm()
const questionType = Form.useWatch('question_style', form)
// 获取操作权限
const { operationPermissionsList } = useSelector(state => state.user)
// 题干名称的编辑器实例
const [titlesEditor, setTitlesEditor] = useState(null)
const [quesList, setQuesList] = useState([])
const [initialValues, setinitialValues] = useState({
const [initialValues, setInitialValues] = useState({
titles: '',
type_id: null,
question_style: '',
......@@ -77,9 +73,6 @@ const CustomerTopic = (props, ref) => {
const [selectedTypeId, setSelectedTypeId] = useState([])
useEffect(() => {
// console.log('typeId', typeId); //书的typeid
// console.log('props.typeDate', props.typeDate); //所有的typeid和typename
const getTypeNameById = id => {
const selectedType = props.typeDate.find(item => item.id === id)
return selectedType ? selectedType.typename : ''
......@@ -122,10 +115,10 @@ const CustomerTopic = (props, ref) => {
setQuesList([])
}
}
setinitialValues({ ...obj })
setInitialValues({ ...obj })
form.setFieldsValue({ ...obj })
} else {
setinitialValues(obj)
setInitialValues(obj)
form.setFieldsValue({ ...obj })
}
}, [topicData, isadd])
......@@ -133,10 +126,8 @@ const CustomerTopic = (props, ref) => {
// 显示不同类型的选项函数
const [edierVal, setedierVal] = useState('')
// 是否显示选项
const [showList, setShowList] = useState(false)
const [formLoading, setFormLoading] = useState(false)
const [showAddClass, setShowAddClass] = useState(false)
const [addClassVal, setaddClassVal] = useState('') // 添加分类
const [addClassVal, setAddClassVal] = useState('') // 添加分类
const [questionStyle, setQuestionStyle] = useState('')
// 分类
......@@ -145,8 +136,8 @@ const CustomerTopic = (props, ref) => {
if (bool) {
await getTypeList()
form.setFieldsValue({ type_id: bool.type_id })
setinitialValues({ ...initialValues, type_id: [bool.type_id] })
setaddClassVal('')
setInitialValues({ ...initialValues, type_id: [bool.type_id] })
setAddClassVal('')
setShowAddClass(false)
}
}
......@@ -189,9 +180,6 @@ const CustomerTopic = (props, ref) => {
console.log('result', result)
insertFn(result.url, '题库图片')
// const { url } = await uploadFiles({ file, file_type: 'question' });
// insertFn(url, '题库图片');
}
}
},
......@@ -304,9 +292,6 @@ const CustomerTopic = (props, ref) => {
wrapperCol={{ span: 19 }}>
<Form.Item name="book_id" label="书籍名称" rules={[{ required: true, message: '请选择书籍名称' }]}>
<Select
onChange={ev => {
setShowList(true)
}}
style={{ width: 260 }}
placeholder="请选择书籍名称"
showSearch //下拉框出现搜素,并可以输入
......@@ -324,9 +309,6 @@ const CustomerTopic = (props, ref) => {
<Form.Item name="question_style" label="题目类型" rules={[{ required: true, message: '请选择题目类型' }]}>
<Select
onChange={ev => {
setShowList(true)
// setinitialValues({ ...initialValues, question_style: ev });
// form.setFieldValue('question_style', ev);
setQuestionStyle(ev)
}}
style={{ width: 260 }}
......@@ -373,7 +355,7 @@ const CustomerTopic = (props, ref) => {
<Input
style={{ width: 200 }}
value={addClassVal}
onChange={e => setaddClassVal(e.target.value)}
onChange={e => setAddClassVal(e.target.value)}
autoComplete="off"
placeholder="请输入题目分类"></Input>
<Space>
......@@ -398,7 +380,6 @@ const CustomerTopic = (props, ref) => {
{ validator: vaildaterHtml, validateTrigger: 'onChange' }
]}
extra={questionType === 4 ? '请在需要填空的位置使用2个或以上的下划线进行区分!' : ''}>
<Spin spinning={formLoading}>
<div style={{ border: '1px solid #ccc', zIndex: 100 }}>
<Toolbar
editor={titlesEditor}
......@@ -413,18 +394,15 @@ const CustomerTopic = (props, ref) => {
onCreated={setTitlesEditor}
onChange={editor => {
form.setFieldValue('titles', editor.getHtml())
// setHtml(editor.getHtml())
}}
config={{
uploadImgServer: 'your_upload_server_address'
// other config options
}}
mode="default"
style={{ height: '200px', overflowY: 'hidden' }}
/>
)}
</div>
</Spin>
</Form.Item>
<Form.Item name="analysis" label="题目解析">
<Input.TextArea
......@@ -485,7 +463,6 @@ const CustomerTopic = (props, ref) => {
initialValue={restField.correct || false}>
<Checkbox
onChange={e => {
// if (quesList.length && temp[index]) {
if (quesList.length) {
let temp = JSON.parse(JSON.stringify(quesList))
if (questionStyle === 1 || questionStyle === 3) {
......@@ -550,29 +527,6 @@ const CustomerTopic = (props, ref) => {
)}
</Form.List>
)}
{/* {questionStyle === 3 && (
<Form.Item name='question_list' label='正确答案'>
<Radio.Group
onChange={(e) => {
let val = e.target.value;
if (val === '正确') {
setQuesList([
{ option: '正确', correct: true },
{ option: '错误', correct: false },
]);
} else {
setQuesList([
{ option: '正确', correct: false },
{ option: '错误', correct: true },
]);
}
}}
>
<Radio value='正确'>√</Radio>
<Radio value='错误'>×</Radio>
</Radio.Group>
</Form.Item>
)} */}
{(questionStyle === 5 || questionStyle === 4) && (
<Form.Item name="answers" label="正确答案">
<QuestionEditr editorValue={edierVal} setedierVal={setedierVal} form={form} name="answers" />
......@@ -580,10 +534,8 @@ const CustomerTopic = (props, ref) => {
)}
<Form.Item wrapperCol={{ offset: 11, span: 16 }}>
<Space size={20}>
<Button className="cancel" onClick={() => setShowModal(false)}>
取消
</Button>
<Button className="submit" disabled={showAddClass} htmlType="submit">
<Button onClick={() => setShowModal(false)}>取消</Button>
<Button type="primary" disabled={showAddClass} htmlType="submit">
提交
</Button>
</Space>
......
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论