|
|
@@ -0,0 +1,193 @@
|
|
|
+<template>
|
|
|
+ <div class="panel-wrap">
|
|
|
+ <van-empty v-if="appointList.length == 0 && finished" mode="list" description="暂无正在上机" />
|
|
|
+ <van-list v-else v-model:loading="listloading" :finished="finished" finished-text="没有更多了" @load="onLoad">
|
|
|
+ <div class="inst-item mb20" v-for="v in appointList" :key="v.id" @click="toDetail(v)">
|
|
|
+ <div class="flex flex-between mb20"><span class="fontSize14 primary-color bold">{{ v.instName }}</span></div>
|
|
|
+ <div class="flex mb20"><div class="equ-tit"><span class="fontSize14 bold">上机人:</span></div><div><span class="fontSize14">{{ v.userName }}</span></div></div>
|
|
|
+ <div class="flex mb20"><div class="equ-tit"><span class="fontSize14 bold">设备型号:</span></div><div><span class="fontSize14">{{ v.instNameEn }}</span></div></div>
|
|
|
+ <div class="flex mb20" v-if="v.projectName"><div class="equ-tit"><span class="fontSize14 bold">课题组:</span></div><div><span class="fontSize14">{{ v.projectName }}</span></div></div>
|
|
|
+ <div class="flex mb20"><div class="equ-tit"><span class="fontSize14 bold">所在位置:</span></div><div><span class="fontSize14">{{ v.placeAddress + '(' + (v.laboratoryName || '') + ')' }}</span></div></div>
|
|
|
+ <div class="flex"><div class="equ-tit"><span class="fontSize14 bold">开始时间:</span></div><div><span class="fontSize14">{{ v.startTime }}</span></div></div>
|
|
|
+ <div class="flex mt20">
|
|
|
+ <div class="off-btn-group">
|
|
|
+ <van-button style="width:90px;height:30px;margin:0;font-size:14px" type="danger" size="small" v-auth="'h5-admin-normal-off'" @click.native.stop="handleIsGetOff(v)">正常下机</van-button>
|
|
|
+ <span class="off-hint">会关闭蓝牙终端</span>
|
|
|
+ </div>
|
|
|
+ <div class="off-btn-group">
|
|
|
+ <van-button style="width:90px;height:30px;margin:0;font-size:14px" type="danger" size="small" v-auth="'h5-admin-force-off'" @click.native.stop="handleAdminForceOff(v)">强制下机</van-button>
|
|
|
+ <span class="off-hint">不关闭蓝牙终端</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </van-list>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { useUseAppointApi } from '/@/api/instr/useAppoint'
|
|
|
+const useAppointApi = useUseAppointApi()
|
|
|
+import instAppointApi from '/@/api/instr/instAppoint'
|
|
|
+import { useInstrApi } from '/@/api/instr'
|
|
|
+const instApi = useInstrApi()
|
|
|
+import { useUserInfo } from '/@/stores/userInfo'
|
|
|
+import { scanCodeWxUrl } from '/@/constants/pageConstants'
|
|
|
+import to from 'await-to-js'
|
|
|
+import { showConfirmDialog, showNotify } from 'vant'
|
|
|
+
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ appointList: [],
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ listloading: false,
|
|
|
+ finished: false,
|
|
|
+ curAppointInfo: {},
|
|
|
+ loading: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.pageNum = 1
|
|
|
+ this.fetchList()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ onLoad() { this.pageNum++; this.fetchList() },
|
|
|
+ async fetchList() {
|
|
|
+ this.listloading = true
|
|
|
+ const [err, res] = await to(useAppointApi.adminGetAppointList({ pageNum: this.pageNum, pageSize: this.pageSize, appointStatus: ['50'] }))
|
|
|
+ this.listloading = false
|
|
|
+ if (err) return
|
|
|
+ if (res?.code === 200) {
|
|
|
+ this.appointList = this.pageNum === 1 ? [...(res.data?.list || [])] : [...this.appointList, ...(res.data?.list || [])]
|
|
|
+ if (this.pageNum * this.pageSize >= (res.data?.total || 0)) this.finished = true
|
|
|
+ }
|
|
|
+ },
|
|
|
+ toDetail(v) { this.$router.push(`/onlineInfo?appointId=${v.id}`) },
|
|
|
+
|
|
|
+ calcTimeDiff(date) {
|
|
|
+ var new_date = new Date()
|
|
|
+ var old_date = new Date(date)
|
|
|
+ var difftime = new_date - old_date
|
|
|
+ return Math.round(difftime / 60000)
|
|
|
+ },
|
|
|
+ getShortWraningTime(time, unit) {
|
|
|
+ if (unit == 'hour') return time * 60
|
|
|
+ else if (unit == 'minute') return time
|
|
|
+ },
|
|
|
+ async handleIsGetOff(row) {
|
|
|
+ const [err, res] = await to(instApi.getSettingDetail({ instId: row.instId, code: 'InstCfgUse' }))
|
|
|
+ if (err) return
|
|
|
+ const useTime = this.calcTimeDiff(row.usedStartTime)
|
|
|
+ if (res?.data?.config.shortWarningEnable) {
|
|
|
+ const shortWraningTime = this.getShortWraningTime(res?.data?.config.shortWarning, res?.data?.config.shortWarningUnit)
|
|
|
+ if (useTime > shortWraningTime) {
|
|
|
+ if (row.controlMode === '30') {
|
|
|
+ this.handleBluetoothOffLine()
|
|
|
+ } else {
|
|
|
+ this.curAppointInfo = row
|
|
|
+ showConfirmDialog({ title: '提示', message: `本次上机时长共计${useTime}分钟,确定要下机吗?` })
|
|
|
+ .then(() => { this.getOff() })
|
|
|
+ .catch(() => {})
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (row.controlMode === '30') {
|
|
|
+ this.handleBluetoothOffLine()
|
|
|
+ } else {
|
|
|
+ this.curAppointInfo = row
|
|
|
+ showConfirmDialog({ title: '提示', message: `本次上机时长共计${useTime}分钟,不足${shortWraningTime}分钟,确定要下机吗?` })
|
|
|
+ .then(() => { this.getOff() })
|
|
|
+ .catch(() => {})
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (row.controlMode === '30') {
|
|
|
+ this.handleBluetoothOffLine()
|
|
|
+ } else {
|
|
|
+ this.curAppointInfo = row
|
|
|
+ showConfirmDialog({ title: '提示', message: `本次上机时长共计${useTime}分钟,确定要下机吗?` })
|
|
|
+ .then(() => { this.getOff() })
|
|
|
+ .catch(() => {})
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async handleBluetoothOffLine() {
|
|
|
+ const res = await useUserInfo().scanCode()
|
|
|
+ this.handleDeCode(res, this.handleBluetoothDeCode)
|
|
|
+ },
|
|
|
+ async handleDeCode(code, func) {
|
|
|
+ if (this.loading) return
|
|
|
+ this.loading = true
|
|
|
+ const params = { content: code }
|
|
|
+ const [err, res] = await to(instApi.decode({ ...params }))
|
|
|
+ if (err) {
|
|
|
+ this.loading = false
|
|
|
+ showNotify({ type: 'danger', message: '解码失败,请重试' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (res?.code == 200 && res?.data?.content) {
|
|
|
+ func(res.data.content)
|
|
|
+ } else {
|
|
|
+ this.loading = false
|
|
|
+ showNotify({ type: 'danger', message: res?.message || '解码失败' })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async handleBluetoothDeCode(content) {
|
|
|
+ if (content.includes('id')) {
|
|
|
+ const terminal = JSON.parse(content)?.terminal
|
|
|
+ const url = scanCodeWxUrl(terminal, 'EndRun')
|
|
|
+ window.location.href = url
|
|
|
+ } else {
|
|
|
+ const url = scanCodeWxUrl(content, 'EndRun')
|
|
|
+ window.location.href = url
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async getOff() {
|
|
|
+ const params = { appointId: this.curAppointInfo.id }
|
|
|
+ const [err, res] = await to(instAppointApi.getOff({ ...params }))
|
|
|
+ if (err) return
|
|
|
+ if (res.code == 200) {
|
|
|
+ this.pageNum = 1
|
|
|
+ this.appointList = []
|
|
|
+ this.finished = false
|
|
|
+ this.fetchList()
|
|
|
+ showNotify({ type: 'success', message: '正常下机成功' })
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ async handleAdminForceOff(row) {
|
|
|
+ showConfirmDialog({
|
|
|
+ title: '提示',
|
|
|
+ message: `确认强制下机【${row.userName}】的【${row.instName}】吗?此操作仅更改状态,不会关闭仪器终端。`
|
|
|
+ }).then(async () => {
|
|
|
+ const [err, res] = await to(useAppointApi.adminForceOff({ id: row.id }))
|
|
|
+ if (err) return
|
|
|
+ if (res.code == 200) {
|
|
|
+ this.pageNum = 1
|
|
|
+ this.appointList = []
|
|
|
+ this.finished = false
|
|
|
+ this.fetchList()
|
|
|
+ showNotify({ type: 'success', message: '强制下机成功' })
|
|
|
+ }
|
|
|
+ }).catch(() => {})
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+* { box-sizing: border-box; }
|
|
|
+.panel-wrap { height: 100%; }
|
|
|
+.inst-item {
|
|
|
+ border-radius: 10px; padding: 15px; box-shadow: -2px 0px 9px rgba(0,0,0,0.12); margin-bottom: 20px; background-color: #fff;
|
|
|
+ .equ-tit { width: 74px; }
|
|
|
+}
|
|
|
+.primary-color { color: #1989fa; }
|
|
|
+.bold { font-weight: bold; }
|
|
|
+.fontSize14 { font-size: 14px; }
|
|
|
+.flex { display: flex; }
|
|
|
+.flex-between { justify-content: space-between; }
|
|
|
+.mb20 { margin-bottom: 20px; }
|
|
|
+.mt20 { margin-top: 20px; }
|
|
|
+.off-btn-group { display: flex; flex-direction: column; align-items: center; margin-right: 10px; }
|
|
|
+.off-hint { font-size: 10px; color: #ee0a24; margin-top: 4px; }
|
|
|
+</style>
|