章节模块(增删改查 批量删除)+课程订单(删查询单查询批量删)

This commit is contained in:
2025-06-25 13:16:06 +08:00
parent 774f7f97ed
commit 927b200cf2
5 changed files with 1520 additions and 178 deletions

View File

@ -5,7 +5,7 @@
<a-space>
<a-form-item label="课程名称">
<a-input-search
style="width: 300px"
style="width: 200px"
placeholder="请输入课程名称"
enter-button
@search="handleCourseSearch"
@ -13,6 +13,34 @@
class="custom-search"
/>
</a-form-item>
<a-form-item label="课程类别">
<a-select
style="width: 120px"
placeholder="请选择"
v-model:value="searchCourseType"
@change="handleCourseSearch"
>
<a-select-option value="">全部</a-select-option>
<a-select-option value="考公考研">考公考研</a-select-option>
<a-select-option value="自媒体">自媒体</a-select-option>
<a-select-option value="财经">财经</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="上架状态">
<a-select
style="width: 120px"
placeholder="请选择"
v-model:value="searchIsShelves"
@change="handleCourseSearch"
>
<a-select-option value="">全部</a-select-option>
<a-select-option value="true">已上架</a-select-option>
<a-select-option value="false">已下架</a-select-option>
</a-select>
</a-form-item>
<a-button class="custom-button" @click="goAddCourse">新增课程</a-button>
<a-button class="custom-button" @click="reset">重置搜索</a-button>
<a-button
@ -30,7 +58,7 @@
<a-table
:columns="columns"
:data-source="tableData"
:scroll="{ x: 1500, y: 550 }"
:scroll="{ x: 1600, y: 550 }"
:loading="loading"
:pagination="pagination"
:row-selection="rowSelection"
@ -43,20 +71,31 @@
<template v-if="column.key === 'image'">
<a-avatar :src="downLoadImage+record.image" shape="square" :size="64"/>
</template>
<template v-if="column.key === 'originPrice'">
{{record.originPrice }}
{{ record.originPrice }}
</template>
<template v-if="column.key === 'discountPrice'">
{{record.discountPrice}}
{{ record.discountPrice }}
</template>
<template v-if="column.key === 'orderCount'">
{{record.orderCount}}
{{ record.orderCount }}
</template>
<template v-if="column.key === 'firstLevelRate'">
{{record.firstLevelRate }}%
{{ record.firstLevelRate }}%
</template>
<template v-if="column.key === 'secondLevelRate'">
{{record.secondLevelRate }}%
{{ record.secondLevelRate }}%
</template>
<template v-if="column.key === 'isShelves'">
<a-tag :color="record.isShelves ? 'green' : 'red'">
{{ record.isShelves ? '已上架' : '已下架' }}
</a-tag>
</template>
<!-- 操作列 -->
@ -97,18 +136,22 @@ import {downLoadImage} from "../../api/ImageUrl.ts";
import router from "../../router";
const loading = ref(false);
const total = ref(0);
const selectedRowKeys = ref<number[]>([]); // 存储选中的行ID
const searchCourseName = ref(""); // 改为项目名称搜索参数
// 搜索参数
const searchCourseName = ref("");
const searchCourseType = ref("");
const searchIsShelves = ref("");
// 分页查询参数
const searchParams = ref({
current: 1,
pageSize: 10,
sortField: "id",
sortOrder: "ascend",
userRole: null,
name: "",
type:""
type: "",
isShelves: ""
});
// 行选择配置
@ -119,9 +162,8 @@ const rowSelection = ref({
}
});
//用户表
// 课程表格列定义
const columns = [
{
title: '课程ID',
dataIndex: 'id',
@ -129,10 +171,9 @@ const columns = [
key: 'id',
fixed: 'left',
align: 'center',
sorter: true, // 添加排序功能
sortDirections: ['ascend', 'descend'] // 允许升序降序
sorter: true,
sortDirections: ['ascend', 'descend']
},
{
title: '课程图片',
dataIndex: 'image',
@ -162,8 +203,8 @@ const columns = [
width: 55,
key: 'originPrice',
align: 'center',
sorter: true, // 添加排序功能
sortDirections: ['ascend', 'descend'] // 允许升序降序
sorter: true,
sortDirections: ['ascend', 'descend']
},
{
title: '折扣价格',
@ -171,8 +212,8 @@ const columns = [
key: 'discountPrice',
width: 55,
align: 'center',
sorter: true, // 添加排序功能
sortDirections: ['ascend', 'descend'] // 允许升序降序
sorter: true,
sortDirections: ['ascend', 'descend']
},
{
title: '已下单人数',
@ -180,8 +221,8 @@ const columns = [
key: 'orderCount',
width: 55,
align: 'center',
sorter: true, // 添加排序功能
sortDirections: ['ascend', 'descend'] // 允许升序降序
sorter: true,
sortDirections: ['ascend', 'descend']
},
{
title: '一级佣金比例',
@ -189,8 +230,8 @@ const columns = [
key: 'firstLevelRate',
width: 65,
align: 'center',
sorter: true, // 添加排序功能
sortDirections: ['ascend', 'descend'] // 允许升序降序
sorter: true,
sortDirections: ['ascend', 'descend']
},
{
title: '二级佣金比例',
@ -198,8 +239,15 @@ const columns = [
key: 'secondLevelRate',
width: 65,
align: 'center',
sorter: true, // 添加排序功能
sortDirections: ['ascend', 'descend'] // 允许升序降序
sorter: true,
sortDirections: ['ascend', 'descend']
},
{
title: '是否上架',
dataIndex: 'isShelves',
key: 'isShelves',
width: 65,
align: 'center'
},
{
title: '操作',
@ -210,42 +258,30 @@ const columns = [
}
];
interface ProjectRecord {
// 这里根据实际数据结构定义属性
superHostList?: string[];
// 其他属性...
}
// 项目名称搜索方法
// 课程名称搜索方法
const handleCourseSearch = async () => {
// 将搜索参数同步到分页查询参数
searchParams.value.name = searchCourseName.value;
searchParams.value.type = searchCourseType.value;
searchParams.value.isShelves = searchIsShelves.value;
searchParams.value.current = 1; // 重置到第一页
await getCourseList();
};
//用户分页查询
// 课程分页查询
const getCourseList = async () => {
loading.value = true;
try {
const storedToken = localStorage.getItem('token');
if (!storedToken) throw new Error('未找到登录信息');
const res:any = await myAxios.post("/course/page",
{
...searchParams.value,
projectName: searchParams.value.projectName
},
const res: any = await myAxios.post("/course/page", searchParams.value,
{ headers: { Authorization: storedToken } }
);
console.log(res)
if (res.code === 1 && res.data && Array.isArray(res.data.records)) {
tableData.value = res.data.records.map((item: ProjectRecord) => ({
...item,
superUserList: item.superHostList? item.superHostList.join(', ') : '无'
}));
tableData.value = res.data.records;
// 同步总条数到分页组件
total.value = res.data.total;
pagination.value.total = res.data.total; // 新增此行
pagination.value.current = searchParams.value.current; // 同步当前页
pagination.value.total = res.data.total;
} else {
message.error(res.message || '请求失败');
}
@ -258,7 +294,6 @@ const getCourseList = async () => {
};
onMounted(getCourseList);
//分页
// 分页配置
const pagination = ref({
@ -270,49 +305,55 @@ const pagination = ref({
showTotal: (total: number) => `${total}`,
pageSizeOptions: ['10', '20', '50', '100']
});
const handleTableChange = (pag: any, _: any, sorter: any) => {
// 处理排序参数
let sortField = "id"; // 默认排序字段
let sortOrder = "ascend"; // 默认排序方式
if (sorter.field) {
sortField = sorter.field;
sortOrder = sorter.order;
// 处理分页和排序变化
const handleTableChange = (pag: any, _filters: any, sorter: any) => {
searchParams.value.current = pag.current;
searchParams.value.pageSize = pag.pageSize;
// 处理排序
if (sorter && sorter.field) {
// 获取排序字段使用列的key而不是dataIndex
const sortField = sorter.field;
// 获取排序方向ascend/descend
const sortOrder = sorter.order ? sorter.order : '';
// 更新搜索参数中的排序字段和排序方向
searchParams.value.sortField = sortField;
searchParams.value.sortOrder = sortOrder;
} else {
// 如果没有排序信息,重置为默认排序
searchParams.value.sortField = "id";
searchParams.value.sortOrder = "ascend";
}
searchParams.value = {
...searchParams.value,
current: pag.current,
pageSize: pag.pageSize,
sortField: sortField, // 设置排序字段
sortOrder: sortOrder
};
// 同步到分页组件
pagination.value = {
...pagination.value,
current: pag.current,
pageSize: pag.pageSize
};
pagination.value.current = pag.current;
pagination.value.pageSize = pag.pageSize;
getCourseList();
};
// ID查询方法
interface Project {
// 课程接口定义
interface Course {
id: number;
projectName: string;
projectImage: string;
projectSettlementCycle: number;
maxPromoterCount: number;
projectStatus: string;
projectDescription: string;
settlementDesc: string;
// 其他可能存在的属性根据实际情况补充
name: string;
type: string;
detail: string;
promoCodeDesc: string;
image: string;
originPrice: number;
discountPrice: number;
orderCount: number;
firstLevelRate: number;
secondLevelRate: number;
isShelves: boolean;
}
const tableData = ref<Project[]>([]);
const tableData = ref<Course[]>([]);
// 删除项目 - 添加确认弹窗
// 删除课程
const deleteCourse = (id: number) => {
Modal.confirm({
title: '确认删除',
@ -322,15 +363,10 @@ const deleteCourse = (id: number) => {
onOk: async () => {
try {
const storedToken = localStorage.getItem('token');
const res:any = await myAxios.post(
const res: any = await myAxios.post(
"/course/delete",
{ id },
{
headers: {
Authorization: storedToken,
'AfterScript': 'required-script'
}
}
{ headers: { Authorization: storedToken } }
);
if (res.code === 1) {
@ -343,10 +379,7 @@ const deleteCourse = (id: number) => {
console.error('删除失败:', error);
message.error('删除操作失败');
}
},
onCancel() {
// 用户点击取消,不做操作
},
}
});
};
@ -362,12 +395,7 @@ const showDeleteConfirm = () => {
content: `确定要删除选中的 ${selectedRowKeys.value.length} 门课程吗?删除后数据将无法恢复!`,
okText: '确认',
cancelText: '取消',
onOk: async () => {
await deleteBatchCourses();
},
onCancel() {
// 用户点击取消,不做操作
},
onOk: deleteBatchCourses
});
};
@ -378,12 +406,7 @@ const deleteBatchCourses = async () => {
const res: any = await myAxios.post(
"/course/delBatch",
{ ids: selectedRowKeys.value },
{
headers: {
Authorization: storedToken,
'Content-Type': 'application/json'
}
}
{ headers: { Authorization: storedToken } }
);
if (res.code === 1) {
@ -399,97 +422,65 @@ const deleteBatchCourses = async () => {
}
};
// 重置按钮
// 重置搜索条件
const reset = () => {
searchCourseName.value = "";
searchCourseType.value = "";
searchIsShelves.value = "";
selectedRowKeys.value = [];
searchParams.value = {
current: 1,
pageSize: 10,
sortField: "id",
sortOrder: "ascend",
userRole: null,
name: "",
type:""
type: "",
isShelves: ""
};
getCourseList();
};
//去新增项目
const goAddCourse=()=>{
// 跳转到新增课程页面
const goAddCourse = () => {
router.push('/addcourse')
}
const showDetails=(id:string)=>{
// 查看课程详情
const showDetails = (id: string) => {
router.push({
path:'/courseDetail',
query:{
id:String(id)
}
path: '/courseDetail',
query: { id: String(id) }
})
}
const chapterDetails=(id:string)=>{
// 查看章节详情
const chapterDetails = (id: string) => {
router.push({
path:'/chapterDetail',
query:{
id:String(id)
}
path: '/chapterDetail',
query: { id: String(id) }
})
}
</script>
<style scoped>
/* 分割线样式 */
:deep(.ant-divider-vertical) {
border-color: rgba(0, 0, 0, 0.15);
height: 1.2em;
margin: 0 4px;
}
:deep(.ant-descriptions-item-label) {
font-weight: 600;
width: 120px;
}
.info-card :deep(.ant-card-head) {
background: #fafafa;
border-bottom: 1px solid #e8e8e8;
}
/* 角色颜色映射 */
:root {
--role-user: #87d068;
--role-admin: #f50;
--role-boss: #722ed1;
}
/* 原有样式保持不变 */
.search-box {
margin-bottom: 10px;
}
/* 批量删除按钮样式 */
.danger {
background-color: #ff4d4f !important;
border-color: #ff4d4f !important;
}
.danger:hover,
.danger:focus {
background-color: #ff7875 !important;
border-color: #ff7875 !important;
}
/*橙色按钮*/
.custom-button {
background-color: #ffa940;
border-color: #ffa940;
color: #fff;
font-weight: 500;
}
.custom-button:hover,
.custom-button:focus {
background-color: #ffa940;
border-color: #ffa940;
background-color: #fa8c16;
border-color: #fa8c16;
color: #fff;
}
@ -500,7 +491,6 @@ const chapterDetails=(id:string)=>{
color: #fff;
}
/* 危险按钮样式 */
.custom-button.ant-btn-dangerous {
background-color: #ff4d4f;
border-color: #ff4d4f;
@ -512,24 +502,13 @@ const chapterDetails=(id:string)=>{
border-color: #ff7875;
}
/* 保持原有的其他样式不变 */
.search-box {
margin-bottom: 10px;
}
.custom-search :deep(.ant-input-search-button) {
background-color: #ffa940;
border-color: #ffa940;
}
.custom-search :deep(.ant-input-search-button:hover),
.custom-search :deep(.ant-input-search-button:focus) {
background-color: #fa8c16;
border-color: #fa8c16;
}
/* 保持输入框原有样式不变 */
.custom-search :deep(.ant-input) {
border-right-color: #ffa940;
.danger {
background-color: #ff4d4f !important;
border-color: #ff4d4f !important;
}
</style>