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.

397 lines
8.1 KiB

6 months ago
6 months ago
  1. <template>
  2. <div class="pda-container">
  3. <!-- 头部栏 -->
  4. <div class="header-bar">
  5. <div class="header-left" @click="$router.back()">
  6. <i class="el-icon-arrow-left"></i>
  7. <span>其他出库</span>
  8. </div>
  9. <div class="header-right" @click="$router.push({ path: '/' })">
  10. 首页
  11. </div>
  12. </div>
  13. <!-- 搜索框 -->
  14. <div class="search-container">
  15. <el-input clearable
  16. v-model="searchCode"
  17. placeholder="请扫描出库单或关联单号"
  18. prefix-icon="el-icon-search"
  19. @keyup.enter.native="handleSearch"
  20. ref="searchInput"
  21. />
  22. </div>
  23. <!-- 出库单列表 -->
  24. <div class="content-area">
  25. <div
  26. v-for="(item, index) in outboundList"
  27. :key="index"
  28. class="outbound-card"
  29. @click="goToOutboundPage(item)"
  30. >
  31. <div class="card-title">
  32. <span class="title-label">出库单号</span>
  33. <span class="title-value">{{ item.outboundNo }}</span>
  34. </div>
  35. <div class="card-details">
  36. <div class="detail-item">
  37. <div class="detail-label">关联订单</div>
  38. <div class="detail-value">{{ item.relatedNo }}</div>
  39. </div>
  40. <div class="detail-item">
  41. <div class="detail-label">标签张数</div>
  42. <div class="detail-value">
  43. <span class="qualified">{{ item.availableLabels }}</span><span class="total">{{ item.totalLabels }}</span>
  44. </div>
  45. </div>
  46. <div class="detail-item">
  47. <div class="detail-label">物料总数</div>
  48. <div class="detail-value">
  49. <span class="qualified">{{ item.availableQty }}</span><span class="total">{{ item.totalQty }}</span>
  50. </div>
  51. </div>
  52. </div>
  53. </div>
  54. <!-- 空状态 -->
  55. <div v-if="outboundList.length === 0 && !loading" class="empty-state">
  56. <i class="el-icon-box"></i>
  57. <p>暂无待出库单据</p>
  58. </div>
  59. <!-- 加载状态 -->
  60. <div v-if="loading" class="loading-state">
  61. <i class="el-icon-loading"></i>
  62. <p>加载中...</p>
  63. </div>
  64. </div>
  65. </div>
  66. </template>
  67. <script>
  68. import { getOtherOutboundList } from "@/api/other-outbound/other-outbound.js";
  69. import { getCurrentWarehouse } from '@/utils'
  70. import moment from 'moment';
  71. export default {
  72. data() {
  73. return {
  74. searchCode: '',
  75. outboundList: [],
  76. loading: false
  77. };
  78. },
  79. methods: {
  80. formatDate(date) {
  81. return date ? moment(date).format('YYYY-MM-DD') : '';
  82. },
  83. // 处理搜索
  84. handleSearch() {
  85. if (this.searchCode.trim()) {
  86. this.searchOutboundList(this.searchCode.trim());
  87. } else {
  88. this.loadOutboundList();
  89. }
  90. },
  91. // 加载其他出库单列表
  92. loadOutboundList() {
  93. const currentWarehouse = getCurrentWarehouse();
  94. if (!currentWarehouse) {
  95. this.$message.error('请先选择仓库');
  96. return;
  97. }
  98. this.loading = true;
  99. const params = {
  100. warehouseId: currentWarehouse,
  101. site: localStorage.getItem('site'),
  102. status: '待出库',
  103. };
  104. getOtherOutboundList(params).then(({ data }) => {
  105. this.loading = false;
  106. if (data && data.code === 0) {
  107. this.outboundList = data.data || [];
  108. } else {
  109. this.$message.error(data.msg || '获取数据失败');
  110. }
  111. }).catch(error => {
  112. this.loading = false;
  113. console.error('获取其他出库单列表失败:', error);
  114. this.$message.error('获取数据失败');
  115. });
  116. },
  117. // 搜索特定出库单
  118. searchOutboundList(searchCode) {
  119. const currentWarehouse = getCurrentWarehouse();
  120. if (!currentWarehouse) {
  121. this.$message.error('请先选择仓库');
  122. return;
  123. }
  124. this.loading = true;
  125. const params = {
  126. warehouseId: currentWarehouse,
  127. searchCode: searchCode,
  128. site: localStorage.getItem('site'),
  129. status: '待出库'
  130. };
  131. getOtherOutboundList(params).then(({ data }) => {
  132. this.loading = false;
  133. if (data && data.code === 0) {
  134. if (data.data.length === 0) {
  135. this.$message.warning('未找到匹配的出库单');
  136. }
  137. this.outboundList = data.data || [];
  138. } else {
  139. this.$message.error(data.msg || '查询失败');
  140. }
  141. }).catch(error => {
  142. this.loading = false;
  143. console.error('搜索失败:', error);
  144. this.$message.error('查询失败');
  145. });
  146. },
  147. // 跳转到出库页面
  148. goToOutboundPage(item) {
  149. this.$router.push({
  150. name: 'otherOutboundDetail',
  151. params: {
  152. buNo: item.buNo,
  153. outboundNo: item.outboundNo,
  154. relatedNo: item.relatedNo
  155. }
  156. });
  157. }
  158. },
  159. mounted() {
  160. // 聚焦搜索框
  161. this.$nextTick(() => {
  162. if (this.$refs.searchInput) {
  163. this.$refs.searchInput.focus();
  164. }
  165. });
  166. // 加载数据
  167. this.loadOutboundList();
  168. }
  169. };
  170. </script>
  171. <style scoped>
  172. .pda-container {
  173. width: 100vw;
  174. height: 100vh;
  175. display: flex;
  176. flex-direction: column;
  177. background: #f5f5f5;
  178. }
  179. /* 头部栏 */
  180. .header-bar {
  181. display: flex;
  182. justify-content: space-between;
  183. align-items: center;
  184. padding: 8px 16px;
  185. background: #17B3A3;
  186. color: white;
  187. height: 40px;
  188. min-height: 40px;
  189. }
  190. .header-left {
  191. display: flex;
  192. align-items: center;
  193. cursor: pointer;
  194. font-size: 16px;
  195. font-weight: 500;
  196. }
  197. .header-left i {
  198. margin-right: 8px;
  199. font-size: 18px;
  200. }
  201. .header-right {
  202. cursor: pointer;
  203. font-size: 16px;
  204. font-weight: 500;
  205. }
  206. /* 搜索容器 */
  207. .search-container {
  208. padding: 12px 16px;
  209. background: white;
  210. }
  211. /* 内容区域 */
  212. .content-area {
  213. flex: 1;
  214. overflow-y: auto;
  215. padding: 12px 16px;
  216. }
  217. /* 出库卡片 */
  218. .outbound-card {
  219. background: white;
  220. border-radius: 8px;
  221. margin-bottom: 12px;
  222. padding: 16px;
  223. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  224. cursor: pointer;
  225. transition: all 0.2s ease;
  226. }
  227. .outbound-card:hover {
  228. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
  229. transform: translateY(-1px);
  230. }
  231. .outbound-card:active {
  232. transform: translateY(0);
  233. }
  234. /* 卡片标题 */
  235. .card-title {
  236. margin-bottom: 12px;
  237. }
  238. .title-label {
  239. font-size: 12px;
  240. color: #666;
  241. display: block;
  242. margin-bottom: 4px;
  243. }
  244. .title-value {
  245. font-size: 16px;
  246. font-weight: bold;
  247. color: #333;
  248. margin-left: 20px;
  249. }
  250. /* 卡片详情 */
  251. .card-details {
  252. display: flex;
  253. justify-content: space-between;
  254. align-items: flex-start;
  255. gap: 4px;
  256. }
  257. .detail-item {
  258. flex: 1;
  259. text-align: center;
  260. min-width: 60px;
  261. max-width: 60px;
  262. }
  263. .detail-label {
  264. font-size: 11px;
  265. color: #666;
  266. margin-bottom: 4px;
  267. line-height: 1.2;
  268. margin-left: -12px;
  269. }
  270. .detail-value {
  271. font-size: 13px;
  272. color: #333;
  273. line-height: 1.2;
  274. margin-left: -12px;
  275. }
  276. .detail-value .qualified {
  277. color: #17B3A3;
  278. font-weight: 500;
  279. }
  280. .detail-value .total {
  281. color: #333;
  282. font-weight: 500;
  283. }
  284. .detail-value .total::before {
  285. content: '/';
  286. color: #333;
  287. }
  288. /* 空状态 */
  289. .empty-state {
  290. display: flex;
  291. flex-direction: column;
  292. align-items: center;
  293. justify-content: center;
  294. padding: 60px 20px;
  295. color: #999;
  296. }
  297. .empty-state i {
  298. font-size: 48px;
  299. margin-bottom: 16px;
  300. }
  301. .empty-state p {
  302. font-size: 14px;
  303. margin: 0;
  304. }
  305. /* 加载状态 */
  306. .loading-state {
  307. display: flex;
  308. flex-direction: column;
  309. align-items: center;
  310. justify-content: center;
  311. padding: 60px 20px;
  312. color: #17B3A3;
  313. }
  314. .loading-state i {
  315. font-size: 24px;
  316. margin-bottom: 12px;
  317. animation: spin 1s linear infinite;
  318. }
  319. @keyframes spin {
  320. from { transform: rotate(0deg); }
  321. to { transform: rotate(360deg); }
  322. }
  323. .loading-state p {
  324. font-size: 14px;
  325. margin: 0;
  326. }
  327. /* 响应式设计 */
  328. @media (max-width: 360px) {
  329. .header-bar {
  330. padding: 8px 12px;
  331. }
  332. .search-container {
  333. padding: 8px 12px;
  334. }
  335. .content-area {
  336. padding: 8px 12px;
  337. }
  338. .outbound-card {
  339. padding: 12px;
  340. }
  341. .card-details {
  342. flex-wrap: wrap;
  343. gap: 6px;
  344. }
  345. .detail-item {
  346. flex: 0 0 48%;
  347. margin-bottom: 6px;
  348. min-width: 50px;
  349. }
  350. }
  351. </style>