feat:更新资料库模块
This commit is contained in:
@@ -6,6 +6,7 @@ export const uploadLibraryFileApi = (formData: FormData): Promise<string> =>
|
|||||||
url: '/study-api/library/upload',
|
url: '/study-api/library/upload',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: formData,
|
data: formData,
|
||||||
|
timeout: 60000,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'multipart/form-data'
|
'Content-Type': 'multipart/form-data'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<el-button type="primary" :icon="Edit" @click="editClick(file)">编辑</el-button>
|
<el-button type="primary" :icon="Edit" @click="editClick(file)">编辑</el-button>
|
||||||
|
<el-button type="primary" :icon="Aim" @click="trainClick(file)">训练</el-button>
|
||||||
<el-button type="danger" :icon="Delete">删除</el-button>
|
<el-button type="danger" :icon="Delete">删除</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -25,15 +26,18 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Delete, Edit, Picture, Document } from '@element-plus/icons-vue'
|
import { Delete, Edit, Picture, Document, Aim } from '@element-plus/icons-vue'
|
||||||
import { useLibraryStore } from '@/stores/library.ts'
|
import { useLibraryStore } from '@/stores/library.ts'
|
||||||
|
import { usePracticeStore } from '@/stores/practice.ts'
|
||||||
import type { ILibraryFile } from '@/types/library.ts'
|
import type { ILibraryFile } from '@/types/library.ts'
|
||||||
import LibraryFilter from '@/components/Library/LibraryFilter.vue'
|
import LibraryFilter from '@/components/Library/LibraryFilter.vue'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { fromNow } from '@/utils/dayUtil.ts'
|
import { fromNow } from '@/utils/dayUtil.ts'
|
||||||
import { filesize } from 'filesize'
|
import { filesize } from 'filesize'
|
||||||
|
import { ElLoading, ElMessage } from 'element-plus'
|
||||||
|
|
||||||
const libraryStore = useLibraryStore()
|
const libraryStore = useLibraryStore()
|
||||||
|
const practiceStore = usePracticeStore()
|
||||||
|
|
||||||
const filterLibraryFileList = computed(() => {
|
const filterLibraryFileList = computed(() => {
|
||||||
const subject = libraryStore.selectedSubject
|
const subject = libraryStore.selectedSubject
|
||||||
@@ -52,4 +56,59 @@ const editClick = async (file: ILibraryFile) => {
|
|||||||
libraryStore.activeStep = 1
|
libraryStore.activeStep = 1
|
||||||
libraryStore.fileDialogVisible = true
|
libraryStore.fileDialogVisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const trainClick = async (file: ILibraryFile) => {
|
||||||
|
await libraryStore.queryFileById(file.id)
|
||||||
|
await generateQuestion()
|
||||||
|
practiceStore.hasStart = true
|
||||||
|
practiceStore.hasSubmit = false
|
||||||
|
practiceStore.checkList = []
|
||||||
|
}
|
||||||
|
|
||||||
|
const generateQuestion = async () => {
|
||||||
|
practiceStore.questionContent = ''
|
||||||
|
practiceStore.hasGenerateQuestion = false
|
||||||
|
|
||||||
|
const loading = ElLoading.service({
|
||||||
|
lock: true,
|
||||||
|
text: '题库生成中 请等待',
|
||||||
|
background: 'rgba(0, 0, 0, 0.7)'
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/study-api/library/question', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
message: libraryStore.currentFile.content
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.body) {
|
||||||
|
throw new Error('未获取到响应流')
|
||||||
|
}
|
||||||
|
|
||||||
|
const reader = response.body.getReader()
|
||||||
|
const decoder = new TextDecoder('utf-8')
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const { value, done } = await reader.read()
|
||||||
|
if (done) break
|
||||||
|
practiceStore.questionContent += decoder.decode(value, { stream: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
ElMessage.success('生成完成')
|
||||||
|
practiceStore.hasGenerateQuestion = true
|
||||||
|
|
||||||
|
practiceStore.questionList = JSON.parse(practiceStore.questionContent)
|
||||||
|
libraryStore.fileTrainDialogVisible = true
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
ElMessage.error('生成失败 请联系管理员')
|
||||||
|
} finally {
|
||||||
|
loading.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="practice-question">
|
<el-dialog v-model="libraryStore.fileTrainDialogVisible"
|
||||||
<div v-if="practiceStore.hasStart" class="question-list">
|
:title="libraryStore.currentFile.name" width="80%" center destroy-on-close
|
||||||
|
class="train-dialog common-dialog">
|
||||||
|
<div class="question-list">
|
||||||
<div v-for="(q, idx) in practiceStore.questionList" :key="q.id" class="question-card">
|
<div v-for="(q, idx) in practiceStore.questionList" :key="q.id" class="question-card">
|
||||||
<div class="q-header">
|
<div class="q-header">
|
||||||
<el-tag :type="q.type === 'single' ? 'primary' : 'warning'" effect="dark">
|
<el-tag :type="q.type === 'single' ? 'primary' : 'warning'" effect="dark">
|
||||||
@@ -38,7 +40,7 @@
|
|||||||
<div v-if="!practiceStore.hasSubmit" class="question-action">
|
<div v-if="!practiceStore.hasSubmit" class="question-action">
|
||||||
<el-button type="success" @click="submitAnswerClick">提交答案</el-button>
|
<el-button type="success" @click="submitAnswerClick">提交答案</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -109,3 +111,68 @@ const addMistakeList = async () => {
|
|||||||
await mistakeStore.addMistakeList()
|
await mistakeStore.addMistakeList()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.train-dialog {
|
||||||
|
.el-dialog__body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-list {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.question-card {
|
||||||
|
padding: 10px 0;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
border-bottom: 1px solid lightgray;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.q-num {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-stem {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-options {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-check {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-action {
|
||||||
|
align-self: center;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="practice-record">
|
|
||||||
<div v-if="practiceStore.recordList.length > 0" class="record-list">
|
|
||||||
<div v-for="r in practiceStore.recordList" :key="r.id" class="record-card">
|
|
||||||
<div class="record-main">
|
|
||||||
<span class="record-status" :style="{color: getCorrectRate(r) < 50 ? 'red' : 'green'}">
|
|
||||||
正确率 {{ r.totalCount ? getCorrectRate(r) : 0 }}%
|
|
||||||
</span>
|
|
||||||
<span class="record-time">{{ fromNow(r.createTime) }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="record-stats">
|
|
||||||
<span>共 {{ r.totalCount }}</span>
|
|
||||||
<span class="text-success">对 {{ r.correctCount }}</span>
|
|
||||||
<span class="text-error">错 {{ r.wrongCount }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-empty v-else description="暂无数据"></el-empty>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { usePracticeStore } from '@/stores/practice.ts'
|
|
||||||
import { fromNow } from '@/utils/dayUtil.ts'
|
|
||||||
import type { IPracticeRecord } from '@/types/practice.ts'
|
|
||||||
|
|
||||||
const practiceStore = usePracticeStore()
|
|
||||||
|
|
||||||
const getCorrectRate = (record: IPracticeRecord) => {
|
|
||||||
return Math.round((record.correctCount / record.totalCount) * 100)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -20,10 +20,6 @@
|
|||||||
<el-icon><Reading /></el-icon>
|
<el-icon><Reading /></el-icon>
|
||||||
<template #title>知识库</template>
|
<template #title>知识库</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item index="/practice">
|
|
||||||
<el-icon><Aim /></el-icon>
|
|
||||||
<template #title>训练场</template>
|
|
||||||
</el-menu-item>
|
|
||||||
<el-menu-item index="/exam">
|
<el-menu-item index="/exam">
|
||||||
<el-icon><EditPen /></el-icon>
|
<el-icon><EditPen /></el-icon>
|
||||||
<template #title>考试中心</template>
|
<template #title>考试中心</template>
|
||||||
@@ -91,7 +87,7 @@
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { ElMessageBox } from 'element-plus'
|
import { ElMessageBox } from 'element-plus'
|
||||||
import { Reading, Aim, EditPen, Notebook, DataLine, Fold, Expand, Bell } from '@element-plus/icons-vue'
|
import { Reading, EditPen, Notebook, DataLine, Fold, Expand, Bell } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const isCollapse = ref(false)
|
const isCollapse = ref(false)
|
||||||
|
|||||||
@@ -13,12 +13,6 @@ const routes = [
|
|||||||
component: () => import('@/views/Library.vue'),
|
component: () => import('@/views/Library.vue'),
|
||||||
meta: { title: '知识库' }
|
meta: { title: '知识库' }
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'practice',
|
|
||||||
name: 'Practice',
|
|
||||||
component: () => import('@/views/Practice.vue'),
|
|
||||||
meta: { title: '训练场' }
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'exam',
|
path: 'exam',
|
||||||
name: 'Exam',
|
name: 'Exam',
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export const useLibraryStore = defineStore('library', {
|
|||||||
fileDetailDialogVisible: false,
|
fileDetailDialogVisible: false,
|
||||||
fileDialogVisible: false,
|
fileDialogVisible: false,
|
||||||
fileContentDialogVisible: false,
|
fileContentDialogVisible: false,
|
||||||
|
fileTrainDialogVisible: false,
|
||||||
fileApiType: 'ADD' as IHandleApi,
|
fileApiType: 'ADD' as IHandleApi,
|
||||||
subjectOptions: [] as IOptions[],
|
subjectOptions: [] as IOptions[],
|
||||||
moduleOptions: [] as IOptions[],
|
moduleOptions: [] as IOptions[],
|
||||||
|
|||||||
@@ -13,12 +13,15 @@
|
|||||||
<library-file-dialog />
|
<library-file-dialog />
|
||||||
|
|
||||||
<library-file-content-dialog />
|
<library-file-content-dialog />
|
||||||
|
|
||||||
|
<library-file-train-dialog />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import LibraryFileList from '@/components/Library/LibraryFileList.vue'
|
import LibraryFileList from '@/components/Library/LibraryFileList.vue'
|
||||||
import LibraryFileDialog from '@/components/Library/LibraryFileDialog.vue'
|
import LibraryFileDialog from '@/components/Library/LibraryFileDialog.vue'
|
||||||
|
import LibraryFileTrainDialog from '@/components/Library/LibraryFileTrainDialog.vue'
|
||||||
import LibraryFileContentDialog from '@/components/Library/LibraryFileContentDialog.vue'
|
import LibraryFileContentDialog from '@/components/Library/LibraryFileContentDialog.vue'
|
||||||
import { useLibraryStore } from '@/stores/library.ts'
|
import { useLibraryStore } from '@/stores/library.ts'
|
||||||
import { Plus } from '@element-plus/icons-vue'
|
import { Plus } from '@element-plus/icons-vue'
|
||||||
@@ -34,8 +37,6 @@ const addFileClick = () => {
|
|||||||
libraryStore.currentFile = libraryStore.getEmptyFile()
|
libraryStore.currentFile = libraryStore.getEmptyFile()
|
||||||
libraryStore.fileApiType = 'ADD'
|
libraryStore.fileApiType = 'ADD'
|
||||||
libraryStore.activeStep = 1
|
libraryStore.activeStep = 1
|
||||||
libraryStore.hasGenerateQuestion = false
|
|
||||||
libraryStore.questionContent = ''
|
|
||||||
libraryStore.fileDialogVisible = true
|
libraryStore.fileDialogVisible = true
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,232 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="practice-view common-view">
|
|
||||||
<div class="view-header">
|
|
||||||
<div class="view-content">
|
|
||||||
<h2 class="view-title">训练场</h2>
|
|
||||||
<p class="view-subtitle">专项练习,巩固知识点</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="view-action">
|
|
||||||
<el-button type="primary" :icon="Aim" @click="startPracticeClick">
|
|
||||||
{{ practiceStore.hasStart ? '重新练习' : '开始练习' }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<library-filter v-if="libraryStore.fileList.length" />
|
|
||||||
|
|
||||||
<practice-question v-if="practiceStore.hasStart"/>
|
|
||||||
|
|
||||||
<practice-record v-else/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import LibraryFilter from '@/components/Library/LibraryFilter.vue'
|
|
||||||
import PracticeQuestion from '@/components/Practice/PracticeQuestion.vue'
|
|
||||||
import PracticeRecord from '@/components/Practice/PracticeRecord.vue'
|
|
||||||
import { onMounted, watch } from 'vue'
|
|
||||||
import { useLibraryStore } from '@/stores/library'
|
|
||||||
import { usePracticeStore } from '@/stores/practice.ts'
|
|
||||||
import { Aim } from '@element-plus/icons-vue'
|
|
||||||
import { ElLoading, ElMessage } from 'element-plus'
|
|
||||||
|
|
||||||
const libraryStore = useLibraryStore()
|
|
||||||
const practiceStore = usePracticeStore()
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
practiceStore.hasStart = false
|
|
||||||
await libraryStore.queryFileList()
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(() => libraryStore.selectedModule, async () => {
|
|
||||||
practiceStore.hasStart = false
|
|
||||||
const subject = libraryStore.selectedSubject
|
|
||||||
const module = libraryStore.selectedModule
|
|
||||||
const fileList = libraryStore.fileList.filter((item) => {
|
|
||||||
return item.subject === subject && item.module === module
|
|
||||||
})
|
|
||||||
|
|
||||||
if (fileList.length > 0) {
|
|
||||||
const { id } = fileList[0]
|
|
||||||
practiceStore.libraryFileId = id
|
|
||||||
await practiceStore.queryRecord()
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
immediate: true
|
|
||||||
})
|
|
||||||
|
|
||||||
const startPracticeClick = async () => {
|
|
||||||
await libraryStore.queryFileById(practiceStore.libraryFileId)
|
|
||||||
await generateQuestion()
|
|
||||||
practiceStore.hasStart = true
|
|
||||||
practiceStore.hasSubmit = false
|
|
||||||
practiceStore.checkList = []
|
|
||||||
}
|
|
||||||
|
|
||||||
const generateQuestion = async () => {
|
|
||||||
practiceStore.questionContent = ''
|
|
||||||
practiceStore.hasGenerateQuestion = false
|
|
||||||
|
|
||||||
const loading = ElLoading.service({
|
|
||||||
lock: true,
|
|
||||||
text: '题库生成中 请等待',
|
|
||||||
background: 'rgba(0, 0, 0, 0.7)'
|
|
||||||
})
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch('/study-api/library/question', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
message: libraryStore.currentFile.content
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!response.body) {
|
|
||||||
throw new Error('未获取到响应流')
|
|
||||||
}
|
|
||||||
|
|
||||||
const reader = response.body.getReader()
|
|
||||||
const decoder = new TextDecoder('utf-8')
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
const { value, done } = await reader.read()
|
|
||||||
if (done) break
|
|
||||||
practiceStore.questionContent += decoder.decode(value, { stream: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
ElMessage.success('生成完成')
|
|
||||||
practiceStore.hasGenerateQuestion = true
|
|
||||||
|
|
||||||
practiceStore.questionList = JSON.parse(practiceStore.questionContent)
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error)
|
|
||||||
ElMessage.error('生成失败 请联系管理员')
|
|
||||||
} finally {
|
|
||||||
loading.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.practice-view {
|
|
||||||
.practice-question {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 16px;
|
|
||||||
|
|
||||||
.question-action {
|
|
||||||
align-self: center;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.question-list {
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 12px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.question-card {
|
|
||||||
padding: 16px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
|
|
||||||
border-bottom: 1px solid lightgray;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.q-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
|
|
||||||
.q-num {
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.q-stem {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 1.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.q-options {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.q-check {
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.practice-record {
|
|
||||||
.record-list {
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 12px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.record-card {
|
|
||||||
padding: 16px;
|
|
||||||
|
|
||||||
border-bottom: 1px solid lightgray;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.record-main {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 5px;
|
|
||||||
|
|
||||||
.record-time {
|
|
||||||
font-size: 13px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.record-status {
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.record-stats {
|
|
||||||
display: flex;
|
|
||||||
gap: 12px;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #555;
|
|
||||||
|
|
||||||
.text-success {
|
|
||||||
color: #52c41a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-error {
|
|
||||||
color: #ff4d4f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
Reference in New Issue
Block a user