materialScanRegister.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. <template>
  2. <gui-page :custom-header="true" :is-header-sized="false"
  3. :header-class="['gui-theme-background-color', isLandscapeScreen?'width: 100vmax;':'']"
  4. :style="[isLandscapeScreen?'width: 100vmax':'']">
  5. <template #gHeader>
  6. <view :style="[isLandscapeScreen?'height:44px;width: 100vmax':'height:44px;']"
  7. class="gui-flex gui-nowrap gui-rows gui-align-items-center">
  8. <text style="font-size:44rpx;" class="gui-header-leader-btns gui-color-white font-icons"
  9. @tap="goBack">&#xe6c5;</text>
  10. <text
  11. class="gui-h4 gui-blod gui-flex1 gui-text-center gui-color-white gui-ellipsis gui-primary-text">来料登记</text>
  12. <view style="width:40px;" />
  13. </view>
  14. </template>
  15. <template #gBody>
  16. <view class="form">
  17. <view class="card-list-flexbox">
  18. <text class="card-list-title" :style="[isPad?'font-size: 18px':'font-size: 14px']">单据信息</text>
  19. <view class="card-list-item">
  20. <text>送货单号</text>
  21. <text>{{ scanParams.deliveryOrderNo }}</text>
  22. </view>
  23. <view class="card-list-item">
  24. <text>供应商编码</text>
  25. <text>{{ scanParams.supplierCode }}</text>
  26. </view>
  27. <view class="card-list-item">
  28. <text>供应商名称</text>
  29. <text>{{ scanParams.supplierName }}</text>
  30. </view>
  31. <view class="card-list-item">
  32. <text>备注</text>
  33. <text>{{ scanParams.remark }}</text>
  34. </view>
  35. <view class="card-list-item">
  36. <text>扫码类型</text>
  37. <text>{{ scanTypeLabel }}</text>
  38. </view>
  39. </view>
  40. <view class="row">
  41. <view class="row-card">
  42. <uni-data-select v-model="scanParams.scanType" :localdata="scanTypeList" placeholder="请选择扫码类型" />
  43. </view>
  44. </view>
  45. <view class="row">
  46. <view class="row-card">
  47. <uni-easyinput ref="easyinput" v-model="scanParams.deliveryOrderNo" :input-border="false"
  48. :clearable="false" type="text" focus @focus="handleInputFocus" placeholder="扫描送货单条码"
  49. @confirm="confirmDeliverOrderNo" />
  50. <text class="font-icons" @click="handleMapass"></text>
  51. </view>
  52. </view>
  53. <view class="table-title">
  54. <span>需求清单</span>
  55. </view>
  56. <view class="custom-table">
  57. <uni-table border stripe empty-text="暂无更多数据">
  58. <uni-tr class="custom-table-head">
  59. <uni-th align="center" width="80px">箱数</uni-th>
  60. <uni-th align="center" width="80px">每箱数量</uni-th>
  61. <uni-th align="center" width="80px">总数量</uni-th>
  62. <uni-th align="center" width="140px">采购单号</uni-th>
  63. <uni-th align="center" width="140px">物料编码</uni-th>
  64. <uni-th align="center" width="140px">物料名称</uni-th>
  65. <uni-th align="center" width="140px">送货批次</uni-th>
  66. <uni-th align="center" width="180px">生产日期</uni-th>
  67. </uni-tr>
  68. <uni-tr v-for="(item, key) in scanParams.detail" :key="key">
  69. <uni-td align="center"
  70. :style="item.state? 'background-color: rgba(109, 205, 50, 1);color: white;': ''">
  71. <uni-easyinput v-model="item.bagQty" type="number" :input-border="false" placeholder="请输入箱数" @input="handleBagQtyChange" :disabled="true" />
  72. </uni-td>
  73. <uni-td align="center"
  74. :style="item.state? 'background-color: rgba(109, 205, 50, 1);color: white;': ''">{{ item.receiptQty }}</uni-td>
  75. <uni-td align="center"
  76. :style="item.state? 'background-color: rgba(109, 205, 50, 1);color: white;': ''">{{ calculateTotalQty(item) }}</uni-td>
  77. <uni-td align="center"
  78. :style="item.state? 'background-color: rgba(109, 205, 50, 1);color: white;': ''">{{ item.purchaseOrderNo }}</uni-td>
  79. <uni-td align="center"
  80. :style="item.state? 'background-color: rgba(109, 205, 50, 1);color: white;': ''">{{ item.materialNo }}</uni-td>
  81. <uni-td align="center"
  82. :style="item.state? 'background-color: rgba(109, 205, 50, 1);color: white;': ''">{{ item.name }}</uni-td>
  83. <uni-td align="center"
  84. :style="item.state? 'background-color: rgba(109, 205, 50, 1);color: white;': ''">{{ item.deliverBatch }}</uni-td>
  85. <uni-td align="center"
  86. :style="item.state? 'background-color: rgba(109, 205, 50, 1);color: white;': ''">
  87. <uni-datetime-picker
  88. v-model="item.produceDate"
  89. type="date"
  90. :border="false"
  91. placeholder="选择日期" />
  92. </uni-td>
  93. </uni-tr>
  94. </uni-table>
  95. </view>
  96. <gui-right-menus>
  97. <template #menus-more>
  98. <view hover-class="gui-tap"
  99. class="menu-items gui-bg-green gui-flex gui-columns gui-justify-content-center"
  100. @click="handeleRegister">
  101. <text class="menu-text gui-block gui-text-center gui-color-white">登记</text>
  102. </view>
  103. <view hover-class="gui-tap"
  104. class="menu-items gui-bg-blue gui-flex gui-columns gui-justify-content-center"
  105. @click="handleNavigateToRegisterRecord">
  106. <text class="menu-text gui-block gui-text-center gui-color-white">登记记录</text>
  107. </view>
  108. </template>
  109. <template #menus-primary>
  110. <view class="menu-items gui-bg-primary gui-flex gui-columns gui-justify-content-center">
  111. <text class="menu-icon gui-color-white gui-block gui-text-center gui-icons"></text>
  112. <text class="menu-text gui-color-white gui-block gui-text-center">操作</text>
  113. </view>
  114. </template>
  115. </gui-right-menus>
  116. <uni-popup ref="modalForm" type="dialog">
  117. <uni-popup-dialog type="error" cancel-text="不使用" confirm-text="继续使用" title="提示" content="此物料已过保质期!"
  118. @confirm="handleCompleteDialog" @close="handleCloseDialog" />
  119. </uni-popup>
  120. <uni-popup ref="errorTip" type="dialog">
  121. <uni-popup-dialog type="error" cancel-text="关闭" confirm-text="确认" title="提示"
  122. :content="errorTipMessage" @confirm="handleCloseErrorTipsModal"
  123. @close="handleCloseErrorTipsModal" />
  124. </uni-popup>
  125. </view>
  126. </template>
  127. </gui-page>
  128. </template>
  129. <script>
  130. import {
  131. defineComponent,
  132. ref,
  133. computed,
  134. onMounted
  135. } from 'vue'
  136. export default defineComponent({
  137. setup() {
  138. const modalForm = ref('')
  139. const errorTip = ref('')
  140. const errorTipMessage = ref('')
  141. const easyinput = ref('')
  142. const easyinput2 = ref('')
  143. const errorState = ref(0)
  144. const fdIndex = ref(0)
  145. const scanParams = ref({
  146. deliveryOrderNo: '',
  147. supplierCode: '',
  148. supplierName: '',
  149. materialUrl:'',
  150. reportUrl:'',
  151. remark: '',
  152. scanType: '',
  153. deliverBatch: '',
  154. validateFlag: -1,
  155. detail: []
  156. })
  157. const scanTypeList = ref([])
  158. // ========== 送货单扫码(改用 uni.scanCode)==========
  159. const handleMapass = function() {
  160. if (!scanParams.value.scanType) {
  161. uni.showToast({ title: '请先选择扫码类型', icon: 'none' });
  162. return;
  163. }
  164. uni.scanCode({
  165. success: function(res) {
  166. const deliveryOrderNo = res.result;
  167. uni.$reqGet('scanDeliveryOrderNo', {
  168. deliveryOrderNo: deliveryOrderNo,
  169. tableName: scanParams.value.scanType
  170. })
  171. .then(({ code, data, msg }) => {
  172. if (code === 0) {
  173. Object.assign(scanParams.value, data);
  174. scanParams.value.detail.forEach(item => {
  175. if (item.bagQty == null || item.bagQty === '') item.bagQty = 1;
  176. });
  177. setInputFocus2();
  178. } else {
  179. // #ifdef APP-PLUS
  180. plus.device.beep(2);
  181. // #endif
  182. errorTipMessage.value = msg;
  183. errorTip.value.open();
  184. errorState.value = 0;
  185. }
  186. });
  187. },
  188. fail: function(err) {
  189. console.log('扫码失败', err);
  190. uni.showToast({ title: '扫码失败', icon: 'none' });
  191. }
  192. });
  193. }
  194. // 扫描送货单输入框回车事件
  195. const confirmDeliverOrderNo = function(e) {
  196. uni.$reqGet('scanDeliveryOrderNo', {
  197. deliveryOrderNo: e,
  198. tableName: scanParams.value.scanType,
  199. })
  200. .then(({
  201. code,
  202. data,
  203. msg
  204. }) => {
  205. if (code === 0) {
  206. Object.assign(scanParams.value, data)
  207. scanParams.value.detail.forEach(item => {
  208. if (item.bagQty == null || item.bagQty === '') item.bagQty = 1
  209. })
  210. setInputFocus2()
  211. } else {
  212. // #ifdef APP-PLUS
  213. plus.device.beep(2)
  214. // #endif
  215. errorTipMessage.value = msg
  216. errorTip.value.open()
  217. errorState.value = 0
  218. }
  219. })
  220. }
  221. // ========== 物料扫码(同样改用 uni.scanCode)==========
  222. const handleScanMaterial = function() {
  223. uni.scanCode({
  224. success: function(res) {
  225. uni.$reqGet('scanRegisterMaterial', {
  226. batchNumber: res.result
  227. })
  228. .then(({ code, data, msg }) => {
  229. scanParams.value.deliverBatch = data?.deliverBatch
  230. if (code === 0) {
  231. fdIndex.value = scanParams.value.detail.findIndex(item => item?.deliverBatch === data?.deliverBatch)
  232. if (fdIndex.value !== -1) {
  233. if (data?.ifExpired === 1) {
  234. modalForm.value.open()
  235. } else {
  236. setInputFocus2()
  237. scanParams.value.detail[fdIndex.value].state = true
  238. }
  239. } else {
  240. // #ifdef APP-PLUS
  241. plus.device.beep(2)
  242. // #endif
  243. errorTipMessage.value = '请扫描正确的物料'
  244. errorTip.value.open()
  245. errorState.value = 1
  246. }
  247. } else {
  248. // #ifdef APP-PLUS
  249. plus.device.beep(2)
  250. // #endif
  251. errorTipMessage.value = msg
  252. errorTip.value.open()
  253. errorState.value = 1
  254. }
  255. })
  256. },
  257. fail: function(err) {
  258. console.log('扫码失败', err)
  259. uni.showToast({ title: '扫码失败', icon: 'none' })
  260. }
  261. })
  262. }
  263. // 扫描物料输入框回车事件
  264. const confirmMaterial = function(e) {
  265. uni.$reqGet('scanRegisterMaterial', {
  266. batchNumber: e
  267. })
  268. .then(({
  269. code,
  270. data,
  271. msg
  272. }) => {
  273. scanParams.value.deliverBatch = data?.deliverBatch
  274. if (code === 0) {
  275. fdIndex.value = scanParams.value.detail.findIndex(item => item
  276. ?.deliverBatch ===
  277. data?.deliverBatch)
  278. if (fdIndex.value !== -1) {
  279. if (data?.ifExpired === 1) {
  280. modalForm.value.open()
  281. } else {
  282. setInputFocus2()
  283. scanParams.value.detail[fdIndex.value].state = true
  284. }
  285. } else {
  286. // #ifdef APP-PLUS
  287. plus.device.beep(2)
  288. // #endif
  289. errorTipMessage.value = '请扫描正确的物料'
  290. errorTip.value.open()
  291. errorState.value = 1
  292. }
  293. } else {
  294. // #ifdef APP-PLUS
  295. plus.device.beep(2)
  296. // #endif
  297. errorTipMessage.value = msg
  298. errorTip.value.open()
  299. errorState.value = 1
  300. }
  301. })
  302. }
  303. const handleNavigateToRegisterRecord = function() {
  304. uni.navigateTo({
  305. url: '/pages/workbranch/warehouse/materialRegister/Record/registerRecord'
  306. })
  307. }
  308. // 登记
  309. const handeleRegister = function() {
  310. let isTrue = false
  311. if (scanParams.value.detail.length === 0) {
  312. // #ifdef APP-PLUS
  313. plus.device.beep(2)
  314. // #endif
  315. errorTipMessage.value = '登记数据不能为空'
  316. errorTip.value.open()
  317. errorState.value = 0
  318. return
  319. }
  320. if (scanParams.value.validateFlag === 0) {
  321. isTrue = true
  322. } else {
  323. isTrue = scanParams.value.detail.every(item => item.state === true)
  324. }
  325. if (isTrue) {
  326. uni.showLoading({
  327. title: '数据请求中',
  328. duration: 20000,
  329. mask: true
  330. })
  331. const requestParams = JSON.parse(JSON.stringify(scanParams.value))
  332. requestParams.detail.forEach(item => {
  333. if (item.produceDate) {
  334. item.produceDate = new Date(item.produceDate).getTime()
  335. }
  336. })
  337. uni.$reqPost('incomingReceiptMasterCreate', requestParams)
  338. .then(({
  339. code,
  340. data,
  341. msg
  342. }) => {
  343. scanParams.value = {
  344. deliveryOrderNo: '',
  345. supplierCode: '',
  346. supplierName: '',
  347. materialUrl:'',
  348. reportUrl:'',
  349. remark: '',
  350. scanType: '',
  351. deliverBatch: '',
  352. validateFlag: -1,
  353. detail: []
  354. }
  355. if (code === 0) {
  356. uni.showToast({
  357. title: '来料登记成功',
  358. icon: 'none',
  359. duration: 2000
  360. })
  361. } else {
  362. // #ifdef APP-PLUS
  363. plus.device.beep(2)
  364. // #endif
  365. errorTipMessage.value = msg
  366. errorTip.value.open()
  367. errorState.value = -1
  368. }
  369. })
  370. .finally(() => {
  371. uni.hideLoading()
  372. })
  373. } else {
  374. // #ifdef APP-PLUS
  375. plus.device.beep(2)
  376. // #endif
  377. errorTipMessage.value = '请填写完整需求清单'
  378. errorTip.value.open()
  379. errorState.value = 1
  380. }
  381. }
  382. const handleCompleteDialog = function() {
  383. setInputFocus2()
  384. scanParams.value.detail[fdIndex.value].state = true
  385. modalForm.value.close()
  386. }
  387. const handleCloseDialog = function() {
  388. setInputFocus2()
  389. modalForm.value.close()
  390. }
  391. const goBack = function() {
  392. uni.$goBack('/pages/workbranch/warehouse/materialRegister/registerType')
  393. }
  394. const setInputFocus = function() {
  395. scanParams.value.deliveryOrderNo = ''
  396. easyinput.value.onBlur()
  397. easyinput.value.onFocus()
  398. }
  399. const setInputFocus2 = function() {
  400. scanParams.value.deliverBatch = ''
  401. easyinput2.value.onBlur()
  402. easyinput2.value.onFocus()
  403. }
  404. const handleCloseErrorTipsModal = async function() {
  405. errorTip.value.close()
  406. if (errorState.value === 0) {
  407. await setInputFocus()
  408. } else if (errorState.value === 1) {
  409. await setInputFocus2()
  410. }
  411. }
  412. const calculateTotalQty = function(item) {
  413. const bagQty = item.bagQty || 1
  414. const receiptQty = item.receiptQty || 0
  415. return bagQty * receiptQty
  416. }
  417. const handleBagQtyChange = function() {}
  418. const handleInputFocus = function() {
  419. setTimeout(() => {
  420. uni.hideKeyboard()
  421. }, 100)
  422. }
  423. const scanTypeLabel = computed(() => {
  424. if (!scanParams.value.scanType) return '未选择'
  425. const typeItem = scanTypeList.value.find(item => item.value === scanParams.value.scanType)
  426. return typeItem ? typeItem.text : scanParams.value.scanType
  427. })
  428. onMounted(() => {
  429. uni.$reqGet('getDictDataPage', {
  430. dictType: 'srm_tablename_type',
  431. pageNo: 1,
  432. pageSize: 100
  433. }).then(({ data }) => {
  434. scanTypeList.value = []
  435. const dataList = data?.list || [];
  436. for (var i = 0; i < dataList.length; i++) {
  437. scanTypeList.value.push({
  438. text: dataList[i].label,
  439. value: dataList[i].value,
  440. })
  441. }
  442. })
  443. })
  444. return {
  445. goBack,
  446. modalForm,
  447. easyinput,
  448. easyinput2,
  449. errorState,
  450. errorTip,
  451. errorTipMessage,
  452. scanParams,
  453. scanTypeList,
  454. scanTypeLabel,
  455. handleMapass,
  456. handleInputFocus,
  457. handleCompleteDialog,
  458. handleCloseDialog,
  459. handleScanMaterial,
  460. handeleRegister,
  461. confirmMaterial,
  462. confirmDeliverOrderNo,
  463. handleCloseErrorTipsModal,
  464. handleNavigateToRegisterRecord,
  465. calculateTotalQty,
  466. handleBagQtyChange
  467. }
  468. }
  469. })
  470. </script>
  471. <style lang="scss" scoped>
  472. .gui-header-leader-btns {
  473. color: black;
  474. font-size: 24px !important;
  475. }
  476. .gui-sbody {
  477. background-color: rgba(234, 239, 242, 1);
  478. }
  479. .form {
  480. margin-top: 85px;
  481. font-size: 14px;
  482. }
  483. .row {
  484. height: 55px;
  485. display: flex;
  486. justify-content: center;
  487. padding-left: 20px;
  488. padding-right: 20px;
  489. margin: 10px 0;
  490. background-color: white;
  491. .row-card {
  492. display: flex;
  493. flex-direction: row;
  494. justify-content: space-between;
  495. align-items: center;
  496. width: calc(375px - 30px);
  497. }
  498. }
  499. .input-200 {
  500. width: 200px;
  501. padding-left: 10px;
  502. }
  503. .font-icons {
  504. width: 40px;
  505. font-size: 20px;
  506. text-align: right;
  507. }
  508. .card-list-flexbox {
  509. width: calc(100vw - 24px);
  510. height: 195px;
  511. margin: 0 12px;
  512. display: flex;
  513. justify-content: center;
  514. flex-direction: column;
  515. align-items: center;
  516. overflow-y: scroll;
  517. .card-list-title {
  518. width: 100%;
  519. height: 35px;
  520. line-height: 35px;
  521. margin: 0 4px 0 4px;
  522. border-radius: 4px 4px 0 0;
  523. text-align: center;
  524. color: white;
  525. background-color: rgba(0, 160, 233, 1.0);
  526. }
  527. .card-list-item,
  528. .card-list-item-operation {
  529. width: 100%;
  530. height: 35px;
  531. margin: 0 4px 3rpx 4px;
  532. border-radius: 4px;
  533. display: flex;
  534. flex-direction: row;
  535. align-items: center;
  536. justify-content: space-between;
  537. background-color: #fff;
  538. uni-text {
  539. font-size: 14px;
  540. height: 50rpx;
  541. text-align: left;
  542. padding: 0 8px;
  543. display: flex;
  544. flex-direction: row;
  545. align-items: center;
  546. }
  547. .text-1 {
  548. flex: 1;
  549. height: 35px;
  550. justify-content: flex-start;
  551. }
  552. .text-2 {
  553. flex: 3;
  554. height: 35px;
  555. justify-content: flex-end;
  556. margin-right: 4px;
  557. padding: 2px 6px;
  558. }
  559. }
  560. }
  561. .table-title {
  562. height: 40px;
  563. line-height: 40px;
  564. margin: 4px 0 -3px 0;
  565. padding: 0 12px;
  566. font-size: 16px;
  567. font-weight: bold;
  568. background-color: white;
  569. }
  570. .custom-table {
  571. height: calc(100vh - 405px);
  572. min-height: 230px;
  573. margin: 5px 0;
  574. overflow-y: scroll;
  575. }
  576. </style>