feat: 管理员 配置信息类型新增file,file_list,string_list类型
This commit is contained in:
@@ -128,6 +128,40 @@
|
||||
<el-table-column prop="value" label="值" min-width="200" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.type === 'bool'">{{ row.value ? '是' : '否' }}</span>
|
||||
<span v-else-if="row.type === 'file'">
|
||||
<el-link v-if="row.value" type="primary" @click="previewFile(row.value)">
|
||||
文件ID: {{ row.value }}
|
||||
</el-link>
|
||||
<span v-else>-</span>
|
||||
</span>
|
||||
<span v-else-if="row.type === 'file_list'">
|
||||
<div v-if="row.value" class="file-list-display">
|
||||
<el-link
|
||||
v-for="(fileId, index) in getFileList(row.value)"
|
||||
:key="fileId"
|
||||
type="primary"
|
||||
@click="previewFile(fileId)"
|
||||
class="file-link"
|
||||
>
|
||||
文件{{ index + 1 }}: {{ fileId }}
|
||||
</el-link>
|
||||
</div>
|
||||
<span v-else>-</span>
|
||||
</span>
|
||||
<span v-else-if="row.type === 'string_list'">
|
||||
<div v-if="row.value" class="string-list-display">
|
||||
<el-tag
|
||||
v-for="(item, index) in getStringList(row.value)"
|
||||
:key="index"
|
||||
type="primary"
|
||||
size="small"
|
||||
class="string-tag"
|
||||
>
|
||||
{{ item }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<span v-else>-</span>
|
||||
</span>
|
||||
<span v-else>{{ row.value }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -185,6 +219,7 @@
|
||||
:title="groupDialogTitle"
|
||||
width="500px"
|
||||
destroy-on-close
|
||||
class="dialog-scrollable"
|
||||
>
|
||||
<el-form
|
||||
ref="groupFormRef"
|
||||
@@ -216,6 +251,7 @@
|
||||
:title="settingDialogTitle"
|
||||
width="600px"
|
||||
destroy-on-close
|
||||
class="dialog-scrollable"
|
||||
>
|
||||
<el-form
|
||||
ref="settingFormRef"
|
||||
@@ -242,6 +278,9 @@
|
||||
<el-option label="整数 (int)" value="int" />
|
||||
<el-option label="浮点数 (float)" value="float" />
|
||||
<el-option label="布尔值 (bool)" value="bool" />
|
||||
<el-option label="文件 (file)" value="file" />
|
||||
<el-option label="多文件 (file_list)" value="file_list" />
|
||||
<el-option label="字符串列表 (string_list)" value="string_list" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="值" prop="value">
|
||||
@@ -271,6 +310,91 @@
|
||||
v-else-if="settingForm.type === 'bool'"
|
||||
v-model="settingForm.value"
|
||||
/>
|
||||
<div v-else-if="settingForm.type === 'file'" class="file-upload-section">
|
||||
<div class="file-info-display" v-if="settingForm.value && fileInfo">
|
||||
<div class="file-details">
|
||||
<span class="file-name" :title="fileInfo.realName || fileInfo.saveName">{{ fileInfo.realName || fileInfo.saveName }}</span>
|
||||
<span class="file-id">文件ID: {{ settingForm.value }}</span>
|
||||
<span class="file-size">{{ formatFileSize(fileInfo.size) }}</span>
|
||||
</div>
|
||||
<el-button type="danger" size="small" @click="clearFile">删除</el-button>
|
||||
</div>
|
||||
<el-upload
|
||||
v-else
|
||||
:auto-upload="false"
|
||||
:show-file-list="false"
|
||||
:on-change="handleFileChange"
|
||||
accept="*/*"
|
||||
drag
|
||||
class="file-uploader"
|
||||
>
|
||||
<el-icon class="el-icon--upload"><UploadFilled /></el-icon>
|
||||
<div class="el-upload__text">
|
||||
将文件拖到此处,或<em>点击上传</em>
|
||||
</div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">
|
||||
支持任意文件类型,文件上传后将自动保存并获取文件ID
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</div>
|
||||
<div v-else-if="settingForm.type === 'file_list'" class="file-list-section">
|
||||
<div class="file-list-info-display" v-if="getFileList(settingForm.value).length > 0">
|
||||
<div class="file-list-details">
|
||||
<div v-for="(fileInfo, index) in fileListInfo" :key="fileInfo.id" class="file-item">
|
||||
<div class="file-details">
|
||||
<span class="file-name" :title="fileInfo.realName || fileInfo.saveName">{{ fileInfo.realName || fileInfo.saveName }}</span>
|
||||
<span class="file-id">文件ID: {{ fileInfo.id }}</span>
|
||||
<span class="file-size">{{ formatFileSize(fileInfo.size) }}</span>
|
||||
</div>
|
||||
<el-button type="danger" size="small" @click="removeFile(index)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-upload
|
||||
:auto-upload="false"
|
||||
:show-file-list="false"
|
||||
:on-change="handleFileListChange"
|
||||
accept="*/*"
|
||||
drag
|
||||
class="file-uploader"
|
||||
>
|
||||
<el-icon class="el-icon--upload"><UploadFilled /></el-icon>
|
||||
<div class="el-upload__text">
|
||||
将文件拖到此处,或<em>点击上传</em>
|
||||
</div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">
|
||||
支持上传多个文件,文件ID将用逗号分隔存储
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</div>
|
||||
<div v-else-if="settingForm.type === 'string_list'" class="string-list-section">
|
||||
<div class="string-list-display" v-if="getStringList(settingForm.value).length > 0">
|
||||
<div class="string-list-items">
|
||||
<el-tag
|
||||
v-for="(item, index) in getStringList(settingForm.value)"
|
||||
:key="index"
|
||||
closable
|
||||
@close="removeStringItem(index)"
|
||||
class="string-item"
|
||||
>
|
||||
{{ item }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="string-list-input">
|
||||
<el-input
|
||||
v-model="newStringItem"
|
||||
placeholder="请输入字符串,按回车添加"
|
||||
@keyup.enter="addStringItem"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<el-button type="primary" @click="addStringItem" style="margin-top: 10px">添加</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-input
|
||||
v-else
|
||||
v-model="settingForm.value"
|
||||
@@ -304,7 +428,7 @@
|
||||
import { ref, reactive, onMounted, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Search, Plus, Delete } from '@element-plus/icons-vue'
|
||||
import { Search, Plus, Delete, UploadFilled } from '@element-plus/icons-vue'
|
||||
import {
|
||||
getSettingGroupList,
|
||||
getSettingGroupInfo,
|
||||
@@ -318,6 +442,7 @@ import {
|
||||
setSettingOpen,
|
||||
deleteSetting
|
||||
} from '@/api/admin/setting'
|
||||
import { uploadFile } from '@/api/admin/file'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
@@ -393,6 +518,10 @@ const settingDialogVisible = ref(false)
|
||||
const settingDialogTitle = ref('新增配置')
|
||||
const settingFormRef = ref(null)
|
||||
const toggleLoading = ref(null)
|
||||
const fileInfo = ref(null)
|
||||
const fileUploading = ref(false)
|
||||
const fileListInfo = ref([])
|
||||
const newStringItem = ref('')
|
||||
|
||||
// 格式化日期时间
|
||||
const formatDate = (dateString) => {
|
||||
@@ -413,7 +542,10 @@ const getTypeColor = (type) => {
|
||||
'string': 'primary',
|
||||
'int': 'success',
|
||||
'float': 'warning',
|
||||
'bool': 'info'
|
||||
'bool': 'info',
|
||||
'file': 'danger',
|
||||
'file_list': 'danger',
|
||||
'string_list': 'primary'
|
||||
}
|
||||
return colorMap[type] || ''
|
||||
}
|
||||
@@ -630,11 +762,134 @@ const handleTypeChange = (type) => {
|
||||
settingForm.value = false
|
||||
} else if (type === 'int' || type === 'float') {
|
||||
settingForm.value = 0
|
||||
} else if (type === 'file') {
|
||||
settingForm.value = ''
|
||||
fileInfo.value = null
|
||||
} else if (type === 'file_list') {
|
||||
settingForm.value = ''
|
||||
fileListInfo.value = []
|
||||
} else if (type === 'string_list') {
|
||||
settingForm.value = ''
|
||||
newStringItem.value = ''
|
||||
} else {
|
||||
settingForm.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
// 文件变化处理
|
||||
const handleFileChange = async (file) => {
|
||||
fileUploading.value = true
|
||||
try {
|
||||
const formData = new FormData()
|
||||
formData.append('file_names', file.name) // Add file_names as an array
|
||||
formData.append('files', file.raw)
|
||||
formData.append('update_type','cover')
|
||||
formData.append('open_down','true')
|
||||
|
||||
const res = await uploadFile(formData)
|
||||
if (res.data.code === 200 && res.data.data.length > 0) {
|
||||
const uploadedFile = res.data.data[0]
|
||||
settingForm.value = String(uploadedFile.id)
|
||||
fileInfo.value = uploadedFile
|
||||
ElMessage.success('文件上传成功')
|
||||
} else {
|
||||
ElMessage.error(res.data.message || '文件上传失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('文件上传失败:', error)
|
||||
ElMessage.error('文件上传失败')
|
||||
} finally {
|
||||
fileUploading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 清除文件
|
||||
const clearFile = () => {
|
||||
settingForm.value = ''
|
||||
fileInfo.value = null
|
||||
}
|
||||
|
||||
// 格式化文件大小
|
||||
const formatFileSize = (bytes) => {
|
||||
if (!bytes) return '0 B'
|
||||
const k = 1024
|
||||
const sizes = ['B', 'KB', 'MB', 'GB']
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
|
||||
}
|
||||
|
||||
// 预览文件
|
||||
const previewFile = (fileId) => {
|
||||
// 这里可以根据需要实现文件预览逻辑
|
||||
ElMessage.info(`文件ID: ${fileId}`)
|
||||
}
|
||||
|
||||
// 获取文件列表
|
||||
const getFileList = (value) => {
|
||||
if (!value) return []
|
||||
return value.split(',').filter(id => id.trim())
|
||||
}
|
||||
|
||||
// 获取字符串列表
|
||||
const getStringList = (value) => {
|
||||
if (!value) return []
|
||||
return value.split(',').filter(str => str.trim())
|
||||
}
|
||||
|
||||
// 文件列表变化处理
|
||||
const handleFileListChange = async (file) => {
|
||||
fileUploading.value = true
|
||||
try {
|
||||
const formData = new FormData()
|
||||
formData.append('file_names', file.name)
|
||||
formData.append('files', file.raw)
|
||||
formData.append('update_type','cover')
|
||||
formData.append('open_down','true')
|
||||
|
||||
const res = await uploadFile(formData)
|
||||
if (res.data.code === 200 && res.data.data.length > 0) {
|
||||
const uploadedFile = res.data.data[0]
|
||||
const currentFileIds = getFileList(settingForm.value)
|
||||
currentFileIds.push(String(uploadedFile.id))
|
||||
settingForm.value = currentFileIds.join(',')
|
||||
fileListInfo.value.push(uploadedFile)
|
||||
ElMessage.success('文件上传成功')
|
||||
} else {
|
||||
ElMessage.error(res.data.message || '文件上传失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('文件上传失败:', error)
|
||||
ElMessage.error('文件上传失败')
|
||||
} finally {
|
||||
fileUploading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 移除文件
|
||||
const removeFile = (index) => {
|
||||
const currentFileIds = getFileList(settingForm.value)
|
||||
currentFileIds.splice(index, 1)
|
||||
settingForm.value = currentFileIds.join(',')
|
||||
fileListInfo.value.splice(index, 1)
|
||||
}
|
||||
|
||||
// 添加字符串项
|
||||
const addStringItem = () => {
|
||||
if (newStringItem.value.trim()) {
|
||||
const currentItems = getStringList(settingForm.value)
|
||||
currentItems.push(newStringItem.value.trim())
|
||||
settingForm.value = currentItems.join(',')
|
||||
newStringItem.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
// 移除字符串项
|
||||
const removeStringItem = (index) => {
|
||||
const currentItems = getStringList(settingForm.value)
|
||||
currentItems.splice(index, 1)
|
||||
settingForm.value = currentItems.join(',')
|
||||
}
|
||||
|
||||
const handleAddSetting = async () => {
|
||||
settingDialogTitle.value = '新增配置'
|
||||
// 刷新配置组列表以确保数据最新
|
||||
@@ -648,6 +903,9 @@ const handleAddSetting = async () => {
|
||||
open: false,
|
||||
note: ''
|
||||
})
|
||||
fileInfo.value = null
|
||||
fileListInfo.value = []
|
||||
newStringItem.value = ''
|
||||
settingDialogVisible.value = true
|
||||
}
|
||||
|
||||
@@ -672,6 +930,12 @@ const handleEditSetting = async (row) => {
|
||||
settingForm.value = parseInt(data.value) || 0
|
||||
} else if (data.type === 'float') {
|
||||
settingForm.value = parseFloat(data.value) || 0
|
||||
} else if (data.type === 'file') {
|
||||
fileInfo.value = null // 如果需要获取文件信息,可以调用文件详情接口
|
||||
} else if (data.type === 'file_list') {
|
||||
fileListInfo.value = [] // 如果需要获取文件信息,可以调用文件详情接口
|
||||
} else if (data.type === 'string_list') {
|
||||
newStringItem.value = ''
|
||||
}
|
||||
settingDialogVisible.value = true
|
||||
}
|
||||
@@ -888,8 +1152,71 @@ onMounted(() => {
|
||||
background-color: #f8f9fa !important;
|
||||
}
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 0;
|
||||
:deep(.dialog-scrollable .el-dialog) {
|
||||
max-height: 90vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
:deep(.dialog-scrollable .el-dialog__body) {
|
||||
max-height: calc(90vh - 120px);
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
scrollbar-width: none; /* Firefox */
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
}
|
||||
|
||||
/* 完全隐藏滚动条但保持滚动功能 */
|
||||
:deep(.dialog-scrollable .el-dialog__body)::-webkit-scrollbar {
|
||||
display: none; /* Chrome, Safari, Opera */
|
||||
}
|
||||
|
||||
/* 确保弹窗内容区域正确布局 */
|
||||
:deep(.dialog-scrollable .el-dialog__header) {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
:deep(.dialog-scrollable .el-dialog__footer) {
|
||||
flex-shrink: 0;
|
||||
padding: 20px;
|
||||
border-top: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media (max-width: 768px) {
|
||||
:deep(.dialog-scrollable .el-dialog) {
|
||||
max-height: 95vh;
|
||||
width: 95vw !important;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
:deep(.dialog-scrollable .el-dialog__body) {
|
||||
max-height: calc(95vh - 140px);
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
:deep(.dialog-scrollable .el-dialog__footer) {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 确保表单在弹窗中正确显示 */
|
||||
:deep(.dialog-scrollable .el-form) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:deep(.dialog-scrollable .el-form-item) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 文件上传组件在弹窗中的样式优化 */
|
||||
:deep(.dialog-scrollable .file-uploader) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
:deep(.dialog-scrollable .file-info-display),
|
||||
:deep(.dialog-scrollable .file-list-info-display) {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__header) {
|
||||
@@ -918,4 +1245,193 @@ onMounted(() => {
|
||||
:deep(.el-tabs__active-bar) {
|
||||
background-color: #2c3e50;
|
||||
}
|
||||
|
||||
/* 文件上传相关样式 */
|
||||
.file-upload-section {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.file-uploader {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.file-uploader .el-upload) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.file-uploader .el-upload-dragger) {
|
||||
width: 100%;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
:deep(.file-uploader .el-upload-dragger:hover) {
|
||||
border-color: #409eff;
|
||||
}
|
||||
|
||||
.file-info-display {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 6px;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.file-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.file-id {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.file-size {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
/* 文件列表相关样式 */
|
||||
.file-list-section {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.file-list-info-display {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.file-list-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 6px;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.file-item .file-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.file-item .file-name {
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
max-width: 180px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.file-item .file-name:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
/* 字符串列表相关样式 */
|
||||
.string-list-section {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.string-list-display {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.string-list-items {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.string-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.string-list-input {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* 表格中的文件列表和字符串列表样式 */
|
||||
.file-list-display {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.file-link {
|
||||
font-size: 12px;
|
||||
margin-right: 8px;
|
||||
max-width: 150px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.string-list-display {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.string-tag {
|
||||
margin: 0;
|
||||
max-width: 120px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* 响应式调整 */
|
||||
@media (max-width: 768px) {
|
||||
.file-name {
|
||||
max-width: 120px !important;
|
||||
}
|
||||
|
||||
.file-item .file-name {
|
||||
max-width: 100px !important;
|
||||
}
|
||||
|
||||
.file-link {
|
||||
max-width: 100px !important;
|
||||
}
|
||||
|
||||
.string-tag {
|
||||
max-width: 80px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user