Files
FileCollect/原型/后台管理页面/category-management.html
T
2025-10-20 07:11:14 +08:00

1209 lines
40 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>分类管理 - 图片收集系统</title>
<!-- 引入Vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script>
<!-- 引入Element UI CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-ui@2.15.8/lib/theme-chalk/index.css">
<!-- 引入Element UI JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/element-ui@2.15.8/lib/index.js"></script>
<!-- 引入Font Awesome -->
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- 引入ECharts -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.0/dist/echarts.min.js"></script>
<style>
body {
margin: 0;
padding: 0;
height: 100vh;
background-color: #f0f2f5;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}
.container {
height: 100vh;
display: flex;
}
.sidebar {
width: 220px;
background-color: #001529;
color: white;
display: flex;
flex-direction: column;
}
.sidebar-header {
padding: 20px;
text-align: center;
border-bottom: 1px solid #1f2937;
}
.logo {
font-size: 20px;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
}
.logo-icon {
margin-right: 8px;
font-size: 22px;
}
.menu-item {
padding: 15px 20px;
cursor: pointer;
transition: background-color 0.3s;
display: flex;
align-items: center;
}
.menu-item:hover {
background-color: #1f2937;
}
.menu-item.active {
background-color: #1989fa;
}
.menu-icon {
margin-right: 10px;
font-size: 16px;
}
.main-content {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.header {
background-color: white;
padding: 15px 20px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.header-title {
font-size: 18px;
font-weight: 600;
color: #303133;
}
.header-actions {
display: flex;
align-items: center;
gap: 15px;
}
.user-info {
display: flex;
align-items: center;
}
.user-avatar {
width: 32px;
height: 32px;
border-radius: 50%;
background-color: #1989fa;
color: white;
display: flex;
align-items: center;
justify-content: center;
margin-right: 8px;
font-size: 14px;
}
.user-name {
color: #606266;
}
.content-wrapper {
flex: 1;
padding: 20px;
overflow-y: auto;
}
.card {
background-color: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
margin-bottom: 20px;
}
.search-section {
display: flex;
gap: 15px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.search-input {
width: 300px;
}
.table-wrapper {
overflow-x: auto;
}
.table-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.table-title {
font-size: 16px;
font-weight: 600;
color: #303133;
}
.btn-primary {
background-color: #1989fa;
border-color: #1989fa;
}
.btn-primary:hover {
background-color: #409eff;
border-color: #409eff;
}
.operation-buttons {
display: flex;
gap: 8px;
}
.el-button {
padding: 6px 12px;
font-size: 14px;
}
.dialog-form-item {
margin-bottom: 20px;
}
.dialog-form-label {
font-weight: 500;
color: #303133;
margin-bottom: 8px;
font-size: 14px;
}
.category-card {
background-color: #f5f7fa;
border-radius: 8px;
padding: 20px;
text-align: center;
transition: transform 0.3s, box-shadow 0.3s;
cursor: pointer;
position: relative;
}
.category-card:hover {
transform: translateY(-5px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.category-icon {
width: 64px;
height: 64px;
border-radius: 50%;
background-color: #ecf5ff;
color: #1989fa;
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
margin: 0 auto 15px;
}
.category-name {
font-size: 18px;
font-weight: 600;
color: #303133;
margin-bottom: 10px;
}
.category-count {
font-size: 24px;
font-weight: 600;
color: #1989fa;
margin-bottom: 5px;
}
.category-desc {
font-size: 12px;
color: #909399;
}
.category-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
}
.chart-container {
height: 300px;
width: 100%;
}
.logout-btn {
cursor: pointer;
color: #606266;
transition: color 0.3s;
}
.logout-btn:hover {
color: #f56c6c;
}
.color-preview {
display: inline-block;
width: 30px;
height: 30px;
border-radius: 4px;
margin-right: 10px;
border: 1px solid #dcdfe6;
}
.icon-preview {
font-size: 24px;
margin-right: 10px;
}
.category-settings {
position: absolute;
top: 10px;
right: 10px;
opacity: 0;
transition: opacity 0.3s;
}
.category-card:hover .category-settings {
opacity: 1;
}
.settings-btn {
width: 32px;
height: 32px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(255, 255, 255, 0.8);
color: #606266;
margin-left: 5px;
cursor: pointer;
}
.settings-btn:hover {
background-color: white;
color: #1989fa;
}
.settings-dropdown {
position: absolute;
top: 40px;
right: 0;
background-color: white;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 1000;
width: 120px;
padding: 5px 0;
}
.dropdown-item {
padding: 10px 15px;
font-size: 14px;
color: #606266;
cursor: pointer;
transition: background-color 0.3s;
}
.dropdown-item:hover {
background-color: #f5f7fa;
color: #1989fa;
}
.dropdown-item.danger:hover {
color: #f56c6c;
}
.image-preview-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 10px;
}
.image-thumb {
width: 60px;
height: 60px;
object-fit: cover;
border-radius: 4px;
border: 1px solid #dcdfe6;
}
.tab-content {
padding: 20px 0;
}
</style>
</head>
<body>
<div id="app">
<div class="container">
<!-- 侧边栏 -->
<div class="sidebar">
<div class="sidebar-header">
<div class="logo">
<i class="fa fa-tachometer logo-icon"></i>
<span>管理平台</span>
</div>
</div>
<div class="menu-item" @click="navigateTo('department')">
<i class="fa fa-building-o menu-icon"></i>
<span>部门管理</span>
</div>
<div class="menu-item" @click="navigateTo('user')">
<i class="fa fa-users menu-icon"></i>
<span>用户管理</span>
</div>
<div class="menu-item" @click="navigateTo('task')">
<i class="fa fa-tasks menu-icon"></i>
<span>任务管理</span>
</div>
<div class="menu-item" @click="navigateTo('image')">
<i class="fa fa-picture-o menu-icon"></i>
<span>图片管理</span>
</div>
<div class="menu-item active" @click="navigateTo('category')">
<i class="fa fa-th-large menu-icon"></i>
<span>分类管理</span>
</div>
</div>
<!-- 主内容区 -->
<div class="main-content">
<!-- 顶部导航栏 -->
<div class="header">
<div class="header-title">分类管理</div>
<div class="header-actions">
<div class="user-info">
<div class="user-avatar"></div>
<span class="user-name">系统管理员</span>
</div>
<div class="logout-btn" @click="handleLogout">
<i class="fa fa-sign-out"></i> 退出
</div>
</div>
</div>
<!-- 内容区域 -->
<div class="content-wrapper">
<!-- 统计卡片 -->
<div class="card">
<div class="search-section">
<el-tabs v-model="activeTab">
<el-tab-pane label="列表管理" name="list">
<div class="search-section" style="margin-bottom: 0;">
<el-input
v-model="searchQuery"
placeholder="搜索分类名称或描述"
prefix-icon="el-icon-search"
class="search-input"
></el-input>
<el-button
type="primary"
class="btn-primary"
@click="showAddCategoryDialog"
>
<i class="fa fa-plus"></i> 新增分类
</el-button>
</div>
</el-tab-pane>
<el-tab-pane label="分类概览" name="overview">
<div class="search-section" style="margin-bottom: 0;">
<el-input
v-model="searchQuery"
placeholder="搜索分类名称"
prefix-icon="el-icon-search"
class="search-input"
></el-input>
</div>
</el-tab-pane>
</el-tabs>
</div>
</div>
<!-- 分类统计图表 -->
<div v-if="activeTab === 'overview'" class="card">
<h3 style="margin-bottom: 20px; color: #303133;">分类统计图表</h3>
<div id="categoryChart" class="chart-container"></div>
</div>
<!-- 分类列表 -->
<div v-if="activeTab === 'list'" class="card">
<div class="tab-content">
<div class="table-wrapper">
<el-table
:data="filteredCategories"
stripe
style="width: 100%"
>
<el-table-column prop="id" label="分类ID" width="80"></el-table-column>
<el-table-column label="图标" width="80">
<template slot-scope="scope">
<div class="icon-preview" :style="{ color: scope.row.color }">
<i :class="['fa', scope.row.icon]"></i>
</div>
</template>
</el-table-column>
<el-table-column prop="name" label="分类名称" width="180"></el-table-column>
<el-table-column prop="description" label="分类描述" min-width="200"></el-table-column>
<el-table-column prop="imageCount" label="图片数量" width="100">
<template slot-scope="scope">
<span style="color: #1989fa; font-weight: 600;">{{ scope.row.imageCount }}</span>
</template>
</el-table-column>
<el-table-column prop="sortOrder" label="排序权重" width="100">
<template slot-scope="scope">
<el-input-number
v-model="scope.row.sortOrder"
:min="1"
:max="100"
size="small"
@change="updateSortOrder(scope.row.id, scope.row.sortOrder)"
></el-input-number>
</template>
</el-table-column>
<el-table-column prop="isActive" label="状态" width="80">
<template slot-scope="scope">
<el-switch
v-model="scope.row.isActive"
active-text="启用"
inactive-text="禁用"
@change="updateStatus(scope.row.id, scope.row.isActive)"
></el-switch>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" min-width="150">
<template slot-scope="scope">
{{ formatDateTime(scope.row.createTime) }}
</template>
</el-table-column>
<el-table-column label="操作" width="180" fixed="right">
<template slot-scope="scope">
<div class="operation-buttons">
<el-button
type="primary"
size="small"
@click="viewCategoryDetail(scope.row)"
>
详情
</el-button>
<el-button
type="warning"
size="small"
@click="editCategory(scope.row)"
>
编辑
</el-button>
<el-button
type="danger"
size="small"
@click="deleteCategory(scope.row.id)"
:disabled="scope.row.imageCount > 0"
>
删除
</el-button>
</div>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
<!-- 分类概览网格 -->
<div v-else-if="activeTab === 'overview'" class="card">
<div class="tab-content">
<div class="category-grid">
<div
v-for="category in filteredCategories"
:key="category.id"
class="category-card"
>
<div class="category-icon" :style="{ backgroundColor: getCategoryBgColor(category.color), color: category.color }">
<i :class="['fa', category.icon]"></i>
</div>
<div class="category-name">{{ category.name }}</div>
<div class="category-count">{{ category.imageCount }}</div>
<div class="category-desc">
{{ category.description }}<br>
<span v-if="!category.isActive" style="color: #f56c6c;">(已禁用)</span>
</div>
<!-- 分类设置按钮 -->
<div class="category-settings">
<div class="settings-btn" @click.stop="showSettingsMenu(category, $event)">
<i class="fa fa-ellipsis-v"></i>
</div>
<!-- 设置下拉菜单 -->
<div
v-if="settingsMenuVisible && settingsMenuCategory.id === category.id"
class="settings-dropdown"
@click.stop
>
<div class="dropdown-item" @click="viewCategoryDetail(category)">
<i class="fa fa-eye"></i> 查看详情
</div>
<div class="dropdown-item" @click="editCategory(category)">
<i class="fa fa-pencil"></i> 编辑分类
</div>
<div class="dropdown-item danger" @click="deleteCategory(category.id)" :class="{ disabled: category.imageCount > 0 }" :style="{ opacity: category.imageCount > 0 ? 0.5 : 1, cursor: category.imageCount > 0 ? 'not-allowed' : 'pointer' }">
<i class="fa fa-trash"></i> 删除分类
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 添加/编辑分类对话框 -->
<el-dialog
:title="dialogTitle"
:visible.sync="showDialog"
width="600px"
>
<el-form :model="categoryForm" :rules="categoryRules" ref="categoryForm" label-width="100px">
<el-form-item label="分类名称" prop="name">
<el-input v-model="categoryForm.name" placeholder="请输入分类名称"></el-input>
</el-form-item>
<el-form-item label="分类描述" prop="description">
<el-input
v-model="categoryForm.description"
type="textarea"
placeholder="请输入分类描述"
:rows="3"
></el-input>
</el-form-item>
<el-form-item label="分类图标" prop="icon">
<el-select v-model="categoryForm.icon" placeholder="请选择分类图标" style="width: 200px;">
<el-option
v-for="icon in availableIcons"
:key="icon.value"
:label="`${icon.label} <i class=\"fa ${icon.value}\"></i>`"
:value="icon.value"
></el-option>
</el-select>
<div v-if="categoryForm.icon" class="icon-preview" :style="{ color: categoryForm.color || '#1989fa' }">
<i :class="['fa', categoryForm.icon]"></i>
</div>
</el-form-item>
<el-form-item label="分类颜色" prop="color">
<el-color-picker v-model="categoryForm.color" show-alpha></el-color-picker>
<div v-if="categoryForm.color" class="color-preview" :style="{ backgroundColor: categoryForm.color }"></div>
</el-form-item>
<el-form-item label="排序权重" prop="sortOrder">
<el-input-number
v-model="categoryForm.sortOrder"
:min="1"
:max="100"
placeholder="请输入排序权重"
></el-input-number>
<div style="color: #909399; font-size: 12px; margin-top: 5px;">
数值越小,排序越靠前
</div>
</el-form-item>
<el-form-item label="状态" prop="isActive">
<el-switch v-model="categoryForm.isActive" active-text="启用" inactive-text="禁用"></el-switch>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="cancelDialog">取消</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
</span>
</el-dialog>
<!-- 分类详情对话框 -->
<el-dialog
:title="'分类详情 - ' + categoryDetail.name"
:visible.sync="showCategoryDetail"
width="800px"
>
<div v-if="categoryDetail.id">
<div style="display: flex; align-items: center; margin-bottom: 30px;">
<div class="category-icon" :style="{ backgroundColor: getCategoryBgColor(categoryDetail.color), color: categoryDetail.color, margin: '0 30px 0 0' }">
<i :class="['fa', categoryDetail.icon]"></i>
</div>
<div>
<h2 style="margin: 0 0 10px 0; color: #303133;">{{ categoryDetail.name }}</h2>
<p style="margin: 0 0 10px 0; color: #606266; line-height: 1.6;">{{ categoryDetail.description }}</p>
<div style="display: flex; gap: 30px;">
<div>
<span style="color: #909399;">图片数量:</span>
<span style="color: #1989fa; font-weight: 600; font-size: 18px;">{{ categoryDetail.imageCount }}</span>
</div>
<div>
<span style="color: #909399;">创建时间:</span>
<span>{{ formatDateTime(categoryDetail.createTime) }}</span>
</div>
<div>
<span style="color: #909399;">状态:</span>
<span :style="{ color: categoryDetail.isActive ? '#67c23a' : '#f56c6c' }">
{{ categoryDetail.isActive ? '已启用' : '已禁用' }}
</span>
</div>
</div>
</div>
</div>
<div v-if="categoryDetail.representativeImages && categoryDetail.representativeImages.length > 0">
<h3 style="margin: 0 0 15px 0; color: #303133;">代表性图片</h3>
<div class="image-preview-list">
<img
v-for="(img, index) in categoryDetail.representativeImages"
:key="index"
:src="img.url"
:alt="img.title"
class="image-thumb"
@click="viewImage(img)"
>
</div>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="editCurrentCategory">编辑分类</el-button>
<el-button @click="showCategoryDetail = false">关闭</el-button>
</span>
</el-dialog>
<!-- 查看图片对话框 -->
<el-dialog
:title="selectedImage.title"
:visible.sync="showImageDialog"
width="70%"
fullscreen
>
<div style="text-align: center; padding: 20px;">
<img
:src="selectedImage.url"
:alt="selectedImage.title"
style="max-width: 100%; max-height: 80vh; object-fit: contain;"
>
<p style="margin-top: 20px; color: #606266;">{{ selectedImage.description || '暂无描述' }}</p>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="showImageDialog = false">关闭</el-button>
</span>
</el-dialog>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
searchQuery: '',
activeTab: 'list',
showDialog: false,
dialogTitle: '',
isEditMode: false,
showCategoryDetail: false,
showImageDialog: false,
settingsMenuVisible: false,
settingsMenuCategory: {},
// 可用图标列表
availableIcons: [
{ value: 'fa-image', label: '图片' },
{ value: 'fa-file-image-o', label: '文件' },
{ value: 'fa-camera', label: '相机' },
{ value: 'fa-cube', label: '产品' },
{ value: 'fa-building', label: '建筑' },
{ value: 'fa-users', label: '用户' },
{ value: 'fa-calendar', label: '日历' },
{ value: 'fa-credit-card', label: '信用卡' },
{ value: 'fa-desktop', label: '电脑' },
{ value: 'fa-mobile', label: '手机' },
{ value: 'fa-briefcase', label: '公文包' },
{ value: 'fa-home', label: '家' },
{ value: 'fa-map-marker', label: '位置' },
{ value: 'fa-coffee', label: '咖啡' },
{ value: 'fa-cutlery', label: '餐具' }
],
// 分类表单
categoryForm: {
name: '',
description: '',
icon: 'fa-image',
color: '#1989fa',
sortOrder: 1,
isActive: true
},
// 表单验证规则
categoryRules: {
name: [
{ required: true, message: '请输入分类名称', trigger: 'blur' },
{ min: 1, max: 50, message: '分类名称长度在 1 到 50 个字符之间', trigger: 'blur' }
],
description: [
{ max: 200, message: '分类描述长度不能超过 200 个字符', trigger: 'blur' }
],
icon: [
{ required: true, message: '请选择分类图标', trigger: 'change' }
],
color: [
{ required: true, message: '请选择分类颜色', trigger: 'change' }
],
sortOrder: [
{ required: true, message: '请输入排序权重', trigger: 'blur', type: 'number' }
]
},
// 分类数据
categories: [
{
id: 1,
name: '产品包装',
description: '各类产品的包装设计和实物照片',
icon: 'fa-cube',
color: '#1989fa',
sortOrder: 1,
isActive: true,
imageCount: 15,
createTime: '2023-11-20 09:30:00',
representativeImages: [
{ url: 'https://picsum.photos/id/26/400/300', title: '产品包装正面' },
{ url: 'https://picsum.photos/id/44/400/300', title: '产品包装侧面' },
{ url: 'https://picsum.photos/id/48/400/300', title: '产品包装展示' }
]
},
{
id: 2,
name: '办公环境',
description: '公司办公区域、会议室等环境照片',
icon: 'fa-building',
color: '#67c23a',
sortOrder: 2,
isActive: true,
imageCount: 23,
createTime: '2023-11-21 14:20:00',
representativeImages: [
{ url: 'https://picsum.photos/id/28/400/300', title: '办公区域全景' },
{ url: 'https://picsum.photos/id/45/400/300', title: '会议室' },
{ url: 'https://picsum.photos/id/42/400/300', title: '接待区' }
]
},
{
id: 3,
name: '活动现场',
description: '公司各类活动、展会、团建等现场照片',
icon: 'fa-calendar',
color: '#e6a23c',
sortOrder: 3,
isActive: true,
imageCount: 47,
createTime: '2023-11-22 10:15:00',
representativeImages: [
{ url: 'https://picsum.photos/id/29/400/300', title: '活动现场' },
{ url: 'https://picsum.photos/id/36/400/300', title: '展会布置' },
{ url: 'https://picsum.photos/id/42/400/300', title: '团队合影' }
]
},
{
id: 4,
name: '员工证件',
description: '员工证件照、工作证等照片',
icon: 'fa-users',
color: '#f56c6c',
sortOrder: 4,
isActive: true,
imageCount: 89,
createTime: '2023-11-23 16:45:00',
representativeImages: [
{ url: 'https://picsum.photos/id/33/400/300', title: '员工证件照模板' }
]
},
{
id: 5,
name: '财务凭证',
description: '各类财务发票、收据、报销凭证照片',
icon: 'fa-credit-card',
color: '#909399',
sortOrder: 5,
isActive: true,
imageCount: 64,
createTime: '2023-11-24 11:30:00',
representativeImages: [
{ url: 'https://picsum.photos/id/36/400/300', title: '发票示例' },
{ url: 'https://picsum.photos/id/42/400/300', title: '财务凭证' }
]
},
{
id: 6,
name: 'IT设备',
description: '公司IT设备、服务器、办公电脑等照片',
icon: 'fa-desktop',
color: '#409eff',
sortOrder: 6,
isActive: true,
imageCount: 12,
createTime: '2023-11-25 09:00:00',
representativeImages: [
{ url: 'https://picsum.photos/id/42/400/300', title: '服务器设备' },
{ url: 'https://picsum.photos/id/48/400/300', title: '办公电脑' }
]
},
{
id: 7,
name: '营销物料',
description: '宣传单页、海报、广告牌等营销材料',
icon: 'fa-bullhorn',
color: '#f7ba1e',
sortOrder: 7,
isActive: false,
imageCount: 0,
createTime: '2023-11-26 15:40:00',
representativeImages: []
}
],
categoryDetail: {},
selectedImage: {}
}
},
computed: {
filteredCategories() {
return this.categories
.filter(category => {
return !this.searchQuery ||
category.name.toLowerCase().includes(this.searchQuery.toLowerCase()) ||
category.description.toLowerCase().includes(this.searchQuery.toLowerCase());
})
.sort((a, b) => a.sortOrder - b.sortOrder);
}
},
mounted() {
this.initCharts();
// 点击文档其他地方关闭设置菜单
document.addEventListener('click', this.closeSettingsMenu);
},
beforeDestroy() {
document.removeEventListener('click', this.closeSettingsMenu);
},
methods: {
// 初始化图表
initCharts() {
// 确保 DOM 元素存在再初始化
setTimeout(() => {
const chartDom = document.getElementById('categoryChart');
if (chartDom) {
const categoryChart = echarts.init(chartDom);
const chartData = this.categories
.filter(cat => cat.isActive)
.map(cat => ({
name: cat.name,
value: cat.imageCount,
itemStyle: { color: cat.color }
}))
.sort((a, b) => b.value - a.value);
const option = {
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: '分类图片数量',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '18',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: chartData
}
]
};
categoryChart.setOption(option);
// 监听窗口大小变化
window.addEventListener('resize', () => {
categoryChart.resize();
});
}
}, 100);
},
// 导航到其他页面
navigateTo(page) {
let url = '';
switch (page) {
case 'department':
url = 'department-management.html';
break;
case 'user':
url = 'user-management.html';
break;
case 'task':
url = 'task-management.html';
break;
case 'image':
url = 'image-management.html';
break;
case 'category':
url = 'category-management.html';
break;
}
if (url && url !== window.location.pathname) {
window.location.href = url;
}
},
// 格式化日期时间
formatDateTime(dateStr) {
return dateStr || '';
},
// 获取分类背景颜色(用于图标背景)
getCategoryBgColor(color) {
// 计算颜色的亮度
const rgb = this.hexToRgb(color);
const brightness = (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
// 如果颜色较亮,返回浅色调;如果颜色较暗,返回稍亮的色调
if (brightness > 128) {
return this.adjustBrightness(color, -40);
} else {
return this.adjustBrightness(color, 60);
}
},
// 十六进制转RGB
hexToRgb(hex) {
// 移除 # 号
hex = hex.replace('#', '');
// 解析 RGB 值
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);
return { r, g, b };
},
// 调整颜色亮度
adjustBrightness(hex, percent) {
let r = parseInt(hex.substring(1, 3), 16);
let g = parseInt(hex.substring(3, 5), 16);
let b = parseInt(hex.substring(5, 7), 16);
// 增加或减少亮度
r = Math.floor(r * (100 + percent) / 100);
g = Math.floor(g * (100 + percent) / 100);
b = Math.floor(b * (100 + percent) / 100);
// 确保值在 0-255 范围内
r = (r < 255) ? r : 255;
r = (r > 0) ? r : 0;
g = (g < 255) ? g : 255;
g = (g > 0) ? g : 0;
b = (b < 255) ? b : 255;
b = (b > 0) ? b : 0;
// 转换回十六进制
const rr = ((r.toString(16).length === 1) ? '0' + r.toString(16) : r.toString(16));
const gg = ((g.toString(16).length === 1) ? '0' + g.toString(16) : g.toString(16));
const bb = ((b.toString(16).length === 1) ? '0' + b.toString(16) : b.toString(16));
return '#' + rr + gg + bb;
},
// 显示添加分类对话框
showAddCategoryDialog() {
this.isEditMode = false;
this.dialogTitle = '新增分类';
this.resetForm();
this.showDialog = true;
},
// 编辑分类
editCategory(category) {
this.isEditMode = true;
this.dialogTitle = '编辑分类';
this.categoryForm = { ...category };
this.showDialog = true;
},
// 重置表单
resetForm() {
this.categoryForm = {
name: '',
description: '',
icon: 'fa-image',
color: '#1989fa',
sortOrder: 1,
isActive: true
};
this.$refs.categoryForm && this.$refs.categoryForm.resetFields();
},
// 取消对话框
cancelDialog() {
this.showDialog = false;
this.resetForm();
},
// 提交表单
submitForm() {
this.$refs.categoryForm.validate((valid) => {
if (valid) {
if (this.isEditMode) {
// 编辑模式
const index = this.categories.findIndex(cat => cat.id === this.categoryForm.id);
if (index > -1) {
// 保留图片数量和创建时间
const imageCount = this.categories[index].imageCount;
const createTime = this.categories[index].createTime;
const representativeImages = this.categories[index].representativeImages;
this.categories[index] = {
...this.categoryForm,
imageCount,
createTime,
representativeImages
};
this.$message.success('分类编辑成功');
}
} else {
// 新增模式
const newCategory = {
...this.categoryForm,
id: Date.now(), // 模拟生成ID
imageCount: 0,
createTime: this.formatDateTime(new Date().toLocaleString('zh-CN')),
representativeImages: []
};
this.categories.push(newCategory);
this.$message.success('分类创建成功');
}
this.showDialog = false;
this.resetForm();
// 如果在概览页,重新初始化图表
if (this.activeTab === 'overview') {
this.initCharts();
}
}
});
},
// 删除分类
deleteCategory(categoryId) {
const category = this.categories.find(cat => cat.id === categoryId);
if (!category) return;
// 检查分类下是否有图片
if (category.imageCount > 0) {
this.$message.warning('该分类下还有图片,无法删除');
return;
}
this.$confirm(`确定要删除「${category.name}」分类吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const index = this.categories.findIndex(cat => cat.id === categoryId);
if (index > -1) {
this.categories.splice(index, 1);
this.$message.success('分类删除成功');
// 关闭设置菜单
this.settingsMenuVisible = false;
// 如果在概览页,重新初始化图表
if (this.activeTab === 'overview') {
this.initCharts();
}
}
}).catch(() => {
// 取消删除
});
},
// 更新分类状态
updateStatus(categoryId, isActive) {
const index = this.categories.findIndex(cat => cat.id === categoryId);
if (index > -1) {
this.categories[index].isActive = isActive;
this.$message.success(`分类${isActive ? '已启用' : '已禁用'}`);
// 如果在概览页,重新初始化图表
if (this.activeTab === 'overview') {
this.initCharts();
}
}
},
// 更新排序权重
updateSortOrder(categoryId, sortOrder) {
const index = this.categories.findIndex(cat => cat.id === categoryId);
if (index > -1) {
this.categories[index].sortOrder = sortOrder;
// 这里可以添加保存到服务器的逻辑
}
},
// 查看分类详情
viewCategoryDetail(category) {
this.categoryDetail = { ...category };
this.showCategoryDetail = true;
// 关闭设置菜单
this.settingsMenuVisible = false;
},
// 编辑当前查看的分类
editCurrentCategory() {
this.showCategoryDetail = false;
this.editCategory(this.categoryDetail);
},
// 查看图片
viewImage(image) {
this.selectedImage = { ...image };
this.showImageDialog = true;
},
// 显示设置菜单
showSettingsMenu(category, event) {
event.stopPropagation();
this.settingsMenuCategory = { ...category };
this.settingsMenuVisible = true;
},
// 关闭设置菜单
closeSettingsMenu() {
this.settingsMenuVisible = false;
},
// 处理退出登录
handleLogout() {
this.$confirm('确定要退出登录吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$message.success('退出成功');
setTimeout(() => {
window.location.href = 'admin-login.html';
}, 1000);
}).catch(() => {
// 取消退出
});
}
}
})
</script>
</body>
</html>