mirror of
https://github.com/certd/certd.git
synced 2026-04-24 04:17:25 +08:00
perf: 选项显示图标
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<a-select>
|
||||
<a-select-option v-for="item of options" :keu="item.value" :value="item.value" :label="item.label">
|
||||
<span class="flex-o">
|
||||
<fs-icon :icon="item.icon" class="fs-16 color-blue mr-5" />
|
||||
{{ item.label }}
|
||||
</span>
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const props = defineProps<{
|
||||
options: { value: any; label: string; icon: string }[];
|
||||
}>();
|
||||
</script>
|
||||
@@ -7,7 +7,8 @@ import FoldBox from "./fold-box.vue";
|
||||
import { CronLight } from "@vue-js-cron/light";
|
||||
import "@vue-js-cron/light/dist/light.css";
|
||||
import Plugins from "./plugins/index";
|
||||
|
||||
import LoadingButton from "./loading-button.vue";
|
||||
import IconSelect from "./icon-select.vue";
|
||||
export default {
|
||||
install(app: any) {
|
||||
app.component("PiContainer", PiContainer);
|
||||
@@ -22,6 +23,9 @@ export default {
|
||||
app.component("InfoCircleOutlined", InfoCircleOutlined);
|
||||
app.component("UndoOutlined", UndoOutlined);
|
||||
|
||||
app.component("LoadingButton", LoadingButton);
|
||||
app.component("IconSelect", IconSelect);
|
||||
|
||||
app.use(vip);
|
||||
app.use(Plugins);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<a-button :loading="loading" @click="onClick">
|
||||
<slot></slot>
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
const props = defineProps<{
|
||||
click?: () => Promise<void>;
|
||||
}>();
|
||||
|
||||
const loading = ref(false);
|
||||
function onClick() {
|
||||
loading.value = true;
|
||||
try {
|
||||
if (props.click) {
|
||||
props.click();
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<a-select class="dns-provider-selector" :value="modelValue" :options="options" @update:value="onChanged"> </a-select>
|
||||
<icon-select class="dns-provider-selector" :value="modelValue" :options="options" @update:value="onChanged"> </icon-select>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -24,7 +24,8 @@ export default {
|
||||
for (let item of list) {
|
||||
array.push({
|
||||
value: item.name,
|
||||
label: item.title
|
||||
label: item.title,
|
||||
icon: item.icon
|
||||
});
|
||||
}
|
||||
options.value = array;
|
||||
|
||||
@@ -12,18 +12,19 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="tsx" setup>
|
||||
import { computed, reactive } from "vue";
|
||||
import { computed, onMounted, reactive } from "vue";
|
||||
import dayjs from "dayjs";
|
||||
import { message, Modal } from "ant-design-vue";
|
||||
import * as api from "./api";
|
||||
import { useSettingStore } from "/@/store/modules/settings";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useUserStore } from "/@/store/modules/user";
|
||||
import { mitter } from "/@/utils/util.mitt";
|
||||
|
||||
const settingStore = useSettingStore();
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
mode?: "button" | "nav" | "icon";
|
||||
mode?: "comm" | "button" | "nav" | "icon";
|
||||
}>(),
|
||||
{
|
||||
mode: "button"
|
||||
@@ -36,7 +37,29 @@ type Text = {
|
||||
const text = computed<Text>(() => {
|
||||
const vipLabel = settingStore.vipLabel;
|
||||
const map = {
|
||||
isComm: {
|
||||
comm: {
|
||||
name: `${vipLabel}已开通`,
|
||||
title: "到期时间:" + expireTime.value
|
||||
},
|
||||
button: {
|
||||
name: `${vipLabel}已开通`,
|
||||
title: "到期时间:" + expireTime.value
|
||||
},
|
||||
icon: {
|
||||
name: "",
|
||||
title: `${vipLabel}已开通`
|
||||
},
|
||||
nav: {
|
||||
name: `${vipLabel}`,
|
||||
title: "到期时间:" + expireTime.value
|
||||
}
|
||||
},
|
||||
isPlus: {
|
||||
comm: {
|
||||
name: "商业版功能",
|
||||
title: "升级商业版,获取商业授权"
|
||||
},
|
||||
button: {
|
||||
name: `${vipLabel}已开通`,
|
||||
title: "到期时间:" + expireTime.value
|
||||
@@ -51,13 +74,17 @@ const text = computed<Text>(() => {
|
||||
}
|
||||
},
|
||||
free: {
|
||||
comm: {
|
||||
name: "商业版功能",
|
||||
title: "升级商业版,获取商业授权"
|
||||
},
|
||||
button: {
|
||||
name: "此为专业版功能",
|
||||
name: "专业版功能",
|
||||
title: "升级专业版,享受更多VIP特权"
|
||||
},
|
||||
icon: {
|
||||
name: "",
|
||||
title: "此为专业版功能"
|
||||
title: "专业版功能"
|
||||
},
|
||||
nav: {
|
||||
name: "基础版",
|
||||
@@ -65,7 +92,9 @@ const text = computed<Text>(() => {
|
||||
}
|
||||
}
|
||||
};
|
||||
if (settingStore.isPlus) {
|
||||
if (settingStore.isComm) {
|
||||
return map.isComm[props.mode];
|
||||
} else if (settingStore.isPlus) {
|
||||
return map.isPlus[props.mode];
|
||||
} else {
|
||||
return map.free[props.mode];
|
||||
@@ -313,6 +342,13 @@ function openUpgrade() {
|
||||
}
|
||||
});
|
||||
}
|
||||
onMounted(() => {
|
||||
mitter.on("openVipModal", () => {
|
||||
if (props.mode === "nav" && !settingStore.isPlus) {
|
||||
openUpgrade();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
@@ -169,7 +169,7 @@ export const sysResources = [
|
||||
icon: "ion:person-outline",
|
||||
permission: "sys:auth:user:view"
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// {
|
||||
// title: "商业版设置",
|
||||
|
||||
@@ -60,6 +60,11 @@ h1, h2, h3, h4, h5, h6 {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.flex-between {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -192,7 +197,9 @@ h1, h2, h3, h4, h5, h6 {
|
||||
border-bottom: 1px solid #dedede;
|
||||
}
|
||||
|
||||
|
||||
.color-plus{
|
||||
color: #c5913f;
|
||||
}
|
||||
.color-blue {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
@@ -87,6 +87,14 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
||||
filterOption: (input: string, option: any) => {
|
||||
input = input?.toLowerCase();
|
||||
return option.value.toLowerCase().indexOf(input) >= 0 || option.label.toLowerCase().indexOf(input) >= 0;
|
||||
},
|
||||
renderLabel(item: any) {
|
||||
return (
|
||||
<span class={"flex-o"}>
|
||||
<fs-icon icon={item.icon} class={"mr-5 fs-16 color-blue"} />
|
||||
{item.label}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
},
|
||||
rules: [{ required: true, message: "请选择类型" }],
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useReference } from "/@/use/use-refrence";
|
||||
import { forEach, get, merge, set } from "lodash-es";
|
||||
import { Modal } from "ant-design-vue";
|
||||
import * as api from "/@/views/sys/cname/provider/api";
|
||||
import { mitter } from "/@/utils/util.mitt";
|
||||
|
||||
export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
||||
provide("notificationApi", api);
|
||||
@@ -96,6 +97,14 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
||||
filterOption: (input: string, option: any) => {
|
||||
input = input?.toLowerCase();
|
||||
return option.value.toLowerCase().indexOf(input) >= 0 || option.label.toLowerCase().indexOf(input) >= 0;
|
||||
},
|
||||
renderLabel(item: any) {
|
||||
return (
|
||||
<span class={"flex-o flex-between"}>
|
||||
{item.label}
|
||||
{item.needPlus && <fs-icon icon={"mingcute:vip-1-line"} className={"color-plus"}></fs-icon>}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
},
|
||||
rules: [{ required: true, message: "请选择通知类型" }],
|
||||
@@ -112,6 +121,8 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
||||
|
||||
if (!immediate) {
|
||||
form.body = {};
|
||||
|
||||
mitter.emit("openVipModal");
|
||||
}
|
||||
|
||||
if (!form.name || form.name === lastTitle) {
|
||||
|
||||
@@ -142,7 +142,7 @@ export default defineComponent({
|
||||
},
|
||||
{
|
||||
validator: async (rule: any, value: any) => {
|
||||
if (value !== formState.password) {
|
||||
if (value && value !== formState.password) {
|
||||
throw new Error("两次输入密码不一致");
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -77,3 +77,11 @@ export async function TestProxy() {
|
||||
method: "post"
|
||||
});
|
||||
}
|
||||
|
||||
export async function TestSms(data: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/testSms",
|
||||
method: "post",
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
<!-- <div class="title">系统设置</div>-->
|
||||
<!-- </template>-->
|
||||
<div class="sys-settings-body">
|
||||
<a-tabs type="card" class="sys-settings-tabs">
|
||||
<a-tab-pane key="site" tab="基本设置">
|
||||
<SettingBase />
|
||||
<a-tabs :active-key="activeKey" type="card" class="sys-settings-tabs" @update:active-key="onChange">
|
||||
<a-tab-pane key="" tab="基本设置">
|
||||
<SettingBase v-if="activeKey === ''" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="register" tab="注册设置">
|
||||
<SettingRegister />
|
||||
<SettingRegister v-if="activeKey === 'register'" />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
@@ -17,13 +17,31 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import { SysSettings } from "./api";
|
||||
import SettingBase from "/@/views/sys/settings/tabs/base.vue";
|
||||
import SettingRegister from "/@/views/sys/settings/tabs/register.vue";
|
||||
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { ref } from "vue";
|
||||
defineOptions({
|
||||
name: "SysSettings"
|
||||
});
|
||||
|
||||
const activeKey = ref("");
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
if (route.query.tab) {
|
||||
activeKey.value = (route.query.tab as string) || "";
|
||||
}
|
||||
|
||||
function onChange(value: string) {
|
||||
// activeKey.value = value;
|
||||
// 创建一个新的查询参数对象
|
||||
const query: any = {};
|
||||
if (value !== "") {
|
||||
query.tab = value;
|
||||
}
|
||||
// 使用`push`方法更新路由,保留其他查询参数不变
|
||||
router.push({ path: route.path, query });
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
@@ -4,28 +4,31 @@
|
||||
<a-form-item label="开启自助注册" :name="['public', 'registerEnabled']">
|
||||
<a-switch v-model:checked="formState.public.registerEnabled" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="限制用户流水线数量" :name="['public', 'limitUserPipelineCount']">
|
||||
<a-input-number v-model:value="formState.public.limitUserPipelineCount" />
|
||||
<div class="helper">0为不限制</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="管理其他用户流水线" :name="['public', 'managerOtherUserPipeline']">
|
||||
<a-switch v-model:checked="formState.public.managerOtherUserPipeline" />
|
||||
</a-form-item>
|
||||
|
||||
<template v-if="formState.public.registerEnabled">
|
||||
<a-form-item label="限制用户流水线数量" :name="['public', 'limitUserPipelineCount']">
|
||||
<a-input-number v-model:value="formState.public.limitUserPipelineCount" />
|
||||
<div class="helper">0为不限制</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="管理其他用户流水线" :name="['public', 'managerOtherUserPipeline']">
|
||||
<a-switch v-model:checked="formState.public.managerOtherUserPipeline" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="开启用户名注册" :name="['public', 'usernameRegisterEnabled']">
|
||||
<a-switch v-model:checked="formState.public.usernameRegisterEnabled" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="开启邮箱注册" :name="['public', 'emailRegisterEnabled']">
|
||||
<a-switch v-model:checked="formState.public.emailRegisterEnabled" />
|
||||
<div class="flex-o">
|
||||
<a-switch v-model:checked="formState.public.emailRegisterEnabled" :disabled="!settingsStore.isPlus" title="专业版功能" />
|
||||
<vip-button class="ml-5" mode="button"></vip-button>
|
||||
</div>
|
||||
<div class="helper">需要<router-link to="/sys/settings/email">设置邮箱服务器</router-link></div>
|
||||
</a-form-item>
|
||||
<a-form-item label="开启密码登录" :name="['public', 'passwordLoginEnabled']">
|
||||
<a-switch v-model:checked="formState.public.passwordLoginEnabled" />
|
||||
</a-form-item>
|
||||
<a-form-item label="开启手机号登录、注册" :name="['public', 'smsLoginEnabled']">
|
||||
<a-switch v-model:checked="formState.public.smsLoginEnabled" />
|
||||
<div class="flex-o">
|
||||
<a-switch v-model:checked="formState.public.smsLoginEnabled" :disabled="!settingsStore.isComm" title="商业版功能" />
|
||||
<vip-button class="ml-5" mode="comm"></vip-button>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<template v-if="formState.public.smsLoginEnabled">
|
||||
<a-form-item label="短信提供商" :name="['private', 'sms', 'type']">
|
||||
@@ -34,18 +37,25 @@
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="阿里云授权" :name="['private', 'sms', 'config', 'accessId']">
|
||||
<a-form-item label="阿里云授权" :name="['private', 'sms', 'config', 'accessId']" :rules="rules.required">
|
||||
<access-selector v-model="formState.private.sms.config.accessId" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="短信签名" :name="['private', 'sms', 'config', 'signName']">
|
||||
<a-form-item label="短信签名" :name="['private', 'sms', 'config', 'signName']" :rules="rules.required">
|
||||
<a-input v-model:value="formState.private.sms.config.signName" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="验证码模版ID" :name="['private', 'sms', 'config', 'codeTemplateId']">
|
||||
<a-form-item label="验证码模版ID" :name="['private', 'sms', 'config', 'codeTemplateId']" :rules="rules.required">
|
||||
<a-input v-model:value="formState.private.sms.config.codeTemplateId" />
|
||||
<div class="helper">需要配置一个变量为{code}的验证码模版</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="短信测试">
|
||||
<div class="flex">
|
||||
<a-input v-model:value="testMobile" placeholder="输入测试手机号" />
|
||||
<loading-button class="ml-5" title="保存后再点击测试" type="primary" :click="testSendSms">测试</loading-button>
|
||||
</div>
|
||||
<div class="helper">保存后再点击测试</div>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -63,13 +73,23 @@ import * as api from "/@/views/sys/settings/api";
|
||||
import { merge } from "lodash-es";
|
||||
import { useSettingStore } from "/@/store/modules/settings";
|
||||
import { notification } from "ant-design-vue";
|
||||
import { util } from "/@/utils";
|
||||
import AccessSelector from "/@/views/certd/access/access-selector/index.vue";
|
||||
|
||||
defineOptions({
|
||||
name: "SettingRegister"
|
||||
});
|
||||
|
||||
const testMobile = ref("");
|
||||
function testSendSms() {
|
||||
if (!testMobile.value) {
|
||||
notification.error({
|
||||
message: "请输入测试手机号"
|
||||
});
|
||||
return;
|
||||
}
|
||||
api.TestSms({
|
||||
mobile: testMobile.value
|
||||
});
|
||||
}
|
||||
const formState = reactive<Partial<SysSettings>>({
|
||||
public: {
|
||||
registerEnabled: false
|
||||
@@ -82,6 +102,22 @@ const formState = reactive<Partial<SysSettings>>({
|
||||
}
|
||||
});
|
||||
|
||||
const rules = {
|
||||
leastOneLogin: {
|
||||
validator: (rule: any, value: any) => {
|
||||
if (!formState.public.passwordLoginEnabled && !formState.public.smsLoginEnabled) {
|
||||
return Promise.reject("密码登录和手机号登录至少开启一个");
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
required: {
|
||||
required: true,
|
||||
trigger: "change",
|
||||
message: "此项必填"
|
||||
}
|
||||
};
|
||||
|
||||
async function loadSysSettings() {
|
||||
const data: any = await api.SysSettingsGet();
|
||||
merge(formState, data);
|
||||
|
||||
Reference in New Issue
Block a user