成就等界面接口调整
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -13,89 +13,171 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 标签卡片网格 -->
|
||||
<div v-loading="loading" class="tag-grid">
|
||||
<div
|
||||
v-for="tag in tags"
|
||||
:key="tag.tagID"
|
||||
class="tag-card"
|
||||
<!-- 按类型分类展示 -->
|
||||
<div class="tag-categories" v-loading="loading">
|
||||
<!-- 文章分类标签 -->
|
||||
<div class="tag-category-section">
|
||||
<div class="category-header">
|
||||
<h3 class="category-title">文章分类标签</h3>
|
||||
<span class="category-count">({{ articleTags.length }})</span>
|
||||
</div>
|
||||
<div class="tag-grid">
|
||||
<div
|
||||
v-for="tag in articleTags"
|
||||
:key="tag.tagID"
|
||||
class="tag-card"
|
||||
>
|
||||
<div class="tag-content">
|
||||
<div class="tag-info">
|
||||
<div class="tag-dot" :style="{ background: tag.color }"></div>
|
||||
<span class="tag-name">{{ tag.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tag-actions">
|
||||
<button class="edit-button" @click="editTag(tag)">
|
||||
<img src="@/assets/imgs/edit.svg" alt="编辑" />
|
||||
<span>编辑</span>
|
||||
</button>
|
||||
<button class="delete-button" @click="deleteTag(tag)">
|
||||
<img src="@/assets/imgs/trashbin.svg" alt="删除" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 空状态 -->
|
||||
<div v-if="!loading && articleTags.length === 0" class="empty-state">
|
||||
暂无文章分类标签
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 课程分类标签 -->
|
||||
<div class="tag-category-section">
|
||||
<div class="category-header">
|
||||
<h3 class="category-title">课程分类标签</h3>
|
||||
<span class="category-count">({{ courseTags.length }})</span>
|
||||
</div>
|
||||
<div class="tag-grid">
|
||||
<div
|
||||
v-for="tag in courseTags"
|
||||
:key="tag.tagID"
|
||||
class="tag-card"
|
||||
>
|
||||
<div class="tag-content">
|
||||
<div class="tag-info">
|
||||
<div class="tag-dot" :style="{ background: tag.color }"></div>
|
||||
<span class="tag-name">{{ tag.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tag-actions">
|
||||
<button class="edit-button" @click="editTag(tag)">
|
||||
<img src="@/assets/imgs/edit.svg" alt="编辑" />
|
||||
<span>编辑</span>
|
||||
</button>
|
||||
<button class="delete-button" @click="deleteTag(tag)">
|
||||
<img src="@/assets/imgs/trashbin.svg" alt="删除" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 空状态 -->
|
||||
<div v-if="!loading && courseTags.length === 0" class="empty-state">
|
||||
暂无课程分类标签
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 学习任务分类标签 -->
|
||||
<div class="tag-category-section">
|
||||
<div class="category-header">
|
||||
<h3 class="category-title">学习任务分类标签</h3>
|
||||
<span class="category-count">({{ taskTags.length }})</span>
|
||||
</div>
|
||||
<div class="tag-grid">
|
||||
<div
|
||||
v-for="tag in taskTags"
|
||||
:key="tag.tagID"
|
||||
class="tag-card"
|
||||
>
|
||||
<div class="tag-content">
|
||||
<div class="tag-info">
|
||||
<div class="tag-dot" :style="{ background: tag.color }"></div>
|
||||
<span class="tag-name">{{ tag.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tag-actions">
|
||||
<button class="edit-button" @click="editTag(tag)">
|
||||
<img src="@/assets/imgs/edit.svg" alt="编辑" />
|
||||
<span>编辑</span>
|
||||
</button>
|
||||
<button class="delete-button" @click="deleteTag(tag)">
|
||||
<img src="@/assets/imgs/trashbin.svg" alt="删除" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 空状态 -->
|
||||
<div v-if="!loading && taskTags.length === 0" class="empty-state">
|
||||
暂无学习任务分类标签
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 全局空状态 -->
|
||||
<div v-if="!loading && tags.length === 0" class="global-empty-state">
|
||||
暂无标签数据
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 创建/编辑标签对话框 -->
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="isEdit ? '编辑标签' : '新增标签'"
|
||||
width="500px"
|
||||
@close="handleDialogClose"
|
||||
>
|
||||
<div class="tag-content">
|
||||
<div class="tag-info">
|
||||
<div class="tag-dot" :style="{ background: tag.color }"></div>
|
||||
<span class="tag-name">{{ tag.name }}</span>
|
||||
</div>
|
||||
<!-- <div class="tag-badge">{{ tag.usageCount || 0 }}</div> -->
|
||||
</div>
|
||||
<el-form :model="currentTag" :rules="rules" ref="formRef" label-width="100px">
|
||||
<el-form-item label="标签名称" prop="name">
|
||||
<el-input v-model="currentTag.name" placeholder="请输入标签名称" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="标签类型" prop="tagType">
|
||||
<el-select v-model="currentTag.tagType" placeholder="请选择标签类型" style="width: 100%">
|
||||
<el-option label="文章分类标签" :value="1" />
|
||||
<el-option label="课程分类标签" :value="2" />
|
||||
<el-option label="学习任务分类标签" :value="3" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<div class="tag-actions">
|
||||
<button class="edit-button" @click="editTag(tag)">
|
||||
<img src="@/assets/imgs/edit.svg" alt="编辑" />
|
||||
<span>编辑</span>
|
||||
</button>
|
||||
<button class="delete-button" @click="deleteTag(tag)">
|
||||
<img src="@/assets/imgs/trashbin.svg" alt="删除" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<el-form-item label="标签颜色" prop="color">
|
||||
<div class="color-picker-wrapper">
|
||||
<el-color-picker v-model="currentTag.color" />
|
||||
<el-input v-model="currentTag.color" placeholder="#000000" style="width: 150px; margin-left: 10px" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<div v-if="!loading && tags.length === 0" class="empty-state">
|
||||
暂无标签数据
|
||||
</div>
|
||||
</div>
|
||||
<el-form-item label="标签描述">
|
||||
<el-input
|
||||
v-model="currentTag.description"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入标签描述"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 创建/编辑标签对话框 -->
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="isEdit ? '编辑标签' : '新增标签'"
|
||||
width="500px"
|
||||
@close="handleDialogClose"
|
||||
>
|
||||
<el-form :model="currentTag" :rules="rules" ref="formRef" label-width="100px">
|
||||
<el-form-item label="标签名称" prop="name">
|
||||
<el-input v-model="currentTag.name" placeholder="请输入标签名称" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="标签类型" prop="tagType">
|
||||
<el-select v-model="currentTag.tagType" placeholder="请选择标签类型" style="width: 100%">
|
||||
<el-option label="文章分类标签" :value="1" />
|
||||
<el-option label="课程分类标签" :value="2" />
|
||||
<el-option label="学习任务分类标签" :value="3" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="标签颜色" prop="color">
|
||||
<div class="color-picker-wrapper">
|
||||
<el-color-picker v-model="currentTag.color" />
|
||||
<el-input v-model="currentTag.color" placeholder="#000000" style="width: 150px; margin-left: 10px" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="标签描述">
|
||||
<el-input
|
||||
v-model="currentTag.description"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入标签描述"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit" :loading="submitting">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit" :loading="submitting">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</AdminLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus';
|
||||
import { resourceTagApi } from '@/apis/resource';
|
||||
import type { Tag } from '@/types/resource';
|
||||
import { TagType } from '@/types/resource';
|
||||
import {AdminLayout} from '@/views/admin';
|
||||
|
||||
defineOptions({
|
||||
@@ -116,6 +198,19 @@ const currentTag = ref<Partial<Tag>>({
|
||||
description: ''
|
||||
});
|
||||
|
||||
// 按类型分类的标签
|
||||
const articleTags = computed(() => {
|
||||
return tags.value.filter(tag => tag.tagType === TagType.ARTICLE_CATEGORY);
|
||||
});
|
||||
|
||||
const courseTags = computed(() => {
|
||||
return tags.value.filter(tag => tag.tagType === TagType.COURSE_CATEGORY);
|
||||
});
|
||||
|
||||
const taskTags = computed(() => {
|
||||
return tags.value.filter(tag => tag.tagType === TagType.LEARNING_TASK_CATEGORY);
|
||||
});
|
||||
|
||||
const rules: FormRules = {
|
||||
name: [
|
||||
{ required: true, message: '请输入标签名称', trigger: 'blur' }
|
||||
@@ -136,7 +231,7 @@ onMounted(() => {
|
||||
async function loadTags() {
|
||||
try {
|
||||
loading.value = true;
|
||||
const result = await resourceTagApi.getTagList();
|
||||
const result = await resourceTagApi.getTagList({});
|
||||
if (result.success) {
|
||||
tags.value = result.dataList || [];
|
||||
// TODO: 加载每个标签的使用计数
|
||||
@@ -292,11 +387,48 @@ function handleDialogClose() {
|
||||
}
|
||||
}
|
||||
|
||||
.tag-categories {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 40px;
|
||||
}
|
||||
|
||||
.tag-category-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.category-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 2px solid #F0F0F0;
|
||||
}
|
||||
|
||||
.category-title {
|
||||
margin: 0;
|
||||
font-family: 'Inter', 'PingFang SC', sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 18px;
|
||||
line-height: 1.5em;
|
||||
color: #101828;
|
||||
}
|
||||
|
||||
.category-count {
|
||||
font-family: 'Inter', 'PingFang SC', sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 1.5em;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.tag-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 24px;
|
||||
min-height: 200px;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.tag-card {
|
||||
@@ -419,6 +551,15 @@ function handleDialogClose() {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.global-empty-state {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 100px 0;
|
||||
font-size: 16px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.color-picker-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-wrapper" v-if="total > 0">
|
||||
<div class="pagination-container" v-if="total > 0">
|
||||
<el-pagination
|
||||
v-model:current-page="pageParam.pageNumber"
|
||||
v-model:page-size="pageParam.pageSize"
|
||||
@@ -431,12 +431,6 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.detail-content {
|
||||
.detail-item {
|
||||
display: flex;
|
||||
|
||||
@@ -154,11 +154,11 @@
|
||||
/>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-wrapper" v-if="total > 0">
|
||||
<div class="pagination-container" v-if="total > 0">
|
||||
<el-pagination
|
||||
v-model:current-page="pageParam.pageNumber"
|
||||
v-model:page-size="pageParam.pageSize"
|
||||
:page-sizes="[9, 18, 36]"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@@ -671,12 +671,6 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.form-content {
|
||||
.form-item {
|
||||
margin-bottom: 20px;
|
||||
|
||||
@@ -127,7 +127,7 @@
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-wrapper" v-if="total > 0">
|
||||
<div class="pagination-container" v-if="total > 0">
|
||||
<el-pagination
|
||||
v-model:current-page="pageParam.pageNumber"
|
||||
v-model:page-size="pageParam.pageSize"
|
||||
@@ -593,12 +593,6 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.form-content {
|
||||
.form-item {
|
||||
margin-bottom: 20px;
|
||||
|
||||
Reference in New Issue
Block a user