feat(router): 更新路由结构并优化页面组件
- 移除经营范围按钮,精简导航栏 - 实现文章标题链接功能,提升用户体验 - 添加商品详情页面包屑导航,支持分类跳转 - 引入配送管理相关页面(区域、接单台、配送员、派单) - 替换控制台布局为站点头部和底部组件 - 重构商品分类页面,集成CMS导航功能 - 新增文章详情页面,支持多种访问方式 - 删除已迁移的创建应用和空应用页面 - 优化样式和组件导入,提升代码质量
This commit is contained in:
@@ -1,164 +1,180 @@
|
||||
<template>
|
||||
<div class="login-page" :style="bgStyle">
|
||||
<div class="overlay" />
|
||||
<div class="login-shell">
|
||||
<SiteHeader />
|
||||
|
||||
<div v-if="config?.siteName" class="brand">
|
||||
<img :src="config.sysLogo || defaultLogo" class="brand-logo" alt="logo" />
|
||||
<h1 class="brand-name">{{ config.siteName }}</h1>
|
||||
</div>
|
||||
<div class="login-page" :style="bgStyle">
|
||||
|
||||
<div v-if="config?.loginTitle" class="brand-title">{{ config.loginTitle }}</div>
|
||||
|
||||
<a-form ref="formRef" :model="form" :rules="rules" class="card">
|
||||
<div class="card-header">
|
||||
<template v-if="loginType === 'scan'">
|
||||
<h2 class="card-title">扫码登录</h2>
|
||||
</template>
|
||||
<template v-else>
|
||||
<h2 class="tab" :class="{ active: loginType === 'sms' }" @click="setLoginType('sms')">
|
||||
手机号登录
|
||||
</h2>
|
||||
<a-divider type="vertical" style="height: 20px" />
|
||||
<h2
|
||||
class="tab"
|
||||
:class="{ active: loginType === 'account' }"
|
||||
@click="setLoginType('account')"
|
||||
>
|
||||
账号登录
|
||||
</h2>
|
||||
</template>
|
||||
|
||||
<a-button class="switch" type="text" @click="toggleScan" :title="loginType === 'scan' ? '切换到手机号登录' : '切换到扫码登录'">
|
||||
<QrcodeOutlined v-if="loginType !== 'scan'" />
|
||||
<MobileOutlined v-else />
|
||||
</a-button>
|
||||
<div v-if="config?.siteName" class="brand">
|
||||
<img :src="config.sysLogo || defaultLogo" class="brand-logo" alt="logo" />
|
||||
<h1 class="brand-name">{{ config.siteName }}</h1>
|
||||
</div>
|
||||
|
||||
<template v-if="loginType === 'account'">
|
||||
<a-form-item name="username">
|
||||
<a-input v-model:value="form.username" size="large" allow-clear placeholder="账号 / 用户ID">
|
||||
<template #prefix><UserOutlined /></template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<div v-if="config?.loginTitle" class="brand-title">{{ config.loginTitle }}</div>
|
||||
|
||||
<a-form-item name="password">
|
||||
<a-input-password
|
||||
v-model:value="form.password"
|
||||
size="large"
|
||||
placeholder="登录密码"
|
||||
@press-enter="submitAccount"
|
||||
<a-form ref="formRef" :model="form" :rules="rules" class="card">
|
||||
<div class="card-header">
|
||||
<template v-if="loginType === 'scan'">
|
||||
<h2 class="card-title">扫码登录</h2>
|
||||
</template>
|
||||
<template v-else>
|
||||
<h2 class="tab" :class="{ active: loginType === 'sms' }" @click="setLoginType('sms')">
|
||||
手机号登录
|
||||
</h2>
|
||||
<a-divider type="vertical" style="height: 20px" />
|
||||
<h2
|
||||
class="tab"
|
||||
:class="{ active: loginType === 'account' }"
|
||||
@click="setLoginType('account')"
|
||||
>
|
||||
账号登录
|
||||
</h2>
|
||||
</template>
|
||||
|
||||
<a-button
|
||||
class="switch"
|
||||
type="text"
|
||||
@click="toggleScan"
|
||||
:title="loginType === 'scan' ? '切换到手机号登录' : '切换到扫码登录'"
|
||||
>
|
||||
<template #prefix><LockOutlined /></template>
|
||||
</a-input-password>
|
||||
</a-form-item>
|
||||
<QrcodeOutlined v-if="loginType !== 'scan'" />
|
||||
<MobileOutlined v-else />
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<a-form-item name="code">
|
||||
<div class="input-group">
|
||||
<a-input
|
||||
v-model:value="form.code"
|
||||
<template v-if="loginType === 'account'">
|
||||
<a-form-item name="username">
|
||||
<a-input v-model:value="form.username" size="large" allow-clear placeholder="账号 / 用户ID">
|
||||
<template #prefix><UserOutlined /></template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item name="password">
|
||||
<a-input-password
|
||||
v-model:value="form.password"
|
||||
size="large"
|
||||
allow-clear
|
||||
:maxlength="5"
|
||||
placeholder="验证码"
|
||||
placeholder="登录密码"
|
||||
@press-enter="submitAccount"
|
||||
>
|
||||
<template #prefix><SafetyCertificateOutlined /></template>
|
||||
</a-input>
|
||||
<a-button class="captcha-btn" @click="changeCaptcha">
|
||||
<img v-if="captcha" :src="captcha" alt="captcha" />
|
||||
<template #prefix><LockOutlined /></template>
|
||||
</a-input-password>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item name="code">
|
||||
<div class="input-group">
|
||||
<a-input
|
||||
v-model:value="form.code"
|
||||
size="large"
|
||||
allow-clear
|
||||
:maxlength="5"
|
||||
placeholder="验证码"
|
||||
@press-enter="submitAccount"
|
||||
>
|
||||
<template #prefix><SafetyCertificateOutlined /></template>
|
||||
</a-input>
|
||||
<a-button class="captcha-btn" @click="changeCaptcha">
|
||||
<img v-if="captcha" :src="captcha" alt="captcha" />
|
||||
</a-button>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item>
|
||||
<div class="row">
|
||||
<a-checkbox v-model:checked="form.remember">记住登录</a-checkbox>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item>
|
||||
<a-button block size="large" type="primary" :loading="loading" @click="submitAccount">
|
||||
{{ loading ? '登录中…' : '登录' }}
|
||||
</a-button>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-form-item>
|
||||
</template>
|
||||
|
||||
<a-form-item>
|
||||
<div class="row">
|
||||
<a-checkbox v-model:checked="form.remember">记住登录</a-checkbox>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item>
|
||||
<a-button block size="large" type="primary" :loading="loading" @click="submitAccount">
|
||||
{{ loading ? '登录中…' : '登录' }}
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</template>
|
||||
|
||||
<template v-else-if="loginType === 'sms'">
|
||||
<a-form-item name="phone">
|
||||
<a-input v-model:value="form.phone" size="large" allow-clear :maxlength="11" placeholder="请输入手机号码">
|
||||
<template #addonBefore>+86</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item name="smsCode">
|
||||
<div class="input-group">
|
||||
<template v-else-if="loginType === 'sms'">
|
||||
<a-form-item name="phone">
|
||||
<a-input
|
||||
v-model:value="form.smsCode"
|
||||
v-model:value="form.phone"
|
||||
size="large"
|
||||
allow-clear
|
||||
:maxlength="6"
|
||||
placeholder="请输入验证码"
|
||||
@press-enter="submitSms"
|
||||
/>
|
||||
<a-button class="captcha-btn" :disabled="countdown > 0" @click="openImgCodeModal">
|
||||
<span v-if="countdown <= 0">发送验证码</span>
|
||||
<span v-else>已发送 {{ countdown }} s</span>
|
||||
:maxlength="11"
|
||||
placeholder="请输入手机号码"
|
||||
>
|
||||
<template #addonBefore>+86</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item name="smsCode">
|
||||
<div class="input-group">
|
||||
<a-input
|
||||
v-model:value="form.smsCode"
|
||||
size="large"
|
||||
allow-clear
|
||||
:maxlength="6"
|
||||
placeholder="请输入验证码"
|
||||
@press-enter="submitSms"
|
||||
/>
|
||||
<a-button class="captcha-btn" :disabled="countdown > 0" @click="openImgCodeModal">
|
||||
<span v-if="countdown <= 0">发送验证码</span>
|
||||
<span v-else>已发送 {{ countdown }} s</span>
|
||||
</a-button>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item>
|
||||
<a-button block size="large" type="primary" :loading="loading" @click="submitSms">
|
||||
{{ loading ? '登录中…' : '登录' }}
|
||||
</a-button>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-form-item>
|
||||
</template>
|
||||
|
||||
<a-form-item>
|
||||
<a-button block size="large" type="primary" :loading="loading" @click="submitSms">
|
||||
{{ loading ? '登录中…' : '登录' }}
|
||||
<template v-else>
|
||||
<QrLogin @login-success="onQrLoginSuccess" @login-error="onQrLoginError" />
|
||||
</template>
|
||||
</a-form>
|
||||
|
||||
<div class="copyright hidden">
|
||||
<span>© {{ new Date().getFullYear() }}</span>
|
||||
<span class="sep">·</span>
|
||||
<span>{{ config?.copyright || 'websoft.top Inc.' }}</span>
|
||||
</div>
|
||||
|
||||
<a-modal v-model:open="imgCodeModalOpen" :width="340" :footer="null" title="发送验证码">
|
||||
<div class="input-group modal-row">
|
||||
<a-input
|
||||
v-model:value="imgCode"
|
||||
size="large"
|
||||
allow-clear
|
||||
:maxlength="5"
|
||||
placeholder="请输入图形验证码"
|
||||
@press-enter="sendSmsCode"
|
||||
/>
|
||||
<a-button class="captcha-btn">
|
||||
<img alt="captcha" :src="captcha" @click="changeCaptcha" />
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</div>
|
||||
<a-button block size="large" type="primary" :loading="sendingSms" @click="sendSmsCode">
|
||||
立即发送
|
||||
</a-button>
|
||||
</a-modal>
|
||||
|
||||
<template v-else>
|
||||
<QrLogin @login-success="onQrLoginSuccess" @login-error="onQrLoginError" />
|
||||
</template>
|
||||
</a-form>
|
||||
|
||||
<div class="copyright">
|
||||
<span>© {{ new Date().getFullYear() }}</span>
|
||||
<span class="sep">·</span>
|
||||
<span>{{ config?.copyright || 'websoft.top Inc.' }}</span>
|
||||
<a-modal v-model:open="selectUserOpen" :width="520" :footer="null" title="选择账号登录">
|
||||
<a-list item-layout="horizontal" :data-source="admins">
|
||||
<template #renderItem="{ item }">
|
||||
<a-list-item class="list-item" @click="selectUser(item)">
|
||||
<a-list-item-meta :description="`租户ID: ${item.tenantId}`">
|
||||
<template #title>{{ item.tenantName || item.username }}</template>
|
||||
<template #avatar>
|
||||
<a-avatar :src="item.avatar" />
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
<template #actions><RightOutlined /></template>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
</a-modal>
|
||||
</div>
|
||||
|
||||
<a-modal v-model:open="imgCodeModalOpen" :width="340" :footer="null" title="发送验证码">
|
||||
<div class="input-group modal-row">
|
||||
<a-input
|
||||
v-model:value="imgCode"
|
||||
size="large"
|
||||
allow-clear
|
||||
:maxlength="5"
|
||||
placeholder="请输入图形验证码"
|
||||
@press-enter="sendSmsCode"
|
||||
/>
|
||||
<a-button class="captcha-btn">
|
||||
<img alt="captcha" :src="captcha" @click="changeCaptcha" />
|
||||
</a-button>
|
||||
</div>
|
||||
<a-button block size="large" type="primary" :loading="sendingSms" @click="sendSmsCode">
|
||||
立即发送
|
||||
</a-button>
|
||||
</a-modal>
|
||||
|
||||
<a-modal v-model:open="selectUserOpen" :width="520" :footer="null" title="选择账号登录">
|
||||
<a-list item-layout="horizontal" :data-source="admins">
|
||||
<template #renderItem="{ item }">
|
||||
<a-list-item class="list-item" @click="selectUser(item)">
|
||||
<a-list-item-meta :description="`租户ID: ${item.tenantId}`">
|
||||
<template #title>{{ item.tenantName || item.username }}</template>
|
||||
<template #avatar>
|
||||
<a-avatar :src="item.avatar" />
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
<template #actions><RightOutlined /></template>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
</a-modal>
|
||||
<SiteFooter />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -183,6 +199,7 @@ import { TEMPLATE_ID } from '@/config/setting'
|
||||
import { setToken } from '@/utils/token-util'
|
||||
import type { QrCodeStatusResponse } from '@/api/passport/qrLogin'
|
||||
|
||||
// Login page is a public page: keep a lightweight layout and render header/footer locally.
|
||||
definePageMeta({ layout: 'blank' })
|
||||
|
||||
const route = useRoute()
|
||||
@@ -387,10 +404,16 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.login-shell {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.login-page {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
background: #111827;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
padding: 48px 16px;
|
||||
|
||||
Reference in New Issue
Block a user