278 lines
6.0 KiB
Vue
278 lines
6.0 KiB
Vue
<template>
|
|
<view>
|
|
<!-- #ifdef MP-WEIXIN -->
|
|
<page-container
|
|
v-if="mode === 'switch'"
|
|
:show="visible"
|
|
:overlay="false"
|
|
@leave="handlePageLeave"
|
|
/>
|
|
<!-- #endif -->
|
|
<u-popup
|
|
v-model="visible"
|
|
mode="bottom"
|
|
length="80%"
|
|
border-radius="24"
|
|
z-index="10090"
|
|
:closeable="true"
|
|
:mask-close-able="true"
|
|
:safe-area-inset-bottom="true"
|
|
@close="handleCancel"
|
|
>
|
|
<view class="sheet-inner white">
|
|
<view class="sheet-title">{{ mode === 'switch' ? '切换账号' : '选择登录账号' }}</view>
|
|
<scroll-view scroll-y class="account-scroll">
|
|
<view
|
|
v-for="(item, index) in accounts"
|
|
:key="item._rowKey"
|
|
class="account-item"
|
|
:class="{ active: isSelected(item) }"
|
|
hover-class="account-item-hover"
|
|
@tap.stop="selectAccount(item)"
|
|
>
|
|
<view class="name">{{ item.nick_name }}</view>
|
|
<view class="meta">
|
|
{{ item.role_name }}<text v-if="item.store_name"> · {{ item.store_name }}</text><text v-if="item.login_account"> · {{ item.login_account }}</text>
|
|
</view>
|
|
<view v-if="item.is_current" class="current-tag">当前</view>
|
|
</view>
|
|
</scroll-view>
|
|
|
|
<view class="actions">
|
|
<button class="btn cancel" @tap.stop="handleCancel">取消</button>
|
|
<button class="btn confirm" :loading="loading" @tap.stop="handleConfirm">确认</button>
|
|
</view>
|
|
</view>
|
|
</u-popup>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import { switchDoctorWxAccount, getDoctorWxSiblingAccounts } from '@/api/doctorAuth.js';
|
|
import { buildDoctorWxAuthExtra } from '@/utils/doctorWxAuth.js';
|
|
|
|
export default {
|
|
name: 'AccountSwitchPanel',
|
|
props: {
|
|
mode: {
|
|
type: String,
|
|
default: 'login',
|
|
},
|
|
phone: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
},
|
|
data() {
|
|
return {
|
|
visible: false,
|
|
accounts: [],
|
|
selected: null,
|
|
loading: false,
|
|
defaultAccountId: null,
|
|
defaultAccountType: null,
|
|
};
|
|
},
|
|
methods: {
|
|
normalizeAccounts(accounts) {
|
|
return (accounts || []).map((item, index) => ({
|
|
...item,
|
|
_rowKey: `${item.account_type}_${item.id}_${item.login_persona || 'admin'}_${index}`,
|
|
}));
|
|
},
|
|
resolveDefaultSelection(accounts, options = {}) {
|
|
const list = accounts || [];
|
|
if (!list.length) {
|
|
return null;
|
|
}
|
|
|
|
if (this.mode === 'switch') {
|
|
return list.find((item) => item.is_current) || list[0];
|
|
}
|
|
|
|
const defaultId = options.defaultAccountId ?? this.defaultAccountId;
|
|
const defaultType = options.defaultAccountType ?? this.defaultAccountType;
|
|
if (defaultId != null && defaultType) {
|
|
const matched = list.find(
|
|
(item) => item.account_type === defaultType && Number(item.id) === Number(defaultId)
|
|
);
|
|
if (matched) {
|
|
return matched;
|
|
}
|
|
}
|
|
|
|
return list.find((item) => item.password_matched) || list[0];
|
|
},
|
|
showPanel() {
|
|
this.$nextTick(() => {
|
|
this.visible = true;
|
|
});
|
|
},
|
|
open(accounts = null, options = {}) {
|
|
this.defaultAccountId = options.defaultAccountId ?? null;
|
|
this.defaultAccountType = options.defaultAccountType ?? null;
|
|
|
|
if (Array.isArray(accounts)) {
|
|
this.accounts = this.normalizeAccounts(accounts);
|
|
if (!this.accounts.length) {
|
|
uni.showToast({ title: '暂无可选账号', icon: 'none' });
|
|
return Promise.resolve();
|
|
}
|
|
this.selected = this.resolveDefaultSelection(this.accounts, options);
|
|
this.showPanel();
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return getDoctorWxSiblingAccounts().then((wrap) => {
|
|
if (!wrap || !wrap.ok) {
|
|
return Promise.reject(new Error('获取账号列表失败'));
|
|
}
|
|
this.accounts = this.normalizeAccounts(wrap.data || []);
|
|
this.selected = this.resolveDefaultSelection(this.accounts, options);
|
|
this.showPanel();
|
|
});
|
|
},
|
|
close() {
|
|
this.visible = false;
|
|
},
|
|
handlePageLeave() {
|
|
this.close();
|
|
},
|
|
isSelected(item) {
|
|
return this.selected && this.selected._rowKey === item._rowKey;
|
|
},
|
|
selectAccount(item) {
|
|
this.selected = item;
|
|
},
|
|
handleCancel() {
|
|
this.close();
|
|
this.$emit('cancel');
|
|
},
|
|
handleConfirm() {
|
|
if (!this.selected) {
|
|
this.$toast('请选择账号');
|
|
return;
|
|
}
|
|
if (this.mode === 'switch') {
|
|
if (this.selected.is_current) {
|
|
this.$toast('已是当前账号');
|
|
return;
|
|
}
|
|
this.submitSwitch();
|
|
return;
|
|
}
|
|
this.$emit('confirm', this.selected);
|
|
this.close();
|
|
},
|
|
resolveSwitchError(wrap, err) {
|
|
return wrap?.res?.msg
|
|
|| wrap?.res?.message
|
|
|| err?.msg
|
|
|| err?.message
|
|
|| '切换失败';
|
|
},
|
|
submitSwitch() {
|
|
this.loading = true;
|
|
switchDoctorWxAccount(buildDoctorWxAuthExtra(this.selected)).then((wrap) => {
|
|
if (!wrap || !wrap.ok || !wrap.data || !wrap.data.token) {
|
|
return Promise.reject({
|
|
message: this.resolveSwitchError(wrap),
|
|
wrap,
|
|
});
|
|
}
|
|
this.$emit('switched', wrap.data);
|
|
this.close();
|
|
}).catch((err) => {
|
|
const message = this.resolveSwitchError(err?.wrap, err);
|
|
uni.showToast({
|
|
title: message,
|
|
icon: 'none',
|
|
duration: 2500,
|
|
});
|
|
}).finally(() => {
|
|
this.loading = false;
|
|
});
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.sheet-inner {
|
|
padding: 32rpx 32rpx calc(32rpx + env(safe-area-inset-bottom));
|
|
box-sizing: border-box;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: #fff;
|
|
}
|
|
|
|
.sheet-title {
|
|
font-size: 34rpx;
|
|
font-weight: 600;
|
|
margin-bottom: 24rpx;
|
|
flex-shrink: 0;
|
|
color: #222b2a;
|
|
}
|
|
|
|
.account-scroll {
|
|
flex: 1;
|
|
width: 100%;
|
|
min-height: 0;
|
|
}
|
|
|
|
.account-item {
|
|
position: relative;
|
|
padding: 24rpx;
|
|
border: 1px solid #e5e7eb;
|
|
border-radius: 16rpx;
|
|
margin-bottom: 16rpx;
|
|
}
|
|
|
|
.account-item.active {
|
|
border-color: #6acdbb;
|
|
background: #f0fbf8;
|
|
}
|
|
|
|
.account-item-hover {
|
|
opacity: 0.85;
|
|
}
|
|
|
|
.name {
|
|
font-size: 30rpx;
|
|
font-weight: 600;
|
|
padding-right: 80rpx;
|
|
color: #222b2a;
|
|
}
|
|
|
|
.meta {
|
|
margin-top: 8rpx;
|
|
font-size: 24rpx;
|
|
color: #6b7280;
|
|
}
|
|
|
|
.current-tag {
|
|
position: absolute;
|
|
right: 24rpx;
|
|
top: 24rpx;
|
|
font-size: 22rpx;
|
|
color: #6acdbb;
|
|
}
|
|
|
|
.actions {
|
|
display: flex;
|
|
gap: 16rpx;
|
|
margin-top: 24rpx;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.btn {
|
|
flex: 1;
|
|
}
|
|
|
|
.confirm {
|
|
background: #6acdbb;
|
|
color: #fff;
|
|
}
|
|
</style>
|