perf: 通知管理

This commit is contained in:
xiaojunnuo
2024-11-22 17:12:39 +08:00
parent 131ed13df1
commit d9a00eeaf7
30 changed files with 1031 additions and 30 deletions
@@ -49,6 +49,17 @@ export const certdResources = [
cache: true
}
},
{
title: "通知设置",
name: "NotificationManager",
path: "/certd/notification",
component: "/certd/notification/index.vue",
meta: {
icon: "ion:disc-outline",
auth: true,
cache: true
}
},
{
title: "CNAME记录管理",
name: "CnameRecord",
@@ -115,7 +115,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
}
},
cnameProviderId: {
title: "CNAME提供者",
title: "CNAME服务",
type: "dict-select",
dict: dict({
url: "/cname/provider/list",
@@ -0,0 +1,70 @@
import { request } from "/src/api/service";
export function createApi() {
const apiPrefix = "/pi/notification";
return {
async GetList(query: any) {
return await request({
url: apiPrefix + "/page",
method: "post",
data: query
});
},
async AddObj(obj: any) {
return await request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
},
async UpdateObj(obj: any) {
return await request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
},
async DelObj(id: number) {
return await request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
},
async GetObj(id: number) {
return await request({
url: apiPrefix + "/info",
method: "post",
params: { id }
});
},
async GetSimpleInfo(id: number) {
return await request({
url: apiPrefix + "/simpleInfo",
method: "post",
params: { id }
});
},
async GetProviderDefine(type: string) {
return await request({
url: apiPrefix + "/define",
method: "post",
params: { type }
});
},
async GetProviderDefineByType(type: string) {
return await request({
url: apiPrefix + "/defineByType",
method: "post",
params: { type }
});
}
};
}
@@ -0,0 +1,147 @@
import { ColumnCompositionProps, dict } from "@fast-crud/fast-crud";
import { computed, provide, ref, toRef } from "vue";
import { useReference } from "/@/use/use-refrence";
import { forEach, get, merge, set } from "lodash-es";
export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
provide("notificationApi", api);
const notificationTypeDictRef = dict({
url: "/pi/notification/getTypeDict"
});
const defaultPluginConfig = {
component: {
name: "a-input",
vModel: "value"
}
};
function buildDefineFields(define: any, form: any, mode: string) {
const formWrapperRef = crudExpose.getFormWrapperRef();
const columnsRef = toRef(formWrapperRef.formOptions, "columns");
for (const key in columnsRef.value) {
if (key.indexOf(".") >= 0) {
delete columnsRef.value[key];
}
}
console.log('crudBinding.value[mode + "Form"].columns', columnsRef.value);
forEach(define.input, (value: any, mapKey: any) => {
const key = "body." + mapKey;
const field = {
...value,
key
};
const column = merge({ title: key }, defaultPluginConfig, field);
//eval
useReference(column);
//设置默认值
if (column.value != null && get(form, key) == null) {
set(form, key, column.value);
}
//字段配置赋值
columnsRef.value[key] = column;
console.log("form", columnsRef.value);
});
}
const currentDefine = ref();
return {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 100
},
form: {
show: false
}
},
name: {
title: "通知名称",
search: {
show: true
},
type: ["text"],
form: {
rules: [{ required: true, message: "请填写名称" }],
helper: "随便填,当多个相同类型的通知时,便于区分"
},
column: {
width: 200
}
},
type: {
title: "类型",
type: "dict-select",
dict: notificationTypeDictRef,
search: {
show: false
},
column: {
width: 200,
component: {
color: "auto"
}
},
form: {
component: {
disabled: false,
showSearch: true,
filterOption: (input: string, option: any) => {
input = input?.toLowerCase();
return option.value.toLowerCase().indexOf(input) >= 0 || option.label.toLowerCase().indexOf(input) >= 0;
}
},
rules: [{ required: true, message: "请选择类型" }],
valueChange: {
immediate: true,
async handle({ value, mode, form, immediate }) {
if (value == null) {
return;
}
const define = await api.GetProviderDefine(value);
currentDefine.value = define;
console.log("define", define);
if (!immediate) {
form.body = {};
}
buildDefineFields(define, form, mode);
}
},
helper: computed(() => {
const define = currentDefine.value;
if (define == null) {
return "";
}
return define.desc;
})
},
addForm: {
value: typeRef
}
} as ColumnCompositionProps,
setting: {
column: { show: false },
form: {
show: false,
valueBuilder({ value, form }) {
form.body = {};
if (!value) {
return;
}
const setting = JSON.parse(value);
for (const key in setting) {
form.body[key] = setting[key];
}
},
valueResolve({ form }) {
const setting = form.body;
form.setting = JSON.stringify(setting);
}
}
} as ColumnCompositionProps
};
}
@@ -0,0 +1,53 @@
// @ts-ignore
import { useI18n } from "vue-i18n";
import { ref } from "vue";
import { getCommonColumnDefine } from "./common";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { t } = useI18n();
const api = context.api;
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async (req: EditReq) => {
const { form, row } = req;
form.id = row.id;
const res = await api.UpdateObj(form);
return res;
};
const delRequest = async (req: DelReq) => {
const { row } = req;
return await api.DelObj(row.id);
};
const addRequest = async (req: AddReq) => {
const { form } = req;
const res = await api.AddObj(form);
return res;
};
const typeRef = ref();
const commonColumnsDefine = getCommonColumnDefine(crudExpose, typeRef, api);
return {
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
form: {
labelCol: {
span: 6
}
},
rowHandle: {
width: 200
},
columns: {
...commonColumnsDefine
}
}
};
}
@@ -0,0 +1,39 @@
<template>
<fs-page>
<template #header>
<div class="title">
通知管理
<span class="sub">管理通知配置</span>
</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
</fs-page>
</template>
<script lang="ts">
import { defineComponent, onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { createApi } from "./api";
export default defineComponent({
name: "NotificationManager",
setup() {
const api = createApi();
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { api } });
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
onActivated(() => {
crudExpose.doRefresh();
});
return {
crudBinding,
crudRef
};
}
});
</script>
@@ -0,0 +1,139 @@
<template>
<div class="notification-selector">
<span v-if="target.name" class="mr-5 cd-flex-inline">
<a-tag class="mr-5" color="green">{{ target.name }}</a-tag>
<fs-icon class="cd-icon-button" icon="ion:close-circle-outline" @click="clear"></fs-icon>
</span>
<span v-else class="mlr-5 text-gray">{{ placeholder }}</span>
<a-button class="ml-5" :size="size" @click="chooseForm.open">选择</a-button>
<a-form-item-rest v-if="chooseForm.show">
<a-modal v-model:open="chooseForm.show" title="选择通知" width="900px" @ok="chooseForm.ok">
<div style="height: 400px; position: relative">
<cert-notification-modal v-model="selectedId" :type="type" :from="from"></cert-notification-modal>
</div>
</a-modal>
</a-form-item-rest>
</div>
</template>
<script>
import { defineComponent, reactive, ref, watch, inject } from "vue";
import CertNotificationModal from "./modal/index.vue";
import { createApi } from "../api";
import { message } from "ant-design-vue";
export default defineComponent({
name: "NotificationSelector",
components: { CertNotificationModal },
props: {
modelValue: {
type: [Number, String],
default: null
},
type: {
type: String,
default: ""
},
placeholder: {
type: String,
default: "请选择"
},
size: {
type: String,
default: "middle"
}
},
emits: ["update:modelValue"],
setup(props, ctx) {
const api = createApi();
const target = ref({});
const selectedId = ref();
async function refreshTarget(value) {
selectedId.value = value;
if (value > 0) {
target.value = await api.GetSimpleInfo(value);
}
}
function clear() {
if (pipeline && pipeline.userId !== target.value.userId) {
message.error("对不起,您不能修改他人流水线的通知");
return;
}
selectedId.value = "";
target.value = null;
ctx.emit("update:modelValue", selectedId.value);
}
watch(
() => {
return props.modelValue;
},
async (value) => {
selectedId.value = null;
target.value = {};
if (value == null) {
return;
}
await refreshTarget(value);
},
{
immediate: true
}
);
const providerDefine = ref({});
async function refreshProviderDefine(type) {
providerDefine.value = await api.GetProviderDefine(type);
}
watch(
() => {
return props.type;
},
async (value) => {
await refreshProviderDefine(value);
},
{
immediate: true
}
);
//当不在pipeline中编辑时,可能为空
const pipeline = inject("pipeline", null);
const chooseForm = reactive({
show: false,
open() {
chooseForm.show = true;
},
ok: () => {
chooseForm.show = false;
console.log("choose ok:", selectedId.value);
refreshTarget(selectedId.value);
if (pipeline && pipeline.userId !== target.value.userId) {
message.error("对不起,您不能修改他人流水线的授权");
return;
}
ctx.emit("change", selectedId.value);
ctx.emit("update:modelValue", selectedId.value);
}
});
return {
clear,
target,
selectedId,
providerDefine,
chooseForm
};
}
});
</script>
<style lang="less">
.notification-selector {
}
</style>
@@ -0,0 +1,90 @@
// @ts-ignore
import { ref } from "vue";
import { getCommonColumnDefine } from "../../common";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { crudBinding } = crudExpose;
const { props, ctx, api } = context;
const lastResRef = ref();
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await context.api.GetList(query);
};
const editRequest = async (req: EditReq) => {
const { form, row } = req;
form.id = row.id;
form.type = props.type;
const res = await context.api.UpdateObj(form);
lastResRef.value = res;
return res;
};
const delRequest = async (req: DelReq) => {
const { row } = req;
return await context.api.DelObj(row.id);
};
const addRequest = async (req: AddReq) => {
const { form } = req;
form.type = props.type;
const res = await context.api.AddObj(form);
lastResRef.value = res;
return res;
};
const selectedRowKey = ref([props.modelValue]);
const onSelectChange = (changed: any) => {
selectedRowKey.value = changed;
ctx.emit("update:modelValue", changed[0]);
};
const typeRef = ref("");
context.typeRef = typeRef;
const commonColumnsDefine = getCommonColumnDefine(crudExpose, typeRef, api);
commonColumnsDefine.type.form.component.disabled = true;
return {
typeRef,
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
toolbar: {
show: false
},
search: {
show: false
},
form: {
wrapper: {
width: "1050px"
}
},
rowHandle: {
width: 200
},
table: {
scroll: {
x: 800
},
rowSelection: {
type: "radio",
selectedRowKeys: selectedRowKey,
onChange: onSelectChange
},
customRow: (record: any) => {
return {
onClick: () => {
onSelectChange([record.id]);
} // 点击行
};
}
},
columns: {
...commonColumnsDefine
}
}
};
}
@@ -0,0 +1,58 @@
<template>
<fs-page class="page-cert-notification-modal">
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
</fs-page>
</template>
<script lang="ts">
import { defineComponent, onMounted, watch } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { createApi } from "../../api";
export default defineComponent({
name: "CertNotificationModal",
props: {
type: {
type: String,
default: ""
},
modelValue: {}
},
emits: ["update:modelValue"],
setup(props, ctx) {
const api = createApi();
const context: any = { props, ctx, api };
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
// 你可以调用此方法,重新初始化crud配置
function onTypeChanged(value: any) {
context.typeRef.value = value;
crudExpose.setSearchFormData({ form: { type: value }, mergeForm: true });
crudExpose.doRefresh();
}
watch(
() => {
return props.type;
},
(value) => {
console.log("access type changed:", value);
onTypeChanged(value);
}
);
// 页面打开后获取列表数据
onMounted(() => {
onTypeChanged(props.type);
});
return {
crudBinding,
crudRef
};
}
});
</script>
<style lang="less">
.page-cert-notification {
}
</style>