feat(setting): 系统设置支持上传 App 登录页背景
This commit is contained in:
1 parent
a94018d5d3
commit
dd4be08d49
2 files changed
+138
-3
No files matched your search
@@ -46,6 +46,13 @@ export const BANNER_IMAGE: ImagePreset = {
|
||||
maxHeight: 1164
|
||||
}
|
||||
|
||||
export const LOGIN_BACKGROUND: ImagePreset = {
|
||||
label: '登录页背景',
|
||||
hint: '建议 1170×2532(390×844dp × 3,iPhone 整屏竖图),min 720×1560',
|
||||
maxWidth: 1170,
|
||||
maxHeight: 2532
|
||||
}
|
||||
|
||||
/** 按规格压缩:尺寸未超且体积不大时原样返回,不做二次编码。 */
|
||||
export function compressForPreset(file: File, preset: ImagePreset): Promise<File> {
|
||||
return compressImage(file, {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<!-- Author: fruit.com.cn -->
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { listConfigsApi, updateConfigsApi } from '@/api/admin/config'
|
||||
import { uploadFile } from '@/utils/uploader'
|
||||
import { compressForPreset, LOGIN_BACKGROUND } from '@/views/contentManagement/upload/imagePresets'
|
||||
import { useRbac } from '@/stores/rbac'
|
||||
|
||||
const { can } = useRbac()
|
||||
@@ -14,6 +16,15 @@ const workspaceName = ref('')
|
||||
const defaultStatus = ref('draft')
|
||||
const registerMaxPerIp = ref(5)
|
||||
const registerMaxPerDevice = ref(3)
|
||||
const loginBackgroundUrl = ref('')
|
||||
|
||||
const MAX_LOGIN_BG_SIZE = 8 * 1024 * 1024 // 8 MB
|
||||
const ALLOWED_LOGIN_BG_TYPES = ['image/jpeg', 'image/png', 'image/webp']
|
||||
const uploadingBg = ref(false)
|
||||
const bgError = ref('')
|
||||
const bgFileName = ref('')
|
||||
|
||||
const canSave = computed(() => can('system:role'))
|
||||
|
||||
const statusOptions = [
|
||||
{ code: 'draft', text: '草稿' },
|
||||
@@ -34,6 +45,7 @@ async function load() {
|
||||
defaultStatus.value = map['content.default-status'] || 'draft'
|
||||
registerMaxPerIp.value = parseRegisterLimit(map['app.register.max-per-ip-per-day'], 5)
|
||||
registerMaxPerDevice.value = parseRegisterLimit(map['app.register.max-per-device-per-day'], 3)
|
||||
loginBackgroundUrl.value = map['app.login.background.url'] || ''
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -46,7 +58,8 @@ async function save() {
|
||||
'workspace.name': workspaceName.value,
|
||||
'content.default-status': defaultStatus.value,
|
||||
'app.register.max-per-ip-per-day': String(registerMaxPerIp.value),
|
||||
'app.register.max-per-device-per-day': String(registerMaxPerDevice.value)
|
||||
'app.register.max-per-device-per-day': String(registerMaxPerDevice.value),
|
||||
'app.login.background.url': loginBackgroundUrl.value
|
||||
})
|
||||
ElMessage.success('设置已保存')
|
||||
} finally {
|
||||
@@ -54,6 +67,52 @@ async function save() {
|
||||
}
|
||||
}
|
||||
|
||||
function beforeBgUpload(file) {
|
||||
bgError.value = ''
|
||||
if (!ALLOWED_LOGIN_BG_TYPES.includes(file.type)) {
|
||||
bgError.value = '图片仅支持 JPG、PNG 或 WebP 格式'
|
||||
return false
|
||||
}
|
||||
if (file.size > MAX_LOGIN_BG_SIZE) {
|
||||
bgError.value = '图片大小不能超过 8MB'
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
async function uploadBg(options) {
|
||||
uploadingBg.value = true
|
||||
bgError.value = ''
|
||||
try {
|
||||
const file = await compressForPreset(options.file, LOGIN_BACKGROUND)
|
||||
const asset = await uploadFile(file, {
|
||||
bizType: 'LOGIN_BG'
|
||||
})
|
||||
loginBackgroundUrl.value = asset.url
|
||||
bgFileName.value = file.name
|
||||
ElMessage.success('登录页背景已上传')
|
||||
} catch {
|
||||
bgError.value = '图片上传失败,请检查网络后重试'
|
||||
} finally {
|
||||
uploadingBg.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function removeBg() {
|
||||
if (uploadingBg.value) return
|
||||
loginBackgroundUrl.value = ''
|
||||
bgFileName.value = ''
|
||||
bgError.value = ''
|
||||
}
|
||||
|
||||
const loginBgPreview = computed(() => {
|
||||
const url = loginBackgroundUrl.value
|
||||
if (!url) return ''
|
||||
if (url.startsWith('http://') || url.startsWith('https://')) return url
|
||||
if (url.startsWith('/')) return url
|
||||
return `/${url}`
|
||||
})
|
||||
|
||||
onMounted(load)
|
||||
</script>
|
||||
|
||||
@@ -78,9 +137,78 @@ onMounted(load)
|
||||
><el-input-number v-model="registerMaxPerIp" :step="1" :precision="0" /></el-form-item
|
||||
><el-form-item label="单设备 24 小时注册上限(0 或负数表示不限制)"
|
||||
><el-input-number v-model="registerMaxPerDevice" :step="1" :precision="0" /></el-form-item
|
||||
><el-button type="primary" :loading="saving" :disabled="!can('system:role')" @click="save"
|
||||
>
|
||||
<el-divider content-position="left">App 登录页</el-divider>
|
||||
<el-form-item label="登录页背景图">
|
||||
<div class="login-bg-field">
|
||||
<el-upload
|
||||
:show-file-list="false"
|
||||
:before-upload="beforeBgUpload"
|
||||
:http-request="uploadBg"
|
||||
accept=".jpg,.jpeg,.png,.webp"
|
||||
>
|
||||
<el-button :disabled="uploadingBg" :loading="uploadingBg">
|
||||
{{ loginBackgroundUrl ? '重新上传' : '上传背景图' }}
|
||||
</el-button>
|
||||
</el-upload>
|
||||
<span class="field-hint">建议 {{ LOGIN_BACKGROUND.hint }}</span>
|
||||
<span v-if="bgFileName" class="field-filename">当前:{{ bgFileName }}</span>
|
||||
<span v-if="bgError" class="field-error">{{ bgError }}</span>
|
||||
<div v-if="loginBgPreview" class="login-bg-preview">
|
||||
<img :src="loginBgPreview" alt="登录页背景预览" />
|
||||
<el-button
|
||||
class="remove-bg-btn"
|
||||
text
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="removeBg"
|
||||
>移除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-button type="primary" :loading="saving" :disabled="!canSave" @click="save"
|
||||
>保存设置</el-button
|
||||
></el-form
|
||||
></section
|
||||
>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.login-bg-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
.field-hint {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
.field-filename {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
.field-error {
|
||||
font-size: 12px;
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
.login-bg-preview {
|
||||
position: relative;
|
||||
margin-top: 4px;
|
||||
width: 96px;
|
||||
aspect-ratio: 1170 / 2532;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
background: var(--el-fill-color-light);
|
||||
}
|
||||
.login-bg-preview img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
.remove-bg-btn {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
padding: 2px 4px;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user