成就等界面接口调整

This commit is contained in:
2025-10-31 19:13:21 +08:00
parent 9ad9507a72
commit 16754b527e
61 changed files with 4748 additions and 592 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;