SemiFinishedProtuctsSign.vue 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. <template>
  2. <gui-page :custom-header="true" :header-class="['gui-theme-background-color']">
  3. <template #gHeader>
  4. <view style="height:44px;" class="gui-flex gui-nowrap gui-rows gui-align-items-center">
  5. <!-- 使用组件实现返回按钮及返回首页按钮 -->
  6. <text style="font-size:44rpx;" class="gui-header-leader-btns gui-color-white font-icons"
  7. @tap="goBack">&#xe6c5;</text>
  8. <!-- 导航文本此处也可以是其他自定义内容 -->
  9. <text class="gui-flex1 gui-text-center gui-color-white">半成品签收【签收人:{{ scanPersonName }}】</text>
  10. <!-- 此处加一个右侧展位元素与左侧同宽,实现标题居中 -->
  11. <!-- 实际宽度请根据自己情况设置 -->
  12. <view style="width:40px;">
  13. <uni-easyinput v-model="batchNumber" type="text" class="hidden-focus" ref="scanRefs" focus @confirm="handleConfirmText" />
  14. </view>
  15. <!-- 如果右侧有其他内容可以利用条件编译和定位来实现-->
  16. </view>
  17. </template>
  18. <template #gBody>
  19. <view class="list-content">
  20. <div class="operation-header">
  21. <view class="operation-header-item">
  22. <text>条码号</text>
  23. <text>{{ formData.batchNumber }}</text>
  24. </view>
  25. <view class="operation-header-item">
  26. <text>产品名称</text>
  27. <text>{{ formData.productName }}</text>
  28. </view>
  29. <view class="operation-header-item">
  30. <text>条码数/已扫入总数</text>
  31. <text>{{ computedSumQty }}</text>
  32. </view>
  33. <view v-if="!scanPersonId" class="operation-header-item-tips">
  34. <text><text class="font-icons">&#xe6d6;</text>请扫描签收人员厂牌完成签收</text>
  35. </view>
  36. <view v-else class="operation-header-item-tips-success">
  37. <text><text class="font-icons">&#xe6d6;</text>已扫描员工码,可进行签收</text>
  38. </view>
  39. </div>
  40. <view class="collapsed-panel">
  41. <div class="collapsed-title">
  42. <text><text class="font-icons">&#xe6da;</text>已签收列表</text>
  43. </div>
  44. <template v-if="cardList.length > 0">
  45. <div class="collapsed-item" v-for="item in cardList" :key="item.id"
  46. @click="handleShowDetail(item)">
  47. <text>{{ item.batchNumber }}/ {{ item.productName }}/ {{ item.boxQty }} PCS</text>
  48. </div>
  49. </template>
  50. <view v-else>
  51. <view class="bg-image">
  52. <image src="@/static/empty.png" mode="heightFix" />
  53. <text>这里什么都没有...</text>
  54. </view>
  55. </view>
  56. </view>
  57. </view>
  58. <uni-popup ref="errorTip" type="dialog">
  59. <uni-popup-dialog type="error" cancel-text="关闭" confirm-text="确认" title="提示" :content="errorTipMessage"
  60. @confirm="handleCloseErrorTipsModal" @close="handleCloseErrorTipsModal" />
  61. </uni-popup>
  62. </template>
  63. </gui-page>
  64. </template>
  65. <script>
  66. import {
  67. computed,
  68. reactive,
  69. defineComponent,
  70. onBeforeMount,
  71. toRefs,
  72. ref
  73. } from 'vue'
  74. import tsc from '@/unit/CHITEN_SDK_APP/tsc.js'
  75. import {
  76. onMounted
  77. } from 'vue';
  78. export default defineComponent({
  79. setup(options) {
  80. const errorState = ref(0)
  81. const errorTip = ref('')
  82. const errorTipMessage = ref('')
  83. const formData = ref({
  84. batchNumber: null,
  85. productName: null,
  86. boxQty: 0,
  87. sumQty: 0
  88. })
  89. const cardList = ref([])
  90. // 隐藏输入框
  91. const scanRefs = ref()
  92. const queryParams = reactive({
  93. batchNumber: '',
  94. scanPersonId: null,
  95. scanPersonName: '未绑定',
  96. })
  97. // 条码数/总数
  98. const computedSumQty = computed(() => {
  99. return formData.value.boxQty + '/' + formData.value.sumQty + ' PCS'
  100. })
  101. onMounted(() => {
  102. // 每3s自动定位到扫码框
  103. setInterval(() => {
  104. if (scanRefs.value.focusShow) {
  105. // #ifdef APP-PLUS
  106. setTimeout(() => {
  107. uni.hideKeyboard()
  108. }, 100)
  109. // #endif
  110. } else {
  111. scanRefs.value.onBlur()
  112. scanRefs.value.onFocus()
  113. }
  114. }, 1000)
  115. })
  116. // 获取签收列表
  117. const search = function() {
  118. uni.$reqGet('getProductMiddleDetailPage', {
  119. signStatus: 1,
  120. signPersonId: queryParams.scanPersonId,
  121. })
  122. .then(async ({
  123. code,
  124. data,
  125. msg
  126. }) => {
  127. if (code === 0) {
  128. cardList.value = data?.list ?? [];
  129. } else {
  130. // #ifdef APP-PLUS
  131. plus.device.beep(2)
  132. // #endif
  133. errorTipMessage.value = msg
  134. errorTip.value.open()
  135. errorState.value = 0
  136. }
  137. })
  138. }
  139. const goBack = function() {
  140. uni.$goBack('/pages/workbranch/warehouse/SemiFinishedProducts/indexPage')
  141. }
  142. const handleScanProductMiddle = function() {
  143. uni.$reqPost("scanProductMiddleDetailSign", {
  144. batchNumber: queryParams.batchNumber,
  145. signPersonId: queryParams.scanPersonId,
  146. signPerson: queryParams.scanPersonName
  147. })
  148. .then(async ({
  149. code,
  150. data,
  151. msg
  152. }) => {
  153. if (code === 0) {
  154. search()
  155. setInputFocus()
  156. } else {
  157. // #ifdef APP-PLUS
  158. plus.device.beep(2)
  159. // #endif
  160. errorTipMessage.value = msg
  161. errorTip.value.open()
  162. errorState.value = -1
  163. }
  164. })
  165. }
  166. const handleConfirmText = function(e) {
  167. // 扫码签收
  168. if (queryParams.scanPersonId && queryParams.scanPersonName) {
  169. // 存在员工码,扫码签收
  170. handleScanProductMiddle(e)
  171. } else {
  172. uni.$reqGet("getEmployeeMaster", {
  173. id: e
  174. })
  175. .then(async ({
  176. code,
  177. data,
  178. msg
  179. }) => {
  180. if (code === 0) {
  181. // 绑定员工
  182. if (!!data) {
  183. queryParams.scanPersonId = data.id
  184. queryParams.scanPersonName = data.employeeName
  185. search()
  186. setInputFocus()
  187. }
  188. } else {
  189. // #ifdef APP-PLUS
  190. plus.device.beep(2)
  191. // #endif
  192. errorTipMessage.value = '员工码不正确,请检查!'
  193. errorTip.value.open()
  194. errorState.value = -1
  195. }
  196. })
  197. }
  198. }
  199. // 详情
  200. const handleShowDetail = function(ret) {
  201. Object.assign(formData.value, ret)
  202. }
  203. // 禁用软键盘
  204. const handleInputFocus = function() {
  205. // #ifdef APP-PLUS
  206. setTimeout(() => {
  207. uni.hideKeyboard()
  208. }, 100)
  209. // #endif
  210. }
  211. const setInputFocus = function() {
  212. queryParams.batchNumber = ''
  213. scanRefs.value.onBlur()
  214. scanRefs.value.onFocus()
  215. }
  216. // 关闭错误信息弹窗
  217. const handleCloseErrorTipsModal = async function() {
  218. errorTip.value.close()
  219. if (errorState.value === 0) {
  220. await setInputFocus()
  221. }
  222. }
  223. return {
  224. options: [{
  225. text: '删除',
  226. style: {
  227. backgroundColor: '#dd524d'
  228. }
  229. }],
  230. scanRefs,
  231. ...toRefs(queryParams),
  232. formData,
  233. cardList,
  234. goBack,
  235. errorTip,
  236. computedSumQty,
  237. handleShowDetail,
  238. errorTipMessage,
  239. handleInputFocus,
  240. handleConfirmText,
  241. handleCloseErrorTipsModal,
  242. }
  243. }
  244. })
  245. </script>
  246. <style lang="scss" scoped>
  247. .gui-header-leader-btns {
  248. color: black;
  249. margin-left: 24rpx;
  250. font-size: 24px !important;
  251. }
  252. .list-content {
  253. margin-top: 68px;
  254. min-height: calc(100vh - 68px);
  255. position: relative;
  256. background-color: #edeeee;
  257. }
  258. .input-200 {
  259. width: 200px;
  260. padding-left: 10px;
  261. }
  262. .icon-scan {
  263. font-size: 20px;
  264. text-align: right;
  265. }
  266. .scan {
  267. height: 45px;
  268. width: calc(100% - 48px);
  269. margin: 12px;
  270. padding: 0 12px;
  271. display: flex;
  272. justify-content: space-between;
  273. align-items: center;
  274. border-radius: 6px;
  275. background-color: white;
  276. .scan-card {
  277. width: 100%;
  278. display: grid;
  279. grid-template-rows: 1fr;
  280. grid-template-columns: 7fr 2fr;
  281. align-items: center;
  282. input {
  283. height: 35px;
  284. line-height: 35px;
  285. }
  286. text {
  287. width: 100%;
  288. text-align: right;
  289. }
  290. }
  291. }
  292. span,
  293. text {
  294. font-size: 12px;
  295. }
  296. .collapsed-panel {
  297. // height: calc(100vh - 190px);
  298. width: calc(100vw - 24px);
  299. min-height: 230px;
  300. position: absolute;
  301. top: 105px;
  302. // bottom: 70px;
  303. bottom: 0px;
  304. padding: 0 12px;
  305. border-radius: 15px 15px 0 0;
  306. background-color: white;
  307. overflow-y: scroll;
  308. .collapsed-title {
  309. font-size: 14px;
  310. font-weight: bold;
  311. padding: 8px;
  312. position: sticky;
  313. top: 0;
  314. left: 0;
  315. width: calc(100% - 12px);
  316. z-index: 1;
  317. background-color: white;
  318. }
  319. .collapsed-item {
  320. display: flex;
  321. justify-content: space-between;
  322. align-items: center;
  323. padding: 8px;
  324. margin: 4px 0;
  325. border-radius: 4px;
  326. background-color: #f3f3f3;
  327. .font-icons {
  328. font-size: 14px;
  329. }
  330. }
  331. .collapsed-title+uni-view:nth-of-type(1) {
  332. margin-top: 8px;
  333. }
  334. }
  335. .operation-panel {
  336. padding: 12px 0;
  337. position: fixed;
  338. bottom: 0;
  339. width: 100%;
  340. display: grid;
  341. grid-template-columns: 1fr;
  342. grid-template-rows: 1fr;
  343. background-color: white;
  344. .operation-title {
  345. height: 40px;
  346. line-height: 40px;
  347. padding: 0 14px;
  348. font-size: 16px;
  349. font-weight: bold;
  350. }
  351. }
  352. .hidden-focus {
  353. position: fixed;
  354. top: 0;
  355. left: 0;
  356. z-index: -1;
  357. opacity: 0;
  358. }
  359. .operation-header {
  360. height: 130px;
  361. background-color: #4badf4;
  362. .operation-header-item {
  363. display: flex;
  364. flex-direction: row;
  365. justify-content: space-between;
  366. align-items: center;
  367. padding: 4px 12px;
  368. font-size: 12px;
  369. color: white;
  370. }
  371. .operation-header-item-tips {
  372. display: flex;
  373. flex-direction: row;
  374. justify-content: center;
  375. align-items: center;
  376. padding: 2px 12px;
  377. font-size: 14px;
  378. font-weight: bold;
  379. color: gold;
  380. }
  381. .operation-header-item-tips-success {
  382. display: flex;
  383. flex-direction: row;
  384. justify-content: center;
  385. align-items: center;
  386. padding: 2px 12px;
  387. font-size: 14px;
  388. font-weight: bold;
  389. color: lightgreen;
  390. }
  391. }
  392. </style>