mirror of
https://github.com/certd/certd.git
synced 2026-05-16 05:07:32 +08:00
First translation step
This commit is contained in:
@@ -8,209 +8,209 @@ import { useSettingStore } from "/@/store/settings";
|
||||
import { statusUtil } from "/@/views/certd/pipeline/pipeline/utils/util.status";
|
||||
|
||||
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 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,
|
||||
},
|
||||
actionbar: {
|
||||
buttons: {
|
||||
add: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
search: {
|
||||
formItem: {
|
||||
labelCol: {
|
||||
style: {
|
||||
// width: "100px"
|
||||
},
|
||||
},
|
||||
wrapperCol: {
|
||||
style: {
|
||||
width: "50%",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
rowHandle: {
|
||||
minWidth: 200,
|
||||
fixed: "right",
|
||||
buttons: {
|
||||
edit: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
id: {
|
||||
title: "ID",
|
||||
key: "id",
|
||||
type: "number",
|
||||
column: {
|
||||
width: 100,
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
userId: {
|
||||
title: "用户Id",
|
||||
type: "number",
|
||||
search: {
|
||||
show: computed(() => {
|
||||
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
||||
}),
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
column: {
|
||||
show: computed(() => {
|
||||
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
||||
}),
|
||||
width: 100,
|
||||
},
|
||||
},
|
||||
pipelineId: {
|
||||
title: "流水线Id",
|
||||
type: "number",
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
column: {
|
||||
width: 100,
|
||||
},
|
||||
},
|
||||
pipelineTitle: {
|
||||
title: "流水线名称",
|
||||
type: "text",
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
column: {
|
||||
width: 300,
|
||||
tooltip: true,
|
||||
ellipsis: true,
|
||||
cellRender: ({ row, value }) => {
|
||||
return <router-link to={{ path: "/certd/pipeline/detail", query: { id: row.pipelineId, editMode: false, historyId: row.id } }}>{value}</router-link>;
|
||||
},
|
||||
},
|
||||
},
|
||||
triggerType: {
|
||||
title: "触发类型",
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
dict: dict({
|
||||
data: [
|
||||
{ value: "user", label: "手动执行" },
|
||||
{ value: "timer", label: "定时执行" },
|
||||
],
|
||||
}),
|
||||
form: {
|
||||
show: false,
|
||||
value: "custom",
|
||||
},
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 90,
|
||||
align: "center",
|
||||
show: true,
|
||||
component: {
|
||||
color: "auto",
|
||||
},
|
||||
},
|
||||
},
|
||||
status: {
|
||||
title: "状态",
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
dict: dict({
|
||||
data: statusUtil.getOptions(),
|
||||
}),
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 120,
|
||||
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,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
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,
|
||||
},
|
||||
actionbar: {
|
||||
buttons: {
|
||||
add: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
search: {
|
||||
formItem: {
|
||||
labelCol: {
|
||||
style: {
|
||||
// width: "100px"
|
||||
},
|
||||
},
|
||||
wrapperCol: {
|
||||
style: {
|
||||
width: "50%",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
rowHandle: {
|
||||
minWidth: 200,
|
||||
fixed: "right",
|
||||
buttons: {
|
||||
edit: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
id: {
|
||||
title: "ID",
|
||||
key: "id",
|
||||
type: "number",
|
||||
column: {
|
||||
width: 100,
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
userId: {
|
||||
title: t("certd.fields.userId"),
|
||||
type: "number",
|
||||
search: {
|
||||
show: computed(() => {
|
||||
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
||||
}),
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
column: {
|
||||
show: computed(() => {
|
||||
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
||||
}),
|
||||
width: 100,
|
||||
},
|
||||
},
|
||||
pipelineId: {
|
||||
title: t("certd.fields.pipelineId"),
|
||||
type: "number",
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
column: {
|
||||
width: 100,
|
||||
},
|
||||
},
|
||||
pipelineTitle: {
|
||||
title: t('certd.fields.pipelineName'),
|
||||
type: "text",
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
column: {
|
||||
width: 300,
|
||||
tooltip: true,
|
||||
ellipsis: true,
|
||||
cellRender: ({ row, value }) => {
|
||||
return <router-link to={{ path: "/certd/pipeline/detail", query: { id: row.pipelineId, editMode: false, historyId: row.id } }}>{value}</router-link>;
|
||||
},
|
||||
},
|
||||
},
|
||||
triggerType: {
|
||||
title: t("certd.fields.triggerType"),
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
dict: dict({
|
||||
data: [
|
||||
{ value: "user", label: t("certd.triggerTypes.manual") },
|
||||
{ value: "timer", label: t("certd.triggerTypes.timer") },
|
||||
],
|
||||
}),
|
||||
form: {
|
||||
show: false,
|
||||
value: "custom",
|
||||
},
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 90,
|
||||
align: "center",
|
||||
show: true,
|
||||
component: {
|
||||
color: "auto",
|
||||
},
|
||||
},
|
||||
},
|
||||
status: {
|
||||
title: t("certd.fields.status"),
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
dict: dict({
|
||||
data: statusUtil.getOptions(),
|
||||
}),
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 120,
|
||||
align: "center",
|
||||
},
|
||||
},
|
||||
createTime: {
|
||||
title: t("certd.fields.createTime"),
|
||||
type: "datetime",
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 160,
|
||||
align: "center",
|
||||
},
|
||||
},
|
||||
updateTime: {
|
||||
title: t("certd.fields.updateTime"),
|
||||
type: "datetime",
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
column: {
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<fs-page class="page-cert">
|
||||
<template #header>
|
||||
<div class="title">流水线执行记录</div>
|
||||
<div class="title">{{ t("certd.pipelineExecutionRecords") }}</div>
|
||||
</template>
|
||||
<fs-crud ref="crudRef" v-bind="crudBinding">
|
||||
<template #pagination-left>
|
||||
<a-tooltip title="批量删除">
|
||||
<a-tooltip :title="t('certd.batchDelete')">
|
||||
<fs-button icon="DeleteOutlined" @click="handleBatchDelete"></fs-button>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
@@ -13,12 +13,16 @@
|
||||
</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: "PipelineHistory",
|
||||
@@ -29,17 +33,17 @@ const selectedRowKeys = context.selectedRowKeys;
|
||||
const handleBatchDelete = () => {
|
||||
if (selectedRowKeys.value?.length > 0) {
|
||||
Modal.confirm({
|
||||
title: "确认",
|
||||
content: `确定要批量删除这${selectedRowKeys.value.length}条记录吗`,
|
||||
title: t("certd.confirm"),
|
||||
content: t("certd.confirmBatchDeleteContent", { count: selectedRowKeys.value.length }),
|
||||
async onOk() {
|
||||
await DeleteBatch(selectedRowKeys.value);
|
||||
message.info("删除成功");
|
||||
message.info(t("certd.deleteSuccess"));
|
||||
crudExpose.doRefresh();
|
||||
selectedRowKeys.value = [];
|
||||
},
|
||||
});
|
||||
} else {
|
||||
message.error("请先勾选记录");
|
||||
message.error(t("certd.pleaseSelectRecords"));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
<template>
|
||||
<a-button v-if="showButton" type="primary" @click="open">修改密码</a-button>
|
||||
<a-button v-if="showButton" type="primary" @click="open">
|
||||
{{ $t("passwordForm.changePasswordButton") }}
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
import { CrudOptions, useColumns, useFormWrapper } from "@fast-crud/fast-crud";
|
||||
import * as api from "/@/views/certd/mine/api";
|
||||
import { notification } from "ant-design-vue";
|
||||
@@ -17,23 +22,24 @@ let passwordFormRef = ref();
|
||||
|
||||
const validatePass1 = async (rule: any, value: any) => {
|
||||
if (value === "") {
|
||||
throw new Error("请输入密码");
|
||||
throw new Error(t("passwordForm.enterPassword"));
|
||||
}
|
||||
const formData = passwordFormRef.value.getFormData();
|
||||
if (formData.confirmNewPassword !== "") {
|
||||
passwordFormRef.value.formRef.formRef.validateFields(["confirmNewPassword"]);
|
||||
}
|
||||
if (formData.password === formData.newPassword) {
|
||||
throw new Error("新密码不能和旧密码相同");
|
||||
throw new Error(t("passwordForm.newPasswordNotSameOld"));
|
||||
}
|
||||
};
|
||||
const validatePass2 = async (rule: any, value: any) => {
|
||||
if (value === "") {
|
||||
throw new Error("请再次输入密码");
|
||||
throw new Error(t("passwordForm.enterPasswordAgain"));
|
||||
} else if (value !== passwordFormRef.value.getFormData().newPassword) {
|
||||
throw new Error("两次输入密码不一致!");
|
||||
throw new Error(t("passwordForm.passwordsNotMatch"));
|
||||
}
|
||||
};
|
||||
|
||||
const userStore = useUserStore();
|
||||
const { openDialog } = useFormWrapper();
|
||||
const { buildFormOptions } = useColumns();
|
||||
@@ -43,7 +49,7 @@ const passwordFormOptions: CrudOptions = {
|
||||
span: 24,
|
||||
},
|
||||
wrapper: {
|
||||
title: "修改密码",
|
||||
title: t("passwordForm.title"),
|
||||
width: "500px",
|
||||
},
|
||||
async doSubmit({ form }) {
|
||||
@@ -52,34 +58,37 @@ const passwordFormOptions: CrudOptions = {
|
||||
await userStore.loadUserInfo();
|
||||
},
|
||||
async afterSubmit() {
|
||||
notification.success({ message: "修改成功" });
|
||||
notification.success({ message: t("passwordForm.successMessage") });
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
password: {
|
||||
title: "旧密码",
|
||||
title: t("passwordForm.oldPassword"),
|
||||
type: "password",
|
||||
form: {
|
||||
rules: [{ required: true, message: "请输入旧密码" }],
|
||||
rules: [{ required: true, message: t("passwordForm.oldPasswordRequired") }],
|
||||
},
|
||||
},
|
||||
newPassword: {
|
||||
title: "新密码",
|
||||
title: t("passwordForm.newPassword"),
|
||||
type: "password",
|
||||
form: {
|
||||
rules: [
|
||||
{ required: true, message: "请输入确认密码" },
|
||||
{ required: true, message: t("passwordForm.newPasswordRequired") },
|
||||
//@ts-ignore
|
||||
{ validator: validatePass1, trigger: "blur" },
|
||||
],
|
||||
},
|
||||
},
|
||||
confirmNewPassword: {
|
||||
title: "确认新密码",
|
||||
title: t("passwordForm.confirmNewPassword"),
|
||||
type: "password",
|
||||
form: {
|
||||
rules: [
|
||||
{ required: true, message: "请输入确认密码" },
|
||||
{
|
||||
required: true,
|
||||
message: t("passwordForm.confirmNewPasswordRequired"),
|
||||
},
|
||||
//@ts-ignore
|
||||
{ validator: validatePass2, trigger: "blur" },
|
||||
],
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<fs-page class="page-cert">
|
||||
<template #header>
|
||||
<div class="title">我的流水线</div>
|
||||
<div class="title">{{ t("certd.myPipelines") }}</div>
|
||||
</template>
|
||||
<fs-crud ref="crudRef" v-bind="crudBinding">
|
||||
<div v-if="selectedRowKeys.length > 0" class="batch-actions">
|
||||
<div class="batch-actions-inner">
|
||||
<span> 已选择 {{ selectedRowKeys.length }} 项 </span>
|
||||
<fs-button icon="ion:trash-outline" class="color-red" type="link" text="批量删除" @click="batchDelete"></fs-button>
|
||||
<fs-button icon="icon-park-outline:replay-music" class="need-plus" type="link" text="强制重新运行" @click="batchRerun"></fs-button>
|
||||
<span>{{ t("certd.selectedCount", { count: selectedRowKeys.length }) }}</span>
|
||||
<fs-button icon="ion:trash-outline" class="color-red" type="link" :text="t('certd.batchDelete')" @click="batchDelete"></fs-button>
|
||||
<fs-button icon="icon-park-outline:replay-music" class="need-plus" type="link" :text="t('certd.batchForceRerun')" @click="batchRerun"></fs-button>
|
||||
<change-group class="color-green" :selected-row-keys="selectedRowKeys" @change="batchFinished"></change-group>
|
||||
<change-notification class="color-green" :selected-row-keys="selectedRowKeys" @change="batchFinished"></change-notification>
|
||||
<change-trigger class="color-green" :selected-row-keys="selectedRowKeys" @change="batchFinished"></change-trigger>
|
||||
@@ -16,12 +16,13 @@
|
||||
</div>
|
||||
<template #actionbar-right> </template>
|
||||
<template #form-bottom>
|
||||
<div>申请证书</div>
|
||||
<div>{{ t("certd.applyCertificate") }}</div>
|
||||
</template>
|
||||
</fs-crud>
|
||||
</fs-page>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onActivated, onMounted, ref } from "vue";
|
||||
import { dict, useFs } from "@fast-crud/fast-crud";
|
||||
@@ -31,6 +32,9 @@ import ChangeGroup from "./components/change-group.vue";
|
||||
import ChangeTrigger from "./components/change-trigger.vue";
|
||||
import { Modal, notification } from "ant-design-vue";
|
||||
import * as api from "./api";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
import ChangeNotification from "/@/views/certd/pipeline/components/change-notification.vue";
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,32 +1,46 @@
|
||||
<template>
|
||||
<a-modal v-model:open="openRef" class="order-modal" title="订单确认" @ok="orderCreate">
|
||||
<a-modal v-model:open="openRef" class="order-modal" :title="$t('order.confirmTitle')" @ok="orderCreate">
|
||||
<div v-if="product" class="order-box">
|
||||
<div class="flex-o mt-5"><span class="label">套餐:</span>{{ product.title }}</div>
|
||||
<div class="flex-o mt-5"><span class="label">说明:</span>{{ product.intro }}</div>
|
||||
<div class="flex-o mt-5">
|
||||
<span class="label">规格:</span>
|
||||
<span class="label">{{$t('order.package')}}:</span>{{ product.title }}
|
||||
</div>
|
||||
<div class="flex-o mt-5">
|
||||
<span class="label">{{$t('order.description')}}:</span>{{ product.intro }}
|
||||
</div>
|
||||
<div class="flex-o mt-5">
|
||||
<span class="label">{{$t('order.specifications')}}:</span>
|
||||
<span class="flex-o flex-wrap">
|
||||
<span class="flex-o">流水线<suite-value class="ml-5" :model-value="product.content.maxPipelineCount" unit="条" />;</span>
|
||||
<span class="flex-o">域名<suite-value class="ml-5" :model-value="product.content.maxDomainCount" unit="个" />;</span>
|
||||
<span class="flex-o">部署次数<suite-value class="ml-5" :model-value="product.content.maxDeployCount" unit="次" />;</span>
|
||||
<span class="flex-o">
|
||||
{{$t('order.pipeline')}}<suite-value class="ml-5" :model-value="product.content.maxPipelineCount" unit="{{$t('order.unit.pieces')}}" />;
|
||||
</span>
|
||||
<span class="flex-o">
|
||||
{{$t('order.domain')}}<suite-value class="ml-5" :model-value="product.content.maxDomainCount" unit="{{$t('order.unit.count')}}" />;
|
||||
</span>
|
||||
<span class="flex-o">
|
||||
{{$t('order.deployTimes')}}<suite-value class="ml-5" :model-value="product.content.maxDeployCount" unit="{{$t('order.unit.times')}}" />;
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flex-o mt-5">
|
||||
<span class="label">时长:</span>
|
||||
<span class="label">{{$t('order.duration')}}:</span>
|
||||
<duration-value v-model="formRef.duration"></duration-value>
|
||||
</div>
|
||||
<div class="flex-o mt-5"><span class="label">价格:</span> <price-input :edit="false" :model-value="durationSelected.price"></price-input></div>
|
||||
<div class="flex-o mt-5">
|
||||
<span class="label">{{$t('order.price')}}:</span>
|
||||
<price-input :edit="false" :model-value="durationSelected.price"></price-input>
|
||||
</div>
|
||||
|
||||
<div class="flex-o mt-5">
|
||||
<span class="label">支付方式:</span>
|
||||
<div v-if="durationSelected.price === 0">免费</div>
|
||||
<span class="label">{{$t('order.paymentMethod')}}:</span>
|
||||
<div v-if="durationSelected.price === 0">{{$t('order.free')}}</div>
|
||||
<fs-dict-select v-else v-model:value="formRef.payType" :dict="paymentsDictRef" style="width: 200px"> </fs-dict-select>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup lang="tsx">
|
||||
import { ref } from "vue";
|
||||
import { GetPaymentTypes, OrderModalOpenReq, TradeCreate } from "/@/views/certd/suite/api";
|
||||
|
||||
@@ -11,19 +11,21 @@
|
||||
<div class="text">
|
||||
<div class="left">
|
||||
<div>
|
||||
<span>您好,{{ userInfo.nickName || userInfo.username }}, 欢迎使用 【{{ siteInfo.title }}】</span>
|
||||
<span>{{ t('certd.dashboard.greeting', { name: userInfo.nickName || userInfo.username, site: siteInfo.title }) }}</span>
|
||||
</div>
|
||||
<div class="flex-o flex-wrap profile-badges">
|
||||
<a-tooltip :title="deltaTimeTip">
|
||||
<a-badge :dot="deltaTimeWarning">
|
||||
<a-tag :color="deltaTimeWarning ? 'red' : 'green'" class="flex-inline pointer"> <fs-icon icon="ion:time-outline"></fs-icon> {{ now }}</a-tag>
|
||||
<a-tag :color="deltaTimeWarning ? 'red' : 'green'" class="flex-inline pointer">
|
||||
<fs-icon icon="ion:time-outline"></fs-icon> {{ now }}
|
||||
</a-tag>
|
||||
</a-badge>
|
||||
</a-tooltip>
|
||||
|
||||
<template v-if="userStore.isAdmin">
|
||||
<a-divider type="vertical" />
|
||||
<a-badge :dot="hasNewVersion">
|
||||
<a-tag color="blue" class="flex-inline pointer mr-0" :title="'最新版本:' + latestVersion" @click="openUpgradeUrl()">
|
||||
<a-tag color="blue" class="flex-inline pointer mr-0" :title="t('certd.dashboard.latestVersion', { version: latestVersion })" @click="openUpgradeUrl()">
|
||||
<fs-icon icon="ion:rocket-outline" class="mr-5"></fs-icon>
|
||||
v{{ version }}
|
||||
</a-tag>
|
||||
@@ -37,7 +39,7 @@
|
||||
</template>
|
||||
<template v-if="settingsStore.isPlus && settingsStore.sysPublic.userValidTimeEnabled === true && userInfo.validTime">
|
||||
<a-divider type="vertical" />
|
||||
<valid-time-format class="flex-o" prefix="账户有效期:" :model-value="userInfo.validTime" />
|
||||
<valid-time-format class="flex-o" :prefix="t('certd.dashboard.validUntil')" :model-value="userInfo.validTime" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -46,9 +48,9 @@
|
||||
|
||||
<div class="suggest hidden md:block">
|
||||
<tutorial-button class="flex-center mt-2">
|
||||
<a-tooltip title="点击查看详细教程">
|
||||
<a-tooltip :title="t('certd.dashboard.tutorialTooltip')">
|
||||
<a-tag color="blue" class="flex-center">
|
||||
仅需3步,全自动申请部署证书
|
||||
{{ t('certd.dashboard.tutorialText') }}
|
||||
<fs-icon class="font-size-16 ml-5" icon="mingcute:question-line"></fs-icon>
|
||||
</a-tag>
|
||||
</a-tooltip>
|
||||
@@ -59,9 +61,10 @@
|
||||
<div v-if="!settingStore.isComm" class="warning">
|
||||
<a-alert type="warning" show-icon>
|
||||
<template #message>
|
||||
证书和授权为敏感信息,不要使用来历不明的在线Certd服务和镜像,以免泄露;请务必私有化部署使用,认准官方版本发布渠道:
|
||||
<a class="ml-5 flex-inline" href="https://gitee.com/certd/certd" target="_blank">gitee</a>、 <a class="ml-5 flex-inline" href="https://github.com/certd/certd" target="_blank">github</a>、
|
||||
<a class="ml-5 flex-inline" href="https://certd.docmirror.cn" target="_blank">帮助文档</a>
|
||||
{{ t('certd.dashboard.alertMessage') }}
|
||||
<a class="ml-5 flex-inline" href="https://gitee.com/certd/certd" target="_blank">gitee</a>、
|
||||
<a class="ml-5 flex-inline" href="https://github.com/certd/certd" target="_blank">github</a>、
|
||||
<a class="ml-5 flex-inline" href="https://certd.docmirror.cn" target="_blank">{{ t('certd.dashboard.helpDoc') }}</a>
|
||||
</template>
|
||||
</a-alert>
|
||||
</div>
|
||||
@@ -69,30 +72,32 @@
|
||||
<div class="statistic-data m-20">
|
||||
<a-row :gutter="20" class="flex-wrap">
|
||||
<a-col :md="6" :xs="24">
|
||||
<statistic-card title="证书流水线数量" :count="count.pipelineCount">
|
||||
<statistic-card :title="t('certd.dashboard.pipelineCount')" :count="count.pipelineCount">
|
||||
<template v-if="count.pipelineCount === 0" #default>
|
||||
<div class="flex-center flex-1 flex-col">
|
||||
<div style="font-size: 18px; font-weight: 700">您还没有证书流水线</div>
|
||||
<fs-button type="primary" class="mt-10" icon="ion:add-circle-outline" @click="goPipeline">立即创建</fs-button>
|
||||
<div style="font-size: 18px; font-weight: 700">{{ t('certd.dashboard.noPipeline') }}</div>
|
||||
<fs-button type="primary" class="mt-10" icon="ion:add-circle-outline" @click="goPipeline">{{ t('certd.dashboard.createNow') }}</fs-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<router-link to="/certd/pipeline" class="flex"><fs-icon icon="ion:settings-outline" class="mr-5 fs-16" /> 管理流水线</router-link>
|
||||
<router-link to="/certd/pipeline" class="flex">
|
||||
<fs-icon icon="ion:settings-outline" class="mr-5 fs-16" /> {{ t('certd.dashboard.managePipeline') }}
|
||||
</router-link>
|
||||
</template>
|
||||
</statistic-card>
|
||||
</a-col>
|
||||
<a-col :md="6" :xs="24">
|
||||
<statistic-card title="流水线状态" :footer="false">
|
||||
<statistic-card :title="t('certd.dashboard.pipelineStatus')" :footer="false">
|
||||
<pie-count v-if="count.pipelineStatusCount" :data="count.pipelineStatusCount"></pie-count>
|
||||
</statistic-card>
|
||||
</a-col>
|
||||
<a-col :md="6" :xs="24">
|
||||
<statistic-card title="最近运行统计" :footer="false">
|
||||
<day-count v-if="count.historyCountPerDay" :data="count.historyCountPerDay" title="运行次数"></day-count>
|
||||
<statistic-card :title="t('certd.dashboard.recentRun')" :footer="false">
|
||||
<day-count v-if="count.historyCountPerDay" :data="count.historyCountPerDay" :title="t('certd.dashboard.runCount')"></day-count>
|
||||
</statistic-card>
|
||||
</a-col>
|
||||
<a-col :md="6" :xs="24">
|
||||
<statistic-card title="最快到期证书">
|
||||
<statistic-card :title="t('certd.dashboard.expiringCerts')">
|
||||
<expiring-list v-if="count.expiringList" :data="count.expiringList"></expiring-list>
|
||||
</statistic-card>
|
||||
</a-col>
|
||||
@@ -102,7 +107,8 @@
|
||||
<div v-if="pluginGroups" class="plugin-list">
|
||||
<a-card>
|
||||
<template #title>
|
||||
已支持的部署任务总览 <a-tag color="green">{{ pluginGroups.groups.all.plugins.length }}</a-tag>
|
||||
{{ t('certd.dashboard.supportedTasks') }}
|
||||
<a-tag color="green">{{ pluginGroups.groups.all.plugins.length }}</a-tag>
|
||||
</template>
|
||||
<a-row :gutter="10">
|
||||
<a-col v-for="item of pluginGroups.groups.all.plugins" :key="item.name" class="plugin-item-col" :xl="4" :md="6" :xs="24">
|
||||
@@ -130,6 +136,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { FsIcon } from "@fast-crud/fast-crud";
|
||||
import SimpleSteps from "/@/components/tutorial/simple-steps.vue";
|
||||
@@ -148,6 +155,8 @@ import { UserInfoRes } from "/@/store/user/api.user";
|
||||
import { GetStatisticCount } from "/@/views/framework/home/dashboard/api";
|
||||
import { useRouter } from "vue-router";
|
||||
import * as api from "./api";
|
||||
import { useI18n } from "vue-i18n";
|
||||
const { t } = useI18n();
|
||||
import { usePluginStore } from "/@/store/plugin";
|
||||
defineOptions({
|
||||
name: "DashboardUser",
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
<fs-page class="home—index bg-neutral-100 dark:bg-black">
|
||||
<!-- <page-content />-->
|
||||
<dashboard-user />
|
||||
<change-password-button ref="changePasswordButtonRef" :show-button="false"></change-password-button>
|
||||
<change-password-button
|
||||
ref="changePasswordButtonRef"
|
||||
:show-button="false"
|
||||
></change-password-button>
|
||||
</fs-page>
|
||||
</template>
|
||||
|
||||
@@ -12,20 +15,23 @@ import { useUserStore } from "/@/store/user";
|
||||
import ChangePasswordButton from "/@/views/certd/mine/change-password-button.vue";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { Modal } from "ant-design-vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const userStore = useUserStore();
|
||||
const changePasswordButtonRef = ref();
|
||||
onMounted(() => {
|
||||
if (userStore.getUserInfo.isWeak === true) {
|
||||
Modal.info({
|
||||
title: "修改密码",
|
||||
content: "为了您的账户安全,请立即修改密码",
|
||||
title: t("passwordForm.title"),
|
||||
content: t("passwordForm.weakPasswordWarning"),
|
||||
onOk: () => {
|
||||
changePasswordButtonRef.value.open({
|
||||
password: "123456",
|
||||
});
|
||||
},
|
||||
okText: "立即修改",
|
||||
okText: t("passwordForm.changeNow"),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,74 +1,96 @@
|
||||
<template>
|
||||
<div class="main login-page">
|
||||
<a-form v-if="!twoFactor.loginId" ref="formRef" class="user-layout-login" name="custom-validation" :model="formState" v-bind="layout" @finish="handleFinish" @finish-failed="handleFinishFailed">
|
||||
<!-- <div class="login-title">登录</div>-->
|
||||
<a-tabs v-model:active-key="formState.loginType" :tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
|
||||
<a-tab-pane key="password" tab="密码登录" :disabled="sysPublicSettings.passwordLoginEnabled !== true">
|
||||
<template v-if="formState.loginType === 'password'">
|
||||
<!-- <div class="login-title">登录</div>-->
|
||||
<a-form-item required has-feedback name="username" :rules="rules.username">
|
||||
<a-input v-model:value="formState.username" placeholder="请输入用户名/邮箱/手机号" autocomplete="off">
|
||||
<template #prefix>
|
||||
<fs-icon icon="ion:phone-portrait-outline"></fs-icon>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item has-feedback name="password" :rules="rules.password">
|
||||
<a-input-password v-model:value="formState.password" placeholder="请输入密码" autocomplete="off">
|
||||
<template #prefix>
|
||||
<fs-icon icon="ion:lock-closed-outline"></fs-icon>
|
||||
</template>
|
||||
</a-input-password>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="sms" tab="短信验证码登录" :disabled="sysPublicSettings.smsLoginEnabled !== true">
|
||||
<template v-if="formState.loginType === 'sms'">
|
||||
<a-form-item has-feedback name="mobile" :rules="rules.mobile">
|
||||
<a-input v-model:value="formState.mobile" placeholder="请输入手机号" autocomplete="off">
|
||||
<template #prefix>
|
||||
<fs-icon icon="ion:phone-portrait-outline"></fs-icon>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item has-feedback name="imgCode">
|
||||
<image-code v-model:value="formState.imgCode" v-model:random-str="formState.randomStr"></image-code>
|
||||
</a-form-item>
|
||||
<div class="main login-page">
|
||||
<a-form v-if="!twoFactor.loginId" ref="formRef" class="user-layout-login" name="custom-validation"
|
||||
:model="formState" v-bind="layout" @finish="handleFinish" @finish-failed="handleFinishFailed">
|
||||
<!-- <div class="login-title">登录</div>-->
|
||||
<a-tabs v-model:active-key="formState.loginType"
|
||||
:tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
|
||||
<a-tab-pane key="password" :tab="$t('authentication.passwordTab')"
|
||||
:disabled="sysPublicSettings.passwordLoginEnabled !== true">
|
||||
<template v-if="formState.loginType === 'password'">
|
||||
<!-- <div class="login-title">登录</div>-->
|
||||
<a-form-item required has-feedback name="username" :rules="rules.username">
|
||||
<a-input v-model:value="formState.username"
|
||||
:placeholder="$t('authentication.usernamePlaceholder')" autocomplete="off">
|
||||
<template #prefix>
|
||||
<fs-icon icon="ion:phone-portrait-outline"></fs-icon>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item has-feedback name="password" :rules="rules.password">
|
||||
<a-input-password v-model:value="formState.password"
|
||||
:placeholder="$t('authentication.passwordPlaceholder')" autocomplete="off">
|
||||
<template #prefix>
|
||||
<fs-icon icon="ion:lock-closed-outline"></fs-icon>
|
||||
</template>
|
||||
</a-input-password>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="sms" :tab="$t('authentication.smsTab')"
|
||||
:disabled="sysPublicSettings.smsLoginEnabled !== true">
|
||||
<template v-if="formState.loginType === 'sms'">
|
||||
<a-form-item has-feedback name="mobile" :rules="rules.mobile">
|
||||
<a-input v-model:value="formState.mobile"
|
||||
:placeholder="$t('authentication.mobilePlaceholder')" autocomplete="off">
|
||||
<template #prefix>
|
||||
<fs-icon icon="ion:phone-portrait-outline"></fs-icon>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item name="smsCode" :rules="rules.smsCode">
|
||||
<sms-code v-model:value="formState.smsCode" :img-code="formState.imgCode" :mobile="formState.mobile" :phone-code="formState.phoneCode" :random-str="formState.randomStr" />
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
<a-form-item>
|
||||
<a-button type="primary" size="large" html-type="submit" :loading="loading" class="login-button">登录</a-button>
|
||||
<a-form-item has-feedback name="imgCode">
|
||||
<image-code v-model:value="formState.imgCode"
|
||||
v-model:random-str="formState.randomStr"></image-code>
|
||||
</a-form-item>
|
||||
|
||||
<div v-if="!settingStore.isComm" class="mt-2"><a href="https://certd.docmirror.cn/guide/use/forgotpasswd/" target="_blank">忘记管理员密码?</a></div>
|
||||
</a-form-item>
|
||||
<a-form-item name="smsCode" :rules="rules.smsCode">
|
||||
<sms-code v-model:value="formState.smsCode" :img-code="formState.imgCode"
|
||||
:mobile="formState.mobile" :phone-code="formState.phoneCode"
|
||||
:random-str="formState.randomStr" />
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
<a-form-item>
|
||||
<a-button type="primary" size="large" html-type="submit" :loading="loading" class="login-button">
|
||||
{{ $t('authentication.loginButton') }}
|
||||
</a-button>
|
||||
|
||||
<a-form-item class="user-login-other">
|
||||
<router-link v-if="hasRegisterTypeEnabled()" class="register" :to="{ name: 'register' }"> 注册 </router-link>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<a-form v-else ref="twoFactorFormRef" class="user-layout-login" :model="twoFactor" v-bind="layout">
|
||||
<div class="mb-10 flex flex-center">请打开您的Authenticator APP,获取动态验证码。</div>
|
||||
<a-form-item name="verifyCode">
|
||||
<a-input ref="verifyCodeInputRef" v-model:value="twoFactor.verifyCode" placeholder="请输入动态验证码" allow-clear @keydown.enter="handleTwoFactorSubmit">
|
||||
<template #prefix>
|
||||
<fs-icon icon="ion:lock-closed-outline"></fs-icon>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<loading-button type="primary" size="large" html-type="button" class="login-button" :click="handleTwoFactorSubmit">OTP验证登录</loading-button>
|
||||
</a-form-item>
|
||||
<div v-if="!settingStore.isComm" class="mt-2">
|
||||
<a href="https://certd.docmirror.cn/guide/use/forgotpasswd/" target="_blank">
|
||||
{{ $t('authentication.forgotAdminPassword') }}
|
||||
</a>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item class="user-login-other">
|
||||
<a class="register" @click="twoFactor.loginId = null"> 返回 </a>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
<a-form-item class="user-login-other">
|
||||
<router-link v-if="hasRegisterTypeEnabled()" class="register" :to="{ name: 'register' }">
|
||||
{{ $t('authentication.registerLink') }}
|
||||
</router-link>
|
||||
</a-form-item>
|
||||
|
||||
</a-form>
|
||||
<a-form v-else ref="twoFactorFormRef" class="user-layout-login" :model="twoFactor" v-bind="layout">
|
||||
<div class="mb-10 flex flex-center">请打开您的Authenticator APP,获取动态验证码。</div>
|
||||
<a-form-item name="verifyCode">
|
||||
<a-input ref="verifyCodeInputRef" v-model:value="twoFactor.verifyCode" placeholder="请输入动态验证码"
|
||||
allow-clear @keydown.enter="handleTwoFactorSubmit">
|
||||
<template #prefix>
|
||||
<fs-icon icon="ion:lock-closed-outline"></fs-icon>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<loading-button type="primary" size="large" html-type="button" class="login-button"
|
||||
:click="handleTwoFactorSubmit">OTP验证登录</loading-button>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item class="user-login-other">
|
||||
<a class="register" @click="twoFactor.loginId = null"> 返回 </a>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, nextTick, reactive, ref, toRaw } from "vue";
|
||||
@@ -79,200 +101,208 @@ import ImageCode from "/@/views/framework/login/image-code.vue";
|
||||
import SmsCode from "/@/views/framework/login/sms-code.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "LoginPage",
|
||||
components: { SmsCode, ImageCode },
|
||||
setup() {
|
||||
const verifyCodeInputRef = ref();
|
||||
const loading = ref(false);
|
||||
const userStore = useUserStore();
|
||||
const settingStore = useSettingStore();
|
||||
const formRef = ref();
|
||||
const formState = reactive({
|
||||
username: "",
|
||||
phoneCode: "86",
|
||||
mobile: "",
|
||||
password: "",
|
||||
loginType: "password", //password
|
||||
imgCode: "",
|
||||
smsCode: "",
|
||||
randomStr: "",
|
||||
});
|
||||
name: "LoginPage",
|
||||
components: { SmsCode, ImageCode },
|
||||
setup() {
|
||||
const verifyCodeInputRef = ref();
|
||||
const loading = ref(false);
|
||||
const userStore = useUserStore();
|
||||
const settingStore = useSettingStore();
|
||||
const formRef = ref();
|
||||
const formState = reactive({
|
||||
username: "",
|
||||
phoneCode: "86",
|
||||
mobile: "",
|
||||
password: "",
|
||||
loginType: "password", //password
|
||||
imgCode: "",
|
||||
smsCode: "",
|
||||
randomStr: "",
|
||||
});
|
||||
|
||||
const rules = {
|
||||
mobile: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入手机号",
|
||||
},
|
||||
],
|
||||
username: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入用户名",
|
||||
},
|
||||
],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入登录密码",
|
||||
},
|
||||
],
|
||||
smsCode: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入短信验证码",
|
||||
},
|
||||
],
|
||||
};
|
||||
const layout = {
|
||||
labelCol: {
|
||||
span: 0,
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 24,
|
||||
},
|
||||
};
|
||||
const rules = {
|
||||
mobile: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入手机号",
|
||||
},
|
||||
],
|
||||
username: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入用户名",
|
||||
},
|
||||
],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入登录密码",
|
||||
},
|
||||
],
|
||||
smsCode: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入短信验证码",
|
||||
},
|
||||
],
|
||||
};
|
||||
const layout = {
|
||||
labelCol: {
|
||||
span: 0,
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 24,
|
||||
},
|
||||
};
|
||||
|
||||
const twoFactor = reactive({
|
||||
loginId: "",
|
||||
verifyCode: "",
|
||||
});
|
||||
const twoFactor = reactive({
|
||||
loginId: "",
|
||||
verifyCode: "",
|
||||
});
|
||||
|
||||
const handleTwoFactorSubmit = async () => {
|
||||
await userStore.loginByTwoFactor(twoFactor);
|
||||
};
|
||||
const handleTwoFactorSubmit = async () => {
|
||||
await userStore.loginByTwoFactor(twoFactor);
|
||||
};
|
||||
|
||||
const handleFinish = async (values: any) => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const loginType = formState.loginType;
|
||||
await userStore.login(loginType, toRaw(formState));
|
||||
} catch (e: any) {
|
||||
//@ts-ignore
|
||||
if (e.code === 10020) {
|
||||
//双重认证
|
||||
//@ts-ignore
|
||||
twoFactor.loginId = e.data;
|
||||
await nextTick();
|
||||
verifyCodeInputRef.value.focus();
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
const handleFinish = async (values: any) => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const loginType = formState.loginType;
|
||||
await userStore.login(loginType, toRaw(formState));
|
||||
} catch (e: any) {
|
||||
//@ts-ignore
|
||||
if (e.code === 10020) {
|
||||
//双重认证
|
||||
//@ts-ignore
|
||||
twoFactor.loginId = e.data;
|
||||
await nextTick();
|
||||
verifyCodeInputRef.value.focus();
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleFinishFailed = (errors: any) => {
|
||||
utils.logger.log(errors);
|
||||
};
|
||||
const handleFinishFailed = (errors: any) => {
|
||||
utils.logger.log(errors);
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
formRef.value.resetFields();
|
||||
};
|
||||
const resetForm = () => {
|
||||
formRef.value.resetFields();
|
||||
};
|
||||
|
||||
const isLoginError = ref();
|
||||
const isLoginError = ref();
|
||||
|
||||
const sysPublicSettings = settingStore.getSysPublic;
|
||||
const sysPublicSettings = settingStore.getSysPublic;
|
||||
|
||||
function hasRegisterTypeEnabled() {
|
||||
return sysPublicSettings.registerEnabled && (sysPublicSettings.usernameRegisterEnabled || sysPublicSettings.emailRegisterEnabled);
|
||||
}
|
||||
function hasRegisterTypeEnabled() {
|
||||
return sysPublicSettings.registerEnabled && (sysPublicSettings.usernameRegisterEnabled || sysPublicSettings.emailRegisterEnabled);
|
||||
}
|
||||
|
||||
return {
|
||||
loading,
|
||||
formState,
|
||||
formRef,
|
||||
rules,
|
||||
layout,
|
||||
handleFinishFailed,
|
||||
handleFinish,
|
||||
resetForm,
|
||||
isLoginError,
|
||||
sysPublicSettings,
|
||||
hasRegisterTypeEnabled,
|
||||
twoFactor,
|
||||
handleTwoFactorSubmit,
|
||||
verifyCodeInputRef,
|
||||
settingStore,
|
||||
};
|
||||
},
|
||||
return {
|
||||
loading,
|
||||
formState,
|
||||
formRef,
|
||||
rules,
|
||||
layout,
|
||||
handleFinishFailed,
|
||||
handleFinish,
|
||||
resetForm,
|
||||
isLoginError,
|
||||
sysPublicSettings,
|
||||
hasRegisterTypeEnabled,
|
||||
twoFactor,
|
||||
handleTwoFactorSubmit,
|
||||
verifyCodeInputRef,
|
||||
settingStore,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import "../../../style/theme/index.less";
|
||||
|
||||
.login-page.main {
|
||||
//margin: 20px !important;
|
||||
margin-bottom: 100px;
|
||||
.user-layout-login {
|
||||
//label {
|
||||
// font-size: 14px;
|
||||
//}
|
||||
//margin: 20px !important;
|
||||
margin-bottom: 100px;
|
||||
|
||||
.login-title {
|
||||
color: @primary-color;
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
margin: 20px;
|
||||
}
|
||||
.getCaptcha {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
.user-layout-login {
|
||||
//label {
|
||||
// font-size: 14px;
|
||||
//}
|
||||
|
||||
.image-code {
|
||||
height: 34px;
|
||||
}
|
||||
.input-right {
|
||||
width: 160px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.forge-password {
|
||||
font-size: 14px;
|
||||
}
|
||||
.login-title {
|
||||
color: @primary-color;
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
button.login-button {
|
||||
padding: 0 15px;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
.getCaptcha {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.user-login-other {
|
||||
text-align: left;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
//line-height: 22px;
|
||||
.image-code {
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
.item-icon {
|
||||
font-size: 24px;
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
margin-left: 16px;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s;
|
||||
.input-right {
|
||||
width: 160px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
.forge-password {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.register {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.fs-icon {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
margin-right: 4px;
|
||||
}
|
||||
.ant-input-affix-wrapper {
|
||||
line-height: 1.8 !important;
|
||||
font-size: 14px !important;
|
||||
> * {
|
||||
line-height: 1.8 !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
button.login-button {
|
||||
padding: 0 15px;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.user-login-other {
|
||||
text-align: left;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
//line-height: 22px;
|
||||
|
||||
.item-icon {
|
||||
font-size: 24px;
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
margin-left: 16px;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
.register {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.fs-icon {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.ant-input-affix-wrapper {
|
||||
line-height: 1.8 !important;
|
||||
font-size: 14px !important;
|
||||
|
||||
>* {
|
||||
line-height: 1.8 !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user