初始化本地仓库
This commit is contained in:
@@ -0,0 +1,284 @@
|
||||
<template>
|
||||
<view class="auth-page" :class="`theme-${themeMode}`">
|
||||
<view class="bg-circle bg-circle-primary"></view>
|
||||
<view class="bg-circle bg-circle-light"></view>
|
||||
|
||||
<view class="brand-area">
|
||||
<view class="brand-mark">
|
||||
<u-icon name="scan" color="#ffffff" size="52" />
|
||||
</view>
|
||||
<text class="brand-title">扫码生产助手</text>
|
||||
<text class="brand-subtitle">登录后开始扫码录入生产数据</text>
|
||||
</view>
|
||||
|
||||
<view class="auth-panel">
|
||||
<view class="panel-header">
|
||||
<text class="panel-title">账号登录</text>
|
||||
<text class="panel-desc">请输入账号和密码</text>
|
||||
</view>
|
||||
|
||||
<u-form :model="form" :border-bottom="false" label-position="top" label-width="120">
|
||||
<u-form-item prop="account" :border-bottom="false">
|
||||
<view class="field-card">
|
||||
<view class="field-icon">
|
||||
<u-icon name="account-fill" color="#1677ff" size="36" />
|
||||
</view>
|
||||
<u-input v-model="form.account" clearable placeholder="请输入账号/手机号" placeholder-style="color: #a0a7b5;" />
|
||||
</view>
|
||||
</u-form-item>
|
||||
<u-form-item prop="password" :border-bottom="false">
|
||||
<view class="field-card">
|
||||
<view class="field-icon">
|
||||
<u-icon name="lock-fill" color="#1677ff" size="36" />
|
||||
</view>
|
||||
<u-input v-model="form.password" type="password" clearable password-icon placeholder="请输入密码" placeholder-style="color: #a0a7b5;" />
|
||||
</view>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
|
||||
<view class="actions">
|
||||
<u-button type="primary" shape="circle" size="large" :loading="loading" @click="handleLogin">登录</u-button>
|
||||
</view>
|
||||
|
||||
<view class="footer-link">
|
||||
<text>还没有账号?</text>
|
||||
<text class="link" @tap="goRegister">立即注册</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { login } from '@/api/auth.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
redirectUrl: '/pages/index/index',
|
||||
form: {
|
||||
account: '',
|
||||
password: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
onLoad(options = {}) {
|
||||
if (options.redirect) {
|
||||
this.redirectUrl = decodeURIComponent(options.redirect)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async handleLogin() {
|
||||
if (!this.form.account || !this.form.password) {
|
||||
uni.showToast({
|
||||
title: '请输入账号和密码',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
try {
|
||||
const result = await login({
|
||||
username: this.form.account,
|
||||
password: this.form.password
|
||||
})
|
||||
const accessToken = result?.access_token || result?.token?.access_token
|
||||
if (!accessToken) {
|
||||
throw new Error('登录响应缺少访问令牌')
|
||||
}
|
||||
|
||||
uni.setStorageSync('scanapp_token', accessToken)
|
||||
if (result?.refresh_token || result?.token?.refresh_token) {
|
||||
uni.setStorageSync('scanapp_refresh_token', result.refresh_token || result.token.refresh_token)
|
||||
}
|
||||
if (result?.user_info) {
|
||||
uni.setStorageSync('scanapp_user', result.user_info)
|
||||
}
|
||||
|
||||
uni.showToast({ title: '登录成功', icon: 'none' })
|
||||
setTimeout(() => {
|
||||
uni.redirectTo({ url: this.redirectUrl })
|
||||
}, 300)
|
||||
} catch (error) {
|
||||
console.error('[scanapp] 登录失败', error)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
goRegister() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/auth/register'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.auth-page {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
min-height: 100vh;
|
||||
padding: 92rpx 40rpx 48rpx;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient(180deg, #eaf4ff 0%, #f6f8fc 50%, #ffffff 100%);
|
||||
}
|
||||
|
||||
.bg-circle {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.bg-circle-primary {
|
||||
top: -120rpx;
|
||||
right: -90rpx;
|
||||
width: 300rpx;
|
||||
height: 300rpx;
|
||||
background: rgba(22, 119, 255, 0.12);
|
||||
}
|
||||
|
||||
.bg-circle-light {
|
||||
top: 160rpx;
|
||||
left: -140rpx;
|
||||
width: 260rpx;
|
||||
height: 260rpx;
|
||||
background: rgba(53, 191, 163, 0.12);
|
||||
}
|
||||
|
||||
.brand-area {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 64rpx;
|
||||
}
|
||||
|
||||
.brand-mark {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
margin-bottom: 24rpx;
|
||||
border-radius: 36rpx;
|
||||
background: linear-gradient(135deg, #1677ff 0%, #35bfa3 100%);
|
||||
box-shadow: 0 20rpx 46rpx rgba(22, 119, 255, 0.26);
|
||||
}
|
||||
|
||||
.brand-title {
|
||||
color: #17233d;
|
||||
font-size: 38rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.brand-subtitle {
|
||||
margin-top: 12rpx;
|
||||
color: #6b778c;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.auth-panel {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: 44rpx 32rpx 38rpx;
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.8);
|
||||
border-radius: 32rpx;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
box-shadow: 0 22rpx 60rpx rgba(23, 35, 61, 0.1);
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
display: block;
|
||||
color: #17233d;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.panel-desc {
|
||||
display: block;
|
||||
margin-top: 8rpx;
|
||||
color: #8a94a6;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-top: 36rpx;
|
||||
}
|
||||
|
||||
.field-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 96rpx;
|
||||
padding: 0 24rpx;
|
||||
box-sizing: border-box;
|
||||
border: 1rpx solid #edf1f7;
|
||||
border-radius: 22rpx;
|
||||
background: #f8fbff;
|
||||
}
|
||||
|
||||
.field-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
margin-right: 14rpx;
|
||||
border-radius: 16rpx;
|
||||
background: rgba(22, 119, 255, 0.1);
|
||||
}
|
||||
|
||||
.footer-link {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 32rpx;
|
||||
color: #8a94a6;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.link {
|
||||
margin-left: 8rpx;
|
||||
color: #1677ff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.theme-dark.auth-page {
|
||||
background: linear-gradient(180deg, #111827 0%, #151923 50%, #151923 100%);
|
||||
}
|
||||
|
||||
.theme-dark .auth-panel {
|
||||
border-color: #364152;
|
||||
background: #222936;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.theme-dark .field-card {
|
||||
border-color: #364152;
|
||||
background: #1c2431;
|
||||
}
|
||||
|
||||
.theme-dark .panel-title {
|
||||
color: #f2f5fa;
|
||||
}
|
||||
|
||||
.theme-dark .panel-desc,
|
||||
.theme-dark .footer-link {
|
||||
color: #aeb9ca;
|
||||
}
|
||||
|
||||
.theme-dark :deep(.u-input__input) {
|
||||
color: #f2f5fa !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,330 @@
|
||||
<template>
|
||||
<view class="auth-page" :class="`theme-${themeMode}`">
|
||||
<view class="bg-circle bg-circle-primary"></view>
|
||||
<view class="bg-circle bg-circle-light"></view>
|
||||
|
||||
<view class="brand-area">
|
||||
<view class="brand-mark">
|
||||
<u-icon name="edit-pen-fill" color="#ffffff" size="52" />
|
||||
</view>
|
||||
<text class="brand-title">创建新账号</text>
|
||||
<text class="brand-subtitle">注册后可进行扫码、录入和查看统计</text>
|
||||
</view>
|
||||
|
||||
<view class="auth-panel">
|
||||
<view class="panel-header">
|
||||
<text class="panel-title">账号注册</text>
|
||||
<text class="panel-desc">请填写以下信息完成注册</text>
|
||||
</view>
|
||||
|
||||
<u-form :model="form" :border-bottom="false" label-position="top" label-width="120">
|
||||
<u-form-item prop="username" :border-bottom="false">
|
||||
<view class="field-card">
|
||||
<view class="field-icon">
|
||||
<u-icon name="account-fill" color="#19be6b" size="36" />
|
||||
</view>
|
||||
<u-input v-model="form.username" clearable placeholder="请输入用户名" placeholder-style="color: #a0a7b5;" />
|
||||
</view>
|
||||
</u-form-item>
|
||||
<u-form-item prop="email" :border-bottom="false">
|
||||
<view class="field-card">
|
||||
<view class="field-icon">
|
||||
<u-icon name="email-fill" color="#19be6b" size="36" />
|
||||
</view>
|
||||
<u-input v-model="form.email" type="text" clearable placeholder="请输入邮箱" placeholder-style="color: #a0a7b5;" />
|
||||
</view>
|
||||
</u-form-item>
|
||||
<u-form-item prop="password" :border-bottom="false">
|
||||
<view class="field-card">
|
||||
<view class="field-icon">
|
||||
<u-icon name="lock-fill" color="#19be6b" size="36" />
|
||||
</view>
|
||||
<u-input v-model="form.password" type="password" clearable password-icon placeholder="请输入密码" placeholder-style="color: #a0a7b5;" />
|
||||
</view>
|
||||
</u-form-item>
|
||||
<u-form-item prop="confirm_password" :border-bottom="false">
|
||||
<view class="field-card">
|
||||
<view class="field-icon">
|
||||
<u-icon name="lock-fill" color="#19be6b" size="36" />
|
||||
</view>
|
||||
<u-input v-model="form.confirm_password" type="password" clearable password-icon placeholder="请再次输入密码" placeholder-style="color: #a0a7b5;" />
|
||||
</view>
|
||||
</u-form-item>
|
||||
<u-form-item prop="captcha_code" :border-bottom="false">
|
||||
<view class="code-field">
|
||||
<view class="field-card code-input-card">
|
||||
<view class="field-icon">
|
||||
<u-icon name="coupon-fill" color="#19be6b" size="36" />
|
||||
</view>
|
||||
<u-input v-model="form.captcha_code" clearable placeholder="请输入图形验证码" placeholder-style="color: #a0a7b5;" />
|
||||
</view>
|
||||
<view class="captcha-box" @tap="refreshCaptcha">{{ captchaText }}</view>
|
||||
</view>
|
||||
</u-form-item>
|
||||
</u-form>
|
||||
|
||||
<view class="actions">
|
||||
<u-button type="primary" shape="circle" size="large" :loading="loading" @click="handleRegister">注册</u-button>
|
||||
</view>
|
||||
|
||||
<view class="footer-link">
|
||||
<text>已有账号?</text>
|
||||
<text class="link" @tap="goLogin">返回登录</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
captchaText: '8K4P',
|
||||
form: {
|
||||
username: '',
|
||||
email: '',
|
||||
password: '',
|
||||
confirm_password: '',
|
||||
captcha_key: '',
|
||||
captcha_code: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleRegister() {
|
||||
if (!this.form.username || !this.form.email || !this.form.password || !this.form.confirm_password || !this.form.captcha_code) {
|
||||
uni.showToast({
|
||||
title: '请完整填写注册信息',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (this.form.password !== this.form.confirm_password) {
|
||||
uni.showToast({
|
||||
title: '两次密码不一致',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
setTimeout(() => {
|
||||
this.loading = false
|
||||
uni.showToast({
|
||||
title: '注册接口待接入',
|
||||
icon: 'none'
|
||||
})
|
||||
}, 500)
|
||||
},
|
||||
refreshCaptcha() {
|
||||
this.captchaText = Math.random().toString(36).slice(2, 6).toUpperCase()
|
||||
},
|
||||
goLogin() {
|
||||
uni.navigateBack({
|
||||
delta: 1
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.auth-page {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
min-height: 100vh;
|
||||
padding: 56rpx 40rpx 48rpx;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient(180deg, #ebfff7 0%, #f6f8fc 48%, #ffffff 100%);
|
||||
}
|
||||
|
||||
.bg-circle {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.bg-circle-primary {
|
||||
top: -130rpx;
|
||||
right: -100rpx;
|
||||
width: 310rpx;
|
||||
height: 310rpx;
|
||||
background: rgba(25, 190, 107, 0.14);
|
||||
}
|
||||
|
||||
.bg-circle-light {
|
||||
top: 190rpx;
|
||||
left: -150rpx;
|
||||
width: 280rpx;
|
||||
height: 280rpx;
|
||||
background: rgba(22, 119, 255, 0.1);
|
||||
}
|
||||
|
||||
.brand-area {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 42rpx;
|
||||
}
|
||||
|
||||
.brand-mark {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 112rpx;
|
||||
height: 112rpx;
|
||||
margin-bottom: 24rpx;
|
||||
border-radius: 34rpx;
|
||||
background: linear-gradient(135deg, #19be6b 0%, #1677ff 100%);
|
||||
box-shadow: 0 20rpx 46rpx rgba(25, 190, 107, 0.24);
|
||||
}
|
||||
|
||||
.brand-title {
|
||||
color: #17233d;
|
||||
font-size: 38rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.brand-subtitle {
|
||||
margin-top: 12rpx;
|
||||
color: #6b778c;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.auth-panel {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: 40rpx 32rpx 36rpx;
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.8);
|
||||
border-radius: 32rpx;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
box-shadow: 0 22rpx 60rpx rgba(23, 35, 61, 0.1);
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
display: block;
|
||||
color: #17233d;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.panel-desc {
|
||||
display: block;
|
||||
margin-top: 8rpx;
|
||||
color: #8a94a6;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-top: 36rpx;
|
||||
}
|
||||
|
||||
.field-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 92rpx;
|
||||
padding: 0 22rpx;
|
||||
box-sizing: border-box;
|
||||
border: 1rpx solid #edf1f7;
|
||||
border-radius: 22rpx;
|
||||
background: #f8fbff;
|
||||
}
|
||||
|
||||
.field-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
margin-right: 12rpx;
|
||||
border-radius: 16rpx;
|
||||
background: rgba(25, 190, 107, 0.1);
|
||||
}
|
||||
|
||||
.code-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.code-input-card {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.captcha-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 0 0 170rpx;
|
||||
margin-left: 20rpx;
|
||||
height: 92rpx;
|
||||
border: 1rpx solid rgba(25, 190, 107, 0.16);
|
||||
border-radius: 22rpx;
|
||||
background: linear-gradient(135deg, #effff7 0%, #eef6ff 100%);
|
||||
color: #19be6b;
|
||||
font-size: 22rpx;
|
||||
font-weight: 600;
|
||||
letter-spacing: 4rpx;
|
||||
}
|
||||
|
||||
.footer-link {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 32rpx;
|
||||
color: #8a94a6;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.link {
|
||||
margin-left: 8rpx;
|
||||
color: #19be6b;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.theme-dark.auth-page {
|
||||
background: linear-gradient(180deg, #111827 0%, #151923 50%, #151923 100%);
|
||||
}
|
||||
|
||||
.theme-dark .auth-panel {
|
||||
border-color: #364152;
|
||||
background: #222936;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.theme-dark .field-card {
|
||||
border-color: #364152;
|
||||
background: #1c2431;
|
||||
}
|
||||
|
||||
.theme-dark .captcha-box {
|
||||
border-color: #36534c;
|
||||
background: #1c2d2b;
|
||||
}
|
||||
|
||||
.theme-dark .panel-title {
|
||||
color: #f2f5fa;
|
||||
}
|
||||
|
||||
.theme-dark .panel-desc,
|
||||
.theme-dark .footer-link {
|
||||
color: #aeb9ca;
|
||||
}
|
||||
|
||||
.theme-dark :deep(.u-input__input) {
|
||||
color: #f2f5fa !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user