|
|
@@ -2,7 +2,7 @@
|
|
|
<route lang="json5">
|
|
|
{
|
|
|
style: {
|
|
|
- navigationBarTitleText: '打印任务列表',
|
|
|
+ navigationBarTitleText: '局域网打印任务列表',
|
|
|
},
|
|
|
}
|
|
|
</route>
|
|
|
@@ -36,11 +36,11 @@
|
|
|
<view v-if="queryParams.printer" class="printer">{{ `当前打印机: ${queryParams.printer} ${queryParams.asname ? `(${queryParams.asname})` : ''}` }}</view>
|
|
|
|
|
|
<template v-if="dataList.length > 0 || loadStatus == 'loading'">
|
|
|
- <view v-for="item of dataList" :key="item.id" class="item-contain" @click="toDetail(item)">
|
|
|
+ <view v-for="item of dataList" :key="item.id" class="item-contain">
|
|
|
<view class="item-info">
|
|
|
<view class="image">
|
|
|
<wd-img
|
|
|
- :src="getFileType(item.title)"
|
|
|
+ :src="getFileType(item['document-name-supplied'])"
|
|
|
:width="60"
|
|
|
:height="60"
|
|
|
mode="aspectFit"
|
|
|
@@ -48,14 +48,14 @@
|
|
|
</view>
|
|
|
<view class="name">
|
|
|
<view class="main-text">
|
|
|
- <view>{{ item.title }}</view>
|
|
|
+ <view>{{ item['document-name-supplied'] }}</view>
|
|
|
</view>
|
|
|
<view class="sub-text">
|
|
|
<text>任务状态: </text>
|
|
|
- <text :class="`color-${getLabelColor(item.jobStatus, jobStatus)}`">{{ getLabel(item.jobStatus, jobStatus) + (item.statusMsg ? `(${item.statusMsg})` : "") }}</text>
|
|
|
+ <text :class="`color-${getLabelColor(item['job-state'], jobStatus)}`">{{ getLabel(item['job-state'], jobStatus) + (item['job-printer-state-message'] ? `(${item['job-printer-state-message']})` : "") }}</text>
|
|
|
</view>
|
|
|
<view class="sub-text">
|
|
|
- {{ `创建时间: ${item.createTime}` }}
|
|
|
+ {{ `创建时间: ${timestampToDatetime(item['time-at-creation'])}` }}
|
|
|
</view>
|
|
|
<!-- <view class="sub-text flex-center">
|
|
|
<view class="flex-1">xxx</view>
|
|
|
@@ -64,9 +64,9 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
<view class="item-opt">
|
|
|
- <view v-if="item.reprint == '1'" class="opt-btn" @click.stop="handleReprint(item.id)">重打</view>
|
|
|
- <view v-if="['3', '4', '5', '6'].includes(item.jobStatus)" class="opt-btn" @click.stop="handleCancel(item.id)">取消</view>
|
|
|
- <view class="opt-btn delete-btn" @click.stop="handleDelete(item)">删除</view>
|
|
|
+ <!-- 移动, 重打, 挂起, 恢复, 取消 -->
|
|
|
+ <view v-if="item['job-state'] == 9 && item['number-of-documents']" class="opt-btn" @click.stop="handleReprint(item['job-id'])">重打</view>
|
|
|
+ <view v-if="[3, 4, 5, 6].includes(item['job-state'])" class="opt-btn" @click.stop="handleCancel(item['job-id'])">取消</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
<!-- 加载更多 -->
|
|
|
@@ -79,30 +79,26 @@
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
import { useMessage, useToast } from 'wot-design-uni'
|
|
|
-import { getUserHubJobsPage, reprintUserHubJobs, cancelUserHubJobs, deleteUserHubJobs } from '@/service/api'
|
|
|
-import { getLabel, getLabelColor } from '@/utils'
|
|
|
+import { getPrinterByLocal, getJobsCompleted, getJobsNotCompleted, cancelJobByLocal, restartJobByLocal } from '@/service/api'
|
|
|
+import { getLabel, getLabelColor, timestampToDatetime } from '@/utils'
|
|
|
import { debounce } from 'wot-design-uni/components/common/util'
|
|
|
import { useUserStore } from '@/store'
|
|
|
-import { handleError } from 'vue'
|
|
|
-import { toLoginWait } from '@/utils'
|
|
|
|
|
|
-let socketBaseUrl = import.meta.env.VITE_SOCKET_BASEURL
|
|
|
-const userStore = useUserStore()
|
|
|
-const token = userStore.token
|
|
|
+const uri = ref("")
|
|
|
+const intranetPrinterList = ref([])
|
|
|
+const intranetIp = ref("")
|
|
|
const message = useMessage()
|
|
|
const toast = useToast()
|
|
|
const total = ref(0)
|
|
|
const queryParams: any = reactive({
|
|
|
pageNo: 1,
|
|
|
pageSize: 10,
|
|
|
- completed: "all",
|
|
|
- title: '',
|
|
|
+ completed: "0",
|
|
|
+ asname: "",
|
|
|
printer: "",
|
|
|
- hubId: '',
|
|
|
- asname: '', // 打印助手名称
|
|
|
+ printer_uri: "",
|
|
|
})
|
|
|
const completedList: any = ref([
|
|
|
- { label: '全部', value: 'all' },
|
|
|
{ label: '当前任务', value: '0' },
|
|
|
{ label: '历史任务', value: '1' }
|
|
|
])
|
|
|
@@ -129,19 +125,9 @@ const pptSrc = '/static/images/ppt.png'
|
|
|
const pdfSrc = '/static/images/pdf.png'
|
|
|
const txtSrc = '/static/images/txt.png'
|
|
|
const otherSrc = '/static/images/other.png'
|
|
|
-// websocket连接对象
|
|
|
-const socketTask = ref(null)
|
|
|
-// 是否正在重连
|
|
|
-const isReconnecting = ref(false)
|
|
|
-// 当前重连次数
|
|
|
-const reconnectAttempts = ref(0)
|
|
|
-// 最大重连次数
|
|
|
-const maxReconnectAttempts = ref(5)
|
|
|
-// 重连间隔时间
|
|
|
-const reconnectInterval = 1000
|
|
|
|
|
|
defineOptions({
|
|
|
- name: 'Job',
|
|
|
+ name: 'IntranetJob',
|
|
|
})
|
|
|
|
|
|
// 根据文件类型获取图片
|
|
|
@@ -149,129 +135,143 @@ defineOptions({
|
|
|
function getFileType(fileName) {
|
|
|
let src = otherSrc
|
|
|
let fileType = ""
|
|
|
- const lastIndex = fileName.lastIndexOf('.')
|
|
|
- if (lastIndex != -1) fileType = fileName.substring(lastIndex + 1)
|
|
|
- switch (fileType) {
|
|
|
- case "doc":
|
|
|
- case "docx":
|
|
|
- src = docSrc
|
|
|
- break;
|
|
|
- case "xls":
|
|
|
- case "xlsx":
|
|
|
- src = xlsSrc;
|
|
|
- break;
|
|
|
- case "ppt":
|
|
|
- case "pptx":
|
|
|
- src = pptSrc;
|
|
|
- break;
|
|
|
- case "png":
|
|
|
- case "jpg":
|
|
|
- case "jpeg":
|
|
|
- case "gif":
|
|
|
- case "webp":
|
|
|
- src = imageSrc;
|
|
|
- break;
|
|
|
- case "txt":
|
|
|
- src = txtSrc;
|
|
|
+ if (fileName) {
|
|
|
+ const lastIndex = fileName.lastIndexOf('.')
|
|
|
+ if (lastIndex != -1) fileType = fileName.substring(lastIndex + 1)
|
|
|
+ switch (fileType) {
|
|
|
+ case "doc":
|
|
|
+ case "docx":
|
|
|
+ src = docSrc
|
|
|
+ break;
|
|
|
+ case "xls":
|
|
|
+ case "xlsx":
|
|
|
+ src = xlsSrc;
|
|
|
+ break;
|
|
|
+ case "ppt":
|
|
|
+ case "pptx":
|
|
|
+ src = pptSrc;
|
|
|
+ break;
|
|
|
+ case "png":
|
|
|
+ case "jpg":
|
|
|
+ case "jpeg":
|
|
|
+ case "gif":
|
|
|
+ case "webp":
|
|
|
+ src = imageSrc;
|
|
|
+ break;
|
|
|
+ case "txt":
|
|
|
+ src = txtSrc;
|
|
|
+ break;
|
|
|
+ case "pdf":
|
|
|
+ src = pdfSrc;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return src
|
|
|
+}
|
|
|
+
|
|
|
+// 获取局域网打印机列表, 匹配uri 查询任务队列
|
|
|
+function getIntranet() {
|
|
|
+ let params = {
|
|
|
+ ip: intranetIp.value
|
|
|
+ }
|
|
|
+ getPrinterByLocal(params).then((res: any) => {
|
|
|
+ intranetPrinterList.value = res.body || []
|
|
|
+ uri.value = intranetPrinterList.value.find(item => item.name == queryParams.printer)?.['printer-uri-supported'] || ""
|
|
|
+ if (uri.value) {
|
|
|
+ getDataList(uri.value)
|
|
|
+ } else {
|
|
|
+ message.alert(`暂未找到该打印机:${queryParams.printer}`)
|
|
|
+ }
|
|
|
+ }).catch(() => {})
|
|
|
+}
|
|
|
+
|
|
|
+// 获取列表数据 (进行中展示全部, 历史任务前端分页)
|
|
|
+function getDataList(uri) {
|
|
|
+ switch (queryParams.completed) {
|
|
|
+ case "0":
|
|
|
+ // 进行中任务
|
|
|
+ getDataListNotCompleted(uri)
|
|
|
break;
|
|
|
- case "pdf":
|
|
|
- src = pdfSrc;
|
|
|
+ case "1":
|
|
|
+ // 已完成任务: 前端分页
|
|
|
+ getDataListCompleted(uri)
|
|
|
break;
|
|
|
}
|
|
|
- return src
|
|
|
}
|
|
|
|
|
|
-// 获取列表数据
|
|
|
-function getDataList() {
|
|
|
+// 进行中的打印任务 (全部展示)
|
|
|
+function getDataListNotCompleted(uri) {
|
|
|
loadStatus.value = 'loading'
|
|
|
- const params = { ...queryParams }
|
|
|
- if (params.title) {
|
|
|
- params.title = '*' + params.title + '*'
|
|
|
- } else {
|
|
|
- delete params.title
|
|
|
+ let params = {
|
|
|
+ "ip": intranetIp.value,
|
|
|
+ "printer_uri": uri,
|
|
|
}
|
|
|
- if (params.completed === '' || params.completed === 'all') delete params.completed
|
|
|
- if (!params.printer) delete params.printer
|
|
|
- if (!params.hubId) delete params.hubId
|
|
|
- getUserHubJobsPage(params)
|
|
|
- .then((res: any) => {
|
|
|
- if (res.code === 0 && res.body) {
|
|
|
- total.value = res.body.total
|
|
|
- if (queryParams.pageNo === 1) {
|
|
|
- dataList.value = res.body.records || []
|
|
|
- } else {
|
|
|
- dataList.value.push(...(res.body.records || []))
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
- .catch((e) => {})
|
|
|
- .finally(() => {
|
|
|
- loadStatus.value = 'finished'
|
|
|
- })
|
|
|
+ getJobsNotCompleted(params).then((res: any) => {
|
|
|
+ total.value = res.body.length
|
|
|
+ dataList.value = res.body || []
|
|
|
+ }).catch((e) => {})
|
|
|
+ .finally(() => {
|
|
|
+ loadStatus.value = 'finished'
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 已经完成的打印任务 (前端分页)
|
|
|
+function getDataListCompleted(uri) {
|
|
|
+ let params = {
|
|
|
+ "ip": intranetIp.value,
|
|
|
+ "printer_uri": uri,
|
|
|
+ }
|
|
|
+ getJobsCompleted(params).then((res: any) => {
|
|
|
+ total.value = res.body.length
|
|
|
+ dataList.value = res.body || []
|
|
|
+ }).catch((e) => {})
|
|
|
+ .finally(() => {
|
|
|
+ loadStatus.value = 'finished'
|
|
|
+ })
|
|
|
+
|
|
|
+ // if (res.code === 0 && res.body) {
|
|
|
+ // total.value = res.body.total
|
|
|
+ // if (queryParams.pageNo === 1) {
|
|
|
+ // dataList.value = res.body.records || []
|
|
|
+ // } else {
|
|
|
+ // dataList.value.push(...(res.body.records || []))
|
|
|
+ // }
|
|
|
+ // }
|
|
|
}
|
|
|
|
|
|
const onSearch = debounce(() => {
|
|
|
queryParams.pageNo = 1
|
|
|
- getDataList()
|
|
|
+ getDataList(uri.value)
|
|
|
}, 500)
|
|
|
|
|
|
-// 查看详情
|
|
|
-function toDetail(item: any) {
|
|
|
- if (['0'].includes(item.jobStatus)) return
|
|
|
- uni.navigateTo({
|
|
|
- url: `/pages/print/jobDetail?id=${item.id}`,
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
// 重打任务
|
|
|
function handleReprint(id: string) {
|
|
|
- reprintUserHubJobs({id}).then((res: any) => {
|
|
|
- if (res.code === 0) {
|
|
|
+ let params = {
|
|
|
+ "ip": intranetIp.value,
|
|
|
+ "job-id": id,
|
|
|
+ }
|
|
|
+ restartJobByLocal(params).then((res: any) => {
|
|
|
+ if (res.code === 200) {
|
|
|
toast.success('已发送重新打印')
|
|
|
- getDataList()
|
|
|
+ getDataList(uri.value)
|
|
|
}
|
|
|
- })
|
|
|
- .catch((error) => {
|
|
|
- console.log(error)
|
|
|
+ }).catch(() => {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 取消任务
|
|
|
function handleCancel(id: string) {
|
|
|
- cancelUserHubJobs({id}).then((res: any) => {
|
|
|
- if (res.code === 0) {
|
|
|
+ let params = {
|
|
|
+ "ip": intranetIp.value,
|
|
|
+ "job-id": id,
|
|
|
+ }
|
|
|
+ cancelJobByLocal(params).then((res: any) => {
|
|
|
+ if (res.code === 200) {
|
|
|
toast.success('取消打印任务成功')
|
|
|
- getDataList()
|
|
|
+ getDataList(uri.value)
|
|
|
}
|
|
|
})
|
|
|
- .catch((error) => {
|
|
|
- console.log(error)
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-// 删除任务
|
|
|
-function handleDelete(item) {
|
|
|
- message
|
|
|
- .confirm({
|
|
|
- title: '提示',
|
|
|
- msg: `是否删除打印任务: ${item.title} ?`,
|
|
|
- })
|
|
|
- .then(() => {
|
|
|
- deleteUserHubJobs({id: item.id})
|
|
|
- .then((res: any) => {
|
|
|
- if (res.code === 0) {
|
|
|
- toast.success('删除成功')
|
|
|
- queryParams.pageNo = 1
|
|
|
- getDataList()
|
|
|
- }
|
|
|
- })
|
|
|
- .catch((error) => {
|
|
|
- console.log(error)
|
|
|
- })
|
|
|
- })
|
|
|
- .catch((error) => {
|
|
|
- console.log(error)
|
|
|
- })
|
|
|
+ .catch((error) => {})
|
|
|
}
|
|
|
|
|
|
// 查询列表, 滚动到顶部, 返回第一页
|
|
|
@@ -286,17 +286,16 @@ function resetDataList() {
|
|
|
|
|
|
// 页面加载
|
|
|
onLoad((option) => {
|
|
|
- initWebSocket()
|
|
|
- // 指定打印机 & 助手ID
|
|
|
- if (option && option.printer && option.hubId) {
|
|
|
+ // 指定局域网IP 和 打印机
|
|
|
+ if (option && option.ip && option.printer) {
|
|
|
+ intranetIp.value = option.ip
|
|
|
queryParams.printer = option.printer
|
|
|
- queryParams.hubId = option.hubId
|
|
|
queryParams.asname = option.asname
|
|
|
+ // 先获取局域网打印机, 匹配uri, 再获取任务列表
|
|
|
+ getIntranet()
|
|
|
+ } else {
|
|
|
+ message.alert("局域网参数异常, 请重试")
|
|
|
}
|
|
|
- if (option && option.tab) {
|
|
|
- queryParams.completed = option.tab
|
|
|
- }
|
|
|
- getDataList()
|
|
|
// 监听刷新
|
|
|
uni.$on('refreshData', () => {
|
|
|
resetDataList()
|
|
|
@@ -304,10 +303,6 @@ onLoad((option) => {
|
|
|
})
|
|
|
})
|
|
|
|
|
|
-onUnload(() => {
|
|
|
- closeWebSocket()
|
|
|
-})
|
|
|
-
|
|
|
// 页面显示
|
|
|
onShow(() => {
|
|
|
if (isToTop.value) {
|
|
|
@@ -323,137 +318,11 @@ onShow(() => {
|
|
|
onReachBottom(() => {
|
|
|
if (dataList.value.length < total.value) {
|
|
|
queryParams.pageNo++
|
|
|
- getDataList()
|
|
|
+ getDataList(uri.value)
|
|
|
} else {
|
|
|
loadStatus.value = 'finished'
|
|
|
}
|
|
|
})
|
|
|
-
|
|
|
-// 创建websocket连接
|
|
|
-function initWebSocket() {
|
|
|
- socketTask.value = uni.connectSocket({
|
|
|
- url: `${socketBaseUrl}/print/ws`,
|
|
|
- header: {
|
|
|
- 'token': token
|
|
|
- },
|
|
|
- success: () => {
|
|
|
- console.log("连接成功");
|
|
|
- },
|
|
|
- fail: (err) => {
|
|
|
- console.log("连接失败: ", err);
|
|
|
- handleReconnect()
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- // 监听 WebSocket 连接打开事件
|
|
|
- socketTask.value.onOpen(() => {
|
|
|
- console.log('WebSocket 连接已打开');
|
|
|
-
|
|
|
- // 发送数据到服务器(心跳)
|
|
|
- // socketTask.send({
|
|
|
- // data: JSON.stringify({ message: 'Hello, Server!' }),
|
|
|
- // success: () => {
|
|
|
- // console.log('消息发送成功');
|
|
|
- // },
|
|
|
- // fail: (err) => {
|
|
|
- // console.error('消息发送失败', err);
|
|
|
- // }
|
|
|
- // });
|
|
|
- })
|
|
|
-
|
|
|
- // 监听 WebSocket 接收到消息事件
|
|
|
- socketTask.value.onMessage((res) => {
|
|
|
- console.log('Received message:', res.data);
|
|
|
-
|
|
|
- // 处理接收到的数据
|
|
|
- const lines = res.data.split(/\r?\n|\r/).filter(line => line.trim() !== '');
|
|
|
- const message = lines.reduce((obj, item) => {
|
|
|
- const [key, value] = item.split(/:(.*)/);
|
|
|
- obj[key] = key == "data" ? JSON.parse(value) : value;
|
|
|
- return obj;
|
|
|
- }, {});
|
|
|
- console.log('解析后的消息:', message);
|
|
|
-
|
|
|
- handleWebsocketMessage(message)
|
|
|
- })
|
|
|
-
|
|
|
- // 监听 WebSocket 错误事件
|
|
|
- socketTask.value.onError((err) => {
|
|
|
- console.error('WebSocket 发生错误', err);
|
|
|
- });
|
|
|
-
|
|
|
- // 监听 WebSocket 连接关闭事件 (线上存在一分钟就断开重连的问题)
|
|
|
- socketTask.value.onClose((res) => {
|
|
|
- console.log('WebSocket 连接已关闭:', res); // 异常断开 {code: 1006, reason: "abnormal closure"}
|
|
|
- if (res.code !== 1000) handleReconnect()
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
-// 断开websocket连接
|
|
|
-function closeWebSocket() {
|
|
|
- if (socketTask.value) {
|
|
|
- socketTask.value.close({
|
|
|
- success: () => {
|
|
|
- console.log('断开 WebSocket 连接成功');
|
|
|
- },
|
|
|
- fail: (err) => {
|
|
|
- console.error('断开 WebSocket 连接失败', err);
|
|
|
- },
|
|
|
- });
|
|
|
- socketTask.value = null
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 处理重连机制
|
|
|
-function handleReconnect() {
|
|
|
- if (isReconnecting.value || reconnectAttempts.value >= maxReconnectAttempts.value) {
|
|
|
- console.log('已达到最大重连次数,停止重连');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- isReconnecting.value = true
|
|
|
- reconnectAttempts.value = reconnectAttempts.value++
|
|
|
-
|
|
|
- setTimeout(() => {
|
|
|
- initWebSocket();
|
|
|
- isReconnecting.value = false;
|
|
|
- }, reconnectInterval)
|
|
|
-}
|
|
|
-
|
|
|
-// 处理Websocket消息
|
|
|
-function handleWebsocketMessage(message: any) {
|
|
|
- switch (message.event) {
|
|
|
- case "job-update":
|
|
|
- handleUpdate(message.data)
|
|
|
- break;
|
|
|
- case "not-verify":
|
|
|
- toast.warning('token失效, 请重新登录')
|
|
|
- toLoginWait(1500)
|
|
|
- break;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 处理更新数据
|
|
|
-function handleUpdate(data) {
|
|
|
- if (data.id && dataList.value.findIndex(i => i.id == data.id) !== -1) {
|
|
|
- // 更新状态
|
|
|
- let target: any = dataList.value.find(i => i.id == data.id)
|
|
|
- target.jobStatus = String(data.jobStatus)
|
|
|
- target.statusMsg = data.statusMsg
|
|
|
- // 通知
|
|
|
- switch (String(data.jobStatus)) {
|
|
|
- case "9":
|
|
|
- toast.success(`打印完成: ${data.title}`)
|
|
|
- break;
|
|
|
- case "6":
|
|
|
- toast.error(`打印错误: ${data.title}`)
|
|
|
- break;
|
|
|
- default:
|
|
|
- toast.info(`打印信息: ${data.title} ${getLabel(data.jobStatus, jobStatus.value)}`)
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|