feat: 管理员 配置信息类型新增file,file_list,string_list类型
This commit is contained in:
@@ -1,600 +0,0 @@
|
||||
<template>
|
||||
<div class="setting-container">
|
||||
<!-- 主容器 -->
|
||||
<el-card class="main-container" shadow="never">
|
||||
<!-- 搜索和操作栏 -->
|
||||
<div class="filter-section">
|
||||
<div class="filter-content">
|
||||
<el-form :inline="true" :model="queryParams" class="search-form">
|
||||
<el-form-item label="配置组">
|
||||
<el-select v-model="queryParams.group_id" placeholder="请选择配置组" clearable style="width: 200px" @change="handleQuery">
|
||||
<el-option
|
||||
v-for="group in groupList"
|
||||
:key="group.id"
|
||||
:label="group.name"
|
||||
:value="group.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="关键词筛选">
|
||||
<el-input v-model="queryParams.key" placeholder="请输入关键词" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">
|
||||
<el-icon><Search /></el-icon>查询
|
||||
</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="action-bar">
|
||||
<el-button type="primary" @click="handleAdd">
|
||||
<el-icon><Plus /></el-icon>新增配置
|
||||
</el-button>
|
||||
<el-button type="danger" :disabled="!selectedRows.length" @click="handleBatchDelete">
|
||||
<el-icon><Delete /></el-icon>批量删除
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 配置列表 -->
|
||||
<div class="table-section">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="settingList"
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
:header-cell-style="{ background: '#fafafa', color: '#333', fontWeight: 600 }"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column prop="id" label="ID" width="80" />
|
||||
<el-table-column prop="name" label="名称" min-width="150" />
|
||||
<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>{{ row.value }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="type" label="类型" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getTypeColor(row.type)">
|
||||
{{ row.type || '未知' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="settingGroupID" label="配置组" width="150" />
|
||||
<el-table-column label="是否开放" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-switch
|
||||
v-model="row.open"
|
||||
@change="handleToggleOpen(row)"
|
||||
:disabled="toggleLoading === row.id"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="note" label="备注" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column label="创建时间" width="180">
|
||||
<template #default="{ row }">
|
||||
{{ formatDate(row.CreatedAt) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button type="danger" link @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<el-pagination
|
||||
v-model:current-page="queryParams.page"
|
||||
v-model:page-size="queryParams.count"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
background
|
||||
class="pagination"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 配置表单对话框 -->
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogTitle"
|
||||
width="600px"
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form
|
||||
ref="settingFormRef"
|
||||
:model="settingForm"
|
||||
:rules="settingRules"
|
||||
label-width="120px"
|
||||
>
|
||||
<el-form-item label="配置组" prop="settingGroupID">
|
||||
<el-select v-model="settingForm.settingGroupID" placeholder="请选择配置组" style="width: 100%">
|
||||
<el-option
|
||||
v-for="group in groupList"
|
||||
:key="group.id"
|
||||
:label="group.name"
|
||||
:value="group.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="settingForm.name" placeholder="请输入配置名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="type">
|
||||
<el-select v-model="settingForm.type" placeholder="请选择类型" style="width: 100%" @change="handleTypeChange">
|
||||
<el-option label="字符串 (string)" value="string" />
|
||||
<el-option label="整数 (int)" value="int" />
|
||||
<el-option label="浮点数 (float)" value="float" />
|
||||
<el-option label="布尔值 (bool)" value="bool" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="值" prop="value">
|
||||
<el-input
|
||||
v-if="settingForm.type === 'string'"
|
||||
v-model="settingForm.value"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入配置值"
|
||||
/>
|
||||
<el-input-number
|
||||
v-else-if="settingForm.type === 'int'"
|
||||
v-model="settingForm.value"
|
||||
:controls="false"
|
||||
placeholder="请输入整数"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<el-input-number
|
||||
v-else-if="settingForm.type === 'float'"
|
||||
v-model="settingForm.value"
|
||||
:controls="false"
|
||||
:precision="2"
|
||||
placeholder="请输入浮点数"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<el-switch
|
||||
v-else-if="settingForm.type === 'bool'"
|
||||
v-model="settingForm.value"
|
||||
/>
|
||||
<el-input
|
||||
v-else
|
||||
v-model="settingForm.value"
|
||||
placeholder="请输入配置值"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否开放访问">
|
||||
<el-switch v-model="settingForm.open" />
|
||||
<span style="margin-left: 10px; color: #909399; font-size: 12px;">
|
||||
开启后允许公开访问
|
||||
</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="note">
|
||||
<el-input
|
||||
v-model="settingForm.note"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入备注信息"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitForm">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Search, Plus, Delete } from '@element-plus/icons-vue'
|
||||
import {
|
||||
getSettingList,
|
||||
getSettingInfo,
|
||||
createSetting,
|
||||
updateSetting,
|
||||
setSettingOpen,
|
||||
deleteSetting
|
||||
} from '@/api/admin/setting'
|
||||
import { getSettingGroupList } from '@/api/admin/setting'
|
||||
|
||||
// 查询参数
|
||||
const queryParams = reactive({
|
||||
group_id: undefined,
|
||||
key: '',
|
||||
page: 1,
|
||||
count: 10
|
||||
})
|
||||
|
||||
// 配置表单
|
||||
const settingForm = reactive({
|
||||
id: undefined,
|
||||
name: '',
|
||||
value: '',
|
||||
type: 'string',
|
||||
settingGroupID: undefined,
|
||||
open: false,
|
||||
note: ''
|
||||
})
|
||||
|
||||
const settingRules = {
|
||||
name: [
|
||||
{ required: true, message: '请输入配置名称', trigger: 'blur' }
|
||||
],
|
||||
value: [
|
||||
{ required: true, message: '请输入配置值', trigger: 'blur' }
|
||||
],
|
||||
type: [
|
||||
{ required: true, message: '请选择配置类型', trigger: 'change' }
|
||||
],
|
||||
settingGroupID: [
|
||||
{ required: true, message: '请选择配置组', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
|
||||
// 状态数据
|
||||
const loading = ref(false)
|
||||
const settingList = ref([])
|
||||
const groupList = ref([])
|
||||
const total = ref(0)
|
||||
const selectedRows = ref([])
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('新增配置')
|
||||
const settingFormRef = ref(null)
|
||||
const toggleLoading = ref(null)
|
||||
|
||||
// 格式化日期时间
|
||||
const formatDate = (dateString) => {
|
||||
if (!dateString) return '-'
|
||||
const date = new Date(dateString)
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
const hours = String(date.getHours()).padStart(2, '0')
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0')
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0')
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
||||
}
|
||||
|
||||
// 获取类型颜色
|
||||
const getTypeColor = (type) => {
|
||||
const colorMap = {
|
||||
'string': 'primary',
|
||||
'int': 'success',
|
||||
'float': 'warning',
|
||||
'bool': 'info'
|
||||
}
|
||||
return colorMap[type] || ''
|
||||
}
|
||||
|
||||
// 获取配置组列表
|
||||
const fetchGroupList = async () => {
|
||||
try {
|
||||
const res = await getSettingGroupList({ page: 1, count: 1000 })
|
||||
if (res.data.code === 200) {
|
||||
groupList.value = res.data.data.data || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取配置组列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取配置列表
|
||||
const fetchSettingList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = { ...queryParams }
|
||||
if (!params.group_id) {
|
||||
delete params.group_id
|
||||
}
|
||||
const res = await getSettingList(params)
|
||||
console.log('配置列表数据:', res.data)
|
||||
if (res.data.code === 200) {
|
||||
settingList.value = res.data.data.data || []
|
||||
total.value = res.data.data.all_count || 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取配置列表失败:', error)
|
||||
ElMessage.error('获取配置列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 查询
|
||||
const handleQuery = () => {
|
||||
queryParams.page = 1
|
||||
fetchSettingList()
|
||||
}
|
||||
|
||||
// 重置查询
|
||||
const resetQuery = () => {
|
||||
queryParams.group_id = undefined
|
||||
queryParams.key = ''
|
||||
queryParams.page = 1
|
||||
fetchSettingList()
|
||||
}
|
||||
|
||||
// 选择项变化
|
||||
const handleSelectionChange = (selection) => {
|
||||
selectedRows.value = selection
|
||||
}
|
||||
|
||||
// 分页
|
||||
const handleSizeChange = (size) => {
|
||||
queryParams.count = size
|
||||
fetchSettingList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (page) => {
|
||||
queryParams.page = page
|
||||
fetchSettingList()
|
||||
}
|
||||
|
||||
// 类型变化
|
||||
const handleTypeChange = (type) => {
|
||||
// 根据类型重置值
|
||||
if (type === 'bool') {
|
||||
settingForm.value = false
|
||||
} else if (type === 'int' || type === 'float') {
|
||||
settingForm.value = 0
|
||||
} else {
|
||||
settingForm.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
// 新增配置
|
||||
const handleAdd = () => {
|
||||
dialogTitle.value = '新增配置'
|
||||
Object.assign(settingForm, {
|
||||
id: undefined,
|
||||
name: '',
|
||||
value: '',
|
||||
type: 'string',
|
||||
setting_group_id: undefined,
|
||||
open: false,
|
||||
note: ''
|
||||
})
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
// 编辑配置
|
||||
const handleEdit = async (row) => {
|
||||
dialogTitle.value = '编辑配置'
|
||||
try {
|
||||
const res = await getSettingInfo({ id: row.id })
|
||||
console.log('配置详情数据:', res)
|
||||
if (res.data.code === 200) {
|
||||
const data = res.data.data
|
||||
Object.assign(settingForm, {
|
||||
id: data.id,
|
||||
name: data.name || '',
|
||||
value: data.value,
|
||||
type: data.type || 'string',
|
||||
settingGroupID: data.settingGroupID,
|
||||
open: data.open || false,
|
||||
note: data.note || ''
|
||||
})
|
||||
console.log('配置详情数据:', settingForm)
|
||||
// 根据类型转换值
|
||||
if (data.type === 'bool') {
|
||||
settingForm.value = data.value === true || data.value === 'true' || data.value === 1
|
||||
} else if (data.type === 'int') {
|
||||
settingForm.value = parseInt(data.value) || 0
|
||||
} else if (data.type === 'float') {
|
||||
settingForm.value = parseFloat(data.value) || 0
|
||||
}
|
||||
dialogVisible.value = true
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取配置详情失败:', error)
|
||||
ElMessage.error('获取配置详情失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 切换开放状态
|
||||
const handleToggleOpen = async (row) => {
|
||||
toggleLoading.value = row.id
|
||||
try {
|
||||
const res = await setSettingOpen({
|
||||
id: row.id,
|
||||
open: row.open
|
||||
})
|
||||
if (res.data.code === 200) {
|
||||
ElMessage.success('修改成功')
|
||||
} else {
|
||||
// 恢复原状态
|
||||
row.open = !row.open
|
||||
ElMessage.error(res.data.message || '修改失败')
|
||||
}
|
||||
} catch (error) {
|
||||
// 恢复原状态
|
||||
row.open = !row.open
|
||||
console.error('修改失败:', error)
|
||||
ElMessage.error(error.response?.data?.message || '修改失败')
|
||||
} finally {
|
||||
toggleLoading.value = null
|
||||
}
|
||||
}
|
||||
|
||||
// 删除配置
|
||||
const handleDelete = (row) => {
|
||||
ElMessageBox.confirm(`确认删除配置 "${row.name}" 吗?`, '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
try {
|
||||
const res = await deleteSetting({ id: row.id })
|
||||
console.log('删除配置响应:', res.data)
|
||||
if (res.data.code === 200) {
|
||||
ElMessage.success('删除成功')
|
||||
fetchSettingList()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error)
|
||||
ElMessage.error(error.response?.data?.message || '删除失败')
|
||||
}
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
// 批量删除
|
||||
const handleBatchDelete = () => {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning('请至少选择一条记录')
|
||||
return
|
||||
}
|
||||
ElMessageBox.confirm(`确认删除选中的 ${selectedRows.value.length} 条记录吗?`, '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
try {
|
||||
const deletePromises = selectedRows.value.map(row =>
|
||||
deleteSetting({ id: row.id })
|
||||
)
|
||||
await Promise.all(deletePromises)
|
||||
ElMessage.success('批量删除成功')
|
||||
fetchSettingList()
|
||||
} catch (error) {
|
||||
console.error('批量删除失败:', error)
|
||||
ElMessage.error('批量删除失败')
|
||||
}
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const submitForm = () => {
|
||||
settingFormRef.value?.validate(async (valid) => {
|
||||
if (valid) {
|
||||
try {
|
||||
const submitData = {
|
||||
name: settingForm.name,
|
||||
value: String(settingForm.value),
|
||||
type: settingForm.type,
|
||||
setting_group_id: settingForm.settingGroupID,
|
||||
open: settingForm.open,
|
||||
note: settingForm.note
|
||||
}
|
||||
if (settingForm.id) {
|
||||
submitData.id = settingForm.id
|
||||
}
|
||||
console.log('提交配置数据:', submitData)
|
||||
const res = settingForm.id
|
||||
? await updateSetting(submitData)
|
||||
: await createSetting(submitData)
|
||||
if (res.data.code === 200) {
|
||||
ElMessage.success(settingForm.id ? '修改成功' : '创建成功')
|
||||
dialogVisible.value = false
|
||||
fetchSettingList()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error)
|
||||
ElMessage.error(error.response?.data?.message || '提交失败')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
fetchGroupList()
|
||||
fetchSettingList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.setting-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
border: 1px solid #e1e8ed;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.filter-section {
|
||||
padding: 0;
|
||||
border-bottom: 1px solid #e1e8ed;
|
||||
background: #fafbfc;
|
||||
}
|
||||
|
||||
.filter-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px 20px;
|
||||
gap: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.search-form :deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.action-bar {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.table-section {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-top: 20px;
|
||||
padding: 16px 20px;
|
||||
border-top: 1px solid #e1e8ed;
|
||||
background: #fafbfc;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* 表格样式优化 */
|
||||
:deep(.el-table) {
|
||||
border: none;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
:deep(.el-table__header) {
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
:deep(.el-table th) {
|
||||
background: #f8f9fa !important;
|
||||
border-bottom: 2px solid #e1e8ed;
|
||||
color: #2c3e50;
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
:deep(.el-table td) {
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
color: #34495e;
|
||||
}
|
||||
|
||||
:deep(.el-table tr:hover > td) {
|
||||
background-color: #f8f9fa !important;
|
||||
}
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,409 +0,0 @@
|
||||
<template>
|
||||
<div class="setting-group-container">
|
||||
<!-- 主容器 -->
|
||||
<el-card class="main-container" shadow="never">
|
||||
<!-- 搜索和操作栏 -->
|
||||
<div class="filter-section">
|
||||
<div class="filter-content">
|
||||
<el-form :inline="true" :model="queryParams" class="search-form">
|
||||
<el-form-item label="关键词筛选">
|
||||
<el-input v-model="queryParams.key" placeholder="请输入关键词" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">
|
||||
<el-icon><Search /></el-icon>查询
|
||||
</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="action-bar">
|
||||
<el-button type="primary" @click="handleAdd">
|
||||
<el-icon><Plus /></el-icon>新增配置组
|
||||
</el-button>
|
||||
<el-button type="danger" :disabled="!selectedRows.length" @click="handleBatchDelete">
|
||||
<el-icon><Delete /></el-icon>批量删除
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 配置组列表 -->
|
||||
<div class="table-section">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="groupList"
|
||||
@selection-change="handleSelectionChange"
|
||||
style="width: 100%"
|
||||
:header-cell-style="{ background: '#fafafa', color: '#333', fontWeight: 600 }"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column prop="id" label="ID" width="80" />
|
||||
<el-table-column prop="name" label="名称" min-width="200" />
|
||||
<el-table-column prop="note" label="备注" min-width="250" show-overflow-tooltip />
|
||||
<el-table-column label="创建时间" width="180">
|
||||
<template #default="{ row }">
|
||||
{{ formatDate(row.CreatedAt) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="更新时间" width="180">
|
||||
<template #default="{ row }">
|
||||
{{ formatDate(row.UpdatedAt) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button type="danger" link @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<el-pagination
|
||||
v-model:current-page="queryParams.page"
|
||||
v-model:page-size="queryParams.count"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
background
|
||||
class="pagination"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 配置组表单对话框 -->
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogTitle"
|
||||
width="500px"
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form
|
||||
ref="groupFormRef"
|
||||
:model="groupForm"
|
||||
:rules="groupRules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="groupForm.name" placeholder="请输入配置组名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="note">
|
||||
<el-input
|
||||
v-model="groupForm.note"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入备注信息"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitForm">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Search, Plus, Delete } from '@element-plus/icons-vue'
|
||||
import {
|
||||
getSettingGroupList,
|
||||
getSettingGroupInfo,
|
||||
createSettingGroup,
|
||||
updateSettingGroup,
|
||||
deleteSettingGroup
|
||||
} from '@/api/admin/setting'
|
||||
|
||||
// 查询参数
|
||||
const queryParams = reactive({
|
||||
key: '',
|
||||
page: 1,
|
||||
count: 10
|
||||
})
|
||||
|
||||
// 配置组表单
|
||||
const groupForm = reactive({
|
||||
id: undefined,
|
||||
name: '',
|
||||
note: ''
|
||||
})
|
||||
|
||||
const groupRules = {
|
||||
name: [
|
||||
{ required: true, message: '请输入配置组名称', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
|
||||
// 状态数据
|
||||
const loading = ref(false)
|
||||
const groupList = ref([])
|
||||
const total = ref(0)
|
||||
const selectedRows = ref([])
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('新增配置组')
|
||||
const groupFormRef = ref(null)
|
||||
|
||||
// 格式化日期时间
|
||||
const formatDate = (dateString) => {
|
||||
if (!dateString) return '-'
|
||||
const date = new Date(dateString)
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
const hours = String(date.getHours()).padStart(2, '0')
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0')
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0')
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
||||
}
|
||||
|
||||
// 获取配置组列表
|
||||
const fetchGroupList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getSettingGroupList(queryParams)
|
||||
console.log('配置组列表数据:', res.data)
|
||||
if (res.data.code === 200) {
|
||||
groupList.value = res.data.data.data || []
|
||||
total.value = res.data.data.all_count || 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取配置组列表失败:', error)
|
||||
ElMessage.error('获取配置组列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 查询
|
||||
const handleQuery = () => {
|
||||
queryParams.page = 1
|
||||
fetchGroupList()
|
||||
}
|
||||
|
||||
// 重置查询
|
||||
const resetQuery = () => {
|
||||
queryParams.key = ''
|
||||
queryParams.page = 1
|
||||
fetchGroupList()
|
||||
}
|
||||
|
||||
// 选择项变化
|
||||
const handleSelectionChange = (selection) => {
|
||||
selectedRows.value = selection
|
||||
}
|
||||
|
||||
// 分页
|
||||
const handleSizeChange = (size) => {
|
||||
queryParams.count = size
|
||||
fetchGroupList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (page) => {
|
||||
queryParams.page = page
|
||||
fetchGroupList()
|
||||
}
|
||||
|
||||
// 新增配置组
|
||||
const handleAdd = () => {
|
||||
dialogTitle.value = '新增配置组'
|
||||
Object.assign(groupForm, {
|
||||
id: undefined,
|
||||
name: '',
|
||||
note: ''
|
||||
})
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
// 编辑配置组
|
||||
const handleEdit = async (row) => {
|
||||
dialogTitle.value = '编辑配置组'
|
||||
try {
|
||||
const res = await getSettingGroupInfo({ setting_group_id: row.id })
|
||||
console.log('配置组详情数据:', res.data)
|
||||
if (res.data.code === 200) {
|
||||
Object.assign(groupForm, {
|
||||
id: res.data.data.id,
|
||||
name: res.data.data.name || '',
|
||||
note: res.data.data.note || ''
|
||||
})
|
||||
dialogVisible.value = true
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取配置组详情失败:', error)
|
||||
ElMessage.error('获取配置组详情失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 删除配置组
|
||||
const handleDelete = (row) => {
|
||||
ElMessageBox.confirm(`确认删除配置组 "${row.name}" 吗?`, '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
try {
|
||||
const res = await deleteSettingGroup({ setting_group_id: row.id })
|
||||
console.log('删除配置组响应:', res.data)
|
||||
if (res.data.code === 200) {
|
||||
ElMessage.success('删除成功')
|
||||
fetchGroupList()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error)
|
||||
ElMessage.error(error.response?.data?.message || '删除失败')
|
||||
}
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
// 批量删除
|
||||
const handleBatchDelete = () => {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning('请至少选择一条记录')
|
||||
return
|
||||
}
|
||||
ElMessageBox.confirm(`确认删除选中的 ${selectedRows.value.length} 条记录吗?`, '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
try {
|
||||
const deletePromises = selectedRows.value.map(row =>
|
||||
deleteSettingGroup({ setting_group_id: row.id })
|
||||
)
|
||||
await Promise.all(deletePromises)
|
||||
ElMessage.success('批量删除成功')
|
||||
fetchGroupList()
|
||||
} catch (error) {
|
||||
console.error('批量删除失败:', error)
|
||||
ElMessage.error('批量删除失败')
|
||||
}
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const submitForm = () => {
|
||||
groupFormRef.value?.validate(async (valid) => {
|
||||
if (valid) {
|
||||
try {
|
||||
const submitData = {
|
||||
name: groupForm.name,
|
||||
note: groupForm.note
|
||||
}
|
||||
if (groupForm.id) {
|
||||
submitData.id = groupForm.id
|
||||
}
|
||||
console.log('提交配置组数据:', submitData)
|
||||
const res = groupForm.id
|
||||
? await updateSettingGroup(submitData)
|
||||
: await createSettingGroup(submitData)
|
||||
if (res.data.code === 200) {
|
||||
ElMessage.success(groupForm.id ? '修改成功' : '创建成功')
|
||||
dialogVisible.value = false
|
||||
fetchGroupList()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error)
|
||||
ElMessage.error(error.response?.data?.message || '提交失败')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
fetchGroupList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.setting-group-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
border: 1px solid #e1e8ed;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.filter-section {
|
||||
padding: 0;
|
||||
border-bottom: 1px solid #e1e8ed;
|
||||
background: #fafbfc;
|
||||
}
|
||||
|
||||
.filter-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px 20px;
|
||||
gap: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.search-form :deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.action-bar {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.table-section {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-top: 20px;
|
||||
padding: 16px 20px;
|
||||
border-top: 1px solid #e1e8ed;
|
||||
background: #fafbfc;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* 表格样式优化 */
|
||||
:deep(.el-table) {
|
||||
border: none;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
:deep(.el-table__header) {
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
:deep(.el-table th) {
|
||||
background: #f8f9fa !important;
|
||||
border-bottom: 2px solid #e1e8ed;
|
||||
color: #2c3e50;
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
:deep(.el-table td) {
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
color: #34495e;
|
||||
}
|
||||
|
||||
:deep(.el-table tr:hover > td) {
|
||||
background-color: #f8f9fa !important;
|
||||
}
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -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>
|
||||
|
||||
@@ -3,13 +3,61 @@
|
||||
|
||||
自行访问下面的接口地址内容
|
||||
|
||||
1.添加了参数show_home 用于控制商品套餐是否在首页显示,http://localhost:5174/product/list在该页面的编辑弹窗和新增弹窗添加show_home参数,是否展示按钮,这是个boolean值,true为展示,false为不展示 ✅已完成
|
||||
创建商品套餐
|
||||
POST /api/v1/admin/good/plan/create
|
||||
接口ID:412068533
|
||||
接口地址:https://app.apifox.com/link/project/5145887/apis/api-412068533
|
||||
1.- 管理员 配置信息类型 type参数新增 file 类型,先点击上传图片的位置上传文件请求文件上传接口后将获取的响应数据中的id赋值到value,用户端返回信息会返回url ✅已完成
|
||||
|
||||
- 管理员 配置信息类型
|
||||
- 新增 file 类型,上传文件后,设置value为id
|
||||
- 新增 file_list 类型,允许上传多个文件,value 为文件列表id,使用 , 分割
|
||||
- 新增 string_list 类型,value 为字符串列表,使用 , 分割
|
||||
创建配置
|
||||
POST /api/v1/admin/server/setting/create
|
||||
接口ID:361964543
|
||||
接口地址:https://app.apifox.com/link/project/5145887/apis/api-361964543
|
||||
以下为响应数据格式:
|
||||
{
|
||||
"code": 200,
|
||||
"message": "Success",
|
||||
"data": {
|
||||
"id": 5,
|
||||
"name": "测试111",
|
||||
"value": "1459",
|
||||
"note": "测试",
|
||||
"type": "file",
|
||||
"settingGroup": null,
|
||||
"settingGroupID": 4,
|
||||
"open": true,
|
||||
"CreatedAt": "2026-03-10T11:06:05.531505043+08:00",
|
||||
"UpdatedAt": "2026-03-10T11:06:05.531505043+08:00",
|
||||
"omitempty": null
|
||||
}
|
||||
}
|
||||
|
||||
文件上传
|
||||
POST /api/v1/tools/file/upload
|
||||
接口ID:223275082
|
||||
接口地址:https://app.apifox.com/link/project/5145887/apis/api-223275082
|
||||
|
||||
以下是响应数据格式:
|
||||
{
|
||||
"code": 200,
|
||||
"message": "Success",
|
||||
"data": [
|
||||
{
|
||||
"id": 1459,
|
||||
"realName": "312",
|
||||
"saveName": "17731118324",
|
||||
"savePath": "static/files/2026-03-10/17731118324",
|
||||
"size": 323351,
|
||||
"type": "work_order",
|
||||
"content": "",
|
||||
"userId": 4,
|
||||
"openDow": true,
|
||||
"CreatedAt": "2026-03-10T11:03:52.910463212+08:00",
|
||||
"UpdatedAt": "2026-03-10T11:03:52.910463212+08:00",
|
||||
"omitempty": null
|
||||
}
|
||||
]
|
||||
}
|
||||
-----------------------------------------------------------------------------------------------需要解决
|
||||
|
||||
规则限制:
|
||||
|
||||
Reference in New Issue
Block a user