数据存储
This commit is contained in:
parent
166c3e5d8c
commit
416a9102b0
|
|
@ -0,0 +1,47 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 系统运维->网络配置->查询TCP/IP配置
|
||||
export function getTCPIPConfigAPI(params) {
|
||||
return request({
|
||||
url: '/smartCar/data/device/getTCPIPConfig',
|
||||
method: 'GET',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 系统运维->网络配置->更新TCP/IP配置
|
||||
export function updateTCPIPConfigAPI(data) {
|
||||
return request({
|
||||
url: '/smartCar/data/device/updateTCPIPConfig',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 系统运维->网络配置->查询网络状态
|
||||
export function getNetworkStatusAPI(params) {
|
||||
return request({
|
||||
url: '/smartCar/data/device/getNetworkStatus',
|
||||
method: 'GET',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 系统运维->网络配置->查询网络配置
|
||||
export function getNetworkConfigAPI(params) {
|
||||
return request({
|
||||
url: '/smartCar/data/device/getNetworkConfig',
|
||||
method: 'GET',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 系统运维->网络配置->更新网络配置
|
||||
export function updateNetworkConfigAPI(data) {
|
||||
return request({
|
||||
url: '/smartCar/data/device/updateNetworkConfig',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 系统运维->TF存储->查询存储信息
|
||||
export function getStorageInfoAPI(params) {
|
||||
return request({
|
||||
url: '/smartCar/data/device/getStorageInfo',
|
||||
method: 'GET',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 系统运维->TF存储->格式化存储
|
||||
export function formatStorageAPI(data) {
|
||||
return request({
|
||||
url: '/smartCar/data/device/formatStorage',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -254,20 +254,22 @@ export default {
|
|||
overflow-y: auto;
|
||||
background: linear-gradient(180deg, #f1f6ff 20%, #e5efff 100%);
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
::v-deep .el-card__body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.info-card {
|
||||
margin-bottom: 16px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
height: calc((100vh - 84px - 16px * 2 - 20px) / 2);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
|
|
@ -303,6 +305,9 @@ export default {
|
|||
|
||||
::v-deep .el-card__body {
|
||||
padding: 16px 20px;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
::v-deep .el-descriptions {
|
||||
|
|
@ -343,6 +348,8 @@ export default {
|
|||
}
|
||||
|
||||
.operation-info-card {
|
||||
margin-top: 15px;
|
||||
|
||||
::v-deep .el-descriptions {
|
||||
.el-descriptions__table {
|
||||
.el-descriptions__label {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,532 @@
|
|||
<template>
|
||||
<!-- 设备运维-网络配置 -->
|
||||
<el-card class="network-container" v-loading="loading">
|
||||
<el-card class="network-card">
|
||||
<div slot="header" class="card-header">
|
||||
<div class="tab-header">
|
||||
<div class="tab-item" :class="{ active: activeTab === 'tcpip' }" @click="activeTab = 'tcpip'">TCP/IP</div>
|
||||
<div class="tab-item" :class="{ active: activeTab === '4g5g' }" @click="activeTab = '4g5g'">4G/5G</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TCP/IP 标签页 -->
|
||||
<div v-if="activeTab === 'tcpip'" class="tab-content">
|
||||
<el-form :model="tcpipForm" :rules="tcpipRules" ref="tcpipForm" label-width="120px">
|
||||
<el-form-item label="以太网接口">
|
||||
<el-select v-model="tcpipForm.ethernetInterface" style="width: 400px">
|
||||
<el-option label="eth0" value="eth0"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="启用DHCP">
|
||||
<el-checkbox v-model="tcpipForm.enableDHCP" @change="handleDHCPChange"></el-checkbox>
|
||||
</el-form-item>
|
||||
<el-form-item label="IP地址" prop="ipAddress" required>
|
||||
<el-input v-model="tcpipForm.ipAddress" placeholder="请输入IP地址" style="width: 400px" :disabled="tcpipForm.enableDHCP"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="子网掩码" prop="subnetMask" required>
|
||||
<el-input v-model="tcpipForm.subnetMask" placeholder="请输入子网掩码" style="width: 400px" :disabled="tcpipForm.enableDHCP"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="默认网关">
|
||||
<el-input v-model="tcpipForm.defaultGateway" placeholder="请输入默认网关" style="width: 400px" :disabled="tcpipForm.enableDHCP"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="DNS">
|
||||
<div class="dns-list">
|
||||
<div v-for="(dns, index) in tcpipForm.dnsList" :key="index" class="dns-item">
|
||||
<el-input v-model="dns.value" placeholder="请输入DNS" style="width: 350px" :disabled="tcpipForm.enableDHCP"></el-input>
|
||||
<el-button type="text" icon="el-icon-plus" class="dns-btn add-btn" @click="addDNS" :disabled="tcpipForm.enableDHCP"></el-button>
|
||||
<el-button type="text" icon="el-icon-minus" class="dns-btn remove-btn" @click="removeDNS(index)" :disabled="tcpipForm.enableDHCP || tcpipForm.dnsList.length === 1"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="MAC地址">
|
||||
<el-input v-model="tcpipForm.macAddress" style="width: 400px" disabled></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button class="save-btn" @click="handleSaveTCPIP">保存</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 4G/5G 标签页 -->
|
||||
<div v-if="activeTab === '4g5g'" class="tab-content">
|
||||
<div class="network-layout">
|
||||
<!-- 左侧:状态参数 -->
|
||||
<div class="status-section">
|
||||
<div class="section-header">
|
||||
<i class="el-icon-connection section-icon"></i>
|
||||
<span class="section-title">状态参数</span>
|
||||
</div>
|
||||
<div class="status-list">
|
||||
<div class="status-item">
|
||||
<span class="status-label">模块状态:</span>
|
||||
<span class="status-value">{{ statusInfo.moduleStatus }}</span>
|
||||
</div>
|
||||
<div class="status-item">
|
||||
<span class="status-label">信号强度:</span>
|
||||
<span class="status-value">{{ statusInfo.signalStrength }}</span>
|
||||
</div>
|
||||
<div class="status-item">
|
||||
<span class="status-label">拨号获取的IP地址:</span>
|
||||
<span class="status-value">{{ statusInfo.dialupIp }}</span>
|
||||
</div>
|
||||
<div class="status-item">
|
||||
<span class="status-label">当前网络模式:</span>
|
||||
<span class="status-value">{{ statusInfo.networkMode }}</span>
|
||||
</div>
|
||||
<div class="status-item">
|
||||
<span class="status-label">当前网络运营商:</span>
|
||||
<span class="status-value">{{ statusInfo.operator }}</span>
|
||||
</div>
|
||||
<div class="status-item">
|
||||
<span class="status-label">模块IMEI:</span>
|
||||
<span class="status-value">{{ statusInfo.imei }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:配置参数 -->
|
||||
<div class="config-section">
|
||||
<div class="section-header">
|
||||
<i class="el-icon-setting section-icon"></i>
|
||||
<span class="section-title">配置参数</span>
|
||||
</div>
|
||||
<el-form :model="networkForm" :rules="networkRules" ref="networkForm" label-width="120px">
|
||||
<el-form-item label="4G/5G">
|
||||
<el-input v-model="networkForm.networkType" style="width: 400px" disabled></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="启用拨号">
|
||||
<el-checkbox v-model="networkForm.enableDialup"></el-checkbox>
|
||||
</el-form-item>
|
||||
<el-form-item label="APN" prop="apn">
|
||||
<el-input v-model="networkForm.apn" placeholder="请输入APN" style="width: 400px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="接入号" prop="accessNumber">
|
||||
<el-input v-model="networkForm.accessNumber" placeholder="请输入接入号" style="width: 400px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="拨号用户名" prop="dialupUsername">
|
||||
<el-input v-model="networkForm.dialupUsername" placeholder="请输入拨号用户名" style="width: 400px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="拨号密码" prop="dialupPassword">
|
||||
<el-input v-model="networkForm.dialupPassword" type="password" placeholder="请输入拨号密码" style="width: 400px" show-password></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button class="save-btn" @click="handleSaveNetwork">保存</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getTCPIPConfigAPI, updateTCPIPConfigAPI, getNetworkStatusAPI, getNetworkConfigAPI, updateNetworkConfigAPI } from '@/api/devops/network'
|
||||
|
||||
export default {
|
||||
name: 'Network',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
activeTab: 'tcpip',
|
||||
tcpipForm: {
|
||||
ethernetInterface: 'eth0',
|
||||
enableDHCP: false,
|
||||
ipAddress: '',
|
||||
subnetMask: '',
|
||||
defaultGateway: '',
|
||||
dnsList: [{ value: '' }],
|
||||
macAddress: '18-F2-2C-32-DF-B6'
|
||||
},
|
||||
tcpipRules: {
|
||||
ipAddress: [
|
||||
{ required: true, message: 'IP地址不能为空', trigger: 'blur' }
|
||||
],
|
||||
subnetMask: [
|
||||
{ required: true, message: '子网掩码不能为空', trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
statusInfo: {
|
||||
moduleStatus: '拨号成功',
|
||||
signalStrength: '96',
|
||||
dialupIp: '10.52.34.103',
|
||||
networkMode: 'LTE TDD',
|
||||
operator: '中国移动',
|
||||
imei: '862819047641246'
|
||||
},
|
||||
networkForm: {
|
||||
networkType: '4G',
|
||||
enableDialup: false,
|
||||
apn: '',
|
||||
accessNumber: '',
|
||||
dialupUsername: '',
|
||||
dialupPassword: ''
|
||||
},
|
||||
networkRules: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getTCPIPConfig()
|
||||
this.getNetworkStatus()
|
||||
this.getNetworkConfig()
|
||||
},
|
||||
methods: {
|
||||
/** 获取TCP/IP配置 */
|
||||
async getTCPIPConfig() {
|
||||
try {
|
||||
this.loading = true
|
||||
const res = await getTCPIPConfigAPI()
|
||||
if (res.code === 200 && res.data) {
|
||||
const data = res.data
|
||||
this.tcpipForm = {
|
||||
ethernetInterface: data.ethernetInterface || 'eth0',
|
||||
enableDHCP: data.enableDHCP || false,
|
||||
ipAddress: data.ipAddress || '',
|
||||
subnetMask: data.subnetMask || '',
|
||||
defaultGateway: data.defaultGateway || '',
|
||||
dnsList: data.dnsList && data.dnsList.length > 0 ? data.dnsList.map(dns => ({ value: dns })) : [{ value: '' }],
|
||||
macAddress: data.macAddress || '18-F2-2C-32-DF-B6'
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取TCP/IP配置失败:', error)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
/** 获取网络状态 */
|
||||
async getNetworkStatus() {
|
||||
try {
|
||||
const res = await getNetworkStatusAPI()
|
||||
if (res.code === 200 && res.data) {
|
||||
this.statusInfo = {
|
||||
moduleStatus: res.data.moduleStatus || '拨号成功',
|
||||
signalStrength: res.data.signalStrength || '96',
|
||||
dialupIp: res.data.dialupIp || '10.52.34.103',
|
||||
networkMode: res.data.networkMode || 'LTE TDD',
|
||||
operator: res.data.operator || '中国移动',
|
||||
imei: res.data.imei || '862819047641246'
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取网络状态失败:', error)
|
||||
}
|
||||
},
|
||||
/** 获取网络配置 */
|
||||
async getNetworkConfig() {
|
||||
try {
|
||||
const res = await getNetworkConfigAPI()
|
||||
if (res.code === 200 && res.data) {
|
||||
const data = res.data
|
||||
this.networkForm = {
|
||||
networkType: data.networkType || '4G',
|
||||
enableDialup: data.enableDialup || false,
|
||||
apn: data.apn || '',
|
||||
accessNumber: data.accessNumber || '',
|
||||
dialupUsername: data.dialupUsername || '',
|
||||
dialupPassword: data.dialupPassword || ''
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取网络配置失败:', error)
|
||||
}
|
||||
},
|
||||
/** DHCP切换 */
|
||||
handleDHCPChange() {
|
||||
// DHCP启用时,清空IP相关字段
|
||||
if (this.tcpipForm.enableDHCP) {
|
||||
this.tcpipForm.ipAddress = ''
|
||||
this.tcpipForm.subnetMask = ''
|
||||
this.tcpipForm.defaultGateway = ''
|
||||
}
|
||||
},
|
||||
/** 添加DNS */
|
||||
addDNS() {
|
||||
this.tcpipForm.dnsList.push({ value: '' })
|
||||
},
|
||||
/** 删除DNS */
|
||||
removeDNS(index) {
|
||||
if (this.tcpipForm.dnsList.length > 1) {
|
||||
this.tcpipForm.dnsList.splice(index, 1)
|
||||
}
|
||||
},
|
||||
/** 保存TCP/IP配置 */
|
||||
async handleSaveTCPIP() {
|
||||
try {
|
||||
await this.$refs.tcpipForm.validate()
|
||||
|
||||
if (!this.tcpipForm.enableDHCP) {
|
||||
if (!this.tcpipForm.ipAddress) {
|
||||
this.$message.error('IP地址不能为空')
|
||||
return
|
||||
}
|
||||
if (!this.tcpipForm.subnetMask) {
|
||||
this.$message.error('子网掩码不能为空')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
const params = {
|
||||
ethernetInterface: this.tcpipForm.ethernetInterface,
|
||||
enableDHCP: this.tcpipForm.enableDHCP,
|
||||
ipAddress: this.tcpipForm.ipAddress,
|
||||
subnetMask: this.tcpipForm.subnetMask,
|
||||
defaultGateway: this.tcpipForm.defaultGateway,
|
||||
dnsList: this.tcpipForm.dnsList.map(item => item.value).filter(item => item),
|
||||
macAddress: this.tcpipForm.macAddress
|
||||
}
|
||||
const res = await updateTCPIPConfigAPI(params)
|
||||
if (res.code === 200) {
|
||||
this.$message.success('保存成功')
|
||||
} else {
|
||||
this.$message.error(res.msg || '保存失败')
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.message !== '数据未填写完整') {
|
||||
console.error('保存TCP/IP配置失败:', error)
|
||||
this.$message.error('保存失败,请稍后重试')
|
||||
}
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
/** 保存网络配置 */
|
||||
async handleSaveNetwork() {
|
||||
try {
|
||||
this.loading = true
|
||||
const params = {
|
||||
networkType: this.networkForm.networkType,
|
||||
enableDialup: this.networkForm.enableDialup,
|
||||
apn: this.networkForm.apn,
|
||||
accessNumber: this.networkForm.accessNumber,
|
||||
dialupUsername: this.networkForm.dialupUsername,
|
||||
dialupPassword: this.networkForm.dialupPassword
|
||||
}
|
||||
const res = await updateNetworkConfigAPI(params)
|
||||
if (res.code === 200) {
|
||||
this.$message.success('保存成功')
|
||||
// 保存后重新获取状态
|
||||
this.getNetworkStatus()
|
||||
} else {
|
||||
this.$message.error(res.msg || '保存失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存网络配置失败:', error)
|
||||
this.$message.error('保存失败,请稍后重试')
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.network-container {
|
||||
height: calc(100vh - 84px);
|
||||
overflow-y: auto;
|
||||
background: linear-gradient(180deg, #f1f6ff 20%, #e5efff 100%);
|
||||
padding: 0;
|
||||
|
||||
.network-card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
height: calc(100vh - 130px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.card-header {
|
||||
background: #fff;
|
||||
padding: 0;
|
||||
border-radius: 8px 8px 0 0;
|
||||
|
||||
.tab-header {
|
||||
display: flex;
|
||||
padding: 0;
|
||||
|
||||
.tab-item {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #1f72ea;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #1f72ea;
|
||||
font-weight: 600;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: #1f72ea;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-card__body {
|
||||
padding: 20px;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
::v-deep .el-form-item {
|
||||
margin-bottom: 18px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.el-form-item__label {
|
||||
font-weight: 500;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
|
||||
.dns-list {
|
||||
.dns-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.dns-btn {
|
||||
margin-left: 8px;
|
||||
padding: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.add-btn {
|
||||
background: #1f72ea;
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
background: #4a8bff;
|
||||
}
|
||||
}
|
||||
|
||||
&.remove-btn {
|
||||
background: #f56c6c;
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
background: #f78989;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.network-layout {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 16px;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
|
||||
.status-section,
|
||||
.config-section {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
|
||||
.section-icon {
|
||||
font-size: 18px;
|
||||
color: #1f72ea;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.status-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
|
||||
.status-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid #f5f7fa;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.status-label {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
.status-value {
|
||||
font-size: 14px;
|
||||
color: #303133;
|
||||
background: #f5f7fa;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
width: 98px;
|
||||
height: 36px;
|
||||
background: #1f72ea;
|
||||
box-shadow: 0px 4px 8px 0px rgba(51, 135, 255, 0.5);
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
border: none;
|
||||
font-size: 14px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background: #4a8bff;
|
||||
box-shadow: 0px 6px 12px 0px rgba(51, 135, 255, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
<template>
|
||||
<!-- 设备运维-时间设置 -->
|
||||
<el-card class="time-setting-container" v-loading="loading">
|
||||
<div class="current-time">
|
||||
<span class="time-label">设备当前时间:</span>
|
||||
<span class="time-value">{{ currentTime }}</span>
|
||||
</div>
|
||||
|
||||
<el-card class="setting-card">
|
||||
<div slot="header" class="card-header">
|
||||
<span class="card-title">时间设置</span>
|
||||
</div>
|
||||
|
||||
<div class="current-time">
|
||||
<span class="time-label">设备当前时间:</span>
|
||||
<span class="time-value">{{ currentTime }}</span>
|
||||
</div>
|
||||
|
||||
<el-form :model="form" :rules="rules" ref="timeSettingForm" label-width="120px">
|
||||
<el-form-item label="校时模式" prop="calibrationMode">
|
||||
<el-radio-group v-model="form.calibrationMode" @change="handleModeChange">
|
||||
|
|
@ -179,34 +179,14 @@ export default {
|
|||
height: calc(100vh - 84px);
|
||||
overflow-y: auto;
|
||||
background: linear-gradient(180deg, #f1f6ff 20%, #e5efff 100%);
|
||||
|
||||
.current-time {
|
||||
margin-bottom: 10px;
|
||||
padding: 8px 14px;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
|
||||
|
||||
.time-label {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.time-value {
|
||||
font-size: 14px;
|
||||
color: #303133;
|
||||
font-weight: 600;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
padding: 0px;
|
||||
|
||||
.setting-card {
|
||||
margin-bottom: 0;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
height: calc(100vh - 180px);
|
||||
height: calc(100vh - 130px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
|
|
@ -225,9 +205,32 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
.current-time {
|
||||
margin-bottom: 16px;
|
||||
padding: 8px 14px;
|
||||
// background: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.time-label {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.time-value {
|
||||
font-size: 14px;
|
||||
color: #303133;
|
||||
font-weight: 600;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-card__body {
|
||||
padding: 14px 18px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,346 @@
|
|||
<template>
|
||||
<!-- 设备运维-TF存储 -->
|
||||
<el-card class="storage-container" v-loading="loading">
|
||||
<!-- 存储信息卡片 -->
|
||||
<el-card class="storage-card">
|
||||
<div slot="header" class="card-header">
|
||||
<div class="tab-header">
|
||||
<div class="tab-item active">TF存储</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="storage-info">
|
||||
<div class="storage-text">
|
||||
<span class="available">{{ availableSpace }}GB可用, 共{{ totalSpace }}GB</span>
|
||||
</div>
|
||||
<el-button class="format-btn" @click="handleFormat">格式化</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 进度条 -->
|
||||
<div class="progress-container">
|
||||
<div class="progress-bar">
|
||||
<el-tooltip
|
||||
v-if="usedPercentage > 0"
|
||||
:content="`已用 容量:${usedSpace.toFixed(2)}GB(${usedPercentage.toFixed(2)}%)`"
|
||||
placement="top"
|
||||
effect="dark">
|
||||
<div class="progress-used" :style="{ width: usedPercentage + '%' }"></div>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
v-if="freePercentage > 0"
|
||||
:content="`空闲 容量:${availableSpace.toFixed(2)}GB(${freePercentage.toFixed(2)}%)`"
|
||||
placement="top"
|
||||
effect="dark">
|
||||
<div class="progress-free" :style="{ width: freePercentage + '%' }"></div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 图例 -->
|
||||
<div class="legend">
|
||||
<div class="legend-item">
|
||||
<span class="legend-color used-color"></span>
|
||||
<span class="legend-label">已用</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<span class="legend-color free-color"></span>
|
||||
<span class="legend-label">空闲</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 格式化确认对话框 -->
|
||||
<el-dialog
|
||||
title="格式化"
|
||||
:visible.sync="formatDialogVisible"
|
||||
width="400px"
|
||||
:close-on-click-modal="false">
|
||||
<div class="dialog-content">
|
||||
<i class="el-icon-warning warning-icon"></i>
|
||||
<span class="dialog-message">确定格式化当前固态硬盘吗?</span>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="formatDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmFormat">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getStorageInfoAPI, formatStorageAPI } from '@/api/devops/storage'
|
||||
|
||||
export default {
|
||||
name: 'Storage',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
totalSpace: 128,
|
||||
usedSpace: 100,
|
||||
availableSpace: 28,
|
||||
formatDialogVisible: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
usedPercentage() {
|
||||
if (this.totalSpace === 0) return 0
|
||||
return Math.round((this.usedSpace / this.totalSpace) * 100)
|
||||
},
|
||||
freePercentage() {
|
||||
return 100 - this.usedPercentage
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getStorageInfo()
|
||||
},
|
||||
methods: {
|
||||
/** 获取存储信息 */
|
||||
async getStorageInfo() {
|
||||
try {
|
||||
this.loading = true
|
||||
const res = await getStorageInfoAPI()
|
||||
if (res.code === 200 && res.data) {
|
||||
const data = res.data
|
||||
this.totalSpace = data.totalSpace || 128
|
||||
this.usedSpace = data.usedSpace || 100
|
||||
this.availableSpace = data.availableSpace || 28
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取存储信息失败:', error)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
/** 格式化操作 */
|
||||
handleFormat() {
|
||||
this.formatDialogVisible = true
|
||||
},
|
||||
/** 确认格式化 */
|
||||
async confirmFormat() {
|
||||
try {
|
||||
this.loading = true
|
||||
const res = await formatStorageAPI()
|
||||
if (res.code === 200) {
|
||||
this.$message.success('格式化成功')
|
||||
this.formatDialogVisible = false
|
||||
// 格式化后重新获取存储信息
|
||||
this.getStorageInfo()
|
||||
} else {
|
||||
this.$message.error(res.msg || '格式化失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('格式化失败:', error)
|
||||
this.$message.error('格式化失败,请稍后重试')
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.storage-container {
|
||||
height: calc(100vh - 84px);
|
||||
overflow-y: auto;
|
||||
background: linear-gradient(180deg, #f1f6ff 20%, #e5efff 100%);
|
||||
padding: 0;
|
||||
|
||||
.storage-card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
height: calc(100vh - 130px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.card-header {
|
||||
background: #fff;
|
||||
padding: 0;
|
||||
border-radius: 8px 8px 0 0;
|
||||
|
||||
.tab-header {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
.tab-item {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
&.active {
|
||||
color: #1f72ea;
|
||||
font-weight: 600;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: #1f72ea;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-card__body {
|
||||
padding: 20px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.storage-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.storage-text {
|
||||
.available {
|
||||
font-size: 14px;
|
||||
color: #303133;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.format-btn {
|
||||
background: #f5f7fa;
|
||||
border: 1px solid #dcdfe6;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background: #e4e7ed;
|
||||
border-color: #c0c4cc;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.progress-container {
|
||||
margin-bottom: 16px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
background: #f5f7fa;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
|
||||
.progress-used {
|
||||
background: #ff6b9d;
|
||||
height: 100%;
|
||||
transition: width 0.3s;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-free {
|
||||
background: #1f72ea;
|
||||
height: 100%;
|
||||
transition: width 0.3s;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.legend {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.legend-color {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 2px;
|
||||
display: inline-block;
|
||||
|
||||
&.used-color {
|
||||
background: #ff6b9d;
|
||||
}
|
||||
|
||||
&.free-color {
|
||||
background: #1f72ea;
|
||||
}
|
||||
}
|
||||
|
||||
.legend-label {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-dialog {
|
||||
.el-dialog__header {
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
|
||||
.el-dialog__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 20px;
|
||||
|
||||
.dialog-content {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
|
||||
.warning-icon {
|
||||
font-size: 24px;
|
||||
color: #f56c6c;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.dialog-message {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
padding: 12px 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
text-align: right;
|
||||
|
||||
.el-button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Loading…
Reference in New Issue