Files
oa_app/pages/tabs/me.vue
T
2026-09-24 10:53:49 +08:00

153 lines
5.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="page edge">
<fy-header title="我的" />
<fy-scroll class="edge-scroll" dock @refresh="reload">
<view class="body">
<view class="profile" @click="goArchive">
<image v-if="me && me.avatar" class="av" :src="me.avatar" mode="aspectFill" />
<view v-else class="av txt">{{ initial }}</view>
<view class="info">
<view class="nm">
<text class="name">{{ me ? me.name : '' }}</text>
<text v-if="statusText" class="tag">{{ statusText }}</text>
</view>
<text class="sub">{{ deptLine }}</text>
<text class="sub">{{ phone }}{{ job }}</text>
</view>
<wd-icon name="qrcode" size="36rpx" color="#111827" />
<text class="chev"></text>
</view>
<view class="group">
<view class="cell" @click="switchClock">
<wd-icon name="location" size="40rpx" color="#1677FF" />
<text class="ct">本月出勤</text>
<text class="cv">{{ attendDays }} </text>
<text class="chev"></text>
</view>
<view class="cell" @click="goTodo">
<wd-icon name="check-circle" size="40rpx" color="#16A34A" />
<text class="ct">待办申请</text>
<text class="cv">{{ todoCount }}</text>
<text class="chev"></text>
</view>
</view>
<view v-if="menus.length" class="group">
<view v-for="a in menus" :key="a.id" class="cell" @click="open(a)">
<wd-icon :name="iconOf(a)" size="40rpx" :color="colorOf(a)" />
<text class="ct">{{ a.title }}</text>
<text class="chev"></text>
</view>
</view>
<view class="group">
<view class="cell" @click="goPwd">
<wd-icon name="lock-on" size="40rpx" color="#576B95" />
<text class="ct">修改密码</text>
<text class="chev"></text>
</view>
</view>
<view class="group">
<view class="cell center" @click="logout">
<text class="danger">退出登录</text>
</view>
</view>
</view>
</fy-scroll>
</view>
</template>
<script>
import FyHeader from '../../components/fy-header.vue'
import FyScroll from '../../components/fy-scroll.vue'
import { store } from '../../utils/store.js'
import { maskPhone } from '../../utils/format.js'
import { tileVisual } from '../../utils/nav.js'
const ME_IDS = ['archive', 'salary', 'perf', 'expense', 'report', 'apply']
export default {
components: { FyHeader, FyScroll },
data() {
return { off: null }
},
computed: {
me() { return store.me },
initial() { return this.me ? this.me.name.slice(0, 1) : '我' },
statusText() {
return (this.me && this.me.employeeStatus) || '在职'
},
deptLine() {
if (!this.me) return ''
return [this.me.department, this.me.title].filter(Boolean).join(' · ')
},
phone() { return maskPhone(this.me && this.me.phone) },
job() { return this.me && this.me.jobId ? ' · 工号: ' + this.me.jobId : '' },
todoCount() { return store.todoCount || 0 },
attendDays() { return (store.attendance || []).length || 0 },
menus() {
return store.personalApps().filter((a) => ME_IDS.includes(a.id))
}
},
onShow() {
if (store.phase !== 'app') uni.reLaunch({ url: '/pages/login/login' })
this.off = store.on(() => this.$forceUpdate())
},
onHide() { if (this.off) this.off() },
methods: {
iconOf(a) { return tileVisual(a).name },
colorOf(a) { return tileVisual(a).color },
goArchive() {
const a = store.personalApps().find((x) => x.id === 'archive')
if (a) this.open(a)
else uni.navigateTo({ url: '/pages/me/archive' })
},
open(a) {
if (a.url.startsWith('/pages/tabs/')) uni.switchTab({ url: a.url.split('?')[0] })
else uni.navigateTo({ url: a.url })
},
switchClock() { uni.switchTab({ url: '/pages/tabs/clock' }) },
goTodo() { uni.navigateTo({ url: '/pages/todo/list' }) },
reload() { store.refreshPerms() },
goPwd() { uni.navigateTo({ url: '/pages/password/password' }) },
logout() {
uni.showModal({
title: '退出登录',
content: '确定退出当前账号?',
success: (r) => {
if (r.confirm) {
store.logout()
uni.reLaunch({ url: '/pages/login/login' })
}
}
})
}
}
}
</script>
<style scoped>
.body { padding: 16rpx 0 48rpx; background: #EDEDED; min-height: 100%; }
.profile {
display: flex; align-items: center;
background: #fff; padding: 48rpx 28rpx 40rpx; margin-bottom: 16rpx;
}
.av { width: 128rpx; height: 128rpx; border-radius: 12rpx; flex-shrink: 0; }
.av.txt { background: #1677FF; color: #fff; display: flex; align-items: center; justify-content: center; font-size: 48rpx; font-weight: 650; }
.info { flex: 1; min-width: 0; margin: 0 20rpx; }
.nm { display: flex; align-items: center; gap: 12rpx; }
.name { font-size: 40rpx; font-weight: 650; color: #111827; }
.tag { font-size: 22rpx; color: #16A34A; background: #E8F8EF; border-radius: 8rpx; padding: 2rpx 10rpx; }
.sub { display: block; font-size: 26rpx; color: #6B7280; margin-top: 8rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.group { background: #fff; margin-bottom: 16rpx; }
.cell { display: flex; align-items: center; min-height: 108rpx; padding: 0 28rpx; gap: 24rpx; }
.cell + .cell { border-top: 1rpx solid #EDEDED; }
.cell.center { justify-content: center; }
.ct { flex: 1; font-size: 32rpx; color: #111827; }
.cv { font-size: 28rpx; color: #9CA3AF; }
.chev { color: #C8C8C8; font-size: 36rpx; }
.danger { font-size: 32rpx; color: #111827; }
</style>