Files
ApiServer-Web-admin_dashboa…/src/views/setting/GlobalSetting.vue
T
wlkjyy f7c3be1d30 refactor: extract image form to standalone page and implement tags view store
- Created ImageForm.vue as standalone page for add/edit image functionality
- Removed dialog-based image form from VmImages.vue
- Implemented tagsViewStore for global tab state management
- Added automatic tab closing on form cancel/back
- Fixed data persistence issue when switching between image edits
- Removed quick actions section from ImageForm
- Updated router configuration for new image form route
2025-11-28 14:15:29 +08:00

494 lines
12 KiB
Vue

<template>
<div class="global-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-input v-model="queryParams.name" placeholder="请输入设置名称" clearable />
</el-form-item>
<el-form-item label="权限">
<el-select v-model="queryParams.authority" placeholder="请选择权限" clearable style="width: 120px">
<el-option label="全部" value="" />
<el-option label="公有" value="0" />
<el-option label="私有" value="1" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery">
<el-icon><Search /></el-icon>查询
</el-button>
<el-button @click="resetQuery">
<el-icon><Delete /></el-icon>重置
</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 @click="handleRefresh">
<el-icon><Refresh /></el-icon>刷新
</el-button>
</div>
</div>
</div>
<!-- 设置列表 -->
<div class="table-section">
<el-table
v-loading="loading"
:data="settingsList"
style="width: 100%"
:header-cell-style="{ background: '#fafafa', color: '#333', fontWeight: 600 }"
>
<el-table-column prop="setting_id" label="ID" width="80" />
<el-table-column prop="name" label="Name值" min-width="200" show-overflow-tooltip />
<el-table-column prop="value" label="Value值" min-width="150" show-overflow-tooltip />
<el-table-column label="权限" width="100" align="center">
<template #default="{ row }">
<el-tag :type="getAuthorityType(row.authority)" size="small">
{{ getAuthorityText(row.authority) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="notes" label="备注" min-width="200" show-overflow-tooltip />
<el-table-column prop="created_at" label="创建时间" width="180" />
<el-table-column label="操作" width="150" fixed="right" align="center">
<template #default="{ row }">
<el-tooltip content="编辑" placement="top">
<el-button type="primary" link @click="handleEdit(row)">
<el-icon><Edit /></el-icon>编辑
</el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button type="danger" link @click="handleDelete(row)">
<el-icon><Delete /></el-icon>删除
</el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
<!-- 新增/编辑设置对话框 -->
<el-dialog
v-model="dialogVisible"
:title="dialogType === 'add' ? '新增设置' : '编辑设置'"
width="600px"
append-to-body
destroy-on-close
>
<el-form
ref="settingFormRef"
:model="settingForm"
:rules="settingRules"
label-width="120px"
>
<el-form-item label="设置名称" prop="name">
<el-input v-model="settingForm.name" placeholder="请输入设置名称" />
</el-form-item>
<el-form-item label="设置值" prop="value">
<el-input v-model="settingForm.value" placeholder="请输入设置值" />
</el-form-item>
<el-form-item label="默认值" prop="default_value">
<el-input v-model="settingForm.default_value" placeholder="请输入默认值" />
</el-form-item>
<el-form-item label="权限" prop="authority">
<el-radio-group v-model="settingForm.authority">
<el-radio :value="0">公有</el-radio>
<el-radio :value="1">私有</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="notes">
<el-input
v-model="settingForm.notes"
type="textarea"
:rows="3"
placeholder="请输入备注信息"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitForm" :loading="submitting">确定</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, nextTick } from 'vue'
import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
import {
Plus, Refresh, Search, Delete, Edit
} from '@element-plus/icons-vue'
import {
getSetting,
updateSetting,
addSetting,
deleteSetting,
getOneSetting,
getSettings
} from '@/utils/acs/setting'
// 查询参数
const queryParams = reactive({
name: '',
authority: '',
pageNum: 1,
pageSize: 10
})
// 数据加载状态
const loading = ref(false)
const submitting = ref(false)
// 设置列表数据
const settingsList = ref([])
// 对话框相关
const dialogVisible = ref(false)
const dialogType = ref('add') // 'add' | 'edit'
const settingFormRef = ref(null)
// 表单数据
const settingForm = reactive({
setting_id: null,
name: '',
value: '',
default_value: '',
authority: 0,
notes: ''
})
// 表单验证规则
const settingRules = {
name: [
{ required: true, message: '请输入设置名称', trigger: 'blur' }
],
value: [
{ required: true, message: '请输入设置值', trigger: 'blur' }
],
default_value: [
{ required: true, message: '请输入默认值', trigger: 'blur' }
],
authority: [
{ required: true, message: '请选择权限', trigger: 'change' }
]
}
// 获取设置列表
const getList = async () => {
loading.value = true
try {
// const params = {
// page: queryParams.pageNum,
// count: queryParams.pageSize,
// name: queryParams.name || '',
// authority: queryParams.authority !== '' ? queryParams.authority : undefined
// }
const response = await getSetting()
console.log('获取设置列表结果', response)
if (response && response.data) {
const apiData = response.data.data || []
// 处理API返回的数据
settingsList.value = apiData.map(item => ({
setting_id: item.setting_id,
name: item.name,
value: item.value,
default_value: item.default_value,
authority: item.authority,
notes: item.notes || '',
created_at: formatTime(item.created_at)
}))
// pagination.total = response.data.total || response.data.count || settingsList.value.length
} else {
settingsList.value = []
// pagination.total = 0
}
} catch (error) {
console.error('获取设置列表失败:', error)
ElMessage.error('获取设置列表失败')
settingsList.value = []
// pagination.total = 0
} finally {
loading.value = false
}
}
// 格式化时间
const formatTime = (timeStr) => {
if (!timeStr) return '未知时间'
try {
let dateStr = timeStr
if (dateStr.includes('T')) {
dateStr = dateStr.replace('T', ' ').substring(0, 19)
}
if (dateStr.includes('+') || dateStr.includes('Z')) {
dateStr = dateStr.substring(0, 19)
}
return dateStr
} catch (error) {
return timeStr || '未知时间'
}
}
// 获取权限类型
const getAuthorityType = (authority) => {
return authority === 0 ? 'success' : 'warning'
}
// 获取权限文本
const getAuthorityText = (authority) => {
return authority === 0 ? '公有' : '私有'
}
// 查询
const handleQuery = () => {
getList()
}
// 重置查询
const resetQuery = () => {
queryParams.name = ''
queryParams.authority = ''
getList()
}
// 刷新
const handleRefresh = () => {
ElNotification({
title: '刷新中',
message: '正在重新获取设置数据',
type: 'info',
duration: 2000
})
getList()
}
// 新增设置
const handleAdd = () => {
dialogType.value = 'add'
resetForm()
dialogVisible.value = true
}
// 编辑设置
const handleEdit = (row) => {
dialogType.value = 'edit'
settingForm.setting_id = row.setting_id
settingForm.name = row.name
settingForm.value = row.value
settingForm.default_value = row.default_value
settingForm.authority = row.authority
settingForm.notes = row.notes
dialogVisible.value = true
}
// 删除设置
const handleDelete = (row) => {
ElMessageBox.confirm(
`确定要删除设置 "${row.name}" 吗?`,
'删除确认',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(async () => {
try {
const response = await deleteSetting({ setting_id: row.setting_id })
console.log('删除设置结果', response)
if (response && response.data) {
ElMessage.success('删除成功')
getList()
} else {
ElMessage.error('删除失败')
}
} catch (error) {
console.error('删除设置失败:', error)
ElMessage.error('删除设置失败')
}
}).catch(() => {})
}
// 重置表单
const resetForm = () => {
settingForm.setting_id = null
settingForm.name = ''
settingForm.value = ''
settingForm.default_value = ''
settingForm.authority = 0
settingForm.notes = ''
if (settingFormRef.value) {
settingFormRef.value.clearValidate()
}
}
// 提交表单
const submitForm = async () => {
if (!settingFormRef.value) return
try {
await settingFormRef.value.validate()
submitting.value = true
const formData = {
name: settingForm.name,
value: settingForm.value,
default_value: settingForm.default_value,
authority: settingForm.authority,
notes: settingForm.notes
}
let response
if (dialogType.value === 'add') {
response = await addSetting(formData)
console.log('新增设置结果', response)
} else {
formData.setting_id = settingForm.setting_id
response = await updateSetting(formData)
console.log('更新设置结果', response)
}
if (response && response.data) {
ElMessage.success(dialogType.value === 'add' ? '新增成功' : '更新成功')
dialogVisible.value = false
getList()
} else {
ElMessage.error(dialogType.value === 'add' ? '新增失败' : '更新失败')
}
} catch (error) {
console.error('提交表单失败:', error)
ElMessage.error('操作失败')
} finally {
submitting.value = false
}
}
// 初始化
onMounted(() => {
getList()
})
</script>
<style scoped>
.global-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;
}
/* 表格样式优化 */
: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;
}
/* 对话框底部 */
.dialog-footer {
display: flex;
justify-content: flex-end;
}
/* 响应式设计 */
@media screen and (max-width: 768px) {
.filter-content {
flex-direction: column;
align-items: stretch;
}
.search-form {
width: 100%;
}
.action-bar {
width: 100%;
justify-content: flex-start;
}
}
</style>