feat: 课程章节部分接口对接(编辑,查询,删除章节), 合并远程更新并恢复本地 api 修改

This commit is contained in:
QDKF 2025-09-12 15:28:31 +08:00
parent 0c638147f2
commit 21845cb21a
7 changed files with 1546 additions and 449 deletions

View File

@ -5,6 +5,7 @@ export * from './request'
// 导出所有API模块
export { default as AuthApi } from './modules/auth'
export { default as CourseApi } from './modules/course'
export { default as ChapterApi } from './modules/chapter'
export { default as CommentApi } from './modules/comment'
export { default as FavoriteApi } from './modules/favorite'
export { default as OrderApi } from './modules/order'

314
src/api/modules/chapter.ts Normal file
View File

@ -0,0 +1,314 @@
// 课程章节相关API接口
import { ApiRequest } from '../request'
import type {
ApiResponse,
CourseSection,
CourseSectionListResponse,
BackendCourseSection,
} from '../types'
// 章节查询参数类型
export interface ChapterQueryParams {
courseId: string
keyword?: string
page?: number
pageSize?: number
type?: number | null // 章节类型0=视频、1=资料、2=考试、3=作业null=全部
parentId?: string // 父章节ID用于查询子章节
level?: number // 章节层级0=一级章节、1=二级章节
}
/**
* API模块
*/
export class ChapterApi {
/**
*
* @param params
* @returns
*/
static async getChapters(params: ChapterQueryParams): Promise<ApiResponse<CourseSectionListResponse>> {
try {
console.log('🚀 调用课程章节列表API参数:', params)
// 构建查询参数 - courseId作为Path参数其他作为Query参数
const queryParams: any = {}
if (params.keyword) queryParams.keyword = params.keyword
if (params.type !== undefined) queryParams.type = params.type
if (params.parentId) queryParams.parentId = params.parentId
if (params.level !== undefined) queryParams.level = params.level
if (params.page) queryParams.page = params.page
if (params.pageSize) queryParams.pageSize = params.pageSize
console.log('🔍 Path参数 courseId (token):', params.courseId)
console.log('🔍 Query参数:', queryParams)
// 调用后端API - courseId作为Path参数其他作为Query参数
const response = await ApiRequest.get<any>(`/aiol/aiolCourse/${params.courseId}/section`, queryParams)
console.log('🔍 章节列表API响应:', response)
// 处理后端响应格式
let rawData = null;
if (response.data && response.data.success && response.data.result) {
rawData = response.data.result;
console.log('✅ 响应数据来源: result字段');
} else if (response.data && response.data.list) {
rawData = response.data.list;
console.log('✅ 响应数据来源: list字段');
} else if (Array.isArray(response.data)) {
rawData = response.data;
console.log('✅ 响应数据来源: 直接数组');
}
if (rawData && Array.isArray(rawData)) {
console.log('✅ 原始章节数据:', rawData)
console.log('✅ 章节数据数量:', rawData.length)
// 适配数据格式 - 直接使用原始数据,因为字段名已经匹配
const adaptedSections: CourseSection[] = rawData.map((section: any) => ({
id: section.id,
lessonId: section.lessonId, // 直接使用原始字段
outline: section.outline || '', // 直接使用原始字段
name: section.name,
type: section.type, // 直接使用原始字段
parentId: section.parentId || '', // 直接使用原始字段
sort: section.sort, // 直接使用原始字段
level: section.level,
revision: section.revision || 1, // 直接使用原始字段
createdAt: section.createdAt, // 直接使用原始字段
updatedAt: section.updatedAt, // 直接使用原始字段
deletedAt: section.deletedAt,
completed: section.completed || false,
duration: section.duration
}))
console.log('✅ 适配后的章节数据:', adaptedSections)
return {
code: 200,
message: 'success',
data: {
list: adaptedSections,
timestamp: Date.now(),
traceId: ''
}
}
} else {
console.warn('⚠️ API返回的数据结构不正确:', response.data)
return {
code: 500,
message: '数据格式错误',
data: {
list: [],
timestamp: Date.now(),
traceId: ''
}
}
}
} catch (error) {
console.error('❌ 章节API调用失败:', error)
console.error('❌ 错误详情:', {
message: (error as Error).message,
stack: (error as Error).stack,
response: (error as any).response?.data,
status: (error as any).response?.status,
statusText: (error as any).response?.statusText
})
// 重新抛出错误,不使用模拟数据
throw error
}
}
/**
*
* @param params
* @returns
*/
static async searchChapters(params: ChapterQueryParams): Promise<ApiResponse<CourseSectionListResponse>> {
try {
console.log('🔍 搜索课程章节,参数:', params)
// 构建搜索参数 - courseId作为Path参数keyword等作为Query参数
const searchParams: any = {}
if (params.keyword) searchParams.keyword = params.keyword
if (params.type !== undefined) searchParams.type = params.type
if (params.parentId) searchParams.parentId = params.parentId
if (params.level !== undefined) searchParams.level = params.level
if (params.page) searchParams.page = params.page
if (params.pageSize) searchParams.pageSize = params.pageSize
console.log('🔍 Path参数 courseId (token):', params.courseId)
console.log('🔍 Query参数 (包含keyword):', searchParams)
// 调用后端API - courseId作为Path参数keyword等作为Query参数
const response = await ApiRequest.get<any>(`/aiol/aiolCourse/${params.courseId}/section`, searchParams)
console.log('🔍 章节搜索API响应:', response)
// 处理后端响应格式
if (response.data && response.data.success && response.data.result) {
console.log('✅ 搜索响应状态码:', response.data.code)
console.log('✅ 搜索响应消息:', response.data.message)
console.log('✅ 搜索结果数据:', response.data.result)
console.log('✅ 搜索结果数量:', response.data.result.length || 0)
// 适配数据格式 - 使用BackendCourseSection类型
const adaptedSections: CourseSection[] = response.data.result.map((section: BackendCourseSection) => ({
id: section.id,
lessonId: section.courseId, // 使用BackendCourseSection字段
outline: '',
name: section.name,
type: section.type,
parentId: section.parentId || '', // 使用BackendCourseSection字段
sort: section.sortOrder, // 使用BackendCourseSection字段
level: section.level,
revision: 1,
createdAt: section.createTime ? new Date(section.createTime).getTime() : null, // 使用BackendCourseSection字段
updatedAt: section.updateTime ? new Date(section.updateTime).getTime() : null, // 使用BackendCourseSection字段
deletedAt: null,
completed: false,
duration: undefined
}))
console.log('✅ 适配后的搜索结果:', adaptedSections)
return {
code: response.data.code,
message: response.data.message,
data: {
list: adaptedSections,
timestamp: Date.now(),
traceId: response.data.timestamp?.toString() || ''
}
}
} else {
console.warn('⚠️ 搜索API返回的数据结构不正确:', response.data)
return {
code: 500,
message: '搜索数据格式错误',
data: {
list: [],
timestamp: Date.now(),
traceId: ''
}
}
}
} catch (error) {
console.error('❌ 章节搜索API调用失败:', error)
throw error
}
}
/**
*
* @param sectionData
* @returns
*/
static async createChapter(sectionData: any): Promise<ApiResponse<any>> {
try {
console.log('🚀 调用新建章节API数据:', sectionData)
// 包装数据为aiolCourseSectionDTO格式
const requestData = {
aiolCourseSectionDTO: sectionData
}
// 调用后端API - 新建章节
const response = await ApiRequest.post<any>('/aiol/aiolCourseSection/add', requestData)
console.log('🔍 新建章节API响应:', response)
return response
} catch (error) {
console.error('❌ 新建章节失败:', error)
throw error
}
}
/**
*
* @param sectionData
* @returns
*/
static async editChapter(sectionData: any): Promise<ApiResponse<any>> {
try {
console.log('🚀 调用编辑章节API数据:', sectionData)
// 尝试不同的数据格式
const requestData = {
...sectionData,
// 确保所有必要字段都存在
id: sectionData.id,
name: sectionData.name,
courseId: sectionData.courseId,
type: sectionData.type || 0,
sortOrder: sectionData.sortOrder || 10,
parentId: sectionData.parentId || '0',
level: sectionData.level || 1
}
console.log('🔍 发送给服务器的完整请求数据:', JSON.stringify(requestData, null, 2))
console.log('🔍 章节ID:', sectionData.id)
console.log('🔍 章节名称:', sectionData.name)
console.log('🔍 课程ID:', sectionData.courseId)
// 调用后端API - 编辑章节
// 使用原来的edit路径
const response = await ApiRequest.post<any>('/aiol/aiolCourseSection/edit', requestData)
console.log('🔍 编辑章节API响应:', response)
return response
} catch (error) {
console.error('❌ 编辑章节失败:', error)
throw error
}
}
/**
*
* @param sectionId ID
* @returns
*/
static async deleteChapter(sectionId: string): Promise<ApiResponse<any>> {
try {
console.log('🚀 调用删除章节API章节ID:', sectionId)
// 调用后端API - 删除章节
const response = await ApiRequest.delete<any>('/aiol/aiolCourseSection/delete', {
id: sectionId
})
console.log('🔍 删除章节API响应:', response)
return response
} catch (error) {
console.error('❌ 删除章节失败:', error)
throw error
}
}
/**
*
* @param sectionIds ID数组
* @returns
*/
static async deleteChaptersBatch(sectionIds: string[]): Promise<ApiResponse<any>> {
try {
console.log('🚀 调用批量删除章节API章节IDs:', sectionIds)
// 调用后端API - 批量删除章节
const response = await ApiRequest.delete<any>('/aiol/aiolCourseSection/deleteBatch', {
ids: sectionIds.join(',')
})
console.log('🔍 批量删除章节API响应:', response)
return response
} catch (error) {
console.error('❌ 批量删除章节失败:', error)
throw error
}
}
}
export default ChapterApi

View File

@ -462,6 +462,17 @@ export interface BackendCourseSectionListResponse {
timestamp: number
}
// 章节查询参数类型
export interface ChapterQueryParams {
courseId: string
keyword?: string
page?: number
pageSize?: number
type?: number | null // 章节类型0=视频、1=资料、2=考试、3=作业null=全部
parentId?: string // 父章节ID用于查询子章节
level?: number // 章节层级0=一级章节、1=二级章节
}
// 后端讲师数据结构
export interface BackendInstructor {
id: string

View File

@ -415,7 +415,10 @@ const handleOfflineCourse = (course: CourseDisplayItem) => {
id: course.id!,
name: course.name,
description: course.description,
status: 2 // 2=
status: 2, // 2=
pause_exit: '0', //
allow_speed: '0', //
show_subtitle: '0' //
};
await TeachCourseApi.editCourse(updatedData);

View File

@ -188,7 +188,6 @@ import {
import '@wangeditor/editor/dist/css/style.css'
// @ts-ignore
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import TeachCourseApi from '@/api/modules/teachCourse'
const router = useRouter()
const route = useRoute()

File diff suppressed because it is too large Load Diff

View File

@ -10,11 +10,7 @@
<n-button @click="exportChapters">导出</n-button>
<n-button type="error" :disabled="selectedChapters.length === 0" @click="deleteSelected">删除</n-button>
<div class="search-container">
<n-input
v-model:value="searchKeyword"
placeholder="请输入想要搜索的内容"
style="width: 200px;"
>
<n-input v-model:value="searchKeyword" placeholder="请输入想要搜索的内容" style="width: 200px;">
</n-input>
<n-button type="primary" @click="searchChapters">搜索</n-button>
</div>
@ -24,9 +20,9 @@
<!-- 章节列表表格 -->
<div class="table-box">
<n-data-table :columns="columns" :data="paginatedChapters" :row-key="rowKey"
:checked-row-keys="selectedChapters" @update:checked-row-keys="handleCheck" :bordered="false"
:single-line="false" size="medium" class="chapter-data-table" :row-class-name="rowClassName" scroll-x="true" />
<n-data-table :columns="columns" :data="paginatedChapters" :row-key="rowKey" :checked-row-keys="selectedChapters"
@update:checked-row-keys="handleCheck" :bordered="false" :single-line="false" size="medium"
class="chapter-data-table" :row-class-name="rowClassName" scroll-x="true" :loading="loading" />
<!-- 自定义分页器 -->
<div class="custom-pagination">
@ -56,36 +52,35 @@
<span class="page-number nav-button" :class="{ disabled: currentPage === totalPages }"
@click="goToPage('last')">
尾页
</span>
</span>
</div>
</div>
</div>
</div>
<ImportModal
v-model:show="showImportModal"
template-name="custom_template.xlsx"
import-type="custom"
@success="handleImportSuccess"
@template-download="handleTemplateDownload" />
<ImportModal v-model:show="showImportModal" template-name="custom_template.xlsx" import-type="custom"
@success="handleImportSuccess" @template-download="handleTemplateDownload" />
</div>
</template>
<script setup lang="ts">
import { ref, computed, h } from 'vue'
import { NButton, useMessage, NDataTable, NInput, NSpace } from 'naive-ui'
import { ref, computed, h, onMounted } from 'vue'
import { NButton, useMessage, NDataTable, NInput, NSpace, useDialog } from 'naive-ui'
import type { DataTableColumns } from 'naive-ui'
import { useRouter, useRoute } from 'vue-router'
import ImportModal from '@/components/common/ImportModal.vue'
import { ChapterApi } from '@/api'
import type { ChapterQueryParams, CourseSection } from '@/api/types'
import { useUserStore } from '@/stores/user'
const router = useRouter()
const route = useRoute()
const userStore = useUserStore()
const message = useMessage()
//
interface Chapter {
id: number
id: string
name: string
type: string
sort: string | number
@ -93,157 +88,155 @@ interface Chapter {
isParent: boolean
children?: Chapter[]
expanded?: boolean
level?: number
parentId?: string
}
const showImportModal = ref(false)
//
const loading = ref(false)
const error = ref('')
// IDcourseId
const courseId = computed(() => userStore.user?.id?.toString() || '')
const handleImportSuccess = () => {
message.success('章节导入成功')
//
loadChapters()
}
const handleTemplateDownload = () => {
message.success('模板下载成功')
}
//
const searchKeyword = ref('')
//
const selectedChapters = ref<number[]>([])
const selectedChapters = ref<string[]>([])
//
const chapterList = ref<Chapter[]>([
{
id: 1,
name: '第一章 课前准备',
type: '-',
sort: '-',
createTime: '2025.07.25 09:20',
isParent: true,
expanded: false,
children: [
{
id: 2,
name: '开课彩蛋:新开始新征程',
type: '视频',
sort: 1,
createTime: '2025.07.25 09:20',
isParent: false
},
{
id: 3,
name: '课件准备PPT',
type: '课件',
sort: 2,
createTime: '2025.07.25 09:20',
isParent: false
},
{
id: 4,
name: '第一节 课程定位与目标',
type: '视频',
sort: 3,
createTime: '2025.07.25 09:20',
isParent: false
},
{
id: 5,
name: '第二节 教学安排及学习建议',
type: '作业',
sort: 4,
createTime: '2025.07.25 09:20',
isParent: false
},
{
id: 6,
name: '第三节 教学安排及学习建议',
type: '考试',
sort: 5,
createTime: '2025.07.25 09:20',
isParent: false
const chapterList = ref<Chapter[]>([])
//
const originalChapterList = ref<Chapter[]>([])
//
const loadChapters = async () => {
if (!courseId.value) {
message.error('用户未登录,无法获取章节数据')
return
}
try {
loading.value = true
error.value = ''
const params: ChapterQueryParams = {
courseId: courseId.value,
page: 1,
pageSize: 1000 //
}
const response = await ChapterApi.getChapters(params)
console.log('🔍 完整API响应:', response)
console.log('🔍 response.data类型:', typeof response.data)
console.log('🔍 response.data是否为数组:', Array.isArray(response.data))
console.log('🔍 response.data内容:', response.data)
if (response.code === 200 && response.data) {
// response.datalist
if (response.data.list && Array.isArray(response.data.list)) {
// API
const chapters = convertApiDataToChapter(response.data.list)
chapterList.value = chapters
originalChapterList.value = chapters
message.success('章节加载成功')
} else {
console.error('❌ response.data.list不是数组:', response.data)
throw new Error('API返回的数据格式不正确')
}
]
},
{
id: 7,
name: '第二章 课前准备',
type: '-',
sort: '-',
createTime: '2025.07.25 09:20',
isParent: true,
expanded: false,
children: [
{
id: 8,
name: '第一节 新开始新征程',
type: '视频',
sort: 1,
createTime: '2025.07.25 09:20',
isParent: false
},
{
id: 9,
name: '第二节 教学安排及学习建议',
type: '课件',
sort: 2,
createTime: '2025.07.25 09:20',
isParent: false
}
]
},
{
id: 10,
name: '第三章 课前准备',
type: '-',
sort: '-',
createTime: '2025.07.25 09:20',
isParent: true,
expanded: false,
children: [
{
id: 12,
name: '第一节 新开始新征程',
type: '视频',
sort: 1,
createTime: '2025.07.25 09:20',
isParent: false
},
{
id: 13,
name: '第二节 教学安排及学习建议',
type: '课件',
sort: 2,
createTime: '2025.07.25 09:20',
isParent: false
}
]
},
{
id: 11,
name: '第四章 课前准备',
type: '-',
sort: '-',
createTime: '2025.07.25 09:20',
isParent: true,
} else {
throw new Error(response.message || '获取章节失败')
}
} catch (err: any) {
console.error('加载章节失败:', err)
error.value = err.message || '加载章节失败'
message.error(error.value)
// API使
chapterList.value = []
originalChapterList.value = []
} finally {
loading.value = false
}
}
// API
const convertApiDataToChapter = (apiData: any[]): Chapter[] => {
console.log('🔍 convertApiDataToChapter 输入数据:', apiData)
console.log('🔍 输入数据类型:', typeof apiData)
console.log('🔍 输入数据是否为数组:', Array.isArray(apiData))
if (!Array.isArray(apiData)) {
console.error('❌ apiData不是数组:', apiData)
return []
}
// sort
const sortedData = [...apiData].sort((a, b) => (a.sort || 0) - (b.sort || 0))
return sortedData.map(section => ({
id: section.id,
name: section.name,
type: mapChapterType(section.type),
sort: section.sort,
createTime: section.createdAt ? new Date(section.createdAt).toLocaleString() : '',
isParent: section.level === 1, // level=1
level: section.level,
parentId: section.parentId,
expanded: false,
children: []
}))
}
// - 0:1:2:3:
const mapChapterType = (type: number | null): string => {
switch (type) {
case 0: return '视频'
case 1: return '资料'
case 2: return '考试'
case 3: return '作业'
default: return '-'
}
])
}
//
const flattenedChapters = computed(() => {
const result: Chapter[] = []
const flatten = (chapters: Chapter[]) => {
chapters.forEach(chapter => {
result.push(chapter)
if (chapter.children && chapter.expanded) {
flatten(chapter.children)
}
})
}
// level=1level=2level=0
const chapters = chapterList.value.filter(item => item.level === 1)
const sections = chapterList.value.filter(item => item.level === 2)
//
chapters.forEach(chapter => {
chapter.children = sections.filter(section => section.parentId === chapter.id)
result.push(chapter)
//
if (chapter.expanded && chapter.children) {
chapter.children.forEach(section => {
result.push(section)
})
}
})
flatten(chapterList.value)
return result
})
@ -302,7 +295,7 @@ const paginatedChapters = computed(() => {
const rowKey = (row: Chapter) => row.id
//
const handleCheck = (rowKeys: number[]) => {
const handleCheck = (rowKeys: string[]) => {
selectedChapters.value = rowKeys
}
@ -351,7 +344,7 @@ const goToPage = (page: string | number) => {
// /
const toggleChapter = (chapter: Chapter) => {
if (chapter.isParent && chapter.children) {
if (chapter.level === 1 && chapter.children) {
chapter.expanded = !chapter.expanded
}
}
@ -367,6 +360,7 @@ const addChapter = () => {
router.push(`/teacher/chapter-editor-teacher/${courseId}`)
}
const importChapters = () => {
showImportModal.value = true
}
@ -375,39 +369,168 @@ const exportChapters = () => {
message.info('导出章节功能')
}
const deleteSelected = () => {
const deleteSelected = async () => {
if (selectedChapters.value.length === 0) return
if (confirm(`确定要删除选中的 ${selectedChapters.value.length} 个章节吗?`)) {
selectedChapters.value.forEach((id: number) => {
const index = chapterList.value.findIndex((c: Chapter) => c.id === id)
if (index > -1) {
chapterList.value.splice(index, 1)
}
try {
if (!userStore.user?.id) {
message.error('用户未登录,无法删除章节')
return
}
//
const confirmed = await new Promise<boolean>((resolve) => {
dialog.warning({
title: '确认批量删除章节',
content: `确定要删除选中的 ${selectedChapters.value.length} 个章节吗?删除后无法恢复。`,
positiveText: '确认删除',
negativeText: '取消',
positiveButtonProps: {
type: 'error'
},
onPositiveClick: () => {
resolve(true)
},
onNegativeClick: () => {
resolve(false)
}
})
})
selectedChapters.value = []
message.success('删除成功')
if (!confirmed) return
// 使API
const response = await ChapterApi.deleteChaptersBatch(selectedChapters.value)
if (response.data && response.data.success) {
message.success(`成功删除 ${selectedChapters.value.length} 个章节`)
//
selectedChapters.value.forEach((id: string) => {
const index = chapterList.value.findIndex((c: Chapter) => c.id === id)
if (index > -1) {
chapterList.value.splice(index, 1)
}
})
selectedChapters.value = []
} else {
message.error('批量删除失败:' + (response.data?.message || '未知错误'))
}
} catch (error: any) {
console.error('❌ 批量删除章节失败:', error)
message.error('批量删除失败:' + (error.message || '网络错误'))
}
}
const searchChapters = () => {
message.info('搜索章节: ' + searchKeyword.value)
currentPage.value = 1
const searchChapters = async () => {
if (!courseId.value) {
message.error('用户未登录,无法搜索章节')
return
}
try {
loading.value = true
error.value = ''
const params: ChapterQueryParams = {
courseId: courseId.value,
keyword: searchKeyword.value,
page: 1,
pageSize: 1000
}
const response = await ChapterApi.searchChapters(params)
if (response.code === 200 && response.data && response.data.list && Array.isArray(response.data.list)) {
// API
const chapters = convertApiDataToChapter(response.data.list)
chapterList.value = chapters
currentPage.value = 1
message.success(`搜索到 ${chapters.length} 个章节`)
} else {
throw new Error(response.message || '搜索章节失败')
}
} catch (err: any) {
console.error('搜索章节失败:', err)
error.value = err.message || '搜索章节失败'
message.error(error.value)
// 使
chapterList.value = []
currentPage.value = 1
} finally {
loading.value = false
}
}
const editChapter = (chapter: Chapter) => {
message.info('编辑章节: ' + chapter.name)
}
const deleteChapter = (chapter: Chapter) => {
if (confirm('确定要删除这个章节吗?')) {
const index = chapterList.value.findIndex((c: Chapter) => c.id === chapter.id)
if (index > -1) {
chapterList.value.splice(index, 1)
message.success('删除成功')
}
console.log('编辑章节:', chapter)
//
const courseId = route.params.id
if (courseId) {
router.push(`/teacher/chapter-editor-teacher/${courseId}`)
} else {
message.error('课程ID不存在')
}
}
// setup dialog
const dialog = useDialog()
const deleteChapter = async (chapter: Chapter) => {
try {
if (!userStore.user?.id) {
message.error('用户未登录,无法删除章节')
return
}
//
const confirmed = await new Promise<boolean>((resolve) => {
dialog.warning({
title: '确认删除章节',
content: `确定要删除章节"${chapter.name}"吗?删除后无法恢复。`,
positiveText: '确认删除',
negativeText: '取消',
positiveButtonProps: {
type: 'error'
},
onPositiveClick: () => {
resolve(true)
},
onNegativeClick: () => {
resolve(false)
}
})
})
if (!confirmed) return
// API
const response = await ChapterApi.deleteChapter(chapter.id.toString())
if (response.data && response.data.success) {
message.success('章节删除成功!')
//
const index = chapterList.value.findIndex((c: Chapter) => c.id === chapter.id)
if (index > -1) {
chapterList.value.splice(index, 1)
}
} else {
message.error('章节删除失败:' + (response.data?.message || '未知错误'))
}
} catch (error: any) {
console.error('❌ 删除章节失败:', error)
message.error('删除章节失败:' + (error.message || '网络错误'))
}
}
//
onMounted(() => {
loadChapters()
})
// - 使 minWidth
const columns: DataTableColumns<Chapter> = [
{
@ -423,17 +546,18 @@ const columns: DataTableColumns<Chapter> = [
tooltip: true
},
render: (row: Chapter) => {
const isChapter = row.level === 1; // level=1
return h('div', {
style: {
display: 'flex',
alignItems: 'center',
gap: '20px',
cursor: row.isParent ? 'pointer' : 'default',
marginLeft: row.isParent ? '0px' : '-3px'
cursor: isChapter ? 'pointer' : 'default',
marginLeft: isChapter ? '0px' : '-3px'
},
onClick: row.isParent ? () => toggleChapter(row) : undefined
onClick: isChapter ? () => toggleChapter(row) : undefined
}, [
row.isParent ? h('i', {
isChapter ? h('i', {
class: 'n-base-icon',
style: {
transition: 'transform 0.2s',
@ -454,10 +578,10 @@ const columns: DataTableColumns<Chapter> = [
]) : null,
h('span', {
style: {
color: row.isParent ? '#062333' : '#666666',
color: isChapter ? '#062333' : '#666666',
fontSize: '14px',
fontWeight: row.isParent ? '500' : 'normal',
marginLeft: row.isParent ? '0' : '24px'
fontWeight: isChapter ? '500' : 'normal',
marginLeft: isChapter ? '0' : '24px'
}
}, row.name)
])
@ -468,7 +592,8 @@ const columns: DataTableColumns<Chapter> = [
key: 'type',
minWidth: 60,
render: (row: Chapter) => {
if (row.type === '-') {
const isChapter = row.level === 1; // level=1
if (isChapter || row.type === '-') {
return h('span', { style: { color: '#BABABA' } }, '-')
}
return h('div', {
@ -489,6 +614,10 @@ const columns: DataTableColumns<Chapter> = [
key: 'sort',
minWidth: 50,
render: (row: Chapter) => {
const isChapter = row.level === 1; // level=1
if (isChapter) {
return h('span', { style: { color: '#BABABA' } }, '-')
}
return h('span', { style: { color: '#062333', fontSize: '12px' } }, row.sort)
}
},