dman-web-admin/src/views/system/ConfigList.vue
2025-02-26 20:42:59 +08:00

373 lines
9.0 KiB
Vue

<template>
<page-container>
<div class="config-list">
<div class="table-header">
<h1>系统配置</h1>
<a-button type="primary" @click="showAddModal">
新增配置
</a-button>
</div>
<a-table
:columns="columns"
:data-source="tableData"
:pagination="pagination"
:loading="loading"
@change="handleTableChange"
row-key="id"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'value'">
<span>{{ formatValue(record) }}</span>
</template>
<template v-if="column.key === 'create_time'">
{{ formatDateTime(record.create_time) }}
</template>
<template v-if="column.key === 'update_time'">
{{ formatDateTime(record.update_time) }}
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="handleEdit(record)">编辑</a>
<a-popconfirm
title="确定要删除这个配置吗?"
@confirm="handleDelete(record)"
>
<a class="danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
<!-- 添加/编辑配置模态框 -->
<a-modal
v-model:visible="modalVisible"
:title="isEdit ? '编辑配置' : '新增配置'"
@ok="handleSubmit"
@cancel="handleCancel"
:confirmLoading="submitting"
>
<a-form
ref="formRef"
:model="formState"
:rules="rules"
layout="vertical"
>
<a-form-item
label="配置键名"
name="key"
:rules="[{ required: true, message: '请输入配置键名' }]"
>
<a-input
v-model:value="formState.key"
placeholder="请输入配置键名"
:disabled="isEdit"
:maxLength="50"
/>
</a-form-item>
<a-form-item
label="配置值"
name="value"
:rules="[{ required: true, message: '请输入配置值' }]"
>
<a-input
v-model:value="formState.value"
placeholder="请输入配置值"
/>
</a-form-item>
<a-form-item
label="备注"
name="description"
>
<a-textarea
v-model:value="formState.description"
placeholder="请输入备注信息"
:rows="2"
:maxLength="200"
/>
</a-form-item>
</a-form>
</a-modal>
</div>
</page-container>
</template>
<script>
import { defineComponent, ref, onMounted, watch } from 'vue'
import {
message,
Input,
Select,
Switch,
InputNumber
} from 'ant-design-vue'
import PageContainer from '@/components/PageContainer.vue'
import dayjs from 'dayjs'
import request from '@/utils/request'
export default defineComponent({
components: {
PageContainer,
AInput: Input,
ATextarea: Input.TextArea,
ASelect: Select,
ASelectOption: Select.Option,
ASwitch: Switch,
AInputNumber: InputNumber
},
setup() {
const loading = ref(false)
const tableData = ref([])
const pagination = ref({
current: 1,
pageSize: 10,
total: 0,
showSizeChanger: true,
showTotal: (total) => `${total} 条记录`
})
const columns = [
{
title: 'ID',
dataIndex: 'id',
key: 'id',
width: 60,
align: 'center'
},
{
title: '配置键名',
dataIndex: 'key',
key: 'key',
width: 150
},
{
title: '配置值',
key: 'value',
width: 200,
ellipsis: true
},
{
title: '备注',
dataIndex: 'description',
key: 'description',
width: 200,
ellipsis: true
},
{
title: '操作',
key: 'action',
width: 120,
fixed: 'right'
}
]
// 格式化日期时间
const formatDateTime = (value) => {
if (!value) return '-'
return dayjs(value).format('YYYY-MM-DD HH:mm:ss')
}
// 格式化配置值显示
const formatValue = (record) => {
if (!record.value) return '-'
if (record.type === 'boolean') {
return record.value === true || record.value === 'true' ? '是' : '否'
} else if (record.type === 'json') {
try {
const obj = JSON.parse(record.value)
return JSON.stringify(obj, null, 2)
} catch (e) {
return record.value
}
}
return record.value
}
// 获取列表数据
const fetchData = async () => {
try {
loading.value = true
const res = await request.get('/api/config')
if (res.code === 200) {
tableData.value = res.data
pagination.value.total = res.data.length
} else {
message.error(res.message || '获取数据失败')
}
} catch (error) {
console.error('获取系统配置列表失败:', error)
message.error('获取数据失败')
} finally {
loading.value = false
}
}
// 处理表格分页变化
const handleTableChange = (pag) => {
pagination.value.current = pag.current
pagination.value.pageSize = pag.pageSize
fetchData()
}
const modalVisible = ref(false)
const submitting = ref(false)
const isEdit = ref(false)
const currentId = ref(null)
const formRef = ref(null)
const formState = ref({
key: '',
value: '',
description: ''
})
const rules = {
key: [
{ required: true, message: '请输入配置键名' },
{ pattern: /^[a-zA-Z0-9_\.]+$/, message: '键名只能包含字母、数字、下划线和点' }
],
value: [
{ required: true, message: '请输入配置值' },
]
}
// 显示新建模态框
const showAddModal = () => {
isEdit.value = false
currentId.value = null
formState.value = {
key: '',
value: '',
description: ''
}
modalVisible.value = true
}
// 显示编辑模态框
const handleEdit = (record) => {
isEdit.value = true
currentId.value = record.id
formState.value = {
key: record.key,
value: record.value,
description: record.description || ''
}
modalVisible.value = true
}
// 提交表单
const handleSubmit = () => {
formRef.value.validate().then(async () => {
try {
submitting.value = true
const params = {
key: formState.value.key,
value: formState.value.value,
description: formState.value.description
}
let res
if (isEdit.value) {
res = await request.put(`/api/config/${formState.value.key}`, params)
} else {
res = await request.post('/api/config', params)
}
if (res.code === 200) {
message.success(isEdit.value ? '更新成功' : '创建成功')
modalVisible.value = false
fetchData()
} else {
message.error(res.message || (isEdit.value ? '更新失败' : '创建失败'))
}
} catch (error) {
console.error(isEdit.value ? '更新系统配置失败:' : '创建系统配置失败:', error)
message.error(isEdit.value ? '更新失败' : '创建失败')
} finally {
submitting.value = false
}
})
}
// 取消操作
const handleCancel = () => {
formRef.value?.resetFields()
modalVisible.value = false
}
// 删除配置
const handleDelete = async (record) => {
try {
loading.value = true
const res = await request.delete(`/api/config/${record.key}`)
if (res.code === 200) {
message.success('删除成功')
fetchData()
} else {
message.error(res.message || '删除失败')
}
} catch (error) {
console.error('删除系统配置失败:', error)
message.error('删除失败')
} finally {
loading.value = false
}
}
onMounted(() => {
fetchData()
})
return {
loading,
tableData,
columns,
pagination,
formatValue,
handleTableChange,
modalVisible,
submitting,
formState,
formRef,
rules,
showAddModal,
handleEdit,
handleSubmit,
handleCancel,
isEdit,
handleDelete
}
}
})
</script>
<style scoped>
.table-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.table-header h1 {
margin: 0;
}
.danger {
color: #ff4d4f;
}
:deep(.ant-table-content) {
overflow-x: auto;
}
</style>