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.

1015 lines
22 KiB

6 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
6 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
5 months ago
6 months ago
5 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 class="compact-input"
  16. v-model="scanCode"
  17. placeholder="请扫描标签条码"
  18. prefix-icon="el-icon-search"
  19. @keyup.enter.native="handleScan"
  20. ref="scanInput"
  21. />
  22. <div class="mode-switch">
  23. <el-switch
  24. class="custom-switch"
  25. v-model="isRemoveMode"
  26. active-color="#ff4949"
  27. inactive-color="#13ce66">
  28. </el-switch>
  29. <span v-if="isRemoveMode" class="switch-text">{{ '移除' }}</span>
  30. <span v-else class="switch-text2">{{ '添加' }}</span>
  31. </div>
  32. </div>
  33. <!-- 出库单信息卡片 -->
  34. <div class="material-info-card" v-if="outboundInfo.outboundNo">
  35. <div class="card-title">
  36. <span class="title-label">出库单号</span>
  37. <span class="title-value">{{ outboundInfo.outboundNo }}</span>
  38. </div>
  39. <div class="card-details">
  40. <div class="detail-item">
  41. <div class="detail-label">销售订单</div>
  42. <div class="detail-value">{{ outboundInfo.relatedNo }}</div>
  43. </div>
  44. <div class="detail-item">
  45. <div class="detail-label">标签张数</div>
  46. <div class="detail-value">
  47. <span class="qualified">{{ outboundInfo.availableLabels }}</span><span class="total">{{ outboundInfo.totalLabels }}</span>
  48. </div>
  49. </div>
  50. <div class="detail-item">
  51. <div class="detail-label">物料总数</div>
  52. <div class="detail-value">
  53. <span class="qualified">{{ outboundInfo.availableQty }}</span><span class="total">{{ outboundInfo.totalQty }}</span>
  54. </div>
  55. </div>
  56. <div class="detail-item">
  57. <div class="detail-label">创建日期</div>
  58. <div class="detail-value">{{ formatDate(outboundInfo.createDate) }}</div>
  59. </div>
  60. </div>
  61. </div>
  62. <!-- 出库信息确认标题 -->
  63. <div class="section-title">
  64. <div class="title-left">
  65. <i class="el-icon-circle-check"></i>
  66. <span>出库信息确认</span>
  67. </div>
  68. <div class="title-right">
  69. <span class="material-list-link" @click="showMaterialListDialog">物料清单</span>
  70. </div>
  71. </div>
  72. <!-- 标签列表 -->
  73. <div class="label-list">
  74. <div class="list-header">
  75. <div class="col-no">NO.</div>
  76. <div class="col-label">标签条码</div>
  77. <div class="col-part">物料编码</div>
  78. <div class="col-qty">标签数量</div>
  79. </div>
  80. <div class="list-body">
  81. <div
  82. v-for="(label, index) in labelList"
  83. :key="label.id"
  84. class="list-item"
  85. >
  86. <div class="col-no">{{ labelList.length - index }}</div>
  87. <div class="col-label">{{ label.labelCode }}</div>
  88. <div class="col-part">{{ label.partNo }}</div>
  89. <div class="col-qty">{{ label.quantity }}</div>
  90. </div>
  91. <!-- 空状态 -->
  92. <div v-if="labelList.length === 0" class="empty-labels">
  93. <p>暂无扫描标签</p>
  94. </div>
  95. </div>
  96. </div>
  97. <!-- 底部操作按钮 -->
  98. <div class="bottom-actions">
  99. <button class="action-btn secondary" @click="confirmOutbound">
  100. 确定
  101. </button>
  102. <button class="action-btn secondary" style="margin-left: 10px;" @click="printLabels">
  103. 打印
  104. </button>
  105. <button class="action-btn secondary" style="margin-left: 10px;" @click="cancelOutbound">
  106. 取消
  107. </button>
  108. </div>
  109. <!-- 物料清单弹窗 -->
  110. <div v-if="showMaterialDialog" class="material-overlay">
  111. <div class="material-modal">
  112. <div class="modal-header">
  113. <span class="modal-title">物料清单</span>
  114. <i class="el-icon-close close-btn" @click="closeMaterialDialog"></i>
  115. </div>
  116. <div class="modal-body">
  117. <!-- 加载状态 -->
  118. <div v-if="materialListLoading" class="loading-container">
  119. <i class="el-icon-loading"></i>
  120. <span>加载中...</span>
  121. </div>
  122. <!-- 物料表格 -->
  123. <div v-else-if="materialList.length > 0" class="material-table">
  124. <div class="table-header">
  125. <div class="col-no">NO.</div>
  126. <div class="col-material-code">物料编码</div>
  127. <div class="col-required-qty">需求数量</div>
  128. <div class="col-available-qty">出库数量</div>
  129. </div>
  130. <div class="table-body">
  131. <div
  132. v-for="(item, index) in materialList"
  133. :key="index"
  134. class="table-row"
  135. >
  136. <div class="col-no">{{ index + 1 }}</div>
  137. <div class="col-material-code">{{ item.materialCode || item.partNo }}</div>
  138. <div class="col-required-qty">{{ item.requiredQty || 0 }}</div>
  139. <div class="col-available-qty">{{ item.availableQty || 0 }}</div>
  140. </div>
  141. </div>
  142. </div>
  143. <!-- 空数据状态 -->
  144. <div v-else class="empty-material">
  145. <i class="el-icon-document"></i>
  146. <p>暂无物料数据</p>
  147. </div>
  148. </div>
  149. <div class="modal-footer">
  150. <button class="btn-close" @click="closeMaterialDialog">关闭</button>
  151. </div>
  152. </div>
  153. </div>
  154. </div>
  155. </template>
  156. <script>
  157. import { getOutboundDetails, validateLabelWithOutbound, confirmSalesOutbound, getMaterialList } from "@/api/sales/sales-outbound.js";
  158. import { getCurrentWarehouse } from '@/utils'
  159. import moment from 'moment';
  160. export default {
  161. data() {
  162. return {
  163. scanCode: '',
  164. outboundInfo: {},
  165. labelList: [],
  166. outboundNo: '',
  167. showMaterialDialog: false,
  168. materialList: [],
  169. materialListLoading: false,
  170. isRemoveMode: false // 默认为添加模式
  171. };
  172. },
  173. methods: {
  174. formatDate(date) {
  175. return date ? moment(date).format('YYYY-MM-DD') : '';
  176. },
  177. // 处理扫描
  178. handleScan() {
  179. if (!this.scanCode.trim()) {
  180. return;
  181. }
  182. if (this.isRemoveMode) {
  183. this.removeLabelByCode(this.scanCode.trim());
  184. } else {
  185. this.validateAndAddLabel(this.scanCode.trim());
  186. }
  187. this.scanCode = '';
  188. },
  189. // 验证标签并添加到列表
  190. validateAndAddLabel(labelCode) {
  191. const params = {
  192. labelCode: labelCode,
  193. outboundNo: this.outboundNo,
  194. warehouseId: getCurrentWarehouse(),
  195. site: localStorage.getItem('site'),
  196. buNo: this.buNo
  197. };
  198. validateLabelWithOutbound(params).then(({ data }) => {
  199. if (data && data.code === 0) {
  200. const resultList = data.data;
  201. // 检查是否已经扫描过
  202. const exists = this.labelList.find(item => item.labelCode === labelCode);
  203. if (exists) {
  204. this.$message.warning('该标签已扫描,请勿重复扫描');
  205. return;
  206. }
  207. // 将所有结果添加到列表
  208. resultList.forEach(result => {
  209. this.labelList.push({
  210. id: Date.now() + Math.random(), // 确保ID唯一
  211. labelCode: result.labelCode,
  212. partNo: result.partNo,
  213. quantity: result.quantity,
  214. batchNo: result.batchNo,
  215. locationId: result.locationId
  216. });
  217. });
  218. this.$message.success(`标签验证成功,共添加 ${resultList.length} 条记录`);
  219. } else {
  220. this.$message.error(data.msg || '该标签与出库单不符,请检查');
  221. }
  222. }).catch(error => {
  223. console.error('标签验证失败:', error);
  224. this.$message.error('操作失败');
  225. });
  226. },
  227. // 通过条码移除标签
  228. removeLabelByCode(labelCode) {
  229. const index = this.labelList.findIndex(item => item.labelCode === labelCode);
  230. if (index !== -1) {
  231. this.labelList.splice(index, 1);
  232. this.$message.success('操作成功');
  233. } else {
  234. this.$message.warning('未找到该标签');
  235. }
  236. },
  237. // 确认出库
  238. confirmOutbound() {
  239. if (this.labelList.length === 0) {
  240. this.$message.warning('请先扫描标签');
  241. return;
  242. }
  243. const params = {
  244. site: this.outboundInfo.site,
  245. buNo: this.outboundInfo.buNo,
  246. outboundNo: this.outboundNo,
  247. warehouseId: getCurrentWarehouse(),
  248. labels: this.labelList.map(label => ({
  249. labelCode: label.labelCode,
  250. partNo: label.partNo,
  251. quantity: label.quantity,
  252. batchNo: label.batchNo,
  253. locationId: label.locationId
  254. }))
  255. };
  256. confirmSalesOutbound(params).then(({ data }) => {
  257. if (data && data.code === 0) {
  258. this.$message.success('出库成功');
  259. this.$router.back();
  260. } else {
  261. this.$message.error(data.msg || '出库失败');
  262. }
  263. }).catch(error => {
  264. console.error('出库失败:', error);
  265. this.$message.error('出库失败');
  266. });
  267. },
  268. // 打印标签
  269. printLabels() {
  270. if (this.labelList.length === 0) {
  271. this.$message.warning('暂无标签可打印');
  272. return;
  273. }
  274. this.$message.warning('打印功能开发中...');
  275. },
  276. // 取消出库
  277. cancelOutbound() {
  278. if (this.labelList.length > 0) {
  279. this.$confirm('取消后将清空已扫描的标签,确定取消吗?', '提示', {
  280. confirmButtonText: '确定',
  281. cancelButtonText: '继续操作',
  282. type: 'warning'
  283. }).then(() => {
  284. this.$router.back();
  285. }).catch(() => {
  286. // 用户选择继续操作
  287. });
  288. } else {
  289. this.$router.back();
  290. }
  291. },
  292. // 显示物料清单弹窗
  293. showMaterialListDialog() {
  294. this.showMaterialDialog = true;
  295. this.loadMaterialList();
  296. },
  297. // 加载物料清单
  298. loadMaterialList() {
  299. if (!this.outboundInfo.site || !this.outboundInfo.buNo || !this.outboundNo) {
  300. this.$message.error('缺少必要参数,无法获取物料清单');
  301. return;
  302. }
  303. this.materialListLoading = true;
  304. const params = {
  305. site: this.outboundInfo.site,
  306. buNo: this.outboundInfo.buNo,
  307. outboundNo: this.outboundNo
  308. };
  309. getMaterialList(params).then(({ data }) => {
  310. this.materialListLoading = false;
  311. if (data && data.code === 0) {
  312. this.materialList = data.data || [];
  313. } else {
  314. this.$message.error(data.msg || '获取物料清单失败');
  315. this.materialList = [];
  316. }
  317. }).catch(error => {
  318. this.materialListLoading = false;
  319. console.error('获取物料清单失败:', error);
  320. this.$message.error('获取物料清单失败');
  321. this.materialList = [];
  322. });
  323. },
  324. // 关闭物料清单弹窗
  325. closeMaterialDialog() {
  326. this.showMaterialDialog = false;
  327. },
  328. // 加载出库单详情
  329. loadOutboundDetails() {
  330. const params = {
  331. outboundNo: this.outboundNo,
  332. buNo: this.buNo,
  333. warehouseId: getCurrentWarehouse(),
  334. site: localStorage.getItem('site'),
  335. };
  336. getOutboundDetails(params).then(({ data }) => {
  337. if (data && data.code === 0) {
  338. this.outboundInfo = data.data;
  339. } else {
  340. this.$message.error(data.msg || '获取出库单详情失败');
  341. }
  342. }).catch(error => {
  343. console.error('获取出库单详情失败:', error);
  344. this.$message.error('获取出库单详情失败');
  345. });
  346. }
  347. },
  348. mounted() {
  349. // 获取路由参数
  350. this.outboundNo = this.$route.params.outboundNo;
  351. this.buNo = this.$route.params.buNo;
  352. if (!this.outboundNo || !this.buNo) {
  353. this.$message.error('参数错误');
  354. this.$router.back();
  355. return;
  356. }
  357. // 聚焦扫描框
  358. this.$nextTick(() => {
  359. if (this.$refs.scanInput) {
  360. this.$refs.scanInput.focus();
  361. }
  362. });
  363. // 加载出库单详情
  364. this.loadOutboundDetails();
  365. }
  366. };
  367. </script>
  368. <style scoped>
  369. /* 复用生产入库的样式,保持一致性 */
  370. .pda-container {
  371. width: 100vw;
  372. height: 100vh;
  373. display: flex;
  374. flex-direction: column;
  375. background: #f5f5f5;
  376. }
  377. /* 头部栏 */
  378. .header-bar {
  379. display: flex;
  380. justify-content: space-between;
  381. align-items: center;
  382. padding: 8px 16px;
  383. background: #17B3A3;
  384. color: white;
  385. height: 40px;
  386. min-height: 40px;
  387. }
  388. .header-left {
  389. display: flex;
  390. align-items: center;
  391. cursor: pointer;
  392. font-size: 16px;
  393. font-weight: 500;
  394. }
  395. .header-left i {
  396. margin-right: 8px;
  397. font-size: 18px;
  398. }
  399. .header-right {
  400. cursor: pointer;
  401. font-size: 16px;
  402. font-weight: 500;
  403. }
  404. /* 搜索容器 */
  405. .search-container {
  406. padding: 12px 16px;
  407. background: white;
  408. display: flex;
  409. align-items: center;
  410. gap: 12px;
  411. }
  412. .search-container .el-input {
  413. width: 240px;
  414. margin-right: 12px;
  415. }
  416. /* 紧凑型输入框样式 */
  417. .compact-input ::v-deep .el-input__inner {
  418. height: 36px;
  419. padding: 0 12px 0 35px;
  420. font-size: 14px;
  421. }
  422. .compact-input ::v-deep .el-input__prefix {
  423. left: 10px;
  424. }
  425. .compact-input ::v-deep .el-input__suffix {
  426. right: 30px;
  427. }
  428. /* 模式切换开关 */
  429. .mode-switch {
  430. position: relative;
  431. display: inline-block;
  432. }
  433. .custom-switch {
  434. transform: scale(1.3);
  435. }
  436. /* 中间文字 */
  437. .switch-text {
  438. position: absolute;
  439. left: 25%;
  440. transform: translateX(-50%);
  441. top: 50%;
  442. transform: translateY(-50%) translateX(-50%);
  443. font-size: 12px;
  444. font-weight: 500;
  445. color: #606266;
  446. white-space: nowrap;
  447. pointer-events: none;
  448. z-index: 1;
  449. top: 53%;
  450. transform: translate(-50%, -50%);
  451. font-size: 12px;
  452. font-weight: bold;
  453. color: white;
  454. pointer-events: none;
  455. z-index: 2;
  456. }
  457. .switch-text2 {
  458. position: absolute;
  459. left: 75%;
  460. transform: translateX(-50%);
  461. top: 50%;
  462. transform: translateY(-50%) translateX(-50%);
  463. font-size: 12px;
  464. font-weight: 500;
  465. color: #606266;
  466. white-space: nowrap;
  467. pointer-events: none;
  468. z-index: 1;
  469. top: 53%;
  470. transform: translate(-50%, -50%);
  471. font-size: 12px;
  472. font-weight: bold;
  473. color: white;
  474. pointer-events: none;
  475. z-index: 2;
  476. }
  477. /* 调整 switch 尺寸以便容纳文字 */
  478. .custom-switch ::v-deep .el-switch__core {
  479. width: 60px;
  480. height: 28px;
  481. }
  482. /* 物料信息卡片 */
  483. .material-info-card {
  484. background: white;
  485. margin: 4px 16px;
  486. padding: 6px 20px;
  487. border-radius: 8px;
  488. box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  489. border: 1px solid #f0f0f0;
  490. }
  491. .card-title {
  492. margin-bottom: 16px;
  493. }
  494. .title-label {
  495. font-size: 11px;
  496. color: #999;
  497. display: block;
  498. margin-bottom: 6px;
  499. font-weight: normal;
  500. }
  501. .title-value {
  502. font-size: 18px;
  503. font-weight: bold;
  504. color: #333;
  505. line-height: 1.2;
  506. margin-left: 20px;
  507. }
  508. .card-details {
  509. display: flex;
  510. justify-content: space-between;
  511. align-items: flex-start;
  512. gap: 4px;
  513. }
  514. .detail-item {
  515. flex: 1;
  516. text-align: center;
  517. min-width: 60px;
  518. max-width: 60px;
  519. }
  520. .detail-label {
  521. font-size: 11px;
  522. color: #999;
  523. margin-bottom: 6px;
  524. font-weight: normal;
  525. line-height: 1.2;
  526. margin-left: -12px;
  527. }
  528. .detail-value {
  529. font-size: 13px;
  530. color: #333;
  531. font-weight: 500;
  532. line-height: 1.2;
  533. margin-left: -12px;
  534. }
  535. .detail-value .qualified {
  536. color: #17B3A3;
  537. font-weight: 500;
  538. }
  539. .detail-value .total {
  540. color: #333;
  541. font-weight: 500;
  542. }
  543. .detail-value .total::before {
  544. content: '/';
  545. color: #333;
  546. }
  547. /* 区域标题 */
  548. .section-title {
  549. display: flex;
  550. align-items: center;
  551. justify-content: space-between;
  552. padding: 6px 8px;
  553. background: white;
  554. margin: 0 16px;
  555. margin-top: 4px;
  556. border-radius: 8px 8px 0 0;
  557. border-bottom: 2px solid #17B3A3;
  558. }
  559. .title-left {
  560. display: flex;
  561. align-items: center;
  562. }
  563. .title-left i {
  564. color: #17B3A3;
  565. font-size: 16px;
  566. margin-right: 8px;
  567. }
  568. .title-left span {
  569. color: #17B3A3;
  570. font-size: 14px;
  571. font-weight: 500;
  572. }
  573. .title-right {
  574. display: flex;
  575. align-items: center;
  576. }
  577. .material-list-link {
  578. color: #17B3A3;
  579. font-size: 14px;
  580. font-weight: 500;
  581. cursor: pointer;
  582. text-decoration: underline;
  583. transition: color 0.2s ease;
  584. }
  585. .material-list-link:hover {
  586. color: #0d8f7f;
  587. }
  588. /* 标签列表 */
  589. .label-list {
  590. background: white;
  591. margin: 0 16px 12px;
  592. border-radius: 0 0 8px 8px;
  593. overflow: hidden;
  594. flex: 1;
  595. display: flex;
  596. flex-direction: column;
  597. max-height: 300px; /* 限制最大高度 */
  598. }
  599. .label-list .list-body {
  600. flex: 1;
  601. overflow-y: auto; /* 允许垂直滚动 */
  602. max-height: 250px; /* 内容区域最大高度 */
  603. }
  604. /* 滚动条样式优化 */
  605. .label-list .list-body::-webkit-scrollbar {
  606. width: 4px;
  607. }
  608. .label-list .list-body::-webkit-scrollbar-track {
  609. background: #f1f1f1;
  610. border-radius: 2px;
  611. }
  612. .label-list .list-body::-webkit-scrollbar-thumb {
  613. background: #17B3A3;
  614. border-radius: 2px;
  615. }
  616. .label-list .list-body::-webkit-scrollbar-thumb:hover {
  617. background: #0d8f7f;
  618. }
  619. .list-header {
  620. display: flex;
  621. background: #f8f9fa;
  622. padding: 12px 8px;
  623. border-bottom: 1px solid #e0e0e0;
  624. font-size: 12px;
  625. color: #666;
  626. font-weight: 500;
  627. }
  628. .list-item {
  629. display: flex;
  630. padding: 12px 8px;
  631. border-bottom: 1px solid #f0f0f0;
  632. font-size: 12px;
  633. color: #333;
  634. }
  635. .list-item:last-child {
  636. border-bottom: none;
  637. }
  638. .col-no {
  639. width: 20px;
  640. text-align: center;
  641. }
  642. .col-label {
  643. flex: 2;
  644. text-align: center;
  645. }
  646. .col-part {
  647. flex: 2;
  648. text-align: center;
  649. }
  650. .col-qty {
  651. width: 60px;
  652. text-align: center;
  653. }
  654. .empty-labels {
  655. padding: 40px 20px;
  656. text-align: center;
  657. color: #999;
  658. }
  659. .empty-labels p {
  660. margin: 0;
  661. font-size: 14px;
  662. }
  663. /* 底部操作按钮 */
  664. .bottom-actions {
  665. display: flex;
  666. padding: 16px;
  667. gap: 20px;
  668. background: white;
  669. margin-top: auto;
  670. }
  671. .action-btn {
  672. flex: 1;
  673. padding: 12px;
  674. border: 1px solid #17B3A3;
  675. background: white;
  676. color: #17B3A3;
  677. border-radius: 20px;
  678. font-size: 14px;
  679. cursor: pointer;
  680. transition: all 0.2s ease;
  681. }
  682. .action-btn:hover {
  683. background: #17B3A3;
  684. color: white;
  685. }
  686. .action-btn:active {
  687. transform: scale(0.98);
  688. }
  689. /* 物料清单弹窗样式 */
  690. .material-overlay {
  691. position: fixed;
  692. top: 0;
  693. left: 0;
  694. right: 0;
  695. bottom: 0;
  696. background: rgba(0, 0, 0, 0.5);
  697. z-index: 9999;
  698. display: flex;
  699. align-items: center;
  700. justify-content: center;
  701. padding: 20px;
  702. }
  703. .material-modal {
  704. background: white;
  705. border-radius: 12px;
  706. width: 100%;
  707. max-width: 800px;
  708. max-height: 80vh;
  709. box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
  710. overflow: hidden;
  711. display: flex;
  712. flex-direction: column;
  713. }
  714. .material-modal .modal-header {
  715. background: #17B3A3;
  716. color: white;
  717. padding: 5px 16px;
  718. display: flex;
  719. justify-content: space-between;
  720. align-items: center;
  721. min-height: 28px;
  722. }
  723. .close-btn {
  724. font-size: 16px;
  725. cursor: pointer;
  726. color: white;
  727. transition: color 0.2s ease;
  728. padding: 4px;
  729. display: flex;
  730. align-items: center;
  731. justify-content: center;
  732. }
  733. .close-btn:hover {
  734. color: #e0e0e0;
  735. }
  736. .material-modal .modal-title {
  737. font-size: 16px;
  738. font-weight: 500;
  739. margin: 0;
  740. line-height: 1.2;
  741. }
  742. .material-modal .modal-body {
  743. flex: 1;
  744. overflow: auto;
  745. padding: 0;
  746. }
  747. .material-table {
  748. width: 100%;
  749. }
  750. .table-header {
  751. display: flex;
  752. background: #f8f9fa;
  753. padding: 10px 6px;
  754. border-bottom: 2px solid #17B3A3;
  755. font-size: 12px;
  756. color: #333;
  757. font-weight: 600;
  758. position: sticky;
  759. top: 0;
  760. z-index: 1;
  761. }
  762. .table-body {
  763. max-height: 400px;
  764. overflow-y: auto;
  765. }
  766. .table-row {
  767. display: flex;
  768. padding: 10px 6px;
  769. border-bottom: 1px solid #f0f0f0;
  770. font-size: 12px;
  771. color: #333;
  772. transition: background-color 0.2s ease;
  773. }
  774. .table-row:hover {
  775. background-color: #f8f9fa;
  776. }
  777. .table-row:last-child {
  778. border-bottom: none;
  779. }
  780. .material-table .col-no {
  781. width: 25px;
  782. text-align: center;
  783. flex-shrink: 0;
  784. font-size: 12px;
  785. }
  786. .material-table .col-material-code {
  787. flex: 1.8;
  788. text-align: center;
  789. min-width: 100px;
  790. font-size: 12px;
  791. word-break: break-all;
  792. }
  793. .material-table .col-required-qty {
  794. flex: 0.8;
  795. text-align: center;
  796. min-width: 65px;
  797. font-size: 12px;
  798. }
  799. .material-table .col-available-qty {
  800. flex: 0.8;
  801. text-align: center;
  802. min-width: 65px;
  803. font-size: 12px;
  804. }
  805. .material-modal .modal-footer {
  806. padding: 15px 20px;
  807. display: flex;
  808. justify-content: center;
  809. border-top: 1px solid #f0f0f0;
  810. }
  811. .btn-close {
  812. padding: 10px 20px;
  813. border-radius: 6px;
  814. font-size: 14px;
  815. cursor: pointer;
  816. transition: all 0.2s;
  817. border: 1px solid #17B3A3;
  818. background: white;
  819. color: #17B3A3;
  820. }
  821. .btn-close:hover {
  822. background: #17B3A3;
  823. color: white;
  824. }
  825. /* 加载状态样式 */
  826. .loading-container {
  827. display: flex;
  828. flex-direction: column;
  829. align-items: center;
  830. justify-content: center;
  831. padding: 60px 20px;
  832. color: #666;
  833. }
  834. .loading-container i {
  835. font-size: 24px;
  836. margin-bottom: 12px;
  837. color: #17B3A3;
  838. }
  839. .loading-container span {
  840. font-size: 14px;
  841. }
  842. /* 空数据状态样式 */
  843. .empty-material {
  844. display: flex;
  845. flex-direction: column;
  846. align-items: center;
  847. justify-content: center;
  848. padding: 60px 20px;
  849. color: #999;
  850. }
  851. .empty-material i {
  852. font-size: 48px;
  853. margin-bottom: 16px;
  854. color: #ddd;
  855. }
  856. .empty-material p {
  857. margin: 0;
  858. font-size: 14px;
  859. }
  860. /* 响应式设计 */
  861. @media (max-width: 360px) {
  862. .header-bar {
  863. padding: 8px 12px;
  864. }
  865. .search-container {
  866. padding: 8px 12px;
  867. }
  868. .material-info-card {
  869. margin: 4px 12px;
  870. padding: 6px 16px;
  871. }
  872. .section-title {
  873. margin: 0 12px;
  874. margin-top: 4px;
  875. }
  876. .label-list {
  877. margin: 0 12px 8px;
  878. }
  879. .card-details {
  880. flex-wrap: wrap;
  881. gap: 6px;
  882. }
  883. .detail-item {
  884. flex: 0 0 48%;
  885. margin-bottom: 6px;
  886. min-width: 50px;
  887. }
  888. .list-header, .list-item {
  889. font-size: 11px;
  890. }
  891. .col-label, .col-part {
  892. flex: 1.5;
  893. }
  894. }
  895. </style>