Files
intc-workbenches/src/views/ManagePage.vue
2025-12-12 23:36:28 +08:00

1283 lines
33 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<page class="manage-page">
<div class="manage-header">
<h1>管理数据</h1>
<button class="back-btn" @click="goBack">返回工作台</button>
</div>
<div class="manage-container">
<!-- 分类管理 -->
<div class="manage-section">
<div class="section-header">
<h2>分类管理</h2>
<button class="add-btn" @click="showAddCategoryDialog">+ 添加分类</button>
</div>
<div class="category-list">
<div v-for="category in categories" :key="category.id" class="category-item">
<div class="category-info">
<span class="category-key">{{ category.key }}</span>
<span class="category-name">{{ category.title }}</span>
<span class="category-sort">排序: {{ category.sortOrder }}</span>
</div>
<div class="category-footer">
<span class="category-count">{{ category.tools ? category.tools.length : 0 }} 个网址</span>
<div class="category-actions">
<button class="edit-btn" @click="editCategory(category)">编辑</button>
<button class="delete-btn" @click="deleteCategory(category)">删除</button>
</div>
</div>
</div>
</div>
</div>
<!-- 网址管理 -->
<div class="manage-section">
<div class="section-header">
<h2>网址管理</h2>
</div>
<div v-for="category in categories" :key="category.id" class="tool-group">
<div class="tool-group-header">
<h3>{{ category.title }}</h3>
<button class="add-btn small" @click="showAddToolDialog(category)">+ 添加网址</button>
</div>
<div class="tool-list">
<div v-for="tool in category.tools" :key="tool.id" class="tool-item">
<div class="tool-main">
<div class="tool-icon" :style="{background: tool.color}">
<span>{{ tool.icon }}</span>
</div>
<div class="tool-info">
<div class="tool-name">{{ tool.name }}</div>
<div class="tool-desc">{{ tool.desc }}</div>
</div>
<span class="tool-sort">排序: {{ tool.sortOrder || 0 }}</span>
</div>
<div class="tool-footer">
<div class="tool-url">{{ tool.url }}</div>
<div class="tool-actions">
<button class="edit-btn" @click="editTool(category, tool)">编辑</button>
<button class="delete-btn" @click="deleteTool(category, tool)">删除</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 分类编辑对话框 -->
<div v-if="showCategoryDialog" class="dialog-overlay" @click="closeCategoryDialog">
<div class="dialog" @click.stop>
<h3>{{ categoryForm.id ? '编辑分类' : '添加分类' }}</h3>
<div class="form-group">
<label><span class="required">*</span>分类标识</label>
<input v-model="categoryForm.key" placeholder="例如doc" :disabled="!!categoryForm.id" />
</div>
<div class="form-group">
<label><span class="required">*</span>分类名称</label>
<input v-model="categoryForm.title" placeholder="例如:智聪科技" />
</div>
<div class="form-group">
<label>排序序号</label>
<input v-model.number="categoryForm.sortOrder" type="number" placeholder="数字越小越靠前例如0" />
</div>
<div class="dialog-actions">
<button class="cancel-btn" @click="closeCategoryDialog">取消</button>
<button class="confirm-btn" @click="saveCategory">保存</button>
</div>
</div>
</div>
<!-- 工具编辑对话框 -->
<div v-if="showToolDialog" class="dialog-overlay" @click="closeToolDialog">
<div class="dialog" @click.stop>
<h3>{{ toolForm.id ? '编辑网址' : '添加网址' }}</h3>
<div class="form-group">
<label><span class="required">*</span>访问地址</label>
<input v-model="toolForm.url" placeholder="例如https://www.qdintc.com" />
</div>
<div class="form-group">
<label><span class="required">*</span>网址名称</label>
<input v-model="toolForm.name" placeholder="例如:智聪官网" />
</div>
<div class="form-group">
<label>网址描述</label>
<input v-model="toolForm.desc" placeholder="例如:智聪官网" />
</div>
<div class="form-group">
<label>显示地址</label>
<input v-model="toolForm.displayUrl" placeholder="例如www.qdintc.com" />
</div>
<div class="form-group">
<label>图标文字</label>
<input v-model="toolForm.icon" placeholder="例如:官" maxlength="4" />
</div>
<div class="form-group">
<label>图标颜色</label>
<div class="color-picker">
<div
v-for="(colorOption, index) in colorOptions"
:key="index"
class="color-option"
:class="{ active: toolForm.color === colorOption.value }"
:style="{ background: colorOption.value }"
@click="toolForm.color = colorOption.value"
:title="colorOption.name"
>
<span v-if="toolForm.color === colorOption.value" class="check-icon"></span>
</div>
</div>
</div>
<div class="form-group">
<label>排序序号</label>
<input v-model.number="toolForm.sortOrder" type="number" placeholder="数字越小越靠前例如0" />
</div>
<div class="dialog-actions">
<button class="cancel-btn" @click="closeToolDialog">取消</button>
<button class="confirm-btn" @click="saveTool">保存</button>
</div>
</div>
</div>
<!-- 确认对话框 -->
<div v-if="showConfirmDialog" class="dialog-overlay" @click="cancelConfirm">
<div class="confirm-dialog" @click.stop>
<div class="confirm-icon warning"></div>
<div class="confirm-message">{{ confirmMessage }}</div>
<div class="confirm-actions">
<button class="cancel-btn" @click="cancelConfirm">取消</button>
<button class="confirm-btn danger" @click="confirmAction">确定</button>
</div>
</div>
</div>
<!-- 消息提示 -->
<transition name="message-fade">
<div v-if="message.show" :class="['message-toast', message.type]">
<span class="message-icon">{{ messageIcon }}</span>
<span class="message-text">{{ message.text }}</span>
</div>
</transition>
</page>
</template>
<script>
import Page from '../components/Page'
import ToolService from '../services/ToolService'
export default {
name: 'ManagePage',
components: { Page },
data() {
return {
loading: false,
categories: [],
showCategoryDialog: false,
showToolDialog: false,
showConfirmDialog: false,
confirmMessage: '',
confirmCallback: null,
message: {
show: false,
text: '',
type: 'success' // success, error, warning
},
colorOptions: [
{ name: '粉色', value: 'linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%)' },
{ name: '蓝色', value: 'linear-gradient(135deg, #a1c4fd 0%, #c2e9fb 100%)' },
{ name: '紫色', value: 'linear-gradient(135deg, #d299c2 0%, #fef9d7 100%)' },
{ name: '绿色', value: 'linear-gradient(135deg, #96fbc4 0%, #f9f586 100%)' },
{ name: '橙色', value: 'linear-gradient(135deg, #ff9966 0%, #ff5e62 100%)' },
{ name: '红黄', value: 'linear-gradient(135deg, #fa709a 0%, #fee140 100%)' },
{ name: '紫蓝', value: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' },
{ name: '青色', value: 'linear-gradient(135deg, #84fab0 0%, #8fd3f4 100%)' },
{ name: '蓝绿', value: 'linear-gradient(135deg, #a8edea 0%, #fed6e3 100%)' },
{ name: '深紫', value: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' },
{ name: '粉蓝', value: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)' },
{ name: '深绿', value: 'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)' },
{ name: '淡紫', value: 'linear-gradient(135deg, #fbc2eb 0%, #a6c1ee 100%)' },
{ name: '天蓝', value: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)' },
{ name: '淡青', value: 'linear-gradient(135deg, #89f7fe 0%, #66a6ff 100%)' },
{ name: '金黄', value: 'linear-gradient(135deg, #f8b500 0%, #fceabb 100%)' },
{ name: '橙红', value: 'linear-gradient(135deg, #e43a15 0%, #e65245 100%)' },
{ name: '绿青', value: 'linear-gradient(135deg, #0ba360 0%, #3cba92 100%)' },
{ name: '翠绿', value: 'linear-gradient(135deg, #38ef7d 0%, #11998e 100%)' },
{ name: '深蓝', value: 'linear-gradient(135deg, #2af598 0%, #009efd 100%)' },
{ name: '粉红', value: 'linear-gradient(135deg, #f77062 0%, #fe5196 100%)' },
{ name: '橙粉', value: 'linear-gradient(135deg, #ee0979 0%, #ff6a00 100%)' },
{ name: '淡粉', value: 'linear-gradient(135deg, #fdcbf1 0%, #e6dee9 100%)' },
{ name: '深青', value: 'linear-gradient(135deg, #a8c0ff 0%, #3f2b96 100%)' },
{ name: '淡黄', value: 'linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%)' },
{ name: '淡蓝', value: 'linear-gradient(135deg, #accbee 0%, #e7f0fd 100%)' }
],
categoryForm: {
id: null,
key: '',
title: '',
sortOrder: 0
},
toolForm: {
id: null,
categoryKey: '',
name: '',
desc: '',
url: '',
displayUrl: '',
icon: '',
color: 'linear-gradient(135deg, #a1c4fd 0%, #c2e9fb 100%)',
sortOrder: 0
},
currentCategory: null
}
},
computed: {
messageIcon() {
const icons = {
success: '✓',
error: '✕',
warning: '⚠'
}
return icons[this.message.type] || '✓'
}
},
created() {
this.loadData()
},
methods: {
// 消息提示
showMessage(text, type = 'success') {
this.message = { show: true, text, type }
setTimeout(() => {
this.message.show = false
}, 3000)
},
// 确认对话框
showConfirm(message, callback) {
this.confirmMessage = message
this.confirmCallback = callback
this.showConfirmDialog = true
},
confirmAction() {
if (this.confirmCallback) {
this.confirmCallback()
}
this.showConfirmDialog = false
this.confirmCallback = null
},
cancelConfirm() {
this.showConfirmDialog = false
this.confirmCallback = null
},
goBack() {
this.$router.push('/')
},
async loadData() {
try {
this.loading = true
const [categoriesRes, toolsRes] = await Promise.all([
ToolService.getCategories(),
ToolService.getTools()
])
if (categoriesRes && categoriesRes.code === 200 && toolsRes && toolsRes.code === 200) {
const categories = (categoriesRes.rows || []).map(cat => ({
id: cat.id,
key: cat.categoryKey,
title: cat.categoryTitle,
sortOrder: cat.sortOrder || 0,
tools: []
}))
const tools = (toolsRes.rows || []).map(tool => ({
id: tool.id,
categoryId: tool.categoryId,
name: tool.name,
desc: tool.description,
url: tool.url,
displayUrl: tool.displayUrl,
icon: tool.icon,
color: tool.color
}))
tools.forEach(tool => {
const category = categories.find(cat => cat.id === tool.categoryId)
if (category) {
category.tools.push(tool)
}
})
categories.sort((a, b) => a.sortOrder - b.sortOrder)
this.categories = categories
}
} catch (error) {
console.error('加载数据异常:', error)
this.showMessage('加载数据失败', 'error')
} finally {
this.loading = false
}
},
// 分类管理
showAddCategoryDialog() {
this.categoryForm = {
id: null,
key: '',
title: '',
sortOrder: this.categories.length
}
this.showCategoryDialog = true
},
editCategory(category) {
this.categoryForm = {
id: category.id,
key: category.key,
title: category.title,
sortOrder: category.sortOrder
}
this.showCategoryDialog = true
},
closeCategoryDialog() {
this.showCategoryDialog = false
},
saveCategory() {
if (!this.categoryForm.key) {
this.showMessage('请填写分类标识', 'warning')
return
}
if (!this.categoryForm.title) {
this.showMessage('请填写分类名称', 'warning')
return
}
if (this.categoryForm.id) {
this.updateCategoryToServer()
} else {
if (this.categories.find(c => c.key === this.categoryForm.key)) {
this.showMessage('分类标识已存在,请使用其他标识', 'warning')
return
}
this.addCategoryToServer()
}
},
async addCategoryToServer() {
try {
const data = {
categoryKey: this.categoryForm.key,
categoryTitle: this.categoryForm.title,
sortOrder: this.categoryForm.sortOrder
}
const response = await ToolService.createCategory(data)
if (response && response.code === 200) {
this.showMessage('添加成功')
this.closeCategoryDialog()
this.loadData()
} else {
this.showMessage('添加失败:' + (response.msg || '未知错误'), 'error')
}
} catch (error) {
console.error('添加分类失败:', error)
this.showMessage('添加失败,请检查网络连接', 'error')
}
},
async updateCategoryToServer() {
try {
const response = await ToolService.updateCategory({
id: this.categoryForm.id,
categoryKey: this.categoryForm.key,
categoryTitle: this.categoryForm.title,
sortOrder: this.categoryForm.sortOrder
})
if (response && response.code === 200) {
this.showMessage('修改成功')
this.closeCategoryDialog()
this.loadData()
} else {
this.showMessage('修改失败:' + (response.msg || '未知错误'), 'error')
}
} catch (error) {
console.error('修改分类失败:', error)
this.showMessage('修改失败,请检查网络连接', 'error')
}
},
deleteCategory(category) {
const message = category.tools && category.tools.length > 0
? `该分类下还有 ${category.tools.length} 个网址,确定要删除"${category.title}"吗?`
: `确定要删除分类"${category.title}"吗?`
this.showConfirm(message, () => {
this.deleteCategoryFromServer(category.id)
})
},
async deleteCategoryFromServer(id) {
try {
const response = await ToolService.deleteCategory([id])
if (response && response.code === 200) {
this.showMessage('删除成功')
this.loadData()
} else {
this.showMessage('删除失败:' + (response.msg || '未知错误'), 'error')
}
} catch (error) {
console.error('删除分类失败:', error)
this.showMessage('删除失败,请检查网络连接', 'error')
}
},
// 工具管理
showAddToolDialog(category) {
this.currentCategory = category
this.toolForm = {
id: null,
categoryKey: category.key,
name: '',
desc: '',
url: '',
displayUrl: '',
icon: '',
color: 'linear-gradient(135deg, #a1c4fd 0%, #c2e9fb 100%)',
sortOrder: category.tools.length
}
this.showToolDialog = true
},
editTool(category, tool) {
this.currentCategory = category
this.toolForm = {
id: tool.id,
categoryKey: category.key,
name: tool.name,
desc: tool.desc,
url: tool.url,
displayUrl: tool.displayUrl,
icon: tool.icon,
color: tool.color,
sortOrder: tool.sortOrder || 0
}
this.showToolDialog = true
},
closeToolDialog() {
this.showToolDialog = false
this.currentCategory = null
},
saveTool() {
if (!this.toolForm.name) {
this.showMessage('请填写网址名称', 'warning')
return
}
if (!this.toolForm.url) {
this.showMessage('请填写访问地址', 'warning')
return
}
// 验证URL格式
if (!this.isValidUrl(this.toolForm.url)) {
this.showMessage('请输入完整的URL地址必须以http://或https://开头', 'warning')
return
}
if (this.toolForm.id) {
this.updateToolToServer()
} else {
if (this.currentCategory.tools.find(t => t.name === this.toolForm.name)) {
this.showMessage('该分类下已存在同名网址,请使用其他名称', 'warning')
return
}
this.addToolToServer()
}
},
// 验证URL格式
isValidUrl(url) {
if (!url) return false
return url.startsWith('http://') || url.startsWith('https://')
},
async addToolToServer() {
try {
const response = await ToolService.createTool({
categoryId: this.currentCategory.id,
name: this.toolForm.name,
description: this.toolForm.desc,
url: this.toolForm.url,
displayUrl: this.toolForm.displayUrl,
icon: this.toolForm.icon,
color: this.toolForm.color,
sortOrder: this.toolForm.sortOrder
})
if (response && response.code === 200) {
this.showMessage('添加成功')
this.closeToolDialog()
this.loadData()
} else {
this.showMessage('添加失败:' + (response.msg || '未知错误'), 'error')
}
} catch (error) {
console.error('添加工具失败:', error)
this.showMessage('添加失败,请检查网络连接', 'error')
}
},
async updateToolToServer() {
try {
const response = await ToolService.updateTool({
id: this.toolForm.id,
categoryId: this.currentCategory.id,
name: this.toolForm.name,
description: this.toolForm.desc,
url: this.toolForm.url,
displayUrl: this.toolForm.displayUrl,
icon: this.toolForm.icon,
color: this.toolForm.color,
sortOrder: this.toolForm.sortOrder
})
if (response && response.code === 200) {
this.showMessage('修改成功')
this.closeToolDialog()
this.loadData()
} else {
this.showMessage('修改失败:' + (response.msg || '未知错误'), 'error')
}
} catch (error) {
console.error('修改工具失败:', error)
this.showMessage('修改失败,请检查网络连接', 'error')
}
},
deleteTool(category, tool) {
this.showConfirm(`确定要删除网址"${tool.name}"吗?`, () => {
this.deleteToolFromServer(tool.id)
})
},
async deleteToolFromServer(id) {
try {
const response = await ToolService.deleteTool([id])
if (response && response.code === 200) {
this.showMessage('删除成功')
this.loadData()
} else {
this.showMessage('删除失败:' + (response.msg || '未知错误'), 'error')
}
} catch (error) {
console.error('删除工具失败:', error)
this.showMessage('删除失败,请检查网络连接', 'error')
}
}
}
}
</script>
<style scoped lang="less">
@primary-color: #667eea;
@primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
@text-primary: #333;
@text-secondary: #666;
@text-tertiary: #999;
@border-color: #dcdfe6;
@white-color: #fff;
.manage-page {
min-height: 100vh;
background: @primary-gradient;
padding-top: 64px; // 为固定头部预留空间
}
.manage-header {
position: fixed;
top: 0;
left: 0;
right: 0;
background: @primary-gradient;
padding: 20px 40px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
justify-content: center; // PC端居中
align-items: center;
z-index: 1000;
h1 {
margin: 0;
font-size: 36px; // 与HomePage保持一致
color: @white-color;
font-weight: 800; // 与HomePage保持一致
text-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
letter-spacing: 2px; // 添加字母间距
}
.back-btn {
position: absolute; // 绝对定位避免遮挡标题
right: 40px;
padding: 12px 28px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
border-radius: 12px;
color: white;
font-size: 15px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
// 返回图标
&::before {
content: '◄';
margin-right: 8px;
font-size: 14px;
display: inline-block;
transition: transform 0.3s ease;
}
&:hover {
transform: translateY(-3px);
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.5);
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
&::before {
transform: translateX(-4px);
}
}
&:active {
transform: translateY(-1px);
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
}
}
}
.manage-container {
padding: 20px 8px;
}
.manage-section {
background: white;
border-radius: 12px;
padding: 20px 12px;
margin-bottom: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 16px;
border-bottom: 2px solid #f0f0f0;
h2 {
margin: 0;
font-size: 20px;
color: @text-primary;
}
}
}
// 统一的添加按钮样式
.add-btn {
padding: 8px 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
border-radius: 8px;
color: white;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
&:hover {
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4);
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
}
&:active {
transform: translateY(0);
}
&.small {
padding: 6px 16px;
font-size: 13px;
}
}
.category-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 10px;
.category-item {
display: flex;
flex-direction: column;
gap: 8px;
padding: 12px;
background: #f9fafb;
border-radius: 6px;
border: 1px solid #e5e7eb;
transition: all 0.2s ease;
&:hover {
background: #f3f4f6;
border-color: @primary-color;
}
.category-info {
display: flex;
align-items: center;
gap: 8px;
.category-key {
padding: 3px 10px;
background: @primary-color;
color: white;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
white-space: nowrap;
}
.category-name {
font-size: 14px;
color: @text-primary;
font-weight: 500;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.category-sort {
font-size: 12px;
color: @primary-color;
background: rgba(102, 126, 234, 0.1);
padding: 2px 8px;
border-radius: 4px;
white-space: nowrap;
font-weight: 500;
}
}
.category-footer {
display: flex;
justify-content: space-between;
align-items: center;
.category-count {
font-size: 12px;
color: @text-tertiary;
white-space: nowrap;
}
.category-actions {
display: flex;
gap: 6px;
}
}
}
}
.tool-group {
margin-bottom: 24px;
&:last-child {
margin-bottom: 0;
}
.tool-group-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
padding: 12px 16px;
background: #f9fafb;
border-radius: 6px;
h3 {
margin: 0;
font-size: 16px;
color: @text-primary;
}
}
.tool-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 10px;
.tool-item {
display: flex;
flex-direction: column;
gap: 8px;
padding: 10px;
background: #fafafa;
border-radius: 6px;
border: 1px solid #e5e7eb;
transition: all 0.2s ease;
&:hover {
background: #f3f4f6;
border-color: @primary-color;
}
.tool-main {
display: flex;
align-items: center;
gap: 10px;
.tool-icon {
width: 36px;
height: 36px;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
color: white;
font-weight: bold;
flex-shrink: 0;
}
.tool-info {
flex: 1;
min-width: 0;
.tool-name {
font-size: 13px;
font-weight: 500;
color: @text-primary;
margin-bottom: 2px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tool-desc {
font-size: 11px;
color: @text-secondary;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.tool-sort {
font-size: 11px;
color: @primary-color;
background: rgba(102, 126, 234, 0.1);
padding: 2px 8px;
border-radius: 4px;
white-space: nowrap;
font-weight: 500;
flex-shrink: 0;
}
}
.tool-footer {
display: flex;
justify-content: space-between;
align-items: center;
gap: 8px;
.tool-url {
font-size: 10px;
color: @text-tertiary;
font-family: 'Consolas', monospace;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
}
.tool-actions {
display: flex;
gap: 6px;
flex-shrink: 0;
}
}
}
}
}
button {
&.edit-btn {
padding: 5px 10px;
background: #409eff;
border: none;
border-radius: 4px;
color: white;
font-size: 12px;
cursor: pointer;
transition: all 0.2s ease;
&:hover {
background: #66b1ff;
}
}
&.delete-btn {
padding: 5px 10px;
background: #f56c6c;
border: none;
border-radius: 4px;
color: white;
font-size: 12px;
cursor: pointer;
transition: all 0.2s ease;
&:hover {
background: #f78989;
}
}
}
// 对话框样式
.dialog-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 2000;
.dialog {
background: white;
border-radius: 12px;
padding: 24px;
width: 90%;
max-width: 500px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
h3 {
margin: 0 0 20px;
font-size: 20px;
color: @text-primary;
}
.form-group {
margin-bottom: 16px;
label {
display: block;
margin-bottom: 8px;
font-size: 14px;
color: @text-secondary;
font-weight: 500;
.required {
color: #f56c6c;
margin-right: 4px;
}
}
input, select {
width: 100%;
padding: 10px 12px;
border: 1px solid @border-color;
border-radius: 6px;
font-size: 14px;
box-sizing: border-box;
transition: border-color 0.2s ease;
&:focus {
outline: none;
border-color: @primary-color;
}
&:disabled {
background: #f5f7fa;
color: #999;
cursor: not-allowed;
}
}
select {
cursor: pointer;
}
}
// 颜色选择器样式
.color-picker {
display: grid;
grid-template-columns: repeat(8, 1fr);
gap: 8px;
padding: 0 2px;
.color-option {
width: 100%;
aspect-ratio: 1;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s ease;
border: 3px solid transparent;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
}
&.active {
border-color: @primary-color;
box-shadow: 0 0 0 2px white, 0 0 0 4px @primary-color;
}
.check-icon {
color: white;
font-size: 20px;
font-weight: bold;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
}
}
.dialog-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
margin-top: 24px;
button {
padding: 10px 24px;
border-radius: 6px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s ease;
}
.cancel-btn {
background: white;
border: 1px solid @border-color;
color: @text-primary;
&:hover {
color: @primary-color;
border-color: @primary-color;
}
}
.confirm-btn {
background: @primary-color;
border: none;
color: white;
&:hover {
background: #5568d3;
}
}
}
}
}
// 确认对话框样式
.confirm-dialog {
background: white;
border-radius: 12px;
padding: 32px 24px 24px;
width: 90%;
max-width: 400px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
text-align: center;
.confirm-icon {
font-size: 48px;
margin-bottom: 16px;
&.warning {
color: #e6a23c;
}
}
.confirm-message {
font-size: 16px;
color: @text-primary;
margin-bottom: 24px;
line-height: 1.6;
}
.confirm-actions {
display: flex;
gap: 12px;
justify-content: center;
button {
padding: 10px 32px;
border-radius: 6px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s ease;
min-width: 100px;
}
.cancel-btn {
background: white;
border: 1px solid @border-color;
color: @text-primary;
&:hover {
color: @primary-color;
border-color: @primary-color;
}
}
.confirm-btn {
background: @primary-color;
border: none;
color: white;
&:hover {
background: #5568d3;
}
&.danger {
background: #f56c6c;
&:hover {
background: #f78989;
}
}
}
}
}
// 消息提示样式
.message-toast {
position: fixed;
top: 80px;
left: 50%;
transform: translateX(-50%);
padding: 14px 24px;
border-radius: 8px;
display: flex;
align-items: center;
gap: 10px;
font-size: 14px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
z-index: 3000;
min-width: 300px;
justify-content: center;
.message-icon {
font-size: 18px;
font-weight: bold;
}
&.success {
background: #f0f9ff;
border: 1px solid #67c23a;
color: #67c23a;
.message-icon {
color: #67c23a;
}
}
&.error {
background: #fef0f0;
border: 1px solid #f56c6c;
color: #f56c6c;
.message-icon {
color: #f56c6c;
}
}
&.warning {
background: #fdf6ec;
border: 1px solid #e6a23c;
color: #e6a23c;
.message-icon {
color: #e6a23c;
}
}
}
// 消息提示动画
.message-fade-enter-active,
.message-fade-leave-active {
transition: all 0.3s ease;
}
.message-fade-enter {
opacity: 0;
transform: translate(-50%, -20px);
}
.message-fade-leave-to {
opacity: 0;
transform: translate(-50%, -20px);
}
// 响应式布局 - 手机端
@media (max-width: 600px) {
.manage-header {
justify-content: flex-start; // 手机端左对齐
padding: 20px;
h1 {
font-size: 24px; // 手机端与HomePage保持一致
}
.back-btn {
right: 20px;
padding: 10px 20px;
font-size: 14px;
&::before {
font-size: 12px;
}
}
}
.manage-container {
padding: 16px 8px;
}
.category-list {
grid-template-columns: 1fr !important;
}
.tool-list {
grid-template-columns: 1fr !important;
}
}
</style>