2025-08-07 17:44:13 +08:00

533 lines
13 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">
<view class="equipment">
<view class="header">
<text>我的设备</text>
<image
v-if="equipmentList.length > 1"
:src="arrow"
mode=""
:class="{ arrow: true, rotate: showAllEquipment }"
@click="handleShowAll"
>
</image>
</view>
<view v-if="!showAllEquipment" class="single">
<view class="left">
<image
:src="
showEquipment?.curDeviceUserAvatar
? showEquipment?.curDeviceUserAvatar
: defaultAvatar
"
mode=""
class="avatar"
></image>
<view class="info">
<view class="info_name">
<template v-if="!equipEmpty">
{{
showEquipment?.curDeviceUserName ? showEquipment?.curDeviceUserName : '未登录账号'
}}
</template>
<template v-else> 未绑定设备 </template>
</view>
<view class="info_serial">
<template v-if="!equipEmpty"> 序列号{{ showEquipment?.simSerialNumber }} </template>
<template v-else> 请先绑定设备 </template>
</view>
</view>
</view>
</view>
<template v-else>
<view v-for="(i, idx) in equipmentList" :key="idx" class="single" @click="handleChecked(i)">
<view class="left">
<image
:src="i?.curDeviceUserAvatar ? i?.curDeviceUserAvatar : defaultAvatar"
mode=""
class="avatar"
></image>
<view class="info">
<view class="info_name">
{{ i?.curDeviceUserName ? i?.curDeviceUserName : '未登录账号' }}
</view>
<view class="info_serial"> 序列号{{ i?.simSerialNumber }} </view>
</view>
</view>
<view class="right">
<image
:src="i.simSerialNumber === showEquipment.simSerialNumber ? checked : unchecked"
mode=""
class="check_icon"
>
</image>
</view>
</view>
</template>
</view>
<!-- 设备应用 -->
<view class="equipment_application">
<view class="navigate">
<text
v-for="(i, idx) in navList"
:key="idx"
:class="{ navigate_item: true, active: activeNav.type === i.type }"
@click="switchNav(i)"
>{{ i.title }}</text
>
</view>
<view class="application">
<view v-if="appEmpty" class="empty_box">
<Empty
:content="
showEquipment.simSerialNumber ? '暂无应用数据~' : '您还没有绑定设备,暂无应用数据~'
"
/>
</view>
<template v-else>
<view v-for="(i, idx) in equipAppList" :key="idx" class="application_item">
<view class="left">
<image
:src="i.iconPath ? i.iconPath : `${OSS_URL}/urm/placeholder_apply_icon.png`"
mode=""
class="avatar"
></image>
<view class="info">
<view class="info_name"> {{ i.appName }} </view>
<!-- <view class="info_time"> 今日使用1时38分 </view> -->
</view>
</view>
<!-- <view class="right">
<text class="control" @click="handleControl">管控</text>
<text class="delete" @click="handleDelete">卸载</text>
</view> -->
</view>
</template>
</view>
</view>
<CustomPopup
v-model="showCustomPopup"
titleText="温馨提示"
@handleConfirmBtn="handleConfirmPopup"
>
<view class="popup_box"> 确认卸载该应用 </view>
</CustomPopup>
<wd-popup
v-model="methodPopup"
safe-area-inset-bottom
position="bottom"
custom-style="border-radius: 20px 20px 0 0;padding-bottom: 30px;"
@click-modal="() => {}"
>
<view class="bottom_popup">
<view class="header_title"> 选择使用方式 </view>
<view class="method_list">
<view v-for="(i, idx) in methodList" :key="idx" class="item">
{{ i.name }}
</view>
</view>
<view class="footer">
<button class="confirm_btn" @click="handleConfirmControl">确定</button>
</view>
</view>
</wd-popup>
</view>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { studentHeadImage } from '@/hooks/useImage'
import { getParentBindDeviceApi, parentDeviceCurrentLoginApi, queryAppRecordApi } from '@/api'
import CustomPopup from '@/components/CustomPopup/index.vue'
import Empty from '@/components/Empty/index.vue'
import { useUserStore, bindApplyStore } from '@/store'
import { storeToRefs } from 'pinia'
import db from '@/utils/db'
import { useBadgeStore } from '@/store/badge'
const { userInfo } = storeToRefs(useUserStore())
const { refreshBadge } = useBadgeStore()
const OSS_URL = import.meta.env.VITE_OSS_HOST
const defaultAvatar = `${OSS_URL}/urm/default_avatar.png`
const arrow = `${OSS_URL}/iconfont/down_arrow.png`
const checked = `${OSS_URL}/iconfont/checked.png`
const unchecked = `${OSS_URL}/iconfont/unchecked.png`
const showAllEquipment = ref(false)
const showCustomPopup = ref(false)
const methodPopup = ref(false)
const methodList = ref([
{
name: '允许使用',
},
{
name: '限制使用',
},
{
name: '禁止使用',
},
])
const showEquipment = ref<any>({})
const equipmentList = ref([])
const equipAppList = ref([]) // 设备应用
const equipEmpty = ref(false) // 无绑定设备
const appEmpty = ref(false)
const activeNav = ref({
title: '允许使用',
type: 1,
})
const navList = reactive([
{
title: '允许使用',
type: 1,
},
// {
// title: '限制使用',
// type: 2,
// },
// {
// title: '禁止使用',
// type: 3,
// },
])
function handleShowAll() {
showAllEquipment.value = !showAllEquipment.value
}
function handleChecked(i) {
showEquipment.value = i
equipmentList.value = equipmentList.value.map(item => {
if (item.id === i.id) {
return {
...item,
checked: true,
}
} else {
return {
...item,
checked: false,
}
}
})
fetchAppRecord()
}
function switchNav(i) {
activeNav.value = i
}
// 管控
function handleControl() {
methodPopup.value = true
}
function handleConfirmControl() {
methodPopup.value = false
setTimeout(() => {
methodPopup.value = false
}, 200)
}
// 卸载
function handleDelete() {
showCustomPopup.value = true
}
function handleConfirmPopup() {
showCustomPopup.value = false
}
// 我的设备
async function getParentBindDevice() {
equipmentList.value = []
try {
uni.showLoading({
title: '加载中...',
})
const data = await getParentBindDeviceApi({ parentId: userInfo.value.id, size: -1 })
equipEmpty.value = data.rows.length === 0
for (let i in data.rows) {
const _r = await deviceCurrentLogin(data.rows[i].id)
equipmentList.value.push({
...data.rows[i],
curDeviceUserName: _r.curDeviceUserName,
curDeviceUserAvatar: _r.curDeviceUserAvatar,
})
}
showEquipment.value = data.rows?.length ? equipmentList.value[0] : {}
uni.hideLoading()
} catch (err) {
uni.hideLoading()
}
}
// 当前设备登录账号
async function deviceCurrentLogin(id: string) {
const data = await parentDeviceCurrentLoginApi(id)
return data
}
// 设备应用
async function fetchAppRecord() {
// 序列号不存在
if (!showEquipment.value.simSerialNumber) return
try {
uni.showLoading({
title: '加载中...',
})
const data = await queryAppRecordApi(showEquipment.value.simSerialNumber)
const res = data.filter(i => i.systemApp === 0)
equipAppList.value = res
appEmpty.value = res.length === 0
uni.hideLoading()
} catch (err) {
uni.hideLoading()
}
}
onShow(() => {
refreshBadge()
})
onMounted(async () => {
await getParentBindDevice()
fetchAppRecord()
})
</script>
<style lang="scss" scoped>
.page {
padding: 30rpx 30rpx 206rpx 30rpx;
.equipment {
padding: 0 30rpx;
border-radius: 20rpx;
background-color: #fff;
.header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 26rpx 0;
font-size: 32rpx;
font-weight: 500;
line-height: 48rpx;
.arrow {
width: 36rpx;
height: 36rpx;
}
.rotate {
transform: rotate(180deg);
}
}
.single {
padding: 30rpx 0;
border-top: 1rpx solid rgba(238, 238, 238, 1);
display: flex;
justify-content: space-between;
align-items: center;
.left {
display: flex;
align-items: center;
.avatar {
width: 100rpx;
height: 100rpx;
margin-right: 20rpx;
}
.info {
&_name {
margin-bottom: 10rpx;
line-height: 45rpx;
font-size: 30rpx;
font-weight: 500;
color: rgba(51, 51, 51, 1);
max-width: 210rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
&_serial {
line-height: 42rpx;
font-size: 28rpx;
color: rgba(169, 170, 181, 1);
}
}
}
.right {
.check_icon {
width: 30rpx;
height: 30rpx;
}
}
}
}
.equipment_application {
margin-top: 40rpx;
.navigate {
display: flex;
&_item {
margin-right: 40rpx;
color: rgba(169, 170, 181, 1);
font-size: 28rpx;
line-height: 48rpx;
}
.active {
position: relative;
font-weight: 500;
font-size: 32rpx;
color: rgba(51, 51, 51, 1);
&::after {
position: absolute;
bottom: -10rpx;
left: 50%;
transform: translateX(-50%);
content: '';
display: block;
width: 30rpx;
height: 8rpx;
background-color: rgba(97, 93, 255, 1);
border-radius: 8rpx;
}
}
}
.application {
padding: 0 30rpx;
margin-top: 10rpx;
background-color: #fff;
border-radius: 20rpx;
.empty_box {
height: 698rpx;
height: #fff;
.empty {
padding-top: 40rpx;
margin-top: 0 !important;
justify-content: flex-start;
}
}
&_item {
padding: 30rpx 0;
border-bottom: 1rpx solid rgba(238, 238, 238, 1);
display: flex;
justify-content: space-between;
align-items: center;
&:last-child {
border-bottom: none;
}
.left {
display: flex;
align-items: center;
.avatar {
width: 80rpx;
height: 80rpx;
margin-right: 20rpx;
border-radius: 25rpx;
}
.info {
&_name {
margin-bottom: 10rpx;
line-height: 45rpx;
font-size: 30rpx;
font-weight: 500;
color: rgba(51, 51, 51, 1);
// max-width: 210rpx;
max-width: 530rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
&_time {
line-height: 36rpx;
font-size: 24rpx;
color: rgba(169, 170, 181, 1);
}
}
}
.right {
font-size: 24rpx;
line-height: 36rpx;
background-color: rgba(235, 235, 255, 1);
border-radius: 10rpx;
.control {
display: inline-block;
padding: 6rpx 20rpx;
color: rgba(97, 93, 255, 1);
border-right: 1rpx solid rgba(223, 223, 242, 1);
}
.delete {
display: inline-block;
padding: 6rpx 20rpx;
color: rgba(156, 153, 255, 1);
}
}
}
}
}
.popup_box {
margin: 50rpx 0;
}
.bottom_popup {
background-color: #fff;
border-radius: 20rpx 20rpx 0 0;
overflow: hidden;
.header_title {
margin: 30rpx 0 0 30rpx;
color: rgba(51, 51, 51, 1);
font-size: 32rpx;
font-weight: 500;
text-align: left;
}
.method_list {
text-align: center;
padding: 0 54rpx;
.item {
padding: 30rpx 0;
border-bottom: 1rpx solid rgba(235, 235, 235, 1);
font-weight: 400;
height: 45rpx;
color: rgba(169, 170, 181, 1);
}
}
.footer {
display: flex;
justify-content: center;
.confirm_btn {
margin: 16rpx auto 20rpx auto;
height: 90rpx;
width: 690rpx;
color: #fff;
background-color: #615dff;
}
}
}
}
</style>