fix: 功能优化完善。
This commit is contained in:
@@ -219,6 +219,7 @@
|
||||
<script>
|
||||
import Page from '../components/Page'
|
||||
import ToolService from '../services/ToolService'
|
||||
import Sortable from 'sortablejs'
|
||||
|
||||
export default {
|
||||
name: 'ManagePage',
|
||||
@@ -293,7 +294,10 @@ export default {
|
||||
color: 'linear-gradient(135deg, #a1c4fd 0%, #c2e9fb 100%)',
|
||||
sortOrder: 0
|
||||
},
|
||||
currentCategory: null
|
||||
currentCategory: null,
|
||||
categorySortable: null, // 分组拖拽实例
|
||||
toolSortables: [], // 网址拖拽实例数组
|
||||
superCategorySortable: null // 大分类拖拽实例
|
||||
}
|
||||
},
|
||||
|
||||
@@ -320,6 +324,18 @@ export default {
|
||||
this.loadData()
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// 初始化拖拽功能
|
||||
this.initSortable()
|
||||
},
|
||||
|
||||
updated() {
|
||||
// 数据更新后重新初始化拖拽
|
||||
this.$nextTick(() => {
|
||||
this.initSortable()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 消息提示
|
||||
showMessage(text, type = 'success') {
|
||||
@@ -825,6 +841,179 @@ export default {
|
||||
console.error('删除工具失败:', error)
|
||||
this.showMessage('删除失败,请检查网络连接', 'error')
|
||||
}
|
||||
},
|
||||
|
||||
// 初始化拖拽排序
|
||||
initSortable() {
|
||||
// 销毁旧的 Sortable 实例
|
||||
if (this.superCategorySortable) {
|
||||
this.superCategorySortable.destroy()
|
||||
}
|
||||
if (this.categorySortable) {
|
||||
this.categorySortable.destroy()
|
||||
}
|
||||
if (this.toolSortables) {
|
||||
this.toolSortables.forEach(s => s.destroy())
|
||||
}
|
||||
this.toolSortables = []
|
||||
|
||||
// 大分类 Tab 拖拽
|
||||
const tabListEl = document.querySelector('.tab-list')
|
||||
if (tabListEl) {
|
||||
this.superCategorySortable = Sortable.create(tabListEl, {
|
||||
animation: 150,
|
||||
handle: '.tab-item',
|
||||
ghostClass: 'sortable-ghost',
|
||||
chosenClass: 'sortable-chosen',
|
||||
dragClass: 'sortable-drag',
|
||||
onEnd: (evt) => {
|
||||
this.handleSuperCategorySort(evt)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 书签分组拖拽
|
||||
const categoryListEl = document.querySelector('.category-list')
|
||||
if (categoryListEl) {
|
||||
this.categorySortable = Sortable.create(categoryListEl, {
|
||||
animation: 150,
|
||||
handle: '.category-item',
|
||||
ghostClass: 'sortable-ghost',
|
||||
chosenClass: 'sortable-chosen',
|
||||
dragClass: 'sortable-drag',
|
||||
onEnd: (evt) => {
|
||||
this.handleCategorySort(evt)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 网址列表拖拽(每个分组都需要初始化)
|
||||
const toolLists = document.querySelectorAll('.tool-list')
|
||||
toolLists.forEach((toolListEl, index) => {
|
||||
const sortable = Sortable.create(toolListEl, {
|
||||
animation: 150,
|
||||
handle: '.tool-item',
|
||||
ghostClass: 'sortable-ghost',
|
||||
chosenClass: 'sortable-chosen',
|
||||
dragClass: 'sortable-drag',
|
||||
onEnd: (evt) => {
|
||||
this.handleToolSort(evt, index)
|
||||
}
|
||||
})
|
||||
this.toolSortables.push(sortable)
|
||||
})
|
||||
},
|
||||
|
||||
// 处理大分类排序
|
||||
async handleSuperCategorySort(evt) {
|
||||
const { oldIndex, newIndex } = evt
|
||||
if (oldIndex === newIndex) return
|
||||
|
||||
const superCategories = [...this.superCategories]
|
||||
const movedItem = superCategories[oldIndex]
|
||||
superCategories.splice(oldIndex, 1)
|
||||
superCategories.splice(newIndex, 0, movedItem)
|
||||
|
||||
// 更新排序号
|
||||
const updates = superCategories.map((cat, index) => ({
|
||||
id: cat.id,
|
||||
sortOrder: index
|
||||
}))
|
||||
|
||||
try {
|
||||
// 批量更新排序
|
||||
for (const update of updates) {
|
||||
await ToolService.updateSuperCategory({
|
||||
id: update.id,
|
||||
superCategoryKey: superCategories.find(c => c.id === update.id).key,
|
||||
superCategoryTitle: superCategories.find(c => c.id === update.id).title,
|
||||
sortOrder: update.sortOrder
|
||||
})
|
||||
}
|
||||
this.showMessage('排序保存成功')
|
||||
await this.loadData()
|
||||
} catch (error) {
|
||||
console.error('排序失败:', error)
|
||||
this.showMessage('排序保存失败', 'error')
|
||||
await this.loadData()
|
||||
}
|
||||
},
|
||||
|
||||
// 处理书签分组排序
|
||||
async handleCategorySort(evt) {
|
||||
const { oldIndex, newIndex } = evt
|
||||
if (oldIndex === newIndex) return
|
||||
|
||||
const categories = [...this.currentCategories]
|
||||
const movedItem = categories[oldIndex]
|
||||
categories.splice(oldIndex, 1)
|
||||
categories.splice(newIndex, 0, movedItem)
|
||||
|
||||
// 更新排序号
|
||||
const updates = categories.map((cat, index) => ({
|
||||
id: cat.id,
|
||||
sortOrder: index
|
||||
}))
|
||||
|
||||
try {
|
||||
// 批量更新排序
|
||||
for (const update of updates) {
|
||||
await ToolService.updateCategory({
|
||||
id: update.id,
|
||||
categoryKey: categories.find(c => c.id === update.id).key,
|
||||
categoryTitle: categories.find(c => c.id === update.id).title,
|
||||
superCategoryId: categories.find(c => c.id === update.id).superCategoryId,
|
||||
sortOrder: update.sortOrder
|
||||
})
|
||||
}
|
||||
this.showMessage('排序保存成功')
|
||||
await this.loadData()
|
||||
} catch (error) {
|
||||
console.error('排序失败:', error)
|
||||
this.showMessage('排序保存失败', 'error')
|
||||
await this.loadData()
|
||||
}
|
||||
},
|
||||
|
||||
// 处理网址排序
|
||||
async handleToolSort(evt, categoryIndex) {
|
||||
const { oldIndex, newIndex } = evt
|
||||
if (oldIndex === newIndex) return
|
||||
|
||||
const category = this.currentCategories[categoryIndex]
|
||||
const tools = [...category.tools]
|
||||
const movedItem = tools[oldIndex]
|
||||
tools.splice(oldIndex, 1)
|
||||
tools.splice(newIndex, 0, movedItem)
|
||||
|
||||
// 更新排序号
|
||||
const updates = tools.map((tool, index) => ({
|
||||
...tool,
|
||||
sortOrder: index
|
||||
}))
|
||||
|
||||
try {
|
||||
// 批量更新排序
|
||||
for (const tool of updates) {
|
||||
await ToolService.updateTool({
|
||||
id: tool.id,
|
||||
categoryId: category.id,
|
||||
name: tool.name,
|
||||
description: tool.desc,
|
||||
url: tool.url,
|
||||
displayUrl: tool.displayUrl,
|
||||
icon: tool.icon,
|
||||
color: tool.color,
|
||||
sortOrder: tool.sortOrder
|
||||
})
|
||||
}
|
||||
this.showMessage('排序保存成功')
|
||||
await this.loadData()
|
||||
} catch (error) {
|
||||
console.error('排序失败:', error)
|
||||
this.showMessage('排序保存失败', 'error')
|
||||
await this.loadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -976,7 +1165,7 @@ export default {
|
||||
background: #f5f7fa;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
cursor: move; // 显示可拖拽
|
||||
transition: all 0.3s ease;
|
||||
user-select: none;
|
||||
|
||||
@@ -1137,6 +1326,7 @@ export default {
|
||||
border-radius: 6px;
|
||||
border: 1px solid #e5e7eb;
|
||||
transition: all 0.2s ease;
|
||||
cursor: move; // 显示可拖拽
|
||||
|
||||
&:hover {
|
||||
background: #f3f4f6;
|
||||
@@ -1245,6 +1435,7 @@ export default {
|
||||
border-radius: 6px;
|
||||
border: 1px solid #e5e7eb;
|
||||
transition: all 0.2s ease;
|
||||
cursor: move; // 显示可拖拽
|
||||
|
||||
&:hover {
|
||||
background: #f3f4f6;
|
||||
@@ -1647,6 +1838,24 @@ button {
|
||||
transform: translate(-50%, -20px);
|
||||
}
|
||||
|
||||
// 拖拽样式
|
||||
.sortable-ghost {
|
||||
opacity: 0.4;
|
||||
background: #e0e7ff !important;
|
||||
border: 2px dashed @primary-color !important;
|
||||
}
|
||||
|
||||
.sortable-chosen {
|
||||
opacity: 0.8;
|
||||
transform: scale(1.02);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.sortable-drag {
|
||||
opacity: 0.8;
|
||||
transform: rotate(2deg);
|
||||
}
|
||||
|
||||
// 响应式布局 - 手机端
|
||||
@media (max-width: 600px) {
|
||||
.manage-header {
|
||||
|
||||
Reference in New Issue
Block a user