index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  1. <template>
  2. <view class="content-box">
  3. <uni-nav-bar
  4. fixed="true"
  5. statusBar="true"
  6. left-icon="back"
  7. title="请托列表"
  8. background-color="#157A2C"
  9. color="#fff"
  10. @clickLeft="back"
  11. ></uni-nav-bar>
  12. <view class="top-wrapper">
  13. <uni-section>
  14. <uni-easyinput
  15. prefixIcon="search"
  16. v-model="searchForm.name"
  17. placeholder="请输入名称"
  18. ></uni-easyinput>
  19. </uni-section>
  20. <image
  21. class="menu_icon"
  22. src="~@/static/pda/menu.svg"
  23. @click="showFilter = true"
  24. ></image>
  25. <button class="search_btn" @click="handleSearch">搜索</button>
  26. <button class="search_btn" @click="handleAdd">新增</button>
  27. </view>
  28. <view class="list_box">
  29. <u-list @scrolltolower="loadMore">
  30. <u-list-item v-for="item in list" :key="item.id">
  31. <view class="list-item" @click="goDetail(item)">
  32. <view class="item-header">
  33. <view class="item-code">{{ item.code }}</view>
  34. <view class="item-status">
  35. <text class="status-tag" :class="getStatusClass(item.status)">{{
  36. getStatusText(item.status)
  37. }}</text>
  38. </view>
  39. </view>
  40. <view class="item-row">
  41. <text class="label">类型:</text>
  42. <text class="value">{{ getTypeText(item.type) }}</text>
  43. </view>
  44. <view class="item-row">
  45. <text class="label">名称:</text>
  46. <text class="value">{{ item.name }}</text>
  47. </view>
  48. <view class="item-row">
  49. <text class="label">紧急程度:</text>
  50. <text class="value">{{
  51. item.priority == 1 ? "一般" : "紧急"
  52. }}</text>
  53. </view>
  54. <view class="item-row">
  55. <text class="label">请托数量:</text>
  56. <text class="value"
  57. >{{ item.totalCount }}{{ item.measuringUnit }}</text
  58. >
  59. </view>
  60. <view class="item-row">
  61. <text class="label">受托工厂:</text>
  62. <text class="value">{{ item.beEntrustedFactoriesName }}</text>
  63. </view>
  64. <view class="item-row">
  65. <text class="label">发货状态:</text>
  66. <text class="value">
  67. <text
  68. class="status-tag"
  69. :class="getSendStatusClass(item.sendStatus)"
  70. >{{ getSendStatusText(item.sendStatus) }}</text
  71. >
  72. </text>
  73. </view>
  74. <view class="item-row">
  75. <text class="label">审批状态:</text>
  76. <text class="value">
  77. <text
  78. class="status-tag"
  79. :class="getApprovalStatusClass(item.approvalStatus)"
  80. >{{ getApprovalStatusText(item.approvalStatus) }}</text
  81. >
  82. </text>
  83. </view>
  84. <view class="item-footer">
  85. <text class="time">{{ item.createTime }}</text>
  86. </view>
  87. <view
  88. class="item-actions"
  89. v-if="
  90. canEdit(item) ||
  91. canSubmit(item) ||
  92. canDelete(item) ||
  93. canSend(item) ||
  94. canReceive(item) ||
  95. canViewReceiveDetail(item) ||
  96. canViewSendDetail(item)
  97. "
  98. >
  99. <button
  100. v-if="canEdit(item)"
  101. class="action-btn btn-primary"
  102. @click.stop="handleEdit(item)"
  103. >
  104. 编辑
  105. </button>
  106. <button
  107. v-if="canDelete(item)"
  108. class="action-btn btn-error"
  109. @click.stop="handleDelete(item)"
  110. >
  111. 删除
  112. </button>
  113. <button
  114. v-if="canSubmit(item)"
  115. class="action-btn btn-success"
  116. @click.stop="handleSubmit(item)"
  117. >
  118. 提交
  119. </button>
  120. <button
  121. v-if="canSend(item)"
  122. class="action-btn btn-warning"
  123. @click.stop="handleSend(item)"
  124. >
  125. 发货
  126. </button>
  127. <button
  128. v-if="canReceive(item)"
  129. class="action-btn btn-success"
  130. @click.stop="handleReceive(item)"
  131. >
  132. 收货
  133. </button>
  134. <button
  135. v-if="canViewReceiveDetail(item)"
  136. class="action-btn btn-info"
  137. @click.stop="handleReceiveDetail(item)"
  138. >
  139. 收货详情
  140. </button>
  141. <button
  142. v-if="canViewSendDetail(item)"
  143. class="action-btn btn-order"
  144. @click.stop="handleSendDetail(item)"
  145. >
  146. 发货详情
  147. </button>
  148. </view>
  149. </view>
  150. </u-list-item>
  151. <u-list-item v-if="list.length === 0">
  152. <view class="empty-wrapper">
  153. <u-empty iconSize="150" textSize="32" text="暂无数据"></u-empty>
  154. </view>
  155. </u-list-item>
  156. </u-list>
  157. </view>
  158. <SearchPopup mode="top" v-if="showFilter">
  159. <template v-slot:list>
  160. <view class="search_list">
  161. <u-form
  162. labelPosition="left"
  163. :model="searchForm"
  164. labelWidth="180"
  165. labelAlign="left"
  166. >
  167. <u-form-item label="类型:" borderBottom>
  168. <picker
  169. mode="selector"
  170. :range="typeList"
  171. range-key="label"
  172. @change="typeChange"
  173. >
  174. <view class="picker-value">{{ currentType || "全部" }}</view>
  175. </picker>
  176. </u-form-item>
  177. </u-form>
  178. </view>
  179. </template>
  180. <template v-slot:operate>
  181. <view class="operate_box">
  182. <u-button
  183. size="small"
  184. class="u-reset-button reset-btn"
  185. @click="filterCancel"
  186. >重置</u-button
  187. >
  188. <u-button
  189. type="success"
  190. size="small"
  191. class="u-reset-button confirm-btn"
  192. @click="filterConfirm"
  193. >确定</u-button
  194. >
  195. </view>
  196. </template>
  197. </SearchPopup>
  198. </view>
  199. </template>
  200. <script>
  201. import { getList, submit, remove } from "@/api/entrust/index.js";
  202. import SearchPopup from "../../components/searchPopup.vue";
  203. let isEnd = false;
  204. export default {
  205. components: {
  206. SearchPopup,
  207. },
  208. data() {
  209. return {
  210. searchForm: {
  211. type: "",
  212. name: "",
  213. beEntrustedFactoriesId: "",
  214. },
  215. currentType: "",
  216. typeList: [],
  217. list: [],
  218. pageNum: 1,
  219. pageSize: 20,
  220. total: 0,
  221. loading: false,
  222. hasMore: true,
  223. showFilter: false,
  224. };
  225. },
  226. onLoad() {
  227. this.getTypeList();
  228. },
  229. onShow() {
  230. this.loadData(true);
  231. },
  232. methods: {
  233. async getTypeList() {
  234. // 获取字典数据
  235. this.typeList = [
  236. { label: "全部", value: "" },
  237. { label: "加工", value: "1" },
  238. { label: "装配", value: "2" },
  239. ];
  240. },
  241. typeChange(e) {
  242. const index = e.detail.value;
  243. this.searchForm.type = this.typeList[index].value;
  244. this.currentType = this.typeList[index].label;
  245. },
  246. async loadData(isRefresh = false) {
  247. if (this.loading) return;
  248. if (isRefresh) {
  249. this.pageNum = 1;
  250. this.list = [];
  251. this.hasMore = true;
  252. }
  253. if (!this.hasMore) return;
  254. this.loading = true;
  255. isEnd = false;
  256. try {
  257. const res = await getList({
  258. pageNum: this.pageNum,
  259. size: this.pageSize,
  260. ...this.searchForm,
  261. });
  262. if (this.pageNum === 1) {
  263. this.list = [];
  264. }
  265. if (res.list && res.list.length > 0) {
  266. this.list.push(...res.list);
  267. this.total = res.total;
  268. isEnd = this.list.length >= this.total;
  269. this.hasMore = !isEnd;
  270. } else {
  271. isEnd = true;
  272. this.hasMore = false;
  273. }
  274. } catch (error) {
  275. uni.showToast({
  276. title: "加载失败",
  277. icon: "none",
  278. });
  279. } finally {
  280. this.loading = false;
  281. }
  282. },
  283. loadMore() {
  284. if (isEnd) return;
  285. this.pageNum++;
  286. this.loadData();
  287. },
  288. handleSearch() {
  289. this.loadData(true);
  290. },
  291. filterConfirm() {
  292. this.showFilter = false;
  293. this.loadData(true);
  294. },
  295. filterCancel() {
  296. this.searchForm.type = "";
  297. this.currentType = "";
  298. this.showFilter = false;
  299. this.loadData(true);
  300. },
  301. goDetail(item) {
  302. uni.navigateTo({
  303. url: `/pages/pda/entrust/detail/detail?id=${item.id}`,
  304. });
  305. },
  306. handleAdd() {
  307. uni.navigateTo({
  308. url: "/pages/pda/entrust/create/create?type=add",
  309. });
  310. },
  311. handleEdit(item) {
  312. uni.navigateTo({
  313. url: `/pages/pda/entrust/create/create?type=edit&id=${item.id}`,
  314. });
  315. },
  316. handleDelete(item) {
  317. uni.showModal({
  318. title: "提示",
  319. content: "确定要删除该请托单吗?",
  320. success: async (res) => {
  321. if (res.confirm) {
  322. try {
  323. await remove([item.id]);
  324. uni.showToast({
  325. title: "删除成功",
  326. icon: "success",
  327. });
  328. this.loadData(true);
  329. } catch (error) {
  330. uni.showToast({
  331. title: "删除失败",
  332. icon: "none",
  333. });
  334. }
  335. }
  336. },
  337. });
  338. },
  339. handleSubmit(item) {
  340. uni.showModal({
  341. title: "提示",
  342. content: "确定要提交该请托单吗?",
  343. success: async (res) => {
  344. if (res.confirm) {
  345. try {
  346. await submit({
  347. businessId: item.id,
  348. beEntrustedDeptId: item.beEntrustedDeptId,
  349. });
  350. uni.showToast({
  351. title: "提交成功",
  352. icon: "success",
  353. });
  354. this.loadData(true);
  355. } catch (error) {
  356. uni.showToast({
  357. title: "提交失败",
  358. icon: "none",
  359. });
  360. }
  361. }
  362. },
  363. });
  364. },
  365. handleSend(item) {
  366. uni.navigateTo({
  367. url: `/pages/pda/entrust/goods/goods?id=${item.id}&type=add`,
  368. });
  369. },
  370. handleReceive(item) {
  371. uni.navigateTo({
  372. url: `/pages/pda/entrust/goods/goods?id=${item.id}&type=receipt`,
  373. });
  374. },
  375. canEdit(item) {
  376. return (
  377. (item.status == 0 &&
  378. item.approvalStatus != 1 &&
  379. item.approvalStatus != 2) ||
  380. item.approvalStatus == 3
  381. );
  382. },
  383. canDelete(item) {
  384. return (
  385. item.status == 0 && item.approvalStatus != 1 && item.approvalStatus != 2
  386. );
  387. },
  388. canSubmit(item) {
  389. return item.approvalStatus != 1 && item.approvalStatus != 2;
  390. },
  391. canSend(item) {
  392. return (
  393. item.approvalStatus == 2 &&
  394. (item.sendStatus == 0 || !item.sendStatus || item.sendStatus == 5)
  395. );
  396. },
  397. canReceive(item) {
  398. return item.approvalStatus == 2 && item.sendStatus == 3;
  399. },
  400. canViewReceiveDetail(item) {
  401. return item.approvalStatus == 2 && item.sendStatus == 4;
  402. },
  403. canViewSendDetail(item) {
  404. return (
  405. item.approvalStatus == 2 &&
  406. item.sendStatus != 0 &&
  407. item.sendStatus &&
  408. item.sendStatus != 5 &&
  409. item.sendStatus != 3 &&
  410. item.sendStatus != 4
  411. );
  412. },
  413. handleReceiveDetail(item) {
  414. uni.navigateTo({
  415. url: `/pages/pda/entrust/goods/goods?id=${item.id}&type=receipt`,
  416. });
  417. },
  418. handleSendDetail(item) {
  419. uni.navigateTo({
  420. url: `/pages/pda/entrust/goods/goods?id=${item.id}&type=detail`,
  421. });
  422. },
  423. getTypeText(type) {
  424. const typeMap = {
  425. 1: "加工",
  426. 2: "装配",
  427. };
  428. return typeMap[type] || "";
  429. },
  430. getStatusText(status) {
  431. const statusMap = {
  432. 0: "未提交",
  433. 1: "已提交",
  434. 2: "已发布",
  435. };
  436. return statusMap[status] || "";
  437. },
  438. getStatusClass(status) {
  439. const classMap = {
  440. 0: "status-default",
  441. 1: "status-warning",
  442. 2: "status-success",
  443. };
  444. return classMap[status] || "status-default";
  445. },
  446. getSendStatusText(sendStatus) {
  447. const statusMap = {
  448. 0: "未发货",
  449. 1: "已发货",
  450. 2: "已收货",
  451. 3: "受托已发",
  452. 4: "请托已收",
  453. 5: "受托拒收",
  454. 6: "请托拒收",
  455. };
  456. return statusMap[sendStatus] || "未发货";
  457. },
  458. getSendStatusClass(sendStatus) {
  459. if (!sendStatus || sendStatus == 0) return "status-default";
  460. if (sendStatus == 5 || sendStatus == 6) return "status-danger";
  461. return "status-success";
  462. },
  463. getApprovalStatusText(approvalStatus) {
  464. const statusMap = {
  465. 0: "未提交",
  466. 1: "审核中",
  467. 2: "审核通过",
  468. 3: "审核不通过",
  469. };
  470. return statusMap[approvalStatus] || "未提交";
  471. },
  472. getApprovalStatusClass(approvalStatus) {
  473. const classMap = {
  474. 0: "status-default",
  475. 1: "status-warning",
  476. 2: "status-success",
  477. 3: "status-danger",
  478. };
  479. return classMap[approvalStatus] || "status-default";
  480. },
  481. },
  482. };
  483. </script>
  484. <style lang="scss" scoped>
  485. page {
  486. height: 100vh;
  487. overflow: hidden;
  488. }
  489. .content-box {
  490. height: 100vh;
  491. overflow: hidden;
  492. display: flex;
  493. flex-direction: column;
  494. background-color: $page-bg;
  495. }
  496. .top-wrapper {
  497. background-color: #fff;
  498. display: flex;
  499. width: 750rpx;
  500. padding: 16rpx 32rpx;
  501. align-items: center;
  502. gap: 16rpx;
  503. flex-shrink: 0;
  504. position: sticky;
  505. top: 88rpx;
  506. z-index: 99;
  507. /deep/.uni-section {
  508. margin-top: 0px;
  509. flex: 1;
  510. }
  511. /deep/.uni-section-header {
  512. padding: 0px;
  513. }
  514. .search_btn {
  515. width: 120rpx;
  516. height: 70rpx;
  517. line-height: 70rpx;
  518. padding: 0 24rpx;
  519. background: $theme-color;
  520. font-size: 32rpx;
  521. color: #fff;
  522. margin: 0;
  523. }
  524. .menu_icon {
  525. width: 44rpx;
  526. height: 44rpx;
  527. }
  528. .add_btn {
  529. width: 70rpx;
  530. height: 70rpx;
  531. line-height: 70rpx;
  532. padding: 0;
  533. background: $theme-color;
  534. font-size: 48rpx;
  535. color: #fff;
  536. border-radius: 50%;
  537. margin: 0;
  538. }
  539. }
  540. .list_box {
  541. flex: 1;
  542. overflow: hidden;
  543. padding: 16rpx 0;
  544. .u-list {
  545. height: 100% !important;
  546. }
  547. }
  548. .list-item {
  549. background-color: #fff;
  550. border-radius: 12rpx;
  551. padding: 24rpx;
  552. margin: 0 24rpx 20rpx;
  553. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
  554. .item-header {
  555. display: flex;
  556. justify-content: space-between;
  557. align-items: center;
  558. margin-bottom: 20rpx;
  559. padding-bottom: 20rpx;
  560. border-bottom: 1rpx solid #f0f0f0;
  561. .item-code {
  562. font-size: 32rpx;
  563. font-weight: bold;
  564. color: $theme-color;
  565. }
  566. }
  567. .item-row {
  568. display: flex;
  569. margin-bottom: 16rpx;
  570. font-size: 28rpx;
  571. .label {
  572. color: #999;
  573. min-width: 160rpx;
  574. }
  575. .value {
  576. flex: 1;
  577. color: #333;
  578. word-break: break-all;
  579. }
  580. }
  581. .item-footer {
  582. margin-top: 20rpx;
  583. padding-top: 20rpx;
  584. border-top: 1rpx solid #f0f0f0;
  585. .time {
  586. font-size: 24rpx;
  587. color: #999;
  588. }
  589. }
  590. .item-actions {
  591. display: flex !important;
  592. justify-content: flex-end !important;
  593. gap: 12rpx;
  594. margin-top: 20rpx;
  595. overflow-x: auto;
  596. .action-btn {
  597. flex: 0 0 auto !important;
  598. width: auto !important;
  599. border-radius: 32rpx !important;
  600. height: 56rpx !important;
  601. line-height: 56rpx !important;
  602. font-size: 26rpx !important;
  603. padding: 0 24rpx !important;
  604. margin: 0 !important;
  605. border: none !important;
  606. color: #fff !important;
  607. &.btn-primary {
  608. background-color: #2979ff !important;
  609. }
  610. &.btn-error {
  611. background-color: #f56c6c !important;
  612. }
  613. &.btn-success {
  614. background-color: $theme-color !important;
  615. }
  616. &.btn-warning {
  617. background-color: #ff9900 !important;
  618. }
  619. &.btn-info {
  620. background-color: #e0ffff !important;
  621. }
  622. &.btn-order {
  623. background-color: #b23aee !important;
  624. }
  625. }
  626. }
  627. }
  628. .status-tag {
  629. display: inline-block;
  630. padding: 4rpx 16rpx;
  631. border-radius: 4rpx;
  632. font-size: 24rpx;
  633. &.status-default {
  634. background-color: #f0f0f0;
  635. color: #666;
  636. }
  637. &.status-warning {
  638. background-color: #fff7e6;
  639. color: #faad14;
  640. }
  641. &.status-success {
  642. background-color: rgba(21, 122, 44, 0.1);
  643. color: $theme-color;
  644. }
  645. &.status-danger {
  646. background-color: #fff1f0;
  647. color: #ff4d4f;
  648. }
  649. }
  650. .empty-wrapper {
  651. display: flex;
  652. align-items: center;
  653. justify-content: center;
  654. padding-top: 25vh;
  655. }
  656. .search_list {
  657. min-height: 100rpx;
  658. padding: 24rpx 32rpx;
  659. .picker-value {
  660. padding: 12rpx 16rpx;
  661. border: 1rpx solid #e0e0e0;
  662. border-radius: 6rpx;
  663. font-size: 28rpx;
  664. }
  665. }
  666. .operate_box {
  667. display: flex;
  668. flex-direction: row;
  669. align-items: center;
  670. justify-content: space-between;
  671. padding: 24rpx 32rpx 32rpx;
  672. gap: 24rpx;
  673. .reset-btn {
  674. flex: 1;
  675. height: 72rpx;
  676. border-radius: 36rpx;
  677. font-size: $uni-font-size-sm;
  678. }
  679. .confirm-btn {
  680. flex: 1;
  681. height: 72rpx;
  682. border-radius: 36rpx;
  683. font-size: $uni-font-size-sm;
  684. }
  685. }
  686. </style>