优化了一些问题
This commit is contained in:
@@ -1,164 +0,0 @@
|
||||
<template>
|
||||
<n-card class="oauth-provider-card" title="">
|
||||
<!-- 平台信息头部 -->
|
||||
<div class="oauth-provider-header">
|
||||
<div class="oauth-header-left">
|
||||
<span class="oauth-platform-icon">
|
||||
<img v-if="icon" :src="icon" :alt="name" class="oauth-platform-img" />
|
||||
<span v-else class="oauth-platform-text">{{ name.charAt(0) }}</span>
|
||||
</span>
|
||||
<div class="oauth-platform-info">
|
||||
<h4>{{ name }}</h4>
|
||||
<a :href="docUrl" target="_blank" class="oauth-doc-link">
|
||||
前往 {{ name }} 创建应用 ↗
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<n-switch v-model:value="modelValue.enabled" class="oauth-enable-switch">
|
||||
<template #checked>启用</template>
|
||||
<template #unchecked>停用</template>
|
||||
</n-switch>
|
||||
</div>
|
||||
|
||||
<!-- 表单区域(启用后才展开) -->
|
||||
<div v-if="modelValue.enabled" class="oauth-form-body">
|
||||
<n-form label-placement="top" class="aksrt-form oauth-form-grid">
|
||||
<n-form-item
|
||||
v-for="field in fields"
|
||||
:key="field.key"
|
||||
:label="field.label"
|
||||
>
|
||||
<n-input
|
||||
v-if="!field.readonly"
|
||||
v-model:value="modelValue[field.key]"
|
||||
:type="field.secret ? 'password' : 'text'"
|
||||
:show-password-on-click="field.secret"
|
||||
:placeholder="'输入 ' + field.label"
|
||||
size="large"
|
||||
/>
|
||||
<n-input
|
||||
v-else
|
||||
:value="callbackUrl"
|
||||
readonly
|
||||
size="large"
|
||||
style='font-family: "SF Mono", Consolas, monospace; font-size:13px;'
|
||||
/>
|
||||
<template v-if="field.hint" #feedback>
|
||||
<span class="aksrt-hint-text">{{ field.hint }}</span>
|
||||
</template>
|
||||
<template v-if="field.readonly && !field.hint" #feedback>
|
||||
<span class="aksrt-hint-text">将此地址填写到对应平台的「授权回调域 / 回调 URL」中</span>
|
||||
</template>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</div>
|
||||
|
||||
<!-- 未启用时的提示 -->
|
||||
<div v-else class="oauth-disabled-hint">
|
||||
<p>开启开关以配置此平台的 OAuth 凭证</p>
|
||||
</div>
|
||||
</n-card>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: { type: Object, required: true },
|
||||
name: { type: String, required: true },
|
||||
docUrl: { type: String, required: true },
|
||||
fields: { type: Array, required: true },
|
||||
icon: { type: String, default: '' },
|
||||
})
|
||||
|
||||
defineEmits(['update:modelValue'])
|
||||
|
||||
const callbackUrl = computed(() => {
|
||||
const siteUrl = window.aksrtAdminData?.siteUrl || window.location.origin
|
||||
return `${siteUrl}/oauth/callback/`
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.oauth-provider-card {
|
||||
border-radius: 12px !important;
|
||||
}
|
||||
|
||||
/* 平台头部 */
|
||||
.oauth-provider-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.oauth-header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.oauth-platform-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--aksrt-color-canvas);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.oauth-platform-img {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.oauth-platform-text {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: var(--aksrt-color-muted);
|
||||
}
|
||||
|
||||
.oauth-platform-info h4 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--aksrt-color-text);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.oauth-doc-link {
|
||||
font-size: 12px;
|
||||
color: var(--aksrt-color-primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
.oauth-doc-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 启用开关 */
|
||||
.oauth-enable-switch {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 表单体 */
|
||||
.oauth-form-body {
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid var(--aksrt-color-border);
|
||||
}
|
||||
|
||||
.oauth-form-grid :deep(.n-form-item) {
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
/* 禁用提示 */
|
||||
.oauth-disabled-hint {
|
||||
text-align: center;
|
||||
padding: 28px 0 10px;
|
||||
}
|
||||
.oauth-disabled-hint p {
|
||||
font-size: 13px;
|
||||
color: var(--aksrt-color-border-strong);
|
||||
}
|
||||
</style>
|
||||
@@ -25,17 +25,28 @@
|
||||
/>
|
||||
|
||||
<!-- Input (text, email, url, password) -->
|
||||
<n-input
|
||||
v-else-if="schema.type === 'input' || schema.type === 'text' || schema.type === 'url'"
|
||||
:value="modelValue"
|
||||
:placeholder="schema.placeholder || ''"
|
||||
:type="schema.inputType || 'text'"
|
||||
:disabled="schema.disabled"
|
||||
@update:value="emit('update:modelValue', $event)"
|
||||
>
|
||||
<template v-if="schema.prefix" #prefix>{{ schema.prefix }}</template>
|
||||
<template v-if="schema.suffix" #suffix>{{ schema.suffix }}</template>
|
||||
</n-input>
|
||||
<div v-else-if="schema.type === 'input' || schema.type === 'text' || schema.type === 'url'" class="aksrt-field__input-wrap">
|
||||
<n-input
|
||||
:value="secretDisplayValue"
|
||||
:placeholder="schema.placeholder || ''"
|
||||
:type="schema.inputType || 'text'"
|
||||
:disabled="schema.disabled"
|
||||
@update:value="emit('update:modelValue', $event)"
|
||||
>
|
||||
<template v-if="schema.prefix" #prefix>{{ schema.prefix }}</template>
|
||||
<template v-if="schema.suffix" #suffix>{{ schema.suffix }}</template>
|
||||
</n-input>
|
||||
<n-button
|
||||
v-if="schema.secret && (modelValue === '***' || secretMarkedForClear)"
|
||||
size="small"
|
||||
secondary
|
||||
:type="secretMarkedForClear ? 'warning' : 'error'"
|
||||
@click="toggleSecretClear"
|
||||
>
|
||||
{{ secretMarkedForClear ? '取消清除' : '清除已配置密钥' }}
|
||||
</n-button>
|
||||
<span v-if="secretMarkedForClear" class="aksrt-field__secret-clear-hint">保存后将删除此密钥</span>
|
||||
</div>
|
||||
|
||||
<!-- Textarea -->
|
||||
<n-input
|
||||
@@ -636,6 +647,13 @@ const props = defineProps({
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const secretMarkedForClear = computed(() => props.schema.secret && props.modelValue === '__AKSRT_CLEAR_SECRET__')
|
||||
const secretDisplayValue = computed(() => secretMarkedForClear.value ? '' : props.modelValue)
|
||||
|
||||
function toggleSecretClear() {
|
||||
emit('update:modelValue', secretMarkedForClear.value ? '***' : '__AKSRT_CLEAR_SECRET__')
|
||||
}
|
||||
|
||||
const repeaterLength = computed(() => Array.isArray(props.modelValue) ? props.modelValue.length : 0)
|
||||
const reachedRepeaterMinimum = computed(() => repeaterLength.value <= Number(props.schema.min || 0))
|
||||
const reachedRepeaterMaximum = computed(() => Number(props.schema.max || 0) > 0 && repeaterLength.value >= Number(props.schema.max))
|
||||
@@ -1014,6 +1032,20 @@ function confirmRepeaterModal() {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.aksrt-field__input-wrap {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.aksrt-field__input-wrap .n-button {
|
||||
justify-self: start;
|
||||
}
|
||||
|
||||
.aksrt-field__secret-clear-hint {
|
||||
color: var(--aksrt-color-warning, #d97706);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.aksrt-field__label-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user