feat(系统设置): 新增系统参数配置扫码登陆平台页面

This commit is contained in:
guoyuqi 2024-06-06 16:10:03 +08:00 committed by 刘瑞斌
parent a4d9799a0f
commit e7304e5272
15 changed files with 864 additions and 0 deletions

View File

@ -85,6 +85,8 @@ public class PermissionConstants {
public static final String SYSTEM_PARAMETER_SETTING_AUTH_READ_DELETE = "SYSTEM_PARAMETER_SETTING_AUTH:READ+DELETE"; public static final String SYSTEM_PARAMETER_SETTING_AUTH_READ_DELETE = "SYSTEM_PARAMETER_SETTING_AUTH:READ+DELETE";
public static final String SYSTEM_PARAMETER_SETTING_DISPLAY_READ = "SYSTEM_PARAMETER_SETTING_DISPLAY:READ"; public static final String SYSTEM_PARAMETER_SETTING_DISPLAY_READ = "SYSTEM_PARAMETER_SETTING_DISPLAY:READ";
public static final String SYSTEM_PARAMETER_SETTING_DISPLAY_READ_UPDATE = "SYSTEM_PARAMETER_SETTING_DISPLAY:READ+UPDATE"; public static final String SYSTEM_PARAMETER_SETTING_DISPLAY_READ_UPDATE = "SYSTEM_PARAMETER_SETTING_DISPLAY:READ+UPDATE";
public static final String SYSTEM_PARAMETER_SETTING_QRCODE_READ = "SYSTEM_PARAMETER_SETTING_QRCODE:READ";
public static final String SYSTEM_PARAMETER_SETTING_QRCODE_UPDATE = "SYSTEM_PARAMETER_SETTING_QRCODE:READ+UPDATE";
public static final String SYSTEM_PARAMETER_SETTING_MEMORY_CLEAN_READ = "SYSTEM_PARAMETER_SETTING_MEMORY_CLEAN:READ"; public static final String SYSTEM_PARAMETER_SETTING_MEMORY_CLEAN_READ = "SYSTEM_PARAMETER_SETTING_MEMORY_CLEAN:READ";
public static final String SYSTEM_PARAMETER_SETTING_MEMORY_CLEAN_READ_UPDATE = "SYSTEM_PARAMETER_SETTING_MEMORY_CLEAN:READ+UPDATE"; public static final String SYSTEM_PARAMETER_SETTING_MEMORY_CLEAN_READ_UPDATE = "SYSTEM_PARAMETER_SETTING_MEMORY_CLEAN:READ+UPDATE";

View File

@ -245,6 +245,8 @@ permission.system_parameter_setting_auth.read=认证设置-查询
permission.system_parameter_setting_auth.add=认证设置-创建 permission.system_parameter_setting_auth.add=认证设置-创建
permission.system_parameter_setting_auth.update=认证设置-编辑 permission.system_parameter_setting_auth.update=认证设置-编辑
permission.system_parameter_setting_auth.delete=认证设置-删除 permission.system_parameter_setting_auth.delete=认证设置-删除
permission.system_parameter_setting_qrcode.read=扫码登录-查询
permission.system_parameter_setting_qrcode.update=扫码登录-编辑
permission.organization_user_role.name=用户组 permission.organization_user_role.name=用户组
permission.organization_member.name=成员 permission.organization_member.name=成员
permission.service_integration.name=服务集成 permission.service_integration.name=服务集成

View File

@ -248,6 +248,8 @@ permission.system_parameter_setting_auth.update=Auth parameter setting update
permission.system_parameter_setting_auth.delete=Auth parameter setting delete permission.system_parameter_setting_auth.delete=Auth parameter setting delete
permission.system_parameter_setting_memory_clean.read=Memory clean parameter setting read permission.system_parameter_setting_memory_clean.read=Memory clean parameter setting read
permission.system_parameter_setting_memory_clean.update=Memory clean parameter setting update permission.system_parameter_setting_memory_clean.update=Memory clean parameter setting update
permission.system_parameter_setting_qrcode.read=Scan the QR code to log in-query
permission.system_parameter_setting_qrcode.update=Scan the QR code to log in-Edit
permission.organization_user_role.name=User group permission.organization_user_role.name=User group
permission.organization_member.name=User permission.organization_member.name=User
permission.service_integration.name=Service Integration permission.service_integration.name=Service Integration

View File

@ -249,6 +249,8 @@ permission.system_parameter_setting_auth.update=认证设置-编辑
permission.system_parameter_setting_auth.delete=认证设置-删除 permission.system_parameter_setting_auth.delete=认证设置-删除
permission.system_parameter_setting_memory_clean.read=内存清理-查询 permission.system_parameter_setting_memory_clean.read=内存清理-查询
permission.system_parameter_setting_memory_clean.update=内存清理-编辑 permission.system_parameter_setting_memory_clean.update=内存清理-编辑
permission.system_parameter_setting_qrcode.read=扫码登录-查询
permission.system_parameter_setting_qrcode.update=扫码登录-编辑
permission.organization_user_role.name=用户组 permission.organization_user_role.name=用户组
permission.organization_member.name=成员 permission.organization_member.name=成员
permission.service_integration.name=服务集成 permission.service_integration.name=服务集成

View File

@ -248,6 +248,8 @@ permission.system_parameter_setting_auth.update=認證設置-編輯
permission.system_parameter_setting_auth.delete=認證設置-刪除 permission.system_parameter_setting_auth.delete=認證設置-刪除
permission.system_parameter_setting_memory_clean.read=內存清理-查詢 permission.system_parameter_setting_memory_clean.read=內存清理-查詢
permission.system_parameter_setting_memory_clean.update=內存清理-編輯 permission.system_parameter_setting_memory_clean.update=內存清理-編輯
permission.system_parameter_setting_qrcode.read=掃碼登入-查詢
permission.system_parameter_setting_qrcode.update=掃碼登入-編輯
permission.organization_user_role.name=用戶組 permission.organization_user_role.name=用戶組
permission.organization_member.name=成員 permission.organization_member.name=成員
permission.service_integration.name=服務集成 permission.service_integration.name=服務集成

View File

@ -162,6 +162,16 @@
{ {
"id": "SYSTEM_PARAMETER_SETTING_MEMORY_CLEAN:READ+UPDATE", "id": "SYSTEM_PARAMETER_SETTING_MEMORY_CLEAN:READ+UPDATE",
"name": "permission.system_parameter_setting_memory_clean.update" "name": "permission.system_parameter_setting_memory_clean.update"
},
{
"id": "SYSTEM_PARAMETER_SETTING_QRCODE:READ",
"name": "permission.system_parameter_setting_qrcode.read",
"license": true
},
{
"id": "SYSTEM_PARAMETER_SETTING_QRCODE:READ",
"name": "permission.system_parameter_setting_qrcode.update",
"license": true
} }
] ]
}, },

View File

@ -0,0 +1,59 @@
import MSR from '@/api/http/index';
import {
GetDingTalkInfoUrl,
GetPlatformInfoUrl,
GetWeComInfoUrl,
PostDingTalkEnableUrl,
PostDingTalkSaveUrl,
PostValidateDingTalkUrl,
PostValidateWeComUrl,
PostWeComEnableUrl,
PostWeComSaveUrl,
} from '@/api/requrls/setting/qrCode';
import { DingTalkInfo, EnableEditorRequest, PlatformSourceList, WeComInfo } from '@/models/setting/qrCode';
// 获取企业微信配置
export function getWeComInfo() {
return MSR.get<WeComInfo>({ url: GetWeComInfoUrl });
}
// 获取钉钉配置
export function getDingInfo() {
return MSR.get<DingTalkInfo>({ url: GetDingTalkInfoUrl });
}
// 保存企业微信登陆配置
export function saveWeComConfig(data: WeComInfo) {
return MSR.post({ url: PostWeComSaveUrl, data });
}
// 保存钉钉登陆配置
export function saveDingTalkConfig(data: DingTalkInfo) {
return MSR.post({ url: PostDingTalkSaveUrl, data });
}
// 校验企业微信外链接
export function validateWeComConfig(data: WeComInfo) {
return MSR.post({ url: PostValidateWeComUrl, data });
}
// 校验钉钉外链接
export function validateDingTalkConfig(data: DingTalkInfo) {
return MSR.post({ url: PostValidateDingTalkUrl, data });
}
// 开启企业微信登陆
export function enableWeCom(data: EnableEditorRequest) {
return MSR.post({ url: PostWeComEnableUrl, data });
}
// 开启钉钉登陆
export function enableDingTalk(data: EnableEditorRequest) {
return MSR.post({ url: PostDingTalkEnableUrl, data });
}
// 获取所有平台配置基础信息
export function getPlatformSourceList() {
return MSR.get<PlatformSourceList>({ url: GetPlatformInfoUrl });
}

View File

@ -0,0 +1,9 @@
export const PostValidateWeComUrl = '/we_com/validate';
export const GetWeComInfoUrl = '/we_com/info/with_detail';
export const PostWeComSaveUrl = '/we_com/save';
export const PostWeComEnableUrl = '/we_com/enable';
export const PostValidateDingTalkUrl = '/ding_talk/validate';
export const GetDingTalkInfoUrl = '/ding_talk/info/with_detail';
export const PostDingTalkSaveUrl = '/ding_talk/save';
export const PostDingTalkEnableUrl = '/ding_talk/enable';
export const GetPlatformInfoUrl = '/setting/get/platform/info';

View File

@ -0,0 +1,40 @@
export interface DingTalkInfo {
agentId: string;
appKey: string;
appSecret: string;
callBack: string;
enable: boolean;
valid: boolean;
}
export interface WeComInfo {
corpId: string;
agentId: string;
appSecret: string;
callBack: string;
enable: boolean;
valid: boolean;
}
export interface EnableEditorRequest {
enable: boolean;
}
export interface PlatformSource {
platform: string;
enable: boolean;
valid: boolean;
}
export interface PlatformConfigItem {
key: string;
title: string;
description: string;
enable: boolean;
valid: boolean;
logo: string;
edit: boolean;
}
export type PlatformSourceList = PlatformSource[];
export type PlatformConfigList = PlatformConfigItem[];

View File

@ -0,0 +1,196 @@
<template>
<a-modal
v-model:visible="detailVisible"
title-align="start"
class="ms-modal-upload ms-modal-medium"
:width="680"
:loading="loading"
>
<template #title>
{{ t('project.messageManagement.DING_TALK') }}
</template>
<a-form class="ms-form rounded-[4px]" :model="dingTalkForm" layout="vertical">
<a-form-item
field="appKey"
:label="t('system.config.qrCodeConfig.appKey')"
:rules="[{ required: true, message: t('system.config.qrCodeConfig.appKey.required') }]"
:validate-trigger="['blur', 'input']"
asterisk-position="end"
>
<a-input v-model="dingTalkForm.appKey" :max-length="255" :placeholder="t('formCreate.PleaseEnter')" />
</a-form-item>
<a-form-item
field="agentId"
:label="t('system.config.qrCodeConfig.agentId')"
:rules="[{ required: true, message: t('system.config.qrCodeConfig.agentId.required') }]"
:validate-trigger="['blur', 'input']"
asterisk-position="end"
>
<a-input v-model="dingTalkForm.agentId" :max-length="255" :placeholder="t('formCreate.PleaseEnter')" />
</a-form-item>
<a-form-item
field="appSecret"
:label="t('system.config.qrCodeConfig.appSecret')"
:rules="[{ required: true, message: t('system.config.qrCodeConfig.appSecret.required') }]"
:validate-trigger="['blur', 'input']"
asterisk-position="end"
>
<a-input-password
v-model="dingTalkForm.appSecret"
allow-clear
:max-length="255"
:placeholder="t('formCreate.PleaseEnter')"
/>
</a-form-item>
<a-form-item
field="callBack"
:label="t('system.config.qrCodeConfig.callBack')"
:rules="[{ required: true, message: t('system.config.qrCodeConfig.callBack.required') }]"
:validate-trigger="['blur', 'input']"
asterisk-position="end"
>
<a-input v-model="dingTalkForm.callBack" :max-length="255" :placeholder="t('formCreate.PleaseEnter')" />
</a-form-item>
</a-form>
<template #footer>
<div class="footer-button">
<div class="ms-switch">
<a-switch
v-model="dingTalkForm.enable"
class="ms-form-table-input-switch execute-form-table-input-switch"
size="small"
/>
<span class="ml-3 font-normal text-[var(--color-text-1)]">{{ t('system.config.qrCodeConfig.enable') }}</span>
</div>
<div class="ms-button-group">
<a-button type="secondary" class="ml-[14px]" @click="cancelEdit">
{{ t('common.cancel') }}
</a-button>
<a-button
type="outline"
class="ml-[14px]"
:disabled="
dingTalkForm.appKey == '' &&
dingTalkForm.appSecret == '' &&
dingTalkForm.agentId == '' &&
dingTalkForm.callBack == ''
"
@click="validateInfo"
>
{{ t('organization.service.testLink') }}
</a-button>
<a-button type="primary" class="ml-[14px]" @click="saveInfo">
{{ t('common.confirm') }}
</a-button>
</div>
</div>
</template>
</a-modal>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { getDingInfo, saveDingTalkConfig, validateDingTalkConfig } from '@/api/modules/setting/qrCode';
import { useI18n } from '@/hooks/useI18n';
import { DingTalkInfo } from '@/models/setting/qrCode';
import Message from '@arco-design/web-vue/es/message';
const { t } = useI18n();
const dingTalkForm = ref<DingTalkInfo>({
agentId: '',
appKey: '',
appSecret: '',
callBack: '',
enable: false,
valid: false,
});
const loading = ref<boolean>(false);
const detailVisible = ref<boolean>(false);
const props = defineProps<{
visible: boolean;
}>();
const emits = defineEmits<{
(event: 'update:visible', visible: boolean): void;
(event: 'success'): void;
}>();
//
const loadList = async () => {
loading.value = true;
try {
dingTalkForm.value = await getDingInfo();
} catch (error) {
console.log(error);
} finally {
loading.value = false;
}
};
watchEffect(() => {
detailVisible.value = props.visible;
});
watch(
() => detailVisible.value,
(val) => {
emits('update:visible', val);
loadList();
}
);
function cancelEdit() {
detailVisible.value = false;
emits('update:visible', detailVisible.value);
}
async function validateInfo() {
loading.value = true;
try {
await validateDingTalkConfig(dingTalkForm.value);
Message.success(t('organization.service.testLinkStatusTip'));
} catch (error) {
console.log(error);
} finally {
loading.value = false;
}
}
async function saveInfo() {
loading.value = true;
try {
await saveDingTalkConfig(dingTalkForm.value);
Message.success(t('organization.service.testLinkStatusTip'));
emits('success');
} catch (error) {
console.log(error);
} finally {
loading.value = false;
detailVisible.value = false;
}
}
</script>
<style scoped lang="less">
.footer-button {
display: flex;
align-items: center;
flex-direction: row;
justify-content: space-between;
}
.ms-switch {
display: flex;
align-items: center;
flex-direction: row;
}
.ms-button-group {
display: flex;
align-items: center;
flex-direction: row;
}
</style>

View File

@ -0,0 +1,311 @@
<template>
<MsCard simple class="mb-[16px]" auto-height :loading="loading">
<div class="outer-wrapper">
<div class="mb-[16px] flex justify-between">
<div class="font-medium text-[var(--color-text-000)]">{{ t('organization.service.integrationList') }}</div>
</div>
<div class="ms-card-wrap">
<a-scrollbar
:style="{
overflow: 'auto',
height: `calc(100vh - 196px)`,
}"
>
<div v-if="filterList.length" class="list">
<div v-for="item of filterList" :key="item.key" class="item">
<div class="flex">
<span class="float-left mr-2 h-[40px] w-[40px] rounded">
<MsIcon :type="item.logo" size="40"></MsIcon>
</span>
<div class="flex flex-col justify-start">
<p>
<span class="mr-4 font-semibold">{{ item.title }}</span>
<span v-if="!item.valid" class="ms-enable">{{ t('organization.service.unconfigured') }}</span>
<span
v-else
class="ms-enable active"
:style="{
background: 'rgb(var(--success-1))',
color: 'rgb(var(--success-6))',
}"
>{{ t('organization.service.configured') }}</span
>
</p>
<p class="mt-2 text-sm text-[var(--color-text-4)]">{{ item.description }}</p>
</div>
</div>
<div class="flex justify-between">
<a-space>
<a-tooltip v-if="!item.valid" :content="t('organization.service.unconfiguredTip')" position="tl">
<span>
<a-button
v-if="!item.valid"
type="outline"
class="arco-btn-outline--secondary"
size="mini"
:disabled="!item.valid || !hasAnyPermission(['SYSTEM_SERVICE_INTEGRATION:READ+UPDATE'])"
@click="getValidateHandler(item.key)"
>{{ t('organization.service.testLink') }}</a-button
></span
>
</a-tooltip>
<a-button
v-else
:disabled="!item.valid || !hasAnyPermission(['SYSTEM_SERVICE_INTEGRATION:READ+UPDATE'])"
type="outline"
class="arco-btn-outline--secondary"
size="mini"
@click="getValidateHandler(item.key)"
>{{ t('organization.service.testLink') }}
</a-button>
<a-button
v-if="item.edit"
v-permission="['SYSTEM_SERVICE_INTEGRATION:READ+UPDATE']"
type="outline"
class="arco-btn-outline--secondary"
size="mini"
@click="editHandler(item.key)"
>{{ t('organization.service.edit') }}
</a-button>
<a-button
v-else
v-permission="['SYSTEM_SERVICE_INTEGRATION:READ+ADD']"
type="outline"
class="arco-btn-outline--secondary"
size="mini"
@click="editHandler(item.key)"
>{{ t('common.add') }}
</a-button>
</a-space>
<span>
<a-tooltip v-if="!item.valid" :content="t('organization.service.unconfiguredTip')" position="br">
<span
><a-switch
v-model="item.enable"
size="small"
:disabled="true"
@change="(v) => changeStatus(v, item.key)"
/></span>
</a-tooltip>
<a-switch
v-else
v-model="item.enable"
size="small"
:disabled="!hasAnyPermission(['SYSTEM_SERVICE_INTEGRATION:READ+UPDATE'])"
@change="(v) => changeStatus(v, item.key)"
/>
</span>
</div>
</div>
</div>
<a-empty v-if="!filterList.length" class="mt-20"></a-empty>
</a-scrollbar>
</div>
</div>
</MsCard>
<we-com-modal v-model:visible="showWeComModal" @success="loadList()" />
<ding-talk-modal v-model:visible="showDingTalkModal" @success="loadList()" />
</template>
<script setup lang="ts">
import { onBeforeMount, ref } from 'vue';
import MsCard from '@/components/pure/ms-card/index.vue';
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import DingTalkModal from '@/views/setting/system/config/components/dingTalkModal.vue';
import WeComModal from '@/views/setting/system/config/components/weComModal.vue';
import {
enableDingTalk,
enableWeCom,
getPlatformSourceList,
validateDingTalkConfig,
validateWeComConfig,
} from '@/api/modules/setting/qrCode';
import { useI18n } from '@/hooks/useI18n';
import { hasAnyPermission } from '@/utils/permission';
import {
DingTalkInfo,
EnableEditorRequest,
PlatformConfigItem,
PlatformConfigList,
PlatformSource,
PlatformSourceList,
WeComInfo,
} from '@/models/setting/qrCode';
import Message from '@arco-design/web-vue/es/message';
const { t } = useI18n();
const filterList = ref<PlatformConfigList>([
{
key: 'WE_COM',
title: t('project.messageManagement.WE_COM'),
description: '为企业打造的专业办公管理工具',
enable: false,
valid: false,
logo: 'icon-logo_wechat-work',
edit: false,
},
{
key: 'DING_TALK',
title: t('project.messageManagement.DING_TALK'),
description: '企业级智能移动办公平台',
enable: false,
valid: false,
logo: 'icon-logo_dingtalk',
edit: false,
},
]);
const data = ref<PlatformSourceList>([]);
const loading = ref<boolean>(false);
const showWeComModal = ref<boolean>(false);
const showDingTalkModal = ref<boolean>(false);
const weComInfo = ref<WeComInfo>({
corpId: '',
agentId: '',
appSecret: '',
callBack: '',
enable: false,
valid: false,
});
const dingTalkInfo = ref<DingTalkInfo>({
agentId: '',
appKey: '',
appSecret: '',
callBack: '',
enable: false,
valid: false,
});
//
const loadList = async () => {
loading.value = true;
try {
data.value = await getPlatformSourceList();
filterList.value.forEach((filterKey: PlatformConfigItem) => {
data.value.forEach((dataKey: PlatformSource) => {
if (filterKey.key === dataKey.platform) {
filterKey.enable = dataKey.enable;
filterKey.valid = dataKey.valid;
filterKey.edit = true;
}
});
});
} catch (error) {
console.log(error);
} finally {
loading.value = false;
}
};
//
const editHandler = (key: string) => {
if (key === 'WE_COM') {
showWeComModal.value = true;
showDingTalkModal.value = false;
} else if (key === 'DING_TALK') {
showWeComModal.value = false;
showDingTalkModal.value = true;
}
};
//
const getValidateHandler = async (key: string) => {
loading.value = true;
try {
if (key === 'WE_COM') {
await validateWeComConfig(weComInfo.value);
} else if (key === 'DING_TALK') {
await validateDingTalkConfig(dingTalkInfo.value);
}
Message.success(t('organization.service.testLinkStatusTip'));
loadList();
} catch (error) {
console.log(error);
} finally {
loading.value = false;
}
};
//
const changeStatus = async (value: string | number | boolean, key: string | undefined) => {
loading.value = true;
const message = value ? 'organization.service.enableSuccess' : 'organization.service.closeSuccess';
const params: EnableEditorRequest = {
enable: typeof value === 'boolean' ? value : false,
};
try {
if (key === 'WE_COM') {
await enableWeCom(params);
} else if (key === 'DING_TALK') {
await enableDingTalk(params);
}
Message.success(t(message));
loadList();
} catch (error) {
console.log(error);
} finally {
loading.value = false;
}
};
onBeforeMount(() => {
loadList();
});
</script>
<style scoped lang="less">
.ms-card-wrap {
overflow: hidden;
padding: 8px;
height: calc(100% - 58px) !important;
min-height: 300px;
border-radius: var(--border-radius-small);
background: var(--color-text-n9);
.list {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
align-content: flex-start;
width: 100%;
.item {
margin: 8px;
padding: 24px;
height: 144px;
border-radius: 4px;
background: white;
@apply flex flex-col justify-between;
.ms-enable {
font-size: 12px;
border-radius: var(--border-radius-small);
background: var(--color-text-n9);
@apply px-2 py-1;
}
}
}
@media screen and (min-width: 800px) {
.item {
flex-basis: calc(50% - 16px);
}
}
@media screen and (min-width: 1160px) {
.item {
flex-basis: calc(33.3% - 16px);
}
}
@media screen and (min-width: 1800px) {
.item {
flex-basis: calc(25% - 16px);
}
}
}
</style>

View File

@ -0,0 +1,193 @@
<template>
<a-modal
v-model:visible="detailVisible"
title-align="start"
class="ms-modal-upload ms-modal-medium"
:width="680"
:loading="loading"
>
<template #title>
{{ t('project.messageManagement.WE_COM') }}
</template>
<a-form class="ms-form rounded-[4px]" :model="weComForm" layout="vertical">
<a-form-item
field="corpId"
:label="t('system.config.qrCodeConfig.corpId')"
:rules="[{ required: true, message: t('system.config.qrCodeConfig.corpId.required') }]"
:validate-trigger="['blur', 'input']"
asterisk-position="end"
>
<a-input v-model="weComForm.corpId" :max-length="255" :placeholder="t('formCreate.PleaseEnter')" />
</a-form-item>
<a-form-item
field="agentId"
:label="t('system.config.qrCodeConfig.agentId')"
:rules="[{ required: true, message: t('system.config.qrCodeConfig.agentId.required') }]"
:validate-trigger="['blur', 'input']"
asterisk-position="end"
>
<a-input v-model="weComForm.agentId" :max-length="255" :placeholder="t('formCreate.PleaseEnter')" />
</a-form-item>
<a-form-item
field="appSecret"
:label="t('system.config.qrCodeConfig.appSecret')"
:rules="[{ required: true, message: t('system.config.qrCodeConfig.appSecret.required') }]"
:validate-trigger="['blur', 'input']"
asterisk-position="end"
>
<a-input-password
v-model="weComForm.appSecret"
allow-clear
:max-length="255"
:placeholder="t('formCreate.PleaseEnter')"
/>
</a-form-item>
<a-form-item
field="callBack"
:label="t('system.config.qrCodeConfig.callBack')"
:rules="[{ required: true, message: t('system.config.qrCodeConfig.callBack.required') }]"
:validate-trigger="['blur', 'input']"
asterisk-position="end"
>
<a-input v-model="weComForm.callBack" :max-length="255" :placeholder="t('formCreate.PleaseEnter')" />
</a-form-item>
</a-form>
<template #footer>
<div class="footer-button">
<div class="ms-switch">
<a-switch
v-model="weComForm.enable"
class="ms-form-table-input-switch execute-form-table-input-switch"
size="small"
/>
<span class="ml-3 font-normal text-[var(--color-text-1)]">{{ t('system.config.qrCodeConfig.enable') }}</span>
</div>
<div>
<a-button class="ml-[14px]" type="secondary" @click="cancelEdit">
{{ t('common.cancel') }}
</a-button>
<a-button
class="ml-[14px]"
type="outline"
:disabled="
weComForm.corpId == '' && weComForm.appSecret == '' && weComForm.agentId == '' && weComForm.callBack == ''
"
@click="validateInfo"
>
{{ t('organization.service.testLink') }}
</a-button>
<a-button class="ml-[14px]" type="primary" @click="saveInfo">
{{ t('common.confirm') }}
</a-button>
</div>
</div>
</template>
</a-modal>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { getWeComInfo, saveWeComConfig, validateWeComConfig } from '@/api/modules/setting/qrCode';
import { useI18n } from '@/hooks/useI18n';
import { WeComInfo } from '@/models/setting/qrCode';
import Message from '@arco-design/web-vue/es/message';
const { t } = useI18n();
const weComForm = ref<WeComInfo>({
corpId: '',
agentId: '',
appSecret: '',
callBack: '',
enable: false,
valid: false,
});
const emits = defineEmits<{
(event: 'update:visible', visible: boolean): void;
(event: 'success'): void;
}>();
const loading = ref<boolean>(false);
const detailVisible = ref<boolean>(false);
const props = defineProps<{
visible: boolean;
}>();
//
const loadList = async () => {
loading.value = true;
try {
weComForm.value = await getWeComInfo();
} catch (error) {
console.log(error);
} finally {
loading.value = false;
}
};
watchEffect(() => {
detailVisible.value = props.visible;
});
watch(
() => detailVisible.value,
(val) => {
emits('update:visible', val);
loadList();
}
);
function cancelEdit() {
detailVisible.value = false;
emits('update:visible', detailVisible.value);
}
async function validateInfo() {
loading.value = true;
try {
await validateWeComConfig(weComForm.value);
Message.success(t('organization.service.testLinkStatusTip'));
} catch (error) {
console.log(error);
} finally {
loading.value = false;
}
}
async function saveInfo() {
loading.value = true;
try {
await saveWeComConfig(weComForm.value);
Message.success(t('organization.service.testLinkStatusTip'));
emits('success');
} catch (error) {
console.log(error);
} finally {
loading.value = false;
detailVisible.value = false;
}
}
</script>
<style scoped lang="less">
.footer-button {
display: flex;
align-items: center;
flex-direction: row;
justify-content: space-between;
}
.ms-switch {
display: flex;
align-items: center;
flex-direction: row;
}
.ms-button-group {
display: flex;
align-items: center;
flex-direction: row;
}
</style>

View File

@ -1,6 +1,7 @@
<template> <template>
<MsTabCard v-model:active-tab="activeTab" :title="t('system.config.parameterConfig')" :tab-list="tabList" /> <MsTabCard v-model:active-tab="activeTab" :title="t('system.config.parameterConfig')" :tab-list="tabList" />
<baseConfig v-if="activeTab === 'baseConfig'" v-show="activeTab === 'baseConfig'" /> <baseConfig v-if="activeTab === 'baseConfig'" v-show="activeTab === 'baseConfig'" />
<qrCodeConfig v-if="activeTab === 'qrCodeConfig'" v-show="activeTab === 'qrCodeConfig'" />
<pageConfig v-if="isInitPageConfig" v-show="activeTab === 'pageConfig'" /> <pageConfig v-if="isInitPageConfig" v-show="activeTab === 'pageConfig'" />
<authConfig v-if="isInitAuthConfig" v-show="activeTab === 'authConfig'" /> <authConfig v-if="isInitAuthConfig" v-show="activeTab === 'authConfig'" />
<memoryCleanup v-if="isInitMemoryCleanup" v-show="activeTab === 'memoryCleanup'" /> <memoryCleanup v-if="isInitMemoryCleanup" v-show="activeTab === 'memoryCleanup'" />
@ -21,6 +22,7 @@
// //
const baseConfig = defineAsyncComponent(() => import('./components/baseConfig.vue')); const baseConfig = defineAsyncComponent(() => import('./components/baseConfig.vue'));
const pageConfig = defineAsyncComponent(() => import('./components/pageConfig.vue')); const pageConfig = defineAsyncComponent(() => import('./components/pageConfig.vue'));
const qrCodeConfig = defineAsyncComponent(() => import('./components/qrCodeConfig.vue'));
const authConfig = defineAsyncComponent(() => import('./components/authConfig.vue')); const authConfig = defineAsyncComponent(() => import('./components/authConfig.vue'));
const memoryCleanup = defineAsyncComponent(() => import('./components/memoryCleanup.vue')); const memoryCleanup = defineAsyncComponent(() => import('./components/memoryCleanup.vue'));
@ -31,9 +33,15 @@
const isInitPageConfig = ref(activeTab.value === 'pageConfig'); const isInitPageConfig = ref(activeTab.value === 'pageConfig');
const isInitAuthConfig = ref(activeTab.value === 'authConfig'); const isInitAuthConfig = ref(activeTab.value === 'authConfig');
const isInitMemoryCleanup = ref(activeTab.value === 'memoryCleanup'); const isInitMemoryCleanup = ref(activeTab.value === 'memoryCleanup');
const isInitQrCodeConfig = ref(activeTab.value === 'qrCodeConfig');
const tabList = ref([ const tabList = ref([
{ key: 'baseConfig', title: t('system.config.baseConfig'), permission: ['SYSTEM_PARAMETER_SETTING_BASE:READ'] }, { key: 'baseConfig', title: t('system.config.baseConfig'), permission: ['SYSTEM_PARAMETER_SETTING_BASE:READ'] },
{ key: 'pageConfig', title: t('system.config.pageConfig'), permission: ['SYSTEM_PARAMETER_SETTING_DISPLAY:READ'] }, { key: 'pageConfig', title: t('system.config.pageConfig'), permission: ['SYSTEM_PARAMETER_SETTING_DISPLAY:READ'] },
{
key: 'qrCodeConfig',
title: t('system.config.qrCodeConfig'),
permission: ['SYSTEM_PARAMETER_SETTING_DISPLAY:READ'],
},
{ key: 'authConfig', title: t('system.config.authConfig'), permission: ['SYSTEM_PARAMETER_SETTING_AUTH:READ'] }, { key: 'authConfig', title: t('system.config.authConfig'), permission: ['SYSTEM_PARAMETER_SETTING_AUTH:READ'] },
{ {
key: 'memoryCleanup', key: 'memoryCleanup',
@ -51,6 +59,8 @@
isInitAuthConfig.value = true; isInitAuthConfig.value = true;
} else if (val === 'memoryCleanup' && !isInitMemoryCleanup.value) { } else if (val === 'memoryCleanup' && !isInitMemoryCleanup.value) {
isInitMemoryCleanup.value = true; isInitMemoryCleanup.value = true;
} else if (val === 'qrCodeConfig' && !isInitMemoryCleanup.value) {
isInitQrCodeConfig.value = true;
} }
}, },
{ {

View File

@ -2,6 +2,7 @@ export default {
'system.config.parameterConfig': 'System Parameters Configuration', 'system.config.parameterConfig': 'System Parameters Configuration',
'system.config.baseConfig': 'Basic Settings', 'system.config.baseConfig': 'Basic Settings',
'system.config.pageConfig': 'Interface settings', 'system.config.pageConfig': 'Interface settings',
'system.config.qrCodeConfig': 'Scan the QR code to log in',
'system.config.authConfig': 'Authentication Settings', 'system.config.authConfig': 'Authentication Settings',
'system.config.baseInfo': 'Base Information', 'system.config.baseInfo': 'Base Information',
'system.config.update': 'Update', 'system.config.update': 'Update',
@ -206,4 +207,16 @@ export default {
'Effective for all projects in the system, the system will clear unset change history in the early morning', 'Effective for all projects in the system, the system will clear unset change history in the early morning',
'system.config.memoryCleanup.numberTip': 'system.config.memoryCleanup.numberTip':
'The system defaults to a maximum of 100,000 records, and will keep all records if exceeded', 'The system defaults to a maximum of 100,000 records, and will keep all records if exceeded',
'system.config.qrCodeConfig.corpId': 'Corp Id',
'system.config.qrCodeConfig.agentId': 'Agent Id',
'system.config.qrCodeConfig.appKey': 'App Key',
'system.config.qrCodeConfig.appSecret': 'App Secret',
'system.config.qrCodeConfig.callBack': 'CallBack',
'system.config.qrCodeConfig.enable': 'Enable',
'system.config.qrCodeConfig.valid': 'Valid',
'system.config.qrCodeConfig.corpId.required': 'Corp Id is empty',
'system.config.qrCodeConfig.agentId.required': 'Agent Id is empty',
'system.config.qrCodeConfig.appKey.required': 'App Key is empty',
'system.config.qrCodeConfig.appSecret.required': 'App Secret is empty',
'system.config.qrCodeConfig.callBack.required': 'CallBack is empty',
}; };

View File

@ -2,6 +2,7 @@ export default {
'system.config.parameterConfig': '系统参数配置', 'system.config.parameterConfig': '系统参数配置',
'system.config.baseConfig': '基础设置', 'system.config.baseConfig': '基础设置',
'system.config.pageConfig': '界面设置', 'system.config.pageConfig': '界面设置',
'system.config.qrCodeConfig': '扫码登陆',
'system.config.authConfig': '认证设置', 'system.config.authConfig': '认证设置',
'system.config.baseInfo': '基本信息', 'system.config.baseInfo': '基本信息',
'system.config.update': '更新', 'system.config.update': '更新',
@ -199,4 +200,16 @@ export default {
'system.config.memoryCleanup.saveCount': '保留条数', 'system.config.memoryCleanup.saveCount': '保留条数',
'system.config.memoryCleanup.saveCountTip': '对系统内所有的项目生效,系统会在凌晨清除超出设置的变更历史记录', 'system.config.memoryCleanup.saveCountTip': '对系统内所有的项目生效,系统会在凌晨清除超出设置的变更历史记录',
'system.config.memoryCleanup.numberTip': '系统默认最大保留条数为100000条超过则为您保留全部记录', 'system.config.memoryCleanup.numberTip': '系统默认最大保留条数为100000条超过则为您保留全部记录',
'system.config.qrCodeConfig.corpId': '企业ID',
'system.config.qrCodeConfig.agentId': '应用ID',
'system.config.qrCodeConfig.appKey': '应用key',
'system.config.qrCodeConfig.appSecret': '应用密钥',
'system.config.qrCodeConfig.callBack': '回调域名',
'system.config.qrCodeConfig.enable': '是否开启',
'system.config.qrCodeConfig.valid': '是否可用',
'system.config.qrCodeConfig.corpId.required': '企业ID不能为空',
'system.config.qrCodeConfig.agentId.required': '应用ID不能为空',
'system.config.qrCodeConfig.appKey.required': '应用key不能为空',
'system.config.qrCodeConfig.appSecret.required': '应用密钥不能为空',
'system.config.qrCodeConfig.callBack.required': '回调域名不能为空',
}; };