提交 4154b335 作者: ZhangLingKun

功能:课程列表

上级 588f2cd4
流水线 #8055 已失败 于阶段
in 33 秒
import { InterFunction, InterListFunction } from '@/api/interface';
// 所有课程分类列表
export type SelectCurriculumClassifyType = InterFunction<
{},
{
classifyDesc: string;
classifyUrl: string;
createTime: string;
id: number;
name: string;
oneCourseId: number;
twoCourseId: number;
updateTime: string;
}[]
>;
// V1.0.1课程视频列表
export type QueryCurriculumInfoListType = InterListFunction<
{
courseAttribute?: number;
curriculumName?: string;
oneCourseId?: number;
twoCourseId?: number;
isHot?: number;
},
{
id: number;
oneCourseId: number;
twoCourseId: number;
curriculumName: string;
curriculumDesc: string;
surfaceUrl: string;
videoUrl: string;
courseAttribute: number;
requireAmout: number;
requireIntegral: number;
isHot: number;
detailContent: string;
createTime: string;
updateTime: string;
}
>;
import {
QueryCurriculumInfoListType,
SelectCurriculumClassifyType,
} from '@/api/interface/course';
import request from '@/api/request';
export class CourseAPI {
// 所有课程分类列表
static selectCurriculumClassify: SelectCurriculumClassifyType = (params) =>
request.get('/release/curriculum/selectCurriculumClassify', { params });
// 课程列表
static getCourseVideoList: QueryCurriculumInfoListType = (data) =>
request.post('/release/curriculum/queryCurriculumInfoList', data);
}
......@@ -12,10 +12,11 @@ const service = axios.create({
service.interceptors.request.use(
(config: any) => {
const token = Cookies.get('SHAREFLY-WEB-TOKEN');
// console.log('config ==========>', config);
// console.log('token ==========>', config.headers);
if (token) {
// eslint-disable-next-line no-param-reassign
config.headers.token = token;
// console.log('config ==========>', config.headers);
}
return config;
},
......@@ -24,6 +25,9 @@ service.interceptors.request.use(
},
);
// 判断是服务端还是客户端
const isServer = typeof window === 'undefined';
service.interceptors.response.use(
(response: AxiosResponse) => {
const { data, status } = response;
......@@ -39,6 +43,11 @@ service.interceptors.response.use(
data.code,
)
) {
if (isServer) {
// 直接阻止后续代码执行
// console.log('出错了 --->', response.config, data);
return Promise.reject(data);
}
message.error(data.message).then();
Cookies.remove('SHAREFLY-WEB-TOKEN');
localStorage.removeItem('persist:SHAREFLY-WEB-STORAGE');
......@@ -52,11 +61,9 @@ service.interceptors.response.use(
if (data instanceof Blob || Base64.isValid(data)) {
return Promise.resolve(data);
}
// 判断是服务端还是客户端
const isServer = typeof window === 'undefined';
if (isServer) {
// 如果是服务端
console.log('出错了 --->', response.config, data);
// console.log('出错了 --->', response.config, data);
return Promise.reject(data);
// eslint-disable-next-line no-alert
// window.confirm(data.message || '啊呀,出错了');
......
......@@ -65,6 +65,7 @@ const BreadcrumbView: React.FC = () => {
},
{ name: '执照培训', path: 'train' },
{ name: '飞手约单', path: 'flyer' },
{ name: '执照培训', path: 'course' },
];
// 转换路由
const getCurrentRouter = () => {
......
import React from 'react';
import styled from 'styled-components';
import { InterListType } from '@/api/interface';
import { QueryCurriculumInfoListType } from '@/api/interface/course';
// 列表类型
type DetailType = InterListType<QueryCurriculumInfoListType>[0];
// 课程类型列表
const courseAttributeList: { label: string; value: number; color: string }[] = [
{ label: '免费', value: 0, color: '#f99a0b' },
{ label: '积分', value: 1, color: '#00AD53' },
{ label: '付费', value: 2, color: '#FF4600' },
];
const CourseListItem: React.FC<{ detail: DetailType }> = ({ detail }) => {
// 获取当前课程属性
const getCourseAttribute = () => {
return courseAttributeList.find((i) => i.value === detail?.courseAttribute);
};
return (
<CourseListItemWrap>
<div className="mb-2 h-32 w-full">
<img
className="h-full w-full object-cover"
src={
detail?.surfaceUrl
? `${detail?.surfaceUrl}?x-oss-process=image/quality,q_25`
: `${detail?.videoUrl}?x-oss-process=video/snapshot,t_1000,m_fast`
}
alt={detail?.curriculumName}
/>
</div>
<div className="course-content w-full px-2">
<div className="content-title flex w-full flex-nowrap">
<div className="title text-ellipsis">{detail?.curriculumName}</div>
<div
className="tag"
style={{ background: getCourseAttribute()?.color }}
>
{getCourseAttribute()?.label}
</div>
</div>
<div className="text-ellipsis text-xs text-gray-400">
{detail?.curriculumDesc}
</div>
{!!detail?.requireAmout && (
<div className="content-price">
<span className="label"></span>
<span className="num">{detail?.requireAmout}</span>
</div>
)}
{!!detail?.requireIntegral && (
<div className="content-price">
<span className="num">{detail?.requireIntegral}</span>
<span className="label">积分</span>
</div>
)}
</div>
<div className="course-footer flex justify-between">
<div className="label">课程供应商</div>
<div className="num">{(detail?.id || 1) * 333}人已学习</div>
</div>
</CourseListItemWrap>
);
};
export default CourseListItem;
// 样式
const CourseListItemWrap = styled.div`
position: relative;
box-sizing: border-box;
width: calc((100% - (0.83rem * 4)) / 5);
height: 14.5rem;
background: #ffffff;
box-shadow: 0 0.17rem 0.86rem 0 rgba(65, 65, 65, 0.08);
border-radius: 0.33rem;
margin: 0 0.83rem 0.83rem 0;
cursor: pointer;
overflow: hidden;
&:nth-child(5n) {
margin-right: 0;
}
.course-content {
.content-title {
margin-bottom: 0.25rem;
.title {
font-weight: bold;
color: #333333;
margin-right: 0.25rem;
}
.tag {
min-width: 2.25rem;
box-sizing: border-box;
font-size: 12px;
background: #f99a0b;
border-radius: 0.1rem;
text-align: center;
color: #ffffff;
padding: 0 0.25rem;
transform: scale(0.8);
}
}
.content-price {
font-weight: 500;
color: #ff3300;
.num {
font-size: 15px;
line-height: 35rpx;
margin-right: 8rpx;
}
.label {
font-size: 12px;
line-height: 28rpx;
font-weight: bold;
}
}
}
.course-footer {
position: absolute;
width: 100%;
bottom: 0.5rem;
left: 0;
box-sizing: border-box;
padding: 0 0.5rem;
color: #aaa;
}
`;
......@@ -48,7 +48,7 @@ const ForumItemView: React.FC<{ detail: DetailType }> = ({ detail }) => {
{getForumMedia(0)?.length
? getForumMedia(0)?.map((i, j) => (
<Image
src={`${i?.url}?x-oss-process=image/quality,q_25`}
src={`${i?.url}?x-oss-process=image/quality,Q_50`}
alt="图片"
key={j}
fallback={
......
......@@ -54,7 +54,7 @@ const HomeProductView = () => {
>
<img
className="item-image"
src={`${i.resourcesList[0].url}?x-oss-process=image/quality,q_25`}
src={`${i.resourcesList[0].url}?x-oss-process=image/quality,Q_50`}
alt={i.tradeName}
/>
<div className="item-title text-ellipsis">{i.tradeName}</div>
......
......@@ -95,7 +95,7 @@ const HeaderView: React.FC<{
dispatch(setAddress(res));
});
}
console.log('当前是否登录 --->', system, token);
// console.log('当前是否登录 --->', system, token);
// 当前是否登录
if (!token) {
dispatch(setSystem({ token: undefined }));
......
import React, { useEffect, useState } from 'react';
import { Empty } from 'antd';
import styled from 'styled-components';
import { InterDataType, InterListType, InterReqType } from '@/api/interface';
import {
QueryCurriculumInfoListType,
SelectCurriculumClassifyType,
} from '@/api/interface/course';
import { CourseAPI } from '@/api/modules/course';
import BreadcrumbView from '@/components/breadcrumb';
import CategorySelectView, { CategoryType } from '@/components/categorySelect';
import CourseListItem from '@/components/courseListItem';
import LayoutView from '@/components/layout';
import ProductListView from '@/components/productList';
// 分类类型
type CategoryListType = Array<
InterDataType<SelectCurriculumClassifyType>[0] & {
children: InterDataType<SelectCurriculumClassifyType> | null;
}
>;
// 列表类型
type ListType = InterListType<QueryCurriculumInfoListType>;
// 请求参数类型
type ReqType = InterReqType<QueryCurriculumInfoListType>;
const CourseView: React.FC<{ categoryList: CategoryListType }> = (props) => {
// 分类列表
const [categoryList, setCategoryList] = useState<CategoryType>([]);
// 转换分类列表
const getCategoryList = () => {
setCategoryList(
props.categoryList?.map((i) => ({
value: i.oneCourseId,
label: i.name,
children: i.children?.map((n) => ({
value: n.twoCourseId,
label: n.name,
})),
})),
);
};
// 分页数据
const [pagination, setPagination] = useState({
pageNo: 1,
pageSize: 18,
totalCount: 0,
});
// 列表数据
const [dataList, setDataList] = useState<ListType>([]);
// 获取课程列表
const getDataList = async (data: ReqType) => {
const res = await CourseAPI.getCourseVideoList({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
...data,
});
if (res && res.code === '200') {
console.log('获取商品列表 --->', res);
const { list, totalCount, pageNo, pageSize } = res.result;
setDataList(list || []);
setPagination({
...pagination,
totalCount,
pageNo,
pageSize,
});
}
};
// 翻页回调
const handlePageChange = async (pageNo: number, pageSize: number) => {
await getDataList({ pageNo, pageSize });
};
// 分类筛选
const handleSelect = async (e: { main?: number; second?: number[] }) => {
if (e.second?.length && e.second?.length > 1) {
await getDataList({
oneCourseId: e?.main,
pageNo: 1,
});
} else {
await getDataList({
oneCourseId: e?.main,
twoCourseId: e?.second?.[0],
pageNo: 1,
});
}
};
// 组件挂载
useEffect(() => {
getCategoryList();
// console.log('组件挂载 --->', props);
}, []);
return (
<LayoutView>
<CourseViewWrap>
{/* 面包屑 */}
<BreadcrumbView />
{/* 类型筛选 */}
<CategorySelectView
list={categoryList}
isMultiple={false}
allText={'全部课程'}
onSelect={handleSelect}
/>
{/* 课程列表 */}
<ProductListView pagination={pagination} onChange={handlePageChange}>
{dataList?.length ? (
dataList?.map((i, j) => <CourseListItem key={j} detail={i} />)
) : (
<div className="list-empty flex-center">
<Empty />
</div>
)}
</ProductListView>
</CourseViewWrap>
</LayoutView>
);
};
export default CourseView;
// 样式
const CourseViewWrap = styled.div`
position: relative;
max-width: 1190px;
box-sizing: border-box;
padding: 2rem 0 0 0;
margin: 0 auto;
`;
import React from 'react';
import { InterDataType } from '@/api/interface';
import { SelectCurriculumClassifyType } from '@/api/interface/course';
import { CourseAPI } from '@/api/modules/course';
import CourseView from '@/pages/course/_view';
import { wrapper } from '@/store';
// 分类类型
type CategoryListType = Array<
InterDataType<SelectCurriculumClassifyType>[0] & {
children: InterDataType<SelectCurriculumClassifyType> | null;
}
>;
// 每次加载页面都会执行
export const getServerSideProps = wrapper.getServerSideProps(
(_store) => async () => {
// 分类数据
let categoryList: CategoryListType = [];
// 获取分类数据
const getCategoryInfo = async () => {
const res = await CourseAPI.selectCurriculumClassify();
if (res && res.code === '200') {
categoryList = res.result
?.filter((i) => !i.twoCourseId)
?.map((i) => {
const children = res.result?.filter(
(k) => k.oneCourseId === i.oneCourseId && k.twoCourseId,
);
return {
...i,
children: children?.length ? children : null,
};
});
}
};
// 依次获取接口数据
await (async () => {
await Promise.all([getCategoryInfo()]);
})();
return { props: { categoryList } };
},
);
const CoursePageView: React.FC<{ categoryList: CategoryListType }> = (
props,
) => <CourseView {...props} />;
export default CoursePageView;
......@@ -51,7 +51,7 @@ const RentView: React.FC<{
...data,
});
if (res && res.code === '200') {
console.log('获取商品列表 --->', res);
// console.log('获取商品列表 --->', res);
const { list, totalCount, pageNo, pageSize } = res.result;
setDataList(list || []);
setPagination({
......
......@@ -45,7 +45,7 @@ const UserSignupView = () => {
);
});
if (!values) return;
message.loading('注册中...', 1000);
message.loading('注册中...', 1);
const res = await CommonAPI.webRegister(values);
if (res && res.code === '200') {
await message.success('注册成功');
......@@ -70,7 +70,7 @@ const UserSignupView = () => {
if (!values) return;
// 禁止再次发送
setIsCanGetCode(false);
message.loading('发送中...', 1000);
message.loading('发送中...', 1);
const res = await CommonAPI.getVerifyCodeAuth({
phoneNum: values.phoneNum,
});
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论