From d7c6c6429a00a480a5b163e0afe7aae217d8a1f6 Mon Sep 17 00:00:00 2001
From: riku <risaku@163.com>
Date: 星期二, 10 三月 2026 17:30:36 +0800
Subject: [PATCH] 2026.3.10
---
src/components/table/FYTable.vue | 1
src/views/system/SystemManage.vue | 627 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 625 insertions(+), 3 deletions(-)
diff --git a/src/components/table/FYTable.vue b/src/components/table/FYTable.vue
index 8cd1348..fc0c3c9 100644
--- a/src/components/table/FYTable.vue
+++ b/src/components/table/FYTable.vue
@@ -1,5 +1,4 @@
<template>
- <div>
<el-row ref="searchRef">
<FYSearchBar @search="onSearch">
<template #options v-if="$slots.options">
diff --git a/src/views/system/SystemManage.vue b/src/views/system/SystemManage.vue
index 0f7f348..c429e89 100644
--- a/src/views/system/SystemManage.vue
+++ b/src/views/system/SystemManage.vue
@@ -1,2 +1,625 @@
-<template>绯荤粺绠$悊</template>
-<script setup lang="ts"></script>
+<template>
+ <div class="system-manage">
+ <el-card class="system-card">
+ <template #header>
+ <div class="card-header">
+ <span>绯荤粺绠$悊</span>
+ </div>
+ </template>
+
+ <!-- 瀵艰埅鏍囩椤� -->
+ <el-tabs v-model="activeTab" class="system-tabs">
+ <!-- 鐢ㄦ埛绠$悊 -->
+ <el-tab-pane label="鐢ㄦ埛绠$悊" name="users">
+ <div class="tab-content">
+ <!-- 鎼滅储鍜屾坊鍔犳寜閽� -->
+ <div class="search-add-bar">
+ <el-input
+ v-model="userSearchQuery"
+ placeholder="鎼滅储鐢ㄦ埛"
+ style="width: 200px"
+ prefix-icon="el-icon-search"
+ />
+ <el-button type="primary" @click="openUserDialog">
+ <el-icon><Plus /></el-icon> 娣诲姞鐢ㄦ埛
+ </el-button>
+ </div>
+
+ <!-- 鐢ㄦ埛琛ㄦ牸 -->
+ <el-table :data="filteredUsers" style="width: 100%">
+ <el-table-column prop="id" label="ID" width="80" />
+ <el-table-column prop="username" label="鐢ㄦ埛鍚�" />
+ <el-table-column prop="name" label="濮撳悕" />
+ <el-table-column prop="role" label="瑙掕壊" />
+ <el-table-column prop="status" label="鐘舵��">
+ <template #default="scope">
+ <el-tag :type="scope.row.status === 'active' ? 'success' : 'danger'">
+ {{ scope.row.status === 'active' ? '娲昏穬' : '绂佺敤' }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" width="200">
+ <template #default="scope">
+ <el-button size="small" @click="editUser(scope.row)"> 缂栬緫 </el-button>
+ <el-button size="small" type="danger" @click="deleteUser(scope.row.id)">
+ 鍒犻櫎
+ </el-button>
+ <el-button size="small" @click="setPermissions(scope.row)"> 鏉冮檺 </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <!-- 鍒嗛〉 -->
+ <el-pagination
+ v-model:current-page="userCurrentPage"
+ v-model:page-size="userPageSize"
+ :page-sizes="[10, 20, 50]"
+ layout="total, sizes, prev, pager, next, jumper"
+ :total="users.length"
+ style="margin-top: 20px"
+ />
+ </div>
+ </el-tab-pane>
+
+ <!-- 椁愰ギ搴楅摵绠$悊 -->
+ <el-tab-pane label="椁愰ギ搴楅摵绠$悊" name="restaurants">
+ <div class="tab-content">
+ <!-- 鎼滅储鍜屾坊鍔犳寜閽� -->
+ <div class="search-add-bar">
+ <el-input
+ v-model="restaurantSearchQuery"
+ placeholder="鎼滅储搴楅摵"
+ style="width: 200px"
+ prefix-icon="el-icon-search"
+ />
+ <el-button type="primary" @click="openRestaurantDialog">
+ <el-icon><Plus /></el-icon> 娣诲姞搴楅摵
+ </el-button>
+ </div>
+
+ <!-- 搴楅摵琛ㄦ牸 -->
+ <el-table :data="filteredRestaurants" style="width: 100%">
+ <el-table-column prop="id" label="ID" width="80" />
+ <el-table-column prop="name" label="搴楅摵鍚嶇О" />
+ <el-table-column prop="address" label="鍦板潃" />
+ <el-table-column prop="contact" label="鑱旂郴浜�" />
+ <el-table-column prop="phone" label="鑱旂郴鐢佃瘽" />
+ <el-table-column label="鎿嶄綔" width="250">
+ <template #default="scope">
+ <el-button size="small" @click="editRestaurant(scope.row)"> 缂栬緫 </el-button>
+ <el-button size="small" type="danger" @click="deleteRestaurant(scope.row.id)">
+ 鍒犻櫎
+ </el-button>
+ <el-button size="small" @click="manageDevices(scope.row)"> 璁惧绠$悊 </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <!-- 鍒嗛〉 -->
+ <el-pagination
+ v-model:current-page="restaurantCurrentPage"
+ v-model:page-size="restaurantPageSize"
+ :page-sizes="[10, 20, 50]"
+ layout="total, sizes, prev, pager, next, jumper"
+ :total="restaurants.length"
+ style="margin-top: 20px"
+ />
+ </div>
+ </el-tab-pane>
+
+ <!-- 璁惧绠$悊 -->
+ <el-tab-pane label="璁惧绠$悊" name="devices">
+ <div class="tab-content" v-if="selectedRestaurant">
+ <h3>{{ selectedRestaurant.name }} - 璁惧鍒楄〃</h3>
+
+ <!-- 鎼滅储鍜屾坊鍔犳寜閽� -->
+ <div class="search-add-bar">
+ <el-input
+ v-model="deviceSearchQuery"
+ placeholder="鎼滅储璁惧"
+ style="width: 200px"
+ prefix-icon="el-icon-search"
+ />
+ <el-button type="primary" @click="openDeviceDialog">
+ <el-icon><Plus /></el-icon> 娣诲姞璁惧
+ </el-button>
+ </div>
+
+ <!-- 璁惧琛ㄦ牸 -->
+ <el-table :data="filteredDevices" style="width: 100%">
+ <el-table-column prop="id" label="ID" width="80" />
+ <el-table-column prop="deviceId" label="璁惧缂栧彿" />
+ <el-table-column prop="type" label="璁惧绫诲瀷" />
+ <el-table-column prop="status" label="鐘舵��">
+ <template #default="scope">
+ <el-tag :type="scope.row.status === 'online' ? 'success' : 'danger'">
+ {{ scope.row.status === 'online' ? '鍦ㄧ嚎' : '绂荤嚎' }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column prop="installDate" label="瀹夎鏃ユ湡" />
+ <el-table-column label="鎿嶄綔" width="200">
+ <template #default="scope">
+ <el-button size="small" @click="editDevice(scope.row)"> 缂栬緫 </el-button>
+ <el-button size="small" type="danger" @click="deleteDevice(scope.row.id)">
+ 鍒犻櫎
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <!-- 鍒嗛〉 -->
+ <el-pagination
+ v-model:current-page="deviceCurrentPage"
+ v-model:page-size="devicePageSize"
+ :page-sizes="[10, 20, 50]"
+ layout="total, sizes, prev, pager, next, jumper"
+ :total="devices.length"
+ style="margin-top: 20px"
+ />
+ </div>
+ <div class="tab-content" v-else>
+ <el-empty description="璇峰厛閫夋嫨涓�涓楗簵閾�" />
+ </div>
+ </el-tab-pane>
+ </el-tabs>
+ </el-card>
+
+ <!-- 鐢ㄦ埛瀵硅瘽妗� -->
+ <el-dialog
+ v-model="userDialogVisible"
+ :title="isEditUser ? '缂栬緫鐢ㄦ埛' : '娣诲姞鐢ㄦ埛'"
+ width="500px"
+ >
+ <el-form :model="userForm" label-width="80px">
+ <el-form-item label="鐢ㄦ埛鍚�">
+ <el-input v-model="userForm.username" />
+ </el-form-item>
+ <el-form-item label="濮撳悕">
+ <el-input v-model="userForm.name" />
+ </el-form-item>
+ <el-form-item label="瀵嗙爜" v-if="!isEditUser">
+ <el-input type="password" v-model="userForm.password" />
+ </el-form-item>
+ <el-form-item label="瑙掕壊">
+ <el-select v-model="userForm.role">
+ <el-option label="绠$悊鍛�" value="admin" />
+ <el-option label="鏅�氱敤鎴�" value="user" />
+ <el-option label="搴楅摵绠$悊鍛�" value="restaurant_admin" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鐘舵��">
+ <el-switch v-model="userForm.status" active-value="active" inactive-value="inactive" />
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="userDialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" @click="saveUser">淇濆瓨</el-button>
+ </span>
+ </template>
+ </el-dialog>
+
+ <!-- 鏉冮檺璁剧疆瀵硅瘽妗� -->
+ <el-dialog v-model="permissionDialogVisible" title="鏉冮檺璁剧疆" width="500px">
+ <el-form label-width="80px">
+ <el-form-item label="鐢ㄦ埛">
+ <el-input :value="selectedUser?.name" disabled />
+ </el-form-item>
+ <el-form-item label="鏉冮檺">
+ <el-checkbox-group v-model="userPermissions">
+ <el-checkbox label="user_management">鐢ㄦ埛绠$悊</el-checkbox>
+ <el-checkbox label="restaurant_management">搴楅摵绠$悊</el-checkbox>
+ <el-checkbox label="device_management">璁惧绠$悊</el-checkbox>
+ <el-checkbox label="data_analysis">鏁版嵁鍒嗘瀽</el-checkbox>
+ <el-checkbox label="system_settings">绯荤粺璁剧疆</el-checkbox>
+ </el-checkbox-group>
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="permissionDialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" @click="savePermissions">淇濆瓨</el-button>
+ </span>
+ </template>
+ </el-dialog>
+
+ <!-- 搴楅摵瀵硅瘽妗� -->
+ <el-dialog
+ v-model="restaurantDialogVisible"
+ :title="isEditRestaurant ? '缂栬緫搴楅摵' : '娣诲姞搴楅摵'"
+ width="500px"
+ >
+ <el-form :model="restaurantForm" label-width="80px">
+ <el-form-item label="搴楅摵鍚嶇О">
+ <el-input v-model="restaurantForm.name" />
+ </el-form-item>
+ <el-form-item label="鍦板潃">
+ <el-input v-model="restaurantForm.address" />
+ </el-form-item>
+ <el-form-item label="鑱旂郴浜�">
+ <el-input v-model="restaurantForm.contact" />
+ </el-form-item>
+ <el-form-item label="鑱旂郴鐢佃瘽">
+ <el-input v-model="restaurantForm.phone" />
+ </el-form-item>
+ <el-form-item label="钀ヤ笟鎵х収">
+ <el-input v-model="restaurantForm.license" />
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="restaurantDialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" @click="saveRestaurant">淇濆瓨</el-button>
+ </span>
+ </template>
+ </el-dialog>
+
+ <!-- 璁惧瀵硅瘽妗� -->
+ <el-dialog
+ v-model="deviceDialogVisible"
+ :title="isEditDevice ? '缂栬緫璁惧' : '娣诲姞璁惧'"
+ width="500px"
+ >
+ <el-form :model="deviceForm" label-width="80px">
+ <el-form-item label="璁惧缂栧彿">
+ <el-input v-model="deviceForm.deviceId" />
+ </el-form-item>
+ <el-form-item label="璁惧绫诲瀷">
+ <el-select v-model="deviceForm.type">
+ <el-option label="娌圭儫鐩戞祴浠�" value="fume_monitor" />
+ <el-option label="棰楃矑鐗╃洃娴嬩华" value="particle_monitor" />
+ <el-option label="鍣0鐩戞祴浠�" value="noise_monitor" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="瀹夎浣嶇疆">
+ <el-input v-model="deviceForm.location" />
+ </el-form-item>
+ <el-form-item label="瀹夎鏃ユ湡">
+ <el-date-picker v-model="deviceForm.installDate" type="date" />
+ </el-form-item>
+ <el-form-item label="鐘舵��">
+ <el-select v-model="deviceForm.status">
+ <el-option label="鍦ㄧ嚎" value="online" />
+ <el-option label="绂荤嚎" value="offline" />
+ </el-select>
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="deviceDialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" @click="saveDevice">淇濆瓨</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { ref, computed } from 'vue'
+import { Plus } from '@element-plus/icons-vue'
+
+// 鏍囩椤电姸鎬�
+const activeTab = ref('users')
+
+// 鐢ㄦ埛绠$悊鐩稿叧
+const users = ref([
+ { id: 1, username: 'admin', name: '绠$悊鍛�', role: 'admin', status: 'active' },
+ { id: 2, username: 'user1', name: '鐢ㄦ埛1', role: 'user', status: 'active' },
+ {
+ id: 3,
+ username: 'restaurant1',
+ name: '搴楅摵绠$悊鍛�1',
+ role: 'restaurant_admin',
+ status: 'active',
+ },
+])
+const userSearchQuery = ref('')
+const userCurrentPage = ref(1)
+const userPageSize = ref(10)
+const userDialogVisible = ref(false)
+const isEditUser = ref(false)
+const userForm = ref({
+ id: 0,
+ username: '',
+ name: '',
+ password: '',
+ role: 'user',
+ status: 'active',
+})
+
+// 鏉冮檺绠$悊鐩稿叧
+const permissionDialogVisible = ref(false)
+const selectedUser = ref<any>(null)
+const userPermissions = ref<string[]>([])
+
+// 椁愰ギ搴楅摵绠$悊鐩稿叧
+const restaurants = ref([
+ {
+ id: 1,
+ name: '娴嬭瘯椁愬巺1',
+ address: '鍖椾含甯傛湞闃冲尯',
+ contact: '寮犱笁',
+ phone: '13800138001',
+ license: '123456789',
+ },
+ {
+ id: 2,
+ name: '娴嬭瘯椁愬巺2',
+ address: '鍖椾含甯傛捣娣�鍖�',
+ contact: '鏉庡洓',
+ phone: '13800138002',
+ license: '987654321',
+ },
+])
+const restaurantSearchQuery = ref('')
+const restaurantCurrentPage = ref(1)
+const restaurantPageSize = ref(10)
+const restaurantDialogVisible = ref(false)
+const isEditRestaurant = ref(false)
+const restaurantForm = ref({
+ id: 0,
+ name: '',
+ address: '',
+ contact: '',
+ phone: '',
+ license: '',
+})
+
+// 璁惧绠$悊鐩稿叧
+const devices = ref([
+ {
+ id: 1,
+ restaurantId: 1,
+ deviceId: 'FUM-001',
+ type: 'fume_monitor',
+ location: '鍘ㄦ埧',
+ status: 'online',
+ installDate: '2024-01-01',
+ },
+ {
+ id: 2,
+ restaurantId: 1,
+ deviceId: 'FUM-002',
+ type: 'particle_monitor',
+ location: '鎺掔儫鍙�',
+ status: 'online',
+ installDate: '2024-01-02',
+ },
+ {
+ id: 3,
+ restaurantId: 2,
+ deviceId: 'FUM-003',
+ type: 'fume_monitor',
+ location: '鍘ㄦ埧',
+ status: 'offline',
+ installDate: '2024-01-03',
+ },
+])
+const deviceSearchQuery = ref('')
+const deviceCurrentPage = ref(1)
+const devicePageSize = ref(10)
+const deviceDialogVisible = ref(false)
+const isEditDevice = ref(false)
+const deviceForm = ref({
+ id: 0,
+ restaurantId: 0,
+ deviceId: '',
+ type: 'fume_monitor',
+ location: '',
+ status: 'online',
+ installDate: '',
+})
+const selectedRestaurant = ref<any>(null)
+
+// 璁$畻灞炴��
+const filteredUsers = computed(() => {
+ if (!userSearchQuery.value) return users.value
+ return users.value.filter(
+ (user) =>
+ user.username.includes(userSearchQuery.value) || user.name.includes(userSearchQuery.value),
+ )
+})
+
+const filteredRestaurants = computed(() => {
+ if (!restaurantSearchQuery.value) return restaurants.value
+ return restaurants.value.filter(
+ (restaurant) =>
+ restaurant.name.includes(restaurantSearchQuery.value) ||
+ restaurant.address.includes(restaurantSearchQuery.value),
+ )
+})
+
+const filteredDevices = computed(() => {
+ if (!selectedRestaurant.value) return []
+ let result = devices.value.filter((device) => device.restaurantId === selectedRestaurant.value.id)
+ if (deviceSearchQuery.value) {
+ result = result.filter(
+ (device) =>
+ device.deviceId.includes(deviceSearchQuery.value) ||
+ device.type.includes(deviceSearchQuery.value),
+ )
+ }
+ return result
+})
+
+// 鏂规硶
+// 鐢ㄦ埛绠$悊鏂规硶
+const openUserDialog = () => {
+ isEditUser.value = false
+ userForm.value = {
+ id: 0,
+ username: '',
+ name: '',
+ password: '',
+ role: 'user',
+ status: 'active',
+ }
+ userDialogVisible.value = true
+}
+
+const editUser = (user: any) => {
+ isEditUser.value = true
+ userForm.value = { ...user }
+ userDialogVisible.value = true
+}
+
+const saveUser = () => {
+ if (isEditUser.value) {
+ const index = users.value.findIndex((u) => u.id === userForm.value.id)
+ if (index !== -1) {
+ users.value[index] = { ...userForm.value }
+ }
+ } else {
+ const newUser = {
+ ...userForm.value,
+ id: users.value.length + 1,
+ }
+ users.value.push(newUser)
+ }
+ userDialogVisible.value = false
+}
+
+const deleteUser = (id: number) => {
+ users.value = users.value.filter((user) => user.id !== id)
+}
+
+const setPermissions = (user: any) => {
+ selectedUser.value = user
+ // 妯℃嫙鏉冮檺鏁版嵁
+ userPermissions.value = ['user_management', 'restaurant_management']
+ permissionDialogVisible.value = true
+}
+
+const savePermissions = () => {
+ // 淇濆瓨鏉冮檺閫昏緫
+ permissionDialogVisible.value = false
+}
+
+// 搴楅摵绠$悊鏂规硶
+const openRestaurantDialog = () => {
+ isEditRestaurant.value = false
+ restaurantForm.value = {
+ id: 0,
+ name: '',
+ address: '',
+ contact: '',
+ phone: '',
+ license: '',
+ }
+ restaurantDialogVisible.value = true
+}
+
+const editRestaurant = (restaurant: any) => {
+ isEditRestaurant.value = true
+ restaurantForm.value = { ...restaurant }
+ restaurantDialogVisible.value = true
+}
+
+const saveRestaurant = () => {
+ if (isEditRestaurant.value) {
+ const index = restaurants.value.findIndex((r) => r.id === restaurantForm.value.id)
+ if (index !== -1) {
+ restaurants.value[index] = { ...restaurantForm.value }
+ }
+ } else {
+ const newRestaurant = {
+ ...restaurantForm.value,
+ id: restaurants.value.length + 1,
+ }
+ restaurants.value.push(newRestaurant)
+ }
+ restaurantDialogVisible.value = false
+}
+
+const deleteRestaurant = (id: number) => {
+ restaurants.value = restaurants.value.filter((restaurant) => restaurant.id !== id)
+ // 鍚屾椂鍒犻櫎鍏宠仈鐨勮澶�
+ devices.value = devices.value.filter((device) => device.restaurantId !== id)
+ if (selectedRestaurant.value && selectedRestaurant.value.id === id) {
+ selectedRestaurant.value = null
+ }
+}
+
+const manageDevices = (restaurant: any) => {
+ selectedRestaurant.value = restaurant
+ activeTab.value = 'devices'
+}
+
+// 璁惧绠$悊鏂规硶
+const openDeviceDialog = () => {
+ isEditDevice.value = false
+ deviceForm.value = {
+ id: 0,
+ restaurantId: selectedRestaurant.value.id,
+ deviceId: '',
+ type: 'fume_monitor',
+ location: '',
+ status: 'online',
+ installDate: '',
+ }
+ deviceDialogVisible.value = true
+}
+
+const editDevice = (device: any) => {
+ isEditDevice.value = true
+ deviceForm.value = { ...device }
+ deviceDialogVisible.value = true
+}
+
+const saveDevice = () => {
+ if (isEditDevice.value) {
+ const index = devices.value.findIndex((d) => d.id === deviceForm.value.id)
+ if (index !== -1) {
+ devices.value[index] = { ...deviceForm.value }
+ }
+ } else {
+ const newDevice = {
+ ...deviceForm.value,
+ id: devices.value.length + 1,
+ }
+ devices.value.push(newDevice)
+ }
+ deviceDialogVisible.value = false
+}
+
+const deleteDevice = (id: number) => {
+ devices.value = devices.value.filter((device) => device.id !== id)
+}
+</script>
+
+<style scoped>
+.system-manage {
+ padding: 20px;
+}
+
+.system-card {
+ margin-bottom: 20px;
+}
+
+.card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.system-tabs {
+ margin-top: 20px;
+}
+
+.tab-content {
+ padding: 20px 0;
+}
+
+.search-add-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20px;
+}
+
+.dialog-footer {
+ display: flex;
+ justify-content: flex-end;
+}
+</style>
--
Gitblit v1.9.3