Commit 627768c0 by liangjianmin

feat(logistics): 添加物流车辆申请页面和个人中心页面

- 在 pages.json 中添加物流车辆申请和个人中心的路由配置
- 新增 logistics/index.vue 页面,待开发的物流车辆申请表单
- 新增 mine/index.vue 页面,展示用户信息和退出功能
- 更新首页,调整快捷入口的样式和功能
- 删除不再使用的图标文件,更新 tabBar 图标路径
- 新增 mine/index.scss 和 logistics/index.scss 样式文件
parent c255ec1f
.logistics-page {
min-height: 100vh;
background: #f4f6fb;
}
.mine-page {
min-height: 100vh;
padding-bottom: 158rpx;
background: #f4f6fb;
.profile-hero {
position: relative;
padding: 56rpx 32rpx 40rpx;
overflow: hidden;
.hero-bg {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 280rpx;
background: linear-gradient(135deg, #1e3a8a 0%, #2563eb 55%, #3b82f6 100%);
border-radius: 0 0 48rpx 48rpx;
&::before {
content: '';
position: absolute;
top: -60rpx;
right: -50rpx;
width: 320rpx;
height: 320rpx;
background: radial-gradient(circle, rgba(255, 255, 255, 0.12) 0%, transparent 70%);
}
}
.profile-card {
position: relative;
z-index: 1;
display: flex;
align-items: center;
.avatar {
width: 120rpx;
height: 120rpx;
border-radius: 32rpx;
background: rgba(255, 255, 255, 0.18);
backdrop-filter: blur(10rpx);
border: 2rpx solid rgba(255, 255, 255, 0.35);
display: flex;
align-items: center;
justify-content: center;
margin-right: 28rpx;
.avatar-text {
font-size: 52rpx;
font-weight: 700;
color: #ffffff;
}
}
.profile-meta {
display: flex;
flex-direction: column;
.p-name {
font-size: 40rpx;
font-weight: 700;
color: #ffffff;
letter-spacing: 1rpx;
margin-bottom: 12rpx;
}
.p-position {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.85);
}
}
}
}
.info-list {
margin: 0 32rpx;
background: #ffffff;
border-radius: 28rpx;
padding: 8rpx 32rpx;
box-shadow: 0 8rpx 28rpx rgba(15, 23, 42, 0.06);
.info-item {
padding: 32rpx 0;
border-bottom: 1rpx solid #f1f5f9;
&:last-child {
border-bottom: none;
}
.info-icon {
width: 64rpx;
height: 64rpx;
border-radius: 18rpx;
display: flex;
align-items: center;
justify-content: center;
margin-right: 24rpx;
flex-shrink: 0;
}
.info-label {
font-size: 28rpx;
color: #64748b;
width: 140rpx;
flex-shrink: 0;
}
.info-value {
flex: 1;
font-size: 28rpx;
font-weight: 600;
color: #1e293b;
text-align: right;
word-break: break-all;
}
}
}
.logout-wrap {
padding: 48rpx 32rpx;
.logout-btn {
height: 96rpx;
background: #ffffff;
border-radius: 24rpx;
box-shadow: 0 8rpx 24rpx rgba(239, 68, 68, 0.08);
transition: all 0.2s ease;
&:active {
transform: scale(0.98);
background: #fef2f2;
}
.logout-text {
font-size: 30rpx;
font-weight: 600;
color: #ef4444;
margin-left: 12rpx;
letter-spacing: 1rpx;
}
}
}
}
......@@ -30,6 +30,18 @@
"style": {
"navigationBarTitleText": "审批详情页"
}
},
{
"path": "pages/logistics/index",
"style": {
"navigationBarTitleText": "物流车辆申请"
}
},
{
"path": "pages/mine/index",
"style": {
"navigationBarTitleText": "个人中心"
}
}
],
"tabBar": {
......@@ -41,20 +53,20 @@
{
"pagePath": "pages/home/index",
"text": "首页",
"iconPath": "static/home.png",
"selectedIconPath": "static/home-sel.png"
},
{
"pagePath": "pages/apply/index",
"text": "发起申请",
"iconPath": "static/apply.png",
"selectedIconPath": "static/apply-sel.png"
"iconPath": "static/tab/home.png",
"selectedIconPath": "static/tab/home-sel.png"
},
{
"pagePath": "pages/approve/index",
"text": "审批列表",
"iconPath": "static/audit.png",
"selectedIconPath": "static/audit-sel.png"
"iconPath": "static/tab/audit.png",
"selectedIconPath": "static/tab/audit-sel.png"
},
{
"pagePath": "pages/mine/index",
"text": "个人中心",
"iconPath": "static/tab/mine.png",
"selectedIconPath": "static/tab/mine-sel.png"
}
]
},
......
<template>
<view class="home-index">
<view class="head" v-if="!loading && info.user_info">
<view class="user-card">
<view class="row bothSide verCenter">
<view class="info-bar row verCenter">
<view class="avatar-wrap">
<text class="iconfont icon-juxing"></text>
</view>
<view class="column">
<text class="t1">{{ info.user_info.name }}</text>
<text class="t2">{{ info.user_info.email }}</text>
</view>
</view>
<view class="setting row verCenter" @click="exit()">
<text class="iconfont icon-a-juxing13"></text>
<view class="hero">
<view class="hero-bg"></view>
<view class="hero-inner">
<view class="greeting">
<text class="g-sub">SUPPLY CHAIN</text>
<text class="g-main">供应链审批系统</text>
</view>
<view class="stat-card">
<view class="stat-item" v-for="(item, index) in statList" :key="item.key" :style="{ animationDelay: (index * 0.08) + 's' }">
<text class="stat-num">{{ item.value }}</text>
<text class="stat-label">{{ item.label }}</text>
</view>
<view class="stat-divider"></view>
<view class="stat-divider stat-divider-2"></view>
</view>
</view>
</view>
<view class="content-wrap" v-if="!loading && info.user_info">
<view class="section-header row verCenter">
<text class="section-title">快捷入口</text>
</view>
<view class="content-wrap">
<view class="group" v-for="(group, gIndex) in groupList" :key="group.title">
<view class="section-header row verCenter">
<view class="title-bar"></view>
<text class="section-title">{{ group.title }}</text>
</view>
<view class="entry-grid">
<view class="entry-card" v-for="(item, index) in entryList" :key="item.id" @click="goApply(item)" :style="{ animationDelay: (index * 0.1) + 's' }">
<view class="card-content">
<view class="icon-section">
<view class="icon-bg-layer"></view>
<view class="icon-container">
<u-icon :name="item.icon" :color="item.color" size="48"></u-icon>
</view>
<view class="icon-shine"></view>
<view class="entry-grid">
<view class="entry-card" :class="{ 'is-disabled': item.disabled }" v-for="(item, index) in group.items" :key="item.id" @click="goApply(item)" :style="{ animationDelay: (gIndex * 0.1 + index * 0.06) + 's' }">
<view class="icon-wrap" :style="{ background: item.bg }">
<u-icon :name="item.icon" color="#ffffff" size="40"></u-icon>
</view>
<view class="text-section">
<text class="entry-title">{{ item.name }}</text>
<text class="entry-subtitle">快速发起申请</text>
<text class="entry-title">{{ item.name }}</text>
<text class="entry-tip" v-if="item.disabled">暂未上线</text>
<view class="entry-arrow" v-else>
<u-icon name="arrow-right" color="#94a3b8" size="22"></u-icon>
</view>
</view>
<view class="card-action">
<view class="action-line"></view>
<view class="action-icon">
<u-icon name="arrow-right" color="#3b82f6" size="18"></u-icon>
</view>
</view>
<view class="card-border"></view>
</view>
</view>
</view>
......@@ -56,71 +43,45 @@
</template>
<script>
import { API } from '@/util/api.js';
export default {
data() {
return {
info: {},
loading: true,
entryList: [
// 统计数据:暂写死,后续接入接口
statList: [
{ key: 'pending', label: '待处理', value: 5 },
{ key: 'done', label: '已处理', value: 1 },
{ key: 'mine', label: '我发起', value: 0 }
],
groupList: [
{
id: 1,
name: '费用减免申请',
icon: 'file-text-fill',
color: '#3b82f6'
title: '日常业务',
items: [
{ id: 'fee', name: '业务费用减免', icon: 'rmb-circle-fill', bg: 'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)', url: '/pages/apply/index' },
{ id: 'logistics', name: '物流车辆申请', icon: 'car-fill', bg: 'linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%)', url: '/pages/logistics/index' }
]
},
{
title: '额度风控',
items: [
{ id: 'tempQuota', name: '临时额度申请', icon: 'clock-fill', bg: 'linear-gradient(135deg, #f59e0b 0%, #d97706 100%)', disabled: true },
{ id: 'creditQuota', name: '授信额度申请', icon: 'integral-fill', bg: 'linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%)', disabled: true }
]
}
]
};
},
onShow() {
this.getData();
},
methods: {
/**
* 获取数据
* @return {void}
*/
getData() {
this.request(API.getStatisticsInfo, 'POST', {}, true).then(res => {
if (res.code === 0) {
this.info = res.data;
uni.setStorageSync('email', res.data.user_info.email);
uni.setStorageSync('user_name', res.data.user_info.name);
}
this.loading = false;
});
},
/**
* 跳转到发起申请页
* 跳转到对应业务页面
* @param {Object} item - 入口项
* @return {void}
*/
goApply(item) {
uni.switchTab({
url: '/pages/apply/index'
});
},
/**
* 退出系统
* @return {void}
*/
exit() {
uni.showModal({
title: '提示',
content: '确定要退出系统吗?',
showCancel: true,
success: res => {
if (res.confirm) {
['oa_skey', 'oa_user_id', 'email', 'user_name'].map(key => uni.removeStorageSync(key));
uni.redirectTo({
url: '/pages/mine/login'
});
}
}
});
if (item.disabled) {
uni.showToast({ title: '功能暂未上线', icon: 'none' });
return;
}
uni.navigateTo({ url: item.url });
}
}
};
......
<template>
<view class="logistics-page">
<!-- 物流车辆申请表单:待开发 -->
</view>
</template>
<script>
export default {
data() {
return {};
},
methods: {}
};
</script>
<style scoped lang="scss">
@import '@/assets/css/logistics/index.scss';
</style>
<template>
<view class="mine-page">
<view class="profile-hero">
<view class="hero-bg"></view>
<view class="profile-card">
<view class="avatar">
<text class="avatar-text">{{ avatarText }}</text>
</view>
<view class="profile-meta">
<text class="p-name">{{ info.name || '--' }}</text>
<text class="p-position">{{ info.position_name || '暂无岗位信息' }}</text>
</view>
</view>
</view>
<view class="info-list">
<view class="info-item row verCenter" v-for="item in infoFields" :key="item.key">
<view class="info-icon" :style="{ background: item.bg }">
<u-icon :name="item.icon" color="#ffffff" size="32"></u-icon>
</view>
<text class="info-label">{{ item.label }}</text>
<text class="info-value">{{ info[item.key] || '--' }}</text>
</view>
</view>
<view class="logout-wrap">
<view class="logout-btn row rowCenter verCenter" @click="exit">
<u-icon name="close-circle" color="#ef4444" size="32"></u-icon>
<text class="logout-text">退出账号</text>
</view>
</view>
</view>
</template>
<script>
import { API } from '@/util/api.js';
export default {
data() {
return {
info: {},
infoFields: [
{ key: 'name', label: '员工姓名', icon: 'account-fill', bg: 'linear-gradient(135deg, #3b82f6, #2563eb)' },
{ key: 'email', label: '绑定邮箱', icon: 'email-fill', bg: 'linear-gradient(135deg, #0ea5e9, #0284c7)' },
{ key: 'department_name', label: '部门', icon: 'home-fill', bg: 'linear-gradient(135deg, #8b5cf6, #7c3aed)' },
{ key: 'position_name', label: '岗位', icon: 'star-fill', bg: 'linear-gradient(135deg, #f59e0b, #d97706)' }
]
};
},
computed: {
/**
* 头像占位文字,取姓名末位字
* @return {string}
*/
avatarText() {
var name = this.info.name || '';
return name ? name.slice(-1) : '员';
}
},
onShow() {
this.getUserInfo();
},
methods: {
/**
* 获取用户基础信息
* @return {void}
*/
getUserInfo() {
this.request(API.userBaseInfo, 'GET', {}, true).then(res => {
if (res.code === 0) {
this.info = res.data;
uni.setStorageSync('email', res.data.email);
uni.setStorageSync('user_name', res.data.name);
}
});
},
/**
* 退出账号
* @return {void}
*/
exit() {
uni.showModal({
title: '提示',
content: '确定要退出账号吗?',
showCancel: true,
success: res => {
if (res.confirm) {
['oa_skey', 'oa_user_id', 'email', 'user_name'].map(key => uni.removeStorageSync(key));
uni.reLaunch({
url: '/pages/mine/login'
});
}
}
});
}
}
};
</script>
<style scoped lang="scss">
@import '@/assets/css/mine/index.scss';
</style>
......@@ -5,20 +5,8 @@
<view class="form-box column rowCenter verCenter">
<view class="input-box row verCenter">
<text class="iconfont icon-riqi"></text>
<input
type="text"
class="uni-input"
placeholder="请输入登录账号"
v-model="name"
placeholder-style="color: #6E767A;"
adjust-position
@input="onEmailInput"
/>
<view
v-if="showDomainTag"
class="domain-tag"
@click="applyDomain"
>
<input type="text" class="uni-input" placeholder="请输入登录账号" v-model="name" placeholder-style="color: #6E767A;" adjust-position @input="onEmailInput" />
<view v-if="showDomainTag" class="domain-tag" @click="applyDomain">
<text class="domain-text">@ichunt.com</text>
</view>
</view>
......@@ -137,7 +125,7 @@
this.request(API.login, 'POST', { name: this.name, passwd: md5.hex_md5_32(this.passwd) }, true).then(res => {
if (res.retcode === 0) {
this.loginSuccess = true;
setTimeout(() => {
uni.setStorageSync('oa_skey', res.data.skey);
uni.setStorageSync('oa_user_id', res.data.userId);
......
......@@ -58,6 +58,10 @@ const API = {
*/
getStatisticsInfo: API_BASE_PUR + '/api/approve/getStatisticsInfo',
/**
* 获取用户信息
*/
userBaseInfo: API_BASE + '/api/user/userBaseInfo',
/**
* 上传文件
*/
upload: API_BASE_OSS + '/uploadImage',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment