You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

341 lines
9.5 KiB

7 months ago
7 months ago
  1. /**
  2. * 打印工具类
  3. * 提供统一的打印功能接口
  4. */
  5. import { getUserLabelPrinters, printLabel } from '@/api/labelSetting/label_setting.js'
  6. /**
  7. * 打印配置类
  8. */
  9. export class PrintConfig {
  10. constructor(options = {}) {
  11. this.zplCode = options.zplCode || ''
  12. this.reportId = options.reportId || ''
  13. this.paperSize = options.paperSize || ''
  14. this.orientation = options.orientation || 'portrait'
  15. this.dpi = options.dpi || 203
  16. this.copies = options.copies || 1
  17. this.printerName = options.printerName || ''
  18. this.printerIP = options.printerIP || ''
  19. }
  20. /**
  21. * 验证配置是否有效
  22. */
  23. validate() {
  24. if (!this.zplCode || this.zplCode.trim() === '') {
  25. throw new Error('ZPL代码不能为空')
  26. }
  27. return true
  28. }
  29. }
  30. /**
  31. * 打印服务类
  32. */
  33. export class PrintService {
  34. constructor(vue) {
  35. this.vue = vue
  36. this.loading = false
  37. }
  38. /**
  39. * 获取用户打印机列表
  40. */
  41. async getUserPrinters() {
  42. try {
  43. const { data } = await getUserLabelPrinters({
  44. userId: localStorage.getItem('userName'),
  45. username: localStorage.getItem('userName'),
  46. site: this.vue.$store.state.user.site
  47. })
  48. return data.rows || []
  49. } catch (error) {
  50. console.error('获取打印机列表失败:', error)
  51. throw new Error('获取打印机列表失败')
  52. }
  53. }
  54. /**
  55. * 服务器打印
  56. */
  57. async printViaServer(config) {
  58. config.validate()
  59. const printRequest = {
  60. reportId: config.reportId,
  61. zplCode: config.zplCode,
  62. printerName: config.printerName,
  63. copies: config.copies,
  64. paperSize: config.paperSize,
  65. orientation: config.orientation,
  66. dpi: config.dpi,
  67. userId: localStorage.getItem('userName'),
  68. username: localStorage.getItem('userName'),
  69. site: this.vue.$store.state.user.site
  70. }
  71. try {
  72. const { data } = await printLabel(printRequest)
  73. if (data.code === 200) {
  74. return {
  75. success: true,
  76. message: `打印任务已发送!打印机: ${config.printerName}, 份数: ${config.copies}`
  77. }
  78. } else {
  79. throw new Error(data.msg || '打印失败')
  80. }
  81. } catch (error) {
  82. throw new Error(`服务器打印失败: ${error.message || error}`)
  83. }
  84. }
  85. /**
  86. * 网络直连打印
  87. */
  88. async printViaNetwork(config) {
  89. config.validate()
  90. if (!config.printerIP) {
  91. throw new Error('打印机IP地址不能为空')
  92. }
  93. try {
  94. // 发送多份打印
  95. for (let i = 0; i < config.copies; i++) {
  96. await fetch(`http://${config.printerIP}:9100`, {
  97. method: 'POST',
  98. headers: {
  99. 'Content-Type': 'text/plain',
  100. },
  101. body: config.zplCode,
  102. mode: 'no-cors'
  103. })
  104. }
  105. return {
  106. success: true,
  107. message: `打印任务已发送到 ${config.printerIP}, 份数: ${config.copies}`
  108. }
  109. } catch (error) {
  110. throw new Error(`网络打印失败: ${error.message}`)
  111. }
  112. }
  113. /**
  114. * 显示打印机选择对话框
  115. */
  116. async showPrinterDialog(printers, defaultCopies = 1) {
  117. return new Promise((resolve, reject) => {
  118. const h = this.vue.$createElement
  119. let selectedPrinter = printers.length > 0 ? printers[0].printerName : ''
  120. let copies = defaultCopies
  121. this.vue.$msgbox({
  122. title: '服务器打印设置',
  123. message: h('div', [
  124. h('div', { style: 'margin-bottom: 15px;' }, [
  125. h('label', { style: 'display: block; margin-bottom: 5px; font-weight: bold;' }, '选择打印机:'),
  126. h('el-select', {
  127. props: {
  128. value: selectedPrinter,
  129. placeholder: '请选择打印机',
  130. style: 'width: 100%;'
  131. },
  132. on: {
  133. input: (val) => { selectedPrinter = val }
  134. }
  135. }, printers.map(printer =>
  136. h('el-option', {
  137. props: {
  138. key: printer.printerName,
  139. label: `${printer.printerName} (${printer.ipAddress})`,
  140. value: printer.printerName
  141. }
  142. })
  143. ))
  144. ]),
  145. h('div', { style: 'margin-bottom: 15px;' }, [
  146. h('label', { style: 'display: block; margin-bottom: 5px; font-weight: bold;' }, '打印份数:'),
  147. h('el-input', {
  148. props: {
  149. value: copies,
  150. min: 1,
  151. max: 99,
  152. size: 'mini',
  153. style: 'width: 100%;'
  154. },
  155. on: {
  156. input: (val) => { copies = val }
  157. }
  158. })
  159. ])
  160. ]),
  161. showCancelButton: true,
  162. confirmButtonText: '开始打印',
  163. cancelButtonText: '取消'
  164. }).then(() => {
  165. if (!selectedPrinter) {
  166. reject(new Error('请选择打印机'))
  167. return
  168. }
  169. resolve({ printerName: selectedPrinter, copies })
  170. }).catch(() => {
  171. reject(new Error('用户取消打印'))
  172. })
  173. })
  174. }
  175. /**
  176. * 显示网络打印机IP输入对话框
  177. */
  178. async showNetworkDialog() {
  179. return new Promise((resolve, reject) => {
  180. this.vue.$prompt('请输入打印机IP地址', '直接网络打印', {
  181. confirmButtonText: '打印',
  182. cancelButtonText: '取消',
  183. inputPattern: /^(\d{1,3}\.){3}\d{1,3}$/,
  184. inputErrorMessage: '请输入正确的IP地址格式',
  185. inputPlaceholder: '例如: 192.168.1.100',
  186. inputValue: localStorage.getItem('localPrinterIP') || ''
  187. }).then(({ value }) => {
  188. localStorage.setItem('localPrinterIP', value)
  189. resolve(value)
  190. }).catch(() => {
  191. reject(new Error('用户取消打印'))
  192. })
  193. })
  194. }
  195. }
  196. /**
  197. * 快速打印函数 - 显示打印方式选择对话框
  198. */
  199. export async function quickPrint(vue, config) {
  200. const printConfig = new PrintConfig(config)
  201. const printService = new PrintService(vue)
  202. return new Promise((resolve, reject) => {
  203. // 显示打印方式选择对话框
  204. const h = vue.$createElement
  205. vue.$msgbox({
  206. title: '选择打印方式',
  207. message: h('div', { class: 'print-options' }, [
  208. h('div', { class: 'option-description' }, [
  209. h('i', { class: 'el-icon-info' }),
  210. h('span', '请选择适合您环境的打印方式')
  211. ]),
  212. h('div', { class: 'print-methods' }, [
  213. h('div', {
  214. class: 'print-method recommended',
  215. on: {
  216. click: () => handleServerPrint()
  217. }
  218. }, [
  219. h('div', { class: 'method-icon' }, [
  220. h('i', { class: 'el-icon-s-platform' })
  221. ]),
  222. h('div', { class: 'method-content' }, [
  223. h('h4', '服务器打印'),
  224. h('p', '通过WMS系统管理打印任务,支持打印机配置和权限控制'),
  225. h('div', { class: 'method-badge' }, '推荐')
  226. ]),
  227. h('div', { class: 'method-arrow' }, [
  228. h('i', { class: 'el-icon-arrow-right' })
  229. ])
  230. ]),
  231. h('div', {
  232. class: 'print-method',
  233. on: {
  234. click: () => handleNetworkPrint()
  235. }
  236. }, [
  237. h('div', { class: 'method-icon' }, [
  238. h('i', { class: 'el-icon-connection' })
  239. ]),
  240. h('div', { class: 'method-content' }, [
  241. h('h4', '直接网络打印'),
  242. h('p', '直接连接网络打印机,适合简单的网络环境')
  243. ]),
  244. h('div', { class: 'method-arrow' }, [
  245. h('i', { class: 'el-icon-arrow-right' })
  246. ])
  247. ])
  248. ])
  249. ]),
  250. showCancelButton: true,
  251. confirmButtonText: '',
  252. cancelButtonText: '取消',
  253. showConfirmButton: false
  254. }).catch(() => {
  255. reject(new Error('用户取消打印'))
  256. })
  257. // 处理服务器打印
  258. async function handleServerPrint() {
  259. vue.$msgbox.close()
  260. try {
  261. const printers = await printService.getUserPrinters()
  262. if (printers.length === 0) {
  263. vue.$confirm(
  264. '您还没有配置打印机,是否前往配置?',
  265. '未找到打印机',
  266. {
  267. confirmButtonText: '去配置',
  268. cancelButtonText: '取消',
  269. type: 'warning'
  270. }
  271. ).then(() => {
  272. vue.$message.warning('请联系管理员配置打印机')
  273. })
  274. return
  275. }
  276. const { printerName, copies } = await printService.showPrinterDialog(printers, printConfig.copies)
  277. printConfig.printerName = printerName
  278. printConfig.copies = copies
  279. const result = await printService.printViaServer(printConfig)
  280. vue.$message.success(result.message)
  281. resolve(result)
  282. } catch (error) {
  283. vue.$message.error(error.message)
  284. reject(error)
  285. }
  286. }
  287. // 处理网络打印
  288. async function handleNetworkPrint() {
  289. vue.$msgbox.close()
  290. try {
  291. const printerIP = await printService.showNetworkDialog()
  292. printConfig.printerIP = printerIP
  293. const result = await printService.printViaNetwork(printConfig)
  294. vue.$message.success(result.message)
  295. resolve(result)
  296. } catch (error) {
  297. vue.$message.error(error.message)
  298. reject(error)
  299. }
  300. }
  301. })
  302. }
  303. /**
  304. * 创建打印服务实例
  305. */
  306. export function createPrintService(vue) {
  307. return new PrintService(vue)
  308. }
  309. export default {
  310. PrintConfig,
  311. PrintService,
  312. quickPrint,
  313. createPrintService
  314. }