mirror of
https://github.com/mindskip/xzs-mysql.git
synced 2026-08-28 19:12:15 +08:00
合并拉取请求 #503
.4062073974432528:8deb233c8ac88b448d2f643e66e84732_69eb2ffca3c75e7cbf955b5e.69ec1708a3c75e7cbf955d10.69ec1707ac8e7345a8a578b2:Trae CN.T(2026/4/25 09:21:12)
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
const FAVORITE_KEY = 'xzs_favorite_papers'
|
||||
const FAVORITE_LIMIT = 100
|
||||
|
||||
function safeParse (str) {
|
||||
try {
|
||||
return JSON.parse(str)
|
||||
} catch (e) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
function safeStringify (obj) {
|
||||
try {
|
||||
return JSON.stringify(obj)
|
||||
} catch (e) {
|
||||
return '[]'
|
||||
}
|
||||
}
|
||||
|
||||
export function getFavorites () {
|
||||
try {
|
||||
const data = window.localStorage.getItem(FAVORITE_KEY)
|
||||
if (!data) return []
|
||||
const favorites = safeParse(data)
|
||||
return Array.isArray(favorites) ? favorites : []
|
||||
} catch (e) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
export function isFavorite (paperId) {
|
||||
const id = Number(paperId)
|
||||
if (isNaN(id)) return false
|
||||
const favorites = getFavorites()
|
||||
return favorites.some(item => item.id === id)
|
||||
}
|
||||
|
||||
export function addFavorite (paperId, paperInfo = {}) {
|
||||
const id = Number(paperId)
|
||||
if (isNaN(id)) return false
|
||||
if (isFavorite(id)) return true
|
||||
|
||||
const favorites = getFavorites()
|
||||
const newItem = {
|
||||
id,
|
||||
name: paperInfo.name || '',
|
||||
subjectId: paperInfo.subjectId || null,
|
||||
createdAt: Date.now()
|
||||
}
|
||||
|
||||
favorites.unshift(newItem)
|
||||
|
||||
if (favorites.length > FAVORITE_LIMIT) {
|
||||
favorites.splice(FAVORITE_LIMIT)
|
||||
}
|
||||
|
||||
try {
|
||||
window.localStorage.setItem(FAVORITE_KEY, safeStringify(favorites))
|
||||
return true
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function removeFavorite (paperId) {
|
||||
const id = Number(paperId)
|
||||
if (isNaN(id)) return false
|
||||
|
||||
const favorites = getFavorites()
|
||||
const newFavorites = favorites.filter(item => item.id !== id)
|
||||
|
||||
try {
|
||||
window.localStorage.setItem(FAVORITE_KEY, safeStringify(newFavorites))
|
||||
return true
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function toggleFavorite (paperId, paperInfo = {}) {
|
||||
if (isFavorite(paperId)) {
|
||||
return removeFavorite(paperId)
|
||||
} else {
|
||||
return addFavorite(paperId, paperInfo)
|
||||
}
|
||||
}
|
||||
|
||||
export function sortByFavorite (paperList) {
|
||||
if (!Array.isArray(paperList) || paperList.length === 0) {
|
||||
return paperList
|
||||
}
|
||||
|
||||
const favoriteIds = getFavorites().map(item => item.id)
|
||||
if (favoriteIds.length === 0) {
|
||||
return paperList
|
||||
}
|
||||
|
||||
const favoritePapers = []
|
||||
const otherPapers = []
|
||||
|
||||
paperList.forEach(paper => {
|
||||
if (favoriteIds.includes(paper.id)) {
|
||||
favoritePapers.push(paper)
|
||||
} else {
|
||||
otherPapers.push(paper)
|
||||
}
|
||||
})
|
||||
|
||||
favoritePapers.sort((a, b) => {
|
||||
const indexA = favoriteIds.indexOf(a.id)
|
||||
const indexB = favoriteIds.indexOf(b.id)
|
||||
return indexA - indexB
|
||||
})
|
||||
|
||||
return [...favoritePapers, ...otherPapers]
|
||||
}
|
||||
|
||||
export function clearFavorites () {
|
||||
try {
|
||||
window.localStorage.removeItem(FAVORITE_KEY)
|
||||
return true
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,26 @@
|
||||
<template>
|
||||
<div style="margin-top: 10px" class="app-contain">
|
||||
<el-tabs tab-position="left" v-model="tabId" @tab-click="subjectChange" >
|
||||
<el-tab-pane :label="item.name" :key="item.id" :name="item.id" v-for="item in subjectList" style="margin-left: 20px;" >
|
||||
<el-row style="float: right">
|
||||
<el-radio-group v-model="queryParam.paperType" size="mini" @change="paperTypeChange" >
|
||||
<el-tabs tab-position="left" v-model="tabId" @tab-click="subjectChange">
|
||||
<el-tab-pane :label="item.name" :key="item.id" :name="item.id" v-for="item in subjectList" style="margin-left: 20px;">
|
||||
<el-row style="float: right">
|
||||
<el-radio-group v-model="queryParam.paperType" size="mini" @change="paperTypeChange">
|
||||
<el-radio v-for="item in paperTypeEnum" size="mini" :key="item.key" :label="item.key">{{item.value}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-row>
|
||||
<el-table v-loading="listLoading" :data="tableData" fit highlight-current-row style="width: 100%">
|
||||
<el-table v-loading="listLoading" :data="sortedTableData" fit highlight-current-row style="width: 100%">
|
||||
<el-table-column prop="id" label="序号" width="90px"/>
|
||||
<el-table-column prop="name" label="名称" />
|
||||
<el-table-column prop="name" label="名称"/>
|
||||
<el-table-column label="收藏" width="60px" align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-button type="text" size="small" @click="handleToggleFavorite(row)" :class="{'is-favorite': isPaperFavorite(row.id)}">
|
||||
<svg-icon :icon-class="isPaperFavorite(row.id) ? 'star' : 'star'" :class="{'favorite-icon': true, 'active': isPaperFavorite(row.id)}"/>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="right">
|
||||
<template slot-scope="{row}">
|
||||
<router-link target="_blank" :to="{path:'/do',query:{id:row.id}}">
|
||||
<el-button type="text" size="small">开始答题</el-button>
|
||||
<el-button type="text" size="small">开始答题</el-button>
|
||||
</router-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -31,6 +38,7 @@ import { mapState } from 'vuex'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import examPaperApi from '@/api/examPaper'
|
||||
import subjectApi from '@/api/subject'
|
||||
import { isFavorite, toggleFavorite, sortByFavorite } from '@/utils/favorite'
|
||||
|
||||
export default {
|
||||
components: { Pagination },
|
||||
@@ -49,6 +57,14 @@ export default {
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('enumItem', {
|
||||
paperTypeEnum: state => state.exam.examPaper.paperTypeEnum
|
||||
}),
|
||||
sortedTableData () {
|
||||
return sortByFavorite(this.tableData)
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.initSubject()
|
||||
},
|
||||
@@ -79,12 +95,48 @@ export default {
|
||||
subjectChange (tab, event) {
|
||||
this.queryParam.subjectId = Number(this.tabId)
|
||||
this.search()
|
||||
},
|
||||
isPaperFavorite (paperId) {
|
||||
return isFavorite(paperId)
|
||||
},
|
||||
handleToggleFavorite (row) {
|
||||
const result = toggleFavorite(row.id, {
|
||||
name: row.name,
|
||||
subjectId: row.subjectId
|
||||
})
|
||||
if (result) {
|
||||
this.$message({
|
||||
message: this.isPaperFavorite(row.id) ? '收藏成功' : '已取消收藏',
|
||||
type: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
} else {
|
||||
this.$message.error('操作失败,请稍后重试')
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('enumItem', {
|
||||
paperTypeEnum: state => state.exam.examPaper.paperTypeEnum
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.favorite-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
fill: #c0c4cc;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.favorite-icon:hover {
|
||||
fill: #409eff;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.favorite-icon.active {
|
||||
fill: #f7ba2a;
|
||||
}
|
||||
|
||||
.is-favorite .favorite-icon {
|
||||
fill: #f7ba2a;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user