@cqsjjb/course-res-design 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CourseInfo.d.ts +24 -0
- package/CourseInfo.js +97 -0
- package/CourseInfo.less +7 -0
- package/Designable.d.ts +1 -2
- package/Designable.js +74 -0
- package/Preview.d.ts +10 -7
- package/Preview.js +475 -0
- package/Preview.less +154 -0
- package/PreviewVideo.d.ts +4 -3
- package/PreviewVideo.js +180 -0
- package/VideoPlayer.d.ts +2 -3
- package/VideoPlayer.js +74 -0
- package/api/courseLibrary.js +37 -0
- package/api/global.js +21 -0
- package/image/scan-background.png +0 -0
- package/index.d.ts +2 -0
- package/index.js +7 -0
- package/index.less +16 -0
- package/package.json +16 -27
- package/utils/index.js +11 -0
- package/utils/request.js +74 -0
- package/utils/tools.js +36 -0
- package/README.md +0 -322
- package/course-res-design.css +0 -1
- package/index.cjs.js +0 -73
- package/index.esm.d.ts +0 -1
- package/index.esm.js +0 -2954
package/CourseInfo.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { CourseInfo } from './types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* CourseInfo 组件 Props
|
|
6
|
+
*/
|
|
7
|
+
export interface CourseInfoProps {
|
|
8
|
+
/** 课程ID(如果提供,组件将内部获取课程信息) */
|
|
9
|
+
courseId?: string | number;
|
|
10
|
+
/** 课程信息(如果提供了 courseId 则此字段可选) */
|
|
11
|
+
courseInfo?: CourseInfo;
|
|
12
|
+
/** 样式 */
|
|
13
|
+
style?: React.CSSProperties;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 课程信息展示组件
|
|
18
|
+
*
|
|
19
|
+
* @description 用于展示课程的基本信息,包括课程名称、培训项目、课程标签、课程封面、课程介绍等。支持通过 courseId 内部获取数据或外部传入数据。
|
|
20
|
+
*/
|
|
21
|
+
declare class CourseInfo extends React.Component<CourseInfoProps> {}
|
|
22
|
+
|
|
23
|
+
export default CourseInfo;
|
|
24
|
+
|
package/CourseInfo.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Descriptions } from 'antd';
|
|
3
|
+
import './CourseInfo.less';
|
|
4
|
+
import { getLabelName } from './utils/tools';
|
|
5
|
+
import { getCourseInfo } from './api/courseLibrary';
|
|
6
|
+
export default class CourseInfo extends React.Component {
|
|
7
|
+
state = {
|
|
8
|
+
loading: false,
|
|
9
|
+
courseInfo: {}
|
|
10
|
+
};
|
|
11
|
+
componentDidMount() {
|
|
12
|
+
// 如果提供了 courseId,则内部获取数据
|
|
13
|
+
if (this.props.courseId) {
|
|
14
|
+
this.fetchCourseInfo();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
componentDidUpdate(prevProps) {
|
|
18
|
+
// 如果 courseId 变化,重新获取数据
|
|
19
|
+
if (prevProps.courseId !== this.props.courseId && this.props.courseId) {
|
|
20
|
+
this.fetchCourseInfo();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
// 如果没有 courseId 且外部传入的 courseInfo 变化,清空内部 state
|
|
24
|
+
if (!this.props.courseId && prevProps.courseInfo !== this.props.courseInfo && this.state.courseInfo?.id) {
|
|
25
|
+
this.setState({
|
|
26
|
+
courseInfo: {}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 通过 courseId 获取课程信息
|
|
33
|
+
*/
|
|
34
|
+
async fetchCourseInfo() {
|
|
35
|
+
const {
|
|
36
|
+
courseId
|
|
37
|
+
} = this.props;
|
|
38
|
+
if (!courseId) return;
|
|
39
|
+
this.setState({
|
|
40
|
+
loading: true
|
|
41
|
+
});
|
|
42
|
+
try {
|
|
43
|
+
const infoRes = await getCourseInfo({
|
|
44
|
+
id: courseId
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// 处理响应数据(兼容不同的响应格式)
|
|
48
|
+
const courseInfo = infoRes?.data || infoRes || {};
|
|
49
|
+
this.setState({
|
|
50
|
+
courseInfo,
|
|
51
|
+
loading: false
|
|
52
|
+
});
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error('获取课程信息失败:', error);
|
|
55
|
+
this.setState({
|
|
56
|
+
loading: false
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
render() {
|
|
61
|
+
const {
|
|
62
|
+
loading,
|
|
63
|
+
courseInfo: stateCourseInfo
|
|
64
|
+
} = this.state;
|
|
65
|
+
// 如果提供了 courseId,优先使用内部 state 的数据,否则使用 props
|
|
66
|
+
const hasCourseId = !!this.props.courseId;
|
|
67
|
+
const courseInfo = hasCourseId && stateCourseInfo?.id ? stateCourseInfo : this.props.courseInfo || {};
|
|
68
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
69
|
+
style: this.props.style,
|
|
70
|
+
className: "course-info"
|
|
71
|
+
}, /*#__PURE__*/React.createElement(Descriptions, {
|
|
72
|
+
size: "middle",
|
|
73
|
+
title: "\u8BFE\u7A0B\u4FE1\u606F",
|
|
74
|
+
column: 3,
|
|
75
|
+
loading: loading
|
|
76
|
+
}, /*#__PURE__*/React.createElement(Descriptions.Item, {
|
|
77
|
+
label: "\u8BFE\u7A0B\u540D\u79F0"
|
|
78
|
+
}, courseInfo?.courseName || '--'), /*#__PURE__*/React.createElement(Descriptions.Item, {
|
|
79
|
+
label: "\u57F9\u8BAD\u9879\u76EE"
|
|
80
|
+
}, getLabelName(courseInfo?.courseTypeLabel) || '--'), /*#__PURE__*/React.createElement(Descriptions.Item, {
|
|
81
|
+
label: "\u8BFE\u7A0B\u6807\u7B7E"
|
|
82
|
+
}, getLabelName(courseInfo?.courseLabel) || '--'), /*#__PURE__*/React.createElement(Descriptions.Item, {
|
|
83
|
+
label: "\u8BFE\u7A0B\u5C01\u9762"
|
|
84
|
+
}, courseInfo?.courseCover ? /*#__PURE__*/React.createElement("img", {
|
|
85
|
+
src: courseInfo.courseCover,
|
|
86
|
+
alt: "\u8BFE\u7A0B\u5C01\u9762",
|
|
87
|
+
width: 84,
|
|
88
|
+
height: 50
|
|
89
|
+
}) : '--'), /*#__PURE__*/React.createElement(Descriptions.Item, {
|
|
90
|
+
label: "\u8BFE\u7A0B\u4ECB\u7ECD"
|
|
91
|
+
}, courseInfo?.courseDescription ? /*#__PURE__*/React.createElement("div", {
|
|
92
|
+
dangerouslySetInnerHTML: {
|
|
93
|
+
__html: courseInfo.courseDescription
|
|
94
|
+
}
|
|
95
|
+
}) : '--')));
|
|
96
|
+
}
|
|
97
|
+
}
|
package/CourseInfo.less
ADDED
package/Designable.d.ts
CHANGED
package/Designable.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
import { createPortal } from 'react-dom';
|
|
3
|
+
const EVENT_OPEN_COURSE_RES_DESIGN = 'EVENT_OPEN_COURSE_RES_DESIGN';
|
|
4
|
+
const EVENT_CLOSE_COURSE_RES_DESIGN = 'EVENT_CLOSE_COURSE_RES_DESIGN';
|
|
5
|
+
export const Designable = ({
|
|
6
|
+
style,
|
|
7
|
+
host = window.location.origin,
|
|
8
|
+
id,
|
|
9
|
+
extraParams = {},
|
|
10
|
+
onClose,
|
|
11
|
+
src,
|
|
12
|
+
visible = true
|
|
13
|
+
}) => {
|
|
14
|
+
const iframeRef = useRef(null);
|
|
15
|
+
|
|
16
|
+
// 计算 iframe 的 src
|
|
17
|
+
const iframeSrc = src || `${host}/course-res-design/setting`;
|
|
18
|
+
|
|
19
|
+
// 处理 iframe 加载完成
|
|
20
|
+
const handleIframeLoad = () => {
|
|
21
|
+
// iframe 加载完成后发送 postMessage
|
|
22
|
+
if (iframeRef.current?.contentWindow) {
|
|
23
|
+
iframeRef.current.contentWindow.postMessage({
|
|
24
|
+
type: EVENT_OPEN_COURSE_RES_DESIGN,
|
|
25
|
+
id: id || '',
|
|
26
|
+
extraParams: extraParams || {}
|
|
27
|
+
}, new URL(iframeSrc).origin);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// 监听来自 iframe 的关闭消息
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
const handleMessage = event => {
|
|
34
|
+
// 验证消息来源
|
|
35
|
+
const iframeOrigin = new URL(iframeSrc).origin;
|
|
36
|
+
if (event.origin !== iframeOrigin) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (event.data && event.data.type === EVENT_CLOSE_COURSE_RES_DESIGN) {
|
|
40
|
+
const {
|
|
41
|
+
id: returnedId
|
|
42
|
+
} = event.data;
|
|
43
|
+
// 调用 onClose 回调
|
|
44
|
+
if (onClose) {
|
|
45
|
+
onClose({
|
|
46
|
+
id: returnedId || ''
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
window.addEventListener('message', handleMessage);
|
|
52
|
+
return () => {
|
|
53
|
+
window.removeEventListener('message', handleMessage);
|
|
54
|
+
};
|
|
55
|
+
}, [onClose, iframeSrc, id]);
|
|
56
|
+
if (!visible) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
const editorContent = /*#__PURE__*/React.createElement("div", {
|
|
60
|
+
style: style,
|
|
61
|
+
className: "course-res-designable-container"
|
|
62
|
+
}, /*#__PURE__*/React.createElement("iframe", {
|
|
63
|
+
ref: iframeRef,
|
|
64
|
+
src: iframeSrc,
|
|
65
|
+
frameBorder: "0",
|
|
66
|
+
className: "course-res-designable-iframe",
|
|
67
|
+
title: "\u8BFE\u7A0B\u8D44\u6E90\u8BBE\u8BA1\u5668",
|
|
68
|
+
onLoad: handleIframeLoad
|
|
69
|
+
}));
|
|
70
|
+
|
|
71
|
+
// 使用 createPortal 将组件渲染到 body
|
|
72
|
+
return /*#__PURE__*/createPortal(editorContent, document.body);
|
|
73
|
+
};
|
|
74
|
+
export default Designable;
|
package/Preview.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { CourseInfo, ResourceLabel } from './types';
|
|
3
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { CourseInfo, ResourceLabel } from './types';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* 试题选项
|
|
@@ -72,10 +71,14 @@ export interface CourseChapterNode {
|
|
|
72
71
|
* Preview 组件 Props
|
|
73
72
|
*/
|
|
74
73
|
export interface PreviewProps {
|
|
75
|
-
/**
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
|
|
74
|
+
/** 课程ID(如果提供,组件将内部获取课程数据) */
|
|
75
|
+
courseId?: string | number;
|
|
76
|
+
/** 课程章节列表(树形结构,如果提供了 courseId 则此字段可选) */
|
|
77
|
+
courseChapterList?: CourseChapterNode[];
|
|
78
|
+
/** 课程信息(如果提供了 courseId 则此字段可选) */
|
|
79
|
+
courseInfo?: CourseInfo;
|
|
80
|
+
/** 样式 */
|
|
81
|
+
style?: React.CSSProperties;
|
|
79
82
|
/** 是否启用预览扫码功能 */
|
|
80
83
|
enablePreview?: boolean;
|
|
81
84
|
}
|