mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 01:06:59 +08:00
feat: Add Wecom Configuration Form
This commit is contained in:
committed by
fit2cloud-chenyw
parent
d56e4779ff
commit
01ca5ec125
@@ -756,6 +756,13 @@
|
||||
"setting_successfully": "Setting Successfully",
|
||||
"customize_theme_color": "Customize theme color"
|
||||
},
|
||||
"platform": {
|
||||
"title": "Platform Integration",
|
||||
"status_open": "Enabled",
|
||||
"status_close": "Disabled",
|
||||
"access_in": "Access",
|
||||
"can_enable_it": "Can be enabled after successful test connection"
|
||||
},
|
||||
"authentication": {
|
||||
"invalid": "Invalid",
|
||||
"valid": "Valid",
|
||||
|
||||
@@ -756,6 +756,13 @@
|
||||
"setting_successfully": "설정 성공",
|
||||
"customize_theme_color": "사용자 정의 테마 색상"
|
||||
},
|
||||
"platform": {
|
||||
"title": "플랫폼 연동",
|
||||
"status_open": "활성화됨",
|
||||
"status_close": "비활성화됨",
|
||||
"access_in": "접속",
|
||||
"can_enable_it": "연결 테스트 성공 후 활성화 가능"
|
||||
},
|
||||
"authentication": {
|
||||
"invalid": "유효하지 않음",
|
||||
"valid": "유효함",
|
||||
|
||||
@@ -215,7 +215,6 @@
|
||||
"chart_selected": "已选{0}"
|
||||
},
|
||||
"qa": {
|
||||
"recommended_repetitive_tips": "Duplicate questions exist",
|
||||
"retrieve_error": "暂无内容",
|
||||
"retrieve_again": "重新获取",
|
||||
"recently": "最近",
|
||||
@@ -757,6 +756,13 @@
|
||||
"setting_successfully": "设置成功",
|
||||
"customize_theme_color": "自定义主题色"
|
||||
},
|
||||
"platform": {
|
||||
"title": "平台对接",
|
||||
"status_open": "已开启",
|
||||
"status_close": "已关闭",
|
||||
"access_in": "接入",
|
||||
"can_enable_it": "测试连接有效后,可开启"
|
||||
},
|
||||
"authentication": {
|
||||
"invalid": "无效",
|
||||
"valid": "有效",
|
||||
|
||||
@@ -21,6 +21,7 @@ import Audit from '@/views/system/audit/index.vue'
|
||||
import Appearance from '@/views/system/appearance/index.vue'
|
||||
import Parameter from '@/views/system/parameter/index.vue'
|
||||
import Authentication from '@/views/system/authentication/index.vue'
|
||||
import Platform from '@/views/system/platform/index.vue'
|
||||
import Permission from '@/views/system/permission/index.vue'
|
||||
import User from '@/views/system/user/User.vue'
|
||||
import Workspace from '@/views/system/workspace/index.vue'
|
||||
@@ -212,6 +213,12 @@ export const routes = [
|
||||
component: Authentication,
|
||||
meta: { title: t('system.authentication_settings') },
|
||||
},
|
||||
{
|
||||
path: 'platform',
|
||||
name: 'platform',
|
||||
component: Platform,
|
||||
meta: { title: t('platform.title') },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,318 @@
|
||||
<template>
|
||||
<div class="info-template-container">
|
||||
<div v-if="!props.hideHead" class="info-template-header">
|
||||
<div class="info-template-title">
|
||||
<span>{{ curTitle }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<el-button v-if="testConnectText" secondary @click="check">{{ testConnectText }}</el-button>
|
||||
<el-button v-if="showValidate" secondary @click="check">{{
|
||||
t('datasource.validate')
|
||||
}}</el-button>
|
||||
<el-button type="primary" @click="edit">{{ t('commons.edit') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-template-content clearfix">
|
||||
<div v-for="item in settingList" :key="item.pkey" class="info-content-item">
|
||||
<div class="info-item-label">
|
||||
<!-- <span>{{ t(item.pkey) }}</span> -->
|
||||
<span>{{ item.pkey }}</span>
|
||||
<el-tooltip
|
||||
v-if="tooltipItem[item.pkey]"
|
||||
effect="dark"
|
||||
:content="tooltipItem[item.pkey]"
|
||||
placement="top"
|
||||
>
|
||||
<el-icon class="info-tips"
|
||||
><Icon name="dv-info"><dvInfo class="svg-icon" /></Icon
|
||||
></el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="info-item-content">
|
||||
<div v-if="item.type === 'pwd'" class="info-item-pwd">
|
||||
<span class="info-item-pwd-span">{{
|
||||
pwdItem[item.pkey]['hidden'] ? '********' : item.pval
|
||||
}}</span>
|
||||
|
||||
<el-tooltip
|
||||
v-if="props.copyList.includes(item.pkey)"
|
||||
effect="dark"
|
||||
:content="t('datasource.copy')"
|
||||
placement="top"
|
||||
>
|
||||
<el-button text class="setting-tip-btn" @click="copyVal(item.pval)">
|
||||
<template #icon>
|
||||
<Icon name="de-copy"><icon_copy_outlined class="svg-icon" /></Icon>
|
||||
</template>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="
|
||||
pwdItem[item.pkey]['hidden']
|
||||
? t('embedded.click_to_show')
|
||||
: t('embedded.click_to_hide')
|
||||
"
|
||||
placement="top"
|
||||
>
|
||||
<el-button text class="setting-tip-btn" @click="switchPwd(item.pkey)">
|
||||
<template #icon>
|
||||
<Icon
|
||||
><component
|
||||
:is="
|
||||
pwdItem[item.pkey]['hidden']
|
||||
? icon_invisible_outlined
|
||||
: icon_visible_outlined
|
||||
"
|
||||
class="svg-icon"
|
||||
></component
|
||||
></Icon>
|
||||
</template>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<!-- <span v-else-if="item.pkey.includes('basic.dsIntervalTime')">
|
||||
<span>{{ item.pval + ' ' + executeTime + t('common.every_exec') }}</span>
|
||||
</span> -->
|
||||
<template v-else>
|
||||
<div class="info-item-content-val">
|
||||
<span style="word-break: break-all">{{ item.pval }}</span>
|
||||
<el-tooltip
|
||||
v-if="props.copyList.includes(item.pkey)"
|
||||
effect="dark"
|
||||
:content="t('datasource.copy')"
|
||||
placement="top"
|
||||
>
|
||||
<el-icon class="info-tips hover-icon_with_bg" @click="copyVal(item.pval)">
|
||||
<icon_copy_outlined class="svg-icon" />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import icon_copy_outlined from '@/assets/svg/icon_copy_outlined.svg'
|
||||
import icon_invisible_outlined from '@/assets/embedded/icon_invisible_outlined.svg'
|
||||
import icon_visible_outlined from '@/assets/embedded/icon_visible_outlined.svg'
|
||||
import dvInfo from '@/assets/svg/dashboard-info.svg'
|
||||
import { ref, computed, type PropType } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { ElMessage } from 'element-plus-secondary'
|
||||
import type { SettingRecord, ToolTipRecord } from './SettingTemplate'
|
||||
const { copy } = useClipboard({ legacy: true })
|
||||
const { t } = useI18n()
|
||||
const props = defineProps({
|
||||
settingKey: {
|
||||
type: String,
|
||||
default: 'basic',
|
||||
},
|
||||
labelTooltips: {
|
||||
type: Array as PropType<ToolTipRecord[]>,
|
||||
default: () => [],
|
||||
},
|
||||
settingData: {
|
||||
type: Array as PropType<SettingRecord[]>,
|
||||
default: () => [],
|
||||
},
|
||||
settingTitle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
hideHead: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
showValidate: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
testConnectText: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
copyList: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => [],
|
||||
},
|
||||
})
|
||||
// const executeTime = ref(t('system.and_0_seconds'))
|
||||
const curTitle = computed(() => {
|
||||
return props.settingTitle || t('system.basic_settings')
|
||||
})
|
||||
const copyVal = async (val: any) => {
|
||||
try {
|
||||
await copy(val)
|
||||
ElMessage.success(t('embedded.copy_successful'))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
ElMessage.warning(t('embedded.copy_failed'))
|
||||
}
|
||||
}
|
||||
const loadList = () => {
|
||||
settingList.value = []
|
||||
if (props.settingData?.length) {
|
||||
props.settingData.forEach((item) => {
|
||||
/* if (item.pkey.includes('basic.dsExecuteTime')) {
|
||||
executeTime.value = getExecuteTime(item.pval)
|
||||
} else {
|
||||
settingList.value.push(item)
|
||||
} */
|
||||
settingList.value.push(item)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/* const getExecuteTime = (val: any) => {
|
||||
const options = [
|
||||
{ value: 'minute', label: t('system.time_0_seconds') },
|
||||
{ value: 'hour', label: t('system.and_0_seconds_de') },
|
||||
]
|
||||
return options.filter((item) => item.value === val)[0].label
|
||||
} */
|
||||
|
||||
const settingList = ref([] as SettingRecord[])
|
||||
|
||||
const init = () => {
|
||||
if (props.settingData?.length) {
|
||||
loadList()
|
||||
}
|
||||
}
|
||||
const pwdItem = ref({} as Record<string, { hidden: boolean }>)
|
||||
|
||||
const formatPwd = () => {
|
||||
settingList.value.forEach((setting) => {
|
||||
if (setting.type === 'pwd') {
|
||||
pwdItem.value[setting.pkey] = { hidden: true }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const tooltipItem = ref({} as Record<string, any>)
|
||||
const formatLabel = () => {
|
||||
if (props.labelTooltips?.length) {
|
||||
props.labelTooltips.forEach((tooltip) => {
|
||||
tooltipItem.value[tooltip.key] = tooltip.val
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const switchPwd = (pkey: string) => {
|
||||
pwdItem.value[pkey]['hidden'] = !pwdItem.value[pkey]['hidden']
|
||||
}
|
||||
|
||||
const emits = defineEmits(['edit', 'check'])
|
||||
const edit = () => {
|
||||
emits('edit')
|
||||
}
|
||||
|
||||
const check = () => {
|
||||
emits('check')
|
||||
}
|
||||
defineExpose({
|
||||
init,
|
||||
})
|
||||
init()
|
||||
formatPwd()
|
||||
formatLabel()
|
||||
</script>
|
||||
|
||||
<style lang="less" scope>
|
||||
.setting-tip-btn {
|
||||
height: 24px !important;
|
||||
width: 24px !important;
|
||||
margin-left: 4px !important;
|
||||
.ed-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
.info-template-container {
|
||||
padding: 24px 24px 8px 24px;
|
||||
background: var(--ContentBG, #ffffff);
|
||||
border-radius: 4px;
|
||||
.info-template-header {
|
||||
display: flex;
|
||||
margin-top: -4px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.info-template-title {
|
||||
height: 24px;
|
||||
line-height: 23px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #1f2329;
|
||||
}
|
||||
}
|
||||
.info-template-content {
|
||||
width: 100%;
|
||||
margin-top: 12px;
|
||||
.info-content-item {
|
||||
width: 50%;
|
||||
float: left;
|
||||
margin-bottom: 16px;
|
||||
min-height: 46px;
|
||||
.info-item-label {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
span {
|
||||
font-size: 14px;
|
||||
color: #646a73;
|
||||
font-weight: 400;
|
||||
}
|
||||
i {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
.info-item-content {
|
||||
line-height: 22px;
|
||||
span {
|
||||
font-size: 14px;
|
||||
color: #1f2329;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.info-item-pwd {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
i {
|
||||
margin-left: 2px;
|
||||
}
|
||||
.info-item-pwd-span {
|
||||
max-width: calc(100% - 84px);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
.info-item-content-val {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 6px;
|
||||
.hover-icon_with_bg {
|
||||
color: var(--ed-color-primary);
|
||||
background-color: var(--ed-button-hover-bg-color);
|
||||
/* &::after {
|
||||
background: var(--ed-button-hover-bg-color);
|
||||
} */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.clearfix::after {
|
||||
content: '';
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,11 @@
|
||||
export interface SettingRecord {
|
||||
pkey: string
|
||||
pval: string
|
||||
type: string
|
||||
sort: number
|
||||
}
|
||||
|
||||
export interface ToolTipRecord {
|
||||
key: string
|
||||
val: string
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ElMessage, ElLoading } from 'element-plus-secondary'
|
||||
import { request } from '@/utils/request'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import type { FormInstance, FormRules } from 'element-plus-secondary'
|
||||
const { t } = useI18n()
|
||||
const dialogVisible = ref(false)
|
||||
const loadingInstance = ref<ReturnType<typeof ElLoading.service> | null>(null)
|
||||
const dingtalkForm = ref<FormInstance>()
|
||||
interface DingtalkForm {
|
||||
agentId?: string
|
||||
appKey?: string
|
||||
appSecret?: string
|
||||
callBack?: string
|
||||
enable?: string
|
||||
valid?: string
|
||||
}
|
||||
const state = reactive({
|
||||
form: reactive<DingtalkForm>({
|
||||
agentId: '',
|
||||
appKey: '',
|
||||
appSecret: '',
|
||||
callBack: '',
|
||||
enable: 'false',
|
||||
valid: 'false',
|
||||
}),
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
const validateUrl = (rule, value, callback) => {
|
||||
const reg = new RegExp(/(http|https):\/\/([\w.]+\/?)\S*/)
|
||||
if (!reg.test(value)) {
|
||||
callback(new Error(t('system.incorrect_please_re_enter')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
const rule = reactive<FormRules>({
|
||||
agentId: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 5,
|
||||
max: 20,
|
||||
message: t('common.input_limit', [5, 20]),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
appKey: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 5,
|
||||
max: 20,
|
||||
message: t('common.input_limit', [5, 20]),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
appSecret: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 5,
|
||||
max: 100,
|
||||
message: t('common.input_limit', [5, 100]),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
callBack: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 10,
|
||||
max: 100,
|
||||
message: t('common.input_limit', [10, 100]),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{ required: true, validator: validateUrl, trigger: 'blur' },
|
||||
],
|
||||
enable: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
valid: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const edit = (row: any) => {
|
||||
state.form = {
|
||||
agentId: row.agentId,
|
||||
appKey: row.appKey,
|
||||
appSecret: row.appSecret,
|
||||
callBack: row.callBack,
|
||||
enable: row.enable,
|
||||
valid: row.valid,
|
||||
}
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const emits = defineEmits(['saved'])
|
||||
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
const param = { ...state.form }
|
||||
const method = request.post('/dingtalk/create', param)
|
||||
showLoading()
|
||||
method
|
||||
.then((res) => {
|
||||
if (!res.msg) {
|
||||
ElMessage.success(t('common.save_success'))
|
||||
emits('saved')
|
||||
reset()
|
||||
}
|
||||
closeLoading()
|
||||
})
|
||||
.catch(() => {
|
||||
closeLoading()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const resetForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.resetFields()
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
resetForm(dingtalkForm.value)
|
||||
}
|
||||
|
||||
const showLoading = () => {
|
||||
loadingInstance.value = ElLoading.service({
|
||||
target: '.platform-info-drawer',
|
||||
})
|
||||
}
|
||||
const closeLoading = () => {
|
||||
loadingInstance.value?.close()
|
||||
}
|
||||
|
||||
const validate = () => {
|
||||
const url = '/dingtalk/validate'
|
||||
const data = state.form
|
||||
showLoading()
|
||||
request
|
||||
.post(url, data)
|
||||
.then(() => {
|
||||
state.form.valid = 'true'
|
||||
ElMessage.success(t('datasource.validate_success'))
|
||||
})
|
||||
.catch(() => {
|
||||
state.form.enable = 'false'
|
||||
state.form.valid = 'false'
|
||||
})
|
||||
.finally(() => {
|
||||
closeLoading()
|
||||
emits('saved')
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
edit,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-drawer
|
||||
v-model="dialogVisible"
|
||||
:title="t('system.dingtalk_settings')"
|
||||
modal-class="platform-info-drawer"
|
||||
size="600px"
|
||||
direction="rtl"
|
||||
>
|
||||
<el-form
|
||||
ref="dingtalkForm"
|
||||
require-asterisk-position="right"
|
||||
:model="state.form"
|
||||
:rules="rule"
|
||||
label-width="80px"
|
||||
label-position="top"
|
||||
>
|
||||
<el-form-item label="AgentId" prop="agentId">
|
||||
<el-input v-model="state.form.agentId" :placeholder="t('common.please_input')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="APP Key" prop="appKey">
|
||||
<el-input v-model="state.form.appKey" :placeholder="t('common.please_input')" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="APP Secret" prop="appSecret">
|
||||
<el-input
|
||||
v-model="state.form.appSecret"
|
||||
type="password"
|
||||
show-password
|
||||
:placeholder="t('common.please_input')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('system.callback_domain_name')" prop="callBack">
|
||||
<el-input v-model="state.form.callBack" :placeholder="t('common.please_input')" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="resetForm(dingtalkForm)">{{ t('common.cancel') }}</el-button>
|
||||
<el-button
|
||||
:disabled="!state.form.appKey || !state.form.appSecret || !state.form.callBack"
|
||||
@click="validate"
|
||||
>
|
||||
{{ t('commons.validate') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="submitForm(dingtalkForm)">
|
||||
{{ t('commons.save') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.platform-info-drawer {
|
||||
.ed-drawer__footer {
|
||||
height: 64px !important;
|
||||
padding: 16px 24px !important;
|
||||
.dialog-footer {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
.ed-form-item__label {
|
||||
line-height: 22px !important;
|
||||
height: 22px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="less" scoped>
|
||||
.platform-info-drawer {
|
||||
.ed-form-item {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.is-error {
|
||||
margin-bottom: 40px !important;
|
||||
}
|
||||
.input-with-select {
|
||||
.ed-input-group__prepend {
|
||||
width: 72px;
|
||||
background-color: #fff;
|
||||
padding: 0 20px;
|
||||
color: #1f2329;
|
||||
text-align: center;
|
||||
font-family: var(--de-custom_font, 'PingFang');
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,246 @@
|
||||
<template>
|
||||
<div class="platform-head-container" :class="{ 'just-head': !existInfo }">
|
||||
<div class="platform-setting-head">
|
||||
<div class="platform-setting-head-left">
|
||||
<div class="lead-left-icon">
|
||||
<el-icon>
|
||||
<Icon name="logo_dingtalk"><logo_dingtalk class="svg-icon" /></Icon>
|
||||
</el-icon>
|
||||
<span>{{ t('user.dingtalk') }}</span>
|
||||
</div>
|
||||
<div v-if="existInfo" class="lead-left-status" :class="{ invalid: !info.valid }">
|
||||
<span>{{
|
||||
info.valid ? t('datasource.valid') : info.appKey ? t('datasource.invalid') : ''
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="existInfo" class="platform-setting-head-right">
|
||||
<span>{{ info.enable ? t('system.enabled') : t('system.close') }}</span>
|
||||
<el-switch
|
||||
v-if="info.valid"
|
||||
v-model="info.enable"
|
||||
class="status-switch"
|
||||
@change="switchEnableApi"
|
||||
/>
|
||||
<el-tooltip
|
||||
v-else
|
||||
class="box-item"
|
||||
effect="dark"
|
||||
:content="t('platform.can_enable_it')"
|
||||
placement="top"
|
||||
>
|
||||
<el-switch
|
||||
v-model="info.enable"
|
||||
disabled=""
|
||||
class="status-switch"
|
||||
@change="switchEnableApi"
|
||||
/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div v-else class="platform-setting-head-right-btn">
|
||||
<el-button type="primary" @click="edit">{{ t('system.access') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<InfoTemplate
|
||||
v-if="existInfo"
|
||||
class="platform-setting-main"
|
||||
:copy-list="copyList"
|
||||
setting-key="dingtalk"
|
||||
setting-title=""
|
||||
:hide-head="true"
|
||||
:setting-data="settingList"
|
||||
@edit="edit"
|
||||
/>
|
||||
<div v-if="existInfo" class="platform-foot-container">
|
||||
<el-button type="primary" @click="edit">
|
||||
{{ t('commons.edit') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
secondary
|
||||
:disabled="!info.appKey || !info.appSecret || !info.callBack"
|
||||
@click="validate"
|
||||
>{{ t('commons.validate') }}</el-button
|
||||
>
|
||||
</div>
|
||||
<dingtalk-edit ref="editor" @saved="search" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import logo_dingtalk from '@/assets/svg/logo_dingtalk.svg'
|
||||
import { ref, reactive } from 'vue'
|
||||
import InfoTemplate from '../common/InfoTemplate.vue'
|
||||
import DingtalkEdit from './DingtalkEdit.vue'
|
||||
import { request } from '@/utils/request'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { ElMessage } from 'element-plus-secondary'
|
||||
const existInfo = ref(false)
|
||||
const { t } = useI18n()
|
||||
const editor = ref()
|
||||
const copyList = ['APP Key', 'APP Secret']
|
||||
const settingList = reactive([
|
||||
{
|
||||
pkey: 'AgentId',
|
||||
pval: 'smtp.exmail.qq.com',
|
||||
type: 'text',
|
||||
sort: 2,
|
||||
},
|
||||
{
|
||||
pkey: 'APP Key',
|
||||
pval: 'smtp.exmail.qq.com',
|
||||
type: 'text',
|
||||
sort: 3,
|
||||
},
|
||||
{
|
||||
pkey: 'APP Secret',
|
||||
pval: 'smtp.exmail.qq.com',
|
||||
type: 'pwd',
|
||||
sort: 4,
|
||||
},
|
||||
{
|
||||
pkey: t('system.callback_domain_name'),
|
||||
pval: 'https://de.fit2cloud.com',
|
||||
type: 'text',
|
||||
sort: 5,
|
||||
},
|
||||
])
|
||||
const info = ref({}) as any
|
||||
const mappingArray = ['agentId', 'appKey', 'appSecret', 'callBack', 'enable']
|
||||
const search = () => {
|
||||
const url = '/dingtalk/info'
|
||||
request.get(url).then((res) => {
|
||||
info.value = res.data
|
||||
existInfo.value = info.value['agentId']
|
||||
for (let index = 0; index < settingList.length; index++) {
|
||||
const element = settingList[index]
|
||||
const key = mappingArray[index]
|
||||
if (index === 4) {
|
||||
element['pval'] = res.data[key] ? t('chart.open') : t('chart.close')
|
||||
} else {
|
||||
element['pval'] = res.data[key] || '-'
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const switchEnableApi = (enable: any) => {
|
||||
const url = '/dingtalk/switchEnable'
|
||||
const data = { enable }
|
||||
request.post(url, data).catch(() => {
|
||||
info.value.enable = false
|
||||
})
|
||||
}
|
||||
const edit = () => {
|
||||
editor?.value.edit(info.value)
|
||||
}
|
||||
const validate = () => {
|
||||
if (info.value?.appKey && info.value?.appSecret && info.value?.callBack) {
|
||||
validateHandler()
|
||||
}
|
||||
}
|
||||
const validateHandler = () => {
|
||||
const url = '/dingtalk/validate'
|
||||
const data = info.value
|
||||
request
|
||||
.post(url, data)
|
||||
.then(() => {
|
||||
info.value.valid = true
|
||||
ElMessage.success(t('datasource.validate_success'))
|
||||
})
|
||||
.catch(() => {
|
||||
info.value.enable = false
|
||||
info.value.valid = false
|
||||
})
|
||||
}
|
||||
search()
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.platform-head-container {
|
||||
height: 41px;
|
||||
border-bottom: 1px solid #1f232926;
|
||||
}
|
||||
.just-head {
|
||||
height: auto !important;
|
||||
border: none !important;
|
||||
}
|
||||
.platform-setting-head {
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.platform-setting-head-left {
|
||||
display: flex;
|
||||
.lead-left-icon {
|
||||
display: flex;
|
||||
line-height: 24px;
|
||||
align-items: center;
|
||||
i {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 20px;
|
||||
}
|
||||
span {
|
||||
margin-left: 4px;
|
||||
font-family: var(--de-custom_font, 'PingFang');
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
.lead-left-status {
|
||||
margin-left: 4px;
|
||||
height: 24px;
|
||||
background: #34c72433;
|
||||
padding: 0 6px;
|
||||
font-size: 14px;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
span {
|
||||
line-height: 24px;
|
||||
color: #2ca91f;
|
||||
}
|
||||
}
|
||||
.invalid {
|
||||
background: #f54a4533 !important;
|
||||
span {
|
||||
color: #d03f3b !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.platform-setting-head-right-btn {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
.platform-setting-head-right {
|
||||
height: 22px;
|
||||
line-height: 24px;
|
||||
display: flex;
|
||||
span {
|
||||
margin-right: 8px;
|
||||
font-size: 14px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
}
|
||||
.status-switch {
|
||||
line-height: 22px !important;
|
||||
height: 22px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.platform-setting-main {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding: 16px 0 0 0 !important;
|
||||
::v-deep(.info-template-content) {
|
||||
display: contents !important;
|
||||
}
|
||||
}
|
||||
.platform-foot-container {
|
||||
height: 32px;
|
||||
margin-top: -7px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<p class="router-title">{{ t('platform.title') }}</p>
|
||||
|
||||
<div class="sys-setting-p">
|
||||
<div class="container-sys-platform">
|
||||
<wecom-info />
|
||||
</div>
|
||||
<!-- <div class="container-sys-platform not-first">
|
||||
<dingtalk-info />
|
||||
</div> -->
|
||||
<!-- <div class="container-sys-platform not-first">
|
||||
<lark-info />
|
||||
</div>
|
||||
<div class="container-sys-platform not-first">
|
||||
<larksuite-info />
|
||||
</div> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import WecomInfo from './wecom/WecomInfo.vue'
|
||||
/* import DingtalkInfo from './dingtalk/DingtalkInfo.vue' */
|
||||
/* import LarkInfo from './lark/LarkInfo.vue'
|
||||
import LarksuiteInfo from './larksuite/LarksuiteInfo.vue' */
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.router-title {
|
||||
color: #1f2329;
|
||||
font-feature-settings:
|
||||
'clig' off,
|
||||
'liga' off;
|
||||
font-family: var(--de-custom_font, 'PingFang');
|
||||
font-size: 20px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 28px;
|
||||
}
|
||||
.sys-setting-p {
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
height: calc(100vh - 136px);
|
||||
box-sizing: border-box;
|
||||
margin-top: 16px;
|
||||
}
|
||||
.container-sys-platform {
|
||||
padding: 24px;
|
||||
overflow: hidden;
|
||||
//border-radius: 4px;
|
||||
background: var(--ContentBG, #ffffff);
|
||||
|
||||
border-radius: 12px;
|
||||
border: 1px solid #dee0e3;
|
||||
}
|
||||
.not-first {
|
||||
margin-top: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,262 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ElMessage, ElLoading } from 'element-plus-secondary'
|
||||
import { request } from '@/utils/request'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import type { FormInstance, FormRules } from 'element-plus-secondary'
|
||||
const { t } = useI18n()
|
||||
const dialogVisible = ref(false)
|
||||
const loadingInstance = ref<ReturnType<typeof ElLoading.service> | null>(null)
|
||||
const larkForm = ref<FormInstance>()
|
||||
interface LarkForm {
|
||||
appId?: string
|
||||
appSecret?: string
|
||||
callBack?: string
|
||||
enable?: string
|
||||
valid?: string
|
||||
}
|
||||
const state = reactive({
|
||||
form: reactive<LarkForm>({
|
||||
appId: '',
|
||||
appSecret: '',
|
||||
callBack: '',
|
||||
enable: 'false',
|
||||
valid: 'false',
|
||||
}),
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
const validateUrl = (rule, value, callback) => {
|
||||
const reg = new RegExp(/(http|https):\/\/([\w.]+\/?)\S*/)
|
||||
if (!reg.test(value)) {
|
||||
callback(new Error(t('system.incorrect_please_re_enter')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
const rule = reactive<FormRules>({
|
||||
appId: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 5,
|
||||
max: 20,
|
||||
message: t('common.input_limit', [5, 20]),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
appSecret: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 5,
|
||||
max: 50,
|
||||
message: t('common.input_limit', [5, 50]),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
callBack: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 10,
|
||||
max: 100,
|
||||
message: t('common.input_limit', [10, 100]),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{ required: true, validator: validateUrl, trigger: 'blur' },
|
||||
],
|
||||
enable: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
valid: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const edit = (row: any) => {
|
||||
state.form = {
|
||||
appId: row.appId,
|
||||
appSecret: row.appSecret,
|
||||
callBack: row.callBack,
|
||||
enable: row.enable,
|
||||
valid: row.valid,
|
||||
}
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const emits = defineEmits(['saved'])
|
||||
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
const param = { ...state.form }
|
||||
const method = request.post('/lark/create', param)
|
||||
showLoading()
|
||||
method
|
||||
.then((res) => {
|
||||
if (!res.msg) {
|
||||
ElMessage.success(t('common.save_success'))
|
||||
emits('saved')
|
||||
reset()
|
||||
}
|
||||
closeLoading()
|
||||
})
|
||||
.catch(() => {
|
||||
closeLoading()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const resetForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.resetFields()
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
resetForm(larkForm.value)
|
||||
}
|
||||
|
||||
const showLoading = () => {
|
||||
loadingInstance.value = ElLoading.service({
|
||||
target: '.platform-info-drawer',
|
||||
})
|
||||
}
|
||||
const closeLoading = () => {
|
||||
loadingInstance.value?.close()
|
||||
}
|
||||
|
||||
const validate = () => {
|
||||
const url = '/lark/validate'
|
||||
const data = state.form
|
||||
showLoading()
|
||||
request
|
||||
.post(url, data)
|
||||
.then(() => {
|
||||
state.form.valid = 'true'
|
||||
ElMessage.success(t('datasource.validate_success'))
|
||||
})
|
||||
.catch(() => {
|
||||
state.form.enable = 'false'
|
||||
state.form.valid = 'false'
|
||||
})
|
||||
.finally(() => {
|
||||
closeLoading()
|
||||
emits('saved')
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
edit,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-drawer
|
||||
v-model="dialogVisible"
|
||||
:title="t('system.feishu_settings')"
|
||||
modal-class="platform-info-drawer"
|
||||
size="600px"
|
||||
direction="rtl"
|
||||
>
|
||||
<el-form
|
||||
ref="larkForm"
|
||||
require-asterisk-position="right"
|
||||
:model="state.form"
|
||||
:rules="rule"
|
||||
label-width="80px"
|
||||
label-position="top"
|
||||
>
|
||||
<el-form-item label="APP Key" prop="appId">
|
||||
<el-input v-model="state.form.appId" :placeholder="t('common.please_input')" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="APP Secret" prop="appSecret">
|
||||
<el-input
|
||||
v-model="state.form.appSecret"
|
||||
type="password"
|
||||
show-password
|
||||
:placeholder="t('common.please_input')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('system.callback_domain_name')" prop="callBack">
|
||||
<el-input v-model="state.form.callBack" :placeholder="t('common.please_input')" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button secondary @click="resetForm(larkForm)">{{ t('common.cancel') }}</el-button>
|
||||
<el-button
|
||||
secondary
|
||||
:disabled="!state.form.appId || !state.form.appSecret || !state.form.callBack"
|
||||
@click="validate"
|
||||
>
|
||||
{{ t('commons.validate') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="submitForm(larkForm)">
|
||||
{{ t('commons.save') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.platform-info-drawer {
|
||||
.ed-drawer__footer {
|
||||
height: 64px !important;
|
||||
padding: 16px 24px !important;
|
||||
.dialog-footer {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
.ed-form-item__label {
|
||||
line-height: 22px !important;
|
||||
height: 22px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="less" scoped>
|
||||
.platform-info-drawer {
|
||||
.ed-form-item {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.is-error {
|
||||
margin-bottom: 40px !important;
|
||||
}
|
||||
.input-with-select {
|
||||
.ed-input-group__prepend {
|
||||
width: 72px;
|
||||
background-color: #fff;
|
||||
padding: 0 20px;
|
||||
color: #1f2329;
|
||||
text-align: center;
|
||||
font-family: var(--de-custom_font, 'PingFang');
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,240 @@
|
||||
<template>
|
||||
<div class="platform-head-container" :class="{ 'just-head': !existInfo }">
|
||||
<div class="platform-setting-head">
|
||||
<div class="platform-setting-head-left">
|
||||
<div class="lead-left-icon">
|
||||
<el-icon>
|
||||
<Icon name="logo_lark"><logo_lark class="svg-icon" /></Icon>
|
||||
</el-icon>
|
||||
<span>{{ t('user.feishu') }}</span>
|
||||
</div>
|
||||
<div v-if="existInfo" class="lead-left-status" :class="{ invalid: !info.valid }">
|
||||
<span>{{
|
||||
info.valid ? t('datasource.valid') : info.appId ? t('datasource.invalid') : ''
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="existInfo" class="platform-setting-head-right">
|
||||
<span>{{ info.enable ? t('system.enabled') : t('system.close') }}</span>
|
||||
<el-switch
|
||||
v-if="info.valid"
|
||||
v-model="info.enable"
|
||||
class="status-switch"
|
||||
@change="switchEnableApi"
|
||||
/>
|
||||
<el-tooltip
|
||||
v-else
|
||||
class="box-item"
|
||||
effect="dark"
|
||||
:content="t('platform.can_enable_it')"
|
||||
placement="top"
|
||||
>
|
||||
<el-switch
|
||||
v-model="info.enable"
|
||||
disabled=""
|
||||
class="status-switch"
|
||||
@change="switchEnableApi"
|
||||
/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div v-else class="platform-setting-head-right-btn">
|
||||
<el-button type="primary" @click="edit">{{ t('system.access') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<InfoTemplate
|
||||
v-if="existInfo"
|
||||
class="platform-setting-main"
|
||||
:copy-list="copyList"
|
||||
setting-key="lark"
|
||||
setting-title=""
|
||||
:hide-head="true"
|
||||
:setting-data="settingList"
|
||||
@edit="edit"
|
||||
/>
|
||||
<div v-if="existInfo" class="platform-foot-container">
|
||||
<el-button type="primary" @click="edit">
|
||||
{{ t('commons.edit') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
secondary
|
||||
:disabled="!info.appId || !info.appSecret || !info.callBack"
|
||||
@click="validate"
|
||||
>{{ t('commons.validate') }}</el-button
|
||||
>
|
||||
</div>
|
||||
<lark-edit ref="editor" @saved="search" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import logo_lark from '@/assets/svg/logo_lark.svg'
|
||||
import { ref, reactive } from 'vue'
|
||||
import InfoTemplate from '../common/InfoTemplate.vue'
|
||||
import LarkEdit from './LarkEdit.vue'
|
||||
import { request } from '@/utils/request'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { ElMessage } from 'element-plus-secondary'
|
||||
const existInfo = ref(false)
|
||||
const { t } = useI18n()
|
||||
const editor = ref()
|
||||
const copyList = ['APP Key', 'APP Secret']
|
||||
const settingList = reactive([
|
||||
{
|
||||
pkey: 'APP Key',
|
||||
pval: 'smtp.exmail.qq.com',
|
||||
type: 'text',
|
||||
sort: 1,
|
||||
},
|
||||
{
|
||||
pkey: 'APP Secret',
|
||||
pval: 'smtp.exmail.qq.com',
|
||||
type: 'pwd',
|
||||
sort: 2,
|
||||
},
|
||||
{
|
||||
pkey: t('system.callback_domain_name'),
|
||||
pval: 'https://de.fit2cloud.com',
|
||||
type: 'text',
|
||||
sort: 3,
|
||||
},
|
||||
])
|
||||
const info = ref({}) as any
|
||||
const mappingArray = ['appId', 'appSecret', 'callBack', 'enable']
|
||||
const search = () => {
|
||||
const url = '/lark/info'
|
||||
request.get(url).then((res) => {
|
||||
info.value = res.data
|
||||
existInfo.value = info.value['appId']
|
||||
for (let index = 0; index < settingList.length; index++) {
|
||||
const element = settingList[index]
|
||||
const key = mappingArray[index]
|
||||
if (index === 3) {
|
||||
element['pval'] = res.data[key] ? t('chart.open') : t('chart.close')
|
||||
} else {
|
||||
element['pval'] = res.data[key] || '-'
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const switchEnableApi = (enable: any) => {
|
||||
const url = '/lark/switchEnable'
|
||||
const data = { enable }
|
||||
request.post(url, data).catch(() => {
|
||||
info.value.enable = false
|
||||
})
|
||||
}
|
||||
const edit = () => {
|
||||
editor?.value.edit(info.value)
|
||||
}
|
||||
const validate = () => {
|
||||
if (info.value?.appId && info.value?.appSecret && info.value?.callBack) {
|
||||
validateHandler()
|
||||
}
|
||||
}
|
||||
const validateHandler = () => {
|
||||
const url = '/lark/validate'
|
||||
const data = info.value
|
||||
request
|
||||
.post(url, data)
|
||||
.then(() => {
|
||||
info.value.valid = true
|
||||
ElMessage.success(t('datasource.validate_success'))
|
||||
})
|
||||
.catch(() => {
|
||||
info.value.enable = false
|
||||
info.value.valid = false
|
||||
})
|
||||
}
|
||||
search()
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.platform-head-container {
|
||||
height: 41px;
|
||||
border-bottom: 1px solid #1f232926;
|
||||
}
|
||||
.just-head {
|
||||
height: auto !important;
|
||||
border: none !important;
|
||||
}
|
||||
.platform-setting-head {
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.platform-setting-head-left {
|
||||
display: flex;
|
||||
.lead-left-icon {
|
||||
display: flex;
|
||||
line-height: 24px;
|
||||
align-items: center;
|
||||
i {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 20px;
|
||||
}
|
||||
span {
|
||||
margin-left: 4px;
|
||||
font-family: var(--de-custom_font, 'PingFang');
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
.lead-left-status {
|
||||
margin-left: 4px;
|
||||
height: 24px;
|
||||
background: #34c72433;
|
||||
padding: 0 6px;
|
||||
font-size: 14px;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
span {
|
||||
line-height: 24px;
|
||||
color: #2ca91f;
|
||||
}
|
||||
}
|
||||
.invalid {
|
||||
background: #f54a4533 !important;
|
||||
span {
|
||||
color: #d03f3b !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.platform-setting-head-right-btn {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
.platform-setting-head-right {
|
||||
height: 22px;
|
||||
line-height: 24px;
|
||||
display: flex;
|
||||
span {
|
||||
margin-right: 8px;
|
||||
font-size: 14px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
}
|
||||
.status-switch {
|
||||
line-height: 22px !important;
|
||||
height: 22px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.platform-setting-main {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding: 16px 0 0 0 !important;
|
||||
::v-deep(.info-template-content) {
|
||||
display: contents !important;
|
||||
}
|
||||
}
|
||||
.platform-foot-container {
|
||||
height: 32px;
|
||||
margin-top: -7px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,262 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ElMessage, ElLoading } from 'element-plus-secondary'
|
||||
import { request } from '@/utils/request'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import type { FormInstance, FormRules } from 'element-plus-secondary'
|
||||
const { t } = useI18n()
|
||||
const dialogVisible = ref(false)
|
||||
const loadingInstance = ref<ReturnType<typeof ElLoading.service> | null>(null)
|
||||
const larksuiteForm = ref<FormInstance>()
|
||||
interface LarksuiteForm {
|
||||
appId?: string
|
||||
appSecret?: string
|
||||
callBack?: string
|
||||
enable?: string
|
||||
valid?: string
|
||||
}
|
||||
const state = reactive({
|
||||
form: reactive<LarksuiteForm>({
|
||||
appId: '',
|
||||
appSecret: '',
|
||||
callBack: '',
|
||||
enable: 'false',
|
||||
valid: 'false',
|
||||
}),
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
const validateUrl = (rule, value, callback) => {
|
||||
const reg = new RegExp(/(http|https):\/\/([\w.]+\/?)\S*/)
|
||||
if (!reg.test(value)) {
|
||||
callback(new Error(t('system.incorrect_please_re_enter')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
const rule = reactive<FormRules>({
|
||||
appId: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 5,
|
||||
max: 20,
|
||||
message: t('common.input_limit', [5, 20]),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
appSecret: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 5,
|
||||
max: 50,
|
||||
message: t('common.input_limit', [5, 50]),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
callBack: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 10,
|
||||
max: 100,
|
||||
message: t('common.input_limit', [10, 100]),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{ required: true, validator: validateUrl, trigger: 'blur' },
|
||||
],
|
||||
enable: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
valid: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'change',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const edit = (row: any) => {
|
||||
state.form = {
|
||||
appId: row.appId,
|
||||
appSecret: row.appSecret,
|
||||
callBack: row.callBack,
|
||||
enable: row.enable,
|
||||
valid: row.valid,
|
||||
}
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const emits = defineEmits(['saved'])
|
||||
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
const param = { ...state.form }
|
||||
const method = request.post('/larksuite/create', param)
|
||||
showLoading()
|
||||
method
|
||||
.then((res) => {
|
||||
if (!res.msg) {
|
||||
ElMessage.success(t('common.save_success'))
|
||||
emits('saved')
|
||||
reset()
|
||||
}
|
||||
closeLoading()
|
||||
})
|
||||
.catch(() => {
|
||||
closeLoading()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const resetForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.resetFields()
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
resetForm(larksuiteForm.value)
|
||||
}
|
||||
|
||||
const showLoading = () => {
|
||||
loadingInstance.value = ElLoading.service({
|
||||
target: '.platform-info-drawer',
|
||||
})
|
||||
}
|
||||
const closeLoading = () => {
|
||||
loadingInstance.value?.close()
|
||||
}
|
||||
|
||||
const validate = () => {
|
||||
const url = '/larksuite/validate'
|
||||
const data = state.form
|
||||
showLoading()
|
||||
request
|
||||
.post(url, data)
|
||||
.then(() => {
|
||||
state.form.valid = 'true'
|
||||
ElMessage.success(t('datasource.validate_success'))
|
||||
})
|
||||
.catch(() => {
|
||||
state.form.enable = 'false'
|
||||
state.form.valid = 'false'
|
||||
})
|
||||
.finally(() => {
|
||||
closeLoading()
|
||||
emits('saved')
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
edit,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-drawer
|
||||
v-model="dialogVisible"
|
||||
:title="t('system.international_feishu_settings')"
|
||||
modal-class="platform-info-drawer"
|
||||
size="600px"
|
||||
direction="rtl"
|
||||
>
|
||||
<el-form
|
||||
ref="larksuiteForm"
|
||||
require-asterisk-position="right"
|
||||
:model="state.form"
|
||||
:rules="rule"
|
||||
label-width="80px"
|
||||
label-position="top"
|
||||
>
|
||||
<el-form-item label="APP Key" prop="appId">
|
||||
<el-input v-model="state.form.appId" :placeholder="t('common.please_input')" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="APP Secret" prop="appSecret">
|
||||
<el-input
|
||||
v-model="state.form.appSecret"
|
||||
type="password"
|
||||
show-password
|
||||
:placeholder="t('common.please_input')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('system.callback_domain_name')" prop="callBack">
|
||||
<el-input v-model="state.form.callBack" :placeholder="t('common.please_input')" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button secondary @click="resetForm(larksuiteForm)">{{ t('common.cancel') }}</el-button>
|
||||
<el-button
|
||||
secondary
|
||||
:disabled="!state.form.appId || !state.form.appSecret || !state.form.callBack"
|
||||
@click="validate"
|
||||
>
|
||||
{{ t('commons.validate') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="submitForm(larksuiteForm)">
|
||||
{{ t('commons.save') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.platform-info-drawer {
|
||||
.ed-drawer__footer {
|
||||
height: 64px !important;
|
||||
padding: 16px 24px !important;
|
||||
.dialog-footer {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
.ed-form-item__label {
|
||||
line-height: 22px !important;
|
||||
height: 22px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="less" scoped>
|
||||
.platform-info-drawer {
|
||||
.ed-form-item {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.is-error {
|
||||
margin-bottom: 40px !important;
|
||||
}
|
||||
.input-with-select {
|
||||
.ed-input-group__prepend {
|
||||
width: 72px;
|
||||
background-color: #fff;
|
||||
padding: 0 20px;
|
||||
color: #1f2329;
|
||||
text-align: center;
|
||||
font-family: var(--de-custom_font, 'PingFang');
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,241 @@
|
||||
<template>
|
||||
<div class="platform-head-container" :class="{ 'just-head': !existInfo }">
|
||||
<div class="platform-setting-head">
|
||||
<div class="platform-setting-head-left">
|
||||
<div class="lead-left-icon">
|
||||
<el-icon>
|
||||
<Icon name="logo_lark"><logo_lark class="svg-icon" /></Icon>
|
||||
</el-icon>
|
||||
<span>{{ t('system.international_feishu') }}</span>
|
||||
</div>
|
||||
<div v-if="existInfo" class="lead-left-status" :class="{ invalid: !info.valid }">
|
||||
<span>{{
|
||||
info.valid ? t('datasource.valid') : info.appId ? t('datasource.invalid') : ''
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="existInfo" class="platform-setting-head-right">
|
||||
<span>{{ info.enable ? t('system.enabled') : t('system.close') }}</span>
|
||||
<el-switch
|
||||
v-if="info.valid"
|
||||
v-model="info.enable"
|
||||
class="status-switch"
|
||||
@change="switchEnableApi"
|
||||
/>
|
||||
<el-tooltip
|
||||
v-else
|
||||
class="box-item"
|
||||
effect="dark"
|
||||
:content="t('platform.can_enable_it')"
|
||||
placement="top"
|
||||
>
|
||||
<el-switch
|
||||
v-model="info.enable"
|
||||
disabled=""
|
||||
class="status-switch"
|
||||
@change="switchEnableApi"
|
||||
/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div v-else class="platform-setting-head-right-btn">
|
||||
<el-button type="primary" @click="edit">{{ t('system.access') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<InfoTemplate
|
||||
v-if="existInfo"
|
||||
class="platform-setting-main"
|
||||
:copy-list="copyList"
|
||||
setting-key="larksuite"
|
||||
setting-title=""
|
||||
:hide-head="true"
|
||||
:setting-data="settingList"
|
||||
@edit="edit"
|
||||
/>
|
||||
<div v-if="existInfo" class="platform-foot-container">
|
||||
<el-button type="primary" @click="edit">
|
||||
{{ t('commons.edit') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
secondary
|
||||
:disabled="!info.appId || !info.appSecret || !info.callBack"
|
||||
@click="validate"
|
||||
>{{ t('commons.validate') }}</el-button
|
||||
>
|
||||
</div>
|
||||
<larksuite-edit ref="editor" @saved="search" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import logo_lark from '@/assets/svg/logo_lark.svg'
|
||||
import { ref, reactive } from 'vue'
|
||||
import InfoTemplate from '../common/InfoTemplate.vue'
|
||||
import LarksuiteEdit from './LarksuiteEdit.vue'
|
||||
import { request } from '@/utils/request'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { ElMessage } from 'element-plus-secondary'
|
||||
const { t } = useI18n()
|
||||
|
||||
const existInfo = ref(false)
|
||||
const editor = ref()
|
||||
const copyList = ['APP Key', 'APP Secret']
|
||||
const settingList = reactive([
|
||||
{
|
||||
pkey: 'APP Key',
|
||||
pval: 'smtp.exmail.qq.com',
|
||||
type: 'text',
|
||||
sort: 1,
|
||||
},
|
||||
{
|
||||
pkey: 'APP Secret',
|
||||
pval: 'smtp.exmail.qq.com',
|
||||
type: 'pwd',
|
||||
sort: 2,
|
||||
},
|
||||
{
|
||||
pkey: t('system.callback_domain_name'),
|
||||
pval: 'https://de.fit2cloud.com',
|
||||
type: 'text',
|
||||
sort: 3,
|
||||
},
|
||||
])
|
||||
const info = ref({}) as any
|
||||
const mappingArray = ['appId', 'appSecret', 'callBack', 'enable']
|
||||
const search = () => {
|
||||
const url = '/larksuite/info'
|
||||
request.get(url).then((res) => {
|
||||
info.value = res.data
|
||||
existInfo.value = info.value['appId']
|
||||
for (let index = 0; index < settingList.length; index++) {
|
||||
const element = settingList[index]
|
||||
const key = mappingArray[index]
|
||||
if (index === 3) {
|
||||
element['pval'] = res.data[key] ? t('chart.open') : t('chart.close')
|
||||
} else {
|
||||
element['pval'] = res.data[key] || '-'
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const switchEnableApi = (enable: any) => {
|
||||
const url = '/larksuite/switchEnable'
|
||||
const data = { enable }
|
||||
request.post(url, data).catch(() => {
|
||||
info.value.enable = false
|
||||
})
|
||||
}
|
||||
const edit = () => {
|
||||
editor?.value.edit(info.value)
|
||||
}
|
||||
const validate = () => {
|
||||
if (info.value?.appId && info.value?.appSecret && info.value?.callBack) {
|
||||
validateHandler()
|
||||
}
|
||||
}
|
||||
const validateHandler = () => {
|
||||
const url = '/larksuite/validate'
|
||||
const data = info.value
|
||||
request
|
||||
.post(url, data)
|
||||
.then(() => {
|
||||
info.value.valid = true
|
||||
ElMessage.success(t('datasource.validate_success'))
|
||||
})
|
||||
.catch(() => {
|
||||
info.value.enable = false
|
||||
info.value.valid = false
|
||||
})
|
||||
}
|
||||
search()
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.platform-head-container {
|
||||
height: 41px;
|
||||
border-bottom: 1px solid #1f232926;
|
||||
}
|
||||
.just-head {
|
||||
height: auto !important;
|
||||
border: none !important;
|
||||
}
|
||||
.platform-setting-head {
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.platform-setting-head-left {
|
||||
display: flex;
|
||||
.lead-left-icon {
|
||||
display: flex;
|
||||
line-height: 24px;
|
||||
align-items: center;
|
||||
i {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 20px;
|
||||
}
|
||||
span {
|
||||
margin-left: 4px;
|
||||
font-family: var(--de-custom_font, 'PingFang');
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
.lead-left-status {
|
||||
margin-left: 4px;
|
||||
height: 24px;
|
||||
background: #34c72433;
|
||||
padding: 0 6px;
|
||||
font-size: 14px;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
span {
|
||||
line-height: 24px;
|
||||
color: #2ca91f;
|
||||
}
|
||||
}
|
||||
.invalid {
|
||||
background: #f54a4533 !important;
|
||||
span {
|
||||
color: #d03f3b !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.platform-setting-head-right-btn {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
.platform-setting-head-right {
|
||||
height: 22px;
|
||||
line-height: 24px;
|
||||
display: flex;
|
||||
span {
|
||||
margin-right: 8px;
|
||||
font-size: 14px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
}
|
||||
.status-switch {
|
||||
line-height: 22px !important;
|
||||
height: 22px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.platform-setting-main {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding: 16px 0 0 0 !important;
|
||||
::v-deep(.info-template-content) {
|
||||
display: contents !important;
|
||||
}
|
||||
}
|
||||
.platform-foot-container {
|
||||
height: 32px;
|
||||
margin-top: -7px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,258 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ElMessage, ElLoading } from 'element-plus-secondary'
|
||||
import { request } from '@/utils/request'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import type { FormInstance, FormRules } from 'element-plus-secondary'
|
||||
const { t } = useI18n()
|
||||
const dialogVisible = ref(false)
|
||||
const loadingInstance = ref<ReturnType<typeof ElLoading.service> | null>(null)
|
||||
const wecomForm = ref<FormInstance>()
|
||||
interface WecomkForm {
|
||||
corpid?: string
|
||||
agent_id?: string
|
||||
corpsecret?: string
|
||||
}
|
||||
const state = reactive({
|
||||
form: reactive<WecomkForm>({
|
||||
agent_id: '',
|
||||
corpid: '',
|
||||
corpsecret: '',
|
||||
}),
|
||||
})
|
||||
const origin = ref(6)
|
||||
const id = ref()
|
||||
const rule = reactive<FormRules>({
|
||||
agent_id: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 5,
|
||||
max: 20,
|
||||
message: t('common.input_limit', [5, 20]),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
corpid: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 5,
|
||||
max: 20,
|
||||
message: t('common.input_limit', [5, 20]),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
corpsecret: [
|
||||
{
|
||||
required: true,
|
||||
message: t('common.require'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
min: 5,
|
||||
max: 100,
|
||||
message: t('common.input_limit', [5, 100]),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const edit = (row: any) => {
|
||||
state.form = {
|
||||
agent_id: row.agent_id,
|
||||
corpid: row.corpid,
|
||||
corpsecret: row.corpsecret,
|
||||
}
|
||||
if (row?.id) {
|
||||
id.value = row.id
|
||||
}
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const emits = defineEmits(['saved'])
|
||||
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
const param = { ...state.form }
|
||||
|
||||
const data = {
|
||||
id: origin.value,
|
||||
type: origin.value,
|
||||
name: 'wecom',
|
||||
config: JSON.stringify(param),
|
||||
}
|
||||
const method = id.value
|
||||
? request.put('/system/authentication', data, { requestOptions: { silent: true } })
|
||||
: request.post('/system/authentication', data, { requestOptions: { silent: true } })
|
||||
showLoading()
|
||||
method
|
||||
.then((res) => {
|
||||
if (!res.msg) {
|
||||
ElMessage.success(t('common.save_success'))
|
||||
emits('saved')
|
||||
reset()
|
||||
}
|
||||
})
|
||||
.catch((e: any) => {
|
||||
if (
|
||||
e.message?.startsWith('sqlbot_authentication_connect_error') ||
|
||||
e.response?.data?.startsWith('sqlbot_authentication_connect_error')
|
||||
) {
|
||||
emits('saved')
|
||||
ElMessage.error(t('ds.connection_failed'))
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
closeLoading()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const resetForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.resetFields()
|
||||
dialogVisible.value = false
|
||||
id.value = null
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
resetForm(wecomForm.value)
|
||||
}
|
||||
|
||||
const showLoading = () => {
|
||||
loadingInstance.value = ElLoading.service({
|
||||
target: '.platform-info-drawer',
|
||||
})
|
||||
}
|
||||
const closeLoading = () => {
|
||||
loadingInstance.value?.close()
|
||||
}
|
||||
|
||||
const validate = () => {
|
||||
const url = '/system/authentication/status'
|
||||
const config_data = state.form
|
||||
const data = {
|
||||
type: origin.value,
|
||||
name: 'wecom',
|
||||
config: JSON.stringify(config_data),
|
||||
}
|
||||
showLoading()
|
||||
request
|
||||
.patch(url, data)
|
||||
.then((res) => {
|
||||
if (res) {
|
||||
ElMessage.success(t('ds.connection_success'))
|
||||
} else {
|
||||
ElMessage.error(t('ds.connection_failed'))
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
closeLoading()
|
||||
emits('saved')
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
edit,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-drawer
|
||||
v-model="dialogVisible"
|
||||
:title="t('user.wechat_for_business')"
|
||||
modal-class="platform-info-drawer"
|
||||
size="600px"
|
||||
direction="rtl"
|
||||
>
|
||||
<el-form
|
||||
ref="wecomForm"
|
||||
require-asterisk-position="right"
|
||||
:model="state.form"
|
||||
:rules="rule"
|
||||
label-width="80px"
|
||||
label-position="top"
|
||||
>
|
||||
<el-form-item label="Corpid" prop="corpid">
|
||||
<el-input v-model="state.form.corpid" :placeholder="t('common.please_input')" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="AgentId" prop="agent_id">
|
||||
<el-input v-model="state.form.agent_id" :placeholder="t('common.please_input')" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="APP Secret" prop="corpsecret">
|
||||
<el-input
|
||||
v-model="state.form.corpsecret"
|
||||
type="password"
|
||||
show-password
|
||||
:placeholder="t('common.please_input')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="resetForm(wecomForm)">{{ t('common.cancel') }}</el-button>
|
||||
<el-button
|
||||
:disabled="!state.form.corpid || !state.form.corpsecret || !state.form.agent_id"
|
||||
@click="validate"
|
||||
>
|
||||
{{ t('ds.check') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="submitForm(wecomForm)">
|
||||
{{ t('common.save') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.platform-info-drawer {
|
||||
.ed-drawer__footer {
|
||||
height: 64px !important;
|
||||
padding: 16px 24px !important;
|
||||
.dialog-footer {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
.ed-form-item__label {
|
||||
line-height: 22px !important;
|
||||
height: 22px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="less" scoped>
|
||||
.platform-info-drawer {
|
||||
.ed-form-item {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.is-error {
|
||||
margin-bottom: 40px !important;
|
||||
}
|
||||
.input-with-select {
|
||||
.ed-input-group__prepend {
|
||||
width: 72px;
|
||||
background-color: #fff;
|
||||
padding: 0 20px;
|
||||
color: #1f2329;
|
||||
text-align: center;
|
||||
font-family: var(--de-custom_font, 'PingFang');
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,247 @@
|
||||
<template>
|
||||
<div class="platform-head-container" :class="{ 'just-head': !existInfo }">
|
||||
<div class="platform-setting-head">
|
||||
<div class="platform-setting-head-left">
|
||||
<div class="lead-left-icon">
|
||||
<el-icon>
|
||||
<Icon name="logo_wechat-work"><logo_wechatWork class="svg-icon" /></Icon>
|
||||
</el-icon>
|
||||
<span>{{ t('user.wechat_for_business') }}</span>
|
||||
</div>
|
||||
<div v-if="existInfo" class="lead-left-status" :class="{ invalid: !info.valid }">
|
||||
<span>{{
|
||||
info.valid ? t('authentication.valid') : info.corpid ? t('authentication.invalid') : ''
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="existInfo" class="platform-setting-head-right">
|
||||
<span>{{ info.enable ? t('platform.status_open') : t('platform.status_close') }}</span>
|
||||
<el-switch
|
||||
v-if="info.valid"
|
||||
v-model="info.enable"
|
||||
class="status-switch"
|
||||
@change="switchEnableApi"
|
||||
/>
|
||||
<el-tooltip
|
||||
v-else
|
||||
class="box-item"
|
||||
effect="dark"
|
||||
:content="t('platform.can_enable_it')"
|
||||
placement="top"
|
||||
>
|
||||
<el-switch
|
||||
v-model="info.enable"
|
||||
disabled=""
|
||||
class="status-switch"
|
||||
@change="switchEnableApi"
|
||||
/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div v-else class="platform-setting-head-right-btn">
|
||||
<el-button type="primary" @click="edit">{{ t('platform.access_in') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<InfoTemplate
|
||||
v-if="existInfo"
|
||||
class="platform-setting-main"
|
||||
:copy-list="copyList"
|
||||
setting-key="wecom"
|
||||
setting-title=""
|
||||
:hide-head="true"
|
||||
:setting-data="settingList"
|
||||
@edit="edit"
|
||||
/>
|
||||
<div v-if="existInfo" class="platform-foot-container">
|
||||
<el-button type="primary" @click="edit">
|
||||
{{ t('datasource.edit') }}
|
||||
</el-button>
|
||||
<el-button secondary :disabled="!info.corpid || !info.corpsecret" @click="validate">{{
|
||||
t('ds.check')
|
||||
}}</el-button>
|
||||
</div>
|
||||
<wecom-edit ref="editor" @saved="search" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import logo_wechatWork from '@/assets/svg/logo_wechat-work.svg'
|
||||
import { ref, reactive } from 'vue'
|
||||
import InfoTemplate from '../common/InfoTemplate.vue'
|
||||
import WecomEdit from './WecomEdit.vue'
|
||||
import { request } from '@/utils/request'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { ElMessage } from 'element-plus-secondary'
|
||||
const { t } = useI18n()
|
||||
const existInfo = ref(false)
|
||||
const editor = ref()
|
||||
const origin = ref(6)
|
||||
const copyList = ['CorpId', 'APP Secret']
|
||||
const settingList = reactive([
|
||||
{
|
||||
pkey: 'CorpId',
|
||||
pval: '',
|
||||
type: 'text',
|
||||
sort: 1,
|
||||
},
|
||||
{
|
||||
pkey: 'AgentId',
|
||||
pval: '',
|
||||
type: 'text',
|
||||
sort: 2,
|
||||
},
|
||||
{
|
||||
pkey: 'APP Secret',
|
||||
pval: '',
|
||||
type: 'pwd',
|
||||
sort: 3,
|
||||
},
|
||||
])
|
||||
const info = ref({}) as any
|
||||
const mappingArray = ['corpid', 'agent_id', 'corpsecret', 'enable']
|
||||
const search = () => {
|
||||
const url = `system/authentication/${origin.value}`
|
||||
request.get(url).then((res) => {
|
||||
const config = res?.config
|
||||
let configData = { enable: res?.enable, valid: res?.valid } as any
|
||||
if (config) {
|
||||
const configObj = JSON.parse(config)
|
||||
Object.assign(configData, configObj)
|
||||
}
|
||||
info.value = configData
|
||||
if (res?.id) {
|
||||
info.value['id'] = res.id
|
||||
}
|
||||
existInfo.value = info.value['agent_id']
|
||||
for (let index = 0; index < settingList.length; index++) {
|
||||
const element = settingList[index]
|
||||
const key = mappingArray[index]
|
||||
element['pval'] = configData[key] || '-'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const switchEnableApi = (enable: any) => {
|
||||
const url = '/system/authentication/enable'
|
||||
const data = { id: origin.value, enable }
|
||||
request.patch(url, data).catch(() => {
|
||||
info.value.enable = false
|
||||
})
|
||||
}
|
||||
const edit = () => {
|
||||
editor?.value.edit(info.value)
|
||||
}
|
||||
const validate = () => {
|
||||
if (info.value?.agent_id && info.value?.corpsecret) {
|
||||
validateHandler()
|
||||
}
|
||||
}
|
||||
const validateHandler = () => {
|
||||
request
|
||||
.patch('/system/authentication/status', { type: origin.value, name: '', config: '' })
|
||||
.then((res) => {
|
||||
if (res) {
|
||||
info.value.valid = true
|
||||
ElMessage.success(t('ds.connection_success'))
|
||||
} else {
|
||||
ElMessage.error(t('ds.connection_failed'))
|
||||
info.value.enable = false
|
||||
info.value.valid = false
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
info.value.enable = false
|
||||
info.value.valid = false
|
||||
})
|
||||
}
|
||||
search()
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.platform-head-container {
|
||||
height: 41px;
|
||||
border-bottom: 1px solid #1f232926;
|
||||
}
|
||||
.just-head {
|
||||
height: auto !important;
|
||||
border: none !important;
|
||||
}
|
||||
.platform-setting-head {
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.platform-setting-head-left {
|
||||
display: flex;
|
||||
.lead-left-icon {
|
||||
display: flex;
|
||||
line-height: 24px;
|
||||
align-items: center;
|
||||
i {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 20px;
|
||||
}
|
||||
span {
|
||||
margin-left: 4px;
|
||||
font-family: var(--de-custom_font, 'PingFang');
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
.lead-left-status {
|
||||
margin-left: 4px;
|
||||
height: 24px;
|
||||
background: #34c72433;
|
||||
padding: 0 6px;
|
||||
font-size: 14px;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
span {
|
||||
line-height: 24px;
|
||||
color: #2ca91f;
|
||||
}
|
||||
}
|
||||
.invalid {
|
||||
background: #f54a4533 !important;
|
||||
span {
|
||||
color: #d03f3b !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.platform-setting-head-right-btn {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
.platform-setting-head-right {
|
||||
height: 22px;
|
||||
line-height: 24px;
|
||||
display: flex;
|
||||
span {
|
||||
margin-right: 8px;
|
||||
font-size: 14px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
}
|
||||
.status-switch {
|
||||
line-height: 22px !important;
|
||||
height: 22px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.platform-setting-main {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding: 16px 0 0 0 !important;
|
||||
::v-deep(.info-template-content) {
|
||||
display: contents !important;
|
||||
}
|
||||
}
|
||||
.platform-foot-container {
|
||||
height: 32px;
|
||||
margin-top: -7px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user