refactor(frontend): 优化多个视图组件代码结构和功能

fix(frontend): 修复表单重置和刷新功能的潜在问题
style(frontend): 统一按钮样式和布局
feat(frontend): 在仪表盘添加文档链接
chore: 删除不再需要的开发数据库文件和git属性配置
This commit is contained in:
zhangtao
2025-07-24 00:24:48 +08:00
parent 2c0ee65844
commit 80179adb73
22 changed files with 676 additions and 356 deletions
+18 -3
View File
@@ -19,8 +19,23 @@
<!-- 右侧图标区域 - PC端 -->
<div class="hidden sm:block">
<div class="flex items-end space-x-6">
<!-- 文档 -->
<div class="flex flex-col items-center">
<div class="font-bold color-#4080ff text-sm flex items-center">
<el-icon class="mr-2px"><Document /></el-icon>
文档
</div>
<div class="mt-3 whitespace-nowrap">
<el-link
href="https://blog.csdn.net/weixin_46768253/article/details/149569141?spm=1001.2014.3001.5502"
target="_blank"
>
<div class="i-svg:csdn text-lg" />
</el-link>
</div>
</div>
<!-- 仓库 -->
<div>
<div class="flex flex-col items-center">
<div class="font-bold color-#ff9a2e text-sm flex items-center">
<el-icon class="mr-2px">
<Folder />
@@ -41,7 +56,6 @@
</el-link>
</div>
</div>
</div>
</div>
@@ -52,13 +66,14 @@
<el-link href="https://gitee.com/tao__tao/fastapi_vue3_admin" target="_blank">
<div class="i-svg:gitee text-lg color-#F76560" />
</el-link>
<el-divider direction="vertical" />
<el-link href="https://github.com/1014TaoTao/fastapi_vue3_admin" target="_blank">
<div class="i-svg:github text-lg color-#4080FF" />
</el-link>
<el-divider direction="vertical" />
<el-link href="https://gitcode.com/qq_36002987/fastapi_vue3_admin" target="_blank">
<div class="i-svg:gitcode text-lg color-#FF9A2E" />
</el-link>
</div>
</div>
</div>
+45 -51
View File
@@ -175,50 +175,44 @@
<el-table-column fixed="right" label="操作" min-width="240">
<template #default="scope">
<el-button
type="info"
size="small"
link
icon="document"
@click="handleOpenDialog('detail', scope.row.id)"
>详情</el-button
>
<el-button
type="primary"
size="small"
link
icon="edit"
@click="handleOpenDialog('update', scope.row.id)"
>编辑</el-button
>
<el-button
type="danger"
size="small"
link
icon="delete"
@click="handleDelete([scope.row.id])"
>删除</el-button
>
<el-dropdown trigger="click">
<el-button type="default" size="small" link icon="ArrowDown"
>更多</el-button
<div class="flex">
<el-button
type="info"
size="small"
link
icon="document"
@click="handleOpenDialog('detail', scope.row.id)"
>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
icon="Check"
@click="handleOption(scope.row, 1)"
>暂停</el-dropdown-item
>
<el-dropdown-item
icon="CircleClose"
@click="handleOption(scope.row, 2)"
>恢复</el-dropdown-item
>
<!-- <el-dropdown-item icon="CircleClose" @click="handleOption(scope.row, 3)">重启</el-dropdown-item> -->
</el-dropdown-menu>
</template>
</el-dropdown>
详情
</el-button>
<el-button
type="primary"
size="small"
link
icon="edit"
@click="handleOpenDialog('update', scope.row.id)"
>
编辑
</el-button>
<el-button
type="danger"
size="small"
link
icon="delete"
@click="handleDelete([scope.row.id])"
>
删除
</el-button>
<el-dropdown trigger="click">
<el-button type="warning" size="small" link icon="ArrowDown">更多</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item icon="Check" @click="handleOption(scope.row, 1)">暂停</el-dropdown-item>
<el-dropdown-item icon="CircleClose" @click="handleOption(scope.row, 2)">恢复</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
</el-table>
@@ -506,7 +500,6 @@ defineOptions({
import JobAPI, { JobTable, JobForm, JobPageQuery } from "@/api/monitor/job";
import { ElMessage, ElMessageBox } from "element-plus";
import { useDebounceFn } from "@vueuse/core";
import IntervalTab from "@/components/IntervalTab/index.vue";
import "vue3-cron-plus-picker/style.css";
@@ -598,11 +591,10 @@ const rules = reactive({
executor: [{ required: true, message: "请选择执行器", trigger: "blur" }],
});
// 刷新数据(防抖)
const handleRefresh = useDebounceFn(() => {
loadingData();
ElMessage.success("刷新成功");
}, 1000);
// 列表刷新
async function handleRefresh () {
await loadingData();
};
// 加载表格数据
async function loadingData() {
@@ -633,8 +625,10 @@ async function handleResetQuery() {
// 重置表单
async function resetForm() {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
if (dataFormRef.value) {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
}
formData.id = undefined;
}
+10 -8
View File
@@ -37,7 +37,7 @@
<!-- 功能区域 -->
<div class="data-table__toolbar">
<div class="data-table__toolbar--actions">
<el-button type="danger" icon="delete" @click="handleClear()">强退所有</el-button>
<el-button type="danger" icon="delete" @click="handleClear">强退所有</el-button>
</div>
<div class="data-table__toolbar--tools">
<el-tooltip content="刷新">
@@ -104,7 +104,6 @@ defineOptions({
import OnlineAPI, { type OnlineUserPageQuery, type OnlineUserTable } from "@/api/monitor/online";
import { ElMessage, ElMessageBox } from "element-plus";
import { useDebounceFn } from "@vueuse/core";
const queryFormRef = ref();
const total = ref(0);
@@ -138,11 +137,10 @@ const queryFormData = reactive<OnlineUserPageQuery>({
ipaddr: undefined
});
// 刷新数据(防抖)
const handleRefresh = useDebounceFn(() => {
loadingData();
ElMessage.success("刷新成功");
}, 1000);
// 列表刷新
async function handleRefresh () {
await loadingData();
};
// 加载表格数据
async function loadingData() {
@@ -212,8 +210,12 @@ async function handleClear() {
handleResetQuery();
} catch (error: any) {
ElMessage.error(error.message);
} finally {
loading.value = false;
}
})
}).catch(() => {
ElMessage.info('已取消强退');
});
}
onMounted(() => {
loadingData();
+8 -8
View File
@@ -189,7 +189,6 @@ defineOptions({
import ConfigAPI, { ConfigTable, ConfigForm, ConfigPageQuery } from "@/api/system/config";
import { ElMessage, ElMessageBox } from "element-plus";
import { useDebounceFn } from "@vueuse/core";
const queryFormRef = ref();
const dataFormRef = ref();
@@ -258,11 +257,10 @@ const rules = reactive({
config_type: [{ required: true, message: "请选择系统配置类型", trigger: "blur" }],
});
// 刷新数据(防抖)
const handleRefresh = useDebounceFn(() => {
loadingData();
ElMessage.success("刷新成功");
}, 1000);
// 列表刷新
async function handleRefresh () {
await loadingData();
};
// 加载表格数据
async function loadingData() {
@@ -295,8 +293,10 @@ async function handleResetQuery() {
// 重置表单
async function resetForm() {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
if (dataFormRef.value) {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
}
formData.id = undefined;
}
@@ -244,7 +244,6 @@ const props = defineProps({
import DictAPI, { DictDataTable, DictDataForm, DictDataPageQuery } from "@/api/system/dict";
import { ElMessage, ElMessageBox } from "element-plus";
import { useDebounceFn } from "@vueuse/core";
import { Check, Close } from '@element-plus/icons-vue'
import { useAppStore } from "@/store/modules/app.store";
import { DeviceEnum } from "@/enums/settings/device.enum";
@@ -332,11 +331,10 @@ const rules = reactive({
is_default: [{ required: true, message: "请选择是否默认", trigger: "blur" }],
});
// 刷新数据(防抖)
const handleRefresh = useDebounceFn(() => {
loadingData();
ElMessage.success("刷新成功");
}, 1000);
// 列表刷新
async function handleRefresh () {
await loadingData();
};
// 加载表格数据
async function loadingData() {
@@ -371,8 +369,10 @@ async function handleResetQuery() {
// 重置表单
async function resetForm() {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
if (dataFormRef.value) {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
}
formData.id = undefined;
}
+8 -8
View File
@@ -205,7 +205,6 @@ defineOptions({
import DictAPI, { DictTable, DictForm, DictPageQuery } from "@/api/system/dict";
import { ElMessage, ElMessageBox } from "element-plus";
import { useDebounceFn } from "@vueuse/core";
import DataDrawer from "@/views/system/dict/components/DataDrawer.vue"
const queryFormRef = ref();
@@ -272,11 +271,10 @@ const rules = reactive({
status: [{ required: true, message: "请选择字典状态", trigger: "blur" }],
});
// 刷新数据(防抖)
const handleRefresh = useDebounceFn(() => {
loadingData();
ElMessage.success("刷新成功");
}, 1000);
// 列表刷新
async function handleRefresh () {
await loadingData();
};
// 抽屉显隐
@@ -319,8 +317,10 @@ async function handleResetQuery() {
// 重置表单
async function resetForm() {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
if (dataFormRef.value) {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
}
formData.id = undefined;
}
+29 -29
View File
@@ -151,36 +151,36 @@
<template v-if="dialogVisible.type === 'detail'">
<el-descriptions :column="4" border>
<el-descriptions-item label="日志类型" :span="2">
<el-tag :type="detailFormData.type === 1 ? 'success' : 'primary'">
{{ detailFormData.type === 1 ? '登录日志' : '操作日志' }}
<el-tag :type="formData.type === 1 ? 'success' : 'primary'">
{{ formData.type === 1 ? '登录日志' : '操作日志' }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="请求路径" :span="2">{{ detailFormData.request_path }}</el-descriptions-item>
<el-descriptions-item label="请求路径" :span="2">{{ formData.request_path }}</el-descriptions-item>
<el-descriptions-item label="请求方法" :span="2">
<el-tag :type="getMethodType(detailFormData.request_method)">
{{ detailFormData.request_method }}
<el-tag :type="getMethodType(formData.request_method)">
{{ formData.request_method }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="响应状态码" :span="2">
<el-tag :type="getStatusCodeType(detailFormData.response_code)">
{{ detailFormData.response_code }}
<el-tag :type="getStatusCodeType(formData.response_code)">
{{ formData.response_code }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="请求IP" :span="2">{{ detailFormData.request_ip }}</el-descriptions-item>
<el-descriptions-item label="处理时间" :span="2">{{ detailFormData.process_time }}</el-descriptions-item>
<el-descriptions-item label="浏览器" :span="2">{{ detailFormData.request_browser }}</el-descriptions-item>
<el-descriptions-item label="操作系统" :span="2">{{ detailFormData.request_os }}</el-descriptions-item>
<el-descriptions-item label="请求IP" :span="2">{{ formData.request_ip }}</el-descriptions-item>
<el-descriptions-item label="处理时间" :span="2">{{ formData.process_time }}</el-descriptions-item>
<el-descriptions-item label="浏览器" :span="2">{{ formData.request_browser }}</el-descriptions-item>
<el-descriptions-item label="操作系统" :span="2">{{ formData.request_os }}</el-descriptions-item>
<el-descriptions-item label="请求参数" :span="4">
<el-input v-model="detailFormData.request_payload" type="textarea" :rows="3" readonly class="long-text-editor" />
<el-input v-model="formData.request_payload" type="textarea" :rows="3" readonly class="long-text-editor" />
</el-descriptions-item>
<el-descriptions-item label="响应数据" :span="4">
<el-input v-model="detailFormData.response_json" type="textarea" :rows="5" readonly class="long-text-editor" />
<el-input v-model="formData.response_json" type="textarea" :rows="5" readonly class="long-text-editor" />
</el-descriptions-item>
<el-descriptions-item label="登录地点" :span="2">{{ detailFormData.login_location }}</el-descriptions-item>
<el-descriptions-item label="创建人" :span="2">{{ detailFormData.creator?.name }}</el-descriptions-item>
<el-descriptions-item label="创建时间" :span="2">{{ detailFormData.created_at }}</el-descriptions-item>
<el-descriptions-item label="更新时间" :span="2">{{ detailFormData.updated_at }}</el-descriptions-item>
<el-descriptions-item label="描述" :span="4">{{ detailFormData.description }}</el-descriptions-item>
<el-descriptions-item label="登录地点" :span="2">{{ formData.login_location }}</el-descriptions-item>
<el-descriptions-item label="创建人" :span="2">{{ formData.creator?.name }}</el-descriptions-item>
<el-descriptions-item label="创建时间" :span="2">{{ formData.created_at }}</el-descriptions-item>
<el-descriptions-item label="更新时间" :span="2">{{ formData.updated_at }}</el-descriptions-item>
<el-descriptions-item label="描述" :span="4">{{ formData.description }}</el-descriptions-item>
</el-descriptions>
</template>
@@ -204,7 +204,6 @@ defineOptions({
import LogAPI, { LogTable, LogPageQuery } from "@/api/system/log";
import { ElMessage, ElMessageBox } from "element-plus";
import { useDebounceFn } from "@vueuse/core";
const queryFormRef = ref();
const dataFormRef = ref();
@@ -238,7 +237,7 @@ const tableColumns = ref([
])
// 详情表单
const detailFormData = ref<LogTable>({});
const formData = ref<LogTable>({});
// 分页查询参数
const queryFormData = reactive<LogPageQuery>({
@@ -258,11 +257,10 @@ const dialogVisible = reactive({
type: 'create' as 'create' | 'update' | 'detail',
});
// 刷新数据(防抖)
const handleRefresh = useDebounceFn(() => {
loadingData();
ElMessage.success("刷新成功");
}, 1000);
// 列表刷新
async function handleRefresh () {
await loadingData();
};
const getStatusCodeType = (code?: number) => {
if (code === undefined) {
@@ -327,9 +325,11 @@ async function handleResetQuery() {
// 重置表单
async function resetForm() {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
detailFormData.value.id = undefined;
if (dataFormRef.value) {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
}
formData.value.id = undefined;
}
// 行复选框选中项变化
@@ -350,7 +350,7 @@ async function handleOpenDialog(type: 'create' | 'update' | 'detail', id: number
const response = await LogAPI.getLogDetail(id);
if (type === 'detail') {
dialogVisible.title = "日志详情";
Object.assign(detailFormData.value, response.data.data);
Object.assign(formData.value, response.data.data);
}
}
dialogVisible.visible = true;
+4 -3
View File
@@ -595,7 +595,6 @@ async function loadingData() {
// 查询(重置页码后获取数据)
async function handleQuery() {
queryFormData.page_no = 1;
loadingData();
}
@@ -607,8 +606,10 @@ async function handleResetQuery() {
// 重置表单
async function resetForm() {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
if (dataFormRef.value) {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
}
formData.id = undefined;
}
+8 -8
View File
@@ -245,7 +245,6 @@ defineOptions({
import NoticeAPI, { NoticeTable, NoticeForm, NoticePageQuery } from "@/api/system/notice";
import { ElMessage, ElMessageBox } from "element-plus";
import { useDebounceFn } from "@vueuse/core";
const queryFormRef = ref();
const dataFormRef = ref();
@@ -312,11 +311,10 @@ const rules = reactive({
status: [{ required: true, message: "请选择公告通知状态", trigger: "blur" }],
});
// 刷新数据(防抖)
const handleRefresh = useDebounceFn(() => {
loadingData();
ElMessage.success("刷新成功");
}, 1000);
// 列表刷新
async function handleRefresh () {
await loadingData();
};
// 加载表格数据
async function loadingData() {
@@ -349,8 +347,10 @@ async function handleResetQuery() {
// 重置表单
async function resetForm() {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
if (dataFormRef.value) {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
}
formData.id = undefined;
}
+9 -8
View File
@@ -194,7 +194,6 @@ defineOptions({
import PositionAPI, { PositionTable, PositionForm, PositionPageQuery } from "@/api/system/position";
import { ElMessage, ElMessageBox } from "element-plus";
import { useDebounceFn } from "@vueuse/core";
const queryFormRef = ref();
const dataFormRef = ref();
@@ -259,11 +258,11 @@ const rules = reactive({
status: [{ required: true, message: "请选择岗位状态", trigger: "blur" }],
});
// 刷新数据(防抖)
const handleRefresh = useDebounceFn(() => {
loadingData();
ElMessage.success("刷新成功");
}, 1000);
// 列表刷新
async function handleRefresh () {
await loadingData();
};
// 加载表格数据
async function loadingData() {
@@ -296,8 +295,10 @@ async function handleResetQuery() {
// 重置表单
async function resetForm() {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
if (dataFormRef.value) {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
}
formData.id = undefined;
}
+15 -14
View File
@@ -303,11 +303,10 @@ async function loadingData() {
}
}
// 刷新数据(防抖)
const handleRefresh = useDebounceFn(() => {
loadingData();
ElMessage.success("刷新成功");
}, 1000);
// 列表刷新
async function handleRefresh () {
await loadingData();
};
// 查询(重置页码后获取数据)
async function handleQuery() {
@@ -315,22 +314,24 @@ async function handleQuery() {
loadingData();
}
// 重置查询
async function handleResetQuery() {
queryFormRef.value.resetFields();
queryFormData.page_no = 1;
loadingData();
}
// 行复选框选中项变化
async function handleSelectionChange(selection: any) {
selectIds.value = selection.map((item: any) => item.id);
}
// 重置查询
async function handleResetQuery() {
queryFormRef.value.resetFields();
queryFormData.page_no = 1;
loadingData();
}
// 重置表单
async function resetForm() {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
if (dataFormRef.value) {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
}
formData.id = undefined;
}
+15 -13
View File
@@ -107,7 +107,7 @@
</div>
<!-- 表格区域 -->
<el-table ref="dataFormRef" v-loading="loading" :data="pageTableData" highlight-current-row class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
<el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
<template #empty>
<el-empty :image-size="80" description="暂无数据" />
</template>
@@ -213,7 +213,7 @@
</template>
<!-- 新增编辑表单 -->
<template v-else>
<el-form ref="userFormRef" :model="formData" :rules="rules" label-width="80px">
<el-form ref="dataFormRef" :model="formData" :rules="rules" label-width="80px">
<el-form-item label="账号" prop="username">
<el-input v-model="formData.username" :readonly="!!formData.id" placeholder="请输入账号" />
</el-form-item>
@@ -308,7 +308,6 @@ defineOptions({
import { useAppStore } from "@/store/modules/app.store";
import { DeviceEnum } from "@/enums/settings/device.enum";
import { ElMessage, ElMessageBox } from "element-plus";
import { useDebounceFn } from "@vueuse/core";
import UserAPI, { type UserForm, type UserInfo, type UserPageQuery } from "@/api/system/user";
import { listToTree, formatTree } from "@/utils/common";
@@ -322,7 +321,6 @@ import UserImport from "./components/UserImport.vue";
const appStore = useAppStore();
const queryFormRef = ref();
const userFormRef = ref();
const dataFormRef = ref();
const total = ref(0);
const loading = ref(false);
@@ -428,11 +426,10 @@ const rules = reactive({
status: [{ required: true, message: "请选择状态", trigger: "blur" }],
});
// 刷新数据(防抖)
const handleRefresh = useDebounceFn(() => {
loadingData();
ElMessage.success("刷新成功");
}, 1000);
// 列表刷新
async function handleRefresh () {
await loadingData();
};
// 加载表格数据
async function loadingData() {
@@ -465,8 +462,10 @@ async function handleResetQuery() {
// 重置表单
async function resetForm() {
userFormRef.value.resetFields();
userFormRef.value.clearValidate();
if (dataFormRef.value) {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
}
formData.id = undefined;
}
@@ -520,10 +519,12 @@ async function handleOpenDialog(type: 'create' | 'update' | 'detail', id?: numbe
}
dialogVisible.visible = true;
// 获取部门树
const deptResponse = await DeptAPI.getDeptList(queryFormData);
const treeData = listToTree(deptResponse.data.data.items);
deptOptions.value = formatTree(treeData);
// 获取角色列表
const roleResponse = await RoleAPI.getRoleList();
roleOptions.value = roleResponse.data.data.items
.filter(item => item.id !== undefined && item.name !== undefined)
@@ -532,6 +533,7 @@ async function handleOpenDialog(type: 'create' | 'update' | 'detail', id?: numbe
label: item.name as string
}));
// 获取岗位列表
const positionResponse = await PositionAPI.getPositionList();
positionOptions.value = positionResponse.data.data.items
.filter(item => item.id !== undefined && item.name !== undefined)
@@ -542,7 +544,7 @@ async function handleOpenDialog(type: 'create' | 'update' | 'detail', id?: numbe
}
// 提交表单(防抖)
const handleSubmit = useDebounceFn(async () => {
async function handleSubmit() {
// 表单校验
dataFormRef.value.validate(async (valid: any) => {
if (valid) {
@@ -576,7 +578,7 @@ const handleSubmit = useDebounceFn(async () => {
}
}
});
}, 1000)
}
// 删除、导入、导出
async function handleOperation(type: 'import' | 'export') {