Parcourir la source

longwei-2025-07-10 07:16:01

genlitex il y a 3 semaines
Parent
commit
c9276ea163

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 4
dist/assets/index-C_m0F2Qf.js


Fichier diff supprimé car celui-ci est trop grand
+ 4 - 0
dist/assets/index-DEiMsT-p.js


+ 2 - 2
dist/index.html

@@ -5,8 +5,8 @@
     <link rel="icon" type="image/svg+xml" href="/vite.svg" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>Vite + Vue</title>
-    <script type="module" crossorigin src="/ide/proxy/6002/assets/index-C_m0F2Qf.js"></script>
-    <link rel="stylesheet" crossorigin href="/ide/proxy/6002/assets/index-4owCqU6i.css">
+    <script type="module" crossorigin src="/ide/proxy/6006/assets/index-DEiMsT-p.js"></script>
+    <link rel="stylesheet" crossorigin href="/ide/proxy/6006/assets/index-4owCqU6i.css">
   </head>
   <body>
     <div id="app"></div>

+ 6 - 0
src/router/index.js

@@ -1,5 +1,6 @@
 import { createRouter, createWebHashHistory } from 'vue-router'
 import HomeView from '../views/HomeView.vue'
+import MaterialCategoryManagement from '../views/MaterialCategoryManagement.vue'
 import MinimalistView from '../assets/templates/ui-standard/MinimalistView.vue'
 import DarkModeView from '../assets/templates/ui-standard/DarkModeView.vue'
 import RetroView from '../assets/templates/ui-standard/RetroView.vue'
@@ -157,6 +158,11 @@ const routes = [
     name: 'Futuristic',
     component: FuturisticView
   },
+  {
+    path: '/material-category-management',
+    name: 'material-category-management',
+    component: MaterialCategoryManagement
+  },
   {
     path: '/:pathMatch(.*)*',
     redirect: '/'

+ 518 - 0
src/views/MaterialCategoryManagement.vue

@@ -0,0 +1,518 @@
+<template>
+  <div class="p-6">
+    <!-- 头部操作区 -->
+    <div class="bg-white rounded-lg shadow p-6 mb-6">
+      <div class="flex justify-between items-center">
+        <h2 class="text-2xl font-bold text-gray-800">原料品类管理</h2>
+        <div class="flex space-x-4">
+          <button 
+            @click="showAddDialog = true"
+            class="flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
+          >
+            <PlusIcon class="w-5 h-5 mr-2" />
+            新增
+          </button>
+          <button 
+            @click="handleEdit"
+            class="flex items-center px-4 py-2 bg-yellow-500 text-white rounded-lg hover:bg-yellow-600 transition-colors"
+          >
+            <EditIcon class="w-5 h-5 mr-2" />
+            修改
+          </button>
+          <button 
+            @click="handleDelete"
+            class="flex items-center px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
+          >
+            <TrashIcon class="w-5 h-5 mr-2" />
+            删除
+          </button>
+          <button 
+            @click="handleExport"
+            class="flex items-center px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors"
+          >
+            <DownloadIcon class="w-5 h-5 mr-2" />
+            导出
+          </button>
+          <div class="relative">
+            <input 
+              type="file" 
+              class="hidden" 
+              ref="fileInput"
+              @change="handleFileChange"
+            />
+            <button 
+              @click="$refs.fileInput.click()"
+              class="flex items-center px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors"
+            >
+              <UploadIcon class="w-5 h-5 mr-2" />
+              导入
+            </button>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 筛选区 -->
+    <div class="bg-white rounded-lg shadow p-6 mb-6">
+      <div class="flex flex-wrap gap-4">
+        <div class="relative flex-1 min-w-[200px]">
+          <SearchIcon class="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
+          <input 
+            v-model="searchQuery"
+            type="text"
+            placeholder="搜索物料编码"
+            class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
+            @input="handleSearch"
+          />
+        </div>
+        <div class="relative flex-1 min-w-[200px]">
+          <SearchIcon class="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
+          <input 
+            v-model="searchGroup"
+            type="text"
+            placeholder="搜索物料组"
+            class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
+            @input="handleSearch"
+          />
+        </div>
+        <div class="relative flex-1 min-w-[200px]">
+          <SearchIcon class="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
+          <input 
+            v-model="searchCategory1"
+            type="text"
+            placeholder="搜索类别一"
+            class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
+            @input="handleSearch"
+          />
+        </div>
+        <div class="relative flex-1 min-w-[200px]">
+          <SearchIcon class="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
+          <input 
+            v-model="searchCategory2"
+            type="text"
+            placeholder="搜索类别二"
+            class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
+            @input="handleSearch"
+          />
+        </div>
+        <div class="relative flex-1 min-w-[200px]">
+          <SearchIcon class="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
+          <input 
+            v-model="searchRawMaterial"
+            type="text"
+            placeholder="搜索原料大类"
+            class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
+            @input="handleSearch"
+          />
+        </div>
+        <div class="flex items-center space-x-2">
+          <button 
+            @click="resetSearch"
+            class="px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors"
+          >
+            重置
+          </button>
+          <button 
+            @click="handleSearch"
+            class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors"
+          >
+            查询
+          </button>
+        </div>
+      </div>
+    </div>
+
+    <!-- 原料品类列表 -->
+    <div class="bg-white rounded-lg shadow overflow-hidden">
+      <div class="overflow-x-auto">
+        <table class="min-w-full divide-y divide-gray-200">
+          <thead class="bg-gray-50">
+            <tr>
+              <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
+                <input 
+                  type="checkbox" 
+                  v-model="selectAll"
+                  class="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
+                />
+              </th>
+              <th 
+                v-for="column in columns" 
+                :key="column.prop"
+                class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider cursor-pointer"
+                @click="handleSort(column.prop)"
+              >
+                <div class="flex items-center">
+                  {{ column.label }}
+                  <span class="ml-1">
+                    <ChevronUpIcon v-if="sortKey === column.prop && sortOrder === 'asc'" class="h-4 w-4 inline-block" />
+                    <ChevronDownIcon v-else-if="sortKey === column.prop && sortOrder === 'desc'" class="h-4 w-4 inline-block" />
+                  </span>
+                </div>
+              </th>
+            </tr>
+          </thead>
+          <tbody class="bg-white divide-y divide-gray-200">
+            <tr v-for="(item, index) in filteredItems" :key="item.id" class="hover:bg-gray-50">
+              <td class="px-6 py-4 whitespace-nowrap">
+                <input 
+                  type="checkbox" 
+                  v-model="selectedItems"
+                  :value="item.id"
+                  class="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
+                />
+              </td>
+              <td class="px-6 py-4 whitespace-nowrap">{{ index + 1 }}</td>
+              <td class="px-6 py-4 whitespace-nowrap">{{ item.materialCode }}</td>
+              <td class="px-6 py-4 whitespace-nowrap">{{ item.materialGroup }}</td>
+              <td class="px-6 py-4 whitespace-nowrap">{{ item.category1 }}</td>
+              <td class="px-6 py-4 whitespace-nowrap">{{ item.category2 }}</td>
+              <td class="px-6 py-4 whitespace-nowrap">{{ item.rawMaterial }}</td>
+            </tr>
+          </tbody>
+        </table>
+      </div>
+
+      <!-- 批量操作 -->
+      <div v-if="selectedItems.length > 0" class="px-6 py-4 bg-gray-50 border-t border-gray-200">
+        <div class="flex items-center justify-between">
+          <span class="text-sm text-gray-600">已选择 {{ selectedItems.length }} 项</span>
+          <div class="flex space-x-4">
+            <button 
+              @click="handleBatchEdit"
+              class="flex items-center px-4 py-2 text-sm text-blue-600 hover:text-blue-800"
+            >
+              <EditIcon class="w-4 h-4 mr-1" />
+              批量编辑
+            </button>
+            <button 
+              @click="handleBatchDelete"
+              class="flex items-center px-4 py-2 text-sm text-red-600 hover:text-red-800"
+            >
+              <TrashIcon class="w-4 h-4 mr-1" />
+              批量删除
+            </button>
+          </div>
+        </div>
+      </div>
+
+      <!-- 分页 -->
+      <div class="px-6 py-4 bg-gray-50 border-t border-gray-200">
+        <div class="flex items-center justify-between">
+          <div class="flex items-center">
+            <span class="text-sm text-gray-700 mr-4">每页显示</span>
+            <select 
+              v-model="pageSize"
+              class="px-2 py-1 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
+              @change="handleSizeChange"
+            >
+              <option v-for="size in [10, 20, 50, 100]" :key="size" :value="size">
+                {{ size }}
+              </option>
+            </select>
+          </div>
+          <div class="flex items-center space-x-2">
+            <button 
+              @click="currentPage--"
+              :disabled="currentPage === 1"
+              class="px-3 py-1 border border-gray-300 rounded-md disabled:opacity-50"
+            >
+              <ChevronLeftIcon class="w-4 h-4" />
+            </button>
+            <span class="text-sm text-gray-700">
+              第 {{ currentPage }} 页 / 共 {{ totalPages }} 页
+            </span>
+            <button 
+              @click="currentPage++"
+              :disabled="currentPage === totalPages"
+              class="px-3 py-1 border border-gray-300 rounded-md disabled:opacity-50"
+            >
+              <ChevronRightIcon class="w-4 h-4" />
+            </button>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 新增/编辑原料品类对话框 -->
+    <div v-if="showAddDialog" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center">
+      <div class="bg-white rounded-lg shadow-xl w-1/2 max-w-2xl">
+        <div class="flex justify-between items-center p-6 border-b">
+          <h3 class="text-lg font-semibold">{{ isEdit ? '编辑原料品类' : '新增原料品类' }}</h3>
+          <button @click="showAddDialog = false" class="text-gray-400 hover:text-gray-500">
+            <XIcon class="w-5 h-5" />
+          </button>
+        </div>
+        <form @submit.prevent="handleSubmit" class="p-6">
+          <div class="grid grid-cols-2 gap-6">
+            <div>
+              <label class="block text-sm font-medium text-gray-700 mb-1">物料编码</label>
+              <input 
+                v-model="addForm.materialCode"
+                type="text"
+                class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
+                required
+              />
+            </div>
+            <div>
+              <label class="block text-sm font-medium text-gray-700 mb-1">物料组</label>
+              <input 
+                v-model="addForm.materialGroup"
+                type="text"
+                class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
+                required
+              />
+            </div>
+            <div>
+              <label class="block text-sm font-medium text-gray-700 mb-1">类别一</label>
+              <input 
+                v-model="addForm.category1"
+                type="text"
+                class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
+                required
+              />
+            </div>
+            <div>
+              <label class="block text-sm font-medium text-gray-700 mb-1">类别二</label>
+              <input 
+                v-model="addForm.category2"
+                type="text"
+                class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
+                required
+              />
+            </div>
+            <div>
+              <label class="block text-sm font-medium text-gray-700 mb-1">原料大类</label>
+              <input 
+                v-model="addForm.rawMaterial"
+                type="text"
+                class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
+                required
+              />
+            </div>
+          </div>
+          <div class="mt-6 flex justify-end space-x-4">
+            <button 
+              type="button"
+              @click="showAddDialog = false"
+              class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50"
+            >
+              取消
+            </button>
+            <button 
+              type="submit"
+              class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
+            >
+              确定
+            </button>
+          </div>
+        </form>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
+import { 
+  PlusIcon, 
+  DownloadIcon, 
+  UploadIcon, 
+  SearchIcon, 
+  ChevronUpIcon,
+  ChevronDownIcon,
+  EditIcon,
+  TrashIcon,
+  ChevronLeftIcon,
+  ChevronRightIcon,
+  XIcon
+} from 'lucide-vue-next'
+
+// Mock 数据
+const mockData = {
+  items: [
+    {
+      id: 1,
+      materialCode: 'MAT001',
+      materialGroup: 'GROUP001',
+      category1: 'CATEGORY001',
+      category2: 'CATEGORY002',
+      rawMaterial: 'RAW001'
+    },
+    {
+      id: 2,
+      materialCode: 'MAT002',
+      materialGroup: 'GROUP002',
+      category1: 'CATEGORY003',
+      category2: 'CATEGORY004',
+      rawMaterial: 'RAW002'
+    }
+  ],
+  total: 2
+}
+
+// 状态管理
+const loading = ref(false)
+const searchQuery = ref('')
+const searchGroup = ref('')
+const searchCategory1 = ref('')
+const searchCategory2 = ref('')
+const searchRawMaterial = ref('')
+const currentPage = ref(1)
+const pageSize = ref(10)
+const total = ref(0)
+const selectedItems = ref([])
+const showAddDialog = ref(false)
+const isEdit = ref(false)
+const sortKey = ref('')
+const sortOrder = ref('asc')
+const statistics = ref([
+  { title: '总原料品类数', value: mockData.total }
+])
+const addForm = ref({
+  materialCode: '',
+  materialGroup: '',
+  category1: '',
+  category2: '',
+  rawMaterial: ''
+})
+
+const columns = [
+  { prop: 'materialCode', label: '物料编码' },
+  { prop: 'materialGroup', label: '物料组' },
+  { prop: 'category1', label: '类别一' },
+  { prop: 'category2', label: '类别二' },
+  { prop: 'rawMaterial', label: '原料大类' }
+]
+
+// 计算属性
+const filteredItems = computed(() => {
+  return mockData.items.filter(item => 
+    item.materialCode.includes(searchQuery.value) &&
+    item.materialGroup.includes(searchGroup.value) &&
+    item.category1.includes(searchCategory1.value) &&
+    item.category2.includes(searchCategory2.value) &&
+    item.rawMaterial.includes(searchRawMaterial.value)
+  )
+})
+
+const totalPages = computed(() => {
+  return Math.ceil(filteredItems.value.length / pageSize.value)
+})
+
+const selectAll = computed({
+  get: () => selectedItems.value.length === filteredItems.value.length,
+  set: (value) => {
+    selectedItems.value = value ? filteredItems.value.map(i => i.id) : []
+  }
+})
+
+// 方法
+const handleSearch = () => {
+  currentPage.value = 1
+  fetchItems()
+}
+
+const resetSearch = () => {
+  searchQuery.value = ''
+  searchGroup.value = ''
+  searchCategory1.value = ''
+  searchCategory2.value = ''
+  searchRawMaterial.value = ''
+  handleSearch()
+}
+
+const handleSort = (prop) => {
+  if (sortKey.value === prop) {
+    sortOrder.value = sortOrder.value === 'asc' ? 'desc' : 'asc'
+  } else {
+    sortKey.value = prop
+    sortOrder.value = 'asc'
+  }
+  const sortedItems = [...filteredItems.value]
+  sortedItems.sort((a, b) => {
+    const aValue = a[prop]
+    const bValue = b[prop]
+    if (sortOrder.value === 'asc') {
+      return aValue > bValue ? 1 : -1
+    } else {
+      return aValue < bValue ? 1 : -1
+    }
+  })
+  filteredItems.value = sortedItems
+}
+
+const handleSizeChange = () => {
+  currentPage.value = 1
+  fetchItems()
+}
+
+const handleFileChange = (event) => {
+  const file = event.target.files[0]
+  if (file) {
+    // 处理文件上传
+  }
+}
+
+const handleExport = () => {
+  // 实现导出逻辑
+}
+
+const handleBatchEdit = () => {
+  // 实现批量编辑逻辑
+}
+
+const handleBatchDelete = () => {
+  // 实现批量删除逻辑
+}
+
+const handleEdit = () => {
+  isEdit.value = true
+  addForm.value = { ...mockData.items[0] } // 假设第一个元素被选中
+  showAddDialog.value = true
+}
+
+const handleDelete = () => {
+  // 实现删除逻辑
+}
+
+const handleSubmit = () => {
+  // 实现表单提交逻辑
+}
+
+// 生命周期钩子
+onMounted(() => {
+  fetchItems()
+})
+
+onUnmounted(() => {
+  // 清理工作
+})
+
+// 数据获取
+const fetchItems = async () => {
+  try {
+    loading.value = true
+    // 模拟网络延迟
+    await new Promise(resolve => setTimeout(resolve, 500))
+    total.value = mockData.total
+  } catch (error) {
+    console.error('获取数据失败:', error)
+  } finally {
+    loading.value = false
+  }
+}
+
+// 添加 watch 监听对话框显示状态
+watch(showAddDialog, (newVal) => {
+  if (!newVal) {
+    addForm.value = {
+      materialCode: '',
+      materialGroup: '',
+      category1: '',
+      category2: '',
+      rawMaterial: ''
+    }
+    isEdit.value = false
+  }
+})
+</script>

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff