@cqsjjb/course-res-design 0.1.0-beta.3 → 0.1.0-beta.5
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.js +100 -12
- package/api/courseLibrary.js +7 -1
- package/package.json +1 -1
- package/utils/index.js +9 -9
- package/utils/request.js +76 -76
package/CourseInfo.js
CHANGED
|
@@ -2,11 +2,74 @@ import React from 'react';
|
|
|
2
2
|
import { Descriptions } from 'antd';
|
|
3
3
|
import './CourseInfo.less';
|
|
4
4
|
import { getLabelName } from './utils/tools';
|
|
5
|
-
import { getCourseInfo } from './api/courseLibrary';
|
|
5
|
+
import { getCourseInfo, typePageAction } from './api/courseLibrary';
|
|
6
|
+
|
|
7
|
+
/** 资源渠道 */
|
|
8
|
+
export const COURSE_CHANNEL_ENUM = {
|
|
9
|
+
'01': '自有',
|
|
10
|
+
'02': '购买',
|
|
11
|
+
'03': '其他'
|
|
12
|
+
};
|
|
13
|
+
/** 资源形式 */
|
|
14
|
+
export const COURSE_MODE_ENUM = {
|
|
15
|
+
'01': '高清大屏',
|
|
16
|
+
'02': '慕课',
|
|
17
|
+
'03': '动画',
|
|
18
|
+
'04': 'PPT',
|
|
19
|
+
'05': '音频',
|
|
20
|
+
'06': '录屏',
|
|
21
|
+
'07': '情景剧',
|
|
22
|
+
'08': '实操',
|
|
23
|
+
'15': '微课',
|
|
24
|
+
'16': '微视频'
|
|
25
|
+
};
|
|
26
|
+
/** 内置字段 labelTypeCode -> { label, valueKey, enumMap } */
|
|
27
|
+
const INNER_FIELD_MAP = {
|
|
28
|
+
INDUSTRY: {
|
|
29
|
+
label: '行业',
|
|
30
|
+
valueKey: 'categorizeName'
|
|
31
|
+
},
|
|
32
|
+
JOB_TYPE: {
|
|
33
|
+
label: '工种',
|
|
34
|
+
valueKey: 'jobTypeName'
|
|
35
|
+
},
|
|
36
|
+
YEAR: {
|
|
37
|
+
label: '年份',
|
|
38
|
+
valueKey: 'yearValue'
|
|
39
|
+
},
|
|
40
|
+
REGION: {
|
|
41
|
+
label: '区域',
|
|
42
|
+
valueKey: 'regionName'
|
|
43
|
+
},
|
|
44
|
+
CHANNEL: {
|
|
45
|
+
label: '渠道',
|
|
46
|
+
valueKey: 'courseChannelEnum',
|
|
47
|
+
enumMap: COURSE_CHANNEL_ENUM
|
|
48
|
+
},
|
|
49
|
+
PRODUCER: {
|
|
50
|
+
label: '制作方',
|
|
51
|
+
valueKey: 'lecturerName'
|
|
52
|
+
},
|
|
53
|
+
RESOURCE_TYPE: {
|
|
54
|
+
label: '资源类型',
|
|
55
|
+
valueKey: 'courseModeEnum',
|
|
56
|
+
enumMap: COURSE_MODE_ENUM
|
|
57
|
+
},
|
|
58
|
+
RESOURCE_FORM: {
|
|
59
|
+
label: '资源形式',
|
|
60
|
+
valueKey: 'courseModeEnum',
|
|
61
|
+
enumMap: COURSE_MODE_ENUM
|
|
62
|
+
},
|
|
63
|
+
STAR: {
|
|
64
|
+
label: '星级',
|
|
65
|
+
valueKey: 'star'
|
|
66
|
+
}
|
|
67
|
+
};
|
|
6
68
|
export default class CourseInfo extends React.Component {
|
|
7
69
|
state = {
|
|
8
70
|
loading: false,
|
|
9
|
-
courseInfo: {}
|
|
71
|
+
courseInfo: {},
|
|
72
|
+
industryFields: []
|
|
10
73
|
};
|
|
11
74
|
componentDidMount() {
|
|
12
75
|
// 如果提供了 courseId,则内部获取数据
|
|
@@ -41,6 +104,13 @@ export default class CourseInfo extends React.Component {
|
|
|
41
104
|
loading: true
|
|
42
105
|
});
|
|
43
106
|
try {
|
|
107
|
+
const labelRes = await typePageAction();
|
|
108
|
+
const data = labelRes.data;
|
|
109
|
+
const arr = Array.isArray(data) ? data : [];
|
|
110
|
+
const industryFields = arr.filter(item => item?.classificationType === 'INNER' && item?.useEnum === 'TRUE' && item?.requiredEnum === 'TRUE');
|
|
111
|
+
this.setState({
|
|
112
|
+
industryFields
|
|
113
|
+
});
|
|
44
114
|
const infoRes = await (this.props.getCourseInfoAction ? this.props.getCourseInfoAction() : getCourseInfo({
|
|
45
115
|
id: courseId,
|
|
46
116
|
apiBaseName: apiBaseName
|
|
@@ -58,10 +128,22 @@ export default class CourseInfo extends React.Component {
|
|
|
58
128
|
});
|
|
59
129
|
}
|
|
60
130
|
}
|
|
131
|
+
getInnerFieldDisplay = item => {
|
|
132
|
+
const config = INNER_FIELD_MAP[item.labelTypeCode];
|
|
133
|
+
const label = config?.label ?? item.labelTypeName ?? '-';
|
|
134
|
+
const raw = config?.valueKey ? this.state.courseInfo[config.valueKey] : this.state.courseInfo[item.labelTypeCode];
|
|
135
|
+
const value = config?.enumMap && raw != null ? config.enumMap[raw] : raw;
|
|
136
|
+
return {
|
|
137
|
+
label,
|
|
138
|
+
value: value ?? '-'
|
|
139
|
+
};
|
|
140
|
+
};
|
|
61
141
|
render() {
|
|
62
142
|
const {
|
|
63
143
|
loading,
|
|
64
|
-
courseInfo: stateCourseInfo
|
|
144
|
+
courseInfo: stateCourseInfo,
|
|
145
|
+
industryFields,
|
|
146
|
+
customFields
|
|
65
147
|
} = this.state;
|
|
66
148
|
// 如果提供了 courseId,优先使用内部 state 的数据,否则使用 props
|
|
67
149
|
const hasCourseId = !!this.props.courseId;
|
|
@@ -77,10 +159,6 @@ export default class CourseInfo extends React.Component {
|
|
|
77
159
|
}, /*#__PURE__*/React.createElement(Descriptions.Item, {
|
|
78
160
|
label: "\u8BFE\u7A0B\u540D\u79F0"
|
|
79
161
|
}, courseInfo?.courseName || '--'), /*#__PURE__*/React.createElement(Descriptions.Item, {
|
|
80
|
-
label: "\u7C7B\u76EE"
|
|
81
|
-
}, courseInfo?.categorizeName ? courseInfo.categorizeName : courseInfo?.courseTypeLabel ? getLabelName(courseInfo?.courseTypeLabel) : '--'), courseInfo?.year && /*#__PURE__*/React.createElement(Descriptions.Item, {
|
|
82
|
-
label: "\u5E74\u4EFD"
|
|
83
|
-
}, courseInfo.year), /*#__PURE__*/React.createElement(Descriptions.Item, {
|
|
84
162
|
label: "\u8BFE\u7A0B\u4ECB\u7ECD"
|
|
85
163
|
}, courseInfo?.courseDescription ? /*#__PURE__*/React.createElement("div", {
|
|
86
164
|
dangerouslySetInnerHTML: {
|
|
@@ -93,11 +171,21 @@ export default class CourseInfo extends React.Component {
|
|
|
93
171
|
alt: "\u8BFE\u7A0B\u5C01\u9762",
|
|
94
172
|
width: 84,
|
|
95
173
|
height: 50
|
|
96
|
-
}) : '--'),
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
174
|
+
}) : '--'), industryFields.map((item, idx) => {
|
|
175
|
+
const {
|
|
176
|
+
label,
|
|
177
|
+
value
|
|
178
|
+
} = this.getInnerFieldDisplay(item);
|
|
179
|
+
return /*#__PURE__*/React.createElement(Descriptions.Item, {
|
|
180
|
+
key: item.id ?? idx,
|
|
181
|
+
label: label
|
|
182
|
+
}, value);
|
|
183
|
+
}), JSON.parse(stateCourseInfo.dynamicTags || '[]')?.map((item, idx) => {
|
|
184
|
+
return /*#__PURE__*/React.createElement(Descriptions.Item, {
|
|
185
|
+
key: item.id ?? idx,
|
|
186
|
+
label: item.fieldkey
|
|
187
|
+
}, item.fieldValue);
|
|
188
|
+
}), /*#__PURE__*/React.createElement(Descriptions.Item, {
|
|
101
189
|
label: "\u8BFE\u7A0B\u6807\u7B7E"
|
|
102
190
|
}, getLabelName(courseInfo?.courseLabel) || '--')));
|
|
103
191
|
}
|
package/api/courseLibrary.js
CHANGED
|
@@ -35,4 +35,10 @@ export const getCourseMenu = params => {
|
|
|
35
35
|
*/
|
|
36
36
|
export const getCourseInfo = params => {
|
|
37
37
|
return request.get(`/${getApiBaseName()}/course/${params.id}`);
|
|
38
|
-
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// 查询标签分类管理列表
|
|
41
|
+
export const typePageAction = params =>
|
|
42
|
+
request.get(`/${getApiBaseName()}/typeManage`, {
|
|
43
|
+
params
|
|
44
|
+
});
|
package/package.json
CHANGED
package/utils/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 获取API Host
|
|
3
|
-
* @returns {string} API Host地址,如果VITE_API_HOST为空则返回location.origin
|
|
4
|
-
*/
|
|
5
|
-
export function getApiHost() {
|
|
6
|
-
return process.env.NODE_ENV === 'development' ?
|
|
7
|
-
process.env?.app?.API_HOST || 'https://yjap.cqzxaq.com'
|
|
8
|
-
: window.location.origin;
|
|
9
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 获取API Host
|
|
3
|
+
* @returns {string} API Host地址,如果VITE_API_HOST为空则返回location.origin
|
|
4
|
+
*/
|
|
5
|
+
export function getApiHost() {
|
|
6
|
+
return process.env.NODE_ENV === 'development' ?
|
|
7
|
+
process.env?.app?.API_HOST || 'https://yjap.cqzxaq.com'
|
|
8
|
+
: window.location.origin;
|
|
9
|
+
}
|
package/utils/request.js
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
import { getApiHost } from './index';
|
|
3
|
-
|
|
4
|
-
export const API_BASE_NAME = 'res';
|
|
5
|
-
|
|
6
|
-
// 创建 axios 实例
|
|
7
|
-
const request = axios.create({
|
|
8
|
-
// baseURL: 'http://192.168.3.47:3000',
|
|
9
|
-
// baseURL: 'http://10.43.82.219',
|
|
10
|
-
baseURL: getApiHost(),
|
|
11
|
-
// mock 阶段使用测试服务器
|
|
12
|
-
timeout: 10000 // 请求超时时间
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
// 请求拦截器 - 添加 token
|
|
16
|
-
request.interceptors.request.use(
|
|
17
|
-
config => {
|
|
18
|
-
// 从 sessionStorage 获取 token
|
|
19
|
-
const token = sessionStorage.getItem('token');
|
|
20
|
-
if (token) {
|
|
21
|
-
config.headers.token = token;
|
|
22
|
-
}
|
|
23
|
-
return config;
|
|
24
|
-
},
|
|
25
|
-
error => {
|
|
26
|
-
return Promise.reject(error);
|
|
27
|
-
}
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
// 响应拦截器
|
|
31
|
-
request.interceptors.response.use(
|
|
32
|
-
response => {
|
|
33
|
-
// 直接返回 response.data,因为 axios 默认返回 response.data
|
|
34
|
-
// 如果后端返回格式是 { respCode: '0000', data: {...} },则统一处理
|
|
35
|
-
if (response.data) {
|
|
36
|
-
// 统一处理响应格式,兼容不同的后端响应结构
|
|
37
|
-
const data = response.data;
|
|
38
|
-
// 如果响应中有 respCode,判断是否成功
|
|
39
|
-
if (data.respCode !== undefined) {
|
|
40
|
-
return {
|
|
41
|
-
success: data.respCode === '0000',
|
|
42
|
-
data: data.data || data,
|
|
43
|
-
...data
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
// 如果响应中有 success 字段,直接使用
|
|
47
|
-
if (data.success !== undefined) {
|
|
48
|
-
return {
|
|
49
|
-
success: data.success,
|
|
50
|
-
data: data.data || data,
|
|
51
|
-
...data
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
// 默认返回数据
|
|
55
|
-
return {
|
|
56
|
-
success: true,
|
|
57
|
-
data: data.data || data,
|
|
58
|
-
...data
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
return response;
|
|
62
|
-
},
|
|
63
|
-
error => {
|
|
64
|
-
console.error('请求失败:', error);
|
|
65
|
-
// 处理错误响应
|
|
66
|
-
if (error.response && error.response.data) {
|
|
67
|
-
return Promise.reject({
|
|
68
|
-
success: false,
|
|
69
|
-
message: error.response.data.message || error.message,
|
|
70
|
-
...error.response.data
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
return Promise.reject(error);
|
|
74
|
-
}
|
|
75
|
-
);
|
|
76
|
-
export default request;
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { getApiHost } from './index';
|
|
3
|
+
|
|
4
|
+
export const API_BASE_NAME = 'res';
|
|
5
|
+
|
|
6
|
+
// 创建 axios 实例
|
|
7
|
+
const request = axios.create({
|
|
8
|
+
// baseURL: 'http://192.168.3.47:3000',
|
|
9
|
+
// baseURL: 'http://10.43.82.219',
|
|
10
|
+
baseURL: getApiHost(),
|
|
11
|
+
// mock 阶段使用测试服务器
|
|
12
|
+
timeout: 10000 // 请求超时时间
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
// 请求拦截器 - 添加 token
|
|
16
|
+
request.interceptors.request.use(
|
|
17
|
+
config => {
|
|
18
|
+
// 从 sessionStorage 获取 token
|
|
19
|
+
const token = sessionStorage.getItem('token');
|
|
20
|
+
if (token) {
|
|
21
|
+
config.headers.token = token;
|
|
22
|
+
}
|
|
23
|
+
return config;
|
|
24
|
+
},
|
|
25
|
+
error => {
|
|
26
|
+
return Promise.reject(error);
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
// 响应拦截器
|
|
31
|
+
request.interceptors.response.use(
|
|
32
|
+
response => {
|
|
33
|
+
// 直接返回 response.data,因为 axios 默认返回 response.data
|
|
34
|
+
// 如果后端返回格式是 { respCode: '0000', data: {...} },则统一处理
|
|
35
|
+
if (response.data) {
|
|
36
|
+
// 统一处理响应格式,兼容不同的后端响应结构
|
|
37
|
+
const data = response.data;
|
|
38
|
+
// 如果响应中有 respCode,判断是否成功
|
|
39
|
+
if (data.respCode !== undefined) {
|
|
40
|
+
return {
|
|
41
|
+
success: data.respCode === '0000',
|
|
42
|
+
data: data.data || data,
|
|
43
|
+
...data
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// 如果响应中有 success 字段,直接使用
|
|
47
|
+
if (data.success !== undefined) {
|
|
48
|
+
return {
|
|
49
|
+
success: data.success,
|
|
50
|
+
data: data.data || data,
|
|
51
|
+
...data
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// 默认返回数据
|
|
55
|
+
return {
|
|
56
|
+
success: true,
|
|
57
|
+
data: data.data || data,
|
|
58
|
+
...data
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return response;
|
|
62
|
+
},
|
|
63
|
+
error => {
|
|
64
|
+
console.error('请求失败:', error);
|
|
65
|
+
// 处理错误响应
|
|
66
|
+
if (error.response && error.response.data) {
|
|
67
|
+
return Promise.reject({
|
|
68
|
+
success: false,
|
|
69
|
+
message: error.response.data.message || error.message,
|
|
70
|
+
...error.response.data
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return Promise.reject(error);
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
export default request;
|