mirror of
https://github.com/certd/certd.git
synced 2026-05-16 05:07:32 +08:00
feat: 域名验证方法支持CNAME间接方式,此方式支持所有域名注册商,且无需提供Access授权,但是需要手动添加cname解析
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="pi-access-selector">
|
||||
<div class="access-selector">
|
||||
<span v-if="target.name" class="mr-5 cd-flex-inline">
|
||||
<span class="mr-5">{{ target.name }}</span>
|
||||
<fs-icon class="cd-icon-button" icon="ion:close-circle-outline" @click="clear"></fs-icon>
|
||||
</span>
|
||||
<span v-else class="mlr-5 gray">请选择</span>
|
||||
<a-button class="ml-5" @click="chooseForm.open">选择</a-button>
|
||||
<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">
|
||||
@@ -23,7 +23,7 @@ import CertAccessModal from "./access/index.vue";
|
||||
import { GetProviderDefineByAccessType } from "../api";
|
||||
|
||||
export default defineComponent({
|
||||
name: "PiAccessSelector",
|
||||
name: "AccessSelector",
|
||||
components: { CertAccessModal },
|
||||
props: {
|
||||
modelValue: {
|
||||
@@ -33,6 +33,14 @@ export default defineComponent({
|
||||
type: {
|
||||
type: String,
|
||||
default: "aliyun"
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "请选择"
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: "middle"
|
||||
}
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
|
||||
@@ -16,7 +16,7 @@ import { useFs } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud";
|
||||
|
||||
export default defineComponent({
|
||||
name: "CertdAccess",
|
||||
name: "AccessManager",
|
||||
setup() {
|
||||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {} });
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import { request } from "/src/api/service";
|
||||
|
||||
const apiPrefix = "/cname/record";
|
||||
|
||||
export async function GetList(query: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/page",
|
||||
method: "post",
|
||||
data: query
|
||||
});
|
||||
}
|
||||
|
||||
export async function AddObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/add",
|
||||
method: "post",
|
||||
data: obj
|
||||
});
|
||||
}
|
||||
|
||||
export async function UpdateObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/update",
|
||||
method: "post",
|
||||
data: obj
|
||||
});
|
||||
}
|
||||
|
||||
export async function DelObj(id: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/delete",
|
||||
method: "post",
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
export async function GetObj(id: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/info",
|
||||
method: "post",
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
export async function GetDetail(id: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/detail",
|
||||
method: "post",
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
export async function DeleteBatch(ids: any[]) {
|
||||
return await request({
|
||||
url: apiPrefix + "/deleteByIds",
|
||||
method: "post",
|
||||
data: { ids }
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
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 { 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
|
||||
},
|
||||
rowHandle: {
|
||||
minWidth: 200,
|
||||
fixed: "right"
|
||||
},
|
||||
columns: {
|
||||
id: {
|
||||
title: "ID",
|
||||
key: "id",
|
||||
type: "number",
|
||||
column: {
|
||||
width: 100
|
||||
},
|
||||
form: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
domain: {
|
||||
title: "被代理域名",
|
||||
type: "text",
|
||||
search: {
|
||||
show: true
|
||||
},
|
||||
editForm: {
|
||||
component: {
|
||||
disabled: true
|
||||
}
|
||||
}
|
||||
},
|
||||
hostRecord: {
|
||||
title: "主机记录",
|
||||
type: "text",
|
||||
form: {
|
||||
show: false
|
||||
},
|
||||
column: {
|
||||
width: 250,
|
||||
cellRender: ({ value }) => {
|
||||
return <fs-copyable v-model={value} />;
|
||||
}
|
||||
}
|
||||
},
|
||||
recordValue: {
|
||||
title: "请设置CNAME",
|
||||
type: "copyable",
|
||||
form: {
|
||||
show: false
|
||||
},
|
||||
column: {
|
||||
width: 500
|
||||
}
|
||||
},
|
||||
cnameProviderId: {
|
||||
title: "CNAME提供者",
|
||||
type: "dict-select",
|
||||
dict: dict({
|
||||
url: "/cname/provider/list",
|
||||
value: "id",
|
||||
label: "domain"
|
||||
}),
|
||||
form: {
|
||||
component: {
|
||||
onDictChange: ({ form, dict }) => {
|
||||
if (!form.cnameProviderId) {
|
||||
const item = dict.data.find((item) => item.isDefault);
|
||||
if (item) {
|
||||
form.cnameProviderId = item.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
column: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
status: {
|
||||
title: "状态",
|
||||
type: "dict-select",
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "待设置CNAME", value: "cname", color: "warning" },
|
||||
{ label: "验证中", value: "validating", color: "primary" },
|
||||
{ label: "验证成功", value: "valid", color: "success" },
|
||||
{ label: "验证失败", value: "failed", color: "error" }
|
||||
]
|
||||
}),
|
||||
addForm: {
|
||||
show: false
|
||||
},
|
||||
column: {
|
||||
width: 120,
|
||||
align: "center"
|
||||
}
|
||||
},
|
||||
triggerValidate: {
|
||||
title: "验证",
|
||||
type: "text",
|
||||
form: {
|
||||
show: false
|
||||
},
|
||||
column: {
|
||||
conditionalRenderDisabled: true,
|
||||
width: 100,
|
||||
align: "center",
|
||||
cellRender({ row, value }) {
|
||||
if (row.status === "valid") {
|
||||
return "-";
|
||||
}
|
||||
return (
|
||||
<a-button size={"small"} type={"primary"}>
|
||||
点击验证
|
||||
</a-button>
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
createTime: {
|
||||
title: "创建时间",
|
||||
type: "datetime",
|
||||
form: {
|
||||
show: false
|
||||
},
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 160,
|
||||
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">CNAME记录管理</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: "CnameRecord"
|
||||
});
|
||||
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>
|
||||
@@ -23,6 +23,10 @@ import { Ref, ref } from "vue";
|
||||
import { CrudOptions, useColumns, useFormWrapper } from "@fast-crud/fast-crud";
|
||||
import { notification } from "ant-design-vue";
|
||||
|
||||
defineOptions({
|
||||
name: "UserProfile"
|
||||
});
|
||||
|
||||
const userInfo: Ref = ref({});
|
||||
|
||||
const getUserInfo = async () => {
|
||||
|
||||
@@ -3,10 +3,12 @@ import { PluginGroup } from "@certd/pipeline";
|
||||
import { useReference } from "/@/use/use-refrence";
|
||||
import _ from "lodash-es";
|
||||
import { useUserStore } from "/@/store/modules/user";
|
||||
import { useSettingStore } from "/@/store/modules/settings";
|
||||
|
||||
export default function (certPluginGroup: PluginGroup, formWrapperRef: any): CreateCrudOptionsRet {
|
||||
const inputs: any = {};
|
||||
const userStore = useUserStore();
|
||||
const settingStore = useSettingStore();
|
||||
for (const plugin of certPluginGroup.plugins) {
|
||||
for (const inputKey in plugin.input) {
|
||||
if (inputs[inputKey]) {
|
||||
@@ -66,8 +68,8 @@ export default function (certPluginGroup: PluginGroup, formWrapperRef: any): Cre
|
||||
render: () => {
|
||||
return (
|
||||
<ul>
|
||||
<li>JS-ACME:如果你的域名DNS属于阿里云、腾讯云、Cloudflare、西部数码可以选择用它来申请</li>
|
||||
<li>Lego-ACME:基于Lego实现,支持海量DNS提供商,熟悉LEGO的用户可以使用</li>
|
||||
<li>JS-ACME:使用简单方便,功能强大【推荐】</li>
|
||||
<li>Lego-ACME:基于Lego实现,支持海量DNS提供商,熟悉LEGO的用户可以使用【即将废弃】</li>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -313,6 +313,9 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
||||
name: "a-input"
|
||||
}
|
||||
},
|
||||
form: {
|
||||
rules: [{ required: true, message: "此项必填" }]
|
||||
},
|
||||
column: {
|
||||
width: 350,
|
||||
sorter: true,
|
||||
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
<template>
|
||||
<a-select class="pi-output-selector" :value="modelValue" :options="options" @update:value="onChanged"> </a-select>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { inject, onMounted, Ref, ref, watch } from "vue";
|
||||
import { pluginManager } from "../../plugin";
|
||||
|
||||
export default {
|
||||
name: "PiOutputSelector",
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
from: {
|
||||
type: [String, Array]
|
||||
}
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
setup(props: any, ctx: any) {
|
||||
const options = ref<any[]>([]);
|
||||
|
||||
const pipeline = inject("pipeline") as Ref<any>;
|
||||
const currentStageIndex = inject("currentStageIndex") as Ref<number>;
|
||||
const currentStepIndex = inject("currentStepIndex") as Ref<number>;
|
||||
const currentTask = inject("currentTask") as Ref<any>;
|
||||
|
||||
const getPluginGroups = inject("getPluginGroups") as any;
|
||||
const pluginGroups = getPluginGroups();
|
||||
function onCreate() {
|
||||
options.value = pluginGroups.getPreStepOutputOptions({
|
||||
pipeline: pipeline.value,
|
||||
currentStageIndex: currentStageIndex.value,
|
||||
currentStepIndex: currentStepIndex.value,
|
||||
currentTask: currentTask.value
|
||||
});
|
||||
if (props.from) {
|
||||
if (typeof props.from === "string") {
|
||||
options.value = options.value.filter((item: any) => item.type === props.from);
|
||||
} else {
|
||||
options.value = options.value.filter((item: any) => props.from.includes(item.type));
|
||||
}
|
||||
}
|
||||
if (props.modelValue == null && options.value.length > 0) {
|
||||
ctx.emit("update:modelValue", options.value[0].value);
|
||||
}
|
||||
}
|
||||
onMounted(() => {
|
||||
onCreate();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => {
|
||||
return pluginGroups.value?.map;
|
||||
},
|
||||
() => {
|
||||
onCreate();
|
||||
}
|
||||
);
|
||||
|
||||
function onChanged(value: any) {
|
||||
ctx.emit("update:modelValue", value);
|
||||
}
|
||||
return {
|
||||
options,
|
||||
onChanged
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less"></style>
|
||||
+29
-21
@@ -73,27 +73,28 @@
|
||||
<a-alert type="info" :message="currentPlugin.title" :description="currentPlugin.desc"> </a-alert>
|
||||
</div>
|
||||
</template>
|
||||
<a-form ref="stepFormRef" class="step-form" :model="currentStep" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<fs-form-item
|
||||
v-model="currentStep.title"
|
||||
:item="{
|
||||
title: '任务名称',
|
||||
key: 'title',
|
||||
component: {
|
||||
name: 'a-input',
|
||||
vModel: 'value'
|
||||
},
|
||||
rules: [{ required: true, message: '此项必填' }]
|
||||
}"
|
||||
:get-context-fn="blankFn"
|
||||
/>
|
||||
<template v-for="(item, key) in currentPlugin.input" :key="key">
|
||||
<fs-form-item v-if="item.show !== false" v-model="currentStep.input[key]" :item="item" :get-context-fn="blankFn" />
|
||||
</template>
|
||||
|
||||
<fs-form-item v-model="currentStep.strategy.runStrategy" :item="runStrategyProps" :get-context-fn="blankFn" />
|
||||
</a-form>
|
||||
<div class="w-100 h-100">
|
||||
<a-form ref="stepFormRef" class="step-form" :model="currentStep" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<fs-form-item
|
||||
v-model="currentStep.title"
|
||||
:item="{
|
||||
title: '任务名称',
|
||||
key: 'title',
|
||||
component: {
|
||||
name: 'a-input',
|
||||
vModel: 'value'
|
||||
},
|
||||
rules: [{ required: true, message: '此项必填' }]
|
||||
}"
|
||||
:get-context-fn="blankFn"
|
||||
/>
|
||||
<template v-for="(item, key) in currentPlugin.input" :key="key">
|
||||
<fs-form-item v-if="item.show !== false" v-model="currentStep.input[key]" :item="item" :get-context-fn="blankFn" />
|
||||
</template>
|
||||
|
||||
<fs-form-item v-model="currentStep.strategy.runStrategy" :item="runStrategyProps" :get-context-fn="blankFn" />
|
||||
</a-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div v-if="editMode" class="bottom-button">
|
||||
<a-button type="primary" @click="stepSave"> 确定 </a-button>
|
||||
@@ -394,17 +395,24 @@ export default {
|
||||
&.fullscreen {
|
||||
.pi-step-form {
|
||||
.body {
|
||||
margin: auto;
|
||||
.step-plugin {
|
||||
width: 16.666666%;
|
||||
}
|
||||
.step-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 1300px;
|
||||
.fs-form-item {
|
||||
width: 50%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.footer {
|
||||
.bottom-button {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<template #header>
|
||||
<div class="title">
|
||||
<fs-button class="back" icon="ion:chevron-back-outline" @click="goBack"></fs-button>
|
||||
<pi-editable v-model="pipeline.title" :hover-show="false" :disabled="!editMode"></pi-editable>
|
||||
<text-editable v-model="pipeline.title" :hover-show="false" :disabled="!editMode"></text-editable>
|
||||
</div>
|
||||
<div class="more">
|
||||
<template v-if="editMode">
|
||||
@@ -24,7 +24,7 @@
|
||||
<template #header>
|
||||
<div class="stage first-stage">
|
||||
<div class="title stage-move-handle">
|
||||
<pi-editable model-value="触发源" :disabled="true" />
|
||||
<text-editable model-value="触发源" :disabled="true" />
|
||||
</div>
|
||||
<div class="tasks">
|
||||
<div class="task-container first-task">
|
||||
@@ -68,7 +68,7 @@
|
||||
<template #item="{ element: stage, index }">
|
||||
<div :key="stage.id" class="stage" :class="{ 'last-stage': isLastStage(index) }">
|
||||
<div class="title">
|
||||
<pi-editable v-model="stage.title" :disabled="!editMode"></pi-editable>
|
||||
<text-editable v-model="stage.title" :disabled="!editMode"></text-editable>
|
||||
<div v-plus class="icon-box stage-move-handle">
|
||||
<fs-icon v-if="editMode" title="拖动排序" icon="ion:move-outline"></fs-icon>
|
||||
</div>
|
||||
@@ -146,7 +146,7 @@
|
||||
<template #footer>
|
||||
<div v-if="editMode" class="stage last-stage">
|
||||
<div class="title">
|
||||
<pi-editable model-value="新阶段" :disabled="true" />
|
||||
<text-editable model-value="新阶段" :disabled="true" />
|
||||
</div>
|
||||
<div class="tasks">
|
||||
<div class="task-container first-task">
|
||||
@@ -188,7 +188,7 @@
|
||||
</div>
|
||||
<div v-else class="stage last-stage">
|
||||
<div class="title">
|
||||
<pi-editable model-value="结束" :disabled="true" />
|
||||
<text-editable model-value="结束" :disabled="true" />
|
||||
</div>
|
||||
<div v-if="pipeline.notifications?.length > 0" class="tasks">
|
||||
<div v-for="(item, index) of pipeline.notifications" :key="index" class="task-container" :class="{ 'first-task': index == 0 }">
|
||||
@@ -704,7 +704,7 @@ export default defineComponent({
|
||||
.back {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.pi-editable {
|
||||
.text-editable {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,12 +79,15 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive } from "vue";
|
||||
import * as api from "./api";
|
||||
import * as emailApi from "./api.email";
|
||||
|
||||
import { SettingKeys } from "./api";
|
||||
import * as emailApi from "./api.email";
|
||||
import { notification } from "ant-design-vue";
|
||||
import { useSettingStore } from "/@/store/modules/settings";
|
||||
|
||||
defineOptions({
|
||||
name: "EmailSetting"
|
||||
});
|
||||
|
||||
interface FormState {
|
||||
host: string;
|
||||
port: number;
|
||||
|
||||
@@ -18,6 +18,10 @@ import { useUserStore } from "/@/store/modules/user";
|
||||
import { useSettingStore } from "/@/store/modules/settings";
|
||||
import * as api from "./api";
|
||||
import { notification } from "ant-design-vue";
|
||||
|
||||
defineOptions({
|
||||
name: "AccountBind"
|
||||
});
|
||||
const iframeRef = ref();
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
@@ -29,7 +29,7 @@ import { usePermission } from "/src/plugin/permission";
|
||||
import { useFs, useUi } from "@fast-crud/fast-crud";
|
||||
|
||||
export default defineComponent({
|
||||
name: "AuthorityPermission",
|
||||
name: "AuthorityManager",
|
||||
components: { FsPermissionTree },
|
||||
setup() {
|
||||
// 此处传入permission进行通用按钮权限设置,会通过commonOptions去设置actionbar和rowHandle的按钮的show属性
|
||||
|
||||
@@ -5,7 +5,15 @@
|
||||
</template>
|
||||
<fs-crud ref="crudRef" v-bind="crudBinding" />
|
||||
<a-modal v-model:open="authzDialogVisible" width="860px" title="分配权限" @ok="updatePermission">
|
||||
<fs-permission-tree ref="permissionTreeRef" v-model:checkedKeys="checkedKeys" :tree="permissionTreeData" :editable="false" checkable :replace-fields="{ key: 'id', label: 'title' }"> </fs-permission-tree>
|
||||
<fs-permission-tree
|
||||
ref="permissionTreeRef"
|
||||
v-model:checked-keys="checkedKeys"
|
||||
:tree="permissionTreeData"
|
||||
:editable="false"
|
||||
checkable
|
||||
:replace-fields="{ key: 'id', label: 'title' }"
|
||||
>
|
||||
</fs-permission-tree>
|
||||
</a-modal>
|
||||
</fs-page>
|
||||
</template>
|
||||
@@ -84,7 +92,7 @@ function useAuthz() {
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: "AuthorityRole",
|
||||
name: "RoleManager",
|
||||
components: { FsPermissionTree },
|
||||
setup() {
|
||||
//授权配置
|
||||
|
||||
@@ -12,7 +12,7 @@ import { defineComponent, ref, onMounted } from "vue";
|
||||
import { useCrud, useExpose, useFs } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud";
|
||||
export default defineComponent({
|
||||
name: "AuthorityUser",
|
||||
name: "UserManager",
|
||||
setup() {
|
||||
// 初始化crud配置
|
||||
// 此处传入权限前缀进行通用按钮权限设置,会通过commonOptions去设置actionbar和rowHandle的按钮的show属性
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import { request } from "/src/api/service";
|
||||
|
||||
const apiPrefix = "/sys/cname/provider";
|
||||
|
||||
export async function GetList(query: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/page",
|
||||
method: "post",
|
||||
data: query
|
||||
});
|
||||
}
|
||||
|
||||
export async function AddObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/add",
|
||||
method: "post",
|
||||
data: obj
|
||||
});
|
||||
}
|
||||
|
||||
export async function UpdateObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/update",
|
||||
method: "post",
|
||||
data: obj
|
||||
});
|
||||
}
|
||||
|
||||
export async function DelObj(id: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/delete",
|
||||
method: "post",
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
export async function GetObj(id: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/info",
|
||||
method: "post",
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
export async function GetDetail(id: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/detail",
|
||||
method: "post",
|
||||
params: { id }
|
||||
});
|
||||
}
|
||||
|
||||
export async function DeleteBatch(ids: any[]) {
|
||||
return await request({
|
||||
url: apiPrefix + "/deleteByIds",
|
||||
method: "post",
|
||||
data: { ids }
|
||||
});
|
||||
}
|
||||
|
||||
export async function SetDefault(id: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/setDefault",
|
||||
method: "post",
|
||||
data: { id }
|
||||
});
|
||||
}
|
||||
|
||||
export async function SetDisabled(id: any, disabled: boolean) {
|
||||
return await request({
|
||||
url: apiPrefix + "/setDisabled",
|
||||
method: "post",
|
||||
data: { id, disabled }
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
import * as api from "./api";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { computed, Ref, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes, utils } from "@fast-crud/fast-crud";
|
||||
import { useUserStore } from "/@/store/modules/user";
|
||||
import { useSettingStore } from "/@/store/modules/settings";
|
||||
import { Modal } from "ant-design-vue";
|
||||
|
||||
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
|
||||
},
|
||||
rowHandle: {
|
||||
minWidth: 200,
|
||||
fixed: "right"
|
||||
},
|
||||
columns: {
|
||||
id: {
|
||||
title: "ID",
|
||||
key: "id",
|
||||
type: "number",
|
||||
column: {
|
||||
width: 100
|
||||
},
|
||||
form: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
domain: {
|
||||
title: "域名",
|
||||
type: "text",
|
||||
editForm: {
|
||||
component: {
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
form: {
|
||||
helper: "CNAME域名一旦确定不可修改",
|
||||
rules: [{ required: true, message: "此项必填" }]
|
||||
},
|
||||
column: {
|
||||
width: 200
|
||||
}
|
||||
},
|
||||
dnsProviderType: {
|
||||
title: "DNS提供商",
|
||||
type: "dict-select",
|
||||
dict: dict({
|
||||
url: "pi/dnsProvider/list",
|
||||
value: "key",
|
||||
label: "title"
|
||||
}),
|
||||
form: {
|
||||
rules: [{ required: true, message: "此项必填" }]
|
||||
},
|
||||
column: {
|
||||
width: 150,
|
||||
component: {
|
||||
color: "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
accessId: {
|
||||
title: "DNS提供商授权",
|
||||
type: "dict-select",
|
||||
dict: dict({
|
||||
url: "/pi/access/list",
|
||||
value: "id",
|
||||
label: "name"
|
||||
}),
|
||||
form: {
|
||||
component: {
|
||||
name: "access-selector",
|
||||
vModel: "modelValue",
|
||||
type: compute(({ form }) => {
|
||||
return form.dnsProviderType;
|
||||
})
|
||||
},
|
||||
rules: [{ required: true, message: "此项必填" }]
|
||||
},
|
||||
column: {
|
||||
width: 150,
|
||||
component: {
|
||||
color: "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
isDefault: {
|
||||
title: "是否默认",
|
||||
type: "dict-switch",
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "是", value: true, color: "success" },
|
||||
{ label: "否", value: false, color: "default" }
|
||||
]
|
||||
}),
|
||||
form: {
|
||||
value: false,
|
||||
rules: [{ required: true, message: "请选择是否默认" }]
|
||||
},
|
||||
column: {
|
||||
align: "center",
|
||||
width: 100
|
||||
}
|
||||
},
|
||||
setDefault: {
|
||||
title: "设置默认",
|
||||
type: "text",
|
||||
form: {
|
||||
show: false
|
||||
},
|
||||
column: {
|
||||
width: 100,
|
||||
align: "center",
|
||||
conditionalRenderDisabled: true,
|
||||
cellRender: ({ row }) => {
|
||||
if (row.isDefault) {
|
||||
return;
|
||||
}
|
||||
const onClick = async () => {
|
||||
Modal.confirm({
|
||||
title: "提示",
|
||||
content: `确定要设置为默认吗?`,
|
||||
onOk: async () => {
|
||||
await api.SetDefault(row.id);
|
||||
await crudExpose.doRefresh();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<a-button type={"link"} size={"small"} onClick={onClick}>
|
||||
设为默认
|
||||
</a-button>
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
disabled: {
|
||||
title: "禁用/启用",
|
||||
type: "dict-switch",
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "启用", value: false, color: "success" },
|
||||
{ label: "禁用", value: true, color: "error" }
|
||||
]
|
||||
}),
|
||||
form: {
|
||||
value: false
|
||||
},
|
||||
column: {
|
||||
width: 100,
|
||||
component: {
|
||||
title: "点击可禁用/启用",
|
||||
on: {
|
||||
async click({ value, row }) {
|
||||
Modal.confirm({
|
||||
title: "提示",
|
||||
content: `确定要${!value ? "禁用" : "启用"}吗?`,
|
||||
onOk: async () => {
|
||||
await api.SetDisabled(row.id, !value);
|
||||
await crudExpose.doRefresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
createTime: {
|
||||
title: "创建时间",
|
||||
type: "datetime",
|
||||
form: {
|
||||
show: false
|
||||
},
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 160,
|
||||
align: "center"
|
||||
}
|
||||
},
|
||||
updateTime: {
|
||||
title: "更新时间",
|
||||
type: "datetime",
|
||||
form: {
|
||||
show: false
|
||||
},
|
||||
column: {
|
||||
show: true,
|
||||
width: 160
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<fs-page class="page-cert">
|
||||
<template #header>
|
||||
<div class="title">
|
||||
CNAME服务配置
|
||||
<span class="sub">
|
||||
此处配置的域名作为其他域名校验的代理,当别的域名需要申请证书时,通过CNAME映射到此域名上来验证所有权。好处是任何域名都可以通过此方式申请证书,也无需填写AccessSecret。
|
||||
</span>
|
||||
</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: "CnameProvider"
|
||||
});
|
||||
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>
|
||||
@@ -47,6 +47,10 @@ import { PublicSettingsSave, SettingKeys } from "./api";
|
||||
import { notification } from "ant-design-vue";
|
||||
import { useSettingStore } from "/@/store/modules/settings";
|
||||
|
||||
defineOptions({
|
||||
name: "SysSettings"
|
||||
});
|
||||
|
||||
interface FormState {
|
||||
registerEnabled: boolean;
|
||||
managerOtherUserPipeline: boolean;
|
||||
|
||||
@@ -68,6 +68,10 @@ import { notification } from "ant-design-vue";
|
||||
import { useSettingStore } from "/src/store/modules/settings";
|
||||
import { useUserStore } from "/@/store/modules/user";
|
||||
|
||||
defineOptions({
|
||||
name: "SiteSetting"
|
||||
});
|
||||
|
||||
interface FormState {
|
||||
title: string;
|
||||
slogan: string;
|
||||
|
||||
Reference in New Issue
Block a user