|
|
|
|
@ -9,188 +9,361 @@ |
|
|
|
|
style="float: right; padding: 3px 0" |
|
|
|
|
type="text" |
|
|
|
|
icon="el-icon-delete" |
|
|
|
|
@click="handleClearRecords" |
|
|
|
|
:disabled="groupedRecords.length === 0" |
|
|
|
|
@click="handleClearAll" |
|
|
|
|
> |
|
|
|
|
清空记录 |
|
|
|
|
</el-button> |
|
|
|
|
</div> |
|
|
|
|
<div v-for="(dateItem, index) in transferDataList" :key="index"> |
|
|
|
|
<!-- 日期分割线 --> |
|
|
|
|
<el-divider> |
|
|
|
|
<el-tag type="info">{{ dateItem.date }}</el-tag> |
|
|
|
|
</el-divider> |
|
|
|
|
<!-- 传输记录表格 --> |
|
|
|
|
<el-table :data="dateItem.list" :show-header="false"> |
|
|
|
|
<el-table-column label="缩略图标" width="80" align="center"> |
|
|
|
|
<template slot-scope="scope"> |
|
|
|
|
<div class="video-thumb"> |
|
|
|
|
<i class="el-icon-video-camera" /> |
|
|
|
|
</div> |
|
|
|
|
</template> |
|
|
|
|
</el-table-column> |
|
|
|
|
<el-table-column prop="name" label="文件名" show-overflow-tooltip /> |
|
|
|
|
<el-table-column |
|
|
|
|
prop="size" |
|
|
|
|
label="文件大小" |
|
|
|
|
width="120" |
|
|
|
|
align="center" |
|
|
|
|
show-overflow-tooltip |
|
|
|
|
/> |
|
|
|
|
<el-table-column |
|
|
|
|
prop="progress" |
|
|
|
|
label="上传进度" |
|
|
|
|
width="200" |
|
|
|
|
align="center" |
|
|
|
|
> |
|
|
|
|
<template slot-scope="scope"> |
|
|
|
|
<el-progress :percentage="scope.row.progress" stroke-width="8" /> |
|
|
|
|
</template> |
|
|
|
|
</el-table-column> |
|
|
|
|
<el-table-column |
|
|
|
|
prop="time" |
|
|
|
|
label="上传时间" |
|
|
|
|
width="100" |
|
|
|
|
align="center" |
|
|
|
|
show-overflow-tooltip |
|
|
|
|
/> |
|
|
|
|
<el-table-column |
|
|
|
|
prop="status" |
|
|
|
|
label="上传状态" |
|
|
|
|
width="100" |
|
|
|
|
align="center" |
|
|
|
|
> |
|
|
|
|
<template slot-scope="scope"> |
|
|
|
|
<el-tag |
|
|
|
|
:type="scope.row.status === '上传成功' ? 'success' : 'warning'" |
|
|
|
|
> |
|
|
|
|
{{ scope.row.status }} |
|
|
|
|
<div v-loading="loading" class="container"> |
|
|
|
|
<template v-if="groupedRecords.length > 0"> |
|
|
|
|
<div v-for="(group, index) in groupedRecords" :key="index"> |
|
|
|
|
<!-- 日期分割线 --> |
|
|
|
|
<el-divider> |
|
|
|
|
<el-tag type="info"> |
|
|
|
|
{{ group.date }} ({{ group.items.length }}) |
|
|
|
|
</el-tag> |
|
|
|
|
</template> |
|
|
|
|
</el-table-column> |
|
|
|
|
<!-- 操作按钮 --> |
|
|
|
|
<el-table-column label="操作" width="200" align="center"> |
|
|
|
|
<template slot-scope="scope"> |
|
|
|
|
<el-button |
|
|
|
|
type="text" |
|
|
|
|
icon="el-icon-view" |
|
|
|
|
@click="handleOpenFile(scope.row)" |
|
|
|
|
</el-divider> |
|
|
|
|
<!-- 传输记录表格 --> |
|
|
|
|
<el-table :data="group.items" :show-header="false"> |
|
|
|
|
<el-table-column label="缩略图标" width="80" align="center"> |
|
|
|
|
<template slot-scope="scope"> |
|
|
|
|
<div class="file-thumb"> |
|
|
|
|
<i :class="getFileIconClass(scope.row.file_name)" /> |
|
|
|
|
</div> |
|
|
|
|
</template> |
|
|
|
|
</el-table-column> |
|
|
|
|
<el-table-column |
|
|
|
|
prop="file_name" |
|
|
|
|
label="文件名" |
|
|
|
|
show-overflow-tooltip |
|
|
|
|
/> |
|
|
|
|
<el-table-column |
|
|
|
|
label="文件大小" |
|
|
|
|
width="100" |
|
|
|
|
align="center" |
|
|
|
|
show-overflow-tooltip |
|
|
|
|
> |
|
|
|
|
打开 |
|
|
|
|
</el-button> |
|
|
|
|
<el-button |
|
|
|
|
type="text" |
|
|
|
|
icon="el-icon-folder-opened" |
|
|
|
|
@click="handleOpenFolder(scope.row)" |
|
|
|
|
<template slot-scope="scope"> |
|
|
|
|
{{ formatFileSize(scope.row.file_size) }} |
|
|
|
|
</template> |
|
|
|
|
</el-table-column> |
|
|
|
|
<el-table-column label="进度" width="150" align="center"> |
|
|
|
|
<template slot-scope="scope"> |
|
|
|
|
<div class="progress-container"> |
|
|
|
|
<el-progress :percentage="scope.row.is_success ? 100 : 0" /> |
|
|
|
|
</div> |
|
|
|
|
</template> |
|
|
|
|
</el-table-column> |
|
|
|
|
<el-table-column |
|
|
|
|
label="上传时间" |
|
|
|
|
width="80" |
|
|
|
|
align="center" |
|
|
|
|
show-overflow-tooltip |
|
|
|
|
> |
|
|
|
|
打开位置 |
|
|
|
|
</el-button> |
|
|
|
|
</template> |
|
|
|
|
</el-table-column> |
|
|
|
|
</el-table> |
|
|
|
|
<template slot-scope="scope"> |
|
|
|
|
{{ formatTime(scope.row.time) }} |
|
|
|
|
</template> |
|
|
|
|
</el-table-column> |
|
|
|
|
<el-table-column label="状态" width="100" align="center"> |
|
|
|
|
<template slot-scope="scope"> |
|
|
|
|
<el-tag |
|
|
|
|
:type=" |
|
|
|
|
getStatusType( |
|
|
|
|
scope.row.transfer_type, |
|
|
|
|
scope.row.is_success |
|
|
|
|
) |
|
|
|
|
" |
|
|
|
|
size="mini" |
|
|
|
|
> |
|
|
|
|
{{ |
|
|
|
|
getStatusText( |
|
|
|
|
scope.row.transfer_type, |
|
|
|
|
scope.row.is_success |
|
|
|
|
) |
|
|
|
|
}} |
|
|
|
|
</el-tag> |
|
|
|
|
</template> |
|
|
|
|
</el-table-column> |
|
|
|
|
<!-- 操作按钮 --> |
|
|
|
|
<el-table-column label="操作" width="180" align="center"> |
|
|
|
|
<template slot-scope="scope"> |
|
|
|
|
<el-button |
|
|
|
|
v-if="scope.row.transfer_type === 3 && scope.row.file_url" |
|
|
|
|
type="text" |
|
|
|
|
icon="el-icon-view" |
|
|
|
|
@click="handleDownload(scope.row)" |
|
|
|
|
> |
|
|
|
|
打开 |
|
|
|
|
</el-button> |
|
|
|
|
<el-button |
|
|
|
|
v-if="scope.row.transfer_type === 3 && scope.row.file_url" |
|
|
|
|
type="text" |
|
|
|
|
icon="el-icon-folder-opened" |
|
|
|
|
@click="handleOpenLocation(scope.row)" |
|
|
|
|
> |
|
|
|
|
打开位置 |
|
|
|
|
</el-button> |
|
|
|
|
<!-- <el-button |
|
|
|
|
v-if="scope.row.transfer_type === 1" |
|
|
|
|
type="text" |
|
|
|
|
size="mini" |
|
|
|
|
icon="el-icon-upload2" |
|
|
|
|
disabled |
|
|
|
|
> |
|
|
|
|
已上传 |
|
|
|
|
</el-button> |
|
|
|
|
<el-button |
|
|
|
|
type="text" |
|
|
|
|
size="mini" |
|
|
|
|
icon="el-icon-delete" |
|
|
|
|
style="color: #f56c6c" |
|
|
|
|
@click="handleDeleteItem(scope.row)" |
|
|
|
|
> |
|
|
|
|
删除 |
|
|
|
|
</el-button> --> |
|
|
|
|
</template> |
|
|
|
|
</el-table-column> |
|
|
|
|
</el-table> |
|
|
|
|
</div> |
|
|
|
|
</template> |
|
|
|
|
<el-empty v-else description="暂无文件传输记录" /> |
|
|
|
|
</div> |
|
|
|
|
</el-card> |
|
|
|
|
</div> |
|
|
|
|
</template> |
|
|
|
|
<script> |
|
|
|
|
const STORAGE_KEY = "file_transfer_records"; |
|
|
|
|
export default { |
|
|
|
|
name: "Utility", |
|
|
|
|
name: "UtilityPage", |
|
|
|
|
data() { |
|
|
|
|
return { |
|
|
|
|
// 最终渲染数据:数组结构,包含日期 + 文件列表 |
|
|
|
|
transferDataList: [], |
|
|
|
|
loading: false, |
|
|
|
|
transferRecords: [], |
|
|
|
|
}; |
|
|
|
|
}, |
|
|
|
|
created() { |
|
|
|
|
this.getList(); |
|
|
|
|
computed: { |
|
|
|
|
// 按日期分组,与 Qt DisplayFiletransferinfo 逻辑一致 |
|
|
|
|
groupedRecords() { |
|
|
|
|
const groups = {}; |
|
|
|
|
for (const item of this.transferRecords) { |
|
|
|
|
const date = this.formatDate(item.time); |
|
|
|
|
if (!groups[date]) { |
|
|
|
|
groups[date] = { date, items: [] }; |
|
|
|
|
} |
|
|
|
|
groups[date].items.push(item); |
|
|
|
|
} |
|
|
|
|
// 按日期降序,同一天内按时间降序 |
|
|
|
|
return Object.values(groups).sort((a, b) => { |
|
|
|
|
return new Date(b.date) - new Date(a.date); |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
mounted() { |
|
|
|
|
this.loadTransferRecords(); |
|
|
|
|
}, |
|
|
|
|
methods: { |
|
|
|
|
// 查询列表 |
|
|
|
|
getList() { |
|
|
|
|
// 从 localStorage 加载文件传输记录(替代 Qt 的 SQLite 查询) |
|
|
|
|
loadTransferRecords() { |
|
|
|
|
this.loading = true; |
|
|
|
|
// listUser(this.addDateRange(this.queryParams, this.dateRange)).then( |
|
|
|
|
// (response) => { |
|
|
|
|
this.transferDataList = [ |
|
|
|
|
{ |
|
|
|
|
date: "2026-05-13", |
|
|
|
|
list: [ |
|
|
|
|
{ |
|
|
|
|
id: 1, |
|
|
|
|
name: "1633500241136.mp4", |
|
|
|
|
size: "17.92M", |
|
|
|
|
progress: 100, |
|
|
|
|
time: "14:31", |
|
|
|
|
status: "上传成功", |
|
|
|
|
fileUrl: "https://www.w3school.com.cn/i/movie.mp4", |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
id: 2, |
|
|
|
|
name: "TG-2023-01-21-215030828.mp4", |
|
|
|
|
size: "11.86M", |
|
|
|
|
progress: 100, |
|
|
|
|
time: "14:31", |
|
|
|
|
status: "上传成功", |
|
|
|
|
fileUrl: "https://www.w3school.com.cn/i/movie.mp4", |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
id: 3, |
|
|
|
|
name: "VID_20230121_200603.mp4", |
|
|
|
|
size: "10.02M", |
|
|
|
|
progress: 100, |
|
|
|
|
time: "14:16", |
|
|
|
|
status: "上传成功", |
|
|
|
|
fileUrl: "https://www.w3school.com.cn/i/movie.mp4", |
|
|
|
|
}, |
|
|
|
|
], |
|
|
|
|
}, |
|
|
|
|
]; |
|
|
|
|
// this.total = response.total; |
|
|
|
|
// this.loading = false; |
|
|
|
|
// } |
|
|
|
|
// ); |
|
|
|
|
try { |
|
|
|
|
const data = localStorage.getItem(STORAGE_KEY); |
|
|
|
|
if (data) { |
|
|
|
|
this.transferRecords = JSON.parse(data); |
|
|
|
|
} |
|
|
|
|
} catch (e) { |
|
|
|
|
console.error("加载文件传输记录失败", e); |
|
|
|
|
this.transferRecords = []; |
|
|
|
|
} finally { |
|
|
|
|
this.loading = false; |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
// 保存到 localStorage |
|
|
|
|
saveTransferRecords() { |
|
|
|
|
try { |
|
|
|
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(this.transferRecords)); |
|
|
|
|
} catch (e) { |
|
|
|
|
console.error("保存文件传输记录失败", e); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
// 格式化日期,与 Qt "yyyy-MM-dd" 一致 |
|
|
|
|
formatDate(timeStr) { |
|
|
|
|
if (!timeStr) return ""; |
|
|
|
|
const date = new Date(timeStr); |
|
|
|
|
const y = date.getFullYear(); |
|
|
|
|
const m = String(date.getMonth() + 1).padStart(2, "0"); |
|
|
|
|
const d = String(date.getDate()).padStart(2, "0"); |
|
|
|
|
return `${y}-${m}-${d}`; |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 格式化时间,与 Qt "hh:mm" 一致 |
|
|
|
|
formatTime(timeStr) { |
|
|
|
|
if (!timeStr) return ""; |
|
|
|
|
const date = new Date(timeStr); |
|
|
|
|
const h = String(date.getHours()).padStart(2, "0"); |
|
|
|
|
const m = String(date.getMinutes()).padStart(2, "0"); |
|
|
|
|
return `${h}:${m}`; |
|
|
|
|
}, |
|
|
|
|
// 格式化文件大小,与 Qt getSendFileSize 一致 |
|
|
|
|
formatFileSize(size) { |
|
|
|
|
if (!size || size < 0) return "0.00B"; |
|
|
|
|
if (size >= 1024 * 1024) { |
|
|
|
|
return (size / (1024.0 * 1024.0)).toFixed(2) + "M"; |
|
|
|
|
} else if (size >= 1024) { |
|
|
|
|
return (size / 1024.0).toFixed(2) + "K"; |
|
|
|
|
} |
|
|
|
|
return size.toFixed(2) + "B"; |
|
|
|
|
}, |
|
|
|
|
// 获取文件图标类名,与 Qt getFileIconPath 逻辑一致 |
|
|
|
|
getFileIconClass(fileName) { |
|
|
|
|
if (!fileName) return "el-icon-document"; |
|
|
|
|
const suffix = fileName.split(".").pop().toLowerCase(); |
|
|
|
|
const iconMap = { |
|
|
|
|
txt: "el-icon-tickets", |
|
|
|
|
pdf: "el-icon-document-copy", |
|
|
|
|
mp3: "el-icon-headset", |
|
|
|
|
wav: "el-icon-headset", |
|
|
|
|
avi: "el-icon-video-camera", |
|
|
|
|
mp4: "el-icon-video-camera", |
|
|
|
|
wmv: "el-icon-video-camera", |
|
|
|
|
mov: "el-icon-video-camera", |
|
|
|
|
zip: "el-icon-folder-opened", |
|
|
|
|
rar: "el-icon-folder-opened", |
|
|
|
|
ppt: "el-icon-data-board", |
|
|
|
|
pps: "el-icon-data-board", |
|
|
|
|
xls: "el-icon-s-grid", |
|
|
|
|
xlsx: "el-icon-s-grid", |
|
|
|
|
doc: "el-icon-document", |
|
|
|
|
docx: "el-icon-document", |
|
|
|
|
jpg: "el-icon-picture", |
|
|
|
|
jpeg: "el-icon-picture", |
|
|
|
|
jpe: "el-icon-picture", |
|
|
|
|
bmp: "el-icon-picture", |
|
|
|
|
gif: "el-icon-picture", |
|
|
|
|
png: "el-icon-picture", |
|
|
|
|
tif: "el-icon-picture", |
|
|
|
|
tiff: "el-icon-picture", |
|
|
|
|
}; |
|
|
|
|
return iconMap[suffix] || "el-icon-document"; |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 获取状态文字,与 Qt UpdateTransferStatus 逻辑一致 |
|
|
|
|
// type: 1=upload, 3=download, 9=other |
|
|
|
|
getStatusText(type, isSuccess) { |
|
|
|
|
// 与 Qt 的 switch(type << isSuccess) 对应 |
|
|
|
|
const key = type << (isSuccess ? 1 : 0); |
|
|
|
|
const statusMap = { |
|
|
|
|
1: "上传中", // upload=1, is_success=false -> 1 << 0 = 1 (新插入时显示上传中) |
|
|
|
|
2: "上传成功", // upload=1, is_success=true -> 1 << 1 = 2 |
|
|
|
|
3: "下载中", // download=3, is_success=false -> 3 << 0 = 3 (新插入时显示下载中) |
|
|
|
|
6: "下载成功", // download=3, is_success=true -> 3 << 1 = 6 |
|
|
|
|
9: "其他", // other=9 |
|
|
|
|
18: "其他完成", // other=9, is_success=true -> 9 << 1 = 18 |
|
|
|
|
}; |
|
|
|
|
// 实际场景:已有的记录失败时 |
|
|
|
|
if (!isSuccess && key === 1) return "上传失败"; |
|
|
|
|
if (!isSuccess && key === 3) return "下载失败"; |
|
|
|
|
return statusMap[key] || "未知"; |
|
|
|
|
}, |
|
|
|
|
// 清空所有传输记录 |
|
|
|
|
handleClearRecords() { |
|
|
|
|
|
|
|
|
|
// 获取状态标签类型(Element UI 样式) |
|
|
|
|
getStatusType(type, isSuccess) { |
|
|
|
|
if (!isSuccess) return "danger"; |
|
|
|
|
if (type === 1) return "success"; |
|
|
|
|
if (type === 3) return "success"; |
|
|
|
|
return "info"; |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 下载文件 |
|
|
|
|
handleDownload(item) { |
|
|
|
|
if (item.file_url) { |
|
|
|
|
window.open(item.file_url, "_blank"); |
|
|
|
|
} else { |
|
|
|
|
this.$message.warning("文件链接不可用"); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
// 打开文件位置 |
|
|
|
|
handleOpenLocation(item) { |
|
|
|
|
if (item.local_path) { |
|
|
|
|
this.$modal.msg("浏览器安全限制:请下载后在下载列表打开文件夹"); |
|
|
|
|
const a = document.createElement("a"); |
|
|
|
|
a.href = item.file_url; |
|
|
|
|
a.download = item.file_name; |
|
|
|
|
document.body.appendChild(a); |
|
|
|
|
a.click(); |
|
|
|
|
document.body.removeChild(a); |
|
|
|
|
} else { |
|
|
|
|
this.$message.warning("文件路径不可用"); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
// 删除单条记录 |
|
|
|
|
handleDeleteItem(item) { |
|
|
|
|
this.$confirm("确认删除该传输记录?", "提示", { type: "warning" }) |
|
|
|
|
.then(() => { |
|
|
|
|
this.transferRecords = this.transferRecords.filter( |
|
|
|
|
(r) => r.id !== item.id |
|
|
|
|
); |
|
|
|
|
this.saveTransferRecords(); |
|
|
|
|
this.$message.success("删除成功"); |
|
|
|
|
}) |
|
|
|
|
.catch(() => {}); |
|
|
|
|
}, |
|
|
|
|
// 清空所有记录,与 Qt on_clearButton_clicked 逻辑一致 |
|
|
|
|
handleClearAll() { |
|
|
|
|
this.$modal |
|
|
|
|
.confirm("是否要清除本地传输记录?") |
|
|
|
|
.then(() => { |
|
|
|
|
this.transferDataList = []; |
|
|
|
|
this.$modal.msgSuccess("清空成功"); |
|
|
|
|
this.transferRecords = []; |
|
|
|
|
this.saveTransferRecords(); |
|
|
|
|
this.$message.success("记录已清空"); |
|
|
|
|
}) |
|
|
|
|
.catch(() => {}); |
|
|
|
|
}, |
|
|
|
|
// 打开文件 |
|
|
|
|
handleOpenFile(row) { |
|
|
|
|
if (!row.fileUrl) { |
|
|
|
|
this.$modal.msgWarning("文件地址无效,无法打开"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
window.open(row.fileUrl, "_blank"); |
|
|
|
|
// 添加一条新的传输记录(供外部调用,与 Qt UpdateToolsWidgetSlot 对应) |
|
|
|
|
addTransferRecord(record) { |
|
|
|
|
const newRecord = { |
|
|
|
|
id: record.id || Date.now(), |
|
|
|
|
user_id: record.user_id || 0, |
|
|
|
|
file_name: record.file_name || "", |
|
|
|
|
local_path: record.local_path || "", |
|
|
|
|
file_size: record.file_size || 0, |
|
|
|
|
transfer_type: record.transfer_type || 9, |
|
|
|
|
is_success: record.is_success || false, |
|
|
|
|
time: record.time || new Date().toISOString(), |
|
|
|
|
file_url: record.file_url || "", |
|
|
|
|
}; |
|
|
|
|
// 插入到列表顶部(与 Qt InsertToolsItemWidget 对应) |
|
|
|
|
this.transferRecords.unshift(newRecord); |
|
|
|
|
this.saveTransferRecords(); |
|
|
|
|
}, |
|
|
|
|
// 打开文件位置(下载) |
|
|
|
|
handleOpenFolder(row) { |
|
|
|
|
this.$modal.msg("浏览器安全限制:请下载后在下载列表打开文件夹"); |
|
|
|
|
const a = document.createElement("a"); |
|
|
|
|
a.href = row.fileUrl; |
|
|
|
|
a.download = row.name; |
|
|
|
|
document.body.appendChild(a); |
|
|
|
|
a.click(); |
|
|
|
|
document.body.removeChild(a); |
|
|
|
|
// 更新传输状态(供外部调用,与 Qt UpdateFinishedToolsWidgetSlot 对应) |
|
|
|
|
updateTransferStatus(id, isSuccess) { |
|
|
|
|
const record = this.transferRecords.find((r) => r.id === id); |
|
|
|
|
if (record) { |
|
|
|
|
record.is_success = isSuccess; |
|
|
|
|
this.saveTransferRecords(); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
</script> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped> |
|
|
|
|
.video-thumb { |
|
|
|
|
width: 42px; |
|
|
|
|
height: 42px; |
|
|
|
|
border-radius: 6px; |
|
|
|
|
background: #655dd4; |
|
|
|
|
color: #fff; |
|
|
|
|
display: flex; |
|
|
|
|
align-items: center; |
|
|
|
|
justify-content: center; |
|
|
|
|
font-size: 20px; |
|
|
|
|
margin: 0 auto; |
|
|
|
|
.container { |
|
|
|
|
height: calc(100vh - 230px); |
|
|
|
|
overflow-y: auto; |
|
|
|
|
.file-thumb { |
|
|
|
|
width: 42px; |
|
|
|
|
height: 42px; |
|
|
|
|
border-radius: 6px; |
|
|
|
|
background: #655dd4; |
|
|
|
|
color: #fff; |
|
|
|
|
display: flex; |
|
|
|
|
align-items: center; |
|
|
|
|
justify-content: center; |
|
|
|
|
font-size: 20px; |
|
|
|
|
margin: 0 auto; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
</style> |