|
@@ -0,0 +1,348 @@
|
|
|
|
+<template>
|
|
|
|
+ <div class="min-h-screen bg-gray-50 dark:bg-gray-900">
|
|
|
|
+ <!-- 顶部导航栏 -->
|
|
|
|
+ <nav class="bg-white dark:bg-gray-800 shadow-sm">
|
|
|
|
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
|
|
+ <div class="flex justify-between h-16">
|
|
|
|
+ <div class="flex items-center">
|
|
|
|
+ <h1 class="text-xl font-bold text-gray-800 dark:text-white">原料品类管理</h1>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="flex items-center space-x-4">
|
|
|
|
+ <button
|
|
|
|
+ @click="handleAddMaterial"
|
|
|
|
+ class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 flex items-center space-x-2"
|
|
|
|
+ >
|
|
|
|
+ <PlusIcon class="h-5 w-5" />
|
|
|
|
+ <span>新增</span>
|
|
|
|
+ </button>
|
|
|
|
+ <button
|
|
|
|
+ @click="handleModifyMaterial"
|
|
|
|
+ class="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 flex items-center space-x-2"
|
|
|
|
+ >
|
|
|
|
+ <EditIcon class="h-5 w-5" />
|
|
|
|
+ <span>修改</span>
|
|
|
|
+ </button>
|
|
|
|
+ <button
|
|
|
|
+ @click="handleDeleteMaterial"
|
|
|
|
+ class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 flex items-center space-x-2"
|
|
|
|
+ >
|
|
|
|
+ <TrashIcon class="h-5 w-5" />
|
|
|
|
+ <span>删除</span>
|
|
|
|
+ </button>
|
|
|
|
+ <button
|
|
|
|
+ @click="handleExportMaterials"
|
|
|
|
+ class="px-4 py-2 bg-teal-600 text-white rounded-md hover:bg-teal-700 flex items-center space-x-2"
|
|
|
|
+ >
|
|
|
|
+ <DownloadIcon class="h-5 w-5" />
|
|
|
|
+ <span>导出</span>
|
|
|
|
+ </button>
|
|
|
|
+ <button
|
|
|
|
+ @click="handleImportMaterials"
|
|
|
|
+ class="px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 flex items-center space-x-2"
|
|
|
|
+ >
|
|
|
|
+ <UploadIcon class="h-5 w-5" />
|
|
|
|
+ <span>导入</span>
|
|
|
|
+ </button>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </nav>
|
|
|
|
+
|
|
|
|
+ <!-- 主要内容区域 -->
|
|
|
|
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
|
|
+ <!-- 搜索和筛选区域 -->
|
|
|
|
+ <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6 mb-8">
|
|
|
|
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
|
|
+ <div class="relative">
|
|
|
|
+ <input
|
|
|
|
+ v-model="materialCode"
|
|
|
|
+ @input="handleSearch"
|
|
|
|
+ type="text"
|
|
|
|
+ placeholder="物料编码..."
|
|
|
|
+ class="w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
|
|
|
+ />
|
|
|
|
+ <SearchIcon class="absolute left-3 top-2.5 h-5 w-5 text-gray-400 dark:text-gray-500" />
|
|
|
|
+ </div>
|
|
|
|
+ <div class="relative">
|
|
|
|
+ <input
|
|
|
|
+ v-model="materialGroup"
|
|
|
|
+ @input="handleSearch"
|
|
|
|
+ type="text"
|
|
|
|
+ placeholder="物料组..."
|
|
|
|
+ class="w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
|
|
|
+ />
|
|
|
|
+ <SearchIcon class="absolute left-3 top-2.5 h-5 w-5 text-gray-400 dark:text-gray-500" />
|
|
|
|
+ </div>
|
|
|
|
+ <div class="relative">
|
|
|
|
+ <input
|
|
|
|
+ v-model="categoryOne"
|
|
|
|
+ @input="handleSearch"
|
|
|
|
+ type="text"
|
|
|
|
+ placeholder="类别一..."
|
|
|
|
+ class="w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
|
|
|
+ />
|
|
|
|
+ <SearchIcon class="absolute left-3 top-2.5 h-5 w-5 text-gray-400 dark:text-gray-500" />
|
|
|
|
+ </div>
|
|
|
|
+ <div class="relative">
|
|
|
|
+ <input
|
|
|
|
+ v-model="categoryTwo"
|
|
|
|
+ @input="handleSearch"
|
|
|
|
+ type="text"
|
|
|
|
+ placeholder="类别二..."
|
|
|
|
+ class="w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
|
|
|
+ />
|
|
|
|
+ <SearchIcon class="absolute left-3 top-2.5 h-5 w-5 text-gray-400 dark:text-gray-500" />
|
|
|
|
+ </div>
|
|
|
|
+ <div class="relative">
|
|
|
|
+ <input
|
|
|
|
+ v-model="rawMaterialClass"
|
|
|
|
+ @input="handleSearch"
|
|
|
|
+ type="text"
|
|
|
|
+ placeholder="原料大类..."
|
|
|
|
+ class="w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
|
|
|
+ />
|
|
|
|
+ <SearchIcon class="absolute left-3 top-2.5 h-5 w-5 text-gray-400 dark:text-gray-500" />
|
|
|
|
+ </div>
|
|
|
|
+ <div class="flex items-center space-x-4">
|
|
|
|
+ <button
|
|
|
|
+ @click="resetFilters"
|
|
|
|
+ class="px-4 py-2 bg-gray-600 text-white rounded-md hover:bg-gray-700"
|
|
|
|
+ >
|
|
|
|
+ <RefreshCcwIcon class="h-5 w-5" />
|
|
|
|
+ <span>重置</span>
|
|
|
|
+ </button>
|
|
|
|
+ <button
|
|
|
|
+ @click="handleSearch"
|
|
|
|
+ class="px-4 py-2 bg-gray-800 text-white rounded-md hover:bg-gray-900"
|
|
|
|
+ >
|
|
|
|
+ <SearchIcon class="h-5 w-5" />
|
|
|
|
+ <span>查询</span>
|
|
|
|
+ </button>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <!-- 原料品类列表 -->
|
|
|
|
+ <div class="bg-white dark:bg-gray-800 rounded-lg shadow overflow-hidden">
|
|
|
|
+ <div class="overflow-x-auto">
|
|
|
|
+ <table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
|
|
+ <thead class="bg-gray-50 dark:bg-gray-700">
|
|
|
|
+ <tr>
|
|
|
|
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">序号</th>
|
|
|
|
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">物料编码</th>
|
|
|
|
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">物料组</th>
|
|
|
|
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">类别一</th>
|
|
|
|
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">类别二</th>
|
|
|
|
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">原料大类</th>
|
|
|
|
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">选择</th>
|
|
|
|
+ </tr>
|
|
|
|
+ </thead>
|
|
|
|
+ <tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
|
|
|
|
+ <tr v-for="(material, index) in paginatedMaterials" :key="material.id" class="hover:bg-gray-50 dark:hover:bg-gray-700">
|
|
|
|
+ <td class="px-6 py-4">
|
|
|
|
+ <div class="text-sm text-gray-900 dark:text-white">{{ (currentPage - 1) * pageSize + index + 1 }}</div>
|
|
|
|
+ </td>
|
|
|
|
+ <td class="px-6 py-4">
|
|
|
|
+ <div class="text-sm text-gray-900 dark:text-white">{{ material.materialCode }}</div>
|
|
|
|
+ </td>
|
|
|
|
+ <td class="px-6 py-4">
|
|
|
|
+ <div class="text-sm text-gray-900 dark:text-white">{{ material.materialGroup }}</div>
|
|
|
|
+ </td>
|
|
|
|
+ <td class="px-6 py-4">
|
|
|
|
+ <div class="text-sm text-gray-900 dark:text-white">{{ material.categoryOne }}</div>
|
|
|
|
+ </td>
|
|
|
|
+ <td class="px-6 py-4">
|
|
|
|
+ <div class="text-sm text-gray-900 dark:text-white">{{ material.categoryTwo }}</div>
|
|
|
|
+ </td>
|
|
|
|
+ <td class="px-6 py-4">
|
|
|
|
+ <div class="text-sm text-gray-900 dark:text-white">{{ material.rawMaterialClass }}</div>
|
|
|
|
+ </td>
|
|
|
|
+ <td class="px-6 py-4">
|
|
|
|
+ <input
|
|
|
|
+ type="checkbox"
|
|
|
|
+ v-model="selectedMaterials"
|
|
|
|
+ :value="material"
|
|
|
|
+ class="form-checkbox h-4 w-4 text-blue-600 dark:text-blue-400"
|
|
|
|
+ />
|
|
|
|
+ </td>
|
|
|
|
+ </tr>
|
|
|
|
+ </tbody>
|
|
|
|
+ </table>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script setup>
|
|
|
|
+import { ref, computed, onMounted, onUnmounted } from 'vue'
|
|
|
|
+import {
|
|
|
|
+ SearchIcon,
|
|
|
|
+ RefreshCcwIcon,
|
|
|
|
+ PlusIcon,
|
|
|
|
+ EditIcon,
|
|
|
|
+ TrashIcon,
|
|
|
|
+ DownloadIcon,
|
|
|
|
+ UploadIcon
|
|
|
|
+} from 'lucide-vue-next'
|
|
|
|
+
|
|
|
|
+// 状态管理
|
|
|
|
+const materialCode = ref('')
|
|
|
|
+const materialGroup = ref('')
|
|
|
|
+const categoryOne = ref('')
|
|
|
|
+const categoryTwo = ref('')
|
|
|
|
+const rawMaterialClass = ref('')
|
|
|
|
+const selectedMaterials = ref([])
|
|
|
|
+const currentPage = ref(1)
|
|
|
|
+const pageSize = ref(10)
|
|
|
|
+
|
|
|
|
+// 模拟数据
|
|
|
|
+const mockMaterials = ref([
|
|
|
|
+ {
|
|
|
|
+ id: 'M1001',
|
|
|
|
+ materialCode: 'MC001',
|
|
|
|
+ materialGroup: 'MG001',
|
|
|
|
+ categoryOne: 'C1',
|
|
|
|
+ categoryTwo: 'C2',
|
|
|
|
+ rawMaterialClass: 'RMC001'
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'M1002',
|
|
|
|
+ materialCode: 'MC002',
|
|
|
|
+ materialGroup: 'MG002',
|
|
|
|
+ categoryOne: 'C1',
|
|
|
|
+ categoryTwo: 'C3',
|
|
|
|
+ rawMaterialClass: 'RMC002'
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ id: 'M1003',
|
|
|
|
+ materialCode: 'MC003',
|
|
|
|
+ materialGroup: 'MG003',
|
|
|
|
+ categoryOne: 'C2',
|
|
|
|
+ categoryTwo: 'C4',
|
|
|
|
+ rawMaterialClass: 'RMC003'
|
|
|
|
+ }
|
|
|
|
+])
|
|
|
|
+
|
|
|
|
+// 计算属性
|
|
|
|
+const filteredMaterials = computed(() => {
|
|
|
|
+ let result = [...mockMaterials.value]
|
|
|
|
+
|
|
|
|
+ // 搜索过滤
|
|
|
|
+ if (materialCode.value) {
|
|
|
|
+ result = result.filter(material => material.materialCode.includes(materialCode.value))
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (materialGroup.value) {
|
|
|
|
+ result = result.filter(material => material.materialGroup.includes(materialGroup.value))
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (categoryOne.value) {
|
|
|
|
+ result = result.filter(material => material.categoryOne.includes(categoryOne.value))
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (categoryTwo.value) {
|
|
|
|
+ result = result.filter(material => material.categoryTwo.includes(categoryTwo.value))
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (rawMaterialClass.value) {
|
|
|
|
+ result = result.filter(material => material.rawMaterialClass.includes(rawMaterialClass.value))
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return result
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+const paginatedMaterials = computed(() => {
|
|
|
|
+ const start = (currentPage.value - 1) * pageSize.value
|
|
|
|
+ const end = start + pageSize.value
|
|
|
|
+ return filteredMaterials.value.slice(start, end)
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+const totalPages = computed(() => {
|
|
|
|
+ return Math.ceil(filteredMaterials.value.length / pageSize.value)
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+// 方法
|
|
|
|
+const handleSearch = () => {
|
|
|
|
+ currentPage.value = 1
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const resetFilters = () => {
|
|
|
|
+ materialCode.value = ''
|
|
|
|
+ materialGroup.value = ''
|
|
|
|
+ categoryOne.value = ''
|
|
|
|
+ categoryTwo.value = ''
|
|
|
|
+ rawMaterialClass.value = ''
|
|
|
|
+ currentPage.value = 1
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const handleAddMaterial = () => {
|
|
|
|
+ console.log('新增原料品类')
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const handleModifyMaterial = () => {
|
|
|
|
+ console.log('修改原料品类:', selectedMaterials.value)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const handleDeleteMaterial = () => {
|
|
|
|
+ console.log('删除原料品类:', selectedMaterials.value)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const handleExportMaterials = () => {
|
|
|
|
+ console.log('导出原料品类')
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const handleImportMaterials = () => {
|
|
|
|
+ console.log('导入原料品类')
|
|
|
|
+}
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style scoped>
|
|
|
|
+@media (max-width: 475px) {
|
|
|
|
+ .grid {
|
|
|
|
+ @apply grid-cols-1;
|
|
|
|
+ }
|
|
|
|
+ table {
|
|
|
|
+ @apply block overflow-x-auto whitespace-nowrap;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 操作按钮样式 */
|
|
|
|
+.action-button {
|
|
|
|
+ @apply text-sm font-medium mr-3;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.add-button {
|
|
|
|
+ @apply text-blue-600 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.modify-button {
|
|
|
|
+ @apply text-green-600 dark:text-green-400 hover:text-green-900 dark:hover:text-green-300;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.delete-button {
|
|
|
|
+ @apply text-red-600 dark:text-red-400 hover:text-red-900 dark:hover:text-red-300;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.export-button {
|
|
|
|
+ @apply text-teal-600 dark:text-teal-400 hover:text-teal-900 dark:hover:text-teal-300;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.import-button {
|
|
|
|
+ @apply text-indigo-600 dark:text-indigo-400 hover:text-indigo-900 dark:hover:text-indigo-300;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 分页样式 */
|
|
|
|
+.pagination-button {
|
|
|
|
+ @apply relative inline-flex items-center px-4 py-2 border border-gray-300 dark:border-gray-600 text-sm font-medium rounded-md text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.pagination-button-active {
|
|
|
|
+ @apply bg-blue-600 text-white border-blue-600;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 加载动画 */
|
|
|
|
+.loading-spinner {
|
|
|
|
+ @apply animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600;
|
|
|
|
+}
|
|
|
|
+</style>
|