Add other translations

pull/436/head
Lorenzo 2025-06-27 00:39:00 +02:00
parent 0b3472d227
commit adc3ab7e0a
12 changed files with 2167 additions and 1929 deletions

View File

@ -344,4 +344,107 @@ export default {
openApi: "Open API",
contentPart2: " request testing",
},
pending_cname_setup: "Pending CNAME setup",
validating: "Validating",
validation_successful: "Validation successful",
validation_failed: "Validation failed",
validation_timed_out: "Validation timed out",
proxied_domain: "Proxied Domain",
host_record: "Host Record",
please_set_cname: "Please set CNAME",
cname_service: "CNAME Service",
default_public_cname: "Default public CNAME service, you can also ",
customize_cname: "Customize CNAME Service",
public_cname: "Public CNAME",
custom_cname: "Custom CNAME",
validate: "Validate",
validation_started: "Validation started, please wait patiently",
click_to_validate: "Click to Validate",
all: "All",
cname_feature_guide: "CNAME feature principle and usage guide",
batch_delete: "Batch Delete",
confirm_delete_count: "Are you sure to delete these {count} records in batch?",
delete_successful: "Delete successful",
please_select_records: "Please select records first",
edit_notification: "Edit Notification",
other_notification_method: "Other Notification Method",
trigger_time: "Trigger Time",
start_time: "At Start",
success_time: "On Success",
fail_to_success_time: "Fail to Success",
fail_time: "On Failure",
helper_suggest_fail_only: "It is recommended to select only 'On Failure' and 'Fail to Success'",
notification_config: "Notification Configuration",
please_select_notification: "Please select a notification method",
please_select_type: "Please select type",
please_select_trigger_time: "Please select notification trigger time",
please_select_notification_config: "Please select notification configuration",
confirm_delete_trigger: "Are you sure you want to delete this trigger?",
gift_package: "Gift Package",
package_name: "Package Name",
click_to_select: "Click to select",
please_select_package: "Please select a package",
package: "Package",
addon_package: "Addon Package",
domain_count: "Domain Count",
unit_count: "pcs",
field_required: "This field is required",
pipeline_count: "Pipeline Count",
unit_item: "items",
deploy_count: "Deploy Count",
unit_times: "times",
monitor_count: "Certificate Monitor Count",
duration: "Duration",
status: "Status",
active_time: "Activation Time",
expires_time: "Expiration Time",
is_present: "Is Present",
is_present_yes: "Yes",
is_present_no: "No",
basicInfo: "Basic Information",
titlea: "Title",
disabled: "Disabled",
ordera: "Order",
supportBuy: "Support Purchase",
intro: "Introduction",
packageContent: "Package Content",
maxDomainCount: "Max Domain Count",
maxPipelineCount: "Max Pipeline Count",
maxDeployCount: "Max Deploy Count",
maxMonitorCount: "Max Monitor Count",
price: "Price",
durationPrices: "Duration Prices",
packageName: "Package Name",
addon: "Addon",
typeHelper: "Suite: Only the most recently purchased one is active at a time\nAddon: Multiple can be purchased, effective immediately without affecting the suite\nThe quantities of suite and addon can be accumulated",
domainCount: "Domain Count",
pipelineCount: "Pipeline Count",
unitPipeline: "pipelines",
deployCount: "Deployment Count",
unitDeploy: "times",
monitorCount: "Certificate Monitor Count",
unitCount: "pcs",
durationPriceTitle: "Duration and Price",
selectDuration: "Select Duration",
supportPurchase: "Support Purchase",
cannotPurchase: "Cannot Purchase",
shelfStatus: "Shelf Status",
onShelf: "On Shelf",
offShelf: "Off Shelf",
orderHelper: "Smaller values appear first",
description: "Description",
createTime: "Creation Time",
updateTime: "Update Time",
edit: "Edit",
groupName: "Group Name",
enterGroupName: "Please enter group name",
subdomainHosting: "Subdomain Hosting",
subdomainHostingHint: "When your domain has subdomain hosting set, you need to create records here, otherwise certificate application will fail",
batchDeleteConfirm: "Are you sure to batch delete these {count} records?",
selectRecordFirst: "Please select records first",
subdomainHosted: "Hosted Subdomain",
subdomainHelpText: "If you don't understand what subdomain hosting is, please refer to the documentation ",
subdomainManagement: "Subdomain Management",
isDisabled: "Is Disabled",
enabled: "Enabled",
};

View File

@ -350,4 +350,107 @@ export default {
openApi: "开放接口",
contentPart2: "请求测试",
},
pending_cname_setup: "待设置CNAME",
validating: "验证中",
validation_successful: "验证成功",
validation_failed: "验证失败",
validation_timed_out: "验证超时",
proxied_domain: "被代理域名",
host_record: "主机记录",
please_set_cname: "请设置CNAME",
cname_service: "CNAME服务",
default_public_cname: "默认提供公共CNAME服务您还可以",
customize_cname: "自定义CNAME服务",
public_cname: "公共CNAME",
custom_cname: "自定义CNAME",
validate: "验证",
validation_started: "开始验证,请耐心等待",
click_to_validate: "点击验证",
all: "全部",
cname_feature_guide: "CNAME功能原理及使用说明",
batch_delete: "批量删除",
confirm_delete_count: "确定要批量删除这{count}条记录吗",
delete_successful: "删除成功",
please_select_records: "请先勾选记录",
edit_notification: "编辑通知",
other_notification_method: "其他通知方式",
trigger_time: "触发时机",
start_time: "开始时",
success_time: "成功时",
fail_to_success_time: "失败转成功时",
fail_time: "失败时",
helper_suggest_fail_only: "建议仅选择'失败时'和'失败转成功'两种即可",
notification_config: "通知配置",
please_select_notification: "请选择通知方式",
please_select_type: "请选择类型",
please_select_trigger_time: "请选择通知时机",
please_select_notification_config: "请选择通知配置",
confirm_delete_trigger: "确定要删除此触发器吗?",
gift_package: "赠送套餐",
package_name: "套餐名称",
click_to_select: "点击选择",
please_select_package: "请选择套餐",
package: "套餐",
addon_package: "加量包",
domain_count: "域名数量",
unit_count: "个",
field_required: "此项必填",
pipeline_count: "流水线数量",
unit_item: "条",
deploy_count: "部署次数",
unit_times: "次",
monitor_count: "证书监控数量",
duration: "时长",
status: "状态",
active_time: "激活时间",
expires_time: "过期时间",
is_present: "是否赠送",
is_present_yes: "是",
is_present_no: "否",
basicInfo: "基础信息",
titlea: "名称",
disabled: "是否禁用",
ordera: "排序",
supportBuy: "支持购买",
intro: "介绍",
packageContent: "套餐内容",
maxDomainCount: "最大域名数",
maxPipelineCount: "最大流水线数",
maxDeployCount: "最大部署数",
maxMonitorCount: "最大监控数",
price: "价格",
durationPrices: "时长价格",
packageName: "套餐名称",
addon: "加量包",
typeHelper: "套餐:同一时间只有最新购买的一个生效\n加量包可购买多个购买后立即生效不影响套餐\n套餐和加量包数量可叠加",
domainCount: "域名数量",
pipelineCount: "流水线数量",
unitPipeline: "条",
deployCount: "部署次数",
unitDeploy: "次",
monitorCount: "证书监控数量",
unitCount: "个",
durationPriceTitle: "时长及价格",
selectDuration: "选择时长",
supportPurchase: "支持购买",
cannotPurchase: "不能购买",
shelfStatus: "上下架",
onShelf: "上架",
offShelf: "下架",
orderHelper: "越小越靠前",
description: "说明",
createTime: "创建时间",
updateTime: "更新时间",
edit: "编辑",
groupName: "分组名称",
enterGroupName: "请输入分组名称",
subdomainHosting: "子域名托管",
subdomainHostingHint: "当你的域名设置了子域名托管,需要在此处创建记录,否则申请证书将失败",
batchDeleteConfirm: "确定要批量删除这{count}条记录吗",
selectRecordFirst: "请先勾选记录",
subdomainHosted: "托管的子域名",
subdomainHelpText: "如果您不理解什么是子域托管,可以参考文档",
subdomainManagement: "子域管理",
isDisabled: "是否禁用",
enabled: "启用",
};

View File

@ -3,159 +3,159 @@ import * as api from "./api.plugin";
import { DynamicType, FormItemProps } from "@fast-crud/fast-crud";
interface PluginState {
group?: PluginGroups;
group?: PluginGroups;
}
export type PluginGroup = {
key: string;
title: string;
desc?: string;
order: number;
icon: string;
plugins: any[];
key: string;
title: string;
desc?: string;
order: number;
icon: string;
plugins: any[];
};
export type PluginDefine = {
name: string;
title: string;
desc?: string;
shortcut: any;
input: {
[key: string]: DynamicType<FormItemProps>;
};
output: {
[key: string]: any;
};
name: string;
title: string;
desc?: string;
shortcut: any;
input: {
[key: string]: DynamicType<FormItemProps>;
};
output: {
[key: string]: any;
};
};
export class PluginGroups {
groups!: { [key: string]: PluginGroup };
map!: { [key: string]: PluginDefine };
constructor(groups: { [key: string]: PluginGroup }) {
this.groups = groups;
this.initGroup(groups);
this.initMap();
}
groups!: { [key: string]: PluginGroup };
map!: { [key: string]: PluginDefine };
constructor(groups: { [key: string]: PluginGroup }) {
this.groups = groups;
this.initGroup(groups);
this.initMap();
}
private initGroup(groups: { [p: string]: PluginGroup }) {
const all: PluginGroup = {
key: "all",
title: "全部",
order: 0,
plugins: [],
icon: "material-symbols:border-all-rounded",
};
for (const key in groups) {
all.plugins.push(...groups[key].plugins);
}
this.groups = {
all,
...groups,
};
}
private initGroup(groups: { [p: string]: PluginGroup }) {
const all: PluginGroup = {
key: "all",
title: t('certd.all'),
order: 0,
plugins: [],
icon: "material-symbols:border-all-rounded",
};
for (const key in groups) {
all.plugins.push(...groups[key].plugins);
}
this.groups = {
all,
...groups,
};
}
initMap() {
const map: { [key: string]: PluginDefine } = {};
for (const key in this.groups) {
const group = this.groups[key];
for (const plugin of group.plugins) {
map[plugin.name] = plugin;
}
}
this.map = map;
}
initMap() {
const map: { [key: string]: PluginDefine } = {};
for (const key in this.groups) {
const group = this.groups[key];
for (const plugin of group.plugins) {
map[plugin.name] = plugin;
}
}
this.map = map;
}
getGroups() {
return this.groups;
}
getGroups() {
return this.groups;
}
get(name: string) {
return this.map[name];
}
get(name: string) {
return this.map[name];
}
getPreStepOutputOptions({ pipeline, currentStageIndex, currentTaskIndex, currentStepIndex, currentTask }: any) {
const steps = this.collectionPreStepOutputs({
pipeline,
currentStageIndex,
currentTaskIndex,
currentStepIndex,
currentTask,
});
const options: any[] = [];
for (const step of steps) {
const stepDefine = this.get(step.type);
for (const key in stepDefine?.output) {
options.push({
value: `step.${step.id}.${key}`,
label: `${stepDefine.output[key].title}【from${step.title}`,
type: step.type,
});
}
}
return options;
}
getPreStepOutputOptions({ pipeline, currentStageIndex, currentTaskIndex, currentStepIndex, currentTask }: any) {
const steps = this.collectionPreStepOutputs({
pipeline,
currentStageIndex,
currentTaskIndex,
currentStepIndex,
currentTask,
});
const options: any[] = [];
for (const step of steps) {
const stepDefine = this.get(step.type);
for (const key in stepDefine?.output) {
options.push({
value: `step.${step.id}.${key}`,
label: `${stepDefine.output[key].title}【from${step.title}`,
type: step.type,
});
}
}
return options;
}
collectionPreStepOutputs({ pipeline, currentStageIndex, currentTaskIndex, currentStepIndex, currentTask }: any) {
const steps: any[] = [];
// 开始放step
for (let i = 0; i < currentStageIndex; i++) {
const stage = pipeline.stages[i];
for (const task of stage.tasks) {
for (const step of task.steps) {
steps.push(step);
}
}
}
//当前阶段之前的task
const currentStage = pipeline.stages[currentStageIndex];
for (let i = 0; i < currentTaskIndex; i++) {
const task = currentStage.tasks[i];
for (const step of task.steps) {
steps.push(step);
}
}
//放当前任务下的step
for (let i = 0; i < currentStepIndex; i++) {
const step = currentTask.steps[i];
steps.push(step);
}
return steps;
}
collectionPreStepOutputs({ pipeline, currentStageIndex, currentTaskIndex, currentStepIndex, currentTask }: any) {
const steps: any[] = [];
// 开始放step
for (let i = 0; i < currentStageIndex; i++) {
const stage = pipeline.stages[i];
for (const task of stage.tasks) {
for (const step of task.steps) {
steps.push(step);
}
}
}
//当前阶段之前的task
const currentStage = pipeline.stages[currentStageIndex];
for (let i = 0; i < currentTaskIndex; i++) {
const task = currentStage.tasks[i];
for (const step of task.steps) {
steps.push(step);
}
}
//放当前任务下的step
for (let i = 0; i < currentStepIndex; i++) {
const step = currentTask.steps[i];
steps.push(step);
}
return steps;
}
}
export const usePluginStore = defineStore({
id: "app.plugin",
state: (): PluginState => ({
group: null,
}),
actions: {
async reload() {
const groups = await api.GetGroups({});
this.group = new PluginGroups(groups);
},
async init() {
if (!this.group) {
await this.reload();
}
return this.group;
},
async getGroups(): Promise<PluginGroups> {
await this.init();
return this.group as PluginGroups;
},
async clear() {
this.group = null;
},
async getList(): Promise<PluginDefine[]> {
await this.init();
return this.group.groups.all.plugins;
},
async getPluginDefine(name: string): Promise<PluginDefine> {
await this.init();
return this.group.get(name);
},
async getPluginConfig(query: any) {
return await api.GetPluginConfig(query);
},
},
id: "app.plugin",
state: (): PluginState => ({
group: null,
}),
actions: {
async reload() {
const groups = await api.GetGroups({});
this.group = new PluginGroups(groups);
},
async init() {
if (!this.group) {
await this.reload();
}
return this.group;
},
async getGroups(): Promise<PluginGroups> {
await this.init();
return this.group as PluginGroups;
},
async clear() {
this.group = null;
},
async getList(): Promise<PluginDefine[]> {
await this.init();
return this.group.groups.all.plugins;
},
async getPluginDefine(name: string): Promise<PluginDefine> {
await this.init();
return this.group.get(name);
},
async getPluginConfig(query: any) {
return await api.GetPluginConfig(query);
},
},
});

View File

@ -8,271 +8,272 @@ import { useSettingStore } from "/@/store/settings";
import { message } from "ant-design-vue";
import CnameTip from "/@/components/plugins/cert/domains-verify-plan-editor/cname-tip.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 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) => {
const res = await api.AddObj(form);
return res;
};
const addRequest = async ({ form }: AddReq) => {
const res = await api.AddObj(form);
return res;
};
const userStore = useUserStore();
const settingStore = useSettingStore();
const selectedRowKeys: Ref<any[]> = ref([]);
context.selectedRowKeys = selectedRowKeys;
const dictRef = dict({
data: [
{ label: "待设置CNAME", value: "cname", color: "warning" },
{ label: "验证中", value: "validating", color: "blue" },
{ label: "验证成功", value: "valid", color: "green" },
{ label: "验证失败", value: "failed", color: "red" },
{ label: "验证超时", value: "timeout", color: "red" },
],
});
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,
},
tabs: {
name: "status",
show: true,
},
rowHandle: {
minWidth: 200,
fixed: "right",
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 80,
},
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 }: any) => {
if (!form.cnameProviderId) {
const list = dict.data.filter((item: any) => {
return !item.disabled;
});
let item = list.find((item: any) => item.isDefault);
if (!item && list.length > 0) {
item = list[0];
}
if (item) {
form.cnameProviderId = item.id;
}
}
},
renderLabel(item: any) {
if (item.title) {
return `${item.domain}<${item.title}>`;
} else {
return item.domain;
}
},
},
helper: {
render() {
const closeForm = () => {
crudExpose.getFormWrapperRef().close();
};
return (
<div>
CNAME
<router-link to={"/sys/cname/provider"} onClick={closeForm}>
CNAME
</router-link>
</div>
);
},
},
},
column: {
width: 120,
align: "center",
cellRender({ value }) {
if (value < 0) {
return <a-tag color={"green"}>CNAME</a-tag>;
} else {
return <a-tag color={"blue"}>CNAME</a-tag>;
}
},
},
},
status: {
title: "状态",
type: "dict-select",
dict: dictRef,
addForm: {
show: false,
},
column: {
width: 120,
align: "center",
cellRender({ value, row }) {
return (
<div class={"flex flex-center"}>
<fs-values-format modelValue={value} dict={dictRef}></fs-values-format>
{row.error && (
<a-tooltip title={row.error}>
<fs-icon class={"ml-5 color-red"} icon="ion:warning-outline"></fs-icon>
</a-tooltip>
)}
</div>
);
},
},
},
triggerValidate: {
title: "验证",
type: "text",
form: {
show: false,
},
column: {
conditionalRenderDisabled: true,
width: 130,
align: "center",
cellRender({ row, value }) {
if (row.status === "valid") {
return "-";
}
const userStore = useUserStore();
const settingStore = useSettingStore();
const selectedRowKeys: Ref<any[]> = ref([]);
context.selectedRowKeys = selectedRowKeys;
const dictRef = dict({
data: [
{ label: t('certd.pending_cname_setup'), value: "cname", color: "warning" },
{ label: t('certd.validating'), value: "validating", color: "blue" },
{ label: t('certd.validation_successful'), value: "valid", color: "green" },
{ label: t('certd.validation_failed'), value: "failed", color: "red" },
{ label: t('certd.validation_timed_out'), value: "timeout", color: "red" },
],
});
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,
},
tabs: {
name: "status",
show: true,
},
rowHandle: {
minWidth: 200,
fixed: "right",
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 80,
},
form: {
show: false,
},
},
domain: {
title: t('certd.proxied_domain'),
type: "text",
search: {
show: true,
},
editForm: {
component: {
disabled: true,
},
},
},
hostRecord: {
title: t('certd.host_record'),
type: "text",
form: {
show: false,
},
column: {
width: 250,
cellRender: ({ value }) => {
return <fs-copyable v-model={value} />;
},
},
},
recordValue: {
title: t('certd.please_set_cname'),
type: "copyable",
form: {
show: false,
},
column: {
width: 500,
},
},
cnameProviderId: {
title: t('certd.cname_service'),
type: "dict-select",
dict: dict({
url: "/cname/provider/list",
value: "id",
label: "domain",
}),
form: {
component: {
onDictChange: ({ form, dict }: any) => {
if (!form.cnameProviderId) {
const list = dict.data.filter((item: any) => {
return !item.disabled;
});
let item = list.find((item: any) => item.isDefault);
if (!item && list.length > 0) {
item = list[0];
}
if (item) {
form.cnameProviderId = item.id;
}
}
},
renderLabel(item: any) {
if (item.title) {
return `${item.domain}<${item.title}>`;
} else {
return item.domain;
}
},
},
helper: {
render() {
const closeForm = () => {
crudExpose.getFormWrapperRef().close();
};
return (
<div>
{t('certd.default_public_cname')}
<router-link to={"/sys/cname/provider"} onClick={closeForm}>
{t('certd.customize_cname')}
</router-link>
</div>
);
},
},
},
column: {
width: 120,
align: "center",
cellRender({ value }) {
if (value < 0) {
return <a-tag color={"green"}>{t('certd.public_cname')}</a-tag>;
} else {
return <a-tag color={"blue"}>{t('certd.custom_cname')}</a-tag>;
}
},
},
},
status: {
title: t('certd.fields.status'),
type: "dict-select",
dict: dictRef,
addForm: {
show: false,
},
column: {
width: 120,
align: "center",
cellRender({ value, row }) {
return (
<div class={"flex flex-center"}>
<fs-values-format modelValue={value} dict={dictRef}></fs-values-format>
{row.error && (
<a-tooltip title={row.error}>
<fs-icon class={"ml-5 color-red"} icon="ion:warning-outline"></fs-icon>
</a-tooltip>
)}
</div>
);
},
},
},
triggerValidate: {
title: t('certd.validate'),
type: "text",
form: {
show: false,
},
column: {
conditionalRenderDisabled: true,
width: 130,
align: "center",
cellRender({ row, value }) {
if (row.status === "valid") {
return "-";
}
async function doVerify() {
row._validating_ = true;
try {
const res = await api.DoVerify(row.id);
if (res === true) {
message.success("验证成功");
row.status = "valid";
} else if (res === false) {
message.success("验证超时");
row.status = "timeout";
} else {
message.success("开始验证,请耐心等待");
}
await crudExpose.doRefresh();
} catch (e: any) {
console.error(e);
message.error(e.message);
} finally {
row._validating_ = false;
}
}
return (
<div>
<a-button onClick={doVerify} loading={row._validating_} size={"small"} type={"primary"}>
</a-button>
<CnameTip record={row} />
</div>
);
},
},
},
createTime: {
title: "创建时间",
type: "datetime",
form: {
show: false,
},
column: {
sorter: true,
width: 160,
align: "center",
},
},
updateTime: {
title: "更新时间",
type: "datetime",
form: {
show: false,
},
column: {
show: true,
},
},
},
},
};
async function doVerify() {
row._validating_ = true;
try {
const res = await api.DoVerify(row.id);
if (res === true) {
message.success(t('certd.validation_successful'));
row.status = "valid";
} else if (res === false) {
message.success(t('certd.validation_timed_out'));
row.status = "timeout";
} else {
message.success(t('certd.validation_started'));
}
await crudExpose.doRefresh();
} catch (e: any) {
console.error(e);
message.error(e.message);
} finally {
row._validating_ = false;
}
}
return (
<div>
<a-button onClick={doVerify} loading={row._validating_} size={"small"} type={"primary"}>
{t('certd.click_to_validate')}
</a-button>
<CnameTip record={row} />
</div>
);
},
},
},
createTime: {
title: t('certd.create_time'),
type: "datetime",
form: {
show: false,
},
column: {
sorter: true,
width: 160,
align: "center",
},
},
updateTime: {
title: t('certd.update_time'),
type: "datetime",
form: {
show: false,
},
column: {
show: true,
},
},
},
},
};
}

View File

@ -1,59 +1,66 @@
<template>
<fs-page class="page-cert">
<template #header>
<div class="title">
CNAME记录管理
<span class="sub">
<a href="https://certd.docmirror.cn/guide/feature/cname/" target="_blank">CNAME功能原理及使用说明</a>
</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>
<fs-page class="page-cert">
<template #header>
<div class="title">
{{ t('certd.cnameRecord') }}
<span class="sub">
<a href="https://certd.docmirror.cn/guide/feature/cname/" target="_blank">
{{ t('certd.cname_feature_guide') }}
</a>
</span>
</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding">
<template #pagination-left>
<a-tooltip :title="t('certd.batch_delete')">
<fs-button icon="DeleteOutlined" @click="handleBatchDelete"></fs-button>
</a-tooltip>
</template>
</fs-crud>
</fs-page>
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
defineOptions({
name: "CnameRecord",
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("请先勾选记录");
}
if (selectedRowKeys.value?.length > 0) {
Modal.confirm({
title: t('certd.confirm'),
content: t('certd.confirm_delete_count', { count: selectedRowKeys.value.length }),
async onOk() {
await DeleteBatch(selectedRowKeys.value);
message.info(t('certd.delete_successful'));
crudExpose.doRefresh();
selectedRowKeys.value = [];
},
});
} else {
message.error(t('certd.please_select_records'));
}
};
//
onMounted(() => {
crudExpose.doRefresh();
crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh();
await crudExpose.doRefresh();
});
</script>
<style lang="less"></style>

View File

@ -5,130 +5,131 @@ import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, Edi
import { pipelineGroupApi } from "./api";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const api = pipelineGroupApi;
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 { t } = useI18n();
const api = pipelineGroupApi;
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 addRequest = async (req: AddReq) => {
const { form } = req;
const res = await api.AddObj(form);
return res;
};
return {
crudOptions: {
settings: {
plugins: {
mobile: {
props: {
rowHandle: {
width: 160,
},
},
},
},
},
request: {
pageRequest,
addRequest,
editRequest,
delRequest,
},
form: {
labelCol: {
//固定label宽度
span: null,
style: {
width: "100px",
},
},
col: {
span: 22,
},
wrapper: {
width: 600,
},
},
rowHandle: {
width: 200,
group: {
editable: {
edit: {
text: "编辑",
order: -1,
type: "primary",
click({ row, index }) {
crudExpose.openEdit({
index,
row,
});
},
},
},
},
},
table: {
editable: {
enabled: true,
mode: "cell",
exclusive: true,
//排他式激活效果,将其他行的编辑状态触发保存
exclusiveEffect: "save", //自动保存其他行编辑状态cancel = 自动关闭其他行编辑状态
async updateCell(opts) {
const { row, key, value } = opts;
//如果是添加,需要返回{[rowKey]:xxx},比如:{id:2}
return await api.UpdateObj({ id: row.id, [key]: value });
},
},
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
search: {
show: true,
},
column: {
width: 100,
editable: {
disabled: true,
},
},
form: {
show: false,
},
},
name: {
title: "分组名称",
search: {
show: true,
},
type: "text",
form: {
rules: [
{
required: true,
message: "请输入分组名称",
},
],
},
column: {
width: 400,
},
},
},
},
};
return {
crudOptions: {
settings: {
plugins: {
mobile: {
props: {
rowHandle: {
width: 160,
},
},
},
},
},
request: {
pageRequest,
addRequest,
editRequest,
delRequest,
},
form: {
labelCol: {
//固定label宽度
span: null,
style: {
width: "100px",
},
},
col: {
span: 22,
},
wrapper: {
width: 600,
},
},
rowHandle: {
width: 200,
group: {
editable: {
edit: {
text: t('certd.edit'),
order: -1,
type: "primary",
click({ row, index }) {
crudExpose.openEdit({
index,
row,
});
},
},
},
},
},
table: {
editable: {
enabled: true,
mode: "cell",
exclusive: true,
//排他式激活效果,将其他行的编辑状态触发保存
exclusiveEffect: "save", //自动保存其他行编辑状态cancel = 自动关闭其他行编辑状态
async updateCell(opts) {
const { row, key, value } = opts;
//如果是添加,需要返回{[rowKey]:xxx},比如:{id:2}
return await api.UpdateObj({ id: row.id, [key]: value });
},
},
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
search: {
show: true,
},
column: {
width: 100,
editable: {
disabled: true,
},
},
form: {
show: false,
},
},
name: {
title: t('certd.groupName'),
search: {
show: true,
},
type: "text",
form: {
rules: [
{
required: true,
message: t('certd.enterGroupName'),
},
],
},
column: {
width: 400,
},
}
},
},
};
}

View File

@ -1,84 +1,78 @@
<template>
<a-drawer v-model:open="notificationDrawerVisible" placement="right" :closable="true" width="600px" class="pi-notification-form" @after-open-change="notificationDrawerOnAfterVisibleChange">
<template #title>
<div>
编辑通知
<a-button v-if="mode === 'edit'" @click="notificationDelete()">
<template #icon><DeleteOutlined /></template>
</a-button>
</div>
</template>
<template v-if="currentNotification">
<pi-container>
<a-form ref="notificationFormRef" class="notification-form" :model="currentNotification" :label-col="labelCol" :wrapper-col="wrapperCol">
<fs-form-item
v-if="currentNotification.type === 'email'"
v-model="currentNotification.type"
:item="{
title: '类型',
key: 'type',
value: 'email',
component: {
name: 'a-select',
vModel: 'value',
disabled: !editMode,
options: [
{ value: 'email', label: '邮件' },
{ value: 'other', label: '其他通知方式' },
],
},
rules: [{ required: true, message: '此项必填' }],
}"
/>
<fs-form-item
v-model="currentNotification.when"
:item="{
title: '触发时机',
key: 'when',
value: ['error'],
component: {
name: 'a-select',
vModel: 'value',
disabled: !editMode,
mode: 'multiple',
options: [
{ value: 'start', label: '开始时' },
{ value: 'success', label: '成功时' },
{ value: 'turnToSuccess', label: '失败转成功时' },
{ value: 'error', label: '失败时' },
],
},
helper: `建议仅选择'失败时'和'失败转成功'两种即可`,
rules: [{ required: true, message: '此项必填' }],
}"
/>
<pi-notification-form-email v-if="currentNotification.type === 'email'" ref="optionsRef" v-model:options="currentNotification.options"></pi-notification-form-email>
<a-drawer v-model:open="notificationDrawerVisible" placement="right" :closable="true" width="600px"
class="pi-notification-form" @after-open-change="notificationDrawerOnAfterVisibleChange">
<template #title>
<div>
{{ t('certd.edit_notification') }}
<a-button v-if="mode === 'edit'" @click="notificationDelete()">
<template #icon>
<DeleteOutlined />
</template>
</a-button>
</div>
</template>
<template v-if="currentNotification">
<pi-container>
<a-form ref="notificationFormRef" class="notification-form" :model="currentNotification"
:label-col="labelCol" :wrapper-col="wrapperCol">
<fs-form-item v-if="currentNotification.type === 'email'" v-model="currentNotification.type" :item="{
title: t('certd.type'),
key: 'type',
value: 'email',
component: {
name: 'a-select',
vModel: 'value',
disabled: !editMode,
options: [
{ value: 'email', label: t('certd.email') },
{ value: 'other', label: t('certd.other_notification_method') },
],
},
rules: [{ required: true, message: t('certd.required') }],
}" />
<fs-form-item v-model="currentNotification.when" :item="{
title: t('certd.trigger_time'),
key: 'when',
value: ['error'],
component: {
name: 'a-select',
vModel: 'value',
disabled: !editMode,
mode: 'multiple',
options: [
{ value: 'start', label: t('certd.start_time') },
{ value: 'success', label: t('certd.success_time') },
{ value: 'turnToSuccess', label: t('certd.fail_to_success_time') },
{ value: 'error', label: t('certd.fail_time') },
],
},
helper: t('certd.helper_suggest_fail_only'),
rules: [{ required: true, message: t('certd.required') }],
}" />
<pi-notification-form-email v-if="currentNotification.type === 'email'" ref="optionsRef"
v-model:options="currentNotification.options"></pi-notification-form-email>
<fs-form-item
v-else
v-model="currentNotification.notificationId"
:item="{
title: '通知配置',
key: 'notificationId',
component: {
disabled: !editMode,
name: NotificationSelector,
onSelectedChange,
},
helper: '请选择通知方式',
rules: [{ required: true, message: '此项必填' }],
}"
/>
</a-form>
<fs-form-item v-else v-model="currentNotification.notificationId" :item="{
title: t('certd.notification_config'),
key: 'notificationId',
component: {
disabled: !editMode,
name: NotificationSelector,
onSelectedChange,
},
helper: t('certd.please_select_notification'),
rules: [{ required: true, message: t('certd.required') }],
}" />
</a-form>
<template #footer>
<a-form-item v-if="editMode" :wrapper-col="{ span: 14, offset: 4 }">
<a-button type="primary" @click="notificationSave"> </a-button>
</a-form-item>
</template>
</pi-container>
</template>
</a-drawer>
<template #footer>
<a-form-item v-if="editMode" :wrapper-col="{ span: 14, offset: 4 }">
<a-button type="primary" @click="notificationSave"> {{ t('certd.confirm') }} </a-button>
</a-form-item>
</template>
</pi-container>
</template>
</a-drawer>
</template>
<script lang="ts">
@ -88,159 +82,161 @@ import * as _ from "lodash-es";
import { nanoid } from "nanoid";
import PiNotificationFormEmail from "./pi-notification-form-email.vue";
import NotificationSelector from "/@/views/certd/notification/notification-selector/index.vue";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
export default {
name: "PiNotificationForm",
// eslint-disable-next-line vue/no-unused-components
components: { NotificationSelector, PiNotificationFormEmail },
props: {
editMode: {
type: Boolean,
default: true,
},
},
emits: ["update"],
setup(props: any, context: any) {
/**
* notification drawer
* @returns
*/
function useNotificationForm() {
const mode = ref("add");
const callback = ref();
const currentNotification: Ref<any> = ref({ type: undefined, when: [], options: {}, notificationId: undefined, title: "" });
const currentPlugin = ref({});
const notificationFormRef = ref(null);
const notificationDrawerVisible = ref(false);
const optionsRef = ref();
const rules = ref({
type: [
{
type: "string",
required: true,
message: "请选择类型",
},
],
when: [
{
type: "string",
required: true,
message: "请选择通知时机",
},
],
notificationId: [
{
type: "number",
required: true,
message: "请选择通知配置",
},
],
});
name: "PiNotificationForm",
// eslint-disable-next-line vue/no-unused-components
components: { NotificationSelector, PiNotificationFormEmail },
props: {
editMode: {
type: Boolean,
default: true,
},
},
emits: ["update"],
setup(props: any, context: any) {
/**
* notification drawer
* @returns
*/
function useNotificationForm() {
const mode = ref("add");
const callback = ref();
const currentNotification: Ref<any> = ref({ type: undefined, when: [], options: {}, notificationId: undefined, title: "" });
const currentPlugin = ref({});
const notificationFormRef = ref(null);
const notificationDrawerVisible = ref(false);
const optionsRef = ref();
const rules = ref({
type: [
{
type: "string",
required: true,
message: t('certd.please_select_type'),
},
],
when: [
{
type: "string",
required: true,
message: t('certd.please_select_trigger_time'),
},
],
notificationId: [
{
type: "number",
required: true,
message: t('certd.please_select_notification_config'),
},
],
});
const notificationDrawerShow = () => {
notificationDrawerVisible.value = true;
};
const notificationDrawerClose = () => {
notificationDrawerVisible.value = false;
};
const notificationDrawerShow = () => {
notificationDrawerVisible.value = true;
};
const notificationDrawerClose = () => {
notificationDrawerVisible.value = false;
};
const notificationDrawerOnAfterVisibleChange = (val: any) => {
console.log("notificationDrawerOnAfterVisibleChange", val);
};
const notificationDrawerOnAfterVisibleChange = (val: any) => {
console.log("notificationDrawerOnAfterVisibleChange", val);
};
const notificationOpen = (notification: any, emit: any) => {
callback.value = emit;
currentNotification.value = _.cloneDeep(notification);
console.log("currentNotificationOpen", currentNotification.value);
notificationDrawerShow();
};
const notificationOpen = (notification: any, emit: any) => {
callback.value = emit;
currentNotification.value = _.cloneDeep(notification);
console.log("currentNotificationOpen", currentNotification.value);
notificationDrawerShow();
};
const notificationAdd = (emit: any) => {
mode.value = "add";
const notification = { id: nanoid(), type: "custom", when: ["error", "turnToSuccess"] };
notificationOpen(notification, emit);
};
const notificationAdd = (emit: any) => {
mode.value = "add";
const notification = { id: nanoid(), type: "custom", when: ["error", "turnToSuccess"] };
notificationOpen(notification, emit);
};
const notificationEdit = (notification: any, emit: any) => {
mode.value = "edit";
notificationOpen(notification, emit);
};
const notificationEdit = (notification: any, emit: any) => {
mode.value = "edit";
notificationOpen(notification, emit);
};
const notificationView = (notification: any, emit: any) => {
mode.value = "view";
notificationOpen(notification, emit);
};
const notificationView = (notification: any, emit: any) => {
mode.value = "view";
notificationOpen(notification, emit);
};
const notificationSave = async (e: any) => {
if (optionsRef.value) {
currentNotification.value.options = await optionsRef.value.getValue();
}
const notificationSave = async (e: any) => {
if (optionsRef.value) {
currentNotification.value.options = await optionsRef.value.getValue();
}
console.log("currentNotificationSave", currentNotification.value);
try {
await notificationFormRef.value.validate();
} catch (e) {
console.error("表单验证失败:", e);
return;
}
console.log("currentNotificationSave", currentNotification.value);
try {
await notificationFormRef.value.validate();
} catch (e) {
console.error("表单验证失败:", e);
return;
}
callback.value("save", currentNotification.value);
notificationDrawerClose();
};
callback.value("save", currentNotification.value);
notificationDrawerClose();
};
const notificationDelete = () => {
Modal.confirm({
title: t('certd.confirm'),
content: t('certd.confirm_delete_trigger'),
async onOk() {
callback.value("delete");
notificationDrawerClose();
},
});
};
const notificationDelete = () => {
Modal.confirm({
title: "确认",
content: `确定要删除此触发器吗?`,
async onOk() {
callback.value("delete");
notificationDrawerClose();
},
});
};
const blankFn = () => {
return {};
};
const blankFn = () => {
return {};
};
function onSelectedChange(node: any) {
currentNotification.value.title = node?.name || null;
}
return {
notificationFormRef,
onSelectedChange,
mode,
notificationAdd,
notificationEdit,
notificationView,
notificationDrawerShow,
notificationDrawerVisible,
notificationDrawerOnAfterVisibleChange,
currentNotification,
currentPlugin,
notificationSave,
notificationDelete,
rules,
blankFn,
optionsRef,
};
}
function onSelectedChange(node: any) {
currentNotification.value.title = node?.name || null;
}
return {
notificationFormRef,
onSelectedChange,
mode,
notificationAdd,
notificationEdit,
notificationView,
notificationDrawerShow,
notificationDrawerVisible,
notificationDrawerOnAfterVisibleChange,
currentNotification,
currentPlugin,
notificationSave,
notificationDelete,
rules,
blankFn,
optionsRef,
};
}
return {
...useNotificationForm(),
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
},
computed: {
NotificationSelector() {
return NotificationSelector;
},
},
return {
...useNotificationForm(),
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
},
computed: {
NotificationSelector() {
return NotificationSelector;
},
},
};
</script>
<style lang="less">
.pi-notification-form {
}
.pi-notification-form {}
</style>

View File

@ -1,137 +1,139 @@
import * as api from "./api";
import { Ref, ref } from "vue";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { useI18n } from "vue-i18n";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
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 { 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) => {
const res = await api.AddObj(form);
return res;
};
const addRequest = async ({ form }: AddReq) => {
const res = await api.AddObj(form);
return res;
};
const selectedRowKeys: Ref<any[]> = ref([]);
context.selectedRowKeys = selectedRowKeys;
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,
},
// tabs: {
// name: "status",
// show: true,
// },
rowHandle: {
minWidth: 200,
fixed: "right",
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 80,
},
form: {
show: false,
},
},
domain: {
title: "托管的子域名",
type: "text",
search: {
show: true,
},
form: {
helper: {
render() {
return (
<div>
<a href={"https://help.aliyun.com/zh/dns/subdomain-management"} target={"_blank"}>
</a>
</div>
);
},
},
},
editForm: {
component: {
disabled: true,
},
},
},
disabled: {
title: "是否禁用",
type: "dict-switch",
dict: dict({
data: [
{ value: false, label: "启用", color: "green" },
{ value: true, label: "禁用", color: "gray" },
],
}),
search: {
show: true,
},
form: {
value: false,
},
},
createTime: {
title: "创建时间",
type: "datetime",
form: {
show: false,
},
column: {
sorter: true,
width: 160,
align: "center",
},
},
updateTime: {
title: "更新时间",
type: "datetime",
form: {
show: false,
},
column: {
show: true,
},
},
},
},
};
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,
},
// tabs: {
// name: "status",
// show: true,
// },
rowHandle: {
minWidth: 200,
fixed: "right",
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 80,
},
form: {
show: false,
},
},
domain: {
title: t('certd.subdomainHosted'),
type: "text",
search: {
show: true,
},
form: {
helper: {
render() {
return (
<div>
{t('certd.subdomainHelpText')}
<a href={"https://help.aliyun.com/zh/dns/subdomain-management"} target={"_blank"}>
{t('certd.subdomainManagement')}
</a>
</div>
);
},
},
},
editForm: {
component: {
disabled: true,
},
},
},
disabled: {
title: t('certd.isDisabled'),
type: "dict-switch",
dict: dict({
data: [
{ value: false, label: t('certd.enabled'), color: "green" },
{ value: true, label: t('certd.disabled'), color: "gray" },
],
}),
search: {
show: true,
},
form: {
value: false,
},
},
createTime: {
title: t('certd.createTime'),
type: "datetime",
form: {
show: false,
},
column: {
sorter: true,
width: 160,
align: "center",
},
},
updateTime: {
title: t('certd.updateTime'),
type: "datetime",
form: {
show: false,
},
column: {
show: true,
},
},
},
},
};
}

View File

@ -1,19 +1,19 @@
<template>
<fs-page class="page-cert">
<template #header>
<div class="title">
子域名托管
<span class="sub"> 当你的域名设置了子域名托管需要在此处创建记录否则申请证书将失败 </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>
<fs-page class="page-cert">
<template #header>
<div class="title">
{{ t('certd.subdomainHosting') }}
<span class="sub">{{ t('certd.subdomainHostingHint') }}</span>
</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding">
<template #pagination-left>
<a-tooltip :title="t('certd.batchDelete')">
<fs-button icon="DeleteOutlined" @click="handleBatchDelete"></fs-button>
</a-tooltip>
</template>
</fs-crud>
</fs-page>
</template>
<script lang="ts" setup>
@ -22,36 +22,40 @@ import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
defineOptions({
name: "CnameRecord",
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("请先勾选记录");
}
if (selectedRowKeys.value?.length > 0) {
Modal.confirm({
title: t('certd.confirm'),
content: t('certd.batchDeleteConfirm', { count: selectedRowKeys.value.length }),
async onOk() {
await DeleteBatch(selectedRowKeys.value);
message.info(t('certd.deleteSuccess'));
crudExpose.doRefresh();
selectedRowKeys.value = [];
},
});
} else {
message.error(t('certd.selectRecordFirst'));
}
};
//
onMounted(() => {
crudExpose.doRefresh();
crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh();
await crudExpose.doRefresh();
});
</script>
<style lang="less"></style>

View File

@ -7,310 +7,310 @@ import DurationValue from "/@/views/sys/suite/product/duration-value.vue";
import UserSuiteStatus from "/@/views/certd/suite/mine/user-suite-status.vue";
import dayjs from "dayjs";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
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 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 addRequest = async (req: AddReq) => {
const { form } = req;
const res = await api.AddObj(form);
return res;
};
const router = useRouter();
const router = useRouter();
return {
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
form: {
labelCol: {
//固定label宽度
span: null,
style: {
width: "100px"
}
},
col: {
span: 22
},
wrapper: {
width: 600
}
},
actionbar: {
buttons: {
add: { show: false },
buy: {
text: "购买",
type: "primary",
click() {
router.push({
path: "/certd/suite/buy"
});
}
}
}
},
rowHandle: {
width: 200,
fixed: "right",
buttons: {
view: { show: false },
copy: { show: false },
edit: { show: false },
remove: { show: false }
// continue:{
// text:"续期",
// type:"link",
// click(){
// console.log("续期");
// }
// }
}
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
search: {
show: false
},
column: {
width: 100,
editable: {
disabled: true
}
},
form: {
show: false
}
},
title: {
title: "套餐名称",
type: "text",
search: {
show: true
},
form: {
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 200
}
},
productType: {
title: "类型",
type: "dict-select",
editForm: {
component: {
disabled: true
}
},
dict: dict({
data: [
{ label: "套餐", value: "suite", color: "green" },
{ label: "加量包", value: "addon", color: "blue" }
]
}),
form: {
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 80,
align: "center"
},
valueBuilder: ({ row }) => {
if (row.content) {
row.content = JSON.parse(row.content);
}
},
valueResolve: ({ form }) => {
if (form.content) {
form.content = JSON.stringify(form.content);
}
}
},
"content.maxDomainCount": {
title: "域名数量",
type: "text",
form: {
key: ["content", "maxDomainCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "个"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "个"
},
align: "center"
}
},
"content.maxPipelineCount": {
title: "流水线数量",
type: "text",
form: {
key: ["content", "maxPipelineCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "条"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "条"
},
align: "center"
}
},
"content.maxDeployCount": {
title: "部署次数",
type: "text",
form: {
key: ["content", "maxDeployCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "次"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "次",
used: compute(({ row }) => {
return row.deployCountUsed;
})
},
align: "center"
}
},
"content.maxMonitorCount": {
title: "证书监控数量",
type: "text",
form: {
key: ["content", "maxMonitorCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "个"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 120,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "个"
},
align: "center"
}
},
duration: {
title: "时长",
type: "text",
form: {},
column: {
component: {
name: DurationValue,
vModel: "modelValue"
},
width: 100,
align: "center"
}
},
status: {
title: "状态",
type: "text",
form: { show: false },
column: {
width: 100,
align: "center",
component: {
name: UserSuiteStatus,
userSuite: compute(({ row }) => {
return row;
}),
currentSuite: context.currentSuite
},
conditionalRender: {
match() {
return false;
}
}
}
},
activeTime: {
title: "激活时间",
type: "date",
column: {
width: 150
}
},
expiresTime: {
title: "过期时间",
type: "date",
column: {
width: 150,
component: {
name: "expires-time-text",
vModel: "value",
mode: "tag",
title: compute(({ value }) => {
return dayjs(value).format("YYYY-MM-DD HH:mm:ss");
})
}
}
},
isPresent: {
title: "是否赠送",
type: "dict-switch",
dict: dict({
data: [
{ label: "是", value: true, color: "success" },
{ label: "否", value: false, color: "blue" }
]
}),
form: {
value: true
},
column: {
width: 100,
align: "center"
}
}
}
}
};
return {
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
form: {
labelCol: {
//固定label宽度
span: null,
style: {
width: "100px"
}
},
col: {
span: 22
},
wrapper: {
width: 600
}
},
actionbar: {
buttons: {
add: { show: false },
buy: {
text: "购买",
type: "primary",
click() {
router.push({
path: "/certd/suite/buy"
});
}
}
}
},
rowHandle: {
width: 200,
fixed: "right",
buttons: {
view: { show: false },
copy: { show: false },
edit: { show: false },
remove: { show: false }
// continue:{
// text:"续期",
// type:"link",
// click(){
// console.log("续期");
// }
// }
}
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
search: {
show: false
},
column: {
width: 100,
editable: {
disabled: true
}
},
form: {
show: false
}
},
title: {
title: "套餐名称",
type: "text",
search: {
show: true
},
form: {
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 200
}
},
productType: {
title: "类型",
type: "dict-select",
editForm: {
component: {
disabled: true
}
},
dict: dict({
data: [
{ label: "套餐", value: "suite", color: "green" },
{ label: "加量包", value: "addon", color: "blue" }
]
}),
form: {
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 80,
align: "center"
},
valueBuilder: ({ row }) => {
if (row.content) {
row.content = JSON.parse(row.content);
}
},
valueResolve: ({ form }) => {
if (form.content) {
form.content = JSON.stringify(form.content);
}
}
},
"content.maxDomainCount": {
title: "域名数量",
type: "text",
form: {
key: ["content", "maxDomainCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "个"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "个"
},
align: "center"
}
},
"content.maxPipelineCount": {
title: "流水线数量",
type: "text",
form: {
key: ["content", "maxPipelineCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "条"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "条"
},
align: "center"
}
},
"content.maxDeployCount": {
title: "部署次数",
type: "text",
form: {
key: ["content", "maxDeployCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "次"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "次",
used: compute(({ row }) => {
return row.deployCountUsed;
})
},
align: "center"
}
},
"content.maxMonitorCount": {
title: "证书监控数量",
type: "text",
form: {
key: ["content", "maxMonitorCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "个"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 120,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "个"
},
align: "center"
}
},
duration: {
title: "时长",
type: "text",
form: {},
column: {
component: {
name: DurationValue,
vModel: "modelValue"
},
width: 100,
align: "center"
}
},
status: {
title: "状态",
type: "text",
form: { show: false },
column: {
width: 100,
align: "center",
component: {
name: UserSuiteStatus,
userSuite: compute(({ row }) => {
return row;
}),
currentSuite: context.currentSuite
},
conditionalRender: {
match() {
return false;
}
}
}
},
activeTime: {
title: "激活时间",
type: "date",
column: {
width: 150
}
},
expiresTime: {
title: "过期时间",
type: "date",
column: {
width: 150,
component: {
name: "expires-time-text",
vModel: "value",
mode: "tag",
title: compute(({ value }) => {
return dayjs(value).format("YYYY-MM-DD HH:mm:ss");
})
}
}
},
isPresent: {
title: "是否赠送",
type: "dict-switch",
dict: dict({
data: [
{ label: "是", value: true, color: "success" },
{ label: "否", value: false, color: "blue" }
]
}),
form: {
value: true
},
column: {
width: 100,
align: "center"
}
}
}
}
};
}

View File

@ -4,317 +4,333 @@ import SuiteValue from "./suite-value.vue";
import SuiteValueEdit from "./suite-value-edit.vue";
import PriceEdit from "./price-edit.vue";
import DurationPriceValue from "/@/views/sys/suite/product/duration-price-value.vue";
import { useI18n } from "vue-i18n";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const emit = context.emit;
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 { t } = useI18n();
const emit = context.emit;
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) => {
const res = await api.AddObj(form);
return res;
};
const addRequest = async ({ form }: AddReq) => {
const res = await api.AddObj(form);
return res;
};
return {
crudOptions: {
table: {
onRefreshed: () => {
emit("refreshed");
}
},
search: {
show: false
},
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
pagination: {
show: false,
pageSize: 999999
},
rowHandle: {
minWidth: 200,
fixed: "right"
},
form: {
group: {
groups: {
base: {
header: "基础信息",
columns: ["title", "type", "disabled", "order", "supportBuy", "intro"]
},
content: {
header: "套餐内容",
columns: ["content.maxDomainCount", "content.maxPipelineCount", "content.maxDeployCount", "content.maxMonitorCount"]
},
price: {
header: "价格",
columns: ["durationPrices"]
}
}
}
},
columns: {
// id: {
// title: "ID",
// key: "id",
// type: "number",
// column: {
// width: 100
// },
// form: {
// show: false
// }
// },
title: {
title: "套餐名称",
type: "text",
search: {
show: true
},
form: {
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 200
}
},
type: {
title: "类型",
type: "dict-select",
editForm: {
component: {
disabled: true
}
},
dict: dict({
data: [
{ label: "套餐", value: "suite" },
{ label: "加量包", value: "addon" }
]
}),
form: {
value: "suite",
rules: [{ required: true, message: "此项必填" }],
helper: "套餐:同一时间只有最新购买的一个生效\n加量包可购买多个购买后立即生效不影响套餐\n套餐和加量包数量可叠加"
},
column: {
width: 80,
align: "center"
},
valueBuilder: ({ row }) => {
if (row.content) {
row.content = JSON.parse(row.content);
}
if (row.durationPrices) {
row.durationPrices = JSON.parse(row.durationPrices);
}
},
valueResolve: ({ form }) => {
if (form.content) {
form.content = JSON.stringify(form.content);
}
if (form.durationPrices) {
form.durationPrices = JSON.stringify(form.durationPrices);
}
}
},
"content.maxDomainCount": {
title: "域名数量",
type: "text",
form: {
key: ["content", "maxDomainCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "个"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "个"
}
}
},
"content.maxPipelineCount": {
title: "流水线数量",
type: "text",
form: {
key: ["content", "maxPipelineCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "条"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "条"
}
}
},
"content.maxDeployCount": {
title: "部署次数",
type: "text",
form: {
key: ["content", "maxDeployCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "次"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "次"
}
}
},
"content.maxMonitorCount": {
title: "证书监控数量",
type: "text",
form: {
key: ["content", "maxMonitorCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "个"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 120,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "个"
}
}
},
durationPrices: {
title: "时长及价格",
type: "text",
form: {
title: "选择时长",
component: {
name: PriceEdit,
vModel: "modelValue",
edit: true,
style: {
minHeight: "120px"
}
},
col: {
span: 24
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
component: {
name: DurationPriceValue,
vModel: "modelValue"
},
width: 350
}
},
supportBuy: {
title: "支持购买",
type: "dict-switch",
dict: dict({
data: [
{ label: "支持购买", value: true, color: "success" },
{ label: "不能购买", value: false, color: "gray" }
]
}),
form: {
value: true
},
column: {
width: 120
}
},
disabled: {
title: "上下架",
type: "dict-radio",
dict: dict({
data: [
{ value: false, label: "上架", color: "green" },
{ value: true, label: "下架", color: "gray" }
]
}),
form: {
value: false
},
column: {
width: 100
}
},
order: {
title: "排序",
type: "number",
form: {
helper: "越小越靠前",
value: 0
},
column: {
width: 100
}
},
intro: {
title: "说明",
type: "textarea",
column: {
width: 200
}
},
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
}
}
}
}
};
return {
crudOptions: {
table: {
onRefreshed: () => {
emit("refreshed");
}
},
search: {
show: false
},
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
pagination: {
show: false,
pageSize: 999999
},
rowHandle: {
minWidth: 200,
fixed: "right"
},
form: {
group: {
groups: {
base: {
header: t('certd.basicInfo'),
columns: [
t('certd.titlea'),
t('certd.type'),
t('certd.disabled'),
t('certd.ordera'),
t('certd.supportBuy'),
t('certd.intro')
]
},
content: {
header: t('certd.packageContent'),
columns: [
t('certd.maxDomainCount'),
t('certd.maxPipelineCount'),
t('certd.maxDeployCount'),
t('certd.maxMonitorCount')
]
},
price: {
header: t('certd.price'),
columns: [
t('certd.durationPrices')
]
}
}
}
}
columns: {
// id: {
// title: "ID",
// key: "id",
// type: "number",
// column: {
// width: 100
// },
// form: {
// show: false
// }
// },
title: {
title: t('certd.packageName'),
type: "text",
search: {
show: true
},
form: {
rules: [{ required: true, message: t('certd.requiredField') }]
},
column: {
width: 200
}
},
type: {
title: t('certd.type'),
type: "dict-select",
editForm: {
component: {
disabled: true
}
},
dict: dict({
data: [
{ label: t('certd.suite'), value: "suite" },
{ label: t('certd.addon'), value: "addon" }
]
}),
form: {
value: "suite",
rules: [{ required: true, message: t('certd.requiredField') }],
helper: t('certd.typeHelper')
},
column: {
width: 80,
align: "center"
},
valueBuilder: ({ row }) => {
if (row.content) {
row.content = JSON.parse(row.content);
}
if (row.durationPrices) {
row.durationPrices = JSON.parse(row.durationPrices);
}
},
valueResolve: ({ form }) => {
if (form.content) {
form.content = JSON.stringify(form.content);
}
if (form.durationPrices) {
form.durationPrices = JSON.stringify(form.durationPrices);
}
}
},
"content.maxDomainCount": {
title: t('certd.domainCount'),
type: "text",
form: {
key: ["content", "maxDomainCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: t('certd.unitCount')
},
rules: [{ required: true, message: t('certd.requiredField') }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: t('certd.unitCount')
}
}
},
"content.maxPipelineCount": {
title: t('certd.pipelineCount'),
type: "text",
form: {
key: ["content", "maxPipelineCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: t('certd.unitPipeline')
},
rules: [{ required: true, message: t('certd.requiredField') }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: t('certd.unitPipeline')
}
}
},
"content.maxDeployCount": {
title: t('certd.deployCount'),
type: "text",
form: {
key: ["content", "maxDeployCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: t('certd.unitDeploy')
},
rules: [{ required: true, message: t('certd.requiredField') }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: t('certd.unitDeploy')
}
}
},
"content.maxMonitorCount": {
title: t('certd.monitorCount'),
type: "text",
form: {
key: ["content", "maxMonitorCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: t('certd.unitCount')
},
rules: [{ required: true, message: t('certd.requiredField') }]
},
column: {
width: 120,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: t('certd.unitCount')
}
}
},
durationPrices: {
title: t('certd.durationPriceTitle'),
type: "text",
form: {
title: t('certd.selectDuration'),
component: {
name: PriceEdit,
vModel: "modelValue",
edit: true,
style: {
minHeight: "120px"
}
},
col: {
span: 24
},
rules: [{ required: true, message: t('certd.requiredField') }]
},
column: {
component: {
name: DurationPriceValue,
vModel: "modelValue"
},
width: 350
}
},
supportBuy: {
title: t('certd.supportBuy'),
type: "dict-switch",
dict: dict({
data: [
{ label: t('certd.supportPurchase'), value: true, color: "success" },
{ label: t('certd.cannotPurchase'), value: false, color: "gray" }
]
}),
form: {
value: true
},
column: {
width: 120
}
},
disabled: {
title: t('certd.shelfStatus'),
type: "dict-radio",
dict: dict({
data: [
{ value: false, label: t('certd.onShelf'), color: "green" },
{ value: true, label: t('certd.offShelf'), color: "gray" }
]
}),
form: {
value: false
},
column: {
width: 100
}
},
order: {
title: t('certd.ordera'),
type: "number",
form: {
helper: t('certd.orderHelper'),
value: 0
},
column: {
width: 100
}
},
intro: {
title: t('certd.description'),
type: "textarea",
column: {
width: 200
}
},
createTime: {
title: t('certd.createTime'),
type: "datetime",
form: {
show: false
},
column: {
sorter: true,
width: 160,
align: "center"
}
},
updateTime: {
title: t('certd.updateTime'),
type: "datetime",
form: {
show: false
},
column: {
show: true,
width: 160
}
}
}
}
};
}

View File

@ -8,392 +8,397 @@ import createCrudOptionsUser from "/@/views/sys/authority/user/crud";
import UserSuiteStatus from "/@/views/certd/suite/mine/user-suite-status.vue";
import SuiteDurationSelector from "../setting/suite-duration-selector.vue";
import dayjs from "dayjs";
import { useI18n } from "vue-i18n";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const api = sysUserSuiteApi;
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 { t } = useI18n();
const api = sysUserSuiteApi;
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.PresentSuite(form);
return res;
};
const addRequest = async (req: AddReq) => {
const { form } = req;
const res = await api.PresentSuite(form);
return res;
};
const router = useRouter();
const router = useRouter();
return {
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
form: {
labelCol: {
//固定label宽度
span: null,
style: {
width: "100px"
}
},
col: {
span: 22
},
wrapper: {
width: 600
}
},
actionbar: {
buttons: {
add: { text: "赠送套餐" }
}
},
toolbar: { show: false },
rowHandle: {
width: 200,
fixed: "right",
buttons: {
view: { show: true },
copy: { show: false },
edit: { show: false },
remove: { show: true }
// continue:{
// text:"续期",
// type:"link",
// click(){
// console.log("续期");
// }
// }
}
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
search: {
show: false
},
column: {
width: 100,
editable: {
disabled: true
}
},
form: {
show: false
}
},
title: {
title: "套餐名称",
type: "text",
search: {
show: true
},
form: {
show: false
},
column: {
width: 200
}
},
userId: {
title: "用户",
type: "table-select",
search: {
show: true
},
dict: dict({
async getNodesByValues(ids: number[]) {
return await api.GetSimpleUserByIds(ids);
},
value: "id",
label: "nickName"
}),
form: {
component: {
crossPage: true,
multiple: false,
select: {
placeholder: "点击选择"
},
createCrudOptions: createCrudOptionsUser
// crudOptionsOverride: crudOptionsOverride
}
}
},
//赠送
presentSuiteId: {
title: "赠送套餐",
type: "dict-select",
column: { show: false },
addForm: {
show: true,
component: {
name: SuiteDurationSelector,
vModel: "modelValue"
},
rules: [
{
validator: async (rule, value) => {
if (value && value.productId) {
return true;
}
throw new Error("请选择套餐");
}
}
]
},
valueResolve({ form, value }) {
if (value && value.productId) {
form.productId = value.productId;
form.duration = value.duration;
}
},
form: { show: false }
},
productType: {
title: "类型",
type: "dict-select",
editForm: {
component: {
disabled: true
}
},
dict: dict({
data: [
{ label: "套餐", value: "suite", color: "green" },
{ label: "加量包", value: "addon", color: "blue" }
]
}),
form: {
show: false
},
column: {
width: 80,
align: "center"
},
valueBuilder: ({ row }) => {
if (row.content) {
row.content = JSON.parse(row.content);
}
},
valueResolve: ({ form }) => {
if (form.content) {
form.content = JSON.stringify(form.content);
}
}
},
"content.maxDomainCount": {
title: "域名数量",
type: "text",
form: {
show: false,
key: ["content", "maxDomainCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "个"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "个"
},
align: "center"
}
},
"content.maxPipelineCount": {
title: "流水线数量",
type: "text",
form: {
show: false,
key: ["content", "maxPipelineCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "条"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "条"
},
align: "center"
}
},
"content.maxDeployCount": {
title: "部署次数",
type: "text",
form: {
show: false,
key: ["content", "maxDeployCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "次"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "次",
used: compute(({ row }) => {
return row.deployCountUsed;
})
},
align: "center"
}
},
"content.maxMonitorCount": {
title: "证书监控数量",
type: "text",
form: {
show: false,
key: ["content", "maxMonitorCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: "个"
},
rules: [{ required: true, message: "此项必填" }]
},
column: {
width: 120,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: "个"
},
align: "center"
}
},
duration: {
title: "时长",
type: "text",
form: { show: false },
column: {
component: {
name: DurationValue,
vModel: "modelValue"
},
width: 100,
align: "center"
}
},
status: {
title: "状态",
type: "text",
form: { show: false },
column: {
width: 100,
align: "center",
component: {
name: UserSuiteStatus,
userSuite: compute(({ row }) => {
return row;
})
},
conditionalRender: {
match() {
return false;
}
}
}
},
activeTime: {
title: "激活时间",
type: "date",
column: {
width: 150
},
form: {
show: false
}
},
expiresTime: {
title: "过期时间",
type: "date",
form: {
show: false
},
column: {
width: 150,
component: {
name: "expires-time-text",
vModel: "value",
mode: "tag",
title: compute(({ value }) => {
return dayjs(value).format("YYYY-MM-DD HH:mm:ss");
})
}
}
},
isPresent: {
title: "是否赠送",
type: "dict-switch",
dict: dict({
data: [
{ label: "是", value: true, color: "success" },
{ label: "否", value: false, color: "blue" }
]
}),
form: {
value: true,
show: false
},
column: {
width: 100,
align: "center"
}
},
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
}
}
}
}
};
return {
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
form: {
labelCol: {
//固定label宽度
span: null,
style: {
width: "100px"
}
},
col: {
span: 22
},
wrapper: {
width: 600
}
},
actionbar: {
buttons: {
add: { text: t('certd.gift_package') }
}
},
toolbar: { show: false },
rowHandle: {
width: 200,
fixed: "right",
buttons: {
view: { show: true },
copy: { show: false },
edit: { show: false },
remove: { show: true }
// continue:{
// text:"续期",
// type:"link",
// click(){
// console.log("续期");
// }
// }
}
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
search: {
show: false
},
column: {
width: 100,
editable: {
disabled: true
}
},
form: {
show: false
}
},
title: {
title: t('certd.package_name'),
type: "text",
search: {
show: true
},
form: {
show: false
},
column: {
width: 200
}
},
userId: {
title: t('certd.usera'),
type: "table-select",
search: {
show: true
},
dict: dict({
async getNodesByValues(ids: number[]) {
return await api.GetSimpleUserByIds(ids);
},
value: "id",
label: "nickName"
}),
form: {
component: {
crossPage: true,
multiple: false,
select: {
placeholder: t('certd.click_to_select')
},
createCrudOptions: createCrudOptionsUser
// crudOptionsOverride: crudOptionsOverride
}
}
},
//赠送
presentSuiteId: {
title: t('certd.gift_package'),
type: "dict-select",
column: { show: false },
addForm: {
show: true,
component: {
name: SuiteDurationSelector,
vModel: "modelValue"
},
rules: [
{
validator: async (rule, value) => {
if (value && value.productId) {
return true;
}
throw new Error(t('certd.please_select_package'));
}
}
]
},
valueResolve({ form, value }) {
if (value && value.productId) {
form.productId = value.productId;
form.duration = value.duration;
}
},
form: { show: false }
},
productType: {
title: t('certd.type'),
type: "dict-select",
editForm: {
component: {
disabled: true
}
},
dict: dict({
data: [
{ label: t('certd.package'), value: "suite", color: "green" },
{ label: t('certd.addon_package'), value: "addon", color: "blue" }
]
}),
form: {
show: false
},
column: {
width: 80,
align: "center"
},
valueBuilder: ({ row }) => {
if (row.content) {
row.content = JSON.parse(row.content);
}
},
valueResolve: ({ form }) => {
if (form.content) {
form.content = JSON.stringify(form.content);
}
}
},
"content.maxDomainCount": {
title: t('certd.domain_count'),
type: "text",
form: {
show: false,
key: ["content", "maxDomainCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: t('certd.unit_count')
},
rules: [{ required: true, message: t('certd.field_required') }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: t('certd.unit_count')
},
align: "center"
}
},
"content.maxPipelineCount": {
title: t('certd.pipeline_count'),
type: "text",
form: {
show: false,
key: ["content", "maxPipelineCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: t('certd.unit_item')
},
rules: [{ required: true, message: t('certd.field_required') }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: t('certd.unit_item')
},
align: "center"
}
},
"content.maxDeployCount": {
title: t('certd.deploy_count'),
type: "text",
form: {
show: false,
key: ["content", "maxDeployCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: t('certd.unit_times')
},
rules: [{ required: true, message: t('certd.field_required') }]
},
column: {
width: 100,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: t('certd.unit_times'),
used: compute(({ row }) => {
return row.deployCountUsed;
})
},
align: "center"
}
},
"content.maxMonitorCount": {
title: t('certd.monitor_count'),
type: "text",
form: {
show: false,
key: ["content", "maxMonitorCount"],
component: {
name: SuiteValueEdit,
vModel: "modelValue",
unit: t('certd.unit_count')
},
rules: [{ required: true, message: t('certd.field_required') }]
},
column: {
width: 120,
component: {
name: SuiteValue,
vModel: "modelValue",
unit: t('certd.unit_count')
},
align: "center"
}
},
duration: {
title: t('certd.duration'),
type: "text",
form: { show: false },
column: {
component: {
name: DurationValue,
vModel: "modelValue"
},
width: 100,
align: "center"
}
},
status: {
title: t('certd.status'),
type: "text",
form: { show: false },
column: {
width: 100,
align: "center",
component: {
name: UserSuiteStatus,
userSuite: compute(({ row }) => {
return row;
})
},
conditionalRender: {
match() {
return false;
}
}
}
},
activeTime: {
title: t('certd.active_time'),
type: "date",
column: {
width: 150
},
form: {
show: false
}
},
expiresTime: {
title: t('certd.expires_time'),
type: "date",
form: {
show: false
},
column: {
width: 150,
component: {
name: "expires-time-text",
vModel: "value",
mode: "tag",
title: compute(({ value }) => {
return dayjs(value).format("YYYY-MM-DD HH:mm:ss");
})
}
}
},
isPresent: {
title: t('certd.is_present'),
type: "dict-switch",
dict: dict({
data: [
{ label: t('certd.is_present_yes'), value: true, color: "success" },
{ label: t('certd.is_present_no'), value: false, color: "blue" }
]
}),
form: {
value: true,
show: false
},
column: {
width: 100,
align: "center"
}
},
createTime: {
title: t('certd.create_time'),
type: "datetime",
form: {
show: false
},
column: {
sorter: true,
width: 160,
align: "center"
}
},
updateTime: {
title: t('certd.update_time'),
type: "datetime",
form: {
show: false
},
column: {
show: true,
width: 160
}
}
}
}
};
}