perf: 修复删除历史记录没有删除log的bug,新增history管理页面,演示站点启动时不自动启动非管理员用户的定时任务

This commit is contained in:
xiaojunnuo
2024-08-05 12:49:44 +08:00
parent 0227155ab4
commit f78ae93eed
25 changed files with 562 additions and 77 deletions
@@ -1,9 +1,9 @@
import { request } from "../service";
export type SysPublicSetting = {
registerEnabled:boolean
}
registerEnabled: boolean;
managerOtherUserPipeline: boolean;
};
export async function getSysPublicSettings(): Promise<SysPublicSetting> {
return await request({
@@ -18,6 +18,7 @@ export interface UserInfoRes {
id: string | number;
username: string;
nickName: string;
roles: number[];
}
export interface LoginRes {
@@ -27,6 +27,15 @@ export const certdResources = [
isMenu: false
}
},
{
title: "执行历史记录",
name: "pipelineHistory",
path: "/certd/history",
component: "/certd/history/index.vue",
meta: {
icon: "ion:timer-outline"
}
},
{
title: "授权管理",
name: "access",
@@ -4,9 +4,8 @@ import _ from "lodash-es";
// @ts-ignore
import { LocalStorage } from "/src/utils/util.storage";
import * as basicApi from "/@/api/modules/api.basic";
import { SysPublicSetting } from "/@/api/modules/api.basic";
import * as basicApi from '/@/api/modules/api.basic'
import _ from "lodash-es";
export type ThemeToken = {
token: {
@@ -21,7 +20,7 @@ export type ThemeConfig = {
export interface SettingState {
themeConfig?: ThemeConfig;
themeToken: ThemeToken;
sysPublic?: SysPublicSetting
sysPublic?: SysPublicSetting;
}
const defaultThemeConfig = {
@@ -38,21 +37,22 @@ export const useSettingStore = defineStore({
algorithm: theme.defaultAlgorithm
},
sysPublic: {
registerEnabled: false
registerEnabled: false,
managerOtherUserPipeline: false
}
}),
getters: {
getThemeConfig(): any {
return this.themeConfig || _.merge({}, defaultThemeConfig, LocalStorage.get(SETTING_THEME_KEY) || {});
},
getSysPublic():SysPublicSetting{
return this.sysPublic
getSysPublic(): SysPublicSetting {
return this.sysPublic;
}
},
actions: {
async loadSysSettings(){
const settings = await basicApi.getSysPublicSettings()
_.merge(this.sysPublic,settings)
async loadSysSettings() {
const settings = await basicApi.getSysPublicSettings();
_.merge(this.sysPublic, settings);
},
persistThemeConfig() {
LocalStorage.set(SETTING_THEME_KEY, this.getThemeConfig);
@@ -92,7 +92,7 @@ export const useSettingStore = defineStore({
},
async init() {
await this.setThemeConfig(this.getThemeConfig);
await this.loadSysSettings()
await this.loadSysSettings();
}
}
});
@@ -34,6 +34,9 @@ export const useUserStore = defineStore({
},
getToken(): string {
return this.token || LocalStorage.get(TOKEN_KEY);
},
isAdmin(): boolean {
return this.getUserInfo?.id === 1;
}
},
actions: {
@@ -0,0 +1,59 @@
import { request } from "/src/api/service";
const apiPrefix = "/pi/history";
export function GetList(query: any) {
return request({
url: apiPrefix + "/page",
method: "post",
data: query
});
}
export function AddObj(obj: any) {
return request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export function UpdateObj(obj: any) {
return request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export function DelObj(id: any) {
return request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export function GetObj(id: any) {
return request({
url: apiPrefix + "/info",
method: "post",
params: { id }
});
}
export function GetDetail(id: any) {
return request({
url: apiPrefix + "/detail",
method: "post",
params: { id }
});
}
export function DeleteBatch(ids: any[]) {
return request({
url: apiPrefix + "/deleteByIds",
method: "post",
data: { ids }
});
}
@@ -0,0 +1,154 @@
import * as api from "./api";
import { useI18n } from "vue-i18n";
import { computed, Ref, ref } from "vue";
import { useRouter } from "vue-router";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes, utils } from "@fast-crud/fast-crud";
import { useUserStore } from "/@/store/modules/user";
import { useSettingStore } from "/@/store/modules/settings";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const router = useRouter();
const { t } = useI18n();
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
form.id = row.id;
const res = await api.UpdateObj(form);
return res;
};
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
const addRequest = async ({ form }: AddReq) => {
form.content = JSON.stringify({
title: form.title
});
const res = await api.AddObj(form);
return res;
};
const userStore = useUserStore();
const settingStore = useSettingStore();
const selectedRowKeys: Ref<any[]> = ref([]);
context.selectedRowKeys = selectedRowKeys;
return {
crudOptions: {
settings: {
plugins: {
//这里使用行选择插件,生成行选择crudOptions配置,最终会与crudOptions合并
rowSelection: {
enabled: true,
order: -2,
before: true,
// handle: (pluginProps,useCrudProps)=>CrudOptions,
props: {
multiple: true,
crossPage: true,
selectedRowKeys
}
}
}
},
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
actionbar: {
buttons: {
add: {
show: false
}
}
},
rowHandle: {
minWidth: 200,
fixed: "right",
buttons: {
edit: {
show: false
}
}
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 100
},
form: {
show: false
}
},
userId: {
title: "用户Id",
type: "number",
search: {
show: computed(() => {
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
})
},
form: {
show: false
},
column: {
show: computed(() => {
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
})
}
},
pipelineId: {
title: "流水线Id",
type: "number",
search: {
show: true
},
form: {
show: false
}
},
pipelineTitle: {
title: "流水线名称",
type: "link",
search: {
show: true,
component: {
name: "a-input"
}
},
column: {
width: 200
}
},
createTime: {
title: "创建时间",
type: "datetime",
form: {
show: false
},
column: {
sorter: true,
width: 125,
align: "center"
}
},
updateTime: {
title: "更新时间",
type: "datetime",
form: {
show: false
},
column: {
show: true
}
}
}
}
};
}
@@ -0,0 +1,51 @@
<template>
<fs-page class="page-cert">
<template #header>
<div class="title">流水线执行记录</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding">
<template #pagination-left>
<a-tooltip title="批量删除">
<fs-button icon="DeleteOutlined" @click="handleBatchDelete"></fs-button>
</a-tooltip>
</template>
</fs-crud>
</fs-page>
</template>
<script lang="ts" setup>
import { onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "/@/views/certd/history/api";
defineOptions({
name: "PipelineHistory"
});
const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions });
const selectedRowKeys = context.selectedRowKeys;
const handleBatchDelete = () => {
if (selectedRowKeys.value?.length > 0) {
Modal.confirm({
title: "确认",
content: `确定要批量删除这${selectedRowKeys.value.length}条记录吗`,
async onOk() {
await DeleteBatch(selectedRowKeys.value);
message.info("删除成功");
crudExpose.doRefresh();
selectedRowKeys.value = [];
}
});
} else {
message.error("请先勾选记录");
}
};
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
</script>
<style lang="less"></style>
@@ -1,6 +1,6 @@
import * as api from "./api";
import { useI18n } from "vue-i18n";
import { ref } from "vue";
import { computed, ref } from "vue";
import { useRouter } from "vue-router";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { statusUtil } from "/@/views/certd/pipeline/pipeline/utils/util.status";
@@ -9,6 +9,7 @@ import { message, Modal } from "ant-design-vue";
import { env } from "/@/utils/util.env";
import { useUserStore } from "/@/store/modules/user";
import dayjs from "dayjs";
import { useSettingStore } from "/@/store/modules/settings";
export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const router = useRouter();
@@ -94,6 +95,7 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
});
}
const userStore = useUserStore();
const settingStore = useSettingStore();
return {
crudOptions: {
request: {
@@ -192,6 +194,23 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
show: false
}
},
userId: {
title: "用户Id",
type: "number",
search: {
show: computed(() => {
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
})
},
form: {
show: false
},
column: {
show: computed(() => {
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
})
}
},
title: {
title: "流水线名称",
type: "link",
@@ -1,6 +1,15 @@
<template>
<div class="main">
<a-form ref="formRef" class="user-layout-login" name="custom-validation" :model="formState" :rules="rules" v-bind="layout" @finish="handleFinish" @finishFailed="handleFinishFailed">
<a-form
ref="formRef"
class="user-layout-login"
name="custom-validation"
:model="formState"
:rules="rules"
v-bind="layout"
@finish="handleFinish"
@finish-failed="handleFinishFailed"
>
<!-- <div class="login-title">登录</div>-->
<a-tabs :active-key="formState.loginType" :tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
<a-tab-pane key="password" tab="用户名密码登录">
@@ -55,7 +64,13 @@
</a-input>
</a-col>
<a-col class="gutter-row" :span="8">
<a-button class="getCaptcha" tabindex="-1" :disabled="smsSendBtnDisabled" @click="sendSmsCode" v-text="smsTime <= 0 ? '发送' : smsTime + ' s'"></a-button>
<a-button
class="getCaptcha"
tabindex="-1"
:disabled="smsSendBtnDisabled"
@click="sendSmsCode"
v-text="smsTime <= 0 ? '发送' : smsTime + ' s'"
></a-button>
</a-col>
</a-row>
</a-form-item>
@@ -75,13 +90,13 @@
import { defineComponent, reactive, ref, toRaw, computed } from "vue";
import { useUserStore } from "/src/store/modules/user";
import { useSettingStore } from "/@/store/modules/settings";
import {utils} from "@fast-crud/fast-crud";
import { utils } from "@fast-crud/fast-crud";
export default defineComponent({
name: "LoginPage",
setup() {
const loading = ref(false);
const userStore = useUserStore();
const settingStore = useSettingStore()
const settingStore = useSettingStore();
const formRef = ref();
const formState = reactive({
username: "",
@@ -168,7 +183,7 @@ export default defineComponent({
function sendSmsCode() {
//api.sendSmsCode();
}
const sysPublicSettings = settingStore.getSysPublic
const sysPublicSettings = settingStore.getSysPublic;
return {
loading,
formState,
@@ -1,6 +1,16 @@
<template>
<div class="main">
<a-form ref="formRef" class="user-layout-register" name="custom-validation" :model="formState" :rules="rules" v-bind="layout" @finish="handleFinish" @finishFailed="handleFinishFailed">
<a-form
ref="formRef"
class="user-layout-register"
name="custom-validation"
:model="formState"
:rules="rules"
v-bind="layout"
:label-col="{ span: 5 }"
@finish="handleFinish"
@finish-failed="handleFinishFailed"
>
<a-tabs :tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
<a-tab-pane key="register" tab="用户注册"> </a-tab-pane>
</a-tabs>
@@ -39,7 +49,7 @@
<script lang="ts">
import { defineComponent, reactive, ref, toRaw } from "vue";
import { useUserStore } from "/src/store/modules/user";
import {utils} from "@fast-crud/fast-crud";
import { utils } from "@fast-crud/fast-crud";
export default defineComponent({
name: "RegisterPage",
setup() {
@@ -4,8 +4,7 @@ const apiPrefix = "/sys/settings";
export const SettingKeys = {
SysPublic: "sys.public",
SysPrivate: "sys.private",
SysPrivate: "sys.private"
};
export async function SettingsGet(key: string) {
return await request({
@@ -17,22 +16,28 @@ export async function SettingsGet(key: string) {
});
}
export async function SettingsSave(key: string,setting: any) {
export async function SettingsSave(key: string, setting: any) {
await request({
url: apiPrefix + "/save",
method: "post",
data: {
key,
setting: JSON.stringify(setting),
setting: JSON.stringify(setting)
}
});
}
export async function PublicSettingsSave(setting: any) {
await request({
url: apiPrefix + "/savePublicSettings",
method: "post",
data: setting
});
}
}
export async function stopOtherUserTimer() {
await request({
url: apiPrefix + "/stopOtherUserTimer",
method: "post"
});
}
@@ -4,14 +4,31 @@
<div class="title">系统设置</div>
</template>
<div class="sys-settings-form">
<a-form :model="formState" name="basic" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" autocomplete="off" @finish="onFinish" @finish-failed="onFinishFailed">
<a-form
:model="formState"
name="basic"
:label-col="{ span: 8 }"
:wrapper-col="{ span: 16 }"
autocomplete="off"
@finish="onFinish"
@finish-failed="onFinishFailed"
>
<a-form-item label="开启自助注册" name="registerEnabled">
<a-switch v-model:checked="formState.registerEnabled" />
</a-form-item>
<a-form-item label="管理其他用户流水线" name="managerOtherUserPipeline">
<a-switch v-model:checked="formState.managerOtherUserPipeline" />
</a-form-item>
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
<a-button type="primary" html-type="submit">保存</a-button>
</a-form-item>
</a-form>
<!-- <a-descriptions label="系统维护操作">-->
<!-- <a-descriptions-item label="自动化任务">-->
<!-- <a-button @click="stopOtherUserTimer">停止所有其他用户的定时任务</a-button>-->
<!-- </a-descriptions-item>-->
<!-- </a-descriptions>-->
</div>
</fs-page>
</template>
@@ -25,11 +42,10 @@ import { useSettingStore } from "/@/store/modules/settings";
interface FormState {
registerEnabled: boolean;
}
const formState = reactive<Partial<FormState>>({
registerEnabled:false
registerEnabled: false
});
async function loadSysPublicSettings() {
@@ -39,11 +55,11 @@ async function loadSysPublicSettings() {
}
loadSysPublicSettings();
const settingsStore= useSettingStore()
const settingsStore = useSettingStore();
const onFinish = async (form: any) => {
console.log("Success:", form);
await api.PublicSettingsSave(form);
await settingsStore.loadSysSettings()
await settingsStore.loadSysSettings();
notification.success({
message: "保存成功"
});
@@ -53,6 +69,12 @@ const onFinishFailed = (errorInfo: any) => {
// console.log("Failed:", errorInfo);
};
async function stopOtherUserTimer() {
await api.stopOtherUserTimer();
notification.success({
message: "停止成功"
});
}
</script>
<style lang="less">