You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
besure_web/src/views/mes/printconfig/index.vue

502 lines
14 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<ContentWrap>
<div class="print-config-header">
<div class="print-config-title-row">
<div class="print-config-title">{{ t('TemplateManagement.PrintConfig.moduleName') }}</div>
<el-tag
class="print-config-host-tag"
:type="currentHostName ? 'primary' : 'info'"
effect="plain"
>
<span class="print-config-host-label">
{{ t('TemplateManagement.PrintConfig.currentHostName') }}
</span>
<span>{{ currentHostName || t('TemplateManagement.PrintConfig.unknownHostName') }}</span>
</el-tag>
</div>
<div class="print-config-tip">{{ t('TemplateManagement.PrintConfig.currentHostTip') }}</div>
</div>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="120px"
>
<el-form-item :label="t('TemplateManagement.PrintConfig.hostName')" prop="hostName">
<el-input
v-model="queryParams.hostName"
:placeholder="t('TemplateManagement.PrintConfig.placeholderHostName')"
:clearable="!currentHostName"
:disabled="!!currentHostName"
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('TemplateManagement.PrintConfig.systemPrinterName')" prop="systemPrinterName">
<el-input
v-model="queryParams.systemPrinterName"
:placeholder="t('TemplateManagement.PrintConfig.placeholderSystemPrinterName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('common.reset') }}</el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['printer:config:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> {{ t('action.add') }}
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['printer:config:export']"
>
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<!-- <el-table-column label="主键ID" align="center" prop="id" />-->
<!-- <el-table-column type="selection" width="55" fixed="left" reserve-selection />-->
<el-table-column :label="t('TemplateManagement.PrintConfig.hostName')" align="center" prop="hostName" />
<el-table-column :label="t('TemplateManagement.PrintConfig.systemPrinterName')" align="center" prop="systemPrinterName" />
<el-table-column :label="t('TemplateManagement.PrintConfig.defaultStatus')" align="center" prop="isDefault" />
<el-table-column :label="t('TemplateManagement.PrintConfig.isEnable')" align="center" prop="isEnabled" />
<el-table-column :label="t('TemplateManagement.PrintConfig.remark')" align="center" prop="remark" />
<el-table-column
:label="t('TemplateManagement.PrintConfig.createTime')"
align="center"
prop="createdAt"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column
:label="t('TemplateManagement.PrintConfig.updateTime')"
align="center"
prop="updatedAt"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column :label="t('TemplateManagement.PrintConfig.operate')" align="center" min-width="120px">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['printer:config:update']"
>
{{ t('action.edit') }}
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['printer:config:delete']"
>
{{ t('action.del') }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗:添加/修改 -->
<ConfigForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { autoConnect, defaultElementTypeProvider, hiprint, hiwebSocket } from 'vue-plugin-hiprint'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { ConfigApi, ConfigVO } from '@/api/mes/printconfig'
import ConfigForm from './ConfigForm.vue'
/** 打印机配置 列表 */
defineOptions({ name: 'PrinterConfig' })
const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
const loading = ref(true) // 列表的加载中
const list = ref<ConfigVO[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数
interface QueryParams {
pageNo: number
pageSize: number
hostName?: string
systemPrinterName?: string
isDefault?: boolean
isEnabled?: boolean
remark?: string
}
const currentHostName = ref('')
const queryParams = reactive<QueryParams>({
pageNo: 1,
pageSize: 10,
hostName: undefined,
systemPrinterName: undefined,
isDefault: undefined,
isEnabled: undefined,
remark: undefined,
})
const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) // 导出的加载中
const clientHostStorageKey = 'hiprint-client-host'
const defaultClientHost = 'http://127.0.0.1:17521'
let hiprintInited = false
const normalizeClientHost = () => {
const host = (localStorage.getItem(clientHostStorageKey) || defaultClientHost).trim()
if (!host) {
return defaultClientHost
}
if (/^https?:\/\//i.test(host)) {
return host
}
return `http://${host}`
}
const getHiwebSocket = () => {
return ((hiwebSocket as any) || (window as any).hiwebSocket) as any
}
const ensureHiprintInit = () => {
if (hiprintInited) {
return
}
// Edge <20><><EFBFBD>ݣ<EFBFBD>Ϊ hiwebSocket <20><><EFBFBD>?polling <20><><EFBFBD><EFBFBD><EFBFBD><E3BDB5>? // ԭ<><D4AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?transports:["websocket"]<5D><>Edge <20><>ȫ<EFBFBD><C8AB><EFBFBD><EFBFBD><EFBFBD><EFBFBD> WebSocket <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>
const socket = getHiwebSocket()
if (socket?.start && !socket.__transportPatched) {
const originalStart = socket.start.bind(socket)
socket.start = function (callback?: any) {
const originalIo = window.io
window.io = function (url: string, opts?: any) {
opts = opts || {}
opts.transports = ['websocket', 'polling']
return originalIo(url, opts)
}
originalStart(callback)
window.io = originalIo
}
socket.__transportPatched = true
}
hiprint.init({
host: normalizeClientHost(),
providers: [defaultElementTypeProvider()]
})
hiprintInited = true
}
const applyClientHost = () => {
const socket = getHiwebSocket()
if (!socket) {
return
}
const host = normalizeClientHost()
if (socket.host !== host) {
socket.stop?.()
socket.host = host
}
}
const sanitizeHostName = (hostName?: unknown) => {
if (typeof hostName !== 'string') {
return ''
}
const value = hostName.trim()
if (!value || /^https?:\/\//i.test(value) || /[/:\\]/.test(value)) {
return ''
}
return value
}
const extractHostName = (source?: any) => {
if (!source || typeof source !== 'object') {
return ''
}
const fields = [
'hostName',
'hostname',
'computerName',
'machineName',
'pcName',
'clientName',
'name'
]
for (const field of fields) {
const hostName = sanitizeHostName(source[field])
if (hostName) {
return hostName
}
}
return ''
}
const getActiveXComputerName = () => {
try {
const ActiveXObjectCtor = (window as any).ActiveXObject
if (!ActiveXObjectCtor) {
return ''
}
const network = new ActiveXObjectCtor('WScript.Network')
return sanitizeHostName(network?.ComputerName)
} catch {
return ''
}
}
const getSocketHostName = () => {
const socket = getHiwebSocket()
// <20><><EFBFBD>ȼ<EFBFBD><C8BC> socket.clientInfo<66><6F><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD>ӿͻ<D3BF><CDBB><EFBFBD><EFBFBD><EFBFBD>Ϣ<EFBFBD><CFA2>
const hostNameFromInfo = extractHostName(socket?.clientInfo)
if (hostNameFromInfo) {
return hostNameFromInfo
}
const clients = socket?.clients
const clientList = Array.isArray(clients) ? clients : Object.values(clients || {})
for (const client of clientList) {
const hostName =
extractHostName(client) ||
extractHostName(client?.client) ||
extractHostName(client?.clientInfo) ||
extractHostName(client?.info)
if (hostName) {
return hostName
}
}
const printerList = Array.isArray(socket?.printerList) ? socket.printerList : []
for (const printer of printerList) {
const hostName =
extractHostName(printer?.server) ||
extractHostName(printer?.client) ||
extractHostName(printer?.clientInfo) ||
extractHostName(clients?.[printer?.clientId]) ||
extractHostName(clients?.[printer?.server?.clientId])
if (hostName) {
return hostName
}
}
return ''
}
const resolveCurrentHostName = async () => {
const activeXHostName = getActiveXComputerName()
if (activeXHostName) {
return activeXHostName
}
try {
ensureHiprintInit()
applyClientHost()
const socketHostName = getSocketHostName()
if (socketHostName) {
return socketHostName
}
return await new Promise<string>((resolve) => {
let settled = false
const finish = (hostName?: string) => {
if (settled) {
return
}
settled = true
window.clearTimeout(timer)
resolve(hostName || getSocketHostName())
}
const timer = window.setTimeout(() => finish(), 3000)
const socket = getHiwebSocket()
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> socket.io ʵ<><CAB5><EFBFBD><EFBFBD>ֱ<EFBFBD>Ӽ<EFBFBD><D3BC><EFBFBD> clients/clientInfo <20>¼<EFBFBD>
if (socket?.socket?.on) {
const onClients = () => {
const hn = getSocketHostName()
if (hn) finish(hn)
}
const onClientInfo = () => {
const hn = extractHostName(socket.clientInfo) || getSocketHostName()
if (hn) finish(hn)
}
socket.socket.on('clients', onClients)
socket.socket.on('clientInfo', onClientInfo)
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (socket) {
if (typeof socket.getClients === 'function') socket.getClients()
if (typeof socket.getClientInfo === 'function') socket.getClientInfo()
if (typeof socket.refreshPrinterList === 'function') socket.refreshPrinterList()
}
if (typeof hiprint.getClientInfo === 'function') {
hiprint.getClientInfo((clientInfo: any) => {
const hn = extractHostName(clientInfo)
if (hn) finish(hn)
})
}
// autoConnect <20><><EFBFBD><EFBFBD> socket<65><74><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD><D8B5><EFBFBD> false<73><65><EFBFBD>ȴ<EFBFBD><C8B4><EFBFBD><EFBFBD>ӳɹ<D3B3><C9B9><EFBFBD><EFBFBD> true<75><65>
autoConnect((status: boolean) => {
if (!status) {
return
}
getHiwebSocket()?.refreshPrinterList?.()
window.setTimeout(() => finish(getSocketHostName()), 300)
})
})
} catch {
return ''
}
}
const initCurrentHostName = async () => {
const hostName = await resolveCurrentHostName()
if (hostName) {
currentHostName.value = hostName
queryParams.hostName = hostName
}
}
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await ConfigApi.getConfigPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
if (currentHostName.value) {
queryParams.hostName = currentHostName.value
}
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
queryParams.hostName = currentHostName.value || undefined
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
let host = normalizeClientHost();
formRef.value.open(type,host, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
// 删除的二次确认
await message.delConfirm()
// 发起删除
await ConfigApi.deleteConfig(id)
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
// 导出的二次确认
await message.exportConfirm()
// 发起导出
exportLoading.value = true
const data = await ConfigApi.exportConfig(queryParams)
download.excel(data, '打印机配置.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(async () => {
await initCurrentHostName()
getList()
})
</script>
<style scoped lang="scss">
.print-config-header {
margin-bottom: 22px;
}
.print-config-title-row {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
.print-config-title {
color: var(--el-text-color-primary);
font-size: 28px;
font-weight: 700;
line-height: 1.25;
}
.print-config-host-tag {
height: 30px;
padding: 0 10px;
border-radius: 4px;
font-size: 14px;
font-weight: 600;
}
.print-config-host-label {
font-weight: 700;
}
.print-config-tip {
margin-top: 8px;
color: var(--el-text-color-secondary);
font-size: 14px;
line-height: 1.5;
}
</style>