mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-20 20:39:55 +00:00
feat: 更新项目名称和配置,优化任务管理和字典功能
refactor(backend): 重命名任务分组为任务存储器并更新相关数据 fix(backend): 修正用户服务中密码重置的参数名错误 feat(frontend): 添加字典数据清理功能并在用户登出时调用 style(frontend): 简化加载页面样式并更新favicon feat(frontend): 实现动态设置页面标题和图标功能 feat(frontend): 增强角色和用户管理界面的操作限制 feat(frontend): 优化任务管理界面,使用字典数据展示选项 refactor(frontend): 改进字典存储模块,增加数据校验和过滤
This commit is contained in:
+35
-30
@@ -13,39 +13,44 @@ import "uno.css";
|
||||
// 过渡动画
|
||||
import "animate.css";
|
||||
|
||||
// import { useConfigStore } from "@/store";
|
||||
import { useConfigStore } from "@/store";
|
||||
|
||||
const app = createApp(App);
|
||||
// 注册插件
|
||||
app.use(setupPlugins);
|
||||
// 封装设置 title 和 favicon 的函数
|
||||
const setTitleAndFavicon = async () => {
|
||||
try {
|
||||
const configStore = useConfigStore();
|
||||
await configStore.getConfig();
|
||||
|
||||
const webTitle = configStore.configData.sys_web_title?.config_value;
|
||||
const webFavicon = configStore.configData.sys_web_favicon?.config_value;
|
||||
const webLogo = configStore.configData.sys_web_logo?.config_value;
|
||||
|
||||
if (webTitle) {
|
||||
document.title = webTitle;
|
||||
}
|
||||
|
||||
if (webFavicon) {
|
||||
const favicon = document.querySelector('link[rel="icon"]');
|
||||
if (favicon instanceof HTMLLinkElement) {
|
||||
favicon.href = webFavicon;
|
||||
}
|
||||
}
|
||||
|
||||
if (webLogo) {
|
||||
const loadingLogo = document.querySelector('.loading-container-logo');
|
||||
if (loadingLogo instanceof HTMLImageElement) {
|
||||
loadingLogo.src = webLogo;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取配置数据失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
app.mount("#app");
|
||||
|
||||
// 封装设置 title 和 favicon 的函数
|
||||
// const setTitleAndFavicon = async () => {
|
||||
// try {
|
||||
// const configStore = useConfigStore();
|
||||
// await configStore.getConfig();
|
||||
// console.log('配置数据获取成功:', configStore.configData);
|
||||
|
||||
// const loginTitle = configStore.configData.sys_web_title;
|
||||
// console.log('sys_web_title:', loginTitle);
|
||||
// const loginLogo = configStore.configData.sys_web_favicon;
|
||||
// console.log('sys_web_favicon:', loginLogo);
|
||||
|
||||
// if (loginTitle) {
|
||||
// document.title = loginTitle;
|
||||
// }
|
||||
|
||||
// if (loginLogo) {
|
||||
// const favicon = document.querySelector('link[rel="icon"]');
|
||||
// if (favicon instanceof HTMLLinkElement) {
|
||||
// favicon.href = loginLogo;
|
||||
// }
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('获取配置数据失败:', error);
|
||||
// }
|
||||
// };
|
||||
|
||||
// // 在 App 组件挂载后执行设置逻辑
|
||||
// onMounted(setTitleAndFavicon);
|
||||
// 在应用挂载后执行设置逻辑
|
||||
setTitleAndFavicon();
|
||||
|
||||
@@ -10,18 +10,43 @@ export const useDictStore = defineStore("dict", {
|
||||
getDictData(): Record<string, DictDataTable[]> {
|
||||
return this.dictData;
|
||||
},
|
||||
|
||||
// 获取指定类型的字典数据,确保返回数组
|
||||
// 获取指定类型的字典数据,确保返回有效的数组且项包含必需属性
|
||||
getDictArray() {
|
||||
return (type: string): Array<{dict_value: string; dict_label: string}> => {
|
||||
return (this.dictData[type] || []).filter(
|
||||
item => item.dict_value !== undefined && item.dict_label !== undefined
|
||||
).map(item => ({
|
||||
dict_value: item.dict_value!,
|
||||
dict_label: item.dict_label!
|
||||
}));
|
||||
};
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
// 批量获取字典数据
|
||||
async getDict(types: string[]) {
|
||||
// 批量获取字典数据
|
||||
async getDict(types: string[]): Promise<Record<string, DictDataTable[]>> {
|
||||
try {
|
||||
for (const type of types) {
|
||||
const response = await DictAPI.getInitDict(type);
|
||||
this.dictData[type] = response.data.data as DictDataTable[];
|
||||
this.isLoaded = true;
|
||||
if (!this.dictData[type]) {
|
||||
const response = await DictAPI.getInitDict(type);
|
||||
// 确保数据格式正确
|
||||
this.dictData[type] = (response.data.data as DictDataTable[] || []).filter(
|
||||
item => item.dict_value !== undefined && item.dict_label !== undefined
|
||||
);
|
||||
this.isLoaded = true;
|
||||
}
|
||||
}
|
||||
// 返回请求的字典数据
|
||||
return types.reduce((result, type) => {
|
||||
result[type] = this.getDictArray(type);
|
||||
return result;
|
||||
}, {} as Record<string, DictDataTable[]>);
|
||||
} catch (error) {
|
||||
console.error("获取字典数据失败", error);
|
||||
return {};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -41,6 +66,9 @@ export const useDictStore = defineStore("dict", {
|
||||
};
|
||||
return dict_data;
|
||||
},
|
||||
clearDictData() {
|
||||
this.dictData = {};
|
||||
},
|
||||
},
|
||||
persist: true,
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { store, useTagsViewStore, usePermissionStoreHook } from "@/store";
|
||||
import { store, useTagsViewStore, usePermissionStoreHook, useDictStoreHook } from "@/store";
|
||||
|
||||
import AuthAPI, {type LoginFormData } from "@/api/system/auth";
|
||||
import UserAPI, {type UserInfo } from "@/api/system/user";
|
||||
@@ -73,6 +73,8 @@ export const useUserStore = defineStore("user", {
|
||||
usePermissionStoreHook().resetRouter();
|
||||
// 清除标签视图
|
||||
useTagsViewStore().delAllViews();
|
||||
// 重置字典
|
||||
useDictStoreHook().clearDictData()
|
||||
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
@@ -134,18 +134,30 @@
|
||||
<el-table-column type="selection" align="center" min-width="55" />
|
||||
<el-table-column type="index" label="序号" fixed min-width="60">
|
||||
<template #default="scope">
|
||||
{{
|
||||
(queryFormData.page_no - 1) * queryFormData.page_size +
|
||||
scope.$index +
|
||||
1
|
||||
}}
|
||||
{{ (queryFormData.page_no - 1) * queryFormData.page_size + scope.$index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="任务名称" prop="name" min-width="140" />
|
||||
<el-table-column label="执行函数" prop="func" min-width="140" />
|
||||
<el-table-column label="触发器" prop="trigger" min-width="100" />
|
||||
<el-table-column label="存储器" prop="jobstore" min-width="100" />
|
||||
<el-table-column label="执行器" prop="executor" min-width="100" />
|
||||
<el-table-column label="执行函数" prop="func" min-width="140" >
|
||||
<template #default="scope">
|
||||
{{ (dictStore.getDictLabel('sys_job_function',scope.row.func) as any)?.dict_label || scope.row.func }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="触发器" prop="trigger" min-width="100">
|
||||
<template #default="scope">
|
||||
{{ (dictStore.getDictLabel('sys_job_trigger',scope.row.trigger) as any)?.dict_label || scope.row.trigger }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="存储器" prop="jobstore" min-width="120">
|
||||
<template #default="scope">
|
||||
{{ (dictStore.getDictLabel('sys_job_store',scope.row.jobstore) as any)?.dict_label || scope.row.jobstore }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="执行器" prop="executor" min-width="100">
|
||||
<template #default="scope">
|
||||
{{ (dictStore.getDictLabel('sys_job_executor',scope.row.executor) as any)?.dict_label || scope.row.executor }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="并发执行" prop="coalesce" min-width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.coalesce === true ? 'success' : 'danger'">
|
||||
@@ -329,24 +341,31 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="任务函数" prop="func" style="width: 40%">
|
||||
<el-input
|
||||
v-model="formData.func"
|
||||
placeholder="请输入任务函数"
|
||||
:maxlength="50"
|
||||
/>
|
||||
<el-select v-model="formData.func" placeholder="请选择任务函数">
|
||||
<el-option v-for="item in dictStore.getDictArray('sys_job_function')"
|
||||
:key="item.dict_value"
|
||||
:label="item.dict_label"
|
||||
:value="item.dict_value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="存储器" prop="jobstore" style="width: 40%">
|
||||
<el-select v-model="formData.jobstore" placeholder="请选择存储器">
|
||||
<el-option value="default" label="默认(Memory)" />
|
||||
<el-option value="sqlalchemy" label="数据库" />
|
||||
<el-option value="redis" label="Redis存储器" />
|
||||
</el-select>
|
||||
<el-option v-for="item in dictStore.getDictArray('sys_job_store')"
|
||||
:key="item.dict_value"
|
||||
:label="item.dict_label"
|
||||
:value="item.dict_value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="执行器" prop="executor" style="width: 40%">
|
||||
<el-select v-model="formData.executor" placeholder="请选择执行器">
|
||||
<el-option value="default" label="默认" />
|
||||
<el-option value="processpool" label="进程池" />
|
||||
</el-select>
|
||||
<el-option v-for="item in dictStore.getDictArray('sys_job_executor')"
|
||||
:key="item.dict_value"
|
||||
:label="item.dict_label"
|
||||
:value="item.dict_value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="位置参数" prop="args" style="width: 40%">
|
||||
<el-input
|
||||
@@ -382,10 +401,12 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="触发器" prop="trigger" style="width: 40%">
|
||||
<el-select v-model="formData.trigger" placeholder="请选择触发器">
|
||||
<el-option value="date" label="指定日期(date)" />
|
||||
<el-option value="interval" label="间隔触发器(interval)" />
|
||||
<el-option value="cron" label="cron表达式" />
|
||||
</el-select>
|
||||
<el-option v-for="item in dictStore.getDictArray('sys_job_trigger')"
|
||||
:key="item.dict_value"
|
||||
:label="item.dict_label"
|
||||
:value="item.dict_value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 运行日期、间隔时间或 Cron 表达式 -->
|
||||
<el-form-item
|
||||
@@ -552,10 +573,6 @@ import "vue3-cron-plus/dist/index.css"; // 引入样式
|
||||
|
||||
const dictStore = useDictStore();
|
||||
|
||||
// const DictDataStore = computed(() => {
|
||||
// return dictStore.dictData;
|
||||
// })
|
||||
|
||||
const queryFormRef = ref();
|
||||
const dataFormRef = ref();
|
||||
const total = ref(0);
|
||||
@@ -565,18 +582,8 @@ const loading = ref(false);
|
||||
const isExpand = ref(false);
|
||||
const isExpandable = ref(true);
|
||||
|
||||
// const createForm = ref();
|
||||
// const updateForm = ref();
|
||||
// const tableLoading = ref(false);
|
||||
// const openModal = ref(false);
|
||||
const openCron = ref(false);
|
||||
|
||||
// const modalSubmitLoading = ref(false);
|
||||
// const detailStateLoading = ref(false);
|
||||
// const dataSource = ref<tableJobType[]>([]);
|
||||
// const selectedRowKeys = ref<tableJobType['id'][]>([]);
|
||||
// const queryState = reactive<searchType>({});
|
||||
// const detailState = ref<tableJobType>({})
|
||||
const openIntervalTab = ref(false);
|
||||
const intervalTabRef = ref();
|
||||
|
||||
@@ -689,7 +696,7 @@ const initialFormData: JobForm = {
|
||||
trigger: undefined,
|
||||
args: undefined,
|
||||
kwargs: undefined,
|
||||
coalesce: undefined,
|
||||
coalesce: false,
|
||||
max_instances: 1,
|
||||
jobstore: undefined,
|
||||
executor: undefined,
|
||||
@@ -892,7 +899,10 @@ const handleOption = (id: number, option: number) => {
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
// 加载字典数据
|
||||
await dictStore.getDict(['sys_job_function','sys_job_executor','sys_job_store', 'sys_job_trigger']);
|
||||
// 加载表格数据
|
||||
loadingData();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -133,10 +133,38 @@
|
||||
|
||||
<el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center" min-width="280">
|
||||
<template #default="scope">
|
||||
<el-button type="warning" size="small" link icon="position" @click="handleOpenAssignPermDialog(scope.row.id, scope.row.name)">分配权限</el-button>
|
||||
<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-button
|
||||
type="warning"
|
||||
size="small"
|
||||
link
|
||||
icon="position"
|
||||
@click="scope.row.id === 1 ? ElMessage.warning('系统默认角色,不可操作') : handleOpenAssignPermDialog(scope.row.id, scope.row.name)"
|
||||
:disabled="scope.row.id === 1"
|
||||
>分配权限</el-button>
|
||||
<el-button
|
||||
type="info"
|
||||
size="small"
|
||||
link
|
||||
icon="document"
|
||||
@click="scope.row.id === 1 ? ElMessage.warning('系统默认角色,不可操作') : handleOpenDialog('detail', scope.row.id)"
|
||||
:disabled="scope.row.id === 1"
|
||||
>详情</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
link
|
||||
icon="edit"
|
||||
@click="scope.row.id === 1 ? ElMessage.warning('系统默认角色,不可操作') : handleOpenDialog('update', scope.row.id)"
|
||||
:disabled="scope.row.id === 1"
|
||||
>编辑</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
link
|
||||
icon="delete"
|
||||
@click="scope.row.id === 1 ? ElMessage.warning('系统默认角色,不可操作') : handleDelete([scope.row.id])"
|
||||
:disabled="scope.row.id === 1"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
@@ -152,10 +152,37 @@
|
||||
</el-table-column>
|
||||
<el-table-column fixed="right" label="操作" align="center" min-width="280">
|
||||
<template #default="scope">
|
||||
<el-button type="warning" icon="RefreshLeft" size="small" link @click="hancleResetPassword(scope.row)">重置密码</el-button>
|
||||
<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-button
|
||||
v-if="scope.row.username !== 'admin'"
|
||||
type="warning"
|
||||
icon="RefreshLeft"
|
||||
size="small"
|
||||
link
|
||||
@click="hancleResetPassword(scope.row)"
|
||||
>重置密码</el-button>
|
||||
<el-button
|
||||
type="info"
|
||||
size="small"
|
||||
link
|
||||
icon="document"
|
||||
@click="handleOpenDialog('detail', scope.row.id)"
|
||||
>详情</el-button>
|
||||
<el-button
|
||||
v-if="scope.row.username !== 'admin'"
|
||||
type="primary"
|
||||
size="small"
|
||||
link
|
||||
icon="edit"
|
||||
@click="handleOpenDialog('update', scope.row.id)"
|
||||
>编辑</el-button>
|
||||
<el-button
|
||||
v-if="scope.row.username !== 'admin'"
|
||||
type="danger"
|
||||
size="small"
|
||||
link
|
||||
icon="delete"
|
||||
@click="handleDelete([scope.row.id])"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -316,7 +343,6 @@ import DeptAPI from "@/api/system/dept";
|
||||
import RoleAPI from "@/api/system/role";
|
||||
|
||||
import DeptTree from "./components/DeptTree.vue";
|
||||
import UserImport from "./components/UserImport.vue";
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user