fix: 功能优化完善。
This commit is contained in:
@@ -2,9 +2,9 @@
|
||||
<html lang="zh-Hans-CN">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="Keywords" content="记账平台,健康档案,茅台预约"/>
|
||||
<meta name="Keywords" content="工作台"/>
|
||||
<meta name="Description"
|
||||
content="智聪工作台"/>
|
||||
content="工作台"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes"/>
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
|
||||
@@ -12,7 +12,7 @@
|
||||
<meta http-equiv="x-dns-prefetch-control" content="on"/>
|
||||
<link rel="icon" href="/static/favicon.ico" />
|
||||
<link rel="dns-prefetch" href="http://www.qdintc.com"/>
|
||||
<title>智聪工作台</title>
|
||||
<title>工作台</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
11
package-lock.json
generated
11
package-lock.json
generated
@@ -10,6 +10,7 @@
|
||||
"dependencies": {
|
||||
"axios": "^0.27.2",
|
||||
"jsonp": "^0.2.1",
|
||||
"sortablejs": "^1.15.6",
|
||||
"vue": "^2.7.15",
|
||||
"vue-carousel": "^0.18.0",
|
||||
"vue-router": "^3.0.1",
|
||||
@@ -13130,6 +13131,11 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sortablejs": {
|
||||
"version": "1.15.6",
|
||||
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.6.tgz",
|
||||
"integrity": "sha512-aNfiuwMEpfBM/CN6LY0ibyhxPfPbyFeBTYJKCvzkJ2GkUpazIt3H+QIPAMHwqQ7tMKaHz1Qj+rJJCqljnf4p3A=="
|
||||
},
|
||||
"node_modules/source-list-map": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
|
||||
@@ -26431,6 +26437,11 @@
|
||||
"is-plain-obj": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"sortablejs": {
|
||||
"version": "1.15.6",
|
||||
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.6.tgz",
|
||||
"integrity": "sha512-aNfiuwMEpfBM/CN6LY0ibyhxPfPbyFeBTYJKCvzkJ2GkUpazIt3H+QIPAMHwqQ7tMKaHz1Qj+rJJCqljnf4p3A=="
|
||||
},
|
||||
"source-list-map": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"dependencies": {
|
||||
"axios": "^0.27.2",
|
||||
"jsonp": "^0.2.1",
|
||||
"sortablejs": "^1.15.6",
|
||||
"vue": "^2.7.15",
|
||||
"vue-carousel": "^0.18.0",
|
||||
"vue-router": "^3.0.1",
|
||||
|
||||
@@ -64,6 +64,11 @@
|
||||
@click="openTool(tool.url)"
|
||||
>
|
||||
<span class="simple-tool-name">{{ tool.name }}</span>
|
||||
<div class="simple-tool-tooltip">
|
||||
<div class="tooltip-content">
|
||||
<p class="tooltip-desc">{{ tool.desc }}</p>
|
||||
<p class="tooltip-url">{{ tool.url }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -87,7 +92,7 @@ export default {
|
||||
superCategories: [],
|
||||
categories: [],
|
||||
activeSuperCategoryId: null, // 当前Tab的大分类ID
|
||||
viewMode: 'colorful' // 'colorful' 或 'simple'
|
||||
viewMode: 'simple' // 'colorful' 或 'simple'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -345,7 +350,7 @@ export default {
|
||||
}
|
||||
|
||||
.workbench-container {
|
||||
max-width: 1920px;
|
||||
max-width: 1820px;
|
||||
margin: 0 auto;
|
||||
padding: @spacing-md;
|
||||
padding-top: 89px; // 为固定的 Tab 区域预留空间 (76px标题栏 + 20px上边距 + 40px Tab高度)
|
||||
@@ -601,6 +606,7 @@ export default {
|
||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||
backdrop-filter: blur(10px);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
.simple-tool-name {
|
||||
font-size: 15px;
|
||||
@@ -608,6 +614,7 @@ export default {
|
||||
color: @text-primary;
|
||||
white-space: nowrap;
|
||||
letter-spacing: 0.3px;
|
||||
position: relative;
|
||||
|
||||
// 文字渐变效果
|
||||
background: linear-gradient(135deg, #333 0%, #555 100%);
|
||||
@@ -616,11 +623,64 @@ export default {
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
// 悬浮提示框
|
||||
.simple-tool-tooltip {
|
||||
position: absolute;
|
||||
bottom: calc(100% + 10px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%) translateY(5px);
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.15s ease-out;
|
||||
pointer-events: none;
|
||||
z-index: 1001;
|
||||
|
||||
.tooltip-content {
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
backdrop-filter: blur(10px);
|
||||
color: @text-primary;
|
||||
padding: 4px 8px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(102, 126, 234, 0.2);
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
|
||||
// 小三角
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border: 6px solid transparent;
|
||||
border-top-color: rgba(255, 255, 255, 0.98);
|
||||
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
|
||||
.tooltip-desc {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
margin: 0 0 4px;
|
||||
line-height: 1.4;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.tooltip-url {
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
font-family: 'Consolas', 'Monaco', monospace;
|
||||
color: #667eea;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-3px) scale(1.02);
|
||||
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.25);
|
||||
background: white;
|
||||
border-color: rgba(102, 126, 234, 0.3);
|
||||
z-index: 999;
|
||||
|
||||
.simple-tool-name {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
@@ -628,6 +688,12 @@ export default {
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.simple-tool-tooltip {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
@@ -968,7 +1034,10 @@ export default {
|
||||
}
|
||||
|
||||
.tool-card-simple {
|
||||
// 手机端已移除提示框
|
||||
// 手机端禁用提示框
|
||||
.simple-tool-tooltip {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.tool-icon {
|
||||
|
||||
@@ -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