180 lines
4.2 KiB
Vue
180 lines
4.2 KiB
Vue
<script setup>
|
||
import { ref } from "vue";
|
||
import { onLoad } from "@dcloudio/uni-app";
|
||
import Signin from "@/components/Signin.vue";
|
||
import SButton from "@/components/SButton.vue";
|
||
import DeviceChargingDialog from "@/components/DeviceChargingDialog.vue";
|
||
import { tempBindOrgAPI } from "@/apis";
|
||
|
||
const scene = ref("");
|
||
const status = ref("idle");
|
||
const errorMessage = ref("");
|
||
const showSignin = ref(false);
|
||
const binding = ref(false);
|
||
|
||
const getToken = () => {
|
||
try {
|
||
const env = uni.getAccountInfoSync().miniProgram.envVersion;
|
||
return uni.getStorageSync(`${env}_token`);
|
||
} catch (error) {
|
||
return "";
|
||
}
|
||
};
|
||
|
||
const openSignin = () => {
|
||
showSignin.value = true;
|
||
};
|
||
|
||
const closeSignin = () => {
|
||
showSignin.value = false;
|
||
};
|
||
|
||
const bindOrg = async () => {
|
||
if (binding.value || !scene.value) return;
|
||
|
||
if (!getToken()) {
|
||
status.value = "login";
|
||
return;
|
||
}
|
||
|
||
binding.value = true;
|
||
status.value = "binding";
|
||
errorMessage.value = "";
|
||
|
||
try {
|
||
await tempBindOrgAPI(scene.value);
|
||
status.value = "success";
|
||
} catch (error) {
|
||
if (error?.type === "AUTH_INVALID") {
|
||
status.value = "login";
|
||
errorMessage.value = "登录已失效,请重新登录后完成绑定。";
|
||
} else {
|
||
status.value = "failed";
|
||
errorMessage.value = error?.message || "网络异常,请稍后重试。";
|
||
}
|
||
} finally {
|
||
binding.value = false;
|
||
}
|
||
};
|
||
|
||
const handleLoginSuccess = async () => {
|
||
await bindOrg();
|
||
};
|
||
|
||
onLoad((options) => {
|
||
try {
|
||
const value = decodeURIComponent(String(options?.scene || ""));
|
||
if (!/^org_\d+$/.test(value)) {
|
||
status.value = "invalid";
|
||
return;
|
||
}
|
||
|
||
scene.value = value;
|
||
if (getToken()) {
|
||
void bindOrg();
|
||
} else {
|
||
status.value = "login";
|
||
}
|
||
} catch (error) {
|
||
status.value = "invalid";
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<view class="page">
|
||
<view class="content">
|
||
<text class="title">机构设备绑定</text>
|
||
|
||
<view v-if="status === 'idle' || status === 'binding'" class="state">
|
||
<text class="state-title">正在绑定</text>
|
||
<text class="description">正在绑定机构设备,请稍候……</text>
|
||
</view>
|
||
|
||
<view v-else-if="status === 'login'" class="state">
|
||
<text class="state-title">请先登录</text>
|
||
<text class="description">
|
||
{{
|
||
errorMessage ||
|
||
"登录后即可绑定当前机构设备。关闭登录窗口后,也可以再次点击下方按钮继续。"
|
||
}}
|
||
</text>
|
||
<SButton width="560rpx" :rounded="20" :onClick="openSignin">
|
||
<text>立即登录</text>
|
||
</SButton>
|
||
</view>
|
||
|
||
<view v-else-if="status === 'success'" class="state">
|
||
<text class="state-title">绑定成功</text>
|
||
<text class="description">
|
||
您的账号已成功绑定机构设备,请返回 iPad 继续操作。
|
||
</text>
|
||
</view>
|
||
|
||
<view v-else-if="status === 'failed'" class="state">
|
||
<text class="state-title">绑定失败</text>
|
||
<text class="description">{{ errorMessage }}</text>
|
||
<SButton width="560rpx" :rounded="20" :onClick="bindOrg">
|
||
<text>重新绑定</text>
|
||
</SButton>
|
||
</view>
|
||
|
||
<view v-else class="state">
|
||
<text class="state-title">二维码无效</text>
|
||
<text class="description">请重新扫描机构设备上的小程序码。</text>
|
||
</view>
|
||
</view>
|
||
|
||
<Signin
|
||
:show="showSignin"
|
||
:onClose="closeSignin"
|
||
:onSuccess="handleLoginSuccess"
|
||
/>
|
||
<DeviceChargingDialog />
|
||
</view>
|
||
</template>
|
||
|
||
<style scoped lang="scss">
|
||
.page {
|
||
box-sizing: border-box;
|
||
width: 100%;
|
||
min-height: 100vh;
|
||
padding: calc(var(--status-bar-height) + 120rpx) 48rpx 80rpx;
|
||
background-color: #000;
|
||
color: #fff;
|
||
}
|
||
|
||
.content {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.title {
|
||
font-size: 44rpx;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.state {
|
||
width: 100%;
|
||
margin-top: 120rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.state-title {
|
||
font-size: 36rpx;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.description {
|
||
max-width: 600rpx;
|
||
margin: 32rpx 0 64rpx;
|
||
color: #b8b8b8;
|
||
font-size: 28rpx;
|
||
line-height: 1.8;
|
||
text-align: center;
|
||
}
|
||
</style>
|