diff --git a/PAGE_OPTIMIZATION_GUIDE.md b/PAGE_OPTIMIZATION_GUIDE.md new file mode 100644 index 0000000..c403a77 --- /dev/null +++ b/PAGE_OPTIMIZATION_GUIDE.md @@ -0,0 +1,145 @@ +# 页面布局优化指南 + +## 已优化的页面 +- CIDList.vue ✓ +- UserList.vue ✓ +- DeviceList.vue ✓ + +## 优化模式 + +所有页面都应该遵循以下布局模式: + +### 1. 导入图标组件 +```javascript +import { Refresh, Plus, Edit, Delete } from "@element-plus/icons-vue"; + +export default { + components: { + Refresh, + Plus, + Edit, + Delete + } +} +``` + +### 2. 模板结构 +```vue + +``` + +### 3. 样式 +```vue + +``` + +## 待优化的页面列表 +- VideoList.vue +- FileList.vue +- ShellList.vue +- CIDLog.vue +- Group.vue +- Chat.vue +- Im.vue +- 其他 views/ 目录下的页面 + +## 优化要点 +1. ✅ 使用 el-card 包裹整个页面 +2. ✅ 标题和操作按钮放在卡片头部 +3. ✅ 表格使用 min-width 自适应宽度 +4. ✅ 操作按钮添加图标 +5. ✅ 对话框样式优化 +6. ✅ 移除旧的 Menu 组件引用 +7. ✅ 充分利用页面空间,消除右侧空白 diff --git a/src/assets/page.css b/src/assets/page.css new file mode 100644 index 0000000..ce76250 --- /dev/null +++ b/src/assets/page.css @@ -0,0 +1,71 @@ +.page-container { + width: 100%; + height: 100%; +} + +.page-card { + height: 100%; + display: flex; + flex-direction: column; + border: none; + border-radius: 8px; +} + +.page-card :deep(.el-card__body) { + flex: 1; + overflow: hidden; + padding: 20px; +} + +.card-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.header-left { + display: flex; + align-items: center; +} + +.page-title { + font-size: 18px; + font-weight: 600; + color: #303133; +} + +.header-actions { + display: flex; + align-items: center; + gap: 12px; +} + +.table-wrapper { + height: 100%; + overflow: auto; +} + +.table-wrapper :deep(.el-table) { + border-radius: 4px; +} + +.form-dialog { + padding: 10px 0; +} + +.dialog-footer { + display: flex; + justify-content: flex-end; + gap: 12px; +} + +.search-bar { + margin-bottom: 16px; + padding: 16px; + background: #f5f7fa; + border-radius: 4px; +} + +.search-bar :deep(.el-form-item) { + margin-bottom: 0; +} diff --git a/src/views/CIDList.vue b/src/views/CIDList.vue index 01b5885..9c62848 100644 --- a/src/views/CIDList.vue +++ b/src/views/CIDList.vue @@ -7,17 +7,25 @@ import { addCIDService } from "@/api/cid.js"; import { deleteCIDService } from "@/api/cid.js"; import { updateCIDService,getCIDRuningListService } from "@/api/cid.js"; import router from "@/router/index.js"; - - +import { VideoPlay, Plus, Refresh, Edit, Delete, Document, View } from "@element-plus/icons-vue"; import {ElMessage, ElLoading} from "element-plus"; export default { + components: { + VideoPlay, + Plus, + Refresh, + Edit, + Delete, + Document, + View + }, data() { return { tableLoading: false, ip: "", tableData: [], - timer: null, // 定时器 + timer: null, tokenData: { server: localStorage.getItem("cid_server") || "gep.ljsea.xyz", token: localStorage.getItem("token"), @@ -61,15 +69,12 @@ export default { }, watch: { - // 监听 runningDialogVisible 的变化 runningDialogVisible(newVal) { if (newVal) { - // 当对话框显示时启动定时器,每秒执行一次 this.timer = setInterval(() => { this.GetCIDRuningList(); }, 1000); } else { - // 当对话框隐藏时清除定时器 if (this.timer) { clearInterval(this.timer); this.timer = null; @@ -78,8 +83,6 @@ export default { } }, - // methods 是一些用来更改状态与触发更新的函数 - // 它们可以在模板中作为事件处理器绑定 methods: { async getCIDList() { this.tableLoading = true; @@ -104,7 +107,6 @@ export default { alert("页码发生变化" + val); }, - //设置项目执行构建部署 async runCID(index) { const loading = ElLoading.service({ lock: true, @@ -138,7 +140,6 @@ export default { router.push("/cidlog"); }, async deleteCID(index) { - //判断是否删除 if (!confirm("是否删除")) { return; } @@ -158,7 +159,6 @@ export default { var d_re = await deleteCIDService(delete_data); if (d_re.code == 0) { ElMessage.success("删除成功"); - //刷新页面 this.getCIDList(); } else { ElMessage.error("操作失败"); @@ -176,9 +176,9 @@ export default { this.updateForm.url = this.tableData[index].Url; this.updateForm.script = this.tableData[index].Script; this.updateForm.time = this.tableData[index].Time; - this.updateForm.cidtoken = this.tableData[index].Token; + this.updateForm.cidtoken = this.tableData[index].Token; this.updateForm.id = id; - this.updateDialogVisible= true; + this.updateDialogVisible = true; }, async addCID() { this.addDialogVisible = false; @@ -193,7 +193,14 @@ export default { result = await addCIDService(this.addForm); if (result.code == 0) { ElMessage.success("添加成功"); - this.getCIDList() + this.getCIDList(); + this.addForm = { + name: "", + time: 0, + url: "", + script: "", + token: localStorage.getItem("token"), + }; } else { ElMessage.error("添加失败"); } @@ -217,7 +224,7 @@ export default { result = await updateCIDService(this.updateForm); if (result.code == 0) { ElMessage.success("修改成功"); - this.getCIDList() + this.getCIDList(); } else { ElMessage.error("修改失败"); } @@ -242,7 +249,7 @@ export default { ElMessage.error("获取失败"); } }catch(e){ - console.log(e) + console.log(e); } }, async getIpClient() { @@ -250,14 +257,13 @@ export default { const response = await axios.get("https://ipinfo.io/json"); this.ip = response.data.ip; localStorage.setItem("ip", this.ip); - //console.log(response); } catch (error) { console.error(error); } }, handleServerChange(){ localStorage.setItem("cid_server", this.tokenData.server); - this.getCIDList() + this.getCIDList(); }, handleMenuSelect(val) { router.push(val); @@ -265,7 +271,6 @@ export default { toVideoList() { router.push("/videoList"); }, - // 修改条纹颜色 tableRowClassName({ row, rowIndex }) { if (row.human === 1) { return { @@ -277,19 +282,15 @@ export default { }, }, - // 生命周期钩子会在组件生命周期的各个不同阶段被调用 - // 例如这个函数就会在组件挂载完成后被调用 async mounted() { let now = new Date(); if (localStorage.getItem("token") === null) { router.push("/login"); } - // console.log("mounted"); this.getIpClient(); this.getCIDList(); }, - // 组件销毁前清除定时器 beforeUnmount() { if (this.timer) { clearInterval(this.timer); @@ -300,254 +301,296 @@ export default { - \ No newline at end of file + +.page-card { + height: 100%; + display: flex; + flex-direction: column; + border: none; + border-radius: 8px; +} + +.page-card :deep(.el-card__body) { + flex: 1; + overflow: hidden; + padding: 20px; +} + +.card-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.header-left { + display: flex; + align-items: center; +} + +.page-title { + font-size: 18px; + font-weight: 600; + color: #303133; +} + +.header-actions { + display: flex; + align-items: center; + gap: 12px; +} + +.server-select { + width: 200px; +} + +.table-wrapper { + height: 100%; + overflow: auto; +} + +.table-wrapper :deep(.el-table) { + border-radius: 4px; +} + +.form-dialog { + padding: 10px 0; +} + +.callback-url { + margin-top: 8px; + display: flex; + align-items: center; + gap: 8px; +} + +.dialog-footer { + display: flex; + justify-content: flex-end; + gap: 12px; +} + diff --git a/src/views/DeviceList.vue b/src/views/DeviceList.vue index a85a1d6..81bd849 100644 --- a/src/views/DeviceList.vue +++ b/src/views/DeviceList.vue @@ -8,12 +8,19 @@ import { deleteDeviceService } from "@/api/device.js"; import { updateDeviceService } from "@/api/device.js"; import router from "@/router/index.js"; import { ElMessage } from 'element-plus'; +import { Refresh, Plus, Edit, Delete, VideoPlay, SwitchButton } from "@element-plus/icons-vue"; import VideoStream from "@/views/DeviceRealVPV2.vue"; export default { components: { VideoStream, + Refresh, + Plus, + Edit, + Delete, + VideoPlay, + SwitchButton }, data() { return { @@ -57,8 +64,6 @@ export default { }; }, - // methods 是一些用来更改状态与触发更新的函数 - // 它们可以在模板中作为事件处理器绑定 methods: { async getDeviceList() { let result = {}; @@ -68,14 +73,6 @@ export default { console.log(e); } let data = result.data; - - // for(let d in data){ - // let res = JSON.parse(d); - // console.log("res=",res); - // this.tableData.push(res); - // } - // console.log(this.tableData); - this.tableData = data; }, onSubmit() { @@ -88,7 +85,6 @@ export default { alert("页码发生变化" + val); }, - //设置设备重启 async restartDevice(index) { var id = this.tableData[index].ID; var restart_data = { @@ -101,11 +97,9 @@ export default { try { var d_re = await restartDeviceService(restart_data); if (d_re.code == 0) { - //alert("重启成功"); ElMessage.success('重启成功'); } else { - alert("操作失败"); - ElMessage.fail('操作失败'); + ElMessage.error('操作失败'); } } catch (e) { console.log(e); @@ -114,17 +108,13 @@ export default { playRealVp(index) { var id = this.tableData[index].ID; localStorage.setItem("realvp_device_id", id); - // router.push("/deviceRealVP"); this.playing_device = id + " " + this.tableData[index].DeviceName; this.deviceStreamDialogVisible = true; }, async deleteDevice(index) { - // 删除前确认 if (!confirm("确定删除吗?")) { return; } - - var id = this.tableData[index].ID; var delete_data = { id: id, @@ -134,13 +124,10 @@ export default { try { var d_re = await deleteDeviceService(delete_data); if (d_re.code == 0) { - //alert("删除成功"); ElMessage.success('删除成功'); - //刷新页面 this.getDeviceList(); } else { - //alert("操作失败"); - ElMessage.fail("操作失败"); + ElMessage.error("操作失败"); } } catch (e) { console.log(e); @@ -165,10 +152,19 @@ export default { result = await addDeviceService(this.addForm); if (result.code == 0) { ElMessage.success("添加成功"); - this.getDeviceList() + this.getDeviceList(); + this.addForm = { + device_name: "", + device_ip: "", + device_status: "", + device_info: "", + device_location: "", + device_type: "", + auth_id: -1, + token: localStorage.getItem("token"), + }; } else { - //alert("添加失败"); - ElMessage.error("添加失败") + ElMessage.error("添加失败"); } } catch (e) { console.log(e); @@ -180,11 +176,10 @@ export default { try { result = await updateDeviceService(this.updateForm); if (result.code == 0) { - //alert("修改成功"); ElMessage.success("修改成功"); - this.getDeviceList() + this.getDeviceList(); } else { - alert("修改失败"); + ElMessage.error("修改失败"); } } catch (e) { console.log(e); @@ -201,10 +196,9 @@ export default { try { var d_re = await restartDeviceService(restart_data); if (d_re.code == 0) { - //alert("重启成功"); ElMessage.success("重启成功"); } else { - alert("操作失败"); + ElMessage.error("操作失败"); } } catch (e) { console.log(e); @@ -215,7 +209,6 @@ export default { const response = await axios.get("https://ipinfo.io/json"); this.ip = response.data.ip; localStorage.setItem("ip", this.ip); - //console.log(response); } catch (error) { console.error(error); } @@ -226,7 +219,6 @@ export default { toVideoList() { router.push("/videoList"); }, - // 修改条纹颜色 tableRowClassName({ row, rowIndex }) { if (row.human === 1) { return { @@ -238,259 +230,217 @@ export default { }, }, - // 生命周期钩子会在组件生命周期的各个不同阶段被调用 - // 例如这个函数就会在组件挂载完成后被调用 async mounted() { let now = new Date(); if (localStorage.getItem("token") === null) { router.push("/login"); } - // console.log("mounted"); - //this.getIpClient(); this.getDeviceList(); }, }; - - - - - - -
+ + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
视频播放({{ playing_device }})
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + +.page-card { + height: 100%; + display: flex; + flex-direction: column; + border: none; + border-radius: 8px; +} + +.page-card :deep(.el-card__body) { + flex: 1; + overflow: hidden; + padding: 20px; +} + +.card-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.header-left { + display: flex; + align-items: center; +} + +.page-title { + font-size: 18px; + font-weight: 600; + color: #303133; +} + +.header-actions { + display: flex; + align-items: center; + gap: 12px; +} + +.table-wrapper { + height: 100%; + overflow: auto; +} + +.table-wrapper :deep(.el-table) { + border-radius: 4px; +} + +.form-dialog { + padding: 10px 0; +} + +.dialog-footer { + display: flex; + justify-content: flex-end; + gap: 12px; +} + +.video-dialog-content { + display: flex; + flex-direction: column; +} + +.video-title { + font-size: 16px; + font-weight: 600; + margin-bottom: 16px; + color: #303133; +} + diff --git a/src/views/UserList.vue b/src/views/UserList.vue index d40f761..cd2689d 100644 --- a/src/views/UserList.vue +++ b/src/views/UserList.vue @@ -17,9 +17,18 @@ import { getFriendListService } from "@/api/chat.js"; import {sendMessageService} from "@/api/chat.js"; import { ElMessage } from 'element-plus'; import CryptoJS from 'crypto-js'; - +import { Search, Refresh, User, ChatDotRound, Message, Setting, Connection } from "@element-plus/icons-vue"; export default { + components: { + Search, + Refresh, + User, + ChatDotRound, + Message, + Setting, + Connection + }, data() { return { ip: "", @@ -50,29 +59,22 @@ export default { }; }, - // methods 是一些用来更改状态与触发更新的函数 - // 它们可以在模板中作为事件处理器绑定 methods: { async getUserList() { let result = {}; try { - //判断search_id是字符串还是数字 if(isNaN(this.search_id)){ - //是字符串,说明是关键字 this.keyword = this.search_id; this.tokenData.id = -1; this.tokenData.keyword = this.keyword; }else if(isFinite(this.search_id)){ - //是数字,说明是ID this.tokenData.id = this.search_id; this.tokenData.keyword = ""; }else{ - //不是数字也不是字符串 ElMessage.error("输入错误,请输入数字或者关键字"); return; } - Cookies.set("search_id", this.search_id); Cookies.set("keyword", this.keyword); result = await SearchUserService(this.tokenData); @@ -108,7 +110,6 @@ export default { console.log(e); } }, - //获取好友列表 async displayFriends(){ let result ={} try{ @@ -124,9 +125,7 @@ export default { console.log(e); } }, - //删除好友 async DelFriendsOrGroup(index){ - // 删除前确认 if (!confirm("确定删除吗?")) { return; } @@ -163,23 +162,16 @@ export default { type: 5, } try{ - result = await addGroupRequestService(req); - console.log(result.code); if(result.code === 0){ ElMessage.success("请求发送成功"); }else{ ElMessage.error("操作失败已有请求或者已经是群组成员"); } - }catch(e){ ElMessage.error("操作失败已有请求或者已经是群组成员"); } - - }, - - //接受好友请求 async AcceptFriendsOrGroup(index){ var id = this.FriendsGRequestList[index].id; var im_id = this.FriendsGRequestList[index].im_id; @@ -207,13 +199,11 @@ export default { }, handleAvatarFileUpload(e) { this.avatar_file = e.target.files[0]; - //判断文件类型是否为图片 if (!this.avatar_file.type.startsWith("image/")) { ElMessage.error("请选择图片文件"); this.avatar_file = null; return; } - //this.UserUpdateForm.avatar = URL.createObjectURL(this.avatar_file); this.uploadAvatarFile(); }, readFileAndCalculateMD5() { @@ -223,7 +213,6 @@ export default { const wordArray = CryptoJS.lib.WordArray.create(event.target.result); const md5Hash = CryptoJS.MD5(wordArray); const md5Str = md5Hash.toString(CryptoJS.enc.Hex); - //console.log("onload: " + md5Str); this.file_md5 = md5Str; resolve(md5Str); }; @@ -242,20 +231,15 @@ export default { try { let result={}; this.file_md5 = await this.readFileAndCalculateMD5(this.avatar_file); - //console.log("md5:",this.file_md5); let md5_result = await GetFileInfoByMd5Service({"md5":this.file_md5,token:this.tokenData.token,"type":1}); if(md5_result.code === 0){ result = md5_result; }else{ let formData = new FormData(); formData.append('file', this.avatar_file); - //console.log("add file: " + this.file); formData.append('upload_type', "1"); formData.append('md5', this.file_md5); formData.append('auth_type', "public"); - //console.log("formData:",formData); - - result = await UploadFileService(formData,this.tokenData.token); if (result.code!== 0) { ElMessage.error('上传文件失败,请稍后再试'); @@ -263,12 +247,8 @@ export default { } } let resp_data = result.data; - - //console.log("resp:",resp_data); let url = "https://tx.ljsea.top/tool/file/"+resp_data.FileStoreName; - this.UserUpdateForm.avatar = url; - //更新用户信息 await this.updateUserInfo(); } catch (error) { ElMessage.error('上传文件时出现网络错误,请稍后再试'); @@ -290,7 +270,6 @@ export default { } else { ElMessage.error("更新失败"); } - }catch(e){ console.log(e); } @@ -320,8 +299,6 @@ export default { console.log(e); } }, - - //获取好友请求列表 async displayFriendReq(){ let result ={} try{ @@ -335,7 +312,6 @@ export default { }catch(e){ console.log(e); } - }, onSubmit() { getUserList({ token: token }); @@ -347,16 +323,13 @@ export default { alert("页码发生变化" + val); }, startChat(index){ - localStorage.setItem("to_user_id", this.tableData[index].ID); localStorage.setItem("to_user_name", this.tableData[index].Name); router.push("/im"); - }, async getMyUserInfo(id){ let result = {}; try{ - //获取用户信息 this.tokenData.id = id; if(this.tokenData.id === undefined){ this.tokenData.id = localStorage.getItem("userId"); @@ -378,21 +351,18 @@ export default { this.UserUpdateForm.video_func = result.data.VideoFunc; this.UserUpdateForm.device_func = result.data.DeviceFunc; this.UserUpdateForm.cid_func = result.data.CIDFunc; - //console.log("token data:",this.tokenData) if(result.data.ID === parseInt(this.tokenData.userId)){ this.role = result.data.Role; localStorage.setItem("video_func", result["data"].VideoFunc > 0 ? "true" : "false"); localStorage.setItem("device_func", result["data"].DeviceFunc > 0 ? "true" : "false"); localStorage.setItem("cid_func", result["data"].CIDFunc > 0 ? "true" : "false"); localStorage.setItem("avatar",result.data.Avatar); - //console.log("my role:",this.role); } } }catch(e){ console.log(e); } }, - async displayMyInfo() { await this.getMyUserInfo(this.tokenData.user_id) this.updateDialogVisible= true; @@ -419,14 +389,12 @@ export default { await this.getMyUserInfo(id) this.updateDialogVisible= true; }, - handleMenuSelect(val) { router.push(val); }, toVideoList() { router.push("/videoList"); }, - // 修改条纹颜色 tableRowClassName({ row, rowIndex }) { if (row.human === 1) { return { @@ -438,14 +406,11 @@ export default { }, }, - // 生命周期钩子会在组件生命周期的各个不同阶段被调用 - // 例如这个函数就会在组件挂载完成后被调用 async mounted() { if (localStorage.getItem("token") === null) { router.push("/login"); } await this.getMyUserInfo(localStorage.getItem("userId")); - this.search_id = Cookies.get("search_id")?Cookies.get("search_id"):2002; this.keyword = Cookies.get("keyword")?Cookies.get("keyword"):""; }, @@ -453,393 +418,265 @@ export default {