Merge pull request #15 from PlayEdu/dev

Dev
This commit is contained in:
Teng
2023-08-04 09:06:53 +08:00
committed by GitHub
29 changed files with 1844 additions and 1685 deletions

4
.gitignore vendored
View File

@@ -32,4 +32,6 @@ deploy-test.sh
deploy-prod.sh deploy-prod.sh
deploy-demo.sh deploy-demo.sh
dist/ dist/
pnpm-lock.yaml

View File

@@ -9,6 +9,7 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@ant-design/icons": "^5.2.3",
"@reduxjs/toolkit": "^1.9.3", "@reduxjs/toolkit": "^1.9.3",
"ahooks": "^3.7.6", "ahooks": "^3.7.6",
"antd": "^5.3.2", "antd": "^5.3.2",

View File

@@ -40,23 +40,25 @@ export const CreateResourceCategory = (props: PropInterface) => {
shape="circle" shape="circle"
icon={<PlusOutlined />} icon={<PlusOutlined />}
/> />
<Modal {showModal ? (
onCancel={() => { <Modal
setShowModal(false); onCancel={() => {
}} setShowModal(false);
onOk={confirm}
open={showModal}
title="创建分类"
>
<Input
placeholder="请输入分类名"
value={name}
onChange={(e) => {
setName(e.target.value);
}} }}
allowClear onOk={confirm}
/> open={true}
</Modal> title="创建分类"
>
<Input
placeholder="请输入分类名"
value={name}
onChange={(e) => {
setName(e.target.value);
}}
allowClear
/>
</Modal>
) : null}
</> </>
); );
}; };

View File

@@ -1,5 +1,5 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Row, Modal, Tabs } from "antd"; import { Row, Modal, Tabs, Spin } from "antd";
import styles from "./index.module.less"; import styles from "./index.module.less";
import { UploadCoursewareSub } from "../../compenents"; import { UploadCoursewareSub } from "../../compenents";
import type { TabsProps } from "antd"; import type { TabsProps } from "antd";
@@ -13,11 +13,13 @@ interface PropsInterface {
export const SelectAttachment = (props: PropsInterface) => { export const SelectAttachment = (props: PropsInterface) => {
const [refresh, setRefresh] = useState(true); const [refresh, setRefresh] = useState(true);
const [init, setInit] = useState(true);
const [tabKey, setTabKey] = useState(1); const [tabKey, setTabKey] = useState(1);
const [selectKeys, setSelectKeys] = useState<any>([]); const [selectKeys, setSelectKeys] = useState<any>([]);
const [selectVideos, setSelectVideos] = useState<any>([]); const [selectVideos, setSelectVideos] = useState<any>([]);
useEffect(() => { useEffect(() => {
setInit(true);
setRefresh(!refresh); setRefresh(!refresh);
}, [props.open]); }, [props.open]);
@@ -26,7 +28,10 @@ export const SelectAttachment = (props: PropsInterface) => {
key: "1", key: "1",
label: `课件`, label: `课件`,
children: ( children: (
<div className="float-left"> <div
className="float-left"
style={{ display: init ? "none" : "block" }}
>
<UploadCoursewareSub <UploadCoursewareSub
label="课件" label="课件"
defaultCheckedList={props.defaultKeys} defaultCheckedList={props.defaultKeys}
@@ -35,6 +40,9 @@ export const SelectAttachment = (props: PropsInterface) => {
setSelectKeys(arr); setSelectKeys(arr);
setSelectVideos(videos); setSelectVideos(videos);
}} }}
onSuccess={() => {
setInit(false);
}}
/> />
</div> </div>
), ),
@@ -47,28 +55,35 @@ export const SelectAttachment = (props: PropsInterface) => {
return ( return (
<> <>
<Modal {props.open ? (
title="资源素材库" <Modal
centered title="资源素材库"
closable={false} centered
onCancel={() => { closable={false}
setSelectKeys([]); onCancel={() => {
setSelectVideos([]); setSelectKeys([]);
props.onCancel(); setSelectVideos([]);
}} props.onCancel();
open={props.open} }}
width={800} open={true}
maskClosable={false} width={800}
onOk={() => { maskClosable={false}
props.onSelected(selectKeys, selectVideos); onOk={() => {
setSelectKeys([]); props.onSelected(selectKeys, selectVideos);
setSelectVideos([]); setSelectKeys([]);
}} setSelectVideos([]);
> }}
<Row> >
<Tabs defaultActiveKey="1" items={items} onChange={onChange} /> <Row>
</Row> <Tabs defaultActiveKey="1" items={items} onChange={onChange} />
</Modal> </Row>
{init && (
<div className="float-left text-center mt-30">
<Spin></Spin>
</div>
)}
</Modal>
) : null}
</> </>
); );
}; };

View File

@@ -1,5 +1,5 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Row, Modal, Tabs } from "antd"; import { Row, Modal, Tabs, Spin } from "antd";
import styles from "./index.module.less"; import styles from "./index.module.less";
import { UploadVideoSub } from "../../compenents"; import { UploadVideoSub } from "../../compenents";
import type { TabsProps } from "antd"; import type { TabsProps } from "antd";
@@ -13,11 +13,13 @@ interface PropsInterface {
export const SelectResource = (props: PropsInterface) => { export const SelectResource = (props: PropsInterface) => {
const [refresh, setRefresh] = useState(true); const [refresh, setRefresh] = useState(true);
const [init, setInit] = useState(true);
const [tabKey, setTabKey] = useState(1); const [tabKey, setTabKey] = useState(1);
const [selectKeys, setSelectKeys] = useState<any>([]); const [selectKeys, setSelectKeys] = useState<any>([]);
const [selectVideos, setSelectVideos] = useState<any>([]); const [selectVideos, setSelectVideos] = useState<any>([]);
useEffect(() => { useEffect(() => {
setInit(true);
setRefresh(!refresh); setRefresh(!refresh);
}, [props.open]); }, [props.open]);
@@ -26,7 +28,10 @@ export const SelectResource = (props: PropsInterface) => {
key: "1", key: "1",
label: `视频`, label: `视频`,
children: ( children: (
<div className="float-left"> <div
className="float-left"
style={{ display: init ? "none" : "block" }}
>
<UploadVideoSub <UploadVideoSub
label="视频" label="视频"
defaultCheckedList={props.defaultKeys} defaultCheckedList={props.defaultKeys}
@@ -35,6 +40,9 @@ export const SelectResource = (props: PropsInterface) => {
setSelectKeys(arr); setSelectKeys(arr);
setSelectVideos(videos); setSelectVideos(videos);
}} }}
onSuccess={() => {
setInit(false);
}}
/> />
</div> </div>
), ),
@@ -47,28 +55,35 @@ export const SelectResource = (props: PropsInterface) => {
return ( return (
<> <>
<Modal {props.open ? (
title="资源素材库" <Modal
centered title="资源素材库"
closable={false} centered
onCancel={() => { closable={false}
setSelectKeys([]); onCancel={() => {
setSelectVideos([]); setSelectKeys([]);
props.onCancel(); setSelectVideos([]);
}} props.onCancel();
open={props.open} }}
width={800} open={true}
maskClosable={false} width={800}
onOk={() => { maskClosable={false}
props.onSelected(selectKeys, selectVideos); onOk={() => {
setSelectKeys([]); props.onSelected(selectKeys, selectVideos);
setSelectVideos([]); setSelectKeys([]);
}} setSelectVideos([]);
> }}
<Row> >
<Tabs defaultActiveKey="1" items={items} onChange={onChange} /> <Row>
</Row> <Tabs defaultActiveKey="1" items={items} onChange={onChange} />
</Modal> </Row>
{init && (
<div className="float-left text-center mt-30">
<Spin></Spin>
</div>
)}
</Modal>
) : null}
</> </>
); );
}; };

View File

@@ -12,7 +12,7 @@ import {
} from "antd"; } from "antd";
import Dragger from "antd/es/upload/Dragger"; import Dragger from "antd/es/upload/Dragger";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { generateUUID, parseVideo } from "../../utils"; import { generateUUID } from "../../utils";
import { minioMergeVideo, minioUploadId } from "../../api/upload"; import { minioMergeVideo, minioUploadId } from "../../api/upload";
import { UploadChunk } from "../../js/minio-upload-chunk"; import { UploadChunk } from "../../js/minio-upload-chunk";
@@ -58,9 +58,14 @@ export const UploadCoursewareButton = (props: PropsInterface) => {
const uploadProps = { const uploadProps = {
multiple: true, multiple: true,
beforeUpload: async (file: File) => { beforeUpload: async (file: File) => {
if (file.size === 0) {
message.error(`文件 ${file.name} 为空文件`);
return Upload.LIST_IGNORE;
}
let extension: any = file.name.split("."); let extension: any = file.name.split(".");
extension = extension[extension.length - 1]; extension = extension[extension.length - 1];
if ( if (
extension === "rar" ||
file.type === file.type ===
"application/vnd.openxmlformats-officedocument.wordprocessingml.document" || "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ||
file.type === "application/msword" || file.type === "application/msword" ||

View File

@@ -34,6 +34,7 @@ interface PropsInterface {
label: string; label: string;
open: boolean; open: boolean;
onSelected: (arr: any[], videos: []) => void; onSelected: (arr: any[], videos: []) => void;
onSuccess: () => void;
} }
export const UploadCoursewareSub = (props: PropsInterface) => { export const UploadCoursewareSub = (props: PropsInterface) => {
@@ -75,6 +76,7 @@ export const UploadCoursewareSub = (props: PropsInterface) => {
setTotal(res.data.result.total); setTotal(res.data.result.total);
setExistingTypes(res.data.existing_types); setExistingTypes(res.data.existing_types);
setVideoList(res.data.result.data); setVideoList(res.data.result.data);
props.onSuccess();
}) })
.catch((err) => { .catch((err) => {
console.log("错误,", err); console.log("错误,", err);

View File

@@ -1,8 +1 @@
.video-list {
width: calc(100% - 100px);
height: auto;
display: flex;
flex-direction: column;
margin-left: 10px;
min-height: 380px;
}

View File

@@ -35,6 +35,7 @@ interface PropsInterface {
label: string; label: string;
open: boolean; open: boolean;
onSelected: (arr: any[], videos: []) => void; onSelected: (arr: any[], videos: []) => void;
onSuccess: () => void;
} }
export const UploadVideoSub = (props: PropsInterface) => { export const UploadVideoSub = (props: PropsInterface) => {
@@ -68,6 +69,7 @@ export const UploadVideoSub = (props: PropsInterface) => {
setTotal(res.data.result.total); setTotal(res.data.result.total);
setVideoExtra(res.data.videos_extra); setVideoExtra(res.data.videos_extra);
setVideoList(res.data.result.data); setVideoList(res.data.result.data);
props.onSuccess();
}) })
.catch((err) => { .catch((err) => {
console.log("错误,", err); console.log("错误,", err);

View File

@@ -189,6 +189,10 @@ code {
flex: 1; flex: 1;
} }
.text-center {
text-align: center;
}
.c-admin { .c-admin {
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;

View File

@@ -28,6 +28,9 @@ export const CourseAttachmentUpdate: React.FC<PropInterface> = ({
if (id === 0) { if (id === 0) {
return; return;
} }
setAttachmentVisible(false);
setAttachmentData([]);
setAttachments([]);
getDetail(); getDetail();
}, [id, open]); }, [id, open]);
@@ -81,16 +84,11 @@ export const CourseAttachmentUpdate: React.FC<PropInterface> = ({
return; return;
} }
courseAttachment courseAttachment.storeCourseAttachmentMulti(id, hours).then((res: any) => {
.storeCourseAttachmentMulti(id, hours) console.log("ok");
.then((res: any) => { setAttachmentVisible(false);
console.log("ok"); getDetail();
setAttachmentVisible(false); });
getDetail();
})
.catch((err) => {
message.error(err.message);
});
}; };
const delAttachments = (hid: number) => { const delAttachments = (hid: number) => {
@@ -149,70 +147,72 @@ export const CourseAttachmentUpdate: React.FC<PropInterface> = ({
return ( return (
<> <>
<Drawer {open ? (
title="课件管理" <Drawer
onClose={onCancel} title="课件管理"
maskClosable={false} onClose={onCancel}
open={open} maskClosable={false}
width={634} open={true}
> width={634}
<div className={styles["top-content"]}> >
<p>1.线</p> <div className={styles["top-content"]}>
</div> <p>1.线</p>
<div className="float-left mt-24"> </div>
<SelectAttachment <div className="float-left mt-24">
defaultKeys={attachments} <SelectAttachment
open={attachmentVisible} defaultKeys={attachments}
onCancel={() => { open={attachmentVisible}
setAttachmentVisible(false); onCancel={() => {
}} setAttachmentVisible(false);
onSelected={(arr: any, videos: any) => { }}
selectAttachmentData(arr, videos); onSelected={(arr: any, videos: any) => {
}} selectAttachmentData(arr, videos);
></SelectAttachment> }}
<Form ></SelectAttachment>
form={form} <Form
name="attachment-update-basic" form={form}
labelCol={{ span: 5 }} name="attachment-update-basic"
wrapperCol={{ span: 19 }} labelCol={{ span: 5 }}
initialValues={{ remember: true }} wrapperCol={{ span: 19 }}
onFinish={onFinish} initialValues={{ remember: true }}
onFinishFailed={onFinishFailed} onFinish={onFinish}
autoComplete="off" onFinishFailed={onFinishFailed}
> autoComplete="off"
<div className="c-flex"> >
<Form.Item> <div className="c-flex">
<div className="ml-42"> <Form.Item>
<Button <div className="ml-42">
onClick={() => setAttachmentVisible(true)} <Button
type="primary" onClick={() => setAttachmentVisible(true)}
> type="primary"
>
</Button>
</Button>
</div>
</Form.Item>
<div className={styles["hous-box"]}>
{attachmentData.length === 0 && (
<span className={styles["no-hours"]}>
</span>
)}
{attachmentData.length > 0 && (
<TreeAttachments
data={attachmentData}
onRemoveItem={(id: number) => {
delAttachments(id);
}}
onUpdate={(arr: any[]) => {
transAttachments(arr);
}}
/>
)}
</div> </div>
</Form.Item>
<div className={styles["hous-box"]}>
{attachmentData.length === 0 && (
<span className={styles["no-hours"]}>
</span>
)}
{attachmentData.length > 0 && (
<TreeAttachments
data={attachmentData}
onRemoveItem={(id: number) => {
delAttachments(id);
}}
onUpdate={(arr: any[]) => {
transAttachments(arr);
}}
/>
)}
</div> </div>
</div> </Form>
</Form> </div>
</div> </Drawer>
</Drawer> ) : null}
</> </>
); );
}; };

View File

@@ -464,386 +464,388 @@ export const CourseCreate: React.FC<PropInterface> = ({
return ( return (
<> <>
<Drawer {open ? (
title="新建课程" <Drawer
onClose={onCancel} title="新建课程"
maskClosable={false} onClose={onCancel}
open={open} maskClosable={false}
footer={ open={true}
<Space className="j-r-flex"> footer={
<Button onClick={() => onCancel()}> </Button> <Space className="j-r-flex">
<Button onClick={() => form.submit()} type="primary"> <Button onClick={() => onCancel()}> </Button>
<Button onClick={() => form.submit()} type="primary">
</Button>
</Space> </Button>
} </Space>
width={634} }
> width={634}
<div className="float-left mt-24"> >
<SelectResource <div className="float-left mt-24">
defaultKeys={ <SelectResource
chapterType == 0 ? hours : changeChapterHours(chapterHours) defaultKeys={
} chapterType == 0 ? hours : changeChapterHours(chapterHours)
open={videoVisible}
onCancel={() => {
setVideoVisible(false);
}}
onSelected={(arr: any, videos: any) => {
if (chapterType === 0) {
selectData(arr, videos);
} else {
selectChapterData(arr, videos);
} }
}} open={videoVisible}
/> onCancel={() => {
<SelectAttachment setVideoVisible(false);
defaultKeys={attachments} }}
open={attachmentVisible} onSelected={(arr: any, videos: any) => {
onCancel={() => { if (chapterType === 0) {
setAttachmentVisible(false); selectData(arr, videos);
}} } else {
onSelected={(arr: any, videos: any) => { selectChapterData(arr, videos);
selectAttachmentData(arr, videos); }
}} }}
></SelectAttachment> />
<Form <SelectAttachment
form={form} defaultKeys={attachments}
name="create-basic" open={attachmentVisible}
labelCol={{ span: 5 }} onCancel={() => {
wrapperCol={{ span: 19 }} setAttachmentVisible(false);
initialValues={{ remember: true }} }}
onFinish={onFinish} onSelected={(arr: any, videos: any) => {
onFinishFailed={onFinishFailed} selectAttachmentData(arr, videos);
autoComplete="off" }}
> ></SelectAttachment>
<Form.Item <Form
label="课程分类" form={form}
name="category_ids" name="create-basic"
rules={[{ required: true, message: "请选择课程分类!" }]} labelCol={{ span: 5 }}
wrapperCol={{ span: 19 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
> >
<TreeSelect
showCheckedStrategy={TreeSelect.SHOW_ALL}
allowClear
multiple
style={{ width: 424 }}
treeData={categories}
placeholder="请选择课程分类"
treeDefaultExpandAll
/>
</Form.Item>
<Form.Item
label="课程名称"
name="title"
rules={[{ required: true, message: "请在此处输入课程名称!" }]}
>
<Input
style={{ width: 424 }}
placeholder="请在此处输入课程名称"
allowClear
/>
</Form.Item>
<Form.Item
label="课程属性"
name="isRequired"
rules={[{ required: true, message: "请选择课程属性!" }]}
>
<Radio.Group>
<Radio value={1}></Radio>
<Radio value={0} style={{ marginLeft: 22 }}>
</Radio>
</Radio.Group>
</Form.Item>
<Form.Item
label="指派部门"
name="type"
rules={[{ required: true, message: "请选择指派部门!" }]}
>
<Radio.Group onChange={getType}>
<Radio value="open"></Radio>
<Radio value="elective"></Radio>
</Radio.Group>
</Form.Item>
{type === "elective" && (
<Form.Item <Form.Item
label="选择部门" label="课程分类"
name="dep_ids" name="category_ids"
rules={[ rules={[{ required: true, message: "请选择课程分类!" }]}
{
required: true,
message: "请选择部门!",
},
]}
> >
<TreeSelect <TreeSelect
showCheckedStrategy={TreeSelect.SHOW_ALL} showCheckedStrategy={TreeSelect.SHOW_ALL}
style={{ width: 424 }}
treeData={departments}
multiple
allowClear allowClear
multiple
style={{ width: 424 }}
treeData={categories}
placeholder="请选择课程分类"
treeDefaultExpandAll treeDefaultExpandAll
placeholder="请选择部门"
/> />
</Form.Item> </Form.Item>
)} <Form.Item
label="课程名称"
<Form.Item name="title"
label="课程封面" rules={[{ required: true, message: "请在此处输入课程名称!" }]}
name="thumb" >
rules={[{ required: true, message: "请上传课程封面!" }]} <Input
> style={{ width: 424 }}
<div className="d-flex"> placeholder="请在此处输入课程名称"
<Image allowClear
src={thumb}
width={160}
height={120}
style={{ borderRadius: 6 }}
preview={false}
/> />
<div className="c-flex ml-8 flex-1"> </Form.Item>
<div className="d-flex mb-28"> <Form.Item
<div label="课程属性"
className={ name="isRequired"
thumb === defaultThumb1 rules={[{ required: true, message: "请选择课程属性!" }]}
? styles["thumb-item-avtive"] >
: styles["thumb-item"] <Radio.Group>
} <Radio value={1}></Radio>
onClick={() => { <Radio value={0} style={{ marginLeft: 22 }}>
setThumb(defaultThumb1);
form.setFieldsValue({ </Radio>
thumb: defaultThumb1, </Radio.Group>
}); </Form.Item>
}} <Form.Item
> label="指派部门"
<Image name="type"
src={defaultThumb1} rules={[{ required: true, message: "请选择指派部门!" }]}
width={80} >
height={60} <Radio.Group onChange={getType}>
style={{ borderRadius: 6 }} <Radio value="open"></Radio>
preview={false} <Radio value="elective"></Radio>
/> </Radio.Group>
</Form.Item>
{type === "elective" && (
<Form.Item
label="选择部门"
name="dep_ids"
rules={[
{
required: true,
message: "请选择部门!",
},
]}
>
<TreeSelect
showCheckedStrategy={TreeSelect.SHOW_ALL}
style={{ width: 424 }}
treeData={departments}
multiple
allowClear
treeDefaultExpandAll
placeholder="请选择部门"
/>
</Form.Item>
)}
<Form.Item
label="课程封面"
name="thumb"
rules={[{ required: true, message: "请上传课程封面!" }]}
>
<div className="d-flex">
<Image
src={thumb}
width={160}
height={120}
style={{ borderRadius: 6 }}
preview={false}
/>
<div className="c-flex ml-8 flex-1">
<div className="d-flex mb-28">
<div
className={
thumb === defaultThumb1
? styles["thumb-item-avtive"]
: styles["thumb-item"]
}
onClick={() => {
setThumb(defaultThumb1);
form.setFieldsValue({
thumb: defaultThumb1,
});
}}
>
<Image
src={defaultThumb1}
width={80}
height={60}
style={{ borderRadius: 6 }}
preview={false}
/>
</div>
<div
className={
thumb === defaultThumb2
? styles["thumb-item-avtive"]
: styles["thumb-item"]
}
onClick={() => {
setThumb(defaultThumb2);
form.setFieldsValue({
thumb: defaultThumb2,
});
}}
>
<Image
src={defaultThumb2}
width={80}
height={60}
style={{ borderRadius: 6 }}
preview={false}
/>
</div>
<div
className={
thumb === defaultThumb3
? styles["thumb-item-avtive"]
: styles["thumb-item"]
}
onClick={() => {
setThumb(defaultThumb3);
form.setFieldsValue({
thumb: defaultThumb3,
});
}}
>
<Image
src={defaultThumb3}
width={80}
height={60}
style={{ borderRadius: 6 }}
preview={false}
/>
</div>
</div> </div>
<div <div className="d-flex">
className={ <UploadImageButton
thumb === defaultThumb2 text="更换封面"
? styles["thumb-item-avtive"] onSelected={(url) => {
: styles["thumb-item"] setThumb(url);
} form.setFieldsValue({ thumb: url });
onClick={() => { }}
setThumb(defaultThumb2); ></UploadImageButton>
form.setFieldsValue({ <span className="helper-text ml-16">
thumb: defaultThumb2, 推荐尺寸:400x300px
}); </span>
}}
>
<Image
src={defaultThumb2}
width={80}
height={60}
style={{ borderRadius: 6 }}
preview={false}
/>
</div> </div>
<div
className={
thumb === defaultThumb3
? styles["thumb-item-avtive"]
: styles["thumb-item"]
}
onClick={() => {
setThumb(defaultThumb3);
form.setFieldsValue({
thumb: defaultThumb3,
});
}}
>
<Image
src={defaultThumb3}
width={80}
height={60}
style={{ borderRadius: 6 }}
preview={false}
/>
</div>
</div>
<div className="d-flex">
<UploadImageButton
text="更换封面"
onSelected={(url) => {
setThumb(url);
form.setFieldsValue({ thumb: url });
}}
></UploadImageButton>
<span className="helper-text ml-16">
推荐尺寸:400x300px
</span>
</div> </div>
</div> </div>
</div> </Form.Item>
</Form.Item> <Form.Item
<Form.Item label="课时列表"
label="课时列表" name="hasChapter"
name="hasChapter" rules={[{ required: true, message: "请选择课时列表!" }]}
rules={[{ required: true, message: "请选择课时列表!" }]} >
> <Radio.Group onChange={getChapterType}>
<Radio.Group onChange={getChapterType}> <Radio value={0}></Radio>
<Radio value={0}></Radio> <Radio value={1} style={{ marginLeft: 22 }}>
<Radio value={1} style={{ marginLeft: 22 }}>
</Radio>
</Radio> </Radio.Group>
</Radio.Group> </Form.Item>
</Form.Item> {chapterType === 0 && (
{chapterType === 0 && ( <div className="c-flex mb-24">
<div className="c-flex mb-24"> <Form.Item>
<Form.Item> <div className="ml-120">
<div className="ml-120"> <Button
<Button onClick={() => setVideoVisible(true)}
onClick={() => setVideoVisible(true)} type="primary"
type="primary" >
>
</Button>
</Button> </div>
</Form.Item>
<div className={styles["hous-box"]}>
{treeData.length === 0 && (
<span className={styles["no-hours"]}>
</span>
)}
{treeData.length > 0 && (
<TreeHours
data={treeData}
onRemoveItem={(id: number) => {
delHour(id);
}}
onUpdate={(arr: any[]) => {
transHour(arr);
}}
/>
)}
</div> </div>
</div>
)}
{chapterType === 1 && (
<div className="c-flex mb-24">
{chapters.length > 0 &&
chapters.map((item: any, index: number) => {
return (
<div
key={item.hours.length + "章节" + index}
className={styles["chapter-item"]}
>
<div className="d-flex">
<div className={styles["label"]}>
{index + 1}
</div>
<Input
value={item.name}
className={styles["input"]}
onChange={(e) => {
setChapterName(index, e.target.value);
}}
allowClear
placeholder="请在此处输入章节名称"
/>
<Button
className="mr-16"
type="primary"
onClick={() => {
setVideoVisible(true);
setAddvideoCurrent(index);
}}
>
</Button>
<Button onClick={() => delChapter(index)}>
</Button>
</div>
<div className={styles["chapter-hous-box"]}>
{item.hours.length === 0 && (
<span className={styles["no-hours"]}>
</span>
)}
{item.hours.length > 0 && (
<TreeHours
data={item.hours}
onRemoveItem={(id: number) => {
delChapterHour(index, id);
}}
onUpdate={(arr: any[]) => {
transChapterHour(index, arr);
}}
/>
)}
</div>
</div>
);
})}
<Form.Item>
<div className="ml-120">
<Button onClick={() => addNewChapter()}></Button>
</div>
</Form.Item>
</div>
)}
<Form.Item label="更多选项">
<div
className={showDrop ? "drop-item active" : "drop-item"}
onClick={() => setShowDrop(!showDrop)}
>
<i
style={{ fontSize: 14 }}
className="iconfont icon-icon-xiala c-red"
/>
<span>()</span>
</div>
</Form.Item>
<div
className="c-flex"
style={{ display: showDrop ? "block" : "none" }}
>
<Form.Item label="课程简介" name="short_desc">
<Input.TextArea
style={{ width: 424, minHeight: 80 }}
allowClear
placeholder="请输入课程简介最多200字"
maxLength={200}
/>
</Form.Item>
<Form.Item label="课程附件">
<Button
onClick={() => setAttachmentVisible(true)}
type="primary"
>
</Button>
</Form.Item> </Form.Item>
<div className={styles["hous-box"]}> <div className={styles["hous-box"]}>
{treeData.length === 0 && ( {attachmentData.length === 0 && (
<span className={styles["no-hours"]}> <span className={styles["no-hours"]}>
</span> </span>
)} )}
{treeData.length > 0 && ( {attachmentData.length > 0 && (
<TreeHours <TreeAttachments
data={treeData} data={attachmentData}
onRemoveItem={(id: number) => { onRemoveItem={(id: number) => {
delHour(id); delAttachments(id);
}} }}
onUpdate={(arr: any[]) => { onUpdate={(arr: any[]) => {
transHour(arr); transAttachments(arr);
}} }}
/> />
)} )}
</div> </div>
</div> </div>
)} </Form>
{chapterType === 1 && ( </div>
<div className="c-flex mb-24"> </Drawer>
{chapters.length > 0 && ) : null}
chapters.map((item: any, index: number) => {
return (
<div
key={item.hours.length + "章节" + index}
className={styles["chapter-item"]}
>
<div className="d-flex">
<div className={styles["label"]}>
{index + 1}
</div>
<Input
value={item.name}
className={styles["input"]}
onChange={(e) => {
setChapterName(index, e.target.value);
}}
allowClear
placeholder="请在此处输入章节名称"
/>
<Button
className="mr-16"
type="primary"
onClick={() => {
setVideoVisible(true);
setAddvideoCurrent(index);
}}
>
</Button>
<Button onClick={() => delChapter(index)}>
</Button>
</div>
<div className={styles["chapter-hous-box"]}>
{item.hours.length === 0 && (
<span className={styles["no-hours"]}>
</span>
)}
{item.hours.length > 0 && (
<TreeHours
data={item.hours}
onRemoveItem={(id: number) => {
delChapterHour(index, id);
}}
onUpdate={(arr: any[]) => {
transChapterHour(index, arr);
}}
/>
)}
</div>
</div>
);
})}
<Form.Item>
<div className="ml-120">
<Button onClick={() => addNewChapter()}></Button>
</div>
</Form.Item>
</div>
)}
<Form.Item label="更多选项">
<div
className={showDrop ? "drop-item active" : "drop-item"}
onClick={() => setShowDrop(!showDrop)}
>
<i
style={{ fontSize: 14 }}
className="iconfont icon-icon-xiala c-red"
/>
<span>()</span>
</div>
</Form.Item>
<div
className="c-flex"
style={{ display: showDrop ? "block" : "none" }}
>
<Form.Item label="课程简介" name="short_desc">
<Input.TextArea
style={{ width: 424, minHeight: 80 }}
allowClear
placeholder="请输入课程简介最多200字"
maxLength={200}
/>
</Form.Item>
<Form.Item label="课程附件">
<Button
onClick={() => setAttachmentVisible(true)}
type="primary"
>
</Button>
</Form.Item>
<div className={styles["hous-box"]}>
{attachmentData.length === 0 && (
<span className={styles["no-hours"]}>
</span>
)}
{attachmentData.length > 0 && (
<TreeAttachments
data={attachmentData}
onRemoveItem={(id: number) => {
delAttachments(id);
}}
onUpdate={(arr: any[]) => {
transAttachments(arr);
}}
/>
)}
</div>
</div>
</Form>
</div>
</Drawer>
</> </>
); );
}; };

View File

@@ -32,6 +32,13 @@ export const CourseHourUpdate: React.FC<PropInterface> = ({
if (id === 0) { if (id === 0) {
return; return;
} }
setVideoVisible(false);
setChapters([]);
setHours([]);
setChapterHours([]);
setTreeData([]);
setAddvideoCurrent(0);
setChapterType(0);
getDetail(); getDetail();
}, [id, open]); }, [id, open]);
@@ -113,16 +120,11 @@ export const CourseHourUpdate: React.FC<PropInterface> = ({
message.error("请选择视频"); message.error("请选择视频");
return; return;
} }
courseHour courseHour.storeCourseHourMulti(id, hours).then((res: any) => {
.storeCourseHourMulti(id, hours) console.log("ok");
.then((res: any) => { setVideoVisible(false);
console.log("ok"); getDetail();
setVideoVisible(false); });
getDetail();
})
.catch((err) => {
message.error(err.message);
});
}; };
const selectChapterData = (arr: any, videos: any) => { const selectChapterData = (arr: any, videos: any) => {
@@ -146,16 +148,11 @@ export const CourseHourUpdate: React.FC<PropInterface> = ({
message.error("请选择视频"); message.error("请选择视频");
return; return;
} }
courseHour courseHour.storeCourseHourMulti(id, hours).then((res: any) => {
.storeCourseHourMulti(id, hours) console.log("ok");
.then((res: any) => { setVideoVisible(false);
console.log("ok"); getDetail();
setVideoVisible(false); });
getDetail();
})
.catch((err) => {
message.error(err.message);
});
}; };
const delHour = (hid: number) => { const delHour = (hid: number) => {
@@ -238,9 +235,6 @@ export const CourseHourUpdate: React.FC<PropInterface> = ({
.then((res: any) => { .then((res: any) => {
console.log("ok"); console.log("ok");
getDetail(); getDetail();
})
.catch((err) => {
message.error(err.message);
}); });
} else { } else {
courseChapter courseChapter
@@ -248,9 +242,6 @@ export const CourseHourUpdate: React.FC<PropInterface> = ({
.then((res: any) => { .then((res: any) => {
console.log("ok"); console.log("ok");
getDetail(); getDetail();
})
.catch((err) => {
message.error(err.message);
}); });
} }
}; };
@@ -272,9 +263,6 @@ export const CourseHourUpdate: React.FC<PropInterface> = ({
.then((res: any) => { .then((res: any) => {
console.log("ok"); console.log("ok");
getDetail(); getDetail();
})
.catch((err) => {
message.error(err.message);
}); });
} }
}, },
@@ -356,146 +344,149 @@ export const CourseHourUpdate: React.FC<PropInterface> = ({
return ( return (
<> <>
<Drawer {open ? (
title="课时管理" <Drawer
onClose={onCancel} title="课时管理"
maskClosable={false} onClose={onCancel}
open={open} maskClosable={false}
width={634} open={true}
> width={634}
<div className={styles["top-content"]}> >
<p>1.线</p> <div className={styles["top-content"]}>
<p>2.</p> <p>1.线</p>
</div> <p>2.</p>
<div className="float-left mt-24"> </div>
<SelectResource <div className="float-left mt-24">
defaultKeys={ <SelectResource
chapterType === 0 ? hours : changeChapterHours(chapterHours) defaultKeys={
} chapterType === 0 ? hours : changeChapterHours(chapterHours)
open={videoVisible}
onCancel={() => {
setVideoVisible(false);
}}
onSelected={(arr: any, videos: any) => {
if (chapterType === 0) {
selectData(arr, videos);
} else {
selectChapterData(arr, videos);
} }
}} open={videoVisible}
/> onCancel={() => {
<Form setVideoVisible(false);
form={form} }}
name="hour-update-basic" onSelected={(arr: any, videos: any) => {
labelCol={{ span: 5 }} if (chapterType === 0) {
wrapperCol={{ span: 19 }} selectData(arr, videos);
initialValues={{ remember: true }} } else {
onFinish={onFinish} selectChapterData(arr, videos);
onFinishFailed={onFinishFailed} }
autoComplete="off" }}
> />
{chapterType === 0 && ( <Form
<div className="c-flex"> form={form}
<Form.Item> name="hour-update-basic"
<div className="ml-42"> labelCol={{ span: 5 }}
<Button wrapperCol={{ span: 19 }}
onClick={() => setVideoVisible(true)} initialValues={{ remember: true }}
type="primary" onFinish={onFinish}
> onFinishFailed={onFinishFailed}
autoComplete="off"
</Button> >
</div> {chapterType === 0 && (
</Form.Item> <div className="c-flex">
<div className={styles["hous-box"]}> <Form.Item>
{treeData.length === 0 && ( <div className="ml-42">
<span className={styles["no-hours"]}> <Button
onClick={() => setVideoVisible(true)}
</span> type="primary"
)}
{treeData.length > 0 && (
<TreeHours
data={treeData}
onRemoveItem={(id: number) => {
delHour(id);
}}
onUpdate={(arr: any[]) => {
transHour(arr);
}}
/>
)}
</div>
</div>
)}
{chapterType === 1 && (
<div className="c-flex">
{chapters.length > 0 &&
chapters.map((item: any, index: number) => {
return (
<div
key={item.hours.length + "章节" + index}
className={styles["chapter-item"]}
> >
<div className="d-flex">
<div className={styles["label"]}> </Button>
{index + 1} </div>
</div> </Form.Item>
<Input <div className={styles["hous-box"]}>
value={item.name} {treeData.length === 0 && (
className={styles["input"]} <span className={styles["no-hours"]}>
onChange={(e) => {
setChapterName(index, e.target.value); </span>
}} )}
onBlur={(e) => { {treeData.length > 0 && (
saveChapterName(index, e.target.value); <TreeHours
}} data={treeData}
placeholder="请在此处输入章节名称" onRemoveItem={(id: number) => {
allowClear delHour(id);
/> }}
<Button onUpdate={(arr: any[]) => {
className="mr-16" transHour(arr);
type="primary" }}
onClick={() => { />
setVideoVisible(true); )}
setAddvideoCurrent(index);
}}
>
</Button>
<Button onClick={() => delChapter(index)}>
</Button>
</div>
<div className={styles["chapter-hous-box"]}>
{item.hours.length === 0 && (
<span className={styles["no-hours"]}>
</span>
)}
{item.hours.length > 0 && (
<TreeHours
data={item.hours}
onRemoveItem={(id: number) => {
delChapterHour(index, id);
}}
onUpdate={(arr: any[]) => {
transChapterHour(index, arr);
}}
/>
)}
</div>
</div>
);
})}
<Form.Item>
<div className="ml-42">
<Button onClick={() => addNewChapter()}></Button>
</div> </div>
</Form.Item> </div>
</div> )}
)} {chapterType === 1 && (
</Form> <div className="c-flex">
</div> {chapters.length > 0 &&
</Drawer> chapters.map((item: any, index: number) => {
return (
<div
key={item.hours.length + "章节" + index}
className={styles["chapter-item"]}
>
<div className="d-flex">
<div className={styles["label"]}>
{index + 1}
</div>
<Input
value={item.name}
className={styles["input"]}
onChange={(e) => {
setChapterName(index, e.target.value);
}}
onBlur={(e) => {
saveChapterName(index, e.target.value);
}}
placeholder="请在此处输入章节名称"
allowClear
/>
<Button
disabled={!item.name}
className="mr-16"
type="primary"
onClick={() => {
setVideoVisible(true);
setAddvideoCurrent(index);
}}
>
</Button>
<Button onClick={() => delChapter(index)}>
</Button>
</div>
<div className={styles["chapter-hous-box"]}>
{item.hours.length === 0 && (
<span className={styles["no-hours"]}>
</span>
)}
{item.hours.length > 0 && (
<TreeHours
data={item.hours}
onRemoveItem={(id: number) => {
delChapterHour(index, id);
}}
onUpdate={(arr: any[]) => {
transChapterHour(index, arr);
}}
/>
)}
</div>
</div>
);
})}
<Form.Item>
<div className="ml-42">
<Button onClick={() => addNewChapter()}></Button>
</div>
</Form.Item>
</div>
)}
</Form>
</div>
</Drawer>
) : null}
</> </>
); );
}; };

View File

@@ -7,9 +7,9 @@ import {
Form, Form,
TreeSelect, TreeSelect,
Input, Input,
Modal,
message, message,
Image, Image,
Spin,
} from "antd"; } from "antd";
import styles from "./update.module.less"; import styles from "./update.module.less";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
@@ -28,6 +28,7 @@ export const CourseUpdate: React.FC<PropInterface> = ({
onCancel, onCancel,
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [init, setInit] = useState(true);
const courseDefaultThumbs = useSelector( const courseDefaultThumbs = useSelector(
(state: any) => state.systemConfig.value.courseDefaultThumbs (state: any) => state.systemConfig.value.courseDefaultThumbs
); );
@@ -41,18 +42,16 @@ export const CourseUpdate: React.FC<PropInterface> = ({
const [type, setType] = useState<string>("open"); const [type, setType] = useState<string>("open");
useEffect(() => { useEffect(() => {
if (open) { setInit(true);
getParams();
getCategory();
}
}, [form, open]);
useEffect(() => {
if (id === 0) { if (id === 0) {
return; return;
} }
getDetail(); if (open) {
}, [id, open]); getParams();
getCategory();
getDetail();
}
}, [form, id, open]);
const getCategory = () => { const getCategory = () => {
course.createCourse().then((res: any) => { course.createCourse().then((res: any) => {
@@ -91,6 +90,7 @@ export const CourseUpdate: React.FC<PropInterface> = ({
}); });
setType(type); setType(type);
setThumb(res.data.course.thumb); setThumb(res.data.course.thumb);
setInit(false);
}); });
}; };
@@ -169,209 +169,219 @@ export const CourseUpdate: React.FC<PropInterface> = ({
return ( return (
<> <>
<Drawer {open ? (
title="编辑课程" <Drawer
onClose={onCancel} title="编辑课程"
maskClosable={false} onClose={onCancel}
open={open} maskClosable={false}
footer={ open={true}
<Space className="j-r-flex"> footer={
<Button onClick={() => onCancel()}> </Button> <Space className="j-r-flex">
<Button onClick={() => form.submit()} type="primary"> <Button onClick={() => onCancel()}> </Button>
<Button onClick={() => form.submit()} type="primary">
</Button>
</Space> </Button>
} </Space>
width={634} }
> width={634}
<div className="float-left mt-24"> >
<Form {init && (
form={form} <div className="float-left text-center mt-30">
name="update-basic" <Spin></Spin>
labelCol={{ span: 5 }} </div>
wrapperCol={{ span: 19 }} )}
initialValues={{ remember: true }} <div
onFinish={onFinish} className="float-left mt-24"
onFinishFailed={onFinishFailed} style={{ display: init ? "none" : "block" }}
autoComplete="off"
> >
<Form.Item <Form
label="课程分类" form={form}
name="category_ids" name="update-basic"
rules={[{ required: true, message: "请选择课程分类!" }]} labelCol={{ span: 5 }}
wrapperCol={{ span: 19 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
> >
<TreeSelect
showCheckedStrategy={TreeSelect.SHOW_ALL}
allowClear
multiple
style={{ width: 424 }}
treeData={categories}
placeholder="请选择课程分类"
treeDefaultExpandAll
/>
</Form.Item>
<Form.Item
label="课程名称"
name="title"
rules={[{ required: true, message: "请在此处输入课程名称!" }]}
>
<Input
allowClear
style={{ width: 424 }}
placeholder="请在此处输入课程名称"
/>
</Form.Item>
<Form.Item
label="课程属性"
name="isRequired"
rules={[{ required: true, message: "请选择课程属性!" }]}
>
<Radio.Group>
<Radio value={1}></Radio>
<Radio value={0} style={{ marginLeft: 22 }}>
</Radio>
</Radio.Group>
</Form.Item>
<Form.Item
label="指派部门"
name="type"
rules={[{ required: true, message: "请选择指派部门!" }]}
>
<Radio.Group onChange={getType}>
<Radio value="open"></Radio>
<Radio value="elective"></Radio>
</Radio.Group>
</Form.Item>
{type === "elective" && (
<Form.Item <Form.Item
label="选择部门" label="课程分类"
name="dep_ids" name="category_ids"
rules={[ rules={[{ required: true, message: "请选择课程分类!" }]}
{
required: true,
message: "请选择部门!",
},
]}
> >
<TreeSelect <TreeSelect
showCheckedStrategy={TreeSelect.SHOW_ALL} showCheckedStrategy={TreeSelect.SHOW_ALL}
style={{ width: 424 }}
treeData={departments}
multiple
allowClear allowClear
multiple
style={{ width: 424 }}
treeData={categories}
placeholder="请选择课程分类"
treeDefaultExpandAll treeDefaultExpandAll
placeholder="请选择部门"
/> />
</Form.Item> </Form.Item>
)} <Form.Item
label="课程名称"
<Form.Item name="title"
label="课程封面" rules={[{ required: true, message: "请在此处输入课程名称!" }]}
name="thumb" >
rules={[{ required: true, message: "请上传课程封面!" }]} <Input
> allowClear
<div className="d-flex"> style={{ width: 424 }}
<Image placeholder="请在此处输入课程名称"
src={thumb}
width={160}
height={120}
style={{ borderRadius: 6 }}
preview={false}
/> />
<div className="c-flex ml-8 flex-1"> </Form.Item>
<div className="d-flex mb-28"> <Form.Item
<div label="课程属性"
className={ name="isRequired"
thumb === defaultThumb1 rules={[{ required: true, message: "请选择课程属性!" }]}
? styles["thumb-item-avtive"] >
: styles["thumb-item"] <Radio.Group>
} <Radio value={1}></Radio>
onClick={() => { <Radio value={0} style={{ marginLeft: 22 }}>
setThumb(defaultThumb1);
form.setFieldsValue({ </Radio>
thumb: defaultThumb1, </Radio.Group>
}); </Form.Item>
}} <Form.Item
> label="指派部门"
<Image name="type"
src={defaultThumb1} rules={[{ required: true, message: "请选择指派部门!" }]}
width={80} >
height={60} <Radio.Group onChange={getType}>
style={{ borderRadius: 6 }} <Radio value="open"></Radio>
preview={false} <Radio value="elective"></Radio>
/> </Radio.Group>
</Form.Item>
{type === "elective" && (
<Form.Item
label="选择部门"
name="dep_ids"
rules={[
{
required: true,
message: "请选择部门!",
},
]}
>
<TreeSelect
showCheckedStrategy={TreeSelect.SHOW_ALL}
style={{ width: 424 }}
treeData={departments}
multiple
allowClear
treeDefaultExpandAll
placeholder="请选择部门"
/>
</Form.Item>
)}
<Form.Item
label="课程封面"
name="thumb"
rules={[{ required: true, message: "请上传课程封面!" }]}
>
<div className="d-flex">
<Image
src={thumb}
width={160}
height={120}
style={{ borderRadius: 6 }}
preview={false}
/>
<div className="c-flex ml-8 flex-1">
<div className="d-flex mb-28">
<div
className={
thumb === defaultThumb1
? styles["thumb-item-avtive"]
: styles["thumb-item"]
}
onClick={() => {
setThumb(defaultThumb1);
form.setFieldsValue({
thumb: defaultThumb1,
});
}}
>
<Image
src={defaultThumb1}
width={80}
height={60}
style={{ borderRadius: 6 }}
preview={false}
/>
</div>
<div
className={
thumb === defaultThumb2
? styles["thumb-item-avtive"]
: styles["thumb-item"]
}
onClick={() => {
setThumb(defaultThumb2);
form.setFieldsValue({
thumb: defaultThumb2,
});
}}
>
<Image
src={defaultThumb2}
width={80}
height={60}
style={{ borderRadius: 6 }}
preview={false}
/>
</div>
<div
className={
thumb === defaultThumb3
? styles["thumb-item-avtive"]
: styles["thumb-item"]
}
onClick={() => {
setThumb(defaultThumb3);
form.setFieldsValue({
thumb: defaultThumb3,
});
}}
>
<Image
src={defaultThumb3}
width={80}
height={60}
style={{ borderRadius: 6 }}
preview={false}
/>
</div>
</div> </div>
<div <div className="d-flex">
className={ <UploadImageButton
thumb === defaultThumb2 text="更换封面"
? styles["thumb-item-avtive"] onSelected={(url) => {
: styles["thumb-item"] setThumb(url);
} form.setFieldsValue({ thumb: url });
onClick={() => { }}
setThumb(defaultThumb2); ></UploadImageButton>
form.setFieldsValue({ <span className="helper-text ml-16">
thumb: defaultThumb2, 推荐尺寸:400x300px
}); </span>
}}
>
<Image
src={defaultThumb2}
width={80}
height={60}
style={{ borderRadius: 6 }}
preview={false}
/>
</div> </div>
<div
className={
thumb === defaultThumb3
? styles["thumb-item-avtive"]
: styles["thumb-item"]
}
onClick={() => {
setThumb(defaultThumb3);
form.setFieldsValue({
thumb: defaultThumb3,
});
}}
>
<Image
src={defaultThumb3}
width={80}
height={60}
style={{ borderRadius: 6 }}
preview={false}
/>
</div>
</div>
<div className="d-flex">
<UploadImageButton
text="更换封面"
onSelected={(url) => {
setThumb(url);
form.setFieldsValue({ thumb: url });
}}
></UploadImageButton>
<span className="helper-text ml-16">
推荐尺寸:400x300px
</span>
</div> </div>
</div> </div>
</div> </Form.Item>
</Form.Item> <Form.Item label="课程简介" name="short_desc">
<Form.Item label="课程简介" name="short_desc"> <Input.TextArea
<Input.TextArea style={{ width: 424, minHeight: 80 }}
style={{ width: 424, minHeight: 80 }} allowClear
allowClear placeholder="请输入课程简介最多200字"
placeholder="请输入课程简介最多200字" maxLength={200}
maxLength={200} />
/> </Form.Item>
</Form.Item> </Form>
</Form> </div>
</div> </Drawer>
</Drawer> ) : null}
</> </>
); );
}; };

View File

@@ -105,57 +105,59 @@ export const DepartmentCreate: React.FC<PropInterface> = ({
return ( return (
<> <>
<Modal {open ? (
title="新建部门" <Modal
centered title="新建部门"
forceRender centered
open={open} forceRender
width={416} open={true}
onOk={() => form.submit()} width={416}
onCancel={() => onCancel()} onOk={() => form.submit()}
maskClosable={false} onCancel={() => onCancel()}
> maskClosable={false}
<div className="float-left mt-24"> >
<Form <div className="float-left mt-24">
form={form} <Form
name="basic" form={form}
labelCol={{ span: 8 }} name="basic"
wrapperCol={{ span: 16 }} labelCol={{ span: 8 }}
initialValues={{ remember: true }} wrapperCol={{ span: 16 }}
onFinish={onFinish} initialValues={{ remember: true }}
onFinishFailed={onFinishFailed} onFinish={onFinish}
autoComplete="off" onFinishFailed={onFinishFailed}
> autoComplete="off"
<Form.Item
label="所属上级"
name="parent_id"
rules={[{ required: true, message: "请选择所属上级!" }]}
> >
<Cascader <Form.Item
style={{ width: 200 }} label="所属上级"
allowClear name="parent_id"
placeholder="请选择所属上级" rules={[{ required: true, message: "请选择所属上级!" }]}
onChange={handleChange} >
options={departments} <Cascader
changeOnSelect style={{ width: 200 }}
expand-trigger="hover" allowClear
displayRender={displayRender} placeholder="请选择所属上级"
/> onChange={handleChange}
</Form.Item> options={departments}
<Form.Item changeOnSelect
label="部门名称" expand-trigger="hover"
name="name" displayRender={displayRender}
rules={[{ required: true, message: "请输入部门名称!" }]} />
> </Form.Item>
<Input <Form.Item
style={{ width: 200 }} label="部门名称"
allowClear name="name"
placeholder="请输入部门名称" rules={[{ required: true, message: "请输入部门名称!" }]}
/> >
</Form.Item> <Input
</Form> style={{ width: 200 }}
</div> allowClear
</Modal> placeholder="请输入部门名称"
/>
</Form.Item>
</Form>
</div>
</Modal>
) : null}
</> </>
); );
}; };

View File

@@ -1,5 +1,5 @@
import React, { useState, useRef, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Modal, Form, Input, Cascader, message } from "antd"; import { Modal, Form, Input, Cascader, message, Spin } from "antd";
import styles from "./update.module.less"; import styles from "./update.module.less";
import { department } from "../../../api/index"; import { department } from "../../../api/index";
@@ -21,12 +21,14 @@ export const DepartmentUpdate: React.FC<PropInterface> = ({
onCancel, onCancel,
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [init, setInit] = useState(true);
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
const [departments, setDepartments] = useState<any>([]); const [departments, setDepartments] = useState<any>([]);
const [parent_id, setParentId] = useState<number>(0); const [parent_id, setParentId] = useState<number>(0);
const [sort, setSort] = useState<number>(0); const [sort, setSort] = useState<number>(0);
useEffect(() => { useEffect(() => {
setInit(true);
if (open) { if (open) {
getParams(); getParams();
} }
@@ -64,6 +66,7 @@ export const DepartmentUpdate: React.FC<PropInterface> = ({
}); });
setParentId(data.parent_id); setParentId(data.parent_id);
setSort(data.sort); setSort(data.sort);
setInit(false);
}); });
}; };
@@ -129,53 +132,63 @@ export const DepartmentUpdate: React.FC<PropInterface> = ({
return ( return (
<> <>
<Modal {open ? (
title="编辑部门" <Modal
centered title="编辑部门"
forceRender centered
open={open} forceRender
width={416} open={true}
onOk={() => form.submit()} width={416}
onCancel={() => onCancel()} onOk={() => form.submit()}
maskClosable={false} onCancel={() => onCancel()}
> maskClosable={false}
<div className="float-left mt-24"> >
<Form {init && (
form={form} <div className="float-left text-center mt-30">
name="basic" <Spin></Spin>
labelCol={{ span: 8 }} </div>
wrapperCol={{ span: 16 }} )}
initialValues={{ remember: true }} <div
onFinish={onFinish} className="float-left mt-24"
onFinishFailed={onFinishFailed} style={{ display: init ? "none" : "block" }}
autoComplete="off"
> >
<Form.Item <Form
label="所属上级" form={form}
name="parent_id" name="basic"
rules={[{ required: true, message: "请选择所属上级!" }]} labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
> >
<Cascader <Form.Item
style={{ width: 200 }} label="所属上级"
allowClear name="parent_id"
placeholder="请选择所属上级" rules={[{ required: true, message: "请选择所属上级!" }]}
onChange={handleChange} >
options={departments} <Cascader
changeOnSelect style={{ width: 200 }}
expand-trigger="hover" allowClear
displayRender={displayRender} placeholder="请选择所属上级"
/> onChange={handleChange}
</Form.Item> options={departments}
<Form.Item changeOnSelect
label="部门名称" expand-trigger="hover"
name="name" displayRender={displayRender}
rules={[{ required: true, message: "请输入部门名称!" }]} />
> </Form.Item>
<Input style={{ width: 200 }} placeholder="请输入部门名称" /> <Form.Item
</Form.Item> label="部门名称"
</Form> name="name"
</div> rules={[{ required: true, message: "请输入部门名称!" }]}
</Modal> >
<Input style={{ width: 200 }} placeholder="请输入部门名称" />
</Form.Item>
</Form>
</div>
</Modal>
) : null}
</> </>
); );
}; };

View File

@@ -105,102 +105,104 @@ export const MemberCreate: React.FC<PropInterface> = ({
return ( return (
<> <>
<Modal {open ? (
title="添加学员" <Modal
centered title="添加学员"
forceRender centered
open={open} forceRender
width={484} open={true}
onOk={() => form.submit()} width={484}
onCancel={() => onCancel()} onOk={() => form.submit()}
maskClosable={false} onCancel={() => onCancel()}
> maskClosable={false}
<div className="member-form float-left mt-24"> >
<Form <div className="member-form float-left mt-24">
form={form} <Form
name="create-basic" form={form}
labelCol={{ span: 7 }} name="create-basic"
wrapperCol={{ span: 17 }} labelCol={{ span: 7 }}
initialValues={{ remember: true }} wrapperCol={{ span: 17 }}
onFinish={onFinish} initialValues={{ remember: true }}
onFinishFailed={onFinishFailed} onFinish={onFinish}
autoComplete="off" onFinishFailed={onFinishFailed}
> autoComplete="off"
<Form.Item
label="学员头像"
labelCol={{ style: { marginTop: 15, marginLeft: 46 } }}
name="avatar"
rules={[{ required: true, message: "请上传学员头像!" }]}
> >
<div className="d-flex"> <Form.Item
{avatar && ( label="学员头像"
<img className="form-avatar mr-16" src={avatar} alt="" /> labelCol={{ style: { marginTop: 15, marginLeft: 46 } }}
)} name="avatar"
rules={[{ required: true, message: "请上传学员头像!" }]}
>
<div className="d-flex"> <div className="d-flex">
<UploadImageButton {avatar && (
text="更换头像" <img className="form-avatar mr-16" src={avatar} alt="" />
onSelected={(url) => { )}
setAvatar(url); <div className="d-flex">
form.setFieldsValue({ avatar: url }); <UploadImageButton
}} text="更换头像"
></UploadImageButton> onSelected={(url) => {
setAvatar(url);
form.setFieldsValue({ avatar: url });
}}
></UploadImageButton>
</div>
</div> </div>
</div> </Form.Item>
</Form.Item> <Form.Item
<Form.Item label="学员姓名"
label="学员姓名" name="name"
name="name" rules={[{ required: true, message: "请输入学员姓名!" }]}
rules={[{ required: true, message: "请输入学员姓名!" }]} >
> <Input style={{ width: 274 }} placeholder="请填写学员姓名" />
<Input style={{ width: 274 }} placeholder="请填写学员姓名" /> </Form.Item>
</Form.Item> <Form.Item
<Form.Item label="登录邮箱"
label="登录邮箱" name="email"
name="email" rules={[{ required: true, message: "请输入登录邮箱!" }]}
rules={[{ required: true, message: "请输入登录邮箱!" }]} >
> <Input
<Input allowClear
allowClear style={{ width: 274 }}
style={{ width: 274 }} placeholder="请输入学员登录邮箱"
placeholder="请输入学员登录邮箱" />
/> </Form.Item>
</Form.Item> <Form.Item
<Form.Item label="登录密码"
label="登录密码" name="password"
name="password" rules={[{ required: true, message: "请输入登录密码!" }]}
rules={[{ required: true, message: "请输入登录密码!" }]} >
> <Input.Password
<Input.Password allowClear
allowClear style={{ width: 274 }}
style={{ width: 274 }} placeholder="请输入登录密码"
placeholder="请输入登录密码" />
/> </Form.Item>
</Form.Item> <Form.Item
<Form.Item label="所属部门"
label="所属部门" name="dep_ids"
name="dep_ids" rules={[{ required: true, message: "请选择学员所属部门!" }]}
rules={[{ required: true, message: "请选择学员所属部门!" }]} >
> <TreeSelect
<TreeSelect showCheckedStrategy={TreeSelect.SHOW_ALL}
showCheckedStrategy={TreeSelect.SHOW_ALL} style={{ width: 274 }}
style={{ width: 274 }} treeData={departments}
treeData={departments} multiple
multiple allowClear
allowClear treeDefaultExpandAll
treeDefaultExpandAll placeholder="请选择学员所属部门"
placeholder="请选择学员所属部门" />
/> </Form.Item>
</Form.Item> <Form.Item label="身份证号" name="idCard">
<Form.Item label="身份证号" name="idCard"> <Input
<Input style={{ width: 274 }}
style={{ width: 274 }} allowClear
allowClear placeholder="请填写学员身份证号"
placeholder="请填写学员身份证号" />
/> </Form.Item>
</Form.Item> </Form>
</Form> </div>
</div> </Modal>
</Modal> ) : null}
</> </>
); );
}; };

View File

@@ -210,43 +210,45 @@ export const MemberLearnProgressDialog: React.FC<PropInterface> = ({
return ( return (
<> <>
<Modal {open ? (
title="课时学习进度" <Modal
centered title="课时学习进度"
forceRender centered
open={open} forceRender
width={1000} open={true}
onOk={() => onCancel()} width={1000}
onCancel={() => onCancel()} onOk={() => onCancel()}
maskClosable={false} onCancel={() => onCancel()}
footer={null} maskClosable={false}
> footer={null}
<div className="d-flex mt-24">
<PerButton
type="primary"
text="重置学习记录"
class="c-white"
icon={null}
p="user-learn-destroy"
onClick={() => {
clearProgress();
}}
disabled={null}
/>
</div>
<div
className="d-flex mt-24"
style={{ maxHeight: 800, overflowY: "auto" }}
> >
<Table <div className="d-flex mt-24">
columns={column} <PerButton
dataSource={list} type="primary"
loading={loading} text="重置学习记录"
rowKey={(record) => record.id} class="c-white"
pagination={false} icon={null}
/> p="user-learn-destroy"
</div> onClick={() => {
</Modal> clearProgress();
}}
disabled={null}
/>
</div>
<div
className="d-flex mt-24"
style={{ maxHeight: 800, overflowY: "auto" }}
>
<Table
columns={column}
dataSource={list}
loading={loading}
rowKey={(record) => record.id}
pagination={false}
/>
</div>
</Modal>
) : null}
</> </>
); );
}; };

View File

@@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Modal, Form, TreeSelect, Input, message } from "antd"; import { Modal, Form, TreeSelect, Input, message, Spin } from "antd";
import styles from "./update.module.less"; import styles from "./update.module.less";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { user, department } from "../../../api/index"; import { user, department } from "../../../api/index";
@@ -24,6 +24,7 @@ export const MemberUpdate: React.FC<PropInterface> = ({
onCancel, onCancel,
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [init, setInit] = useState(true);
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
const [departments, setDepartments] = useState<any>([]); const [departments, setDepartments] = useState<any>([]);
const memberDefaultAvatar = useSelector( const memberDefaultAvatar = useSelector(
@@ -32,20 +33,18 @@ export const MemberUpdate: React.FC<PropInterface> = ({
const [avatar, setAvatar] = useState<string>(memberDefaultAvatar); const [avatar, setAvatar] = useState<string>(memberDefaultAvatar);
useEffect(() => { useEffect(() => {
setInit(true);
if (id == 0) { if (id == 0) {
return; return;
} }
getDetail();
}, [id, open]);
useEffect(() => {
if (open) { if (open) {
getParams(); getParams();
form.setFieldsValue({ form.setFieldsValue({
password: "", password: "",
}); });
getDetail();
} }
}, [form, open]); }, [form, id, open]);
const getParams = () => { const getParams = () => {
if (id === 0) { if (id === 0) {
@@ -71,6 +70,7 @@ export const MemberUpdate: React.FC<PropInterface> = ({
idCard: user.id_card, idCard: user.id_card,
dep_ids: res.data.dep_ids, dep_ids: res.data.dep_ids,
}); });
setInit(false);
}); });
}; };
@@ -134,102 +134,112 @@ export const MemberUpdate: React.FC<PropInterface> = ({
return ( return (
<> <>
<Modal {open ? (
title="编辑学员" <Modal
centered title="编辑学员"
forceRender centered
open={open} forceRender
width={484} open={true}
onOk={() => form.submit()} width={484}
onCancel={() => onCancel()} onOk={() => form.submit()}
maskClosable={false} onCancel={() => onCancel()}
> maskClosable={false}
<div className="float-left mt-24"> >
<Form {init && (
form={form} <div className="float-left text-center mt-30">
name="update-basic" <Spin></Spin>
labelCol={{ span: 7 }} </div>
wrapperCol={{ span: 17 }} )}
initialValues={{ remember: true }} <div
onFinish={onFinish} className="float-left mt-24"
onFinishFailed={onFinishFailed} style={{ display: init ? "none" : "block" }}
autoComplete="off"
> >
<Form.Item <Form
label="学员头像" form={form}
labelCol={{ style: { marginTop: 15, marginLeft: 46 } }} name="update-basic"
name="avatar" labelCol={{ span: 7 }}
rules={[{ required: true, message: "请上传学员头像!" }]} wrapperCol={{ span: 17 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
> >
<div className="d-flex"> <Form.Item
{avatar && ( label="学员头像"
<img className="form-avatar mr-16" src={avatar} alt="" /> labelCol={{ style: { marginTop: 15, marginLeft: 46 } }}
)} name="avatar"
rules={[{ required: true, message: "请上传学员头像!" }]}
>
<div className="d-flex"> <div className="d-flex">
<UploadImageButton {avatar && (
text="更换头像" <img className="form-avatar mr-16" src={avatar} alt="" />
onSelected={(url) => { )}
setAvatar(url); <div className="d-flex">
form.setFieldsValue({ avatar: url }); <UploadImageButton
}} text="更换头像"
></UploadImageButton> onSelected={(url) => {
setAvatar(url);
form.setFieldsValue({ avatar: url });
}}
></UploadImageButton>
</div>
</div> </div>
</div> </Form.Item>
</Form.Item> <Form.Item
<Form.Item label="学员姓名"
label="学员姓名" name="name"
name="name" rules={[{ required: true, message: "请输入学员姓名!" }]}
rules={[{ required: true, message: "请输入学员姓名!" }]} >
> <Input
<Input allowClear
allowClear style={{ width: 274 }}
style={{ width: 274 }} placeholder="请填写学员姓名"
placeholder="请填写学员姓名" />
/> </Form.Item>
</Form.Item> <Form.Item
<Form.Item label="登录邮箱"
label="登录邮箱" name="email"
name="email" rules={[{ required: true, message: "请输入登录邮箱!" }]}
rules={[{ required: true, message: "请输入登录邮箱!" }]} >
> <Input
<Input style={{ width: 274 }}
style={{ width: 274 }} allowClear
allowClear placeholder="请输入学员登录邮箱"
placeholder="请输入学员登录邮箱" />
/> </Form.Item>
</Form.Item> <Form.Item label="登录密码" name="password">
<Form.Item label="登录密码" name="password"> <Input.Password
<Input.Password style={{ width: 274 }}
style={{ width: 274 }} allowClear
allowClear placeholder="请输入登录密码"
placeholder="请输入登录密码" />
/> </Form.Item>
</Form.Item> <Form.Item
<Form.Item label="所属部门"
label="所属部门" name="dep_ids"
name="dep_ids" rules={[{ required: true, message: "请选择学员所属部门!" }]}
rules={[{ required: true, message: "请选择学员所属部门!" }]} >
> <TreeSelect
<TreeSelect showCheckedStrategy={TreeSelect.SHOW_ALL}
showCheckedStrategy={TreeSelect.SHOW_ALL} style={{ width: 274 }}
style={{ width: 274 }} treeData={departments}
treeData={departments} multiple
multiple allowClear
allowClear treeDefaultExpandAll
treeDefaultExpandAll placeholder="请选择学员所属部门"
placeholder="请选择学员所属部门" />
/> </Form.Item>
</Form.Item> <Form.Item label="身份证号" name="idCard">
<Form.Item label="身份证号" name="idCard"> <Input
<Input allowClear
allowClear style={{ width: 274 }}
style={{ width: 274 }} placeholder="请填写学员身份证号"
placeholder="请填写学员身份证号" />
/> </Form.Item>
</Form.Item> </Form>
</Form> </div>
</div> </Modal>
</Modal> ) : null}
</> </>
); );
}; };

View File

@@ -71,6 +71,7 @@ const MemberPage = () => {
{ {
title: "学员", title: "学员",
dataIndex: "name", dataIndex: "name",
width: 300,
render: (_, record: any) => ( render: (_, record: any) => (
<> <>
<Image <Image
@@ -104,10 +105,13 @@ const MemberPage = () => {
}, },
{ {
title: "登录邮箱", title: "登录邮箱",
width: 200,
dataIndex: "email", dataIndex: "email",
render: (email: string) => <span>{email}</span>,
}, },
{ {
title: "加入时间", title: "加入时间",
width: 200,
dataIndex: "created_at", dataIndex: "created_at",
render: (text: string) => <span>{dateFormat(text)}</span>, render: (text: string) => <span>{dateFormat(text)}</span>,
}, },

View File

@@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Modal, Form, Input, message, TreeSelect } from "antd"; import { Modal, Form, Input, message, TreeSelect, Spin } from "antd";
import { resource, resourceCategory } from "../../../../../api/index"; import { resource, resourceCategory } from "../../../../../api/index";
interface PropInterface { interface PropInterface {
@@ -17,9 +17,11 @@ export const CoursewareUpdateDialog: React.FC<PropInterface> = ({
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
const [init, setInit] = useState(true);
const [categories, setCategories] = useState<any>([]); const [categories, setCategories] = useState<any>([]);
useEffect(() => { useEffect(() => {
setInit(true);
if (id === 0) { if (id === 0) {
return; return;
} }
@@ -27,7 +29,7 @@ export const CoursewareUpdateDialog: React.FC<PropInterface> = ({
getCategory(); getCategory();
getDetail(); getDetail();
} }
}, [id, open]); }, [form, id, open]);
const getCategory = () => { const getCategory = () => {
resourceCategory.resourceCategoryList().then((res: any) => { resourceCategory.resourceCategoryList().then((res: any) => {
@@ -46,6 +48,7 @@ export const CoursewareUpdateDialog: React.FC<PropInterface> = ({
name: data.name, name: data.name,
category_id: res.data.category_ids, category_id: res.data.category_ids,
}); });
setInit(false);
}); });
}; };
@@ -96,55 +99,65 @@ export const CoursewareUpdateDialog: React.FC<PropInterface> = ({
return ( return (
<> <>
<Modal {open ? (
title="编辑课件" <Modal
centered title="编辑课件"
forceRender centered
open={open} forceRender
width={416} open={true}
onOk={() => form.submit()} width={416}
onCancel={() => onCancel()} onOk={() => form.submit()}
maskClosable={false} onCancel={() => onCancel()}
> maskClosable={false}
<div className="float-left mt-24"> >
<Form {init && (
form={form} <div className="float-left text-center mt-30">
name="videos-update" <Spin></Spin>
labelCol={{ span: 8 }} </div>
wrapperCol={{ span: 16 }} )}
initialValues={{ remember: true }} <div
onFinish={onFinish} className="float-left mt-24"
onFinishFailed={onFinishFailed} style={{ display: init ? "none" : "block" }}
autoComplete="off"
> >
<Form.Item <Form
label="课件分类" form={form}
name="category_id" name="videos-update"
rules={[{ required: true, message: "请选择课件分类!" }]} labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
> >
<TreeSelect <Form.Item
showCheckedStrategy={TreeSelect.SHOW_ALL} label="课件分类"
allowClear name="category_id"
style={{ width: 200 }} rules={[{ required: true, message: "请选择课件分类!" }]}
treeData={categories} >
placeholder="课件分类" <TreeSelect
treeDefaultExpandAll showCheckedStrategy={TreeSelect.SHOW_ALL}
/> allowClear
</Form.Item> style={{ width: 200 }}
<Form.Item treeData={categories}
label="课件名称" placeholder="课件分类"
name="name" treeDefaultExpandAll
rules={[{ required: true, message: "请输入课件名称!" }]} />
> </Form.Item>
<Input <Form.Item
allowClear label="课件名称"
style={{ width: 200 }} name="name"
placeholder="请输入课件名称" rules={[{ required: true, message: "请输入课件名称!" }]}
/> >
</Form.Item> <Input
</Form> allowClear
</div> style={{ width: 200 }}
</Modal> placeholder="请输入课件名称"
/>
</Form.Item>
</Form>
</div>
</Modal>
) : null}
</> </>
); );
}; };

View File

@@ -105,57 +105,59 @@ export const ResourceCategoryCreate: React.FC<PropInterface> = ({
return ( return (
<> <>
<Modal {open ? (
title="新建分类" <Modal
centered title="新建分类"
forceRender centered
maskClosable={false} forceRender
open={open} maskClosable={false}
width={416} open={true}
onOk={() => form.submit()} width={416}
onCancel={() => onCancel()} onOk={() => form.submit()}
> onCancel={() => onCancel()}
<div className="float-left mt-24"> >
<Form <div className="float-left mt-24">
form={form} <Form
name="basic" form={form}
labelCol={{ span: 8 }} name="basic"
wrapperCol={{ span: 16 }} labelCol={{ span: 8 }}
initialValues={{ remember: true }} wrapperCol={{ span: 16 }}
onFinish={onFinish} initialValues={{ remember: true }}
onFinishFailed={onFinishFailed} onFinish={onFinish}
autoComplete="off" onFinishFailed={onFinishFailed}
> autoComplete="off"
<Form.Item
label="所属上级"
name="parent_id"
rules={[{ required: true, message: "请选择所属上级!" }]}
> >
<Cascader <Form.Item
style={{ width: 200 }} label="所属上级"
allowClear name="parent_id"
placeholder="请选择所属上级" rules={[{ required: true, message: "请选择所属上级!" }]}
onChange={handleChange} >
options={categories} <Cascader
changeOnSelect style={{ width: 200 }}
expand-trigger="hover" allowClear
displayRender={displayRender} placeholder="请选择所属上级"
/> onChange={handleChange}
</Form.Item> options={categories}
<Form.Item changeOnSelect
label="分类名称" expand-trigger="hover"
name="name" displayRender={displayRender}
rules={[{ required: true, message: "请输入分类名称!" }]} />
> </Form.Item>
<Input <Form.Item
style={{ width: 200 }} label="分类名称"
allowClear name="name"
placeholder="请输入分类名称" rules={[{ required: true, message: "请输入分类名称!" }]}
/> >
</Form.Item> <Input
</Form> style={{ width: 200 }}
</div> allowClear
</Modal> placeholder="请输入分类名称"
/>
</Form.Item>
</Form>
</div>
</Modal>
) : null}
</> </>
); );
}; };

View File

@@ -1,5 +1,5 @@
import React, { useState, useRef, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Modal, Form, Input, Cascader, message } from "antd"; import { Modal, Form, Input, Cascader, message, Spin } from "antd";
import styles from "./update.module.less"; import styles from "./update.module.less";
import { resourceCategory } from "../../../../api/index"; import { resourceCategory } from "../../../../api/index";
@@ -21,12 +21,14 @@ export const ResourceCategoryUpdate: React.FC<PropInterface> = ({
onCancel, onCancel,
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [init, setInit] = useState(true);
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
const [categories, setCategories] = useState<any>([]); const [categories, setCategories] = useState<any>([]);
const [parent_id, setParentId] = useState<number>(0); const [parent_id, setParentId] = useState<number>(0);
const [sort, setSort] = useState<number>(0); const [sort, setSort] = useState<number>(0);
useEffect(() => { useEffect(() => {
setInit(true);
if (open) { if (open) {
getParams(); getParams();
} }
@@ -64,6 +66,7 @@ export const ResourceCategoryUpdate: React.FC<PropInterface> = ({
}); });
setParentId(data.parent_id); setParentId(data.parent_id);
setSort(data.sort); setSort(data.sort);
setInit(false);
}); });
}; };
@@ -127,57 +130,67 @@ export const ResourceCategoryUpdate: React.FC<PropInterface> = ({
return ( return (
<> <>
<Modal {open ? (
title="编辑分类" <Modal
centered title="编辑分类"
forceRender centered
open={open} forceRender
width={416} open={true}
onOk={() => form.submit()} width={416}
onCancel={() => onCancel()} onOk={() => form.submit()}
maskClosable={false} onCancel={() => onCancel()}
> maskClosable={false}
<div className="float-left mt-24"> >
<Form {init && (
form={form} <div className="float-left text-center mt-30">
name="basic" <Spin></Spin>
labelCol={{ span: 8 }} </div>
wrapperCol={{ span: 16 }} )}
initialValues={{ remember: true }} <div
onFinish={onFinish} className="float-left mt-24"
onFinishFailed={onFinishFailed} style={{ display: init ? "none" : "block" }}
autoComplete="off"
> >
<Form.Item <Form
label="所属上级" form={form}
name="parent_id" name="basic"
rules={[{ required: true, message: "请选择所属上级!" }]} labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
> >
<Cascader <Form.Item
style={{ width: 200 }} label="所属上级"
allowClear name="parent_id"
placeholder="请选择所属上级" rules={[{ required: true, message: "请选择所属上级!" }]}
onChange={handleChange} >
options={categories} <Cascader
changeOnSelect style={{ width: 200 }}
expand-trigger="hover" allowClear
displayRender={displayRender} placeholder="请选择所属上级"
/> onChange={handleChange}
</Form.Item> options={categories}
<Form.Item changeOnSelect
label="分类名称" expand-trigger="hover"
name="name" displayRender={displayRender}
rules={[{ required: true, message: "请输入分类名称!" }]} />
> </Form.Item>
<Input <Form.Item
style={{ width: 200 }} label="分类名称"
allowClear name="name"
placeholder="请输入分类名称" rules={[{ required: true, message: "请输入分类名称!" }]}
/> >
</Form.Item> <Input
</Form> style={{ width: 200 }}
</div> allowClear
</Modal> placeholder="请输入分类名称"
/>
</Form.Item>
</Form>
</div>
</Modal>
) : null}
</> </>
); );
}; };

View File

@@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Modal, Form, Input, message, TreeSelect } from "antd"; import { Modal, Form, Input, message, TreeSelect, Spin } from "antd";
import { resource, resourceCategory } from "../../../../../api/index"; import { resource, resourceCategory } from "../../../../../api/index";
interface PropInterface { interface PropInterface {
@@ -17,9 +17,11 @@ export const VideosUpdateDialog: React.FC<PropInterface> = ({
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
const [init, setInit] = useState(true);
const [categories, setCategories] = useState<any>([]); const [categories, setCategories] = useState<any>([]);
useEffect(() => { useEffect(() => {
setInit(true);
if (id === 0) { if (id === 0) {
return; return;
} }
@@ -27,7 +29,7 @@ export const VideosUpdateDialog: React.FC<PropInterface> = ({
getCategory(); getCategory();
getDetail(); getDetail();
} }
}, [id, open]); }, [form, id, open]);
const getCategory = () => { const getCategory = () => {
resourceCategory.resourceCategoryList().then((res: any) => { resourceCategory.resourceCategoryList().then((res: any) => {
@@ -46,6 +48,7 @@ export const VideosUpdateDialog: React.FC<PropInterface> = ({
name: data.name, name: data.name,
category_id: res.data.category_ids, category_id: res.data.category_ids,
}); });
setInit(false);
}); });
}; };
@@ -89,55 +92,65 @@ export const VideosUpdateDialog: React.FC<PropInterface> = ({
return ( return (
<> <>
<Modal {open ? (
title="编辑视频" <Modal
centered title="编辑视频"
forceRender centered
open={open} forceRender
width={416} open={true}
onOk={() => form.submit()} width={416}
onCancel={() => onCancel()} onOk={() => form.submit()}
maskClosable={false} onCancel={() => onCancel()}
> maskClosable={false}
<div className="float-left mt-24"> >
<Form {init && (
form={form} <div className="float-left text-center mt-30">
name="videos-update" <Spin></Spin>
labelCol={{ span: 8 }} </div>
wrapperCol={{ span: 16 }} )}
initialValues={{ remember: true }} <div
onFinish={onFinish} className="float-left mt-24"
onFinishFailed={onFinishFailed} style={{ display: init ? "none" : "block" }}
autoComplete="off"
> >
<Form.Item <Form
label="视频分类" form={form}
name="category_id" name="videos-update"
rules={[{ required: true, message: "请选择视频分类!" }]} labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
> >
<TreeSelect <Form.Item
showCheckedStrategy={TreeSelect.SHOW_ALL} label="视频分类"
allowClear name="category_id"
style={{ width: 200 }} rules={[{ required: true, message: "请选择视频分类!" }]}
treeData={categories} >
placeholder="视频分类" <TreeSelect
treeDefaultExpandAll showCheckedStrategy={TreeSelect.SHOW_ALL}
/> allowClear
</Form.Item> style={{ width: 200 }}
<Form.Item treeData={categories}
label="视频名称" placeholder="视频分类"
name="name" treeDefaultExpandAll
rules={[{ required: true, message: "请输入视频名称!" }]} />
> </Form.Item>
<Input <Form.Item
allowClear label="视频名称"
style={{ width: 200 }} name="name"
placeholder="请输入视频名称" rules={[{ required: true, message: "请输入视频名称!" }]}
/> >
</Form.Item> <Input
</Form> allowClear
</div> style={{ width: 200 }}
</Modal> placeholder="请输入视频名称"
/>
</Form.Item>
</Form>
</div>
</Modal>
) : null}
</> </>
); );
}; };

View File

@@ -85,86 +85,88 @@ export const SystemAdministratorCreate: React.FC<PropInterface> = ({
return ( return (
<> <>
<Modal {open ? (
title="添加管理员" <Modal
centered title="添加管理员"
forceRender centered
open={open} forceRender
width={416} open={true}
onOk={() => form.submit()} width={416}
onCancel={() => onCancel()} onOk={() => form.submit()}
maskClosable={false} onCancel={() => onCancel()}
> maskClosable={false}
<div className="float-left mt-24"> >
<Form <div className="float-left mt-24">
form={form} <Form
name="basic" form={form}
labelCol={{ span: 8 }} name="basic"
wrapperCol={{ span: 16 }} labelCol={{ span: 8 }}
initialValues={{ remember: true }} wrapperCol={{ span: 16 }}
onFinish={onFinish} initialValues={{ remember: true }}
onFinishFailed={onFinishFailed} onFinish={onFinish}
autoComplete="off" onFinishFailed={onFinishFailed}
> autoComplete="off"
<Form.Item
label="选择角色"
name="roleIds"
rules={[{ required: true, message: "请选择角色!" }]}
> >
<Select <Form.Item
style={{ width: 200 }} label="选择角色"
mode="multiple" name="roleIds"
allowClear rules={[{ required: true, message: "请选择角色!" }]}
placeholder="请选择角色" >
onChange={handleChange} <Select
options={roles} style={{ width: 200 }}
/> mode="multiple"
</Form.Item> allowClear
<Form.Item placeholder="请选择角色"
label="管理员姓名" onChange={handleChange}
name="name" options={roles}
rules={[{ required: true, message: "请输入管理员姓名!" }]} />
> </Form.Item>
<Input <Form.Item
allowClear label="管理员姓名"
style={{ width: 200 }} name="name"
placeholder="请输入管理员姓名" rules={[{ required: true, message: "请输入管理员姓名!" }]}
/> >
</Form.Item> <Input
<Form.Item allowClear
label="邮箱" style={{ width: 200 }}
name="email" placeholder="请输入管理员姓名"
rules={[{ required: true, message: "请输入学员邮箱!" }]} />
> </Form.Item>
<Input <Form.Item
allowClear label="邮箱"
style={{ width: 200 }} name="email"
placeholder="请输入学员邮箱" rules={[{ required: true, message: "请输入学员邮箱!" }]}
/> >
</Form.Item> <Input
<Form.Item allowClear
label="密码" style={{ width: 200 }}
name="password" placeholder="请输入学员邮箱"
rules={[{ required: true, message: "请输入登录密码!" }]} />
> </Form.Item>
<Input.Password <Form.Item
autoComplete="new-password" label="密码"
allowClear name="password"
style={{ width: 200 }} rules={[{ required: true, message: "请输入登录密码!" }]}
placeholder="请输入登录密码" >
/> <Input.Password
</Form.Item> autoComplete="new-password"
allowClear
style={{ width: 200 }}
placeholder="请输入登录密码"
/>
</Form.Item>
<Form.Item <Form.Item
label="禁止登录" label="禁止登录"
name="is_ban_login" name="is_ban_login"
valuePropName="checked" valuePropName="checked"
> >
<Switch onChange={onChange} /> <Switch onChange={onChange} />
</Form.Item> </Form.Item>
</Form> </Form>
</div> </div>
</Modal> </Modal>
) : null}
</> </>
); );
}; };

View File

@@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Modal, Form, Input, Select, Switch, message } from "antd"; import { Modal, Form, Input, Select, Switch, message, Spin } from "antd";
import styles from "./update.module.less"; import styles from "./update.module.less";
import { adminUser } from "../../../../api/index"; import { adminUser } from "../../../../api/index";
@@ -17,6 +17,7 @@ export const SystemAdministratorUpdate: React.FC<PropInterface> = ({
onCancel, onCancel,
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [init, setInit] = useState(true);
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
const [roles, setRoles] = useState<any>([]); const [roles, setRoles] = useState<any>([]);
@@ -27,6 +28,7 @@ export const SystemAdministratorUpdate: React.FC<PropInterface> = ({
}, [refresh, open]); }, [refresh, open]);
useEffect(() => { useEffect(() => {
setInit(true);
if (id === 0) { if (id === 0) {
return; return;
} }
@@ -58,6 +60,7 @@ export const SystemAdministratorUpdate: React.FC<PropInterface> = ({
is_ban_login: user.is_ban_login, is_ban_login: user.is_ban_login,
roleIds: res.data.role_ids, roleIds: res.data.role_ids,
}); });
setInit(false);
}); });
}; };
@@ -93,81 +96,91 @@ export const SystemAdministratorUpdate: React.FC<PropInterface> = ({
return ( return (
<> <>
<Modal {open ? (
title="编辑管理人员" <Modal
centered title="编辑管理人员"
forceRender centered
open={open} forceRender
width={416} open={true}
onOk={() => form.submit()} width={416}
onCancel={() => onCancel()} onOk={() => form.submit()}
maskClosable={false} onCancel={() => onCancel()}
> maskClosable={false}
<div className="float-left mt-24"> >
<Form {init && (
form={form} <div className="float-left text-center mt-30">
name="basic" <Spin></Spin>
labelCol={{ span: 8 }} </div>
wrapperCol={{ span: 16 }} )}
initialValues={{ remember: true }} <div
onFinish={onFinish} className="float-left mt-24"
onFinishFailed={onFinishFailed} style={{ display: init ? "none" : "block" }}
autoComplete="off"
> >
<Form.Item <Form
label="选择角色" form={form}
name="roleIds" name="basic"
rules={[{ required: true, message: "请选择角色!" }]} labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
> >
<Select <Form.Item
style={{ width: 200 }} label="选择角色"
mode="multiple" name="roleIds"
allowClear rules={[{ required: true, message: "请选择角色!" }]}
placeholder="请选择角色" >
onChange={handleChange} <Select
options={roles} style={{ width: 200 }}
/> mode="multiple"
</Form.Item> allowClear
<Form.Item placeholder="请选择角色"
label="管理员姓名" onChange={handleChange}
name="name" options={roles}
rules={[{ required: true, message: "请输入管理员姓名!" }]} />
> </Form.Item>
<Input <Form.Item
allowClear label="管理员姓名"
style={{ width: 200 }} name="name"
placeholder="请输入管理员姓名" rules={[{ required: true, message: "请输入管理员姓名!" }]}
/> >
</Form.Item> <Input
<Form.Item allowClear
label="邮箱" style={{ width: 200 }}
name="email" placeholder="请输入管理员姓名"
rules={[{ required: true, message: "请输入学员邮箱!" }]} />
> </Form.Item>
<Input <Form.Item
allowClear label="邮箱"
style={{ width: 200 }} name="email"
placeholder="请输入学员邮箱" rules={[{ required: true, message: "请输入学员邮箱!" }]}
/> >
</Form.Item> <Input
<Form.Item label="密码" name="password"> allowClear
<Input.Password style={{ width: 200 }}
autoComplete="new-password" placeholder="请输入学员邮箱"
style={{ width: 200 }} />
allowClear </Form.Item>
placeholder="请输入登录密码" <Form.Item label="密码" name="password">
/> <Input.Password
</Form.Item> autoComplete="new-password"
<Form.Item style={{ width: 200 }}
label="禁止登录" allowClear
name="is_ban_login" placeholder="请输入登录密码"
valuePropName="checked" />
> </Form.Item>
<Switch onChange={onChange} /> <Form.Item
</Form.Item> label="禁止登录"
</Form> name="is_ban_login"
</div> valuePropName="checked"
</Modal> >
<Switch onChange={onChange} />
</Form.Item>
</Form>
</div>
</Modal>
) : null}
</> </>
); );
}; };

View File

@@ -25,33 +25,35 @@ export const AdminLogDetailDialog: React.FC<PropInterface> = ({
return ( return (
<> <>
<Modal {open ? (
title="日志详情" <Modal
centered title="日志详情"
forceRender centered
open={open} forceRender
width={416} open={true}
onOk={() => onCancel()} width={416}
onCancel={() => onCancel()} onOk={() => onCancel()}
footer={null} onCancel={() => onCancel()}
maskClosable={false} footer={null}
> maskClosable={false}
<div className="mt-24"> >
<Form <div className="mt-24">
form={form} <Form
name="adminlog-detail" form={form}
labelCol={{ span: 5 }} name="adminlog-detail"
wrapperCol={{ span: 19 }} labelCol={{ span: 5 }}
initialValues={{ remember: true }} wrapperCol={{ span: 19 }}
onFinish={onFinish} initialValues={{ remember: true }}
onFinishFailed={onFinishFailed} onFinish={onFinish}
autoComplete="off" onFinishFailed={onFinishFailed}
> autoComplete="off"
<Form.Item label="Param">{param}</Form.Item> >
<Form.Item label="Result">{result}</Form.Item> <Form.Item label="Param">{param}</Form.Item>
</Form> <Form.Item label="Result">{result}</Form.Item>
</div> </Form>
</Modal> </div>
</Modal>
) : null}
</> </>
); );
}; };

View File

@@ -151,68 +151,70 @@ export const SystemAdminrolesCreate: React.FC<PropInterface> = ({
return ( return (
<> <>
<Drawer {open ? (
title="新建角色" <Drawer
onClose={onCancel} title="新建角色"
maskClosable={false} onClose={onCancel}
open={open} maskClosable={false}
footer={ open={true}
<Space className="j-r-flex"> footer={
<Button onClick={() => onCancel()}> </Button> <Space className="j-r-flex">
<Button onClick={() => form.submit()} type="primary"> <Button onClick={() => onCancel()}> </Button>
<Button onClick={() => form.submit()} type="primary">
</Button>
</Space> </Button>
} </Space>
width={634} }
> width={634}
<div className="float-left mt-24"> >
<Form <div className="float-left mt-24">
form={form} <Form
name="adminroles-create" form={form}
labelCol={{ span: 5 }} name="adminroles-create"
wrapperCol={{ span: 19 }} labelCol={{ span: 5 }}
initialValues={{ remember: true }} wrapperCol={{ span: 19 }}
onFinish={onFinish} initialValues={{ remember: true }}
onFinishFailed={onFinishFailed} onFinish={onFinish}
autoComplete="off" onFinishFailed={onFinishFailed}
> autoComplete="off"
<Form.Item
label="角色名称"
name="name"
rules={[{ required: true, message: "请输入角色名称!" }]}
> >
<Input <Form.Item
style={{ width: 424 }} label="角色名称"
placeholder="请在此处输入角色名称" name="name"
allowClear rules={[{ required: true, message: "请输入角色名称!" }]}
/> >
</Form.Item> <Input
<Form.Item label="操作权限" name="action_ids"> style={{ width: 424 }}
<TreeSelect placeholder="请在此处输入角色名称"
listHeight={600} allowClear
style={{ width: 424 }} />
treeCheckable={true} </Form.Item>
placeholder="请选择权限" <Form.Item label="操作权限" name="action_ids">
multiple <TreeSelect
allowClear listHeight={600}
treeData={actions} style={{ width: 424 }}
/> treeCheckable={true}
</Form.Item> placeholder="请选择权限"
<Form.Item label="数据权限" name="permission_ids"> multiple
<TreeSelect allowClear
listHeight={600} treeData={actions}
style={{ width: 424 }} />
treeCheckable={true} </Form.Item>
placeholder="请选择权限" <Form.Item label="数据权限" name="permission_ids">
multiple <TreeSelect
allowClear listHeight={600}
treeData={permissions} style={{ width: 424 }}
/> treeCheckable={true}
</Form.Item> placeholder="请选择权限"
</Form> multiple
</div> allowClear
</Drawer> treeData={permissions}
/>
</Form.Item>
</Form>
</div>
</Drawer>
) : null}
</> </>
); );
}; };

View File

@@ -1,5 +1,14 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Drawer, TreeSelect, Space, Button, Form, Input, message } from "antd"; import {
Drawer,
TreeSelect,
Space,
Button,
Form,
Input,
message,
Spin,
} from "antd";
import styles from "./update.module.less"; import styles from "./update.module.less";
import { adminRole } from "../../../../api/index"; import { adminRole } from "../../../../api/index";
@@ -21,6 +30,7 @@ export const SystemAdminrolesUpdate: React.FC<PropInterface> = ({
onCancel, onCancel,
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [init, setInit] = useState(true);
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
const [permissions, setPermissions] = useState<any>([]); const [permissions, setPermissions] = useState<any>([]);
const [actions, setActions] = useState<any>([]); const [actions, setActions] = useState<any>([]);
@@ -32,6 +42,7 @@ export const SystemAdminrolesUpdate: React.FC<PropInterface> = ({
}, [open]); }, [open]);
useEffect(() => { useEffect(() => {
setInit(true);
if (id === undefined) { if (id === undefined) {
return; return;
} }
@@ -136,6 +147,7 @@ export const SystemAdminrolesUpdate: React.FC<PropInterface> = ({
permission_ids: res.data.perm_data, permission_ids: res.data.perm_data,
action_ids: res.data.perm_action, action_ids: res.data.perm_action,
}); });
setInit(false);
}); });
}; };
@@ -165,68 +177,78 @@ export const SystemAdminrolesUpdate: React.FC<PropInterface> = ({
return ( return (
<> <>
<Drawer {open ? (
title="编辑角色权限" <Drawer
onClose={onCancel} title="编辑角色权限"
maskClosable={false} onClose={onCancel}
open={open} maskClosable={false}
footer={ open={true}
<Space className="j-r-flex"> footer={
<Button onClick={() => onCancel()}> </Button> <Space className="j-r-flex">
<Button onClick={() => form.submit()} type="primary"> <Button onClick={() => onCancel()}> </Button>
<Button onClick={() => form.submit()} type="primary">
</Button>
</Space> </Button>
} </Space>
width={634} }
> width={634}
<div className="float-left mt-24"> >
<Form {init && (
form={form} <div className="float-left text-center mt-30">
name="adminroles-update" <Spin></Spin>
labelCol={{ span: 5 }} </div>
wrapperCol={{ span: 19 }} )}
initialValues={{ remember: true }} <div
onFinish={onFinish} className="float-left mt-24"
onFinishFailed={onFinishFailed} style={{ display: init ? "none" : "block" }}
autoComplete="off"
> >
<Form.Item <Form
label="角色名" form={form}
name="name" name="adminroles-update"
rules={[{ required: true, message: "请输入角色名!" }]} labelCol={{ span: 5 }}
wrapperCol={{ span: 19 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
> >
<Input <Form.Item
style={{ width: 424 }} label="角色名"
allowClear name="name"
placeholder="请输入角色名" rules={[{ required: true, message: "请输入角色名!" }]}
/> >
</Form.Item> <Input
<Form.Item label="操作权限" name="action_ids"> style={{ width: 424 }}
<TreeSelect allowClear
style={{ width: 424 }} placeholder="请输入角色名"
listHeight={600} />
treeCheckable={true} </Form.Item>
placeholder="请选择权限" <Form.Item label="操作权限" name="action_ids">
multiple <TreeSelect
allowClear style={{ width: 424 }}
treeData={actions} listHeight={600}
/> treeCheckable={true}
</Form.Item> placeholder="请选择权限"
<Form.Item label="数据权限" name="permission_ids"> multiple
<TreeSelect allowClear
style={{ width: 424 }} treeData={actions}
listHeight={600} />
treeCheckable={true} </Form.Item>
placeholder="请选择权限" <Form.Item label="数据权限" name="permission_ids">
multiple <TreeSelect
allowClear style={{ width: 424 }}
treeData={permissions} listHeight={600}
/> treeCheckable={true}
</Form.Item> placeholder="请选择权限"
</Form> multiple
</div> allowClear
</Drawer> treeData={permissions}
/>
</Form.Item>
</Form>
</div>
</Drawer>
) : null}
</> </>
); );
}; };