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.

543 lines
12 KiB

5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
  1. <template>
  2. <div class="print-service">
  3. <!-- 打印方式选择对话框 -->
  4. <el-dialog
  5. title="选择打印方式"
  6. :visible.sync="printDialogVisible"
  7. width="480px"
  8. :close-on-click-modal="false"
  9. class="print-dialog"
  10. >
  11. <div class="print-options">
  12. <div class="option-description">
  13. <i class="el-icon-info"></i>
  14. <span>请选择适合您环境的打印方式</span>
  15. </div>
  16. <div class="print-methods">
  17. <div class="print-method recommended" @click="selectPrintMethod('server')">
  18. <div class="method-icon">
  19. <i class="el-icon-s-platform"></i>
  20. </div>
  21. <div class="method-content">
  22. <h4>服务器打印</h4>
  23. <p>通过WMS系统管理打印任务支持打印机配置和权限控制</p>
  24. <div class="method-badge">推荐</div>
  25. </div>
  26. <div class="method-arrow">
  27. <i class="el-icon-arrow-right"></i>
  28. </div>
  29. </div>
  30. <div class="print-method" @click="selectPrintMethod('network')">
  31. <div class="method-icon">
  32. <i class="el-icon-connection"></i>
  33. </div>
  34. <div class="method-content">
  35. <h4>直接网络打印</h4>
  36. <p>直接连接网络打印机适合简单的网络环境</p>
  37. </div>
  38. <div class="method-arrow">
  39. <i class="el-icon-arrow-right"></i>
  40. </div>
  41. </div>
  42. </div>
  43. </div>
  44. <div slot="footer" class="dialog-footer">
  45. <el-button @click="printDialogVisible = false">取消</el-button>
  46. </div>
  47. </el-dialog>
  48. <!-- 打印机选择对话框 -->
  49. <el-dialog
  50. title="服务器打印设置"
  51. :visible.sync="printerSelectionVisible"
  52. width="350px"
  53. :close-on-click-modal="false"
  54. class="printer-selection-dialog"
  55. >
  56. <div class="printer-selection-content">
  57. <div class="form-item">
  58. <label class="form-label">选择打印机:</label>
  59. <el-select
  60. v-model="selectedPrinter"
  61. placeholder="请选择打印机"
  62. style="width: 100%;"
  63. >
  64. <el-option
  65. v-for="printer in availablePrinters"
  66. :key="printer.printerName"
  67. :label="`${printer.printerName} (${printer.ipAddress})`"
  68. :value="printer.printerName"
  69. />
  70. </el-select>
  71. </div>
  72. <div class="form-item">
  73. <label class="form-label">打印份数:</label>
  74. <el-input
  75. v-model.number="printCopies"
  76. :min="1"
  77. :max="1"
  78. size="mini"
  79. style="width: 100%;"
  80. />
  81. </div>
  82. </div>
  83. <div slot="footer" class="dialog-footer">
  84. <el-button @click="printerSelectionVisible = false">取消</el-button>
  85. <el-button type="primary" @click="confirmPrint" :disabled="!selectedPrinter">开始打印</el-button>
  86. </div>
  87. </el-dialog>
  88. </div>
  89. </template>
  90. <script>
  91. import { getUserLabelPrinters, printLabel } from '@/api/labelSetting/label_setting.js'
  92. export default {
  93. name: 'PrintService',
  94. props: {
  95. // 是否显示打印对话框
  96. visible: {
  97. type: Boolean,
  98. default: false
  99. },
  100. // ZPL代码
  101. zplCode: {
  102. type: String,
  103. required: true
  104. },
  105. // 报告ID(可选)
  106. reportId: {
  107. type: String,
  108. default: ''
  109. },
  110. // 纸张尺寸(可选)
  111. paperSize: {
  112. type: String,
  113. default: ''
  114. },
  115. // 打印方向(可选)
  116. orientation: {
  117. type: String,
  118. default: 'portrait'
  119. },
  120. // DPI(可选)
  121. dpi: {
  122. type: Number,
  123. default: 203
  124. }
  125. },
  126. data() {
  127. return {
  128. printLoading: false,
  129. printerSelectionVisible: false,
  130. availablePrinters: [],
  131. selectedPrinter: '',
  132. printCopies: 1
  133. }
  134. },
  135. computed: {
  136. printDialogVisible: {
  137. get() {
  138. return this.visible
  139. },
  140. set(value) {
  141. this.$emit('update:visible', value)
  142. }
  143. }
  144. },
  145. methods: {
  146. /**
  147. * 开始打印流程
  148. */
  149. async startPrint() {
  150. if (!this.zplCode || this.zplCode.trim() === '') {
  151. this.$message.warning('没有可打印的内容')
  152. return
  153. }
  154. this.printDialogVisible = true
  155. },
  156. /**
  157. * 选择打印方式
  158. */
  159. selectPrintMethod(method) {
  160. this.printDialogVisible = false
  161. switch (method) {
  162. case 'server':
  163. this.showServerPrintDialog()
  164. break
  165. case 'network':
  166. this.showNetworkPrinterDialog()
  167. break
  168. default:
  169. console.warn('未知的打印方式:', method)
  170. }
  171. },
  172. /**
  173. * 显示服务器打印对话框
  174. */
  175. async showServerPrintDialog() {
  176. try {
  177. // 获取用户可用的打印机列表
  178. const { data } = await getUserLabelPrinters({
  179. userId: localStorage.getItem('userName'),
  180. username: localStorage.getItem('userName'),
  181. site: this.$store.state.user.site
  182. })
  183. if (!data.rows || data.rows.length === 0) {
  184. this.$confirm(
  185. '您还没有配置打印机,是否前往配置?',
  186. '未找到打印机',
  187. {
  188. confirmButtonText: '去配置',
  189. cancelButtonText: '取消',
  190. type: 'warning'
  191. }
  192. ).then(() => {
  193. this.$message.info('请联系管理员配置打印机')
  194. })
  195. return
  196. }
  197. // 显示打印机选择和份数设置对话框
  198. this.showPrinterSelectionDialog(data.rows)
  199. } catch (error) {
  200. console.error('获取打印机列表失败:', error)
  201. this.$message.error('获取打印机列表失败,请稍后重试')
  202. }
  203. },
  204. /**
  205. * 显示打印机选择对话框
  206. */
  207. showPrinterSelectionDialog(printers) {
  208. this.availablePrinters = printers
  209. this.selectedPrinter = printers.length > 0 ? printers[0].printerName : ''
  210. this.printCopies = 1
  211. this.printerSelectionVisible = true
  212. },
  213. /**
  214. * 确认打印
  215. */
  216. confirmPrint() {
  217. if (!this.selectedPrinter) {
  218. this.$message.warning('请选择打印机')
  219. return
  220. }
  221. this.printerSelectionVisible = false
  222. this.printViaServer(this.selectedPrinter, this.printCopies)
  223. },
  224. /**
  225. * 通过服务器打印
  226. */
  227. async printViaServer(printerName, copies) {
  228. this.printLoading = true
  229. this.$emit('print-start')
  230. try {
  231. const printRequest = {
  232. reportId: this.reportId,
  233. zplCode: this.zplCode,
  234. printerName: printerName,
  235. copies: copies,
  236. paperSize: this.paperSize,
  237. orientation: this.orientation,
  238. dpi: this.dpi,
  239. userId: localStorage.getItem('userName'),
  240. username: localStorage.getItem('userName'),
  241. site: this.$store.state.user.site
  242. }
  243. const { data } = await printLabel(printRequest)
  244. if (data.code === 200) {
  245. this.$message.success(`打印任务已发送!打印机: ${printerName}, 份数: ${copies}`)
  246. this.$emit('print-success', { printerName, copies })
  247. } else {
  248. throw new Error(data.msg || '打印失败')
  249. }
  250. } catch (error) {
  251. console.error('服务器打印失败:', error)
  252. this.$message.error(`打印失败: ${error.message || error}`)
  253. this.$emit('print-error', error)
  254. } finally {
  255. this.printLoading = false
  256. this.$emit('print-end')
  257. }
  258. },
  259. /**
  260. * 显示网络打印机对话框
  261. */
  262. showNetworkPrinterDialog() {
  263. this.$prompt('请输入打印机IP地址', '直接网络打印', {
  264. confirmButtonText: '打印',
  265. cancelButtonText: '取消',
  266. inputPattern: /^(\d{1,3}\.){3}\d{1,3}$/,
  267. inputErrorMessage: '请输入正确的IP地址格式',
  268. inputPlaceholder: '例如: 192.168.1.100',
  269. inputValue: localStorage.getItem('localPrinterIP') || ''
  270. }).then(({ value }) => {
  271. localStorage.setItem('localPrinterIP', value)
  272. this.printToNetworkPrinter(value)
  273. }).catch(() => {
  274. this.$message.info('已取消打印')
  275. })
  276. },
  277. /**
  278. * 直接网络打印
  279. */
  280. async printToNetworkPrinter(printerIP) {
  281. /*this.printLoading = true
  282. this.$emit('print-start')
  283. try {
  284. } catch (error) {
  285. console.error('网络打印失败:', error)
  286. this.$message.error(`网络打印失败: ${error.message}`)
  287. this.$emit('print-error', error)
  288. } finally {
  289. this.printLoading = false
  290. this.$emit('print-end')
  291. }*/
  292. // 直接发送到网络打印机
  293. //this.$emit('print-start')
  294. await fetch(`http://${printerIP}:9100`, {
  295. method: 'POST',
  296. headers: {
  297. 'Content-Type': 'text/plain',
  298. },
  299. body: this.zplCode,
  300. mode: 'no-cors'
  301. })
  302. this.$message.success(`打印任务已发送到 ${printerIP}`)
  303. //this.$emit('print-success', { printerIP })
  304. console.log('网络打印成功:', {
  305. printerIP,
  306. zplCode: this.zplCode,
  307. paperSize: this.paperSize,
  308. orientation: this.orientation,
  309. dpi: this.dpi
  310. })
  311. //this.$emit('print-end')
  312. }
  313. }
  314. }
  315. </script>
  316. <style scoped>
  317. /* 打印对话框样式 */
  318. .print-options {
  319. padding: 10px 0;
  320. }
  321. .option-description {
  322. display: flex;
  323. align-items: center;
  324. gap: 8px;
  325. margin-bottom: 20px;
  326. padding: 12px;
  327. background: #f0f9ff;
  328. border: 1px solid #e0f2fe;
  329. border-radius: 8px;
  330. color: #0369a1;
  331. font-size: 14px;
  332. }
  333. .option-description i {
  334. font-size: 16px;
  335. color: #0284c7;
  336. }
  337. .print-methods {
  338. display: flex;
  339. flex-direction: column;
  340. gap: 12px;
  341. }
  342. .print-method {
  343. display: flex;
  344. align-items: center;
  345. padding: 16px;
  346. border: 2px solid #e5e7eb;
  347. border-radius: 12px;
  348. cursor: pointer;
  349. transition: all 0.3s ease;
  350. background: #ffffff;
  351. position: relative;
  352. overflow: hidden;
  353. }
  354. .print-method:hover {
  355. border-color: #3b82f6;
  356. box-shadow: 0 4px 12px rgba(59, 130, 246, 0.15);
  357. transform: translateY(-2px);
  358. }
  359. .print-method.recommended {
  360. border-color: #10b981;
  361. background: linear-gradient(135deg, #f0fdf4 0%, #ffffff 100%);
  362. }
  363. .print-method.recommended:hover {
  364. border-color: #059669;
  365. box-shadow: 0 4px 12px rgba(16, 185, 129, 0.2);
  366. }
  367. .method-icon {
  368. flex-shrink: 0;
  369. width: 48px;
  370. height: 48px;
  371. display: flex;
  372. align-items: center;
  373. justify-content: center;
  374. border-radius: 12px;
  375. margin-right: 16px;
  376. background: #f3f4f6;
  377. color: #6b7280;
  378. font-size: 20px;
  379. transition: all 0.3s ease;
  380. }
  381. .print-method:hover .method-icon {
  382. background: #3b82f6;
  383. color: white;
  384. transform: scale(1.1);
  385. }
  386. .print-method.recommended .method-icon {
  387. background: #10b981;
  388. color: white;
  389. }
  390. .print-method.recommended:hover .method-icon {
  391. background: #059669;
  392. }
  393. .method-content {
  394. flex: 1;
  395. position: relative;
  396. }
  397. .method-content h4 {
  398. margin: 0 0 6px 0;
  399. font-size: 16px;
  400. font-weight: 600;
  401. color: #1f2937;
  402. line-height: 1.2;
  403. }
  404. .method-content p {
  405. margin: 0;
  406. font-size: 13px;
  407. color: #6b7280;
  408. line-height: 1.4;
  409. }
  410. .method-badge {
  411. position: absolute;
  412. top: -2px;
  413. right: 0;
  414. background: #10b981;
  415. color: white;
  416. font-size: 11px;
  417. font-weight: 600;
  418. padding: 2px 8px;
  419. border-radius: 12px;
  420. text-transform: uppercase;
  421. letter-spacing: 0.5px;
  422. }
  423. .method-arrow {
  424. flex-shrink: 0;
  425. margin-left: 12px;
  426. color: #9ca3af;
  427. font-size: 16px;
  428. transition: all 0.3s ease;
  429. }
  430. .print-method:hover .method-arrow {
  431. color: #3b82f6;
  432. transform: translateX(4px);
  433. }
  434. .print-method.recommended:hover .method-arrow {
  435. color: #10b981;
  436. }
  437. .dialog-footer {
  438. text-align: center;
  439. padding-top: 10px;
  440. }
  441. /* 打印机选择对话框样式 */
  442. .printer-selection-content {
  443. padding: 10px 0;
  444. }
  445. .form-item {
  446. margin-bottom: 20px;
  447. }
  448. .form-label {
  449. display: block;
  450. margin-bottom: 8px;
  451. font-weight: 600;
  452. color: #303133;
  453. font-size: 14px;
  454. }
  455. .form-hint {
  456. margin-top: 6px;
  457. font-size: 12px;
  458. color: #909399;
  459. line-height: 1.4;
  460. }
  461. /* 响应式设计 */
  462. @media (max-width: 600px) {
  463. .print-method {
  464. padding: 12px;
  465. }
  466. .method-icon {
  467. width: 40px;
  468. height: 40px;
  469. margin-right: 12px;
  470. font-size: 18px;
  471. }
  472. .method-content h4 {
  473. font-size: 15px;
  474. }
  475. .method-content p {
  476. font-size: 12px;
  477. }
  478. .printer-selection-content {
  479. padding: 5px 0;
  480. }
  481. .form-label {
  482. font-size: 13px;
  483. }
  484. }
  485. </style>