refactor: organize certd client i18n translations

This commit is contained in:
xiaojunnuo
2026-04-30 23:48:48 +08:00
parent 267243e71b
commit 028932c04a
35 changed files with 503 additions and 150 deletions
@@ -89,15 +89,15 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
form: {
async beforeSubmit({ form }) {
if (form.challengeType === "cname") {
throw new Error("CNAME方式请前往CNAME记录页面进行管理");
throw new Error(t("certd.domain.cnameManagedInCnamePage"));
}
if (form.challengeType === "dns") {
const isSubdomain = await api.IsSubdomain({ domain: form.domain });
if (isSubdomain && !subdomainConfirmed.value) {
Modal.confirm({
title: "子域名确认",
content: `检测到${form.domain}为子域名,只有托管子域名和免费二级子域名才需要在此处维护,否则会导致申请证书失败,请确认是否继续?`,
okText: "确认",
title: t("certd.domain.subdomainConfirmTitle"),
content: t("certd.domain.subdomainConfirmContent", { domain: form.domain }),
okText: t("common.confirm"),
okType: "danger",
onOk: () => {
subdomainConfirmed.value = true;
@@ -119,9 +119,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
import: {
show: hasActionPermission("write"),
title: "从域名提供商导入域名",
title: t("certd.domain.importFromProvider"),
type: "primary",
text: "从域名提供商导入",
text: t("certd.domain.importFromProvider"),
needPlus: true,
color: "gold",
icon: "mingcute:vip-1-line",
@@ -135,14 +135,14 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
syncExpirationDate: {
show: hasActionPermission("write"),
title: "同步域名过期时间",
title: t("certd.domain.syncExpirationDate"),
type: "primary",
icon: "ion:refresh-outline",
text: "同步域名过期时间",
text: t("certd.domain.syncExpirationDate"),
click: async () => {
await api.SyncExpirationStart();
notification.success({
message: "同步任务已提交",
message: t("certd.domain.syncTaskSubmitted"),
});
setTimeout(() => {
crudExpose.doRefresh();
@@ -151,10 +151,10 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
monitorSettingSave: {
show: hasActionPermission("write"),
title: "域名过期监控设置",
title: t("certd.domain.expirationMonitorSetting"),
type: "primary",
icon: "ion:save-outline",
text: "域名过期监控设置",
text: t("certd.domain.expirationMonitorSetting"),
click: async () => {
router.push({
path: "/certd/cert/domain/setting",
@@ -184,7 +184,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
form: {
required: true,
helper: "注意:DNS校验方式下,子域名不需要在此处维护,否则会影响证书申请(子域名托管或免费二级域名除外)",
helper: t("certd.domain.subdomainDnsHelper"),
},
editForm: {
component: {
@@ -361,7 +361,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
<fs-values-format modelValue={row.challengeType} dict={Dicts.challengeTypeDict} color={"auto"}></fs-values-format>
<fs-values-format modelValue={row.httpUploaderType} dict={httpUploaderTypeDict} color={"auto"}></fs-values-format>
<fs-values-format class={"ml-5"} modelValue={row.httpUploaderAccess} dict={accessDict} color={"auto"}></fs-values-format>
<a-tag class={"ml-5 flex items-center"}>{row.httpUploadRootDir}</a-tag>
<a-tag class={"ml-5 flex items-center"}>{t("certd.domain.path")}: {row.httpUploadRootDir}</a-tag>
</div>
);
}
@@ -1,16 +1,16 @@
<template>
<div class="domain-import-task-status min-h-[300px]">
<div class="action mb-5">
<fs-button type="primary" icon="mingcute:vip-1-line" @click="addTask">添加导入任务</fs-button>
<fs-button type="primary" icon="ion:refresh-outline" class="ml-2" @click="loadImportTaskStatus">刷新</fs-button>
<fs-button type="primary" icon="mingcute:vip-1-line" @click="addTask">{{ t("certd.domain.addImportTask") }}</fs-button>
<fs-button type="primary" icon="ion:refresh-outline" class="ml-2" @click="loadImportTaskStatus">{{ t("certd.domain.refresh") }}</fs-button>
</div>
<div class="table-container overflow-auto mb-10">
<table class="cd-table border-gray-300 w-full">
<thead>
<tr>
<th class="w-[220px]">来源</th>
<th class="">进度</th>
<th class="w-[220px]">操作</th>
<th class="w-[220px]">{{ t("certd.sourcee") }}</th>
<th class="">{{ t("certd.domain.progress") }}</th>
<th class="w-[220px]">{{ t("certd.domain.operation") }}</th>
</tr>
</thead>
<tbody>
@@ -27,23 +27,23 @@
<td>
<div v-if="item.task">
<div>
<a-tag color="blue">总数{{ item.task?.total }}</a-tag>
<a-tag color="success" class="ml-2">成功{{ item.task?.successCount }}</a-tag>
<a-tag type="info" class="ml-2">跳过{{ item.task?.skipCount }}</a-tag>
<a-tag color="blue">{{ t("certd.domain.total") }}{{ item.task?.total }}</a-tag>
<a-tag color="success" class="ml-2">{{ t("certd.success") }}{{ item.task?.successCount }}</a-tag>
<a-tag type="info" class="ml-2">{{ t("certd.domain.skipped") }}{{ item.task?.skipCount }}</a-tag>
<a-tooltip v-if="item.task?.errors.length > 0">
<template #title>
<div v-for="error in item.task?.errors" :key="error">{{ error }}</div>
</template>
<a-tag color="red" class="ml-2">失败{{ item.task?.errors.length }}</a-tag>
<a-tag color="red" class="ml-2">{{ t("certd.domain.failed") }}{{ item.task?.errors.length }}</a-tag>
</a-tooltip>
</div>
<a-progress :percent="item.task?.progress" size="small" status="active" />
</div>
<div v-else>未执行</div>
<div v-else>{{ t("certd.domain.notExecuted") }}</div>
</td>
<td>
<fs-button type="primary" icon="ion:play-outline" :disabled="item.task?.status === 'running'" @click="startTask(item)">执行</fs-button>
<fs-button type="primary" class="ml-2" danger icon="ion:trash-outline" @click="deleteTask(item)">删除</fs-button>
<fs-button type="primary" icon="ion:play-outline" :disabled="item.task?.status === 'running'" @click="startTask(item)">{{ t("certd.domain.execute") }}</fs-button>
<fs-button type="primary" class="ml-2" danger icon="ion:trash-outline" @click="deleteTask(item)">{{ t("certd.domain.delete") }}</fs-button>
</td>
</tr>
</tbody>
@@ -58,11 +58,13 @@ import { onMounted, onUnmounted, ref } from "vue";
import * as api from "./api";
import { useDomainImport } from "./use";
import { useSettingStore } from "/@/store/settings";
import { useI18n } from "/@/locales";
defineOptions({
name: "DomainImportTaskStatus",
});
const list = ref([]);
const { t } = useI18n();
async function loadImportTaskStatus() {
const res = await api.ImportTaskStatus();
@@ -77,8 +79,8 @@ async function startTask(item: any) {
async function deleteTask(item: any) {
Modal.confirm({
title: "确认删除吗?",
okText: "确认",
title: t("certd.domain.confirmDelete"),
okText: t("common.confirm"),
okType: "danger",
onOk: async () => {
await api.ImportTaskDelete(item.key);
@@ -5,12 +5,14 @@ import { compute } from "@fast-crud/fast-crud";
import { Dicts } from "/@/components/plugins/lib/dicts";
import { useSettingStore } from "/@/store/settings";
import DomainImportTaskStatus from "./import.vue";
import { useI18n } from "/@/locales";
export function useDomainImport() {
const { openFormDialog } = useFormDialog();
const { t } = useI18n();
const columns = {
dnsProviderType: {
title: "域名提供商",
title: t("certd.domain.domainProvider"),
type: "text",
form: {
component: {
@@ -29,14 +31,14 @@ export function useDomainImport() {
},
},
dnsProviderAccessType: {
title: "域名提供商访问类型",
title: t("certd.domain.domainProviderAccessType"),
type: "text",
form: {
show: false,
},
},
dnsProviderAccessId: {
title: "域名提供商授权",
title: t("certd.domain.domainProviderAccess"),
type: "text",
form: {
component: {
@@ -52,7 +54,7 @@ export function useDomainImport() {
return function openDomainImportDialog(req: { afterSubmit?: (res?: any) => void; form?: any }) {
openFormDialog({
title: "从域名提供商导入域名",
title: t("certd.domain.importFromProvider"),
columns: columns,
initialForm: {
...req.form,
@@ -73,10 +75,11 @@ export function useDomainImport() {
export function useDomainImportManage() {
const { openFormDialog } = useFormDialog();
const { t } = useI18n();
const settingStore = useSettingStore();
return async function openDomainImportManageDialog(req: { afterSubmit?: (res?: any) => void; form?: any; zIndex?: number }) {
await openFormDialog({
title: "从域名提供商导入域名",
title: t("certd.domain.importFromProvider"),
body: () => {
return <DomainImportTaskStatus />;
},
@@ -79,9 +79,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
import: {
show: hasActionPermission("write"),
title: "导入CNAME记录",
title: t("certd.cname.importRecords"),
type: "primary",
text: "批量导入",
text: t("certd.cname.batchImport"),
icon: "mingcute:vip-1-line",
click: () => {
settingStore.checkPlus();
@@ -95,9 +95,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
},
export: {
title: "导出CNAME记录之后,可用于批量导入cname解析到域名注册商",
title: t("certd.cname.exportRecordsTip"),
type: "primary",
text: "批量导出",
text: t("certd.cname.batchExport"),
icon: "mingcute:vip-1-line",
click: () => {
settingStore.checkPlus();
@@ -235,8 +235,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
cellRender({ value, row }) {
async function resetStatus() {
Modal.confirm({
title: "重置状态",
content: "确定要重置校验状态吗?",
title: t("certd.cname.resetStatus"),
content: t("certd.cname.confirmResetStatus"),
onOk: async () => {
await api.ResetStatus(row.id);
await crudExpose.doRefresh();
@@ -253,7 +253,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
)}
{row.status === "valid" && (
<a-tooltip title={"重置校验状态,重新校验"}>
<a-tooltip title={t("certd.cname.resetStatusTooltip")}>
<fs-icon class={"ml-5 pointer "} icon="solar:undo-left-square-bold" onClick={resetStatus}></fs-icon>
</a-tooltip>
)}
@@ -2,6 +2,7 @@ import { dict } from "@fast-crud/fast-crud";
import { message } from "ant-design-vue";
import * as api from "./api";
import { useFormDialog } from "/@/use/use-dialog";
import { useI18n } from "/@/locales";
export const cnameProviderDict = dict({
url: "/cname/provider/list",
@@ -10,10 +11,11 @@ export const cnameProviderDict = dict({
});
export function useCnameImport() {
const { openFormDialog } = useFormDialog();
const { t } = useI18n();
const columns = {
domainList: {
title: "域名列表",
title: t("certd.cname.domainList"),
type: "text",
form: {
component: {
@@ -24,11 +26,11 @@ export function useCnameImport() {
span: 24,
},
required: true,
helper: "每个域名一行,批量导入\n泛域名请去掉*.\n已经存在的会自动跳过",
helper: t("certd.cname.domainListHelper"),
},
},
cnameProviderId: {
title: "CNAME服务",
title: t("certd.cname.cnameService"),
type: "dict-select",
dict: cnameProviderDict,
form: {
@@ -39,14 +41,14 @@ export function useCnameImport() {
return function openCnameImportDialog(req: { afterSubmit?: () => void }) {
openFormDialog({
title: "导入CNAME记录",
title: t("certd.cname.importRecords"),
columns: columns,
onSubmit: async (form: any) => {
await api.Import({
domainList: form.domainList,
cnameProviderId: form.cnameProviderId,
});
message.success("导入任务已提交");
message.success(t("certd.cname.importTaskSubmitted"));
if (req.afterSubmit) {
req.afterSubmit();
}
@@ -69,17 +69,17 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
const handleBatchDelete = () => {
if (selectedRowKeys.value?.length > 0) {
Modal.confirm({
title: "确认",
content: `确定要批量删除这${selectedRowKeys.value.length}条记录吗`,
title: t("monitor.confirmTitle"),
content: t("monitor.batchDeleteConfirm", { count: selectedRowKeys.value.length }),
async onOk() {
await api.BatchDelObj(selectedRowKeys.value);
message.info("删除成功");
message.info(t("monitor.deleteSuccess"));
crudExpose.doRefresh();
selectedRowKeys.value = [];
},
});
} else {
message.error("请先勾选记录");
message.error(t("monitor.selectRecordsFirst"));
}
};
@@ -265,7 +265,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
type: "link",
text: null,
tooltip: {
title: "立即检查",
title: t("monitor.checkNow"),
},
icon: "ion:play-sharp",
click: async ({ row }) => {
@@ -17,7 +17,7 @@
</template>
<fs-crud ref="crudRef" v-bind="crudBinding">
<template #pagination-left>
<a-tooltip title="批量删除">
<a-tooltip :title="t('monitor.batchDelete')">
<fs-button icon="DeleteOutlined" @click="handleBatchDelete"></fs-button>
</a-tooltip>
</template>
@@ -2,14 +2,16 @@ import { useFormWrapper } from "@fast-crud/fast-crud";
import SiteIpCertMonitor from "./index.vue";
import { siteIpApi } from "/@/views/certd/monitor/site/ip/api";
import { useI18n } from "/@/locales";
export function useSiteIpMonitor() {
const { openDialog, openCrudFormDialog } = useFormWrapper();
const { t } = useI18n();
async function openSiteIpMonitorDialog(opts: { siteId: number }) {
await openDialog({
wrapper: {
title: "站点IP监控",
title: t("monitor.siteIpMonitor"),
width: "80%",
is: "a-modal",
footer: false,
@@ -40,10 +42,10 @@ export function useSiteIpMonitor() {
columns: {
text: {
type: "textarea",
title: "IP列表",
title: t("monitor.ipList"),
form: {
helper: "IP或者CNAME域名,一行一个",
rules: [{ required: true, message: "请输入要导入的IP或域名" }],
helper: t("monitor.ipListHelper"),
rules: [{ required: true, message: t("monitor.enterImportIpOrDomain") }],
component: {
placeholder: "192.168.1.2\ncname.foo.com",
rows: 8,