mirror of
https://github.com/certd/certd.git
synced 2026-04-24 04:17:25 +08:00
chore: 插件编辑器
This commit is contained in:
@@ -6,7 +6,7 @@ export async function GetList(query: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/page",
|
||||
method: "post",
|
||||
data: query
|
||||
data: query,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ export async function AddObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/add",
|
||||
method: "post",
|
||||
data: obj
|
||||
data: obj,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export async function UpdateObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/update",
|
||||
method: "post",
|
||||
data: obj
|
||||
data: obj,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ export async function DelObj(id: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/delete",
|
||||
method: "post",
|
||||
params: { id }
|
||||
params: { id },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ export async function GetObj(id: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/info",
|
||||
method: "post",
|
||||
params: { id }
|
||||
params: { id },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export async function GetDetail(id: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/detail",
|
||||
method: "post",
|
||||
params: { id }
|
||||
params: { id },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ export async function DeleteBatch(ids: any[]) {
|
||||
return await request({
|
||||
url: apiPrefix + "/deleteByIds",
|
||||
method: "post",
|
||||
data: { ids }
|
||||
data: { ids },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ export async function SetDisabled(data: { id?: number; name?: string; type?: str
|
||||
return await request({
|
||||
url: apiPrefix + "/setDisabled",
|
||||
method: "post",
|
||||
data: data
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ export type CommPluginConfig = {
|
||||
export async function GetCommPluginConfigs(): Promise<CommPluginConfig> {
|
||||
return await request({
|
||||
url: apiPrefix + "/getCommPluginConfigs",
|
||||
method: "post"
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -98,6 +98,6 @@ export async function SaveCommPluginConfigs(data: CommPluginConfig): Promise<voi
|
||||
return await request({
|
||||
url: apiPrefix + "/saveCommPluginConfigs",
|
||||
method: "post",
|
||||
data
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<div class="plugin-inputs">
|
||||
<div class="actions mb-1">
|
||||
<a-button type="primary" @click="addNewField"> 添加 </a-button>
|
||||
</div>
|
||||
|
||||
<div class="inputs">
|
||||
<div class="inputs-inner">
|
||||
<a-collapse v-model:active-key="activeKey">
|
||||
<a-collapse-panel v-for="(item, index) in inputs" :key="index">
|
||||
<template #header> {{ item.key }} : {{ item.title }} </template>
|
||||
<a-form :label-col="{ style: { width: '80px' } }">
|
||||
<a-form-item label="字段名称">
|
||||
<a-input v-model:value="item.key" />
|
||||
</a-form-item>
|
||||
<a-form-item label="字段标题">
|
||||
<a-input v-model:value="item.title" />
|
||||
</a-form-item>
|
||||
<a-form-item label="字段说明">
|
||||
<a-input v-model:value="item.helper" />
|
||||
</a-form-item>
|
||||
<a-form-item label="默认值">
|
||||
<a-input v-model:value="item.value" />
|
||||
</a-form-item>
|
||||
<a-form-item label="必填">
|
||||
<a-switch v-model:checked="item.required" />
|
||||
</a-form-item>
|
||||
<a-form-item label="组件配置">
|
||||
<fs-editor-code v-model:model-value="item.component" language="yaml" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, Ref } from "vue";
|
||||
|
||||
const activeKey = ref([]);
|
||||
const inputs: Ref = ref([]);
|
||||
|
||||
function addNewField() {
|
||||
inputs.value.push({
|
||||
key: "newInput",
|
||||
title: "新字段",
|
||||
component: `
|
||||
name: a-input
|
||||
|
||||
`,
|
||||
helper: "",
|
||||
value: undefined,
|
||||
required: false,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.plugin-inputs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
.actions {
|
||||
}
|
||||
.inputs {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
.inputs-inner {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -2,7 +2,7 @@ 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, dict, EditReq, UserPageQuery, UserPageRes, utils } from "@fast-crud/fast-crud";
|
||||
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes, utils } from "@fast-crud/fast-crud";
|
||||
import { useUserStore } from "/src/store/modules/user";
|
||||
import { useSettingStore } from "/src/store/modules/settings";
|
||||
import { Modal } from "ant-design-vue";
|
||||
@@ -59,29 +59,43 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
actionbar: {
|
||||
buttons: {
|
||||
add: {
|
||||
show: false,
|
||||
show: true,
|
||||
text: "自定义插件",
|
||||
},
|
||||
},
|
||||
},
|
||||
rowHandle: {
|
||||
show: false,
|
||||
show: true,
|
||||
minWidth: 200,
|
||||
fixed: "right",
|
||||
buttons: {
|
||||
edit: {
|
||||
show: false,
|
||||
show: compute(({ row }) => {
|
||||
return row.type === "custom";
|
||||
}),
|
||||
},
|
||||
copy: {
|
||||
show: false,
|
||||
show: compute(({ row }) => {
|
||||
return row.type === "custom";
|
||||
}),
|
||||
},
|
||||
remove: {
|
||||
show: false,
|
||||
show: compute(({ row }) => {
|
||||
return row.type === "custom";
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
table: {
|
||||
rowKey: "name",
|
||||
},
|
||||
tabs: {
|
||||
name: "type",
|
||||
show: true,
|
||||
defaultOption: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
// id: {
|
||||
// title: "ID",
|
||||
@@ -101,20 +115,47 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
show: true,
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
show: true,
|
||||
order: 0,
|
||||
helper: "必须为英文,驼峰命名,类型作为前缀\n例如AliyunDeployToCDN",
|
||||
rules: [{ required: true }],
|
||||
},
|
||||
column: {
|
||||
width: 250,
|
||||
cellRender({ row }) {
|
||||
if (row.author) {
|
||||
return <fs-copyable model-value={`${row.author}/${row.name}`} />;
|
||||
} else {
|
||||
return <fs-copyable model-value={row.name} />;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
author: {
|
||||
title: "作者",
|
||||
type: "text",
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
form: {
|
||||
show: true,
|
||||
order: 0,
|
||||
helper: "上传到应用商店时,将作为插件名称前缀,例如:greper/pluginName",
|
||||
rules: [{ required: true }],
|
||||
},
|
||||
column: {
|
||||
width: 200,
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
icon: {
|
||||
title: "图标",
|
||||
type: "text",
|
||||
type: "icon",
|
||||
form: {
|
||||
show: false,
|
||||
rules: [{ required: true }],
|
||||
},
|
||||
column: {
|
||||
width: 100,
|
||||
width: 70,
|
||||
align: "center",
|
||||
component: {
|
||||
name: "fs-icon",
|
||||
@@ -125,26 +166,102 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
title: {
|
||||
title: "标题",
|
||||
type: "text",
|
||||
form: {
|
||||
order: 0,
|
||||
helper: "插件中文名称",
|
||||
rules: [{ required: true }],
|
||||
},
|
||||
column: {
|
||||
width: 300,
|
||||
cellRender({ row }) {
|
||||
if (row.type === "custom") {
|
||||
return <router-link to={`/sys/plugin/edit?id=${row.id}`}>{row.title}</router-link>;
|
||||
}
|
||||
return <div>{row.title}</div>;
|
||||
},
|
||||
},
|
||||
},
|
||||
desc: {
|
||||
title: "描述",
|
||||
type: "text",
|
||||
helper: "插件的描述",
|
||||
column: {
|
||||
width: 300,
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
type: {
|
||||
title: "来源",
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
form: {
|
||||
value: "custom",
|
||||
component: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "内置", value: "builtIn" },
|
||||
{ label: "自建", value: "custom" },
|
||||
{ label: "商店", value: "store" },
|
||||
],
|
||||
}),
|
||||
column: {
|
||||
width: 70,
|
||||
align: "center",
|
||||
component: {
|
||||
color: "auto",
|
||||
},
|
||||
},
|
||||
},
|
||||
pluginType: {
|
||||
title: "插件类型",
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
form: {
|
||||
rules: [{ required: true }],
|
||||
},
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "授权", value: "access" },
|
||||
{ label: "DNS", value: "dnsProvider" },
|
||||
{ label: "部署插件", value: "plugin" },
|
||||
],
|
||||
}),
|
||||
column: {
|
||||
width: 100,
|
||||
align: "center",
|
||||
component: {
|
||||
color: "auto",
|
||||
},
|
||||
},
|
||||
},
|
||||
group: {
|
||||
title: "分组",
|
||||
type: "text",
|
||||
type: "dict-select",
|
||||
dict: dict({
|
||||
url: "/pi/plugin/groupsList",
|
||||
label: "title",
|
||||
value: "key",
|
||||
}),
|
||||
form: {
|
||||
rules: [{ required: true }],
|
||||
},
|
||||
column: {
|
||||
width: 100,
|
||||
align: "center",
|
||||
align: "left",
|
||||
component: {
|
||||
color: "auto",
|
||||
},
|
||||
},
|
||||
},
|
||||
disabled: {
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<fs-page class="page-plugin-edit">
|
||||
<template #header>
|
||||
<div class="title">
|
||||
插件编辑
|
||||
<span class="sub">
|
||||
<span class="name">{{ plugin.title }} 【{{ plugin.author }}/{{ plugin.name }}】 </span>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="pi-plugin-editor">
|
||||
<div class="metadata">
|
||||
<a-tabs v-model:active-key="metadataActive" type="card">
|
||||
<a-tab-pane key="editor" tab="元数据"> </a-tab-pane>
|
||||
<a-tab-pane key="source" tab="yaml"> </a-tab-pane>
|
||||
</a-tabs>
|
||||
<div class="metadata-body">
|
||||
<a-tabs v-if="metadataActive === 'editor'" class="metadata-editor" tab-position="left" type="card">
|
||||
<a-tab-pane key="input" tab="输入">
|
||||
<plugin-input></plugin-input>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="output" tab="输出"></a-tab-pane>
|
||||
<a-tab-pane key="dependLibs" tab="第三方依赖"></a-tab-pane>
|
||||
<a-tab-pane key="dependPlugins" tab="插件依赖"></a-tab-pane>
|
||||
</a-tabs>
|
||||
|
||||
<div v-if="metadataActive === 'source'" class="metadata-source">
|
||||
<fs-editor-code v-model="plugin.metadata" language="yaml"></fs-editor-code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="script">
|
||||
<a-tabs type="card">
|
||||
<a-tab-pane key="script" tab="脚本"> </a-tab-pane>
|
||||
</a-tabs>
|
||||
<fs-editor-code v-model="plugin.content" language="javascript"></fs-editor-code>
|
||||
</div>
|
||||
</div>
|
||||
</fs-page>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import * as api from "./api";
|
||||
import PluginInput from "/@/views/sys/plugin/components/plugin-input.vue";
|
||||
defineOptions({
|
||||
name: "SysPluginEdit",
|
||||
});
|
||||
const route = useRoute();
|
||||
|
||||
const plugin = ref<any>({});
|
||||
|
||||
const metadataActive = ref("editor");
|
||||
async function getPlugin() {
|
||||
const id = route.query.id;
|
||||
plugin.value = await api.GetObj(id);
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await getPlugin();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.page-plugin-edit {
|
||||
.pi-plugin-editor {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
.fs-editor-code {
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.metadata {
|
||||
width: 500px;
|
||||
margin-right: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
.metadata-body {
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.metadata-editor {
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
overflow-y: hidden;
|
||||
.ant-tabs-content {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.metadata-source {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.script {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user