提交 a36158fe 作者: 方治民

feat: 更新初始配置 + 接口配置 + 登录/退出 + 通用个人中心页面等相关内容

上级 333f6d07
# APP 名称
VITE_GLOB_APP_NAME = Basic APP
VITE_GLOB_APP_NAME = 数智农服
# APP 描述
VITE_GLOB_APP_DESCRIPTION = APP 基础工程
VITE_GLOB_APP_DESCRIPTION = 湖南省农业服务平台
# API 接口地址
VITE_GLOB_API_URL=http://192.168.0.110:8081
VITE_GLOB_API_URL=http://111.22.182.169:49600
# API 接口地址前缀
VITE_GLOB_API_URL_PREFIX=/api
VITE_GLOB_API_URL_PREFIX=/jeecgboot
{
"name": "agri-app",
"name": "湖南省农业服务平台",
"version": "1.0.2",
"description": "数智农服",
"keywords": [
......
......@@ -2,7 +2,6 @@
import { onExit } from '@dcloudio/uni-app'
import { isDevMode } from '@/utils/env'
import { usePermissions } from '@/hooks/app/usePermissions'
import { closeSplashscreenAndChechUpgrade } from '@/utils/upgrade'
// import * as Push from '@/utils/push'
......@@ -27,11 +26,6 @@
setTimeout(() => {
plus.navigator.closeSplashscreen()
}, 3000)
} else {
setTimeout(() => {
// 检查更新
closeSplashscreenAndChechUpgrade()
}, 1500)
}
// #endif
})
......
import { otherHttp } from '/@/utils/http/axios'
enum Api {
getUserInfo = '/sys/user/login/setting/getUserData', // 查询登录用户信息
logout = '/sys/logout', // 登出
sysLogin = '/sys/mLogin', // 登陆
}
/**
* @param params 请求参数
* @description: 查询登录用户信息
*/
export function getUserInfo(params = {}) {
return otherHttp.get({
url: Api.getUserInfo,
data: params,
})
}
/**
* @param params 请求参数
* @description: 登录
*/
export function sysLogin(params = {}) {
return otherHttp.post({
url: Api.sysLogin,
params,
})
}
/**
* @param params 请求参数
* @description: 退出登录
*/
export function logout(params = {}) {
return otherHttp.get({
url: Api.logout,
params,
})
}
......@@ -8,7 +8,7 @@
/* #ifndef APP-NVUE */
page {
/* 行为相关颜色 */
--fui-color-primary: #465CFF;
--fui-color-primary: #4da25b;
--fui-color-success: #09BE4F;
--fui-color-warning: #FFB703;
--fui-color-danger: #FF2B2B;
......
{
"pages": [
{
"path": "pages/login/login",
"style": {
"navigationStyle": "custom",
"transparentTitle": "auto",
"backgroundColor": "#FFFFFF",
"enablePullDownRefresh": false,
"app-plus": {
"titleNView": {}
}
}
},
{
"path": "pages/shouye/shouye",
"style": {
"navigationBarTitleText": "",
......@@ -70,6 +82,29 @@
}
}
},
{
"path": "pages/mine/index",
"style": {
"navigationBarTitleText": "我的",
"app-plus": {
"titleNView": false,
"bounce": false
}
}
},
{
"path": "pages/mine/components/myMessage",
"style": {
"navigationBarTitleText": "个人资料",
"enablePullDownRefresh": false,
"navigationBarBackgroundColor": "#F8F8F8",
"navigationBarTextStyle": "black",
"backgroundColorBottom": "#F2F2F2",
"app-plus": {
"titleNView": {}
}
}
},
// pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
......@@ -215,7 +250,7 @@
"text": "农知"
},
{
"pagePath": "pages/wode/wode",
"pagePath": "pages/mine/index",
"iconPath": "static/images/codefun/me.png",
"selectedIconPath": "static/images/codefun/me.active.png",
"text": "我的"
......
<script setup lang="ts">
// import { PUSH_CLIENT_KEY } from '/@/enums/cacheEnum'
import { useUserStore } from '@/store/modules/user'
import { closeSplashscreenAndChechUpgrade } from '@/utils/upgrade'
import { isDevMode } from '@/utils/env'
import Link from '@/utils/const/link'
import * as API from '/@/api/model/userInfo'
const userStore = useUserStore()
onLoad(async () => {
// 获取推送标识并设置 PushClientId 缓存
// uni.getPushClientId({
// success: (res) => {
// uni.setStorageSync(PUSH_CLIENT_KEY, res.cid)
// },
// })
// 检查是否有 token
const token = userStore.getToken
if (token) {
// // 检查登录状态
// try {
// const valid = await Auth.valid.request()
// if (valid && userStore.getUserInfo) {
// model.isLogin = true
// }
// } catch (error) {
// console.log('error', error)
// }
model.isLogin = true
}
if (model.isLogin) {
// 刷新用户信息
await userStore.refreshUserInfo()
// 跳转到登录页
goHome()
} else {
// 关闭启动页并检查更新
try {
await closeSplashscreenAndChechUpgrade()
} catch (error) {
console.log('error', error)
} finally {
nextTick(() => {
model.show = true
})
}
}
})
// 页面数据
const defaultText = '湖南省农业服务平台'
const readConfirmShow = ref<boolean>(false)
const form = ref()
const model = reactive({
show: false,
isLogin: false,
loading: false,
text: '',
form: {
rules: [
{
name: 'username',
rule: ['required'],
msg: ['请输入手机号/账号'],
},
{
name: 'password',
rule: ['required'],
msg: ['请输入密码'],
},
{
name: 'read',
validator: [
{
msg: '请阅读并同意服务协议和隐私政策',
method: (value: boolean) => {
readConfirmShow.value = !value
return value
},
},
],
},
],
data: {
username: '',
password: '',
read: false,
deviceId: '',
},
},
})
// TODO: 开发环境快速填入账户密码,并默认勾选已读隐私政策和服务协议
if (isDevMode()) {
model.form.data.username = 'admin'
model.form.data.password = 'ZzqEUxdqARrd!aeH'
model.form.data.read = true
}
/**
* 登录
*/
function login() {
form?.value.validator(model.form.data, model.form.rules).then(async (res: { isPassed: boolean }) => {
if (res.isPassed) {
// 登录参数
const params = {
username: model.form.data.username,
password: model.form.data.password,
}
// 短信登录
model.loading = true
API.sysLogin(params)
.then(async (body) => {
console.log('body', body)
if (body) {
// 设置登录缓存信息
userStore.setToken(body.token)
// 登录成功后查询用户信息
const user = await API.getUserInfo()
userStore.setUserInfo(user)
// 打开登录页
goHome()
Message.toast(`登录成功, 欢迎回来!`)
} else {
Message.toast(body.message)
return false
}
})
.finally(() => {
model.loading = false
})
}
})
}
/**
* 跳转到门户页
*/
function goHome() {
uni.reLaunch({
url: '/pages/shouye/shouye',
})
}
// 添加欢迎登录的文字打字动态效果
let loop = null
let direction = 'right'
const count = ref(0)
watch(
() => model.show,
(show) => {
if (show) {
loop && clearInterval(loop)
loop = setInterval(() => {
if (direction === 'right') {
count.value++
if (count.value > defaultText.length + 20) {
direction = 'left'
count.value = defaultText.length
}
} else {
count.value--
if (count.value < 0) {
direction = 'right'
}
}
if (count.value > defaultText.length) {
model.text = defaultText
} else if (count.value < 0) {
model.text = ''
} else {
model.text = defaultText.slice(0, count.value)
}
}, 200)
}
},
)
onUnload(() => {
model.show = false
loop && clearInterval(loop)
})
function onReadConfirm(val) {
if (val.index === 0) {
model.form.data.read = false
} else {
model.form.data.read = true
login()
}
readConfirmShow.value = false
}
</script>
<template>
<view class="warp">
<!-- <image class="login-warp" src="/static/login/login_bg.png" /> -->
<view class="login-bg-wrap">
<image class="login-bg" src="/static/logo.png" />
<view class="logo-content-wrap">
<!-- <view class="">{{ '欢迎登录' }}</view> -->
<view class="logo-text mb-3">{{ model.text }}</view>
<!-- <text class="text-#999 text-24">{{ '*小程序仅供内部员工使用' }}</text> -->
</view>
</view>
<fui-form class="form" ref="form" top="50" :padding="['0rpx', '32rpx']">
<fui-input
height="100rpx"
class="input"
autocomplete="off"
:required="false"
clearable
trim
placeholder="请输入手机号/账号"
v-model="model.form.data.username"
name="mobile"
backgroundColor="transparent"
borderColor="#DDDDDD"
maxlength="11"
>
<template #left>
<view class="fui-left__icon mr-2">
<fui-icon name="my" color="#333" :size="48" />
</view>
</template>
</fui-input>
<fui-input
height="100rpx"
class="input"
password
autocomplete="new-password"
code
:required="false"
clearable
trim
placeholder="请输入密码"
v-model="model.form.data.password"
name="code"
marginTop="50"
backgroundColor="transparent"
borderColor="#DDDDDD"
>
<template #left>
<view class="fui-left__icon mr-2">
<fui-icon name="lock" color="#333" :size="48" />
</view>
</template>
</fui-input>
<view class="btn__box flex-center p-32rpx box-border">
<fui-button
height="88rpx"
background="#67c17a"
size="32rpx"
radius="8rpx"
text="立即登录"
@click="login"
:disabled="model.loading"
:loading="model.loading"
/>
</view>
</fui-form>
<!-- </view> -->
<fui-checkbox-group class="checkbox" name="checkbox">
<view class="fui-list__item fiexdText">
<view class="fui-align__center" style="justify-content: center">
<view
class="fui-text privacy-wrap"
style="font-size: 28rpx; text-align: center; align-items: center"
>
<fui-label style="display: inline-flex; align-items: center">
<fui-checkbox
value="true"
color="#4da25b"
:checked="model.form.data.read"
@change="(e) => (model.form.data.read = e.checked)"
style="margin-right: 10rpx; width: 32rpx; height: 32rpx; margin-top: 2rpx"
/>
已阅读并同意
</fui-label>
<fui-text
@tap="Link.to(Link.services, '服务协议')"
size="28rpx"
text="《服务协议》"
color="#4da25b"
/>
<fui-text
@tap="Link.to(Link.privacy, '隐私政策')"
size="28rpx"
text="《隐私政策》"
color="#4da25b"
/>
</view>
</view>
<!-- 安全区 -->
<fui-safe-area />
</view>
</fui-checkbox-group>
<fui-modal
:show="readConfirmShow"
title="服务协议及隐私保护"
:buttons="[
{ text: '不同意', plain: true },
{ text: '同意', plain: false },
]"
@click="onReadConfirm"
>
<text class="fui-descr">
<text> 为了更好地保障您的合法权益,请您阅读并同意以下协议 </text>
<fui-text
@tap="Link.to(Link.services, '服务协议')"
size="28rpx"
text="《服务协议》"
color="#1890FF"
/>
<fui-text @tap="Link.to(Link.privacy, '隐私政策')" size="28rpx" text="《隐私政策》" color="#1890FF" />
</text>
</fui-modal>
</view>
</template>
<style lang="less" scoped>
// .login-warp {
// width: 100%;
// height: calc(100vh);
// position: absolute;
// // border: 1px solid #000;
// z-index: 0;
// }
@keyframes blink-caret {
0%,
100% {
border-right-color: #333;
}
50% {
border-right-color: transparent;
}
}
.warp {
position: relative;
font-size: 24rpx;
height: calc(100vh);
block-size: 100% 100%;
// background-size: 100% 100%;
// border: 1px solid #000;
background-color: #fff;
}
.fui-descr {
letter-spacing: 1rpx;
padding: 50rpx;
font-size: 24rpx;
color: #b2b2b2;
padding-top: 12rpx;
padding-bottom: 48rpx;
::v-deep(.fui-text__content) {
text-indent: 0 !important;
}
}
.login-bg-wrap {
position: absolute;
top: 260rpx;
width: 100%;
// border: 1px solid #000;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.login-bg {
width: 124rpx;
height: 124rpx;
}
.logo-content-wrap {
// position: absolute;
// left: 40rpx;
// bottom: 40rpx;
font-size: 40rpx;
color: #474747;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.logo-text {
margin-top: 20rpx;
font-weight: bold;
display: flex;
width: fit-content;
height: 40rpx;
line-height: 40rpx;
letter-spacing: 0.15em;
border-right: 0.2em solid transparent;
padding-right: 0.15em;
animation: blink-caret 1s infinite;
}
}
}
.form {
position: absolute;
top: 500rpx;
width: 100%;
z-index: 10;
}
.checkbox {
position: fixed;
left: 0rpx;
bottom: 32rpx;
width: 100%;
z-index: 10;
}
.privacy-wrap {
display: flex;
justify-content: center;
align-items: center;
}
.input,
.btn__box {
width: 100%;
height: 100rpx;
margin-top: 60rpx;
}
.fiexdText {
// position: absolute;
width: 100%;
margin-top: 40rpx;
}
:deep(.fui-input__border-bottom) {
right: 32rpx !important;
}
</style>
<script setup lang="ts">
// import * as API from '/@/api/model/userInfo'
import { useUserStore } from '@/store/modules/user'
const model = reactive({
userId: '',
show: false,
descr: '',
state: '',
version: '',
loading: false,
msg: {
avatar: '/static/logo.png',
realname: '',
orgCodeTxt: '',
phone: '15688642241',
postText: '',
email: '',
sex: 1, // 1 男 2 女
},
})
const userStore = useUserStore()
onLoad(() => {
const { userId, realname, orgCodeTxt, postText, avatar, phone, sex, email } = userStore.getUserInfo
model.userId = userId
model.msg.realname = realname
model.msg.orgCodeTxt = orgCodeTxt
model.msg.postText = postText
model.msg.phone = phone
model.msg.email = email
model.msg.sex = sex
if (avatar) {
model.msg.avatar = avatar
}
})
onShow(async () => {
// await API.getUserInfo().then((res) => {
// model.msg = res
// })
// if (!model.msg.avatar) {
// if (uni.getStorageSync('AvatarUrl')) {
// model.msg.avatar = uni.getStorageSync('AvatarUrl')
// } else {
// model.msg.avatar = '/static/logo.png'
// }
// }
})
function previewImg() {
console.log(11)
const imgsArray = []
imgsArray[0] = model.msg.avatar
uni.previewImage({
current: 0,
urls: imgsArray,
})
}
</script>
<template>
<view class="pb-3 flex flex-col">
<view class="bg-#fff w-700/750 m-auto h-160 headBox">
<view class="h-full flex justify-between items-center avtar">
<text class="text-#999999">头像</text>
<image
:src="model.msg.avatar"
class="avtarImg"
background="transparent"
style="box-shadow: 0 0 20rpx #656565"
@click="previewImg"
/>
</view>
</view>
<view class="bg-#fff w-700/750 m-auto bodyBox">
<view class="msgBox flex justify-between items-center text-30">
<view class="text-#999999"> 姓名 </view>
<view class="text-#333333">
{{ model.msg.realname }}
</view>
</view>
<view class="msgBox flex justify-between items-center text-30">
<view class="text-#999999"> 性别 </view>
<view class="text-#333333">
{{ model.msg.sex === 1 ? '男' : model.msg.sex === 2 ? ' 女' : '- -' }}
</view>
</view>
<view class="msgBox flex justify-between items-center text-30">
<view class="text-#999999"> 手机号码 </view>
<view class="text-#333333">
{{ model.msg.phone }}
</view>
</view>
<view class="msgBox flex justify-between items-center text-30">
<view class="text-#999999"> 邮箱 </view>
<view class="text-#333333">
{{ model.msg.email }}
</view>
</view>
<view class="msgBox flex justify-between items-center text-30">
<view class="text-#999999"> 部门 </view>
<view class="text-#333333 w-8/10">
<fui-overflow-hidden
size="30"
align="right"
:text="model.msg.orgCodeTxt ? `${model.msg.orgCodeTxt}` : '- -'"
/>
<!-- {{ model.msg.orgCodeTxt ? model.msg.orgCodeTxt : '- -' }} -->
</view>
</view>
<view class="msgBox lastBox flex justify-between items-center text-30">
<view class="text-#999999"> 岗位 </view>
<view class="text-#333333">
{{ model.msg.postText ? model.msg.postText : '- -' }}
</view>
</view>
</view>
</view>
</template>
<style lang="scss" scoped>
.headBox {
margin-top: 24rpx;
border-radius: 16rpx;
.avtar {
padding: 0 24rpx;
}
.avtarImg {
width: 112rpx;
height: 112rpx;
border-radius: 50%;
}
}
.bodyBox {
margin-top: 20rpx;
border-radius: 16rpx;
// height: 100rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.msgBox {
width: 92.3%;
min-height: 100rpx;
// padding: 0 24rpx;
border-bottom: 1rpx solid #eeeeee;
// border: 1px solid #000;
}
.lastBox {
border: none;
}
}
</style>
export function getColor(val) {
const style = {} as any
if (val && val === 'DISTRIBUTE') {
style.background = 'rgba(255, 208, 0, 0.2)'
style.color = 'rgba(220, 170, 0, 1)'
} else if (val && val === 'ARRIVE') {
style.background = 'rgba(254, 164, 59, 0.2)'
style.color = 'rgba(255, 151, 30, 1)'
} else if (val && val === 'DISPATCH') {
style.background = 'rgba(255, 111, 111, 0.2)'
style.color = 'rgba(255, 83, 83, 1)'
} else if (val && val === 'FEEDBACK') {
style.background = 'rgba(80, 184, 255, 0.2)'
style.color = 'rgba(80, 184, 255, 1)'
} else if (val && val === 'OVER') {
style.background = 'rgba(91, 207, 83, 0.2)'
style.color = 'rgba(91, 207, 83, 1)'
} else if (val && val === 'CANCEL') {
style.background = 'rgba(204, 204, 204, 0.2)'
style.color = 'rgba(173, 173, 173, 1)'
}
return style
}
<script setup lang="ts">
import { useRuntime } from '@/hooks/app/useRuntime'
import { convertKB } from '@/utils'
import { calculateCacheSize, cleanCache } from '@/components/CacheImage/index'
import { useUserStore } from '@/store/modules/user'
import { checkUpgrade } from '@/utils/upgrade'
// import { Permissions, usePermissions } from '@/components/Permissions'
// import { useUserPermissions } from '@/utils/auth'
// const [registerPermissions, { request }] = usePermissions()
const userStore = useUserStore()
const { app } = useRuntime()
const version = computed(() => app.value.version)
onShow(() => {
const { id, realname, phone, avatar } = userStore.getUserInfo
model.id = id
model.realname = realname
model.phone = phone
if (avatar) {
model.avatar = avatar
}
})
// 个人信息
function navMsg() {
uni.navigateTo({
url: '/pages/mine/components/myMessage',
})
}
// 退出登录
function logOut() {
Message.confirm('确认退出登录状态?', '温馨提示').then((confirm) => {
if (confirm) {
loginOut()
}
})
}
// 调用登出
function loginOut() {
model.loading = true
userStore.logout().finally(() => {
model.loading = false
})
}
/**
* 计算缓存
*/
function calculateCache() {
// 重新计算
const cacheIamgeSizeTotal = calculateCacheSize()
const { size: currentStorageSize, unit: currentStorageSizeUnit } = convertKB(cacheIamgeSizeTotal / 1024)
// 更新视图
items.find((item) => item.title === '系统缓存清除').suffix =
Number(currentStorageSize) === 0 ? '' : `${currentStorageSize}${currentStorageSizeUnit}`
}
const model = reactive({
id: '',
avatar: '/static/logo.png',
realname: '',
phone: '',
show: false,
descr: '',
state: '',
version: '',
loading: false,
})
// 用户默认层级
// const { isPermission } = useUserPermissions('user_default_zIndex_btn')
// 用户应急管理
// const { isPermission: emergencyPermission } = useUserPermissions('emergency_response_btn')
const items = reactive<Recordable[]>([
{
title: '个人资源',
icon: 'level',
disabled: false,
show: true,
handle: () => {
uni.navigateTo({
url: '/pages/wode/wode',
})
},
},
{
title: '问题意见反馈',
icon: 'feedback',
disabled: false,
show: true,
handle: () => {
uni.navigateTo({
url: '/pages/common/feedback/index',
})
},
},
{
title: '系统缓存清除',
icon: 'clean',
suffix: '',
show: true,
handle: (item: Recordable) => {
if (!item.suffix) {
return
}
Message.confirm('确认清除缓存?', '温馨提示').then(async (confirm) => {
if (confirm) {
Message.loading('清理中...')
try {
// 清理缓存
await cleanCache()
// 重新计算
calculateCache()
} finally {
// 延迟提示
setTimeout(() => {
Message.toast('缓存清除成功')
Message.hideLoading()
}, 500)
}
}
})
},
},
{
title: '系统检查更新',
icon: 'update',
suffix: '',
show: true,
handle: () => {
// #ifdef APP-PLUS
// 检查更新
checkUpgrade(true)
// #endif
},
},
{
title: `关于${$app.name}`,
icon: 'about',
show: true,
handle: () => {
uni.navigateTo({
url: '/pages/common/about/index',
})
},
},
])
onShow(() => {
// 计算缓存
calculateCache()
})
watch(
() => version.value,
(value) => {
if (value) {
items.find((item) => item.title === '系统检查更新').suffix = `v${value}`
}
},
)
</script>
<template>
<view class="main page-bg">
<view class="w-full h-250 flex flex-row items-center avatar pt-44px pl-6">
<CacheImage
:src="model.avatar"
width="150"
height="150"
radius="999"
background="transparent"
style="box-shadow: 0 0 10rpx #cdcdcd"
@click="navMsg"
/>
<view class="flex flex-col ml-50rpx">
<text class="text-#fff" style="text-shadow: 0 0 10rpx #888">{{ model.realname }}</text>
<view class="max-w-400rpx mt-20rpx flex-center">
<fui-overflow-hidden
width="100%"
size="24"
color="#fff"
:text="model.phone ? `${model.phone}` : '- -'"
/>
</view>
</view>
</view>
<view class="px-6 pt-6">
<fui-list class="rd-3 overflow-hidden shadow" :top-border="false">
<fui-list-cell
arrow
v-for="(item, index) in items.slice(0, 1)"
:key="index"
:bottom-border="false"
:class="{ disabled: item.disabled }"
v-show="item.show"
@tap="item.handle(item)"
>
<CacheImage
:src="`/static/images/mine/${item.icon}.png`"
width="42"
height="42"
background="transparent"
/>
<text class="ml-3.5 text-30 text-#333333 font-500">{{ item.title }}</text>
</fui-list-cell>
</fui-list>
<fui-list class="rd-3 overflow-hidden shadow !mt-20rpx" :top-border="false">
<fui-list-cell
arrow
v-for="(item, index) in items.slice(1, 5)"
:key="index"
:bottom-border="false"
:class="{ disabled: item.disabled }"
v-show="item.show"
@tap="item.handle(item)"
>
<CacheImage
:src="`/static/images/mine/${item.icon}.png`"
width="42"
height="42"
background="transparent"
/>
<text class="ml-3.5 text-30 text-#333333 font-500">{{ item.title }}</text>
</fui-list-cell>
</fui-list>
<fui-list class="rd-3 overflow-hidden shadow !mt-20rpx" :top-border="false">
<fui-list-cell
arrow
v-for="(item, index) in items.slice(5, 10)"
:key="index"
:bottom-border="false"
class="pos-relative"
:class="{ disabled: item.disabled }"
v-show="item.show"
@tap="item.handle(item)"
>
<CacheImage
:src="`/static/images/mine/${item.icon}.png`"
width="42"
height="42"
background="transparent"
/>
<text class="ml-3.5 text-30 text-#333333 font-500">{{ item.title }}</text>
<text
v-if="item.suffix"
class="pos-absolute right-70"
:style="{ color: item.icon === 'call' ? '#1890FF' : '#999' }"
>
{{ item.suffix }}
</text>
</fui-list-cell>
</fui-list>
</view>
<view class="p-6 pt-5 pb-2">
<fui-button
class="shadow"
background="#fff"
radius="18rpx"
color="#4da25b"
@click="logOut"
:disabled="model.loading"
:loading="model.loading"
>
退出登录
</fui-button>
</view>
<!-- 权限提示组件 -->
<!-- <Permissions @register="registerPermissions" /> -->
</view>
</template>
<style lang="less" scoped>
.main {
width: 100%;
height: 100%;
// #ifdef H5
height: calc(100vh - 60px);
// #endif
}
.page-bg {
background: url('/static/images/codefun/7a5dc4ee864fe55da98b41c14ee3b931.png') no-repeat top center;
background-size: 100%;
}
.userInfo_box {
background: #fff;
padding: 32rpx 30rpx;
display: flex;
align-items: center;
padding-top: 120rpx;
.user_info {
height: 125rpx;
margin-left: 32rpx;
display: flex;
flex-direction: column;
justify-content: space-around;
}
}
.fui-color-border {
border-color: #fff;
}
.me_action {
margin-top: 20rpx;
}
.fui-list__item {
flex: 1;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.fui-text__explain {
font-size: 28rpx;
color: #7f7f7f;
flex-shrink: 0;
}
.fui-list__img {
width: 48rpx;
height: 48rpx;
margin-right: 10rpx;
}
.action_text {
font-size: 32rpx;
}
.loginout {
height: 104rpx;
background: #fff;
font-weight: 400;
color: #1890ff;
font-size: 32rpx;
text-align: center;
line-height: 104rpx;
margin-top: 20rpx;
}
.avatar {
font-weight: bold;
color: #fff;
}
.border-bottom {
&.disabled {
pointer-events: none;
* {
color: gray;
}
}
}
</style>
<script setup lang="ts">
import { reactive } from 'vue'
import { onPullDownRefresh } from '@dcloudio/uni-app'
import { closeSplashscreenAndChechUpgrade } from '@/utils/upgrade'
onLoad(() => {
// 关闭启动页并检查更新
closeSplashscreenAndChechUpgrade()
})
// 下拉刷新
onPullDownRefresh(() => {
......
......@@ -2,10 +2,15 @@ import { defineStore } from 'pinia'
import { store } from '/@/store'
import { Storage } from '@/utils/storage'
import { TOKEN_KEY, USER_INFO_KEY } from '@/enums/cacheEnum'
import type { defs } from '@/api/services'
import Navigate from '@/utils/page/navigate'
import * as API from '/@/api/model/userInfo'
export type UserInfo = Partial<defs.UserInfo>
export interface UserInfo {
id: string
phone: string
avatar: string
realname: string
}
interface UserState {
userInfo: Nullable<UserInfo>
......@@ -50,7 +55,7 @@ export const useUserStore = defineStore({
* @returns 是否为审核账号
*/
isAuditMode(): boolean {
return this.getUserInfo?.mobile === '10000000001'
return this.getUserInfo?.phone === '10000000001'
},
},
actions: {
......@@ -69,7 +74,7 @@ export const useUserStore = defineStore({
this.loading = true
try {
await API.auth.logout.request()
await API.logout()
} finally {
this.setToken(null)
this.setUserInfo(null)
......@@ -84,7 +89,7 @@ export const useUserStore = defineStore({
this.loading = true
try {
const userInfo = await API.userView.getUserInfo.request()
const userInfo = await API.getUserInfo()
this.setUserInfo(userInfo)
} finally {
this.loading = false
......
......@@ -15,7 +15,7 @@
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-primary: #4da25b;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
......
export default {
/**
* 公司官网
*/
company: 'https://yiring.com',
/**
* 服务协议地址
*/
services: 'https://app.yiring.com/agri/app/agreement.html',
/**
* 隐私政策地址
*/
privacy: 'https://app.yiring.com/agri/app/guide.html',
/**
* 从内部打开指定页面
* @param link 链接
* @param title 页面标题
*/
to(link: string, title: string) {
uni.navigateTo({
url: `/pages/common/webview/index?title=${encodeURIComponent(title)}&link=${encodeURIComponent(link)}`,
})
},
/**
* 从外部打开指定页面
* @param link 链接
*/
open(link: string) {
// #ifdef APP-PLUS
if (link?.startsWith('tel:')) {
uni.makePhoneCall({
phoneNumber: link.replace('tel:', ''),
})
} else {
plus.runtime.openURL(link)
}
// #endif
// #ifdef H5
window.open(link)
// #endif
},
}
......@@ -20,6 +20,8 @@ import { API_URL, API_URL_PREFIX } from '/@/utils/net'
import { handleResponseResource } from '/@/utils/proxy'
import { useUserStoreWithOut } from '@/store/modules/user'
// import { useUserStoreWithOut } from '@/store/modules/user'
const globSetting = useGlobSetting()
const urlPrefix = globSetting.urlPrefix
const { createMessage, createErrorModal } = useMessage()
......@@ -51,18 +53,18 @@ const transform: AxiosTransform = {
throw new Error(t('sys.api.apiRequestFailed'))
}
// 这里 status,body,message为 后台统一的字段,需要在 types.ts 内修改为项目自己的接口返回格式
const { status, body, message, details } = data
const { code, result, message, details } = data
// 这里逻辑可以根据项目进行修改
const hasSuccess = data && Reflect.has(data, 'status') && status === HTTP.Status.OK
const hasSuccess = (data && Reflect.has(data, 'code') && code === HTTP.Status.OK) || code === 0
if (hasSuccess) {
return handleResponseResource(body, options)
return handleResponseResource(result, options)
}
// 在此处根据自己项目的实际情况对不同的code执行不同的操作
// 如果不希望中断当前请求,请return数据,否则直接抛出异常即可
let timeoutMsg = ''
switch (status) {
switch (code) {
case HTTP.Status.UNAUTHORIZED: {
timeoutMsg = t('sys.api.unauthorizeMessage')
......@@ -155,12 +157,18 @@ const transform: AxiosTransform = {
// 请求之前处理config
const userStore = useUserStoreWithOut()
const token = userStore.getToken
if (token && (config as Recordable)?.requestOptions?.withToken !== false) {
// jwt token
;(config as Recordable).headers[options.authenticationHeader] = options.authenticationScheme
;(config as Recordable).headers['X-Access-Token'] = options.authenticationScheme
? `${options.authenticationScheme} ${token}`
: token
}
if (token) {
config.headers['X-Access-Token'] = token
}
return config
},
......@@ -202,7 +210,7 @@ const transform: AxiosTransform = {
throw new Error(error as unknown as string)
}
checkStatus(error?.response?.status, msg, errorMessageMode)
checkStatus(error?.response?.code, msg, errorMessageMode)
// 添加自动重试机制 保险起见 只针对GET请求
const retryRequest = new AxiosRetry()
......@@ -224,14 +232,14 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) {
// authenticationScheme: 'Bearer',
authenticationScheme: '',
// authenticationHeader: 'Authorization',
authenticationHeader: 'App-Token',
authenticationHeader: 'X-Access-Token',
timeout: 10 * 1000,
// 基础接口地址
// baseURL: globSetting.apiUrl,
// headers: { 'Content-Type': ContentTypeEnum.JSON },
// 如果是form-data格式
headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED },
headers: { 'Content-Type': ContentTypeEnum.JSON },
// 数据处理方式
transform: clone(transform),
// 配置项,下面的选项都可以在独立的接口请求中覆盖
......@@ -272,22 +280,29 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) {
// TODO: 实际项目所需的请求配置,可自定义扩展
export const defHttp = createAxios({
headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED },
requestOptions: {
apiUrl: API_URL,
urlPrefix: API_URL_PREFIX,
},
})
export const otherHttp = createAxios({
headers: { 'Content-Type': ContentTypeEnum.JSON },
requestOptions: {
apiUrl: API_URL,
urlPrefix: API_URL_PREFIX,
},
})
// other api url
// export const otherHttp = createAxios({
// transform: {
// inject: (config: AxiosRequestConfig<any>, options: http.RequestOptions) => {
// // TODO: 根据实际项目配置
// return { config, options }
// },
// },
// requestOptions: {
// apiUrl: 'xxx',
// urlPrefix: 'xxx',
// },
// })
/**
* 用于请求外部资源,不需要携带 token,返回原生 response
*/
export const externalHttp = createAxios({
requestOptions: {
apiUrl: '',
urlPrefix: '',
withToken: false,
isReturnNativeResponse: true,
},
})
......@@ -60,3 +60,18 @@ export function withInstall<T>(component: T, alias?: string) {
}
return component as T & Plugin
}
// 将 KB 转换为其他单位
export function convertKB(kb: number) {
const bytes = kb * 1024
const units = ['B', 'KB', 'MB', 'GB', 'TB']
let size = bytes
let unitIndex = 0
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024
unitIndex++
}
return { size: size.toFixed(2), unit: units[unitIndex] }
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论