admin/addon/cashier/source/os/layout/components/layout-aside.vue

606 lines
14 KiB
Vue

<template>
<view>
<view class="aside-container">
<view class="aside-headimg">
<uni-dropdown>
<view slot="dropdown-link" class="head-box" @click="$refs.moreMenu.close()">
<image :src="$util.img(defaultImg.store)" v-if="!storeInfo || !storeInfo.store_image || logoError" mode="aspectFit"></image>
<image :src="$util.img(storeInfo.store_image)" v-else @error="$util.img(defaultImg.store)" mode="aspectFit"></image>
</view>
<view slot="dropdown">
<view class="dropdown-menu">
<view class="menu-item" v-if="userInfo" @click="changePassword">
{{ userInfo ? userInfo.username : '' }}
<text class="iconfont iconqianhou2"></text>
</view>
<view class="menu-item">门店名称:{{ storeInfo ? storeInfo.store_name : '' }}</view>
<view class="menu-item" @click="switchStore()" v-if="storeList.length > 1">切换门店</view>
<view class="menu-item logout" @click="$refs.logout.open()">
退出登录
<text class="iconfont icontuichu"></text>
</view>
<view class="arrow"></view>
</view>
</view>
</uni-dropdown>
</view>
<view class="menu-wrap">
<block v-for="(item, index) in menu" :key="index">
<view class="menu-item" :class="{ active: index == first }" @click="firstMenu(item, index)">
<view class="iconfont" :class="item.icon"></view>
<view>{{ item.title }}</view>
</view>
</block>
</view>
</view>
<uni-popup ref="passwordPopup">
<view class="password-popup">
<view class="head">修改密码</view>
<view class="common-form body">
<view class="common-form-item">
<view class="form-label">
<text class="required">*</text>
原密码
</view>
<view class="form-input-inline"><input type="text" :password="true" v-model="codeData.old_pass" class="form-input" placeholder="请输入原密码" /></view>
</view>
<view class="common-form-item">
<view class="form-label">
<text class="required">*</text>
新密码
</view>
<view class="form-input-inline"><input type="text" :password="true" v-model="codeData.new_pass" class="form-input" placeholder="请输入新密码" /></view>
</view>
<view class="common-form-item">
<view class="form-label">
<text class="required">*</text>
确认新密码
</view>
<view class="form-input-inline">
<input type="text" :password="true" v-model="codeData.confirm_new_pass" class="form-input" placeholder="请输入新密码" />
</view>
</view>
<view class="common-btn-wrap">
<button type="default" class="primary-btn screen-btn" @click="modifyPasswordFn">确定</button>
<button type="default" class="default-btn" @click="$refs.passwordPopup.close()">取消</button>
</view>
</view>
</view>
</uni-popup>
<uni-popup ref="moreMenu">
<scroll-view scroll-y="true" class="more-menu-scroll common-scrollbar">
<view class="more-menu">
<block v-for="(item, secondIndex) in moreMenu" :key="secondIndex">
<block v-if="item.children && item.children.length">
<view class="title">{{ item.title }}</view>
<view class="child-menu-wrap">
<block v-for="(thirditem, thirdIndex) in item.children" :key="thirdIndex">
<view
class="menu-item"
:class="{ active: secondIndex == second && thirdIndex == third }"
@click="thirdMenu(thirditem, secondIndex, thirdIndex)"
>
<view class="iconfont" :class="thirditem.icon"></view>
<view>{{ thirditem.title }}</view>
</view>
</block>
</view>
</block>
</block>
</view>
</scroll-view>
</uni-popup>
<uni-popup ref="storePop">
<view class="pop-box store-select">
<view class="pop-header">
<view class="pop-header-text">选择门店</view>
<view class="pop-header-close" @click="$refs.storePop.close()"><i class="iconguanbi1 iconfont"></i></view>
</view>
<scroll-view scroll-y="true" class="common-scrollbar pop-content">
<view class="content-lists">
<view
class="content-items"
v-for="(item, index) in storeList"
@click="selectStore(item)"
:key="index"
:class="{ active: storeInfo && storeInfo.store_id == item.store_id }"
>
<view class="item-img">
<image v-if="item.store_image" :src="$util.img(item.store_image, { size: 'small' })" @error="$util.img(defaultImg.store)" mode="aspectFit"></image>
<image v-else :src="$util.img(defaultImg.store)" mode="aspectFit"></image>
</view>
<view class="item-info">
<view class="item-name">{{ item.store_name }}</view>
<view class="item-phone">
<i class="iconfont iconshijian"></i>
{{ item.open_date ? item.open_date : '营业时间请联系管理员' }}
</view>
<view class="item-addr">
<i class="iconfont icondizhi"></i>
{{ item.full_address }}
</view>
</view>
</view>
</view>
</scroll-view>
<view class="pop-bottom"><button class="primary-btn" @click="$refs.storePop.close()">确定</button></view>
</view>
</uni-popup>
<uni-popup ref="logout" type="center">
<view class="logout-popup">
<view class="title">确定退出系统?系统将自动交班</view>
<view class="btn">
<button type="primary" class="default-btn btn save" @click="$refs.logout.close()">取消</button>
<button type="primary" class="primary-btn btn" @click="logout">确定</button>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import { mapState } from 'vuex';
export default {
name: 'LayoutAside',
props: {},
created() {
this.getStoreList();
},
data() {
return {
moreMenu: [],
moreIndex: 0,
logoError: false,
storeList: [],
codeData: {
old_pass: '',
new_pass: '',
confirm_new_pass: ''
}
};
},
computed: {
...mapState(['first', 'second', 'third', 'currRoute', 'addon', 'userInfo', 'menu'])
},
watch: {
storeInfo: function() {
this.$store.dispatch('getUserGroup');
},
menu: function() {
this.checkPageAuth();
}
},
methods: {
firstMenu(data, index) {
// #ifdef H5
if (data.path == this.$route.path) return;
// #endif
// #ifdef APP-PLUS
if (data.path == '/' + this.$mp.page.route) return;
// #endif
if (data.children && data.childshow) {
this.moreMenu = data.children;
this.moreIndex = index;
this.$refs.moreMenu.open('left');
} else {
this.$refs.moreMenu.close('left');
this.$util.redirectTo(data.path, data.query ?? {});
}
},
thirdMenu(data, second, third) {
this.$refs.moreMenu.close('left');
this.$util.redirectTo(data.path, data.query ?? {});
},
logout() {
this.$api.sendRequest({
url: '/cashier/storeapi/store/changeshifts',
success: res => {
if (res.code == 0 && res.data) {
this.$refs.logout.close();
uni.removeStorage({
key: 'cashier_token',
success: () => {
this.$store.commit('setStoreInfo', null);
this.$store.commit('setMemberInfo', null);
this.$store.commit('setUserInfo', null);
this.$store.commit('setMenu', []);
this.$util.redirectTo('/pages/login/login', {}, 'reLaunch');
}
});
} else {
this.isSub = false;
this.$util.showToast({
title: res.message
});
}
}
});
},
switchStore() {
this.$refs.storePop.open('center');
},
changePassword() {
this.$refs.passwordPopup.open('center');
},
modifyPasswordFn() {
if (this.codeData.new_pass != this.codeData.confirm_new_pass) {
this.$util.showToast({
title: '两次密码输入不一致,请重新输入'
});
return false;
}
this.$api.sendRequest({
url: '/cashier/storeapi/user/modifypassword',
data: this.codeData,
success: res => {
this.$util.showToast({
title: res.message
});
if (res.code >= 0) {
this.codeData.old_pass = '';
this.codeData.new_pass = '';
this.codeData.confirm_new_pass = '';
uni.removeStorageSync('cashier_token');
this.$refs.passwordPopup.close();
setTimeout(() => {
this.$util.redirectTo('/pages/login/login');
}, 500);
}
}
});
},
selectStore(data) {
uni.setStorageSync('store_id', data.store_id);
this.$store.dispatch('getStoreInfo');
this.$refs.storePop.close();
this.$forceUpdate();
},
getStoreList() {
this.$api.sendRequest({
url: '/cashier/storeapi/store/lists',
success: res => {
if (res.code == 0 && res.data) this.storeList = res.data;
}
});
},
/**
* 检测页面是否有权限
*/
checkPageAuth() {
this.$api.sendRequest({
url: '/cashier/storeapi/store/checkpageauth',
data: {
page: this.currRoute
},
success: res => {
if (res.code && res.code == -10012) {
this.$util.redirectTo('/pages/index/no_permission', {}, 'redirectTo');
}
}
});
}
}
};
</script>
<style lang="scss">
/deep/ .aside-headimg .dropdown-box {
left: 0 !important;
right: unset !important;
}
.aside-container {
position: fixed;
top: $statusbar-height;
width: $aside-width;
height: 100vh;
background-color: #272738;
font-size: 0.12rem;
color: #fff;
z-index: 1000;
}
.aside-headimg {
width: 100%;
height: 0.8rem;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
.head-box {
image {
border-radius: 50%;
width: 0.4rem;
height: 0.4rem;
}
}
}
.menu-wrap {
height: calc(100vh - #{$header-height} - #{$statusbar-height});
overflow-y: scroll;
&::-webkit-scrollbar {
display: none;
}
.menu-item {
text-align: center;
color: #cccccc;
font-size: 0.14rem;
line-height: 1;
padding: 0.15rem 0;
cursor: pointer;
.iconfont {
font-size: 0.2rem;
margin-bottom: 0.1rem;
}
&.active {
background: $primary-color;
color: #fff;
}
}
}
.more-menu-scroll {
height: calc(100vh - #{$statusbar-height});
margin-top: $statusbar-height;
background-color: #fff;
}
.more-menu {
width: 3rem;
background: #fff;
box-sizing: content-box;
padding-left: $aside-width;
height: 100%;
.title {
font-size: 0.2rem;
font-weight: 400;
color: #303133;
line-height: 0.36rem;
padding: 0.2rem;
}
}
.child-menu-wrap {
padding: 0 0.2rem;
display: flex;
flex-wrap: wrap;
.menu-item {
width: 0.8rem;
height: 0.8rem;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
font-size: 0.14rem;
color: #303133;
background: #f5f5f5;
cursor: pointer;
margin: 0 0.1rem 0.1rem 0;
&:nth-child(3n + 3) {
margin-right: 0;
}
view {
line-height: 1;
}
.iconfont {
font-size: 0.23rem;
margin-bottom: 0.1rem;
}
&.active {
background-color: rgba($color: $primary-color, $alpha: 0.2);
color: $primary-color;
}
}
}
/deep/ .uni-popup {
z-index: 999;
}
.dropdown-menu {
padding: 0rem 0;
margin-top: 0.15rem;
background-color: #fff;
border: 0.01rem solid #ebeef5;
border-radius: 0.04rem;
box-shadow: 0 0.01rem 0.12rem 0 rgba(0, 0, 0, 0.1);
position: relative;
width: 3rem;
.arrow {
position: absolute;
top: -0.1rem;
left: 0.08rem;
width: 0;
height: 0;
border-left: 0.1rem solid transparent;
border-right: 0.1rem solid transparent;
border-bottom: 0.1rem solid #fff;
}
.menu-item {
width: calc(100% - 0.2rem);
height: 0.57rem;
display: flex;
align-items: center;
justify-content: space-between;
margin: 0 0.1rem;
padding: 0.05rem 0.05rem;
text-align: center;
cursor: pointer;
color: #303133;
box-sizing: border-box;
border-bottom: 0.01rem solid #e6e6e6;
&:hover {
color: $primary-color;
}
.iconfont {
color: #999;
}
&:nth-child(3) {
border: 0;
}
&.logout {
margin: 0;
background-color: #eff0f4;
padding: 0.05rem 0.15rem;
width: 100%;
}
}
}
.pop-box {
background: #ffffff;
width: 6rem;
height: 4rem;
.pop-header {
padding: 0 0.15rem 0 0.2rem;
height: 0.5rem;
line-height: 0.5rem;
border-bottom: 0.01rem solid #f0f0f0;
font-size: 0.14rem;
color: #333;
overflow: hidden;
border-radius: 0.02rem 0.2rem 0 0;
box-sizing: border-box;
display: flex;
justify-content: space-between;
.pop-header-text {
}
.pop-header-close {
cursor: pointer;
i {
font-size: 0.18rem;
}
}
}
.pop-content {
height: calc(100% - 1.05rem);
overflow-y: scroll;
padding: 0.2rem;
box-sizing: border-box;
}
.pop-bottom {
padding: 0.1rem;
height: 0.65rem;
border-top: 0.01rem solid #eee;
button {
width: 1rem;
}
}
}
// 选择门店
.store-select {
.content-lists {
width: calc(100% - 0.2rem);
padding-bottom: 0.2rem;
.content-items {
cursor: pointer;
border-width: 0.01rem;
border-color: #cccccc;
border-style: solid;
padding: 0.15rem;
border-radius: 0.03rem;
margin-bottom: 0.1rem;
display: flex;
.item-info {
margin-left: 0.1rem;
.item-name {
font-size: 0.16rem;
font-weight: 600;
}
.item-phone {
margin-top: 0.08rem;
color: #999;
i {
margin-right: 0.05rem;
font-size: 0.14rem;
}
}
.item-addr {
margin-top: 0.03rem;
color: #999;
i {
font-size: 0.14rem;
margin-right: 0.05rem;
}
}
}
.item-img {
width: 0.7rem;
height: 0.7rem;
image {
width: 100%;
height: 100%;
}
}
&.active {
border-color: $primary-color;
}
}
}
}
.password-popup {
background-color: #fff;
width: 4.5rem;
.head {
padding: 0 0.2rem;
height: 0.5rem;
line-height: 0.5rem;
margin-bottom: 0.1rem;
}
.body {
padding: 0 0.1rem 0.2rem 0.3rem;
}
}
.logout-popup {
width: 3rem;
min-height: 1.5rem;
border-radius: 0.06rem;
background: #ffffff;
padding: 0.4rem 0.15rem 0;
box-sizing: border-box;
.title {
font-size: 0.16rem;
text-align: center;
}
.btn {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-top: 0.3rem;
.btn {
width: 36%;
height: auto;
padding: 0 0.15rem;
margin: 0;
height: 0.35rem;
}
.btn:last-child {
margin-left: 0.25rem;
}
}
}
</style>