InConfirm.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. <!-- 还料入库 -->
  2. <template>
  3. <div class="page-container">
  4. <!-- 顶部信息栏 -->
  5. <PageHeader title="还料入库" />
  6. <!-- 主内容区域 -->
  7. <main class="main-content">
  8. <!-- 页面标题 -->
  9. <div class="page-header-row">
  10. <van-button type="primary" @click="verify">
  11. <i class="fas fa-sync-alt mr-1" /> 重新校验
  12. </van-button>
  13. </div>
  14. <!-- 卡片容器 -->
  15. <div class="card-container">
  16. <!-- 卡片列表区域 -->
  17. <div class="card-list-wrapper">
  18. <van-empty v-if="materialList.length === 0" description="暂无数据" />
  19. <!-- 卡片列表 -->
  20. <div v-else class="card-list">
  21. <div
  22. v-for="(item, index) in materialList" :key="item.id || index" :class="getCardClass(item.remarks)"
  23. class="inventory-card"
  24. >
  25. <div class="card-header">
  26. <div class="card-header-left">
  27. <div class="custom-avatar">
  28. <!-- :style="{ backgroundColor: getStatusColor(item.remarks) }" -->
  29. <i :class="getInventoryIcon(item.inventoryType)" />
  30. </div>
  31. <div class="ml-4 card-title-info">
  32. <div class="card-name">{{ item.inventoryName }}</div>
  33. <div class="card-subtitle">编号: {{ item.inventoryNo }}</div>
  34. </div>
  35. </div>
  36. <div class="card-header-right">
  37. <div class="card-location">
  38. <i class="fas fa-map-marker-alt mr-2" />
  39. <span>{{ item.positionName || '-' }}</span>
  40. <span class="mx-2">/</span>
  41. <span>{{ item.remarks || '-' }}</span>
  42. </div>
  43. </div>
  44. </div>
  45. </div>
  46. </div>
  47. </div>
  48. <!-- 分页区域(固定底部) -->
  49. <div v-if="materialList.length > 0" class="pagination-wrapper">
  50. <span class="text-gray-600">共 {{ materialList.length }} 条数据</span>
  51. </div>
  52. </div>
  53. </main>
  54. <!-- 底部完成按钮 -->
  55. <div class="bottom-actions">
  56. <van-button
  57. type="primary" size="large" :disabled="notInStockCount === 0" class="submit-btn"
  58. @click="handleComplete"
  59. >
  60. <i class="fas fa-check-circle mr-2" />
  61. 还料入库
  62. </van-button>
  63. </div>
  64. </div>
  65. <Loading v-if="loading" />
  66. </template>
  67. <script setup>
  68. import { useRouter } from 'vue-router';
  69. import { showNotify } from 'vant';
  70. import PageHeader from '../common/PageHeader.vue';
  71. import { ref, reactive, onMounted, computed } from 'vue';
  72. import { cfStockIn, createStockIn, cfStockInLeave } from '../api/stockIn.js';
  73. const router = useRouter();
  74. // 表格加载状态
  75. const loading = ref(false);
  76. // 物料列表数据
  77. const materialList = ref([]);
  78. // 分页配置
  79. const pagination = reactive({
  80. start: 1,
  81. lang: 10,
  82. total: 0,
  83. });
  84. // 计算不在库的数量
  85. const notInStockCount = computed(() => {
  86. return materialList.value.filter(item => item.remarks === '不在库').length;
  87. });
  88. // 根据 remarks 返回卡片样式类
  89. const getCardClass = remarks => {
  90. if (remarks === '不在库') {
  91. return 'not-in-stock-card';
  92. } else if (remarks === '在库') {
  93. return 'in-stock-card';
  94. }
  95. return '';
  96. };
  97. // 获取设备类型图标
  98. const getInventoryIcon = type => {
  99. const iconMap = {
  100. '工装': 'fas fa-cube',
  101. '设备': 'fas fa-cogs',
  102. '成品': 'fas fa-box',
  103. };
  104. return iconMap[type] || 'fas fa-cube';
  105. };
  106. // 获取状态颜色
  107. // const getStatusColor = remarks => {
  108. // if (remarks === '不在库') {
  109. // return '#3b82f6'; // 蓝色 - 需要入库
  110. // } else if (remarks === '在库') {
  111. // return '#10b981'; // 绿色 - 已在库
  112. // }
  113. // return '#6b7280'; // 灰色 - 默认
  114. // };
  115. // 还料入库
  116. const handleComplete = async () => {
  117. // 只处理不在库的数据
  118. const notInStockItems = materialList.value.filter(item => item.remarks === '不在库');
  119. if (notInStockItems.length === 0) {
  120. showNotify({ type: 'warning', message: '没有需要入库的物料!' });
  121. return;
  122. }
  123. const params = [];
  124. notInStockItems.forEach(item => {
  125. if (item.remarks === '不在库') {
  126. params.push({
  127. inventoryId: item.inventoryId,
  128. });
  129. }
  130. });
  131. console.log('提交参数:', params);
  132. await generateCFStockIn(params);
  133. };
  134. // 校验
  135. const verify = () => {
  136. getList();
  137. };
  138. // 获取物料列表(外侧校验)
  139. const getList = async () => {
  140. loading.value = true;
  141. try {
  142. const res = await cfStockIn();
  143. if (res.errorCode === 0) {
  144. if (res.datas && res.datas.length > 0) {
  145. materialList.value = res.datas;
  146. pagination.total = materialList.value.length;
  147. } else {
  148. materialList.value = [];
  149. }
  150. } else {
  151. showNotify({ type: 'warning', message: res.errorMessage });
  152. }
  153. } catch (error) {
  154. console.error('获取物料列表API调用失败:', error);
  155. showNotify({ type: 'danger', message: '获取物料列表API调用失败' });
  156. } finally {
  157. loading.value = false;
  158. }
  159. };
  160. // 获取物料列表(内侧校验)
  161. const getInnerList = async () => {
  162. loading.value = true;
  163. try {
  164. const res = await cfStockInLeave();
  165. if (res.errorCode === 0) {
  166. if (res.datas && res.datas.length > 0) {
  167. materialList.value = res.datas;
  168. pagination.total = materialList.value.length;
  169. showNotify({ type: 'warning', message: '检测到您已携带工装设备,请将工装设备全部还料后,再次点击【重新校验】按钮,待校验通过后,请在闸机开门后离开', duration: 8000 });
  170. } else {
  171. showNotify({ type: 'success', message: '校验成功,请在闸机开门后离开' });
  172. }
  173. } else {
  174. showNotify({ type: 'warning', message: res.errorMessage });
  175. }
  176. } catch (error) {
  177. console.error('获取物料列表API调用失败:', error);
  178. showNotify({ type: 'danger', message: '获取物料列表API调用失败' });
  179. } finally {
  180. loading.value = false;
  181. }
  182. };
  183. // 生成CF入库单
  184. const generateCFStockIn = async params => {
  185. loading.value = true;
  186. try {
  187. const res = await createStockIn(params);
  188. if (res.errorCode === 0) {
  189. showNotify({ type: 'success', message: '入库申请已完成,还料任务已创建!' });
  190. router.push('/home');
  191. } else {
  192. showNotify({ type: 'warning', message: res.errorMessage });
  193. }
  194. } catch (error) {
  195. console.error('生成CF入库单API调用失败:', error);
  196. showNotify({ type: 'danger', message: '生成CF入库单API调用失败' });
  197. } finally {
  198. loading.value = false;
  199. }
  200. };
  201. onMounted(() => {
  202. getList();
  203. });
  204. </script>
  205. <style scoped>
  206. /* 页面容器 - 固定高度布局 */
  207. .page-container {
  208. display: flex;
  209. flex-direction: column;
  210. height: 100vh;
  211. background-color: #f9fafb;
  212. overflow: hidden;
  213. }
  214. /* 主内容区 - 可滚动 */
  215. .main-content {
  216. flex: 1;
  217. overflow-y: auto;
  218. padding: 1rem;
  219. display: flex;
  220. flex-direction: column;
  221. }
  222. /* 操作按钮行 */
  223. .page-header-row {
  224. display: flex;
  225. justify-content: flex-end;
  226. align-items: center;
  227. margin-bottom: 1rem;
  228. }
  229. /* 卡片容器 */
  230. .card-container {
  231. flex: 1;
  232. background-color: white;
  233. border-radius: 0.5rem;
  234. box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
  235. display: flex;
  236. flex-direction: column;
  237. overflow: hidden;
  238. min-height: 0;
  239. }
  240. /* 卡片列表包装器(可滚动区域) */
  241. .card-list-wrapper {
  242. flex: 1;
  243. overflow-y: auto;
  244. padding: 1.5rem;
  245. min-height: 0;
  246. }
  247. /* 卡片列表(单列布局) */
  248. .card-list {
  249. display: flex;
  250. flex-direction: column;
  251. }
  252. .card-list>* {
  253. margin-bottom: 1rem;
  254. }
  255. .card-list>*:last-child {
  256. margin-bottom: 0;
  257. }
  258. /* 分页包装器(固定底部) */
  259. .pagination-wrapper {
  260. padding: 0.5rem 1.5rem;
  261. border-top: 1px solid #e5e7eb;
  262. border-bottom: 1px solid #e5e7eb;
  263. background-color: #fafafa;
  264. display: flex;
  265. justify-content: flex-end;
  266. align-items: center;
  267. }
  268. /* 底部操作按钮 */
  269. .bottom-actions {
  270. position: sticky;
  271. bottom: 0;
  272. padding: 0 1rem 1rem 1rem;
  273. background-color: #f9fafb;
  274. display: flex;
  275. justify-content: flex-end;
  276. z-index: 10;
  277. }
  278. /* 库存卡片样式 */
  279. .inventory-card {
  280. padding: 1rem 1.5rem;
  281. transition: all 0.25s ease;
  282. border: 2px solid #e5e7eb;
  283. background-color: #ffffff;
  284. border-radius: 0.5rem;
  285. cursor: pointer;
  286. }
  287. .inventory-card:hover {
  288. border-color: #93c5fd;
  289. box-shadow: 0 4px 12px rgba(59, 130, 246, 0.1);
  290. }
  291. /* 不在库卡片 */
  292. .not-in-stock-card {
  293. background-color: #eff6ff !important;
  294. border-color: #93c5fd !important;
  295. }
  296. /* 在库卡片 */
  297. .in-stock-card {
  298. background-color: #f5f5f5 !important;
  299. border-color: #d1d5db !important;
  300. }
  301. /* 卡片标题区域 */
  302. .card-header {
  303. display: flex;
  304. align-items: center;
  305. justify-content: space-between;
  306. width: 100%;
  307. }
  308. .card-header>* {
  309. margin-right: 1rem;
  310. }
  311. .card-header>*:last-child {
  312. margin-right: 0;
  313. }
  314. .card-header-left {
  315. display: flex;
  316. align-items: center;
  317. flex: 1;
  318. min-width: 0;
  319. }
  320. .card-header-right {
  321. display: flex;
  322. align-items: center;
  323. }
  324. .card-header-right>* {
  325. margin-left: 0.75rem;
  326. }
  327. .card-header-right>*:first-child {
  328. margin-left: 0;
  329. }
  330. /* 卡片标题信息 */
  331. .card-title-info {
  332. display: flex;
  333. flex-direction: column;
  334. min-width: 0;
  335. }
  336. .card-title-info>* {
  337. margin-bottom: 0.25rem;
  338. }
  339. .card-title-info>*:last-child {
  340. margin-bottom: 0;
  341. }
  342. .card-name {
  343. font-size: 1.125rem;
  344. font-weight: 600;
  345. color: #111827;
  346. line-height: 1.5;
  347. white-space: nowrap;
  348. overflow: hidden;
  349. text-overflow: ellipsis;
  350. }
  351. .card-subtitle {
  352. font-size: 0.875rem;
  353. color: #6b7280;
  354. line-height: 1.4;
  355. }
  356. /* 卡片位置信息 */
  357. .card-location {
  358. display: flex;
  359. align-items: center;
  360. padding: 0.5rem 1rem;
  361. background-color: #f3f4f6;
  362. border-radius: 0.375rem;
  363. font-size: 0.875rem;
  364. color: #374151;
  365. white-space: nowrap;
  366. }
  367. .card-location i {
  368. color: #3b82f6;
  369. }
  370. /* 按钮样式 */
  371. :deep(.van-button--primary) {
  372. background-color: #3b82f6;
  373. border-color: #3b82f6;
  374. }
  375. :deep(.van-button--primary:active) {
  376. background-color: #2563eb;
  377. border-color: #2563eb;
  378. }
  379. :deep(.van-button--disabled) {
  380. opacity: 0.5;
  381. cursor: not-allowed;
  382. }
  383. .submit-btn {
  384. background-color: #10b981 !important;
  385. border-color: #10b981 !important;
  386. width: auto;
  387. padding: 0 24px;
  388. }
  389. :deep(.submit-btn.van-button--primary) {
  390. background-color: #10b981 !important;
  391. border-color: #10b981 !important;
  392. }
  393. :deep(.submit-btn.van-button--primary:active) {
  394. background-color: #059669 !important;
  395. border-color: #059669 !important;
  396. }
  397. /* 自定义头像 */
  398. .custom-avatar {
  399. width: 42px;
  400. height: 42px;
  401. border-radius: 50%;
  402. background-color: #3b82f6;
  403. display: flex;
  404. align-items: center;
  405. justify-content: center;
  406. color: white;
  407. font-size: 20px;
  408. flex-shrink: 0;
  409. }
  410. </style>