- 新增现代化企业协同办公系统,包含概览仪表板、项目管理、任务看板和文档协同 - 使用Vue 3、TypeScript、Nuxt.js及Ant Design Vue实现前端结构和交互 - 设计响应式布局、渐变背景及毛玻璃视觉效果,优化移动端体验 - 创建设备管理页面,实现设备台账、巡检、维修和报警管理 - 新建文档协同页面,支持文档搜索、筛选、分类显示及多种视图切换 - 配置协同办公导航及布局文件,完善模块化和组件化架构 - 修复管理页语法错误,完善演示数据和统计信息展示 - 提供新建、导入、分享、重命名和删除文档等核心操作功能 - 添加设备健康度及维修记录展示模块,方便车间设备管理和维护 - 更新.gitignore忽略输出目录,提升项目环境整洁性
329 lines
17 KiB
Vue
329 lines
17 KiB
Vue
<template>
|
||
<div class="flex min-h-screen bg-gradient-to-br from-gray-50 to-gray-100">
|
||
<aside class="w-64 fixed h-full text-white flex flex-col sidebar">
|
||
<div class="p-6 border-b border-white/10">
|
||
<div class="flex items-center gap-3">
|
||
<div class="w-10 h-10 bg-white/20 rounded-xl flex items-center justify-center">
|
||
<BlockOutlined class="text-xl" />
|
||
</div>
|
||
<div>
|
||
<h1 class="font-bold text-lg">DEMO演示系统</h1>
|
||
<p class="text-xs text-white/70">ERP 管理平台</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<nav class="flex-1 py-6 px-3">
|
||
<div class="space-y-1">
|
||
<NuxtLink to="/" class="sidebar-item flex items-center gap-3 px-4 py-3 rounded-xl cursor-pointer">
|
||
<HomeOutlined class="text-base" /><span>工作台</span>
|
||
</NuxtLink>
|
||
<NuxtLink to="/device" class="sidebar-item flex items-center gap-3 px-4 py-3 rounded-xl cursor-pointer">
|
||
<SettingOutlined class="text-base" /><span>设备管理</span>
|
||
</NuxtLink>
|
||
<NuxtLink to="/procurement" class="sidebar-item flex items-center gap-3 px-4 py-3 rounded-xl cursor-pointer">
|
||
<ShoppingCartOutlined class="text-base" /><span>采购管理</span>
|
||
</NuxtLink>
|
||
<NuxtLink to="/warehouse" class="sidebar-item active flex items-center gap-3 px-4 py-3 rounded-xl cursor-pointer">
|
||
<InboxOutlined class="text-base" /><span>仓储物流</span>
|
||
</NuxtLink>
|
||
<NuxtLink to="/finance" class="sidebar-item flex items-center gap-3 px-4 py-3 rounded-xl cursor-pointer">
|
||
<WalletOutlined class="text-base" /><span>财务管理</span>
|
||
</NuxtLink>
|
||
<NuxtLink to="/hr" class="sidebar-item flex items-center gap-3 px-4 py-3 rounded-xl cursor-pointer">
|
||
<TeamOutlined class="text-base" /><span>人力资源</span>
|
||
</NuxtLink>
|
||
<NuxtLink to="/office" class="sidebar-item flex items-center gap-3 px-4 py-3 rounded-xl cursor-pointer">
|
||
<ProjectOutlined class="text-base" /><span>协同办公</span>
|
||
</NuxtLink>
|
||
</div>
|
||
<div class="mt-8 pt-6 border-t border-white/10">
|
||
<p class="px-4 text-xs text-white/50 mb-3">个人</p>
|
||
<a href="#" class="sidebar-item flex items-center gap-3 px-4 py-3 rounded-xl cursor-pointer">
|
||
<UserOutlined class="text-base" /><span>个人信息</span>
|
||
</a>
|
||
<a href="#" class="sidebar-item flex items-center gap-3 px-4 py-3 rounded-xl cursor-pointer">
|
||
<SettingOutlined class="text-base" /><span>系统设置</span>
|
||
</a>
|
||
</div>
|
||
</nav>
|
||
<div class="p-4 border-t border-white/10">
|
||
<div class="flex items-center gap-3">
|
||
<div class="w-10 h-10 bg-white/20 rounded-full flex items-center justify-center"><UserOutlined /></div>
|
||
<div class="flex-1">
|
||
<p class="font-medium">管理员</p>
|
||
<p class="text-xs text-white/70">超级管理员</p>
|
||
</div>
|
||
<button class="text-white/70 hover:text-white"><LogoutOutlined /></button>
|
||
</div>
|
||
</div>
|
||
</aside>
|
||
|
||
<main class="flex-1 ml-64">
|
||
<header class="bg-white/85 backdrop-blur-xl sticky top-0 z-50 px-8 py-4 border-b border-white/30">
|
||
<div class="flex items-center justify-between">
|
||
<div class="relative w-96">
|
||
<a-input v-model:value="searchKeyword" placeholder="搜索物料名称、编码、位置..." size="large">
|
||
<template #prefix><SearchOutlined class="text-gray-400" /></template>
|
||
</a-input>
|
||
</div>
|
||
<div class="flex items-center gap-6">
|
||
<button class="text-gray-500 hover:text-purple-600 transition-colors">
|
||
<FullscreenOutlined class="text-lg" />
|
||
</button>
|
||
<a-badge count="2" :offset="[-2, 2]">
|
||
<BellOutlined class="text-gray-500 hover:text-purple-600 transition-colors text-lg cursor-pointer" />
|
||
</a-badge>
|
||
<div class="flex items-center gap-3 pl-6 border-l border-gray-200">
|
||
<a-avatar class="bg-gradient-to-br from-purple-500 to-pink-500">A</a-avatar>
|
||
<div>
|
||
<p class="font-medium text-gray-800">Admin</p>
|
||
<p class="text-xs text-gray-500">超级管理员</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="p-8">
|
||
<div class="mb-8">
|
||
<div class="flex items-center gap-3 mb-2">
|
||
<NuxtLink to="/" class="text-gray-500 hover:text-purple-600 transition-colors">
|
||
<ArrowLeftOutlined />
|
||
</NuxtLink>
|
||
<h2 class="text-3xl font-bold text-gray-800">仓储物流</h2>
|
||
</div>
|
||
<p class="text-gray-500">管理物料入库、出库、库存盘点及物流配送</p>
|
||
</div>
|
||
|
||
<!-- 数据概览 -->
|
||
<div class="grid grid-cols-4 gap-6 mb-8">
|
||
<div class="stat-card blue bg-white rounded-2xl p-6 card-hover shadow-sm">
|
||
<div class="flex items-center justify-between mb-4">
|
||
<div class="w-12 h-12 bg-blue-100 rounded-xl flex items-center justify-center">
|
||
<InboxOutlined class="text-blue-600 text-xl" />
|
||
</div>
|
||
<span class="text-green-500 text-sm font-medium flex items-center gap-1"><ArrowUpOutlined /> 6%</span>
|
||
</div>
|
||
<h3 class="text-3xl font-bold text-gray-800 mb-1">5,230</h3>
|
||
<p class="text-gray-500 text-sm">库存物料种类</p>
|
||
</div>
|
||
<div class="stat-card green bg-white rounded-2xl p-6 card-hover shadow-sm">
|
||
<div class="flex items-center justify-between mb-4">
|
||
<div class="w-12 h-12 bg-green-100 rounded-xl flex items-center justify-center">
|
||
<ImportOutlined class="text-green-600 text-xl" />
|
||
</div>
|
||
<span class="text-green-500 text-sm font-medium flex items-center gap-1"><ArrowUpOutlined /> 15%</span>
|
||
</div>
|
||
<h3 class="text-3xl font-bold text-gray-800 mb-1">48</h3>
|
||
<p class="text-gray-500 text-sm">本月入库单</p>
|
||
</div>
|
||
<div class="stat-card orange bg-white rounded-2xl p-6 card-hover shadow-sm">
|
||
<div class="flex items-center justify-between mb-4">
|
||
<div class="w-12 h-12 bg-orange-100 rounded-xl flex items-center justify-center">
|
||
<ExportOutlined class="text-orange-600 text-xl" />
|
||
</div>
|
||
<span class="text-green-500 text-sm font-medium flex items-center gap-1"><ArrowUpOutlined /> 9%</span>
|
||
</div>
|
||
<h3 class="text-3xl font-bold text-gray-800 mb-1">62</h3>
|
||
<p class="text-gray-500 text-sm">本月出库单</p>
|
||
</div>
|
||
<div class="stat-card red bg-white rounded-2xl p-6 card-hover shadow-sm">
|
||
<div class="flex items-center justify-between mb-4">
|
||
<div class="w-12 h-12 bg-red-100 rounded-xl flex items-center justify-center">
|
||
<WarningOutlined class="text-red-600 text-xl" />
|
||
</div>
|
||
<span class="text-red-500 text-sm font-medium">需补货</span>
|
||
</div>
|
||
<h3 class="text-3xl font-bold text-gray-800 mb-1">12</h3>
|
||
<p class="text-gray-500 text-sm">库存预警</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 操作栏 -->
|
||
<div class="bg-white/85 backdrop-blur-xl rounded-2xl p-4 mb-8 shadow-sm">
|
||
<div class="flex items-center justify-between">
|
||
<div class="flex gap-3">
|
||
<a-button type="primary" class="bg-gradient-to-r from-purple-600 to-purple-700 border-0">
|
||
<PlusOutlined />新建入库单
|
||
</a-button>
|
||
<a-button><ExportOutlined class="text-orange-500" />新建出库单</a-button>
|
||
<a-button><AuditOutlined class="text-blue-500" />库存盘点</a-button>
|
||
</div>
|
||
<div class="flex gap-3">
|
||
<a-button><FilterOutlined class="text-gray-500" />筛选</a-button>
|
||
<a-button><ExportOutlined class="text-green-500" />导出报表</a-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 标签页 -->
|
||
<div class="bg-white/85 backdrop-blur-xl rounded-2xl p-2 mb-8 inline-flex shadow-sm">
|
||
<a-segmented v-model:value="activeTab" :options="tabOptions" />
|
||
</div>
|
||
|
||
<!-- 库存列表 -->
|
||
<div class="bg-white/85 backdrop-blur-xl rounded-2xl overflow-hidden mb-8 shadow-sm">
|
||
<div class="p-6 border-b border-gray-100">
|
||
<div class="flex items-center justify-between">
|
||
<h3 class="font-bold text-lg text-gray-800 flex items-center gap-2">
|
||
<UnorderedListOutlined class="text-purple-500" />
|
||
物料库存列表
|
||
<a-tag color="purple">5,230</a-tag>
|
||
</h3>
|
||
<a-input-search v-model:value="listSearchKeyword" placeholder="搜索物料编码、名称..." class="w-64" />
|
||
</div>
|
||
</div>
|
||
<a-table :dataSource="stockData" :columns="columns" :pagination="false">
|
||
<template #bodyCell="{ column, record }">
|
||
<template v-if="column.key === 'material'">
|
||
<div>
|
||
<p class="font-medium text-gray-800">{{ record.name }}</p>
|
||
<p class="text-xs text-gray-500">{{ record.code }}</p>
|
||
</div>
|
||
</template>
|
||
<template v-if="column.key === 'stock'">
|
||
<span :class="record.qty < record.minQty ? 'text-red-600 font-bold' : 'text-gray-800'">
|
||
{{ record.qty }} {{ record.unit }}
|
||
</span>
|
||
</template>
|
||
<template v-if="column.key === 'warning'">
|
||
<a-tag v-if="record.qty < record.minQty" color="error"><WarningOutlined /> 库存不足</a-tag>
|
||
<a-tag v-else color="success"><CheckCircleOutlined /> 正常</a-tag>
|
||
</template>
|
||
<template v-if="column.key === 'action'">
|
||
<div class="flex items-center justify-center gap-2">
|
||
<a-button type="text" size="small" class="text-blue-600"><EyeOutlined /></a-button>
|
||
<a-button type="text" size="small" class="text-green-600"><ImportOutlined /></a-button>
|
||
<a-button type="text" size="small" class="text-orange-600"><ExportOutlined /></a-button>
|
||
</div>
|
||
</template>
|
||
</template>
|
||
</a-table>
|
||
<div class="p-6 border-t border-gray-100">
|
||
<div class="flex items-center justify-between">
|
||
<p class="text-sm text-gray-500">显示 1-6 条,共 5,230 条</p>
|
||
<a-pagination v-model:current="currentPage" :total="5230" :pageSize="6" show-less-items />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 底部 -->
|
||
<div class="grid grid-cols-2 gap-6">
|
||
<!-- 出入库趋势 -->
|
||
<div class="bg-white/85 backdrop-blur-xl rounded-2xl p-6 card-hover shadow-sm">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<h3 class="font-bold text-lg text-gray-800 flex items-center gap-2">
|
||
<LineChartOutlined class="text-purple-500" />出入库趋势
|
||
</h3>
|
||
</div>
|
||
<div class="space-y-4">
|
||
<div v-for="trend in stockTrends" :key="trend.month">
|
||
<div class="flex items-center justify-between mb-1">
|
||
<span class="text-sm text-gray-600">{{ trend.month }}</span>
|
||
<span class="text-sm font-medium text-gray-800">入库 {{ trend.inQty }} / 出库 {{ trend.outQty }}</span>
|
||
</div>
|
||
<div class="flex gap-1 h-3">
|
||
<div class="rounded-full bg-blue-400" :style="{ width: trend.inPercent + '%' }"></div>
|
||
<div class="rounded-full bg-orange-400" :style="{ width: trend.outPercent + '%' }"></div>
|
||
</div>
|
||
</div>
|
||
<div class="flex gap-4 text-xs text-gray-500 pt-2">
|
||
<span class="flex items-center gap-1"><span class="w-3 h-3 rounded-full bg-blue-400 inline-block"></span>入库</span>
|
||
<span class="flex items-center gap-1"><span class="w-3 h-3 rounded-full bg-orange-400 inline-block"></span>出库</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 库存预警 -->
|
||
<div class="bg-white/85 backdrop-blur-xl rounded-2xl p-6 card-hover shadow-sm">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<h3 class="font-bold text-lg text-gray-800 flex items-center gap-2">
|
||
<WarningOutlined class="text-red-500" />库存预警
|
||
</h3>
|
||
<a-badge count="12" />
|
||
</div>
|
||
<div class="space-y-3">
|
||
<div v-for="w in warnings" :key="w.code" class="flex items-center gap-4 p-3 bg-red-50 rounded-xl border border-red-100">
|
||
<div class="w-10 h-10 bg-red-100 rounded-xl flex items-center justify-center flex-shrink-0">
|
||
<WarningOutlined class="text-red-600" />
|
||
</div>
|
||
<div class="flex-1">
|
||
<p class="font-medium text-gray-800">{{ w.name }}</p>
|
||
<p class="text-xs text-gray-500">当前库存:{{ w.current }} / 最低要求:{{ w.min }}</p>
|
||
</div>
|
||
<a-button type="primary" size="small" danger>申请补货</a-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref } from 'vue'
|
||
import {
|
||
HomeOutlined, SettingOutlined, ShoppingCartOutlined, InboxOutlined, WalletOutlined,
|
||
TeamOutlined, ProjectOutlined, UserOutlined, LogoutOutlined, SearchOutlined,
|
||
FullscreenOutlined, BellOutlined, ArrowLeftOutlined, ArrowUpOutlined,
|
||
PlusOutlined, ExportOutlined, ImportOutlined, FilterOutlined, UnorderedListOutlined,
|
||
CheckCircleOutlined, WarningOutlined, EyeOutlined, LineChartOutlined,
|
||
BlockOutlined, AuditOutlined,
|
||
} from '@ant-design/icons-vue'
|
||
|
||
definePageMeta({ layout: 'blank' })
|
||
|
||
const searchKeyword = ref('')
|
||
const listSearchKeyword = ref('')
|
||
const currentPage = ref(1)
|
||
const activeTab = ref('库存管理')
|
||
const tabOptions = ['库存管理', '入库管理', '出库管理', '库存盘点', '物流配送']
|
||
|
||
const columns = [
|
||
{ title: '物料信息', key: 'material' },
|
||
{ title: '类别', dataIndex: 'category', key: 'category' },
|
||
{ title: '存放位置', dataIndex: 'location', key: 'location' },
|
||
{ title: '当前库存', key: 'stock' },
|
||
{ title: '单价', dataIndex: 'price', key: 'price' },
|
||
{ title: '库存状态', key: 'warning' },
|
||
{ title: '操作', key: 'action', align: 'center' },
|
||
]
|
||
|
||
const stockData = [
|
||
{ key: '1', name: '304不锈钢板 2mm', code: 'WL-STL-001', category: '原材料', location: 'A区-01-03', qty: 850, minQty: 500, unit: 'kg', price: '¥38/kg' },
|
||
{ key: '2', name: '铝合金型材 6061', code: 'WL-ALU-008', category: '原材料', location: 'A区-02-01', qty: 120, minQty: 200, unit: 'kg', price: '¥45/kg' },
|
||
{ key: '3', name: '标准六角螺栓 M8', code: 'WL-BLT-023', category: '标准件', location: 'B区-05-12', qty: 5800, minQty: 1000, unit: '个', price: '¥0.5/个' },
|
||
{ key: '4', name: 'ABS工程塑料颗粒', code: 'WL-PLT-006', category: '原材料', location: 'C区-03-08', qty: 380, minQty: 400, unit: 'kg', price: '¥28/kg' },
|
||
{ key: '5', name: '密封圈 O型 20mm', code: 'WL-SL-047', category: '耗材', location: 'B区-08-04', qty: 1200, minQty: 500, unit: '个', price: '¥2.5/个' },
|
||
{ key: '6', name: '导轨润滑油脂', code: 'WL-OIL-012', category: '耗材', location: 'D区-01-02', qty: 45, minQty: 50, unit: 'kg', price: '¥85/kg' },
|
||
]
|
||
|
||
const stockTrends = [
|
||
{ month: '1月', inQty: 380, outQty: 320, inPercent: 55, outPercent: 45 },
|
||
{ month: '2月', inQty: 290, outQty: 260, inPercent: 52, outPercent: 48 },
|
||
{ month: '3月', inQty: 420, outQty: 390, inPercent: 51, outPercent: 49 },
|
||
{ month: '4月', inQty: 480, outQty: 620, inPercent: 43, outPercent: 57 },
|
||
]
|
||
|
||
const warnings = [
|
||
{ code: 'WL-ALU-008', name: '铝合金型材 6061', current: '120kg', min: '200kg' },
|
||
{ code: 'WL-PLT-006', name: 'ABS工程塑料颗粒', current: '380kg', min: '400kg' },
|
||
{ code: 'WL-OIL-012', name: '导轨润滑油脂', current: '45kg', min: '50kg' },
|
||
]
|
||
</script>
|
||
|
||
<style scoped>
|
||
.sidebar { background: linear-gradient(180deg, #667eea 0%, #764ba2 100%); }
|
||
.sidebar-item { color: white; }
|
||
.sidebar-item:hover, .sidebar-item.active { background: rgba(255,255,255,0.2); }
|
||
.card-hover { transition: all 0.3s cubic-bezier(0.4,0,0.2,1); }
|
||
.card-hover:hover { transform: translateY(-4px); box-shadow: 0 20px 40px rgba(0,0,0,0.1); }
|
||
.stat-card { position: relative; overflow: hidden; }
|
||
.stat-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; }
|
||
.stat-card.blue::before { background: linear-gradient(90deg, #667eea, #764ba2); }
|
||
.stat-card.green::before { background: linear-gradient(90deg, #11998e, #38ef7d); }
|
||
.stat-card.orange::before { background: linear-gradient(90deg, #f093fb, #f5576c); }
|
||
.stat-card.red::before { background: linear-gradient(90deg, #f5576c, #ff4d4f); }
|
||
</style>
|