三端对接完成

This commit is contained in:
zwz 2026-06-18 14:38:02 +08:00
parent b22438134c
commit 482ec9a6f1
5 changed files with 190 additions and 180 deletions

View File

@ -236,3 +236,18 @@ export const getWindowStat = params => {
params
});
};
// ==================== 大屏展示接口 ====================
/**
* 大屏展示当前呼叫 + 等候队列
* @param {*} params { calledSize, waitingSize }
* @returns
*/
export const getDisplayScreen = params => {
return http.request({
url: '/api/blade-queuerecord/queueRecord/display-screen',
method: 'GET',
params
});
};

View File

@ -77,7 +77,7 @@
}
},
{
"path": "pages/screen/index",
"path": "pages/screen/screen",
"style": {
"navigationBarTitleText": "公告屏",
"enablePullDownRefresh": false,

View File

@ -28,11 +28,6 @@
</view>
</view>
<!-- 挂起提示条 -->
<view class="suspend-bar" v-if="serviceStatus === 2">
<text>窗口已挂起无法进行叫号操作</text>
</view>
<!-- 底部功能按钮区 -->
<view class="btn-group">
<view class="btn-item green" @click="handleCall" :class="{ disabled: callDisabled }">
@ -55,9 +50,14 @@
<image class="btn-icon" src="../../static/images/takeTicket/gq_icon.png" mode="aspectFit" />
<text>挂起</text>
</view>
<view class="btn-item green" @click="handleResume" v-if="serviceStatus === 2">
<image class="btn-icon" src="../../static/images/takeTicket/hj_icon.png" mode="aspectFit" />
<text>恢复</text>
</view>
<!-- 挂起遮罩层 -->
<view class="suspend-overlay" v-if="serviceStatus === 2">
<text class="suspend-tip">窗口已挂起无法进行叫号操作</text>
<view class="resume-btn" @click="handleResume">
<image class="resume-btn-icon" src="../../static/images/takeTicket/hj_icon.png" mode="aspectFit" />
<text class="resume-btn-text">恢复</text>
</view>
</view>
@ -78,27 +78,11 @@
</view>
</view>
</view>
<!-- 挂起原因弹窗 -->
<view class="transfer-mask" v-if="showSuspend" @click="showSuspend = false">
<view class="suspend-dialog" @click.stop>
<text class="dialog-title">请输入挂起原因</text>
<input class="suspend-input" v-model="suspendReason" placeholder="请输入挂起原因(选填)" />
<view class="suspend-btns">
<view class="dialog-cancel" @click="showSuspend = false">
<text>取消</text>
</view>
<view class="dialog-confirm" @click="confirmSuspend">
<text>确认挂起</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { getWindowWorkbench, callNext, recall, transferRecord, passRecord, suspendWindow, resumeWindow, getWindowList } from '@/api/ticket.js'
import { getWindowWorkbench, callNext, recall, transferRecord, passRecord, suspendWindow, resumeWindow, getWindowList, finishHandle } from '@/api/ticket.js'
export default {
name: 'CallWindow',
@ -121,10 +105,6 @@ export default {
showTransfer: false,
targetWindowList: [],
//
showSuspend: false,
suspendReason: '',
//
actionLock: false
}
@ -136,29 +116,14 @@ export default {
return this.currentRecord ? this.currentRecord.queueNo : '----'
},
//
statusText() {
if (!this.currentRecord) return ''
const map = { 1: '等待办理', 2: '已叫号', 3: '已过号', 4: '已完成', 5: '已取消', 7: '办理中' }
return map[this.currentRecord.status] || ''
},
//
statusTagClass() {
if (!this.currentRecord) return ''
if (this.currentRecord.status === 2) return 'tag-called'
if (this.currentRecord.status === 7) return 'tag-handling'
return ''
},
//
suspended() {
return this.serviceStatus === 2
},
//
// 0
callDisabled() {
return this.suspended || !!this.currentRecord || this.actionLock
return this.suspended || this.waitingCount === 0 || this.actionLock
},
// /
@ -252,10 +217,25 @@ export default {
})
},
//
//
async handleCall() {
if (this.callDisabled) return
this.actionLock = true
//
if (this.currentRecord) {
uni.showLoading({ title: '完成当前办理...', mask: true })
try {
await finishHandle({
recordId: this.currentRecord.id,
windowId: this.windowId
})
} catch (e) {
//
console.error('自动完成失败', e)
}
}
uni.showLoading({ title: '呼叫中...', mask: true })
try {
const res = await callNext({ windowId: this.windowId })
@ -380,21 +360,14 @@ export default {
})
},
// -
handleSuspend() {
this.suspendReason = ''
this.showSuspend = true
},
//
async confirmSuspend() {
this.showSuspend = false
// -
async handleSuspend() {
this.actionLock = true
uni.showLoading({ title: '挂起中...', mask: true })
try {
const res = await suspendWindow({
windowId: this.windowId,
reason: this.suspendReason || '临时离岗'
reason: '临时离岗'
})
if (res.success && res.data) {
this.serviceStatus = res.data.serviceStatus
@ -575,18 +548,26 @@ export default {
font-weight: bold;
}
/* 挂起提示条 */
.suspend-bar {
width: 100%;
background-color: #ff6633;
padding: 2vh 0;
text-align: center;
/* 挂起全屏遮罩 */
.suspend-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 998;
}
.suspend-bar text {
font-size: 2.5vw;
.suspend-tip {
font-size: 3.125vw;
color: #fff;
font-weight: bold;
margin-bottom: 4vh;
}
/* 底部按钮 */
@ -643,6 +624,33 @@ export default {
background-color: #ff6633;
}
.resume-btn {
width: 18vw;
height: 22.222vh;
border-radius: 1.667vw;
background-color: #28c958;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
}
.resume-btn:active {
opacity: 0.8;
}
.resume-btn-icon {
width: 3.646vw;
height: 3.646vw;
margin-bottom: 1.667vh;
}
.resume-btn-text {
font-size: 3.021vw;
color: #fff;
}
/* 按钮禁用态 */
.btn-item.disabled {
opacity: 0.4;
@ -674,15 +682,6 @@ export default {
flex-direction: column;
}
.suspend-dialog {
width: 45vw;
background: #fff;
border-radius: 2vw;
padding: 4vh 3vw;
display: flex;
flex-direction: column;
}
.dialog-title {
font-size: 3vw;
font-weight: bold;
@ -738,46 +737,11 @@ export default {
cursor: pointer;
}
/* 挂起弹窗 */
.suspend-input {
width: 100%;
height: 8vh;
border: 1px solid #ddd;
border-radius: 1vw;
padding: 0 2vw;
font-size: 2.2vw;
margin-bottom: 3vh;
}
.suspend-btns {
display: flex;
justify-content: space-between;
gap: 3vw;
}
.dialog-confirm {
flex: 1;
text-align: center;
padding: 2.5vh 0;
font-size: 2.5vw;
background: #ff6633;
color: #fff;
border-radius: 1.5vw;
cursor: pointer;
}
.dialog-confirm:active {
opacity: 0.8;
}
.dialog-cancel {
flex: 1;
text-align: center;
padding: 2.5vh 0;
padding: 2vh 0;
font-size: 2.5vw;
background: #eee;
color: #666;
border-radius: 1.5vw;
color: #999;
cursor: pointer;
}
</style>

View File

@ -31,7 +31,7 @@
</view>
<!-- 公告屏 -->
<view class="card" @click="goToPage('/pages/screen/index', '公告屏')">
<view class="card" @click="goToPage('/pages/screen/screen', '公告屏')">
<view class="card-icon-box screen-bg">
<text class="card-icon-text screen-text"></text>
</view>

View File

@ -2,7 +2,7 @@
<view class="screen-wrap">
<!-- 顶部标题栏 -->
<view class="top-header">
<text class="title-left">环江毛南族自治县政务服务中心</text>
<text class="title-left">{{ screenTitle }}</text>
<view class="title-right">
<text>{{ dateStr }}</text>
<text>{{ weekStr }} {{ timeStr }}</text>
@ -13,7 +13,7 @@
<text class="normal-text"></text>
<text class="yellow-text">{{ currCallNo }}</text>
<text class="normal-text"></text>
<text class="yellow-text">{{ currWinNo }}号窗口</text>
<text class="yellow-text">{{ currWinNo }}</text>
</view>
<!-- 左右双栏表格区域 -->
<view class="table-box">
@ -28,7 +28,7 @@
<text></text>
<text class="row-no">{{ item.no }}</text>
<text></text>
<text class="row-no">{{ item.win }}号窗口</text>
<text class="row-no">{{ item.win }}</text>
</view>
</view>
</view>
@ -46,88 +46,60 @@
</template>
<script>
import { getDisplayScreen } from '@/api/ticket.js'
export default {
name: 'CallScreen',
data() {
return {
//
screenTitle: '环江毛南族自治县政务服务中心',
//
dateStr: '',
weekStr: '',
timeStr: '',
timer: null, //
//
currCallNo: 'A010',
currWinNo: '2',
//
callList: [
{
no: 'A0009',
win: '1'
},
{
no: 'A0009',
win: '1'
},
{
no: 'A0009',
win: '1'
},
{
no: 'A0009',
win: '1'
},
{
no: 'A0009',
win: '1'
},
{
no: 'A0009',
win: '1'
},
{
no: 'A0009',
win: '1'
},
{
no: 'A0009',
win: '1'
}
],
//
waitList: [
['A0001', 'A0002', 'A0003'],
['A0004', 'A0005', 'A0006'],
['A0001', 'A0001', 'A0001'],
['A0001', 'A0001', 'A0001'],
['A0001', 'A0001', 'A0001'],
['A0001', 'A0001', 'A0001'],
['A0001', 'A0001', 'A0001'],
['A0001', 'A0001', 'A0001']
]
serverTimeOffset: 0, //
clockTimer: null, //
fetchTimer: null, //
//
currCallNo: '',
currWinNo: '',
//
callList: [],
// 3
waitList: []
}
},
onLoad() {
this.getNowTime() //
//
this.timer = setInterval(() => {
this.getNowTime()
}, 1000)
//
this.fetchDisplayData()
//
this.fetchTimer = setInterval(() => {
this.fetchDisplayData()
}, 5000)
},
onUnload() {
//
clearInterval(this.timer)
clearInterval(this.clockTimer)
clearInterval(this.fetchTimer)
},
methods: {
//
getNowTime() {
const now = new Date()
// serverTime
startClock() {
clearInterval(this.clockTimer)
this.tick()
this.clockTimer = setInterval(() => {
this.tick()
}, 1000)
},
//
tick() {
// + =
const now = this.serverTimeOffset ? new Date(Date.now() + this.serverTimeOffset) : new Date()
const year = now.getFullYear()
const month = this.addZero(now.getMonth() + 1)
const day = this.addZero(now.getDate())
const hour = this.addZero(now.getHours())
const minute = this.addZero(now.getMinutes())
// const second = this.addZero(now.getSeconds())
//
const weekArr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
const week = weekArr[now.getDay()]
@ -135,9 +107,66 @@ export default {
this.weekStr = week
this.timeStr = `${hour}:${minute}`
},
// 0
addZero(num) {
return num < 10 ? '0' + num : num
},
//
fetchDisplayData() {
getDisplayScreen({ calledSize: 8, waitingSize: 24 })
.then(res => {
const data = res.data
if (!data) return
// 1.
if (data.title) {
this.screenTitle = data.title
}
// 2.
if (data.serverTime && !this.serverTimeOffset) {
const serverTs = new Date(data.serverTime.replace(/-/g, '/')).getTime()
this.serverTimeOffset = serverTs - Date.now()
this.startClock()
}
// 3.
if (data.latestCall) {
this.currCallNo = data.latestCall.queueNo || ''
this.currWinNo = data.latestCall.windowName || ''
} else {
this.currCallNo = ''
this.currWinNo = ''
}
// 4.
if (data.callingList && Array.isArray(data.callingList)) {
this.callList = data.callingList.map(item => ({
no: item.queueNo || '',
win: item.windowName || ''
}))
} else {
this.callList = []
}
// 5. 3
if (data.waitingList && Array.isArray(data.waitingList)) {
const waitNos = data.waitingList.map(item => item.queueNo || '')
const rows = []
for (let i = 0; i < waitNos.length; i += 3) {
const row = waitNos.slice(i, i + 3)
while (row.length < 3) {
row.push('')
}
rows.push(row)
}
this.waitList = rows
} else {
this.waitList = []
}
})
.catch(err => {
console.error('获取大屏数据失败:', err)
})
}
}
}
@ -261,7 +290,9 @@ export default {
}
.wait-row {
justify-content: space-around;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
justify-items: center;
}
.row-blue {