mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-22 21:06:32 +00:00
上线系统配置功能
This commit is contained in:
@@ -24,19 +24,26 @@ export function createConfig(body) {
|
||||
});
|
||||
}
|
||||
|
||||
export function updateConfig(body) {
|
||||
export function batchConfig(body) {
|
||||
return request({
|
||||
url: "/api/v1/system/config/update",
|
||||
url: "/api/v1/system/config/batch",
|
||||
method: "put",
|
||||
data: body,
|
||||
});
|
||||
}
|
||||
|
||||
export function deleteConfig(params) {
|
||||
export function uploadFile(body) {
|
||||
return request({
|
||||
url: "/api/v1/system/config/delete",
|
||||
method: "delete",
|
||||
params: params,
|
||||
url: "/api/v1/system/config/upload",
|
||||
method: "post",
|
||||
data: body,
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
});
|
||||
}
|
||||
|
||||
export function getInitConfig() {
|
||||
return request({
|
||||
url: "/api/v1/system/config/init",
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
>
|
||||
<!-- Logo 区域 -->
|
||||
<div class="logo-container">
|
||||
<a-image src="/logo.png" :preview="false" :width="28" :height="28" />
|
||||
<h1 class="logo-title" v-show="!menuState.collapsed">fastapi-vue-admin</h1>
|
||||
<a-image :src="initConfigState.web_favicon" :preview="false" :width="28" :height="28" />
|
||||
<h1 class="logo-title" v-show="!menuState.collapsed">{{ initConfigState.web_title }}</h1>
|
||||
</div>
|
||||
|
||||
<a-menu
|
||||
@@ -147,6 +147,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { reactive, computed, watch, onMounted, inject, type Ref } from "vue";
|
||||
import type { MenuProps, ItemType } from "ant-design-vue";
|
||||
import { message } from 'ant-design-vue';
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import storage from 'store';
|
||||
import store from '@/store';
|
||||
@@ -166,6 +167,7 @@ import {
|
||||
} from '@ant-design/icons-vue';
|
||||
import { logout } from '@/api/system/auth';
|
||||
import { getNoticeList } from '@/api/system/notice'
|
||||
import { getInitConfig } from "@/api/system/config"
|
||||
|
||||
// 通知公告获取
|
||||
const dataSource = reactive({
|
||||
@@ -327,13 +329,38 @@ const noticeState = reactive({
|
||||
});
|
||||
|
||||
|
||||
const initConfigState = reactive({
|
||||
web_title: '',
|
||||
web_favicon: '',
|
||||
});
|
||||
|
||||
const initConfig = () => {
|
||||
getInitConfig()
|
||||
.then(response => {
|
||||
const { status_code, data } = response.data;
|
||||
if (status_code === 200) {
|
||||
const configData = JSON.parse(data);
|
||||
configData.forEach(item => {
|
||||
if (item.fied_key === 'web_title') {
|
||||
initConfigState.web_title = item.fied_value;
|
||||
} else if (item.fied_key === 'web_favicon') {
|
||||
initConfigState.web_favicon = item.fied_value;
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
message.error('获取系统配置失败');
|
||||
console.error(error); // 打印错误信息以便调试
|
||||
});
|
||||
};
|
||||
|
||||
// 在页面加载时获取通知列表
|
||||
onMounted(() => {
|
||||
initMenu();
|
||||
handleNoticeList();
|
||||
initConfig();
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
+3
-1
@@ -74,6 +74,7 @@
|
||||
:loading="loading"
|
||||
:dataSource="cacheNames"
|
||||
:pagination="false"
|
||||
:scroll="{ y: 600 }"
|
||||
rowKey="cache_name"
|
||||
>
|
||||
<a-table-column key="cache_name" title="缓存名称" align="center" :ellipsis="true">
|
||||
@@ -109,6 +110,7 @@
|
||||
:loading="subLoading"
|
||||
:dataSource="cacheKeys.map(key => ({ cacheKey: key }))"
|
||||
:pagination="false"
|
||||
:scroll="{ y: 600 }"
|
||||
rowKey="cacheKey"
|
||||
>
|
||||
<a-table-column key="cacheKey" title="缓存键名" align="center" :ellipsis="true">
|
||||
@@ -147,7 +149,7 @@
|
||||
<a-form-item label="缓存内容:" name="cache_value">
|
||||
<a-textarea
|
||||
v-model:value="cacheForm.cache_value"
|
||||
:rows="8"
|
||||
:rows="19"
|
||||
readonly
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<a-layout>
|
||||
<!-- 页面主体 -->
|
||||
<div class="container">
|
||||
<div class="container" :style="{ backgroundImage: `url(${initConfigState.login_background})` }">
|
||||
<a-layout-content :style="contentStyle">
|
||||
<div class="header">
|
||||
<div class="logo">
|
||||
<a-image src="/logo.png" :preview="false" />
|
||||
<a-image :src="initConfigState.login_logo" :preview="false" />
|
||||
</div>
|
||||
<div class="title">FastAPI Vue Admin</div>
|
||||
<div class="title">{{ initConfigState.login_title }}</div>
|
||||
</div>
|
||||
<div class="desc">FastAPI Vue Admin 是完全开源的权限管理系统</div>
|
||||
<div class="desc">{{ initConfigState.login_description }}</div>
|
||||
|
||||
<div class="login-main" style="width: 330px; margin: 0 auto;">
|
||||
<a-tabs centered>
|
||||
@@ -62,13 +62,28 @@
|
||||
|
||||
<!-- 页面底部 -->
|
||||
<a-layout-footer :style="footerStyle">
|
||||
<div class="footer-copyright">
|
||||
<a-button type="link" href="https://gitee.com/tao__tao/fastapi_vue_admin.git">
|
||||
<icon-font type="icon-copyright" :style="{ fontSize: '16px' }" />
|
||||
Copyright © 2024 insistence.tech All Rights Reserved. 皖ICP备2023021369号-1
|
||||
</a-button>
|
||||
<div class="footer-content">
|
||||
<div class="footer-links">
|
||||
<a-button type="link" :href="initConfigState.code_url">
|
||||
<icon-font type="icon-copyright" :style="{ fontSize: '16px' }" />
|
||||
{{ initConfigState.copyright }} |
|
||||
</a-button>
|
||||
<a-button type="link" :href="initConfigState.help_url">
|
||||
{{ initConfigState.help_name }} |
|
||||
</a-button>
|
||||
<a-button type="link" :href="initConfigState.privacy_url">
|
||||
{{ initConfigState.privacy_name }} |
|
||||
</a-button>
|
||||
<a-button type="link" :href="initConfigState.clause_url">
|
||||
{{ initConfigState.clause_name }}
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="footer-record">
|
||||
{{ initConfigState.keep_record }}
|
||||
</div>
|
||||
</div>
|
||||
</a-layout-footer>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 弹窗区域 -->
|
||||
@@ -146,6 +161,7 @@ import { save_token } from "@/utils/util"
|
||||
import { message } from 'ant-design-vue';
|
||||
import { login, getCaptcha } from "@/api/system/auth"
|
||||
import { registerUser, forgetPassword } from "@/api/system/user"
|
||||
import { getInitConfig } from "@/api/system/config"
|
||||
import type { LoginForm, CaptchaState, ForgetPasswordForm, RegisterForm } from './types'
|
||||
|
||||
const router = useRouter();
|
||||
@@ -271,7 +287,70 @@ const requestCaptcha = () => {
|
||||
.catch(() => captchaState.enable = false);
|
||||
};
|
||||
|
||||
onMounted(requestCaptcha);
|
||||
const initConfigState = reactive({
|
||||
login_title: '',
|
||||
login_description: '/logo.png',
|
||||
login_logo: '',
|
||||
login_background: '/background.png',
|
||||
copyright: '',
|
||||
copyright_name: '',
|
||||
keep_record: '',
|
||||
keep_record_name: '',
|
||||
help_url: '',
|
||||
help_name: '',
|
||||
privacy_url: '',
|
||||
privacy_name: '',
|
||||
clause_url: '',
|
||||
clause_name: '',
|
||||
code_url: '',
|
||||
});
|
||||
|
||||
const initConfig = () => {
|
||||
getInitConfig()
|
||||
.then(response => {
|
||||
const { status_code, data } = response.data;
|
||||
if (status_code === 200) {
|
||||
const configData = JSON.parse(data);
|
||||
configData.forEach(item => {
|
||||
if (item.fied_key === 'login_title') {
|
||||
initConfigState.login_title = item.fied_value;
|
||||
} else if (item.fied_key === 'login_description') {
|
||||
initConfigState.login_description = item.fied_value;
|
||||
} else if (item.fied_key === 'login_logo') {
|
||||
initConfigState.login_logo = item.fied_value;
|
||||
} else if (item.fied_key === 'login_background') {
|
||||
initConfigState.login_background = item.fied_value;
|
||||
} else if (item.fied_key === 'copyright') {
|
||||
initConfigState.copyright = item.fied_value;
|
||||
initConfigState.copyright_name = item.name;
|
||||
} else if (item.fied_key === 'keep_record') {
|
||||
initConfigState.keep_record = item.fied_value;
|
||||
initConfigState.keep_record_name = item.name;
|
||||
} else if (item.fied_key === 'help_url') {
|
||||
initConfigState.help_url = item.fied_value;
|
||||
initConfigState.help_name = item.name;
|
||||
} else if (item.fied_key === 'privacy_url') {
|
||||
initConfigState.privacy_url = item.fied_value;
|
||||
initConfigState.privacy_name = item.name;
|
||||
} else if (item.fied_key === 'clause_url') {
|
||||
initConfigState.clause_url = item.fied_value;
|
||||
initConfigState.clause_name = item.name;
|
||||
} else if (item.fied_key === 'code_url') {
|
||||
initConfigState.code_url = item.fied_value;
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
message.error('获取系统配置失败');
|
||||
console.error(error); // 打印错误信息以便调试
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
requestCaptcha();
|
||||
initConfig();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -282,7 +361,6 @@ onMounted(requestCaptcha);
|
||||
}
|
||||
|
||||
.container {
|
||||
background-image: url("/background.png");
|
||||
background-size: 100% 100%;
|
||||
|
||||
.desc {
|
||||
|
||||
@@ -1,376 +1,179 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 页面头部 -->
|
||||
<page-header />
|
||||
<div>
|
||||
<!-- 页面头部 -->
|
||||
<page-header />
|
||||
|
||||
<!-- 搜索表单 -->
|
||||
<div class="tree-search-wrapper">
|
||||
<a-card :bordered="false">
|
||||
<a-form :model="queryState" @finish="onFinish">
|
||||
<a-row>
|
||||
<a-col flex="0 1 450px">
|
||||
<a-form-item name="name" label="名称" style="max-width: 300px;">
|
||||
<a-input v-model:value="queryState.name" placeholder="请输入名称" allowClear />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col>
|
||||
<a-space>
|
||||
<a-button type="primary" html-type="submit" :loading="tableLoading">查询</a-button>
|
||||
<a-button @click="resetFields">重置</a-button>
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-card>
|
||||
<!-- 配置项编辑区域 -->
|
||||
<div class="config-edit-wrapper">
|
||||
<a-card title="系统配置" :bordered="false">
|
||||
<!-- 动态生成配置项 -->
|
||||
<template v-for="group in updateState" :key="group.id">
|
||||
<a-card :title="group.name" :bordered="false" style="margin-bottom: 24px;">
|
||||
<a-row :gutter="16">
|
||||
<template v-for="config in group.children" :key="config.id">
|
||||
<a-col :span="12">
|
||||
<!-- 图片上传类型 -->
|
||||
<a-form-item v-if="config.fied_key === 'web_favicon' || config.fied_key === 'login_logo' || config.fied_key === 'login_background'" :label="config.name">
|
||||
<a-upload
|
||||
v-model:file-list="config.fileList"
|
||||
list-type="picture-card"
|
||||
:before-upload="beforeUpload"
|
||||
:custom-request="(options) => handleUpload(options, config)"
|
||||
>
|
||||
<div v-if="!config.fileList || config.fileList.length === 0">
|
||||
<plus-outlined />
|
||||
<div style="margin-top: 8px">上传图片</div>
|
||||
</div>
|
||||
</a-upload>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 输入框类型 -->
|
||||
<a-form-item v-else :label="config.name">
|
||||
<a-input v-model:value="config.fied_value" :placeholder="`请输入${config.name}`" allowClear />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</template>
|
||||
</a-row>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<!-- 保存按钮 -->
|
||||
<div style="text-align: right; margin-top: 24px;">
|
||||
<a-button type="primary" @click="handleSave">保存</a-button>
|
||||
</div>
|
||||
|
||||
<!-- 表格区域 -->
|
||||
<div class="table-wrapper">
|
||||
<a-card title="配置列表" :bordered="false" :headStyle="{ borderBottom: 'none', padding: '20px 24px' }"
|
||||
:bodyStyle="{ padding: '0 24px', minHeight: 'calc(100vh - 400px)' }">
|
||||
<template #extra>
|
||||
<a-space>
|
||||
<a-button type="primary" :icon="h(PlusOutlined)" @click="modalHandle('create')">新建</a-button>
|
||||
<a-button type="primary" @click="openSystemConfigModal">系统配置</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
|
||||
<!-- 树形表格 -->
|
||||
<a-table :rowKey="record => record.id"
|
||||
:columns="columns"
|
||||
:data-source="dataSource"
|
||||
:loading="tableLoading"
|
||||
:scroll="{ x: 500, y: 'calc(100vh - 500px)' }"
|
||||
:row-selection="rowSelection"
|
||||
:pagination="false"
|
||||
:style="{ minHeight: '500px' }">
|
||||
<template #bodyCell="{ column, record }">
|
||||
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<a-space size="middle">
|
||||
<a @click="modalHandle('view', record)">查看</a>
|
||||
<a @click="modalHandle('update', record)">修改</a>
|
||||
<a-popconfirm title="确定要删除吗?" ok-text="确定" cancel-text="取消"
|
||||
@confirm="deleteRow(record)">
|
||||
<a style="color: red;">删除</a>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
</div>
|
||||
|
||||
<!-- 系统配置弹窗 -->
|
||||
<a-modal v-model:open="systemConfigModalVisible" title="系统配置" :width="800" :destroyOnClose="true"
|
||||
:confirmLoading="systemConfigModalLoading" @ok="handleSystemConfigSubmit">
|
||||
<!-- 基础配置部分 -->
|
||||
<a-card title="基础配置" :bordered="false" style="margin-bottom: 16px;">
|
||||
<a-form ref="systemConfigForm" :model="systemConfigState" :label-col="{ span: 5 }"
|
||||
:wrapper-col="{ span: 15 }">
|
||||
<!-- 基础配置的顶级配置项 -->
|
||||
<a-form-item v-for="config in systemConfigState.filter(item => item.fied_key === 'base')"
|
||||
:key="config.id" :name="config.id" :label="config.name"
|
||||
:rules="[{ required: true, message: `请输入${config.name}` }]">
|
||||
<a-input v-model:value="config.fied_value" :placeholder="`请输入${config.name}`" allowClear />
|
||||
</a-form-item>
|
||||
|
||||
<!-- 基础配置的子配置项 -->
|
||||
<a-form-item v-for="config in systemConfigState.filter(item => item.parent_id === 1)"
|
||||
:key="config.id" :name="config.id" :label="config.name"
|
||||
:rules="[{ required: true, message: `请输入${config.name}` }]">
|
||||
<a-input v-model:value="config.fied_value" :placeholder="`请输入${config.name}`" allowClear />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-card>
|
||||
|
||||
<!-- 登录页配置部分 -->
|
||||
<a-card title="登录页配置" :bordered="false">
|
||||
<a-form ref="systemConfigForm" :model="systemConfigState" :label-col="{ span: 5 }"
|
||||
:wrapper-col="{ span: 15 }">
|
||||
<!-- 登录页配置的顶级配置项 -->
|
||||
<a-form-item v-for="config in systemConfigState.filter(item => item.fied_key === 'login')"
|
||||
:key="config.id" :name="config.id" :label="config.name"
|
||||
:rules="[{ required: true, message: `请输入${config.name}` }]">
|
||||
<a-input v-model:value="config.fied_value" :placeholder="`请输入${config.name}`" allowClear />
|
||||
</a-form-item>
|
||||
|
||||
<!-- 登录页配置的子配置项 -->
|
||||
<a-form-item v-for="config in systemConfigState.filter(item => item.parent_id === 4)"
|
||||
:key="config.id" :name="config.id" :label="config.name"
|
||||
:rules="[{ required: true, message: `请输入${config.name}` }]">
|
||||
<a-input v-model:value="config.fied_value" :placeholder="`请输入${config.name}`" allowClear />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-card>
|
||||
</a-modal>
|
||||
</a-card>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed, onMounted, h, unref } from 'vue';
|
||||
import { message, Modal, Table } from 'ant-design-vue';
|
||||
import type { MenuProps, TableColumnsType } from 'ant-design-vue';
|
||||
import { PlusOutlined, DownOutlined, CheckOutlined, StopOutlined } from '@ant-design/icons-vue';
|
||||
import { listToTree, cloneDeep, isEmpty } from '@/utils/util';
|
||||
import { getConfigList, createConfig, updateConfig, deleteConfig } from '@/api/system/config';
|
||||
import PageHeader from '@/components/PageHeader.vue'
|
||||
import type { searchDataType, tableDataType } from './types';
|
||||
import { reactive, onMounted } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||
import { getConfigList, batchConfig, uploadFile } from '@/api/system/config';
|
||||
import PageHeader from '@/components/PageHeader.vue';
|
||||
import type { tableDataType } from './types'
|
||||
|
||||
// 响应式数据
|
||||
const createForm = ref();
|
||||
const updateForm = ref();
|
||||
const tableLoading = ref(false);
|
||||
const openModal = ref(false);
|
||||
const modalTitle = ref('');
|
||||
const modalSubmitLoading = ref(false);
|
||||
const detailStateLoading = ref(false);
|
||||
const dataSource = ref<tableDataType[]>([]);
|
||||
const selectedRowKeys = ref<tableDataType['id'][]>([]);
|
||||
interface ConfigGroup extends tableDataType {
|
||||
children: tableDataType[];
|
||||
fileList?: any[];
|
||||
}
|
||||
|
||||
const queryState = reactive<searchDataType>({
|
||||
name: null,
|
||||
});
|
||||
const createState = reactive<tableDataType>({
|
||||
name: '',
|
||||
order: 1,
|
||||
parent_id: undefined,
|
||||
fied_key: null,
|
||||
fied_value: '',
|
||||
const updateState = reactive<ConfigGroup[]>([]);
|
||||
|
||||
});
|
||||
const updateState = reactive<tableDataType>({
|
||||
id: undefined,
|
||||
name: '',
|
||||
order: 1,
|
||||
parent_id: undefined,
|
||||
fied_key: null,
|
||||
fied_value: '',
|
||||
});
|
||||
const detailState = ref<tableDataType>({});
|
||||
// 加载配置数据
|
||||
const loadConfigData = async () => {
|
||||
try {
|
||||
const response = await getConfigList({});
|
||||
const items = response.data.data.items;
|
||||
|
||||
const columns = reactive<TableColumnsType>([
|
||||
{
|
||||
title: '配置名称',
|
||||
dataIndex: 'name',
|
||||
ellipsis: true,
|
||||
key: 'name',
|
||||
// width: 160
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'order',
|
||||
key: 'order',
|
||||
// align: 'center',
|
||||
ellipsis: true,
|
||||
// width: 100
|
||||
},
|
||||
{
|
||||
title: '父级',
|
||||
dataIndex: 'parent_id',
|
||||
key: 'parent_id',
|
||||
ellipsis: true,
|
||||
// align: 'center',
|
||||
// width: 100
|
||||
},
|
||||
{
|
||||
title: '键',
|
||||
dataIndex: 'fied_key',
|
||||
key: 'fied_key',
|
||||
ellipsis: true,
|
||||
// align: 'center'
|
||||
},
|
||||
{
|
||||
title: '值',
|
||||
dataIndex: 'fied_value',
|
||||
key: 'fied_value',
|
||||
ellipsis: true,
|
||||
// align: 'center'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
key: 'action',
|
||||
align: 'center',
|
||||
width: 150
|
||||
}
|
||||
]);
|
||||
// 将配置项按父级分组
|
||||
const groups = items
|
||||
.filter(item => item.parent_id === null) // 获取顶级配置项
|
||||
.map(group => ({
|
||||
...group,
|
||||
children: items.filter(item => item.parent_id === group.id) // 获取子配置项
|
||||
}));
|
||||
|
||||
const rowSelection = computed(() => {
|
||||
return {
|
||||
selectedRowKeys: unref(selectedRowKeys),
|
||||
onChange: (selectingRowKeys: tableDataType['id'][]) => {
|
||||
selectedRowKeys.value = selectingRowKeys;
|
||||
},
|
||||
hideDefaultSelections: true,
|
||||
selections: [
|
||||
Table.SELECTION_ALL,
|
||||
Table.SELECTION_INVERT,
|
||||
Table.SELECTION_NONE
|
||||
]
|
||||
}
|
||||
});
|
||||
// 初始化图片上传列表
|
||||
groups.forEach(group => {
|
||||
group.children.forEach(config => {
|
||||
if (config.fied_key === 'web_favicon' || config.fied_key === 'login_logo' || config.fied_key === 'login_background') {
|
||||
config.fileList = config.fied_value ? [{ url: config.fied_value }] : [];
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 避免直接修改 reactive 对象,使用重新赋值的方式
|
||||
updateState.length = 0; // 清空数组
|
||||
updateState.push(...groups); // 添加新数据
|
||||
} catch (error) {
|
||||
console.error('加载配置数据失败:', error);
|
||||
message.error('加载配置数据失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 图片上传前的校验
|
||||
const beforeUpload = (file: File) => {
|
||||
const isImage = file.type.startsWith('image/');
|
||||
if (!isImage) {
|
||||
message.error('只能上传图片文件!');
|
||||
}
|
||||
return isImage;
|
||||
};
|
||||
|
||||
// 自定义上传逻辑
|
||||
const handleUpload = async (options: any, config: any) => {
|
||||
const { file, onSuccess, onError } = options;
|
||||
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
const response = await uploadFile(formData);
|
||||
const fileUrl = response.data.data.file_url; // 使用 file_url 更新配置项的值
|
||||
|
||||
// 更新配置项的值
|
||||
config.fied_value = fileUrl;
|
||||
config.fileList = [{ url: fileUrl }]; // 更新文件列表显示
|
||||
|
||||
onSuccess(response, file);
|
||||
message.success('上传成功');
|
||||
} catch (error) {
|
||||
onError(error);
|
||||
console.error('上传失败:', error);
|
||||
message.error('上传失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 保存配置
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
// 提取所有配置项(包括父级和子级)
|
||||
const configs = updateState.flatMap(group => [
|
||||
{
|
||||
id: group.id,
|
||||
name: group.name,
|
||||
order: group.order,
|
||||
fied_key: group.fied_key,
|
||||
fied_value: group.fied_value,
|
||||
parent_id: group.parent_id,
|
||||
},
|
||||
...group.children.map(config => ({
|
||||
id: config.id,
|
||||
name: config.name,
|
||||
order: config.order,
|
||||
fied_key: config.fied_key,
|
||||
fied_value: config.fied_value,
|
||||
parent_id: config.parent_id,
|
||||
})),
|
||||
]);
|
||||
|
||||
// 调用批量保存接口,直接发送数组
|
||||
await batchConfig(configs); // 修改为直接发送数组
|
||||
message.success('配置保存成功');
|
||||
} catch (error) {
|
||||
console.error('保存配置失败:', error);
|
||||
message.error('配置保存失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 生命周期钩子
|
||||
onMounted(() => loadingData());
|
||||
|
||||
// 查询
|
||||
const onFinish = () => {
|
||||
loadingData();
|
||||
};
|
||||
|
||||
// 加载表格数据
|
||||
const loadingData = () => {
|
||||
tableLoading.value = true;
|
||||
|
||||
let params = {};
|
||||
if (queryState.name) {
|
||||
params['name'] = queryState.name;
|
||||
}
|
||||
getConfigList(params).then(response => {
|
||||
const result = response.data;
|
||||
dataSource.value = listToTree(result.data.items);
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
}).finally(() => {
|
||||
tableLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 重置查询
|
||||
const resetFields = () => {
|
||||
Object.keys(queryState).forEach((key: string) => {
|
||||
delete queryState[key];
|
||||
});
|
||||
loadingData();
|
||||
};
|
||||
|
||||
// 删除
|
||||
const deleteRow = (row: tableDataType) => {
|
||||
deleteConfig({ id: row.id }).then(response => {
|
||||
const result = response.data;
|
||||
message.success(result.msg);
|
||||
loadingData();
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 弹窗关键字处理
|
||||
const modalHandle = (modalType: string, record?: tableDataType) => {
|
||||
modalTitle.value = modalType;
|
||||
openModal.value = true;
|
||||
|
||||
if (modalType === 'view' && record !== undefined) {
|
||||
detailStateLoading.value = true;
|
||||
detailState.value = record
|
||||
detailStateLoading.value = false;
|
||||
|
||||
} else if (modalType === 'update' && record !== undefined) {
|
||||
Object.keys(updateState).forEach(key => {
|
||||
updateState[key] = record[key];
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// 弹窗提交(详情/新建/修改)
|
||||
const handleModalSumbit = () => {
|
||||
modalSubmitLoading.value = true;
|
||||
if (modalTitle.value === 'view') {
|
||||
modalSubmitLoading.value = false;
|
||||
openModal.value = false;
|
||||
|
||||
} else if (modalTitle.value === 'create') {
|
||||
createForm.value.validate().then(() => {
|
||||
const createBody = cloneDeep(createState);
|
||||
Object.keys(createBody).forEach(key => {
|
||||
if (isEmpty(createBody[key])) {
|
||||
delete createBody[key];
|
||||
}
|
||||
});
|
||||
|
||||
createConfig(createBody).then(response => {
|
||||
const result = response.data;
|
||||
modalSubmitLoading.value = false;
|
||||
openModal.value = false;
|
||||
Object.keys(createState).forEach(key => delete createState[key]);
|
||||
createState.order = 1;
|
||||
message.success(result.msg);
|
||||
loadingData();
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
}).catch(error => {
|
||||
modalSubmitLoading.value = false;
|
||||
console.error(error)
|
||||
})
|
||||
|
||||
} else if (modalTitle.value === 'update') {
|
||||
updateForm.value.validate().then(() => {
|
||||
updateConfig(updateState).then(response => {
|
||||
modalSubmitLoading.value = false;
|
||||
openModal.value = false;
|
||||
const result = response.data;
|
||||
message.success(result.msg);
|
||||
loadingData();
|
||||
|
||||
}).catch(error => {
|
||||
modalSubmitLoading.value = false;
|
||||
console.error(error)
|
||||
});
|
||||
|
||||
}).catch(error => {
|
||||
modalSubmitLoading.value = false;
|
||||
console.error(error)
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// 系统配置弹窗状态
|
||||
const systemConfigModalVisible = ref(false);
|
||||
const systemConfigModalLoading = ref(false);
|
||||
const systemConfigState = ref<tableDataType[]>([]);
|
||||
|
||||
// 打开系统配置弹窗
|
||||
const openSystemConfigModal = async () => {
|
||||
systemConfigModalVisible.value = true;
|
||||
systemConfigModalLoading.value = true;
|
||||
try {
|
||||
const response = await getConfigList({});
|
||||
systemConfigState.value = listToTree(response.data.items);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
systemConfigModalLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 提交系统配置
|
||||
const handleSystemConfigSubmit = async () => {
|
||||
systemConfigModalLoading.value = true;
|
||||
try {
|
||||
const updatePromises = systemConfigState.value.map(config =>
|
||||
updateConfig(config)
|
||||
);
|
||||
await Promise.all(updatePromises);
|
||||
message.success('系统配置更新成功');
|
||||
systemConfigModalVisible.value = false;
|
||||
loadingData(); // 重新加载数据
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
systemConfigModalLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
loadConfigData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tree-search-wrapper {
|
||||
margin-block-end: 16px;
|
||||
.config-edit-wrapper {
|
||||
margin-block-end: 16px;
|
||||
}
|
||||
|
||||
.ant-card {
|
||||
margin-bottom: 24px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,15 +1,10 @@
|
||||
export interface searchDataType {
|
||||
name?: string
|
||||
}
|
||||
|
||||
export interface tableDataType {
|
||||
id?: number;
|
||||
index?: number;
|
||||
name?: string;
|
||||
order?: number;
|
||||
fied_key?: string;
|
||||
fied_value?: string;
|
||||
parent_id?: number;
|
||||
parent_name?: string;
|
||||
fileList?: any[];
|
||||
children?: tableDataType[];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user