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.

931 lines
20 KiB

4 months ago
4 months ago
2 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
2 months ago
4 months ago
4 months ago
4 months ago
2 months ago
2 months ago
4 months ago
2 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
2 months ago
4 months ago
4 months ago
3 months ago
3 months ago
4 months ago
4 months ago
2 months ago
4 months ago
2 months ago
4 months ago
4 months ago
3 months ago
4 months ago
3 months ago
4 months ago
3 months ago
4 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: '/' })">首页</div>
  10. </div>
  11. <!-- 工单号输入 -->
  12. <div class="search-container">
  13. <el-input
  14. clearable
  15. v-model="workOrderNo"
  16. placeholder="请输入工单号"
  17. prefix-icon="el-icon-search"
  18. @keyup.enter.native="handleSearchWorkOrderByShopOrderLine"
  19. ref="workOrderInput"
  20. />
  21. </div>
  22. <!-- 原先需要精准查询现在不用了换成模糊查询接口 -->
  23. <!-- <div class="search-container">
  24. <el-input
  25. clearable
  26. v-model="releaseNo"
  27. placeholder="请输入下达号(默认*)"
  28. @keyup.enter.native="handleSearchWorkOrder"
  29. class="narrow-input"
  30. />
  31. <el-input
  32. clearable
  33. v-model="sequenceNo"
  34. placeholder="请输入序列号(默认*)"
  35. @keyup.enter.native="handleSearchWorkOrder"
  36. class="narrow-input"
  37. />
  38. </div> -->
  39. <!-- 工单信息卡片列表 -->
  40. <div class="work-order-list" v-if="workOrderList.length > 0">
  41. <div
  42. v-for="(workOrder, index) in displayWorkOrderList"
  43. :key="index"
  44. :class="['work-order-card', { selected: selectedWorkOrder && isSameWorkOrder(selectedWorkOrder, workOrder) }]"
  45. @click="selectWorkOrder(workOrder)"
  46. >
  47. <div class="card-title">
  48. <span class="title-label">工单号{{ workOrder.orderNo }}-{{workOrder.releaseNo}}-{{workOrder.sequenceNo}}</span>
  49. <span class="title-value">{{ workOrder.partNo }}</span>
  50. </div>
  51. <!-- 物料描述单独一行 -->
  52. <div class="part-desc-row">
  53. <span class="desc-text">{{ workOrder.partDesc }}</span>
  54. </div>
  55. <div class="card-details">
  56. <div class="detail-item">
  57. <div class="detail-label">计划数量</div>
  58. <div class="detail-value">{{ workOrder.lotSize }}</div>
  59. </div>
  60. <div class="detail-item">
  61. <div class="detail-label">状态</div>
  62. <div class="detail-value">{{ workOrder.status}}</div>
  63. </div>
  64. <div class="detail-item">
  65. <div class="detail-label">单位</div>
  66. <div class="detail-value">{{ workOrder.uom}}</div>
  67. </div>
  68. </div>
  69. </div>
  70. </div>
  71. <!-- 材料列表 -->
  72. <div
  73. class="content-area"
  74. v-if="selectedWorkOrder && materialList.length > 0"
  75. >
  76. <div
  77. v-for="(material, index) in materialList"
  78. :key="index"
  79. class="material-card"
  80. @click="selectMaterial(material)"
  81. >
  82. <div class="card-title">
  83. <span class="title-label"
  84. >物料编码{{ material.componentPartNo }} &nbsp;&nbsp; 行号{{
  85. material.lineItemNo
  86. }}</span
  87. >
  88. <!-- <span class="title-value">{{ material.componentPartNo }}</span> -->
  89. </div>
  90. <!-- 物料描述单独一行 -->
  91. <div class="part-desc-row">
  92. <span class="desc-text">{{ material.componentPartDesc }}</span>
  93. </div>
  94. <div class="card-details">
  95. <div class="detail-item">
  96. <div class="detail-label">需求数量</div>
  97. <div class="detail-value">{{ material.qtyRequired }}</div>
  98. </div>
  99. <div class="detail-item" :class="{ 'issued-qty-highlight': (material.qtyIssued || 0) > 0 }">
  100. <div class="detail-label">已发数量</div>
  101. <div class="detail-value">{{ material.qtyIssued || 0 }}</div>
  102. </div>
  103. <div class="detail-item">
  104. <div class="detail-label">单位</div>
  105. <div class="detail-value">{{ material.uom || "个" }}</div>
  106. </div>
  107. </div>
  108. </div>
  109. </div>
  110. <!-- 空状态 -->
  111. <div
  112. v-if="selectedWorkOrder && materialList.length === 0"
  113. class="empty-state"
  114. >
  115. <i class="el-icon-box"></i>
  116. <p>该工单暂无材料清单</p>
  117. </div>
  118. <!-- 加载状态 -->
  119. <div v-if="loading" class="loading-state">
  120. <i class="el-icon-loading"></i>
  121. <p>加载中...</p>
  122. </div>
  123. </div>
  124. </template>
  125. <script>
  126. import {
  127. getWorkOrderInfo,
  128. getWorkOrderMaterials,
  129. getShopOrderLine,
  130. } from "@/api/production/production-issue";
  131. import moment from "moment";
  132. export default {
  133. data() {
  134. return {
  135. workOrderNo: "",
  136. releaseNo: "*",
  137. sequenceNo: "*",
  138. workOrderList: [],
  139. selectedWorkOrder: null,
  140. materialList: [],
  141. selectedMaterial: null,
  142. loading: false,
  143. showOnlySelected: false,
  144. };
  145. },
  146. computed: {
  147. displayWorkOrderList() {
  148. if (this.showOnlySelected && this.selectedWorkOrder) {
  149. return [this.selectedWorkOrder];
  150. }
  151. return this.workOrderList;
  152. },
  153. },
  154. methods: {
  155. formatDate(date) {
  156. return date ? moment(date).format("YYYY-MM-DD") : "";
  157. },
  158. // 保存页面状态到sessionStorage(仅用于从详情页返回时恢复)
  159. savePageStateForDetail() {
  160. const state = {
  161. workOrderNo: this.workOrderNo,
  162. releaseNo: this.releaseNo,
  163. sequenceNo: this.sequenceNo,
  164. workOrderList: this.workOrderList,
  165. selectedWorkOrder: this.selectedWorkOrder,
  166. materialList: this.materialList,
  167. showOnlySelected: this.showOnlySelected,
  168. };
  169. sessionStorage.setItem('directIssue_state_fromDetail', JSON.stringify(state));
  170. },
  171. // 从sessionStorage恢复页面状态(仅当从详情页返回时)
  172. restorePageStateFromDetail() {
  173. try {
  174. const shouldRestore = sessionStorage.getItem('directIssue_shouldRestore');
  175. const savedState = sessionStorage.getItem('directIssue_state_fromDetail');
  176. if (shouldRestore === 'true' && savedState) {
  177. const state = JSON.parse(savedState);
  178. this.workOrderNo = state.workOrderNo || "";
  179. this.releaseNo = state.releaseNo || "*";
  180. this.sequenceNo = state.sequenceNo || "*";
  181. this.workOrderList = state.workOrderList || [];
  182. this.selectedWorkOrder = state.selectedWorkOrder || null;
  183. this.materialList = state.materialList || [];
  184. this.showOnlySelected = state.showOnlySelected || false;
  185. // 如果发料成功,刷新材料列表
  186. const needRefresh = sessionStorage.getItem('directIssue_needRefresh');
  187. if (needRefresh === 'true' && this.selectedWorkOrder) {
  188. this.loadMaterialList();
  189. }
  190. // 清除标记
  191. sessionStorage.removeItem('directIssue_shouldRestore');
  192. sessionStorage.removeItem('directIssue_state_fromDetail');
  193. sessionStorage.removeItem('directIssue_needRefresh');
  194. }
  195. } catch (error) {
  196. console.error('恢复页面状态失败:', error);
  197. // 清除可能损坏的数据
  198. sessionStorage.removeItem('directIssue_shouldRestore');
  199. sessionStorage.removeItem('directIssue_state_fromDetail');
  200. sessionStorage.removeItem('directIssue_needRefresh');
  201. }
  202. },
  203. // 查询工单信息(原方法)
  204. handleSearchWorkOrder() {
  205. if (!this.workOrderNo.trim()) {
  206. this.$message.warning("请输入工单号");
  207. return;
  208. }
  209. this.loading = true;
  210. const params = {
  211. workOrderNo: this.workOrderNo.trim(),
  212. releaseNo: (this.releaseNo || "*").trim() || "*",
  213. sequenceNo: (this.sequenceNo || "*").trim() || "*",
  214. site: localStorage.getItem('site'),
  215. };
  216. getWorkOrderInfo(params)
  217. .then(({ data }) => {
  218. this.loading = false;
  219. console.log("工单信息", data);
  220. if (
  221. data.workOrders &&
  222. data.workOrders.length > 0 &&
  223. data.code === 0
  224. ) {
  225. this.workOrderList = data.workOrders;
  226. this.selectedWorkOrder = null;
  227. this.materialList = [];
  228. this.showOnlySelected = false;
  229. } else {
  230. this.$message.error(data.msg ||"未找到该工单信息");
  231. this.workOrderList = [];
  232. this.selectedWorkOrder = null;
  233. this.materialList = [];
  234. this.showOnlySelected = false;
  235. }
  236. })
  237. .catch((error) => {
  238. this.loading = false;
  239. this.$message.error(error.msg || "查询工单信息失败");
  240. });
  241. },
  242. // 查询工单信息(使用ShopOrderLine方法)
  243. handleSearchWorkOrderByShopOrderLine() {
  244. if (!this.workOrderNo.trim()) {
  245. this.$message.warning("请输入工单号");
  246. return;
  247. }
  248. this.loading = true;
  249. const params = {
  250. workOrderNo: this.workOrderNo.trim(),
  251. site: localStorage.getItem('site'),
  252. };
  253. getShopOrderLine(params)
  254. .then(({ data }) => {
  255. this.loading = false;
  256. console.log("工单信息", data);
  257. if (
  258. data.workOrders &&
  259. data.workOrders.length > 0 &&
  260. data.code === 0
  261. ) {
  262. this.workOrderList = data.workOrders;
  263. this.selectedWorkOrder = null;
  264. this.materialList = [];
  265. this.showOnlySelected = false;
  266. } else {
  267. this.$message.error(data.msg ||"未找到该工单信息");
  268. this.workOrderList = [];
  269. this.selectedWorkOrder = null;
  270. this.materialList = [];
  271. this.showOnlySelected = false;
  272. }
  273. })
  274. .catch((error) => {
  275. this.loading = false;
  276. this.$message.error(error.msg || "查询工单信息失败");
  277. });
  278. },
  279. // 判断是否为同一工单
  280. isSameWorkOrder(a, b) {
  281. if (!a || !b) return false;
  282. return (
  283. a.orderNo === b.orderNo &&
  284. a.releaseNo === b.releaseNo &&
  285. a.sequenceNo === b.sequenceNo
  286. );
  287. },
  288. // 选择工单(支持再次点击切换显示所有)
  289. selectWorkOrder(workOrder) {
  290. if (
  291. this.showOnlySelected &&
  292. this.selectedWorkOrder &&
  293. this.isSameWorkOrder(this.selectedWorkOrder, workOrder)
  294. ) {
  295. // 再次点击同一条,恢复显示所有主数据
  296. this.selectedWorkOrder = null;
  297. this.materialList = [];
  298. this.showOnlySelected = false;
  299. return;
  300. }
  301. // 选择并仅显示当前工单
  302. this.selectedWorkOrder = workOrder;
  303. this.showOnlySelected = true;
  304. this.loadMaterialList();
  305. },
  306. // 加载材料清单
  307. loadMaterialList() {
  308. if (!this.selectedWorkOrder) {
  309. this.materialList = [];
  310. return;
  311. }
  312. const params = {
  313. workOrderNo: this.selectedWorkOrder.orderNo,
  314. site: localStorage.getItem('site'),
  315. releaseNo: (this.releaseNo || "*").trim() || "*",
  316. sequenceNo: (this.sequenceNo || "*").trim() || "*",
  317. };
  318. getWorkOrderMaterials(params)
  319. .then(({ data }) => {
  320. console.log("材料清单", data);
  321. if (data && data.code === 0) {
  322. this.materialList = (data.materials || []).map((item, index) => ({
  323. ...item,
  324. id: index + 1,
  325. }));
  326. } else {
  327. this.$message.error(data.msg || "获取材料清单失败");
  328. this.materialList = [];
  329. }
  330. })
  331. .catch((error) => {
  332. console.error("获取材料清单失败:", error);
  333. this.$message.error("获取材料清单失败");
  334. });
  335. },
  336. // 选择材料,跳转到扫描明细页
  337. selectMaterial(material) {
  338. console.log("选择材料", material);
  339. if(material.reserveIssueMethod != 'Reserve And Backflush'){
  340. this.$message.warning('该物料为'+material.reserveIssueMethod+',不支持直接领料,请选择其他物料!');
  341. return;
  342. }
  343. // 跳转前保存当前页面状态(用于从详情页返回时恢复)
  344. this.savePageStateForDetail();
  345. this.$router.push({
  346. name: "directIssueDetail",
  347. query: {
  348. workOrderNo: this.selectedWorkOrder.orderNo,
  349. partNo: material.componentPartNo,
  350. itemNo: material.lineItemNo,
  351. releaseNo: this.selectedWorkOrder.releaseNo,
  352. sequenceNo: this.selectedWorkOrder.sequenceNo,
  353. requiredQty: material.qtyRequired,
  354. issuedQty: material.qtyIssued || 0,
  355. partDesc: material.componentPartDesc,
  356. }
  357. });
  358. },
  359. },
  360. mounted() {
  361. // 检查是否从详情页返回,如果是则恢复状态
  362. this.restorePageStateFromDetail();
  363. // 聚焦工单号输入框
  364. this.$nextTick(() => {
  365. if (this.$refs.workOrderInput) {
  366. this.$refs.workOrderInput.focus();
  367. }
  368. });
  369. },
  370. };
  371. </script>
  372. <style scoped>
  373. .pda-container {
  374. width: 100vw;
  375. height: 100vh;
  376. display: flex;
  377. flex-direction: column;
  378. background: #f5f5f5;
  379. }
  380. /* 头部栏 */
  381. .header-bar {
  382. display: flex;
  383. justify-content: space-between;
  384. align-items: center;
  385. padding: 8px 16px;
  386. background: #17b3a3;
  387. color: white;
  388. height: 40px;
  389. min-height: 40px;
  390. }
  391. .header-left {
  392. display: flex;
  393. align-items: center;
  394. cursor: pointer;
  395. font-size: 16px;
  396. font-weight: 500;
  397. }
  398. .header-left i {
  399. margin-right: 8px;
  400. font-size: 18px;
  401. }
  402. .header-right {
  403. cursor: pointer;
  404. font-size: 16px;
  405. font-weight: 500;
  406. }
  407. /* 搜索容器 */
  408. .search-container {
  409. padding: 3px 16px;
  410. background: white;
  411. display: flex;
  412. align-items: center;
  413. gap: 12px;
  414. }
  415. .search-container .el-input {
  416. flex: 1;
  417. }
  418. .narrow-input {
  419. width: 120px;
  420. }
  421. .narrow-input ::v-deep .el-input__inner {
  422. text-align: center;
  423. }
  424. .search-btn {
  425. padding: 8px 16px;
  426. background: #17b3a3;
  427. color: white;
  428. border: none;
  429. border-radius: 4px;
  430. cursor: pointer;
  431. font-size: 14px;
  432. transition: background-color 0.2s;
  433. }
  434. .search-btn:hover {
  435. background: #0d8f7f;
  436. }
  437. .search-btn:disabled {
  438. background: #ccc;
  439. cursor: not-allowed;
  440. }
  441. /* 工单列表 */
  442. .work-order-list {
  443. overflow-y: auto;
  444. padding: 12px 16px;
  445. }
  446. /* 工单卡片 */
  447. .work-order-card {
  448. background: white;
  449. border-radius: 8px;
  450. margin-bottom: 12px;
  451. padding: 16px;
  452. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  453. cursor: pointer;
  454. transition: all 0.2s ease;
  455. border: 2px solid transparent;
  456. }
  457. .work-order-card:hover {
  458. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
  459. transform: translateY(-1px);
  460. }
  461. .work-order-card.selected {
  462. border-color: #17b3a3;
  463. background: #f0fffe;
  464. }
  465. .work-order-card:active {
  466. transform: translateY(0);
  467. }
  468. /* 内容区域 */
  469. .content-area {
  470. flex: 1;
  471. overflow-y: auto;
  472. padding: 12px 16px;
  473. }
  474. /* 材料卡片 */
  475. .material-card {
  476. background: white;
  477. border-radius: 8px;
  478. margin-bottom: 12px;
  479. padding: 16px;
  480. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  481. cursor: pointer;
  482. transition: all 0.2s ease;
  483. border: 2px solid transparent;
  484. }
  485. .material-card:hover {
  486. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
  487. transform: translateY(-1px);
  488. }
  489. .material-card.selected {
  490. border-color: #17b3a3;
  491. background: #f0fffe;
  492. }
  493. .material-card:active {
  494. transform: translateY(0);
  495. }
  496. /* 卡片标题 */
  497. .card-title {
  498. margin-bottom: 12px;
  499. }
  500. .title-label {
  501. font-size: 12px;
  502. color: #666;
  503. display: block;
  504. margin-bottom: 4px;
  505. }
  506. .title-value {
  507. font-size: 16px;
  508. font-weight: bold;
  509. color: #333;
  510. margin-left: 16px;
  511. }
  512. /* 物料描述行 */
  513. .part-desc-row {
  514. margin-bottom: 12px;
  515. padding: 0 4px;
  516. }
  517. .desc-text {
  518. font-size: 12px;
  519. color: #666;
  520. line-height: 1.3;
  521. word-break: break-all;
  522. }
  523. /* 卡片详情 */
  524. .card-details {
  525. display: flex;
  526. justify-content: space-between;
  527. align-items: flex-start;
  528. gap: 4px;
  529. }
  530. .detail-item {
  531. flex: 1;
  532. text-align: center;
  533. min-width: 50px;
  534. max-width: 70px;
  535. }
  536. .detail-label {
  537. font-size: 11px;
  538. color: #666;
  539. margin-bottom: 4px;
  540. line-height: 1.2;
  541. margin-left: -12px;
  542. }
  543. .detail-value {
  544. font-size: 13px;
  545. color: #333;
  546. line-height: 1.2;
  547. margin-left: -12px;
  548. }
  549. /* 已发数量高亮样式 */
  550. .detail-item.issued-qty-highlight .detail-label,
  551. .detail-item.issued-qty-highlight .detail-value {
  552. font-weight: bold;
  553. color: #ff0000;
  554. }
  555. /* 扫描区域 */
  556. .scan-section {
  557. margin-top: 16px;
  558. }
  559. /* 扫描容器 */
  560. .scan-container {
  561. padding: 12px 16px;
  562. background: white;
  563. display: flex;
  564. align-items: center;
  565. gap: 12px;
  566. border-radius: 0 0 8px 8px;
  567. margin-bottom: 12px;
  568. }
  569. .scan-container .el-input {
  570. width: 240px;
  571. margin-right: 12px;
  572. }
  573. /* 紧凑型输入框样式 */
  574. .compact-input ::v-deep .el-input__inner {
  575. height: 36px;
  576. padding: 0 12px 0 35px;
  577. font-size: 14px;
  578. }
  579. .compact-input ::v-deep .el-input__prefix {
  580. left: 10px;
  581. }
  582. .compact-input ::v-deep .el-input__suffix {
  583. right: 30px;
  584. }
  585. /* 模式切换开关 */
  586. .mode-switch {
  587. position: relative;
  588. display: inline-block;
  589. }
  590. .custom-switch {
  591. transform: scale(1.3);
  592. }
  593. /* 中间文字 */
  594. .switch-text {
  595. position: absolute;
  596. left: 25%;
  597. top: 53%;
  598. transform: translate(-50%, -50%);
  599. font-size: 12px;
  600. font-weight: bold;
  601. color: white;
  602. pointer-events: none;
  603. z-index: 2;
  604. }
  605. .switch-text2 {
  606. position: absolute;
  607. left: 75%;
  608. top: 53%;
  609. transform: translate(-50%, -50%);
  610. font-size: 12px;
  611. font-weight: bold;
  612. color: white;
  613. pointer-events: none;
  614. z-index: 2;
  615. }
  616. /* 调整 switch 尺寸以便容纳文字 */
  617. .custom-switch ::v-deep .el-switch__core {
  618. width: 60px;
  619. height: 28px;
  620. }
  621. /* 已选材料信息 */
  622. .selected-material-info {
  623. background: #e8f5e8;
  624. padding: 12px 16px;
  625. margin-bottom: 12px;
  626. border-radius: 8px;
  627. border-left: 4px solid #17b3a3;
  628. }
  629. .info-title {
  630. font-size: 14px;
  631. font-weight: bold;
  632. color: #333;
  633. margin-bottom: 8px;
  634. }
  635. .info-details {
  636. display: flex;
  637. gap: 16px;
  638. font-size: 12px;
  639. color: #666;
  640. }
  641. /* 标签列表 */
  642. .label-list {
  643. background: white;
  644. margin-bottom: 12px;
  645. border-radius: 8px;
  646. overflow: hidden;
  647. }
  648. .list-header {
  649. display: flex;
  650. background: #f8f9fa;
  651. padding: 12px 8px;
  652. border-bottom: 1px solid #e0e0e0;
  653. font-size: 12px;
  654. color: #666;
  655. font-weight: 500;
  656. }
  657. .list-item {
  658. display: flex;
  659. padding: 12px 8px;
  660. border-bottom: 1px solid #f0f0f0;
  661. font-size: 12px;
  662. color: #333;
  663. align-items: flex-start;
  664. min-height: 40px;
  665. }
  666. .list-item:last-child {
  667. border-bottom: none;
  668. }
  669. .col-no {
  670. width: 30px;
  671. text-align: center;
  672. }
  673. .col-label {
  674. flex: 1.5;
  675. text-align: center;
  676. word-break: break-all;
  677. white-space: normal;
  678. line-height: 1.2;
  679. }
  680. .col-batch {
  681. flex: 1;
  682. text-align: center;
  683. }
  684. .col-qty {
  685. width: 60px;
  686. text-align: center;
  687. }
  688. .empty-labels {
  689. padding: 40px 20px;
  690. text-align: center;
  691. color: #999;
  692. }
  693. .empty-labels p {
  694. margin: 0;
  695. font-size: 14px;
  696. }
  697. /* 底部操作按钮 */
  698. .bottom-actions {
  699. display: flex;
  700. padding: 16px;
  701. gap: 20px;
  702. background: white;
  703. border-radius: 8px;
  704. }
  705. .action-btn {
  706. flex: 1;
  707. padding: 12px;
  708. border: 1px solid #17b3a3;
  709. background: white;
  710. color: #17b3a3;
  711. border-radius: 20px;
  712. font-size: 14px;
  713. cursor: pointer;
  714. transition: all 0.2s ease;
  715. }
  716. .action-btn.primary {
  717. background: #17b3a3;
  718. color: white;
  719. }
  720. .action-btn.primary:hover {
  721. background: #0d8f7f;
  722. }
  723. .action-btn.secondary:hover {
  724. background: #17b3a3;
  725. color: white;
  726. }
  727. .action-btn:active {
  728. transform: scale(0.98);
  729. }
  730. .action-btn:disabled {
  731. opacity: 0.5;
  732. cursor: not-allowed;
  733. }
  734. .action-btn:disabled:hover {
  735. background: #17b3a3;
  736. color: white;
  737. }
  738. /* 空状态 */
  739. .empty-state {
  740. display: flex;
  741. flex-direction: column;
  742. align-items: center;
  743. justify-content: center;
  744. padding: 60px 20px;
  745. color: #999;
  746. }
  747. .empty-state i {
  748. font-size: 48px;
  749. margin-bottom: 16px;
  750. }
  751. .empty-state p {
  752. font-size: 14px;
  753. margin: 0;
  754. }
  755. /* 加载状态 */
  756. .loading-state {
  757. display: flex;
  758. flex-direction: column;
  759. align-items: center;
  760. justify-content: center;
  761. padding: 60px 20px;
  762. color: #17b3a3;
  763. }
  764. .loading-state i {
  765. font-size: 24px;
  766. margin-bottom: 12px;
  767. animation: spin 1s linear infinite;
  768. }
  769. @keyframes spin {
  770. from {
  771. transform: rotate(0deg);
  772. }
  773. to {
  774. transform: rotate(360deg);
  775. }
  776. }
  777. .loading-state p {
  778. font-size: 14px;
  779. margin: 0;
  780. }
  781. /* 响应式设计 */
  782. @media (max-width: 360px) {
  783. .header-bar {
  784. padding: 8px 12px;
  785. }
  786. .search-container {
  787. padding: 8px 12px;
  788. }
  789. .work-order-list {
  790. padding: 8px 12px;
  791. }
  792. .work-order-card {
  793. padding: 12px;
  794. }
  795. .content-area {
  796. padding: 8px 12px;
  797. }
  798. .material-card {
  799. padding: 12px;
  800. }
  801. .card-details {
  802. flex-wrap: wrap;
  803. gap: 6px;
  804. }
  805. .detail-item {
  806. flex: 0 0 48%;
  807. margin-bottom: 6px;
  808. min-width: 50px;
  809. }
  810. .list-header,
  811. .list-item {
  812. font-size: 11px;
  813. }
  814. .col-label {
  815. flex: 1.5;
  816. }
  817. }
  818. </style>