代码修改
This commit is contained in:
parent
8d345598cf
commit
1b6239b4bc
@ -1,10 +1,761 @@
|
||||
<!-- src/views/controlPanel/fileStore/index.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<h1>文件存储管理</h1>
|
||||
<p>这个页面显示在Layout中,包含侧边栏</p>
|
||||
<router-link to="/" style="color: blue; text-decoration: underline;">
|
||||
返回首页(无侧边栏)
|
||||
</router-link>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>文件存储</h1>
|
||||
</header>
|
||||
|
||||
<div class="storage-grid">
|
||||
<div
|
||||
v-for="storage in storageOptions"
|
||||
:key="storage.id"
|
||||
:class="['storage-card', storage.class, { selected: selectedStorage === storage.id }]"
|
||||
@click="selectStorage(storage.id)"
|
||||
>
|
||||
<div class="card-header">
|
||||
<div class="card-icon">
|
||||
<i :class="storage.icon"></i>
|
||||
</div>
|
||||
<div class="card-title">{{ storage.name }}</div>
|
||||
</div>
|
||||
<div class="card-description">
|
||||
{{ storage.description }}
|
||||
</div>
|
||||
<div class="card-stats">
|
||||
<div class="stat">
|
||||
<div class="stat-value">{{ storage.capacity }}</div>
|
||||
<div class="stat-label">存储容量</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-value">{{ storage.speed }}</div>
|
||||
<div class="stat-label">传输速度</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-value">{{ storage.price }}</div>
|
||||
<div class="stat-label">价格/月</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<section class="init-section">
|
||||
<h2>初始化文件存储</h2>
|
||||
<div class="init-content">
|
||||
<div class="init-form" v-if="!isInitialized">
|
||||
<div class="form-group">
|
||||
<label for="storageName">存储名称</label>
|
||||
<input
|
||||
id="storageName"
|
||||
v-model="initForm.name"
|
||||
type="text"
|
||||
placeholder="请输入存储名称"
|
||||
:class="{ error: formErrors.name }"
|
||||
>
|
||||
<span class="error-message" v-if="formErrors.name">{{ formErrors.name }}</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="storageSize">存储容量</label>
|
||||
<div class="size-input">
|
||||
<input
|
||||
id="storageSize"
|
||||
v-model.number="initForm.size"
|
||||
type="number"
|
||||
placeholder="请输入存储容量"
|
||||
:class="{ error: formErrors.size }"
|
||||
>
|
||||
<select v-model="initForm.sizeUnit">
|
||||
<option value="GB">GB</option>
|
||||
<option value="TB">TB</option>
|
||||
<option value="PB">PB</option>
|
||||
</select>
|
||||
</div>
|
||||
<span class="error-message" v-if="formErrors.size">{{ formErrors.size }}</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>存储类型</label>
|
||||
<div class="radio-group">
|
||||
<label class="radio-option">
|
||||
<input
|
||||
type="radio"
|
||||
v-model="initForm.storageType"
|
||||
value="standard"
|
||||
>
|
||||
<span class="radio-label">标准存储</span>
|
||||
</label>
|
||||
<label class="radio-option">
|
||||
<input
|
||||
type="radio"
|
||||
v-model="initForm.storageType"
|
||||
value="archive"
|
||||
>
|
||||
<span class="radio-label">归档存储</span>
|
||||
</label>
|
||||
<label class="radio-option">
|
||||
<input
|
||||
type="radio"
|
||||
v-model="initForm.storageType"
|
||||
value="performance"
|
||||
>
|
||||
<span class="radio-label">性能存储</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="checkbox-option">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="initForm.enableEncryption"
|
||||
>
|
||||
<span class="checkmark"></span>
|
||||
启用数据加密
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button class="btn btn-outline" @click="resetForm">重置</button>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
@click="initializeStorage"
|
||||
:disabled="!canInitialize"
|
||||
>
|
||||
{{ isInitializing ? '初始化中...' : '开始初始化' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="init-success" v-else>
|
||||
<div class="success-icon">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
</div>
|
||||
<h3>初始化成功!</h3>
|
||||
<p>文件存储已成功创建,您现在可以开始使用了。</p>
|
||||
<div class="storage-info">
|
||||
<div class="info-item">
|
||||
<span class="info-label">存储名称:</span>
|
||||
<span class="info-value">{{ initializedStorage.name }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">存储区域:</span>
|
||||
<span class="info-value">{{ getSelectedStorageName() }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">存储容量:</span>
|
||||
<span class="info-value">{{ initializedStorage.size }} {{ initializedStorage.sizeUnit }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">存储类型:</span>
|
||||
<span class="info-value">{{ getStorageTypeText(initializedStorage.storageType) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="success-actions">
|
||||
<button class="btn btn-outline" @click="createNewStorage">创建新的存储</button>
|
||||
<button class="btn btn-primary" @click="goToStorage">进入文件存储</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="init-help">
|
||||
<h3>文件存储使用介绍</h3>
|
||||
<p>选择适合您需求的存储区域,配置存储参数并开始使用</p>
|
||||
<div v-if="selectedStorage" class="selected-info">
|
||||
当前选择: <strong>{{ getSelectedStorageName() }}</strong>
|
||||
</div>
|
||||
<div class="help-actions">
|
||||
<button class="btn btn-outline">查看文档</button>
|
||||
<button class="btn btn-primary" @click="viewPricingRules">查看计费规则</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
|
||||
// 定义存储选项接口
|
||||
interface StorageOption {
|
||||
id: number
|
||||
name: string
|
||||
class: string
|
||||
icon: string
|
||||
description: string
|
||||
capacity: string
|
||||
speed: string
|
||||
price: string
|
||||
}
|
||||
|
||||
// 定义初始化表单接口
|
||||
interface InitForm {
|
||||
name: string
|
||||
size: number | null
|
||||
sizeUnit: string
|
||||
storageType: string
|
||||
enableEncryption: boolean
|
||||
}
|
||||
|
||||
interface FormErrors {
|
||||
name?: string
|
||||
size?: string
|
||||
}
|
||||
|
||||
interface InitializedStorage {
|
||||
name: string
|
||||
size: number
|
||||
sizeUnit: string
|
||||
storageType: string
|
||||
enableEncryption: boolean
|
||||
}
|
||||
|
||||
// 响应式数据
|
||||
const selectedStorage = ref<number | null>(null)
|
||||
const isInitializing = ref(false)
|
||||
const isInitialized = ref(false)
|
||||
|
||||
// 初始化表单数据
|
||||
const initForm = reactive<InitForm>({
|
||||
name: '',
|
||||
size: null,
|
||||
sizeUnit: 'GB',
|
||||
storageType: 'standard',
|
||||
enableEncryption: true
|
||||
})
|
||||
|
||||
const formErrors = reactive<FormErrors>({})
|
||||
const initializedStorage = ref<InitializedStorage | null>(null)
|
||||
|
||||
// 存储选项数据
|
||||
const storageOptions = ref<StorageOption[]>([
|
||||
{
|
||||
id: 1,
|
||||
name: 'A100专区',
|
||||
class: 'a100',
|
||||
icon: 'fas fa-microchip',
|
||||
description: '高性能计算存储,适用于AI训练和大数据分析',
|
||||
capacity: '10TB',
|
||||
speed: '10Gbps',
|
||||
price: '¥299'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'V100专区',
|
||||
class: 'v100',
|
||||
icon: 'fas fa-server',
|
||||
description: '企业级存储解决方案,提供高可靠性和稳定性',
|
||||
capacity: '20TB',
|
||||
speed: '8Gbps',
|
||||
price: '¥499'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '佛山区',
|
||||
class: 'foshan',
|
||||
icon: 'fas fa-map-marker-alt',
|
||||
description: '华南地区存储节点,低延迟访问',
|
||||
capacity: '15TB',
|
||||
speed: '6Gbps',
|
||||
price: '¥199'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '北京B区',
|
||||
class: 'beijing',
|
||||
icon: 'fas fa-cloud',
|
||||
description: '华北地区存储节点,高可用性架构',
|
||||
capacity: '25TB',
|
||||
speed: '12Gbps',
|
||||
price: '¥399'
|
||||
}
|
||||
])
|
||||
|
||||
// 计算属性
|
||||
const canInitialize = computed(() => {
|
||||
return selectedStorage.value !== null &&
|
||||
initForm.name.trim() !== '' &&
|
||||
initForm.size !== null &&
|
||||
initForm.size > 0
|
||||
})
|
||||
|
||||
// 方法:选择存储区域
|
||||
const selectStorage = (id: number): void => {
|
||||
selectedStorage.value = id
|
||||
}
|
||||
|
||||
// 方法:获取选中的存储名称
|
||||
const getSelectedStorageName = (): string => {
|
||||
const selected = storageOptions.value.find(storage => storage.id === selectedStorage.value)
|
||||
return selected ? selected.name : ''
|
||||
}
|
||||
|
||||
// 方法:验证表单
|
||||
const validateForm = (): boolean => {
|
||||
// 清空错误信息
|
||||
formErrors.name = ''
|
||||
formErrors.size = ''
|
||||
|
||||
let isValid = true
|
||||
|
||||
if (!initForm.name.trim()) {
|
||||
formErrors.name = '请输入存储名称'
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if (initForm.size === null || initForm.size <= 0) {
|
||||
formErrors.size = '请输入有效的存储容量'
|
||||
isValid = false
|
||||
}
|
||||
|
||||
return isValid
|
||||
}
|
||||
|
||||
// 方法:初始化存储
|
||||
const initializeStorage = async (): Promise<void> => {
|
||||
if (!validateForm()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!selectedStorage.value) {
|
||||
alert('请先选择存储区域')
|
||||
return
|
||||
}
|
||||
|
||||
isInitializing.value = true
|
||||
|
||||
try {
|
||||
// 模拟API调用
|
||||
await new Promise(resolve => setTimeout(resolve, 2000))
|
||||
|
||||
// 保存初始化后的存储信息
|
||||
initializedStorage.value = {
|
||||
name: initForm.name,
|
||||
size: initForm.size!,
|
||||
sizeUnit: initForm.sizeUnit,
|
||||
storageType: initForm.storageType,
|
||||
enableEncryption: initForm.enableEncryption
|
||||
}
|
||||
|
||||
isInitialized.value = true
|
||||
} catch (error) {
|
||||
console.error('初始化失败:', error)
|
||||
alert('初始化失败,请重试')
|
||||
} finally {
|
||||
isInitializing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 方法:重置表单
|
||||
const resetForm = (): void => {
|
||||
initForm.name = ''
|
||||
initForm.size = null
|
||||
initForm.sizeUnit = 'GB'
|
||||
initForm.storageType = 'standard'
|
||||
initForm.enableEncryption = true
|
||||
|
||||
// 清空错误信息
|
||||
formErrors.name = ''
|
||||
formErrors.size = ''
|
||||
}
|
||||
|
||||
// 方法:创建新的存储
|
||||
const createNewStorage = (): void => {
|
||||
isInitialized.value = false
|
||||
resetForm()
|
||||
}
|
||||
|
||||
// 方法:进入文件存储
|
||||
const goToStorage = (): void => {
|
||||
alert('正在跳转到文件存储管理页面...')
|
||||
// 实际项目中这里会进行页面跳转
|
||||
}
|
||||
|
||||
// 方法:获取存储类型文本
|
||||
const getStorageTypeText = (type: string): string => {
|
||||
const typeMap: { [key: string]: string } = {
|
||||
standard: '标准存储',
|
||||
archive: '归档存储',
|
||||
performance: '性能存储'
|
||||
}
|
||||
return typeMap[type] || type
|
||||
}
|
||||
|
||||
// 方法:查看计费规则
|
||||
const viewPricingRules = (): void => {
|
||||
alert('计费规则页面即将打开')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
header {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.2rem;
|
||||
color: #2c3e50;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1px;
|
||||
background: linear-gradient(to right, transparent, #ddd, transparent);
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.6rem;
|
||||
color: #34495e;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.storage-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.storage-card {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
border: 2px solid transparent;
|
||||
}
|
||||
|
||||
.storage-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.storage-card.selected {
|
||||
border-color: #3498db;
|
||||
background-color: #f8fafd;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 15px;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.a100 .card-icon {
|
||||
background-color: #e8f4fd;
|
||||
color: #3498db;
|
||||
}
|
||||
|
||||
.v100 .card-icon {
|
||||
background-color: #e8f6f3;
|
||||
color: #1abc9c;
|
||||
}
|
||||
|
||||
.foshan .card-icon {
|
||||
background-color: #fef9e7;
|
||||
color: #f39c12;
|
||||
}
|
||||
|
||||
.beijing .card-icon {
|
||||
background-color: #fdedec;
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.card-description {
|
||||
color: #7f8c8d;
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.card-stats {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.stat {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-weight: 700;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.8rem;
|
||||
color: #7f8c8d;
|
||||
}
|
||||
|
||||
.init-section {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 25px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.init-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 40px;
|
||||
}
|
||||
|
||||
.init-form {
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.init-help {
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.form-group input[type="text"],
|
||||
.form-group input[type="number"] {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.form-group input:focus {
|
||||
outline: none;
|
||||
border-color: #3498db;
|
||||
}
|
||||
|
||||
.form-group input.error {
|
||||
border-color: #e74c3c;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: #e74c3c;
|
||||
font-size: 12px;
|
||||
margin-top: 5px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.size-input {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.size-input input {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.size-input select {
|
||||
padding: 10px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.radio-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.radio-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.radio-option input {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.checkbox-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox-option input {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 20px;
|
||||
border-radius: 6px;
|
||||
border: none;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #3498db;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover:not(:disabled) {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background-color: transparent;
|
||||
border: 1px solid #3498db;
|
||||
color: #3498db;
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
background-color: #e8f4fd;
|
||||
}
|
||||
|
||||
.init-success {
|
||||
grid-column: 1 / -1;
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
font-size: 4rem;
|
||||
color: #27ae60;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.success-icon i {
|
||||
animation: scaleIn 0.5s ease;
|
||||
}
|
||||
|
||||
@keyframes scaleIn {
|
||||
0% { transform: scale(0); }
|
||||
70% { transform: scale(1.2); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
|
||||
.storage-info {
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin: 30px 0;
|
||||
text-align: left;
|
||||
max-width: 400px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.info-item:last-child {
|
||||
margin-bottom: 0;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.success-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.selected-info {
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
background-color: #e8f4fd;
|
||||
border-radius: 8px;
|
||||
border-left: 4px solid #3498db;
|
||||
}
|
||||
|
||||
.help-actions {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.init-help h3 {
|
||||
font-size: 1.4rem;
|
||||
margin-bottom: 8px;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.init-help p {
|
||||
color: #7f8c8d;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.storage-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.init-content {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.init-form,
|
||||
.init-help {
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.success-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
x
Reference in New Issue
Block a user