feat(system): 添加系统配置功能- 新增系统配置页面和相关功能

- 实现配置列表展示、筛选、添加、编辑和删除功能
- 添加配置详情页面- 优化配置缓存刷新逻辑
This commit is contained in:
Ky10
2024-11-16 20:16:36 +08:00
parent e5525dfd62
commit d2ead8fd56
6 changed files with 498 additions and 30 deletions

View File

@@ -1,4 +1,3 @@
// import request from "@/utils/request";
import request from "@/utils/request";
const CONFIG_BASE_URL = "/api/v1/config";
@@ -62,12 +61,8 @@ const ConfigAPI = {
refreshCache() {
return request({
url: `${CONFIG_BASE_URL}`,
method: "POST",
header: {
"Content-Type": "application/json",
"X-HTTP-Method-Override": "PATCH",
},
url: `${CONFIG_BASE_URL}/refresh`,
method: "PUT",
});
},
};

View File

@@ -54,6 +54,18 @@
"style": {
"navigationBarTitleText": "日志管理"
}
},
{
"path": "pages/work/system/config/config",
"style": {
"navigationBarTitleText": "系统配置"
}
},
{
"path": "pages/work/system/config/item",
"style": {
"navigationBarTitleText": "配置详情"
}
}
],
"globalStyle": {

View File

@@ -51,6 +51,7 @@ const gridList = reactive([
{
icon: "/static/icons/config.png",
title: "系统配置",
url: "/pages/work/system/config/config",
},
{
icon: "/static/icons/notice.png",

View File

@@ -1,23 +0,0 @@
<template>
<view class="work" />
</template>
<script lang="ts">
export default {
data() {
return {};
},
};
</script>
<style lang="scss" scoped>
/* stylelint-disable selector-type-no-unknown */
page {
background: #f8f8f8;
}
/* stylelint-enable selector-type-no-unknown */
.work {
padding: 40rpx 0;
}
</style>

View File

@@ -0,0 +1,260 @@
<template>
<view class="work">
<!-- 筛选 -->
<wd-drop-menu
close-on-click-modal
class="mb-20rpx"
style=" margin-right: 20rpx;margin-left: 20rpx"
>
<wd-drop-menu-item
ref="dropMenu"
title="筛选"
icon="filter"
icon-size="18px"
@opened="handleOpened"
>
<view>
<wd-input
v-model="queryParams.keywords"
label="关键字"
type="text"
placeholder="请输入关键字"
/>
<view class="flex flex-row items-center mb-20rpx">
<wd-button class="mt-20rpx mb-20rpx" size="medium" @click="search()">查询</wd-button>
<wd-button size="medium" type="info" @click="reset">重置</wd-button>
</view>
</view>
</wd-drop-menu-item>
</wd-drop-menu>
<!-- 列表 -->
<scroll-view scroll-y class="list-container">
<view
v-for="(item, index) in pageData"
:key="index"
class="card"
style="margin: 20rpx; border-bottom: 1px solid #ccc"
@click="itemClicked(item)"
>
<view class="card-content" style=" padding: 20rpx;margin: 20rpx">
<view class="item">
<view class="title">配置名称{{ item.configName }}</view>
<view class="content">
<!-- <view class="row">-->
<!-- <view class="label">配置名称</view>-->
<!-- <view class="value">{{ item.configName }}</view>-->
<!-- </view>-->
<view class="row">
<view class="label">配置键</view>
<view class="value">{{ item.configKey }}</view>
</view>
<view class="row">
<view class="label">配置值</view>
<view class="value">{{ item.configValue }}</view>
</view>
<view class="row">
<view class="label">备注</view>
<view class="value">{{ item.remark }}</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
<!-- 底部按钮 -->
<view
class="footer-buttons"
style="
position: fixed;
right: 0;
bottom: 0;
left: 0;
display: flex;
justify-content: space-around;
padding: 20rpx;
background-color: #fff;
"
>
<wd-button size="medium" type="primary" @click="add">添加</wd-button>
<wd-button size="medium" type="success" @click="refreshCache">刷新缓存</wd-button>
</view>
</view>
</template>
<script lang="ts" setup>
import ConfigAPI, { ConfigPageVO, ConfigForm, ConfigPageQuery } from "@/api/system/config";
import { DropMenuItemExpose } from "wot-design-uni/components/wd-drop-menu-item/types";
import { LoadMoreState } from "wot-design-uni/components/wd-loadmore/types";
const loading = ref(false);
const selectIds = ref<number[]>([]);
const total = ref(0);
const loadMoreState = ref<LoadMoreState>("loading");
const queryParams = reactive<ConfigPageQuery>({
pageNum: 1,
pageSize: 10,
keywords: "",
});
// 系统配置表格数据
const pageData = ref<ConfigPageVO[]>([]);
/**
* 搜索栏
*/
const dropMenu = ref<DropMenuItemExpose>();
function search() {
pageData.value = [];
dropMenu.value?.close();
handleQuery();
}
/**
* 重置搜索条件
*/
function reset() {
queryParams.pageNum = 1;
queryParams.keywords = "";
// queryParams.createTime = ["", ""];
// timeStampArray.value = [];
pageData.value = [];
dropMenu.value?.close();
handleQuery();
}
/**
* 处理下拉菜单打开事件
*/
function handleOpened() {
// 在这里可以添加处理下拉菜单打开时的逻辑
console.log("下拉菜单已打开");
}
function handleQuery() {
loading.value = true;
ConfigAPI.getPage(queryParams)
.then((data) => {
pageData.value = data.list;
total.value = data.total;
})
.finally(() => {
loading.value = false;
});
}
function add() {
// 跳转到指定页面
uni.navigateTo({
url: "/pages/work/system/config/item",
});
}
function refreshCache() {
ConfigAPI.refreshCache().then(() => {
uni.showToast({
title: "刷新缓存成功",
icon: "success",
duration: 1000, // 显示时间,单位为毫秒,设置为 0 则不会自动消失
});
});
}
function itemClicked(item: ConfigPageVO) {
console.log(item);
// 直接传递整个 item 对象
uni.navigateTo({
url: "/pages/work/system/config/item?item=" + encodeURIComponent(JSON.stringify(item)),
});
}
// 新增 onShow 方法
onShow(() => {
handleQuery(); // 重新加载数据
});
onLoad(() => {
handleQuery();
});
</script>
<style lang="scss" scoped>
/* stylelint-disable selector-type-no-unknown */
page {
background: #f8f8f8;
}
/* stylelint-enable selector-type-no-unknown */
.work {
padding: 40rpx 0;
}
::v-deep .wd-drop-menu__item {
display: flex;
justify-content: flex-end;
padding: 0 50rpx;
}
.list-container {
height: calc(100vh - 350rpx); /* 调整高度以避免被底部按钮挡住 */
overflow-y: auto;
}
.card {
background-color: #fff;
border-radius: 8rpx;
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
}
.card-content {
padding: 10rpx;
}
.item {
//margin-bottom: 20rpx;
}
.title {
margin-bottom: 10rpx;
font-weight: bold;
}
.content {
display: flex;
flex-direction: column;
gap: 10rpx;
padding: 10rpx;
margin: 10rpx;
background: #f5f5f5;
}
.row-group {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
margin-bottom: 10rpx;
}
.row {
display: flex;
flex-direction: row;
gap: 0rpx; /* 调整 label 和 value 之间的间距 */
align-items: center;
justify-content: space-between;
width: 100%; /* 调整宽度以适应两列布局 */
margin-left: 20rpx;
}
.label {
flex: 1; /* 让 label 占据剩余空间的一部分 */
font-size: 24rpx;
}
.value {
flex: 3; /* 让 value 占据剩余空间的大部分 */
font-size: 22rpx;
color: #999;
}
</style>

View File

@@ -0,0 +1,223 @@
<template>
<view class="container">
<view class="form-container">
<wd-form ref="formRef" :model="form">
<wd-cell-group border>
<wd-input
v-model="form.configName"
label="配置名称"
label-width="100px"
prop="configName"
clearable
placeholder="请输入配置名称"
:rules="[{ required: true, message: '请填写配置名称' }]"
/>
<wd-input
v-model="form.configKey"
label="配置键"
label-width="100px"
prop="configKey"
clearable
placeholder="请输入配置键"
:rules="[{ required: true, message: '请填写配置键' }]"
/>
<wd-input
v-model="form.configValue"
label="配置值"
label-width="100px"
prop="configValue"
clearable
placeholder="请输入配置值"
:rules="[{ required: true, message: '请填写配置值' }]"
/>
<wd-input
v-model="form.remark"
label="描述、备注"
label-width="100px"
prop="remark"
clearable
placeholder="请输入描述或备注"
/>
</wd-cell-group>
<view class="footer">
<view class="button-container">
<wd-button type="primary" size="large" native-type="submit" block @click="handleSubmit">
提交
</wd-button>
<wd-button v-if="form.id" type="error" size="large" block @click="handleDelete">
删除
</wd-button>
</view>
</view>
</wd-form>
</view>
</view>
</template>
<script lang="ts" setup>
import { ref, onMounted } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import ConfigAPI, { ConfigForm, ConfigPageVO } from "@/api/system/config";
import { FormInstance } from "wot-design-uni/components/wd-form/types";
const form = ref<ConfigForm>({
id: undefined,
configName: "",
configKey: "",
configValue: "",
remark: "",
});
const formRef = ref<FormInstance>();
onMounted(() => {
console.log("Form ref:", formRef.value);
});
const handleSubmit = () => {
console.log("点击了提交按钮");
if (formRef.value) {
formRef.value!.validate().then(({ valid, errors }) => {
if (valid) {
console.log("表单数据:", form.value);
if (form.value.id) {
// 如果 id 不为 null调用更新 API
ConfigAPI.update(form.value.id as number, form.value)
.then((response) => {
console.log("更新成功:", response);
uni.showToast({
title: "更新成功",
icon: "success",
duration: 2000,
});
uni.navigateBack();
})
.catch((error) => {
console.error("更新失败:", error);
});
} else {
// 如果 id 为 null调用新增 API
ConfigAPI.add(form.value)
.then((response) => {
console.log("提交成功:", response);
uni.showToast({
title: "提交成功",
icon: "success",
duration: 2000,
});
uni.navigateBack();
})
.catch((error) => {
console.error("提交失败:", error);
});
}
} else {
console.log("表单验证未通过", errors);
}
});
} else {
console.error("Form ref is not defined");
}
};
const handleDelete = () => {
if (form.value.id !== undefined) {
uni.showModal({
title: "提示",
content: "确定要删除此配置吗?",
success: (res) => {
if (res.confirm) {
ConfigAPI.deleteById(form.value.id as number)
.then((response) => {
console.log("删除成功:", response);
uni.showToast({
title: "删除成功",
icon: "success",
duration: 2000,
});
uni.navigateBack();
})
.catch((error) => {
console.error("删除失败:", error);
});
}
},
});
} else {
console.error("无效的 ID");
}
};
// 定义接收的参数
const item = ref<ConfigPageVO | null>(null);
// 获取传递的参数
onLoad((options) => {
console.log("接收到参数:", options);
if (options && options.item) {
try {
item.value = JSON.parse(decodeURIComponent(options.item));
console.log("接收到的参数:", item.value);
if (item.value) {
form.value = {
id: item.value.id,
configName: item.value.configName,
configKey: item.value.configKey,
configValue: item.value.configValue,
remark: item.value.remark,
};
}
} catch (error) {
console.error("解析参数失败:", error);
}
} else {
console.log("没有接收到 item 参数");
}
});
</script>
<style scoped>
.container {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
padding: 40rpx;
background: #f8f8f8;
}
.form-container {
box-sizing: border-box;
width: 100%;
height: 100%;
padding: 40rpx;
background: #fff;
border-radius: 8rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
}
.footer {
display: flex;
align-items: center;
justify-content: space-between;
}
.button-container {
display: flex;
justify-content: space-between;
width: 100%;
}
.button-container .wd-button {
flex: 1;
margin: 0 5px; /* 调整按钮之间的间距 */
}
.wd-cell-group {
margin-bottom: 20rpx;
}
.wd-button {
width: 100%;
margin-top: 10rpx; /* 调整按钮间距 */
}
</style>