Merge branch 'develop' of https://gitee.com/likeadmin/likeadmin_java into develop

This commit is contained in:
TinyAnts 2022-09-13 19:02:18 +08:00
commit e5560889fc
14 changed files with 289 additions and 88 deletions

View File

@ -4,7 +4,6 @@
*/ */
export function streamFileDownload(file: any, fileName = '文件名称.zip') { export function streamFileDownload(file: any, fileName = '文件名称.zip') {
const blob = new Blob([file], { type: 'application/octet-stream;charset=UTF-8' }) const blob = new Blob([file], { type: 'application/octet-stream;charset=UTF-8' })
console.log(blob.text())
const url = window.URL.createObjectURL(blob) const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') const link = document.createElement('a')
link.style.display = 'none' link.style.display = 'none'

View File

@ -4,9 +4,9 @@ import { useAppStore } from './stores/app'
import { useUserStore } from './stores/user' import { useUserStore } from './stores/user'
const { getConfig } = useAppStore() const { getConfig } = useAppStore()
const { getUser } = useUserStore() const { getUser } = useUserStore()
onLaunch(() => { onLaunch(async () => {
getConfig() await getConfig()
getUser() await getUser()
}) })
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -1,28 +1,28 @@
import request from '@/utils/request' import request from '@/utils/request'
export function getUserCenter() { export function getUserCenter(header?: any) {
return request.get({ url: '/user/center' }) return request.get({ url: '/user/center', header })
} }
// 个人信息 // 个人信息
export function getUserInfo() { export function getUserInfo() {
return request.get({ url: '/user/info' }) return request.get({ url: '/user/info' }, { isAuth: true })
} }
// 个人编辑 // 个人编辑
export function userEdit(data: any) { export function userEdit(data: any) {
return request.post({ url: '/user/edit', data: data }) return request.post({ url: '/user/edit', data }, { isAuth: true })
} }
// 绑定手机 // 绑定手机
export function userBindMobile(data: any) { export function userBindMobile(data: any, header?: any) {
return request.post({ url: '/user/bindMobile', data: data }) return request.post({ url: '/user/bindMobile', data, header }, { isAuth: true })
} }
// 微信电话 // 微信电话
export function userMnpMobile(data: any) { export function userMnpMobile(data: any) {
return request.post({ url: '/user/mnpMobile', data: data }) return request.post({ url: '/user/mnpMobile', data }, { isAuth: true })
} }
export function userChangePwd(data: any) { export function userChangePwd(data: any) {
return request.post({ url: '/user/changePwd', data: data }) return request.post({ url: '/user/changePwd', data }, { isAuth: true })
} }

View File

View File

@ -5,7 +5,6 @@ import './router'
import './styles/index.scss' import './styles/index.scss'
export function createApp() { export function createApp() {
const app = createSSRApp(App) const app = createSSRApp(App)
app.use(plugins) app.use(plugins)
return { return {
app app

View File

@ -97,6 +97,12 @@
{ {
"path": "pages/webview/webview" "path": "pages/webview/webview"
}, },
{
"path": "pages/bind_mobile/bind_mobile",
"style": {
"navigationBarTitleText": "绑定手机号"
}
},
{ {
"path": "uni_modules/vk-uview-ui/components/u-avatar-cropper/u-avatar-cropper", "path": "uni_modules/vk-uview-ui/components/u-avatar-cropper/u-avatar-cropper",
"style": { "style": {

View File

@ -0,0 +1,85 @@
<template>
<view class="bg-white min-h-full flex flex-col items-center px-[40rpx] pt-[40rpx] box-border">
<view class="w-full">
<u-form borderBottom :label-width="150">
<u-form-item label="手机号" borderBottom>
<u-input
class="flex-1"
v-model="formData.mobile"
:border="false"
placeholder="请输入手机号码"
/>
</u-form-item>
<u-form-item label="验证码" borderBottom>
<u-input
class="flex-1"
v-model="formData.code"
placeholder="请输入验证码"
:border="false"
/>
<view
class="border-l border-solid border-0 border-light pl-3 text-muted leading-4 ml-3 w-[180rpx]"
@click="sendSms"
>
<u-verification-code
ref="uCodeRef"
:seconds="60"
@change="codeChange"
change-text="x秒"
/>
{{ codeTips }}
</view>
</u-form-item>
</u-form>
<view class="mt-[40rpx]">
<u-button type="primary" shape="circle" @click="handleConfirm"> 确定 </u-button>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { userBindMobile } from '@/api/user'
import { smsSend } from '@/api/app'
import { SMSEnum } from '@/enums/appEnums'
import { reactive, ref, shallowRef } from 'vue'
import { useUserStore } from '@/stores/user'
const uCodeRef = shallowRef()
const codeTips = ref('')
const userStore = useUserStore()
const codeChange = (text: string) => {
codeTips.value = text
}
const formData = reactive({
type: 'bind',
mobile: '',
code: ''
})
const sendSms = async () => {
if (!formData.mobile) return uni.$u.toast('请输入手机号码')
if (uCodeRef.value?.canGetCode) {
await smsSend({
scene: SMSEnum.BIND_MOBILE,
mobile: formData.mobile
})
uni.$u.toast('发送成功')
uCodeRef.value?.start()
}
}
const handleConfirm = async () => {
if (!formData.mobile) return uni.$u.toast('请输入手机号码')
if (!formData.code) return uni.$u.toast('请输入验证码')
await userBindMobile(formData, { token: userStore.temToken })
uni.$u.toast('绑定成功')
userStore.login(userStore.temToken!)
uni.navigateBack()
}
</script>
<style lang="scss">
page {
height: 100%;
}
</style>

View File

@ -29,7 +29,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { getIndex } from '@/api/shop' import { getIndex } from '@/api/shop'
import { reactive, ref } from 'vue' import { reactive } from 'vue'
const state = reactive<{ const state = reactive<{
pages: any[] pages: any[]
article: any[] article: any[]

View File

@ -8,7 +8,9 @@
<view class="mt-4">{{ appStore.config.website.name }}</view> <view class="mt-4">{{ appStore.config.website.name }}</view>
<view class="w-full mt-[60rpx]"> <view class="w-full mt-[60rpx]">
<u-form borderBottom> <u-form borderBottom>
<template v-if="scene == LoginTypeEnum.ACCOUNT"> <template
v-if="loginWay == LoginWayEnum.ACCOUNT && includeLoginWay(LoginWayEnum.ACCOUNT)"
>
<u-form-item borderBottom> <u-form-item borderBottom>
<u-icon class="mr-2" :size="36" name="/static/images/icon/icon_user.png" /> <u-icon class="mr-2" :size="36" name="/static/images/icon/icon_user.png" />
<u-input <u-input
@ -40,7 +42,9 @@
</navigator> </navigator>
</u-form-item> </u-form-item>
</template> </template>
<template v-if="scene == LoginTypeEnum.MOBILE"> <template
v-if="loginWay == LoginWayEnum.MOBILE && includeLoginWay(LoginWayEnum.MOBILE)"
>
<u-form-item borderBottom> <u-form-item borderBottom>
<u-icon <u-icon
class="mr-2" class="mr-2"
@ -77,7 +81,7 @@
</u-form-item> </u-form-item>
</template> </template>
</u-form> </u-form>
<view class="mt-[60rpx]"> <view class="mt-[40rpx]" v-if="isOpenAgreement">
<u-checkbox v-model="isCheckAgreement" shape="circle"> <u-checkbox v-model="isCheckAgreement" shape="circle">
<view class="text-xs flex"> <view class="text-xs flex">
已阅读并同意 已阅读并同意
@ -100,26 +104,43 @@
</view> </view>
</u-checkbox> </u-checkbox>
</view> </view>
<view class="mt-[40rpx]"> <view class="mt-[60rpx]">
<u-button type="primary" shape="circle" @click="handleLogin(scene)"> <u-button type="primary" shape="circle" @click="handleLogin(formData.scene)">
</u-button> </u-button>
</view> </view>
<view class="text-content flex justify-between mt-[40rpx]"> <view class="text-content flex justify-between mt-[40rpx]">
<view v-if="scene == LoginTypeEnum.MOBILE" @click="scene = LoginTypeEnum.ACCOUNT"> <view class="flex-1">
账号密码登录 <view
</view> v-if="
<view v-if="scene == LoginTypeEnum.ACCOUNT" @click="scene = LoginTypeEnum.MOBILE"> loginWay == LoginWayEnum.MOBILE && includeLoginWay(LoginWayEnum.ACCOUNT)
短信验证码登录 "
@click="changeLoginWay(LoginTypeEnum.ACCOUNT, LoginWayEnum.ACCOUNT)"
>
账号密码登录
</view>
<view
v-if="
loginWay == LoginWayEnum.ACCOUNT && includeLoginWay(LoginWayEnum.MOBILE)
"
@click="changeLoginWay(LoginTypeEnum.MOBILE, LoginWayEnum.MOBILE)"
>
短信验证码登录
</view>
</view> </view>
<navigator url="/pages/register/register" hover-class="none">注册账号</navigator> <navigator url="/pages/register/register" hover-class="none">注册账号</navigator>
</view> </view>
<!-- #ifdef MP-WEIXIN --> <!-- #ifdef MP-WEIXIN -->
<view class="mt-[80rpx]"> <view class="mt-[80rpx]" v-if="isOpenOtherAuth">
<u-divider>第三方登录</u-divider> <u-divider>第三方登录</u-divider>
<div class="flex justify-center mt-[40rpx]"> <div class="flex justify-center mt-[40rpx]">
<div class="flex flex-col items-center" @click="wxLogin"> <div
v-if="includeAuthWay(LoginAuthEnum.WX)"
class="flex flex-col items-center"
@click="wxLogin"
>
<u-icon name="/static/images/icon/icon_wx.png" size="80" /> <u-icon name="/static/images/icon/icon_wx.png" size="80" />
<div class="text-sm mt-[10px]">微信登录</div> <div class="text-sm mt-[10px]">微信登录</div>
</div> </div>
@ -138,20 +159,34 @@ import { useLockFn } from '@/hooks/useLockFn'
import { useAppStore } from '@/stores/app' import { useAppStore } from '@/stores/app'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import { currentPage } from '@/utils/util' import { currentPage } from '@/utils/util'
import { reactive, ref, shallowRef } from 'vue' import { onShow } from '@dcloudio/uni-app'
import { computed, reactive, ref, shallowRef, watch } from 'vue'
enum LoginTypeEnum { enum LoginTypeEnum {
MOBILE = 'mobile', MOBILE = 'mobile',
ACCOUNT = 'account', ACCOUNT = 'account',
MNP = 'mnp' MNP = 'mnp'
} }
const uCodeRef = shallowRef()
const scene = ref(LoginTypeEnum.ACCOUNT) enum LoginWayEnum {
const codeTips = ref('') ACCOUNT = 1,
const isCheckAgreement = ref(false) MOBILE = 2
}
enum LoginAuthEnum {
WX = 1,
QQ = 2
}
const userStore = useUserStore() const userStore = useUserStore()
const appStore = useAppStore() const appStore = useAppStore()
const uCodeRef = shallowRef()
const loginWay = ref<LoginWayEnum>()
const codeTips = ref('')
const isCheckAgreement = ref(false)
const formData = reactive({ const formData = reactive({
scene: '',
username: '', username: '',
password: '', password: '',
code: '', code: '',
@ -174,8 +209,27 @@ const sendSms = async () => {
} }
} }
const changeLoginWay = (type: LoginTypeEnum, way: LoginWayEnum) => {
formData.scene = type
loginWay.value = way
}
const includeLoginWay = (way: LoginWayEnum) => {
return appStore.getLoginConfig.loginWay.includes(way)
}
const includeAuthWay = (way: LoginAuthEnum) => {
return appStore.getLoginConfig.autoLoginAuth.includes(way)
}
const isOpenAgreement = computed(() => appStore.getLoginConfig.openAgreement == 1)
const isOpenOtherAuth = computed(() => appStore.getLoginConfig.openOtherAuth == 1)
const isForceBindMobile = computed(() => appStore.getLoginConfig.forceBindMobile == 1)
const loginFun = async (scene: LoginTypeEnum, code?: string) => { const loginFun = async (scene: LoginTypeEnum, code?: string) => {
if (!isCheckAgreement.value) return uni.$u.toast('请勾选已阅读并同意《服务协议》和《隐私协议》') if (!isCheckAgreement.value && isOpenAgreement.value)
return uni.$u.toast('请勾选已阅读并同意《服务协议》和《隐私协议》')
if (scene == LoginTypeEnum.ACCOUNT) { if (scene == LoginTypeEnum.ACCOUNT) {
if (!formData.username) return uni.$u.toast('请输入账号/手机号码') if (!formData.username) return uni.$u.toast('请输入账号/手机号码')
if (!formData.password) return uni.$u.toast('请输入密码') if (!formData.password) return uni.$u.toast('请输入密码')
@ -194,6 +248,15 @@ const loginFun = async (scene: LoginTypeEnum, code?: string) => {
}) })
try { try {
const data = await login(params) const data = await login(params)
const { token, isBindMobile } = data
if (!isBindMobile && isForceBindMobile.value) {
userStore.temToken = token
uni.navigateTo({
url: '/pages/bind_mobile/bind_mobile'
})
uni.hideLoading()
return
}
userStore.login(data.token) userStore.login(data.token)
await userStore.getUser() await userStore.getUser()
uni.$u.toast('登录成功') uni.$u.toast('登录成功')
@ -212,7 +275,7 @@ const loginFun = async (scene: LoginTypeEnum, code?: string) => {
} }
} }
const { isLock, lockFn: handleLogin } = useLockFn(loginFun) const { lockFn: handleLogin } = useLockFn(loginFun)
const wxLogin = async () => { const wxLogin = async () => {
const data: any = await uni.login({ const data: any = await uni.login({
@ -220,6 +283,35 @@ const wxLogin = async () => {
}) })
handleLogin(LoginTypeEnum.MNP, data.code) handleLogin(LoginTypeEnum.MNP, data.code)
} }
watch(
() => appStore.getLoginConfig,
(value) => {
if (value.loginWay) {
loginWay.value = value.loginWay[0]
//@ts-ignore
formData.scene = LoginTypeEnum[LoginWayEnum[loginWay.value]]
}
},
{
immediate: true
}
)
onShow(async () => {
try {
if (userStore.isLogin) {
uni.showLoading({
title: '请稍后...'
})
await userStore.getUser()
uni.hideLoading()
uni.navigateBack()
}
} catch (error) {
uni.hideLoading()
}
})
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -7,7 +7,7 @@
<u-form-item label="创建账号" borderBottom> <u-form-item label="创建账号" borderBottom>
<u-input <u-input
class="flex-1" class="flex-1"
v-model="accountData.username" v-model="formData.username"
:border="false" :border="false"
placeholder="请输入账号" placeholder="请输入账号"
/> />
@ -16,7 +16,7 @@
<u-input <u-input
class="flex-1" class="flex-1"
type="password" type="password"
v-model="accountData.password" v-model="formData.password"
placeholder="请输入字母+数字组合的密码" placeholder="请输入字母+数字组合的密码"
:border="false" :border="false"
/> />
@ -25,13 +25,13 @@
<u-input <u-input
class="flex-1" class="flex-1"
type="password" type="password"
v-model="accountData.password2" v-model="formData.password2"
placeholder="请确认密码" placeholder="请确认密码"
:border="false" :border="false"
/> />
</u-form-item> </u-form-item>
</u-form> </u-form>
<view class="mt-[60rpx]"> <view class="mt-[40rpx]" v-if="isOpenAgreement">
<u-checkbox v-model="isCheckAgreement" shape="circle"> <u-checkbox v-model="isCheckAgreement" shape="circle">
<view class="text-xs flex"> <view class="text-xs flex">
已阅读并同意 已阅读并同意
@ -54,7 +54,7 @@
</view> </view>
</u-checkbox> </u-checkbox>
</view> </view>
<view class="mt-[40rpx]"> <view class="mt-[60rpx]">
<u-button type="primary" shape="circle" @click="accountRegister"> 注册 </u-button> <u-button type="primary" shape="circle" @click="accountRegister"> 注册 </u-button>
</view> </view>
</view> </view>
@ -63,23 +63,26 @@
<script setup lang="ts"> <script setup lang="ts">
import { register } from '@/api/account' import { register } from '@/api/account'
import { reactive, ref } from 'vue' import { useAppStore } from '@/stores/app'
import { computed, reactive, ref } from 'vue'
const isCheckAgreement = ref(false) const isCheckAgreement = ref(false)
const appStore = useAppStore()
const accountData = reactive({ const isOpenAgreement = computed(() => appStore.getLoginConfig.openAgreement == 1)
const formData = reactive({
username: '', username: '',
password: '', password: '',
password2: '' password2: ''
}) })
const accountRegister = async () => { const accountRegister = async () => {
if (!isCheckAgreement.value) return uni.$u.toast('请勾选已阅读并同意《服务协议》和《隐私协议》') if (!isCheckAgreement.value && isOpenAgreement.value)
if (!accountData.username) return uni.$u.toast('请输入账号') return uni.$u.toast('请勾选已阅读并同意《服务协议》和《隐私协议》')
if (!accountData.password) return uni.$u.toast('请输入密码') if (!formData.username) return uni.$u.toast('请输入账号')
if (!accountData.password2) return uni.$u.toast('请输入确认密码') if (!formData.password) return uni.$u.toast('请输入密码')
if (accountData.password != accountData.password2) return uni.$u.toast('两次输入的密码不一致') if (!formData.password2) return uni.$u.toast('请输入确认密码')
await register(accountData) if (formData.password != formData.password2) return uni.$u.toast('两次输入的密码不一致')
await register(formData)
uni.$u.toast('注册成功') uni.$u.toast('注册成功')
uni.navigateBack() uni.navigateBack()
} }

View File

@ -41,40 +41,47 @@
<u-icon name="arrow-right" color="#666"></u-icon> <u-icon name="arrow-right" color="#666"></u-icon>
</view> </view>
</navigator> </navigator>
<navigator url="/pages/as_us/as_us"> <navigator url="/pages/as_us/as_us">
<view class="item bg-white flex flex-1 justify-between"> <view class="item bg-white flex flex-1 justify-between">
<view class="">关于我们</view> <view class="">关于我们</view>
<view class="flex justify-between"> <view class="flex justify-between">
<view class="text-muted mr-[20rpx]"> <view class="text-muted mr-[20rpx]">
{{ appStore.config.version }} {{ appStore.config.version }}
</view> </view>
<u-icon name="arrow-right" color="#666"></u-icon> <u-icon name="arrow-right" color="#666"></u-icon>
</view> </view>
</view> </view>
</navigator> </navigator>
<view class="mt-[60rpx] mx-[26rpx]"> <view class="mt-[60rpx] mx-[26rpx]">
<u-button type="primary" shape="circle" @click="logoutHandle"> <u-button type="primary" shape="circle" @click="logoutHandle"> 退出登录 </u-button>
退出登录 </view>
</u-button>
</view> <u-action-sheet
:list="list"
v-model="show"
<u-action-sheet :list="list" v-model="show" @click="handleClick" :safe-area-inset-bottom="true"></u-action-sheet> @click="handleClick"
:safe-area-inset-bottom="true"
></u-action-sheet>
</view> </view>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { getUserInfo } from '@/api/user' import { getUserInfo } from '@/api/user'
import { onShow } from '@dcloudio/uni-app' import { onShow } from '@dcloudio/uni-app'
import { reactive, ref } from 'vue' import { ref } from 'vue'
import { useAppStore } from '@/stores/app' import { useAppStore } from '@/stores/app'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import { AgreementEnum } from '@/enums/agreementEnums' import { AgreementEnum } from '@/enums/agreementEnums'
const appStore = useAppStore() const appStore = useAppStore()
const userStore = useUserStore() const userStore = useUserStore()
const userInfo = ref({}) const userInfo = ref({
avatar: '',
nickname: '',
username: '',
isBindMnp: ''
})
const list = ref([ const list = ref([
{ {
text: '修改密码' text: '修改密码'
@ -105,17 +112,15 @@ const handleClick = (index: number) => {
// 退 // 退
const logoutHandle = () => { const logoutHandle = () => {
uni.showModal({ uni.showModal({
content: '是否退出登录?', content: '是否退出登录?',
confirmColor: '#4173FF', confirmColor: '#4173FF',
success: ({ success: ({ cancel }) => {
cancel if (cancel) return
}) => { userStore.logout()
if (cancel) return uni.redirectTo({ url: '/pages/login/login' })
userStore.login() }
uni.redirectTo({ url: '/pages/login/login' }) })
}
})
} }
onShow(() => { onShow(() => {
@ -126,11 +131,11 @@ onShow(() => {
<style lang="scss" scoped> <style lang="scss" scoped>
.user-set { .user-set {
.item { .item {
padding: 30rpx; padding: 30rpx;
} }
.btn-border { .btn-border {
border-bottom: 2rpx solid #F8F8F8; border-bottom: 2rpx solid #f8f8f8;
} }
} }
</style> </style>

View File

@ -8,10 +8,18 @@ export const useAppStore = defineStore({
id: 'appStore', id: 'appStore',
state: (): AppSate => ({ state: (): AppSate => ({
config: { config: {
website: {} website: {},
login: {}
} }
}), }),
getters: {}, getters: {
getWebsiteConfig(state) {
return state.config.website
},
getLoginConfig(state) {
return state.config.login
}
},
actions: { actions: {
getImageUrl(url: string) { getImageUrl(url: string) {
return url ? `${this.config.domain}${url}` : '' return url ? `${this.config.domain}${url}` : ''

View File

@ -6,19 +6,23 @@ import { defineStore } from 'pinia'
interface UserSate { interface UserSate {
userInfo: Record<string, any> userInfo: Record<string, any>
token: string | null token: string | null
temToken: string | null
} }
export const useUserStore = defineStore({ export const useUserStore = defineStore({
id: 'userStore', id: 'userStore',
state: (): UserSate => ({ state: (): UserSate => ({
userInfo: {}, userInfo: {},
token: cache.get(TOKEN_KEY) || null token: cache.get(TOKEN_KEY) || null,
temToken: null
}), }),
getters: { getters: {
isLogin: (state) => !!state.token isLogin: (state) => !!state.token
}, },
actions: { actions: {
async getUser() { async getUser() {
const data = await getUserCenter() const data = await getUserCenter({
token: this.token || this.temToken
})
this.userInfo = data this.userInfo = data
}, },
login(token: string) { login(token: string) {

View File

@ -15,9 +15,9 @@ const requestHooks: RequestHooks = {
if (baseUrl) { if (baseUrl) {
options.url = `${baseUrl}${options.url}` options.url = `${baseUrl}${options.url}`
} }
const token = getToken()
// 添加token // 添加token
if (withToken) { if (withToken && token) {
const token = getToken()
options.header.token = token options.header.token = token
} }
return options return options