App.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. <template>
  2. <div id="app">
  3. <router-view></router-view>
  4. <div class="hide">
  5. <webview
  6. id="printWebview"
  7. :src="publicPath"
  8. nodeintegration
  9. ></webview>
  10. <webview
  11. id="printSmallTicketWebview"
  12. :src="publicSmallTicketPath"
  13. nodeintegration
  14. ></webview>
  15. <!-- 打印模板 -->
  16. <PrintTemplate :current-ticket="currentTicket"></PrintTemplate>
  17. <!-- 小票打印模板 -->
  18. <SmallTicketPrintTemplate :current-order="printOrder"></SmallTicketPrintTemplate>
  19. </div>
  20. <UpdateFile></UpdateFile>
  21. </div>
  22. </template>
  23. <script>
  24. import PrintTemplate from '@/components/PrintTemplate.vue'
  25. import SmallTicketPrintTemplate from '@/components/SmallTicketPrintTemplate'
  26. import UpdateFile from './UpdateFile'
  27. const { ipcRenderer } = require('electron')
  28. const path = require('path')
  29. export default {
  30. name: 'AdminClient',
  31. components: {
  32. PrintTemplate,
  33. UpdateFile,
  34. SmallTicketPrintTemplate
  35. },
  36. computed: {
  37. faceModelIsReady () {
  38. return this.$store.state.app.faceModelIsReady
  39. },
  40. printList () {
  41. return this.$store.state.app.printList
  42. },
  43. printOrder () {
  44. return this.$store.state.app.printOrder
  45. }
  46. },
  47. data () {
  48. return {
  49. publicPath: path.join(__static, 'print.html'),
  50. publicSmallTicketPath: path.join(__static, 'smallTicket.html'),
  51. isPrinting: false, // 正在打印
  52. printers: [],
  53. currentTicket: null,
  54. currentOrder: null
  55. }
  56. },
  57. watch: {
  58. $route: {
  59. handler (val) {
  60. console.log(val.fullPath)
  61. },
  62. immediate: true
  63. },
  64. // 待打印列表
  65. printList (val) {
  66. // 打印列表不为空,且当前未在打印时,设置当前打印对象
  67. if (val.length > 0 && !this.isPrinting) {
  68. this.isPrinting = true
  69. this.currentTicket = val[0]
  70. }
  71. }
  72. },
  73. methods: {
  74. checkConfig () {
  75. const serverUrl = this.$localStore.get('serverUrl')
  76. if (!serverUrl) {
  77. this.$router.push('/config')
  78. return false
  79. } else {
  80. // 检查更新
  81. ipcRenderer.send('updateReady', this.$localStore.get('updateUrl'))
  82. if (this.$route.name === 'config') {
  83. this.$router.push('/')
  84. }
  85. }
  86. },
  87. setPrint () {
  88. ipcRenderer.send('getPrinters')
  89. ipcRenderer.on('sendPrinters', (event, printers) => {
  90. console.log(printers)
  91. this.printers = printers
  92. this.defaultPrinter = printers.find(i => i.isDefault) && printers.find(i => i.isDefault).name
  93. })
  94. this.webview = document.querySelector('#printWebview')
  95. this.webview.removeEventListener('ipc-message', this.handlePrint)
  96. this.webview.addEventListener('ipc-message', this.handlePrint)
  97. this.smallTicketWebview = document.querySelector('#printSmallTicketWebview')
  98. this.smallTicketWebview.removeEventListener('ipc-message', this.handlePrintSmallTicket)
  99. this.smallTicketWebview.addEventListener('ipc-message', this.handlePrintSmallTicket)
  100. },
  101. handlePrint (event) {
  102. if (event.channel === 'webview-print-do') {
  103. // if (this.isPrinting) return
  104. try {
  105. let printer
  106. if (this.currentTicket && this.currentTicket.printer_name && this.printers.find(v => v.name === this.currentTicket.printer_name)) {
  107. printer = this.currentTicket.printer_name || this.$localStore.get('defaultPrinter') || this.defaultPrinter
  108. } else {
  109. printer = this.$localStore.get('defaultPrinter') || this.defaultPrinter
  110. }
  111. console.error('开始打印!', printer)
  112. this.webview.print({
  113. silent: true,
  114. printBackground: true,
  115. deviceName: printer
  116. }, (data) => {
  117. // console.log(data)
  118. // this.$message.success('打印成功')
  119. console.log('打印成功')
  120. // 打印成功后,更新打印列表
  121. this.isPrinting = false
  122. this.$store.commit('PRINT_NEW')
  123. })
  124. } catch (e) {
  125. console.log(e)
  126. }
  127. }
  128. },
  129. handlePrintSmallTicket (event) {
  130. if (event.channel === 'webview-print-do') {
  131. // if (this.isPrinting) return
  132. try {
  133. let printer = this.$localStore.get('defaultSmallTicketPrinter') || this.defaultPrinter
  134. console.error('开始打印!', printer)
  135. this.smallTicketWebview.print({
  136. silent: true,
  137. printBackground: true,
  138. deviceName: printer
  139. }, (data) => {
  140. // console.log(data)
  141. // this.$message.success('打印成功')
  142. console.log('打印成功')
  143. // 打印成功后,更新打印列表
  144. this.isPrinting = false
  145. this.$store.commit('SET_PRINT_ORDER', null)
  146. })
  147. } catch (e) {
  148. console.log(e)
  149. }
  150. }
  151. },
  152. setConfigEvent () {
  153. ipcRenderer.on('goConfig', () => {
  154. this.$router.push('/config')
  155. })
  156. ipcRenderer.on('goPos', () => {
  157. this.$router.push('/posTool')
  158. })
  159. }
  160. },
  161. created () {
  162. this.$log.info('程序初始化完成')
  163. },
  164. mounted () {
  165. console.log('app mounted')
  166. // 检查本地配置
  167. this.checkConfig()
  168. // 设置打印事件
  169. this.setPrint()
  170. // 设置配置事件
  171. this.setConfigEvent()
  172. this.$store.dispatch('initDonsee100R')
  173. }
  174. }
  175. </script>
  176. <style lang="scss">
  177. .success {
  178. color: #67c23a;
  179. }
  180. .danger {
  181. color: #f56c6c;
  182. }
  183. i {
  184. font-style: normal;
  185. }
  186. .hidden {
  187. width: 0;
  188. height: 0;
  189. overflow: hidden;
  190. }
  191. .el-card__header {
  192. padding: 10px 20px;
  193. font-size: 16px;
  194. line-height: 22px;
  195. }
  196. .form-wrap {
  197. .el-input,
  198. .el-select,
  199. .el-date-editor,
  200. .el-date-editor.el-input,
  201. .el-input-number {
  202. width: 194px;
  203. }
  204. }
  205. .el-pagination {
  206. padding: 30px 0 20px;
  207. text-align: center;
  208. .el-select {
  209. width: auto;
  210. input {
  211. height: 28px;
  212. }
  213. }
  214. .el-input__icon {
  215. line-height: 28px;
  216. }
  217. &__jump {
  218. .el-input {
  219. width: 50px !important;
  220. }
  221. }
  222. }
  223. .el-table {
  224. .el-table__row.expanded {
  225. background: lighten(#b5bec7, 18%);
  226. }
  227. .el-table__expanded-cell {
  228. background: lighten(#e9eaee, 5%) !important;
  229. &:hover {
  230. background: lighten(#e9eaee, 5%) !important;
  231. }
  232. }
  233. .el-tag {
  234. margin: 3px 5px 3px 0;
  235. }
  236. }
  237. // 表格的详情展开面板
  238. .table-expand {
  239. .el-form-item {
  240. label {
  241. color: #99a9bf;
  242. }
  243. }
  244. }
  245. // 对话框padding太大了,30 20改成20
  246. .el-dialog__body {
  247. padding: 20px;
  248. }
  249. // 表单信息p标签不换行
  250. .p-nowrap {
  251. overflow: hidden;
  252. text-overflow: ellipsis;
  253. white-space: nowrap;
  254. }
  255. // 信息对话框的样式
  256. .info-form {
  257. display: flex;
  258. flex-wrap: wrap;
  259. .info-form-line {
  260. display: flex;
  261. width: 50%;
  262. height: 40px;
  263. line-height: 40px;
  264. .info-form-label {
  265. width: 80px;
  266. padding-right: 12px;
  267. color: #64667b;
  268. text-align: right;
  269. flex-shrink: 0;
  270. flex-grow: 0;
  271. }
  272. }
  273. }
  274. .overflow-txt {
  275. display: block;
  276. width: 180px;
  277. overflow: hidden;
  278. text-overflow: ellipsis;
  279. white-space: nowrap;
  280. }
  281. // 图片上传样式
  282. .avatar-uploader {
  283. width: 100px;
  284. height: 100px;
  285. text-align: center;
  286. background: #eee;
  287. border: 1px dashed #d9d9d9;
  288. border-radius: 6px;
  289. .el-upload {
  290. position: relative;
  291. overflow: hidden;
  292. cursor: pointer;
  293. }
  294. .el-upload:hover {
  295. border-color: #409eff;
  296. }
  297. .avatar-uploader-icon {
  298. width: 100px;
  299. height: 100px;
  300. font-size: 28px;
  301. line-height: 100px;
  302. color: #8c939d;
  303. text-align: center;
  304. }
  305. .avatar {
  306. display: block;
  307. width: 100px;
  308. height: 100px;
  309. background: center center no-repeat;
  310. background-size: contain;
  311. }
  312. }
  313. .no-wrap {
  314. width: 100%;
  315. overflow: hidden;
  316. white-space: nowrap;
  317. }
  318. .offSale-btn {
  319. color: #f56c6c;
  320. }
  321. .onSale-btn {
  322. color: #67c23a;
  323. }
  324. #printWebview {
  325. width: 500px;
  326. height: 500px;
  327. }
  328. .hide {
  329. width: 0;
  330. height: 0;
  331. overflow: hidden;
  332. }
  333. .nohide {
  334. position: absolute;
  335. top: 0;
  336. left: 0;
  337. width: 100%;
  338. height: 100%;
  339. pointer-events: none;
  340. z-index: 9999;
  341. }
  342. .card-title {
  343. display: flex;
  344. color: #333;
  345. align-items: center;
  346. justify-content: space-between;
  347. .price {
  348. b {
  349. font-size: 1.6em;
  350. color: $blue;
  351. }
  352. }
  353. }
  354. .price {
  355. b {
  356. color: $blue;
  357. font-size: 1.6em;
  358. }
  359. }
  360. .buyer-info {
  361. .el-form-item {
  362. display: inline-block;
  363. margin-right: 20px;
  364. }
  365. .el-form-item__content {
  366. font-weight: bold;
  367. }
  368. }
  369. .readCard {
  370. position: absolute;
  371. right: 0;
  372. z-index: 0;
  373. display: flex;
  374. width: 80px;
  375. height: 100%;
  376. font-size: 12px;
  377. color: #fff;
  378. cursor: pointer;
  379. align-items: center;
  380. .inner {
  381. display: flex;
  382. height: 80%;
  383. padding: 0 5px;
  384. padding-right: 30px;
  385. background: $blue;
  386. border-radius: 5px;
  387. align-items: center;
  388. }
  389. .wave {
  390. position: absolute;
  391. top: 50%;
  392. left: 50%;
  393. display: none;
  394. width: 20px;
  395. height: 20px;
  396. box-sizing: border-box;
  397. margin-top: -10px;
  398. margin-left: -10px;
  399. background: rgba(255, 255, 255, .384);
  400. border: 1px solid red;
  401. border-radius: 50%;
  402. opacity: 0;
  403. animation: wave infinite linear 1s forwards;
  404. }
  405. .wave2 {
  406. opacity: 0;
  407. animation: wave infinite 2s 1s forwards;
  408. }
  409. .svg-icon {
  410. position: relative;
  411. width: 16px;
  412. height: 16px;
  413. margin-right: 5px;
  414. font-size: 16px;
  415. }
  416. &.active {
  417. .wave {
  418. display: block;
  419. }
  420. .svg-icon {
  421. color: #fff;
  422. }
  423. }
  424. }
  425. @keyframes wave {
  426. 0% {
  427. opacity: 0;
  428. transform: scale(3);
  429. }
  430. 50% {
  431. opacity: .5;
  432. transform: scale(1);
  433. }
  434. 100% {
  435. opacity: 0;
  436. transform: scale(0);
  437. }
  438. }
  439. .dark-btn {
  440. display: flex;
  441. height: 26px;
  442. padding: 0 5px;
  443. margin-left: 10px;
  444. font-size: 12px;
  445. color: #fff;
  446. cursor: pointer;
  447. background: $blue;
  448. border-radius: 5px;
  449. align-items: center;
  450. .svg-icon {
  451. width: 16px;
  452. height: 16px;
  453. margin-right: 5px;
  454. color: #fff;
  455. }
  456. }
  457. .pay-channel-wrap {
  458. display: flex;
  459. margin-left: 20px;
  460. margin-bottom: 10px;
  461. align-items: center;
  462. .text {
  463. display: inline-block;
  464. width: 73px;
  465. padding-bottom: 5px;
  466. }
  467. }
  468. .tags-btn {
  469. flex: 1;
  470. .el-radio.is-bordered+.el-radio.is-bordered {
  471. margin-left: 0;
  472. }
  473. .el-radio--small.is-bordered .el-radio__label {
  474. font-size: 14px;
  475. line-height: 20px;
  476. }
  477. .el-radio.is-bordered.is-checked {
  478. background: #0075ff;
  479. }
  480. .el-radio__input.is-checked+.el-radio__label {
  481. color: #fff;
  482. }
  483. .el-radio.is-bordered {
  484. padding: 5px 10px;
  485. margin: 0px 10px 5px 0;
  486. }
  487. .el-radio__input {
  488. display: none;
  489. }
  490. .el-radio__label {
  491. padding: 0;
  492. }
  493. }
  494. .el-submenu .el-menu-item {
  495. padding: 0 30px;
  496. }
  497. </style>