review-detail.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. <template>
  2. <view class="order-detail" :class="{ 'fixed-bottom-2': type == 2 }" @click="playGlobalSound">
  3. <scroll-view class="scroller" :scroll-into-view="toView" scroll-y="true" scroll-with-animation="true">
  4. <view class="flex flex-a-c flex-j-b bg-white bind-audit mb-16">
  5. <text>绑定复审员</text>
  6. <text class="text-center flex-1">{{
  7. orderDetail.auditUserName || selectedAuditor?.userName || ""
  8. }}</text>
  9. <text @click="showAuditorSelector = true" class="color-primary">绑定</text>
  10. </view>
  11. <OrderInfo :detail="orderDetail" @refresh="() => getOrderDetail(true)" />
  12. <UserInfoCard :detail="orderDetail" />
  13. <view class="mt-16" style="padding: 0 6rpx">
  14. <u-subsection :list="list" mode="subsection" :current="current"
  15. @change="handleSectionChange"></u-subsection>
  16. <ReviewBookInfo v-if="current == 0" :bookList="orderDetail.detailReviewVoList" :detail="orderDetail"
  17. @get-all-firstLetter="onGetAllFirstLetter" />
  18. <LogisticsTimeline v-if="current == 1" :list="orderDetail.trackingVoList" />
  19. <FileInfo v-if="current == 2" :orderId="orderDetail.orderId" />
  20. </view>
  21. </scroll-view>
  22. <view class="fixed-left">
  23. <view class="bind-code common-bg" style="margin-bottom: 30px; padding: 20rpx" @click="handleBindCode">绑码
  24. </view>
  25. <view class="common-bg flex flex-a-c flex-j-c flex-d">
  26. <view class="book-status-item" @click="scrollToView('good')">良好</view>
  27. <view class="book-status-item item-center" @click="scrollToView('average')">一般</view>
  28. <view class="book-status-item" @click="scrollToView('poor')">极差</view>
  29. </view>
  30. </view>
  31. <view class="fixed-right">
  32. <view class="letter-bg flex flex-a-c flex-j-c flex-d">
  33. <view class="letter-item"><u-icon name="arrow-up-fill" size="20" color="#ffffff"
  34. @click="scrollToTop"></u-icon></view>
  35. <view class="letter-item" v-for="(item, index) in allLetters" :key="index" @click="scrollToView(item)">
  36. {{ item }}</view>
  37. </view>
  38. </view>
  39. <view class="common-bg fixed-bottom">
  40. <u-button type="primary" size="large" @click="handleComplete">完成</u-button>
  41. </view>
  42. <AuditorSelector :show="showAuditorSelector" @update:show="showAuditorSelector = $event"
  43. @auditor-selected="handleAuditorSelected" />
  44. </view>
  45. </template>
  46. <script setup>
  47. import { ref, onUnmounted } from "vue";
  48. import { onLoad, onShow } from "@dcloudio/uni-app";
  49. import AuditorSelector from "./components/AuditorSelector.vue";
  50. import OrderInfo from "./components/OrderInfo.vue";
  51. import UserInfoCard from "./components/UserInfoCard.vue";
  52. import LogisticsTimeline from "../express/components/LogisticsTimeline.vue";
  53. import ReviewBookInfo from "./components/ReviewBookInfo.vue";
  54. import FileInfo from "./components/FileInfo.vue";
  55. const showAuditorSelector = ref(false);
  56. const selectedAuditor = ref({});
  57. const handleAuditorSelected = (auditor) => {
  58. selectedAuditor.value = auditor;
  59. orderDetail.value.auditUserId = auditor.userId;
  60. orderDetail.value.auditUserName = auditor.userName;
  61. uni.setStorageSync("checkUserInfo", {
  62. userName: auditor.userName,
  63. userId: auditor.userId,
  64. });
  65. };
  66. //点击全局音效
  67. function playGlobalSound() {
  68. uni.$u.playClickSound();
  69. }
  70. //点击滚动的位置
  71. const toView = ref("");
  72. function scrollToView(to) {
  73. toView.value = to;
  74. uni.pageScrollTo({
  75. selector: "#" + to,
  76. duration: 200,
  77. });
  78. }
  79. //回到顶部
  80. function scrollToTop() {
  81. uni.pageScrollTo({
  82. top: 0,
  83. duration: 200,
  84. });
  85. }
  86. //绑码
  87. function handleBindCode() {
  88. uni.$u.toast("暂无开发");
  89. }
  90. const list = ref(["不良清单", "物流信息", "上传附件"]);
  91. const current = ref(0);
  92. const handleSectionChange = (index) => {
  93. current.value = index;
  94. };
  95. //监听书籍的首字母
  96. const allLetters = ref([]);
  97. function onGetAllFirstLetter(data) {
  98. allLetters.value = data;
  99. }
  100. //完成
  101. function handleComplete() {
  102. let bookList = orderDetail.value.detailReviewVoList;
  103. let bool = bookList.some((item) => !item.auditReviewComment?.sts);
  104. if (bool) {
  105. let text = "还有未复审的书";
  106. uni.$u.toast(text);
  107. uni.$u.ttsModule.speak(text);
  108. return;
  109. } else {
  110. uni.$u.http
  111. .post("/app/orderreview/reviewOrderFinish", {
  112. reviewId: orderDetail.value.reviewId,
  113. })
  114. .then((res) => {
  115. if (res.code == 200) {
  116. uni.showToast({ title: "复审完成", icon: "none" });
  117. uni.$u.ttsModule.speak("复审完成");
  118. uni.navigateBack();
  119. }else{
  120. uni.$u.ttsModule.speak(res.msg);
  121. }
  122. });
  123. }
  124. }
  125. const orderDetail = ref({ status: 0 });
  126. //获取订单详情
  127. function getOrderDetail(forceRefresh = false) {
  128. if (!orderId.value) return;
  129. // 如果是强制刷新,重置标志位
  130. if (forceRefresh) {
  131. hasLoadedOrderDetail.value = false;
  132. hasLoadedCheckUser.value = false;
  133. }
  134. uni.showLoading({
  135. title: "加载中...",
  136. mask: true,
  137. });
  138. uni.$u.http
  139. .get("/app/orderreview/getOrderInfoForReview", {
  140. params: {
  141. searchType: 1,
  142. search: orderId.value,
  143. },
  144. })
  145. .then((res) => {
  146. if (res.code == 200) {
  147. orderDetail.value = res.data;
  148. // 只有在首次加载且没有复审员信息时才调用getCheckUserInfo
  149. if (!hasLoadedCheckUser.value && !res.data.auditUserId) {
  150. getCheckUserInfo();
  151. }
  152. if (res.data.auditUserId) {
  153. let auditUserInfo = {
  154. userName: res.data.auditUserName,
  155. userId: res.data.auditUserId,
  156. };
  157. uni.setStorageSync("checkUserInfo", auditUserInfo);
  158. } else {
  159. let userInfo = uni.getStorageSync("checkUserInfo");
  160. if (userInfo && userInfo.userName) {
  161. orderDetail.value.auditUserName = userInfo.userName;
  162. orderDetail.value.auditUserId = userInfo.userId;
  163. }
  164. }
  165. if (isOnLoad.value) {
  166. if (res.data.manageRemark.length > 0 && res.data.status < 10) {
  167. uni.$u.ttsModule.speak("此订单有备注信息,请注意查看");
  168. }
  169. if (res.data.warnArea && res.data.warnArea.length > 0) {
  170. let text = `此订单来源于${res.data.warnArea}`;
  171. uni.$u.ttsModule.speak(text);
  172. }
  173. isOnLoad.value = false;
  174. }
  175. hasLoadedOrderDetail.value = true; // 标记订单详情已加载
  176. } else {
  177. uni.$u.toast(res.msg);
  178. }
  179. })
  180. .finally(() => {
  181. uni.hideLoading();
  182. });
  183. }
  184. //获取上一次绑定的复审员信息
  185. function getCheckUserInfo() {
  186. uni.$u.http.get("/app/orderinfo/getCheckUser").then((res) => {
  187. if (res.code == 200) {
  188. let userInfo = res.data || {};
  189. orderDetail.value.auditUserName = userInfo.userName || '';
  190. orderDetail.value.auditUserId = userInfo.userId || '';
  191. uni.setStorageSync("checkUserInfo", {
  192. userName: userInfo.userName,
  193. userId: userInfo.userId,
  194. });
  195. }
  196. hasLoadedCheckUser.value = true; // 标记复审员信息已加载
  197. });
  198. }
  199. //isbn正则校验是否符合
  200. function checkIsbn(isbn) {
  201. const isbn13Regex = /^(?:97[89]-?\d{1,5}-?\d{1,7}-?\d{1,6}-?\d)$/;
  202. if (isbn13Regex.test(isbn)) {
  203. return true;
  204. }
  205. return false;
  206. }
  207. //扫码之后的逻辑
  208. function handleScan(isbn) {
  209. if (!checkIsbn(isbn)) {
  210. let text = `不是正确的ISBN码`;
  211. uni.$u.ttsModule.speak(text);
  212. return;
  213. }
  214. if (orderDetail.value.status >= 10) {
  215. uni.$u.ttsModule.speak("订单已复审完成");
  216. return;
  217. }
  218. //取 isbn 的后四位字符串进行播报
  219. let isbnStr = `${isbn.slice(-4)}`;
  220. let isbnList = orderDetail.value.detailVoList.map((item) => item.isbn);
  221. if (isbnList.includes(isbn)) {
  222. let book = orderDetail.value.detailVoList.find((item) => item.isbn == isbn);
  223. //扫描到套装书
  224. if (book.suit == 1) {
  225. let text = `${isbnStr}请注意套装书是否齐全`;
  226. uni.$u.ttsModule.speak(text);
  227. }
  228. //扫描到需要取出的书
  229. if (book.bookWarn == 1) {
  230. let text = `请注意${isbnStr}需要取出`;
  231. uni.$u.ttsModule.speak(text);
  232. }
  233. uni.navigateTo({
  234. url: `/pages/index/detail/book-audit?isbn=${isbn}&orderId=${orderDetail.value.orderId}`,
  235. });
  236. uni.setStorageSync("auditBook", book);
  237. uni.setStorageSync("orderDetail", orderDetail.value);
  238. } else {
  239. let text = `此订单中不存在${isbnStr}这本书 `;
  240. uni.$u.ttsModule.speak(text);
  241. }
  242. }
  243. //扫码
  244. function handleScanCode() {
  245. uni.scanCode({
  246. success: (res) => {
  247. res.result && handleScan(res.result);
  248. },
  249. });
  250. }
  251. const orderId = ref("");
  252. const isOnLoad = ref(false);
  253. const hasLoadedOrderDetail = ref(false); // 添加标志位控制订单详情是否已加载
  254. const hasLoadedCheckUser = ref(false); // 添加标志位控制复审员信息是否已加载
  255. // 1 表示到货复审 2 表示查看订单
  256. const type = ref(1);
  257. onLoad((options) => {
  258. isOnLoad.value = true;
  259. orderId.value = options.id;
  260. orderDetail.value = uni.getStorageSync("orderDetail") || {};
  261. type.value = options.type || 1;
  262. uni.removeStorageSync("scannedBooks");
  263. });
  264. onShow(() => {
  265. // 只有在首次加载时才调用getOrderDetail,避免重复请求
  266. getOrderDetail();
  267. });
  268. </script>
  269. <style>
  270. page {
  271. background-color: #f5f5f5;
  272. }
  273. </style>
  274. <style lang="scss" scoped>
  275. .order-detail {
  276. font-size: 30rpx;
  277. padding-bottom: 140rpx;
  278. position: relative;
  279. &.fixed-bottom-2 {
  280. padding-bottom: 30rpx;
  281. }
  282. .bind-audit {
  283. padding: 20rpx 30rpx;
  284. border-bottom: 1px solid #e5e5e5;
  285. }
  286. .fixed-left {
  287. position: fixed;
  288. left: 0;
  289. top: 11%;
  290. width: 100rpx;
  291. .common-bg {
  292. background-color: rgba(34, 172, 56, 0.7);
  293. border-radius: 0 30rpx 30rpx 0;
  294. font-weight: 500;
  295. color: #ffffff;
  296. }
  297. .book-status-item {
  298. padding: 20rpx;
  299. border-top: 1rpx solid #ffffff;
  300. border-bottom: 1rpx solid #ffffff;
  301. }
  302. }
  303. .fixed-right {
  304. position: fixed;
  305. right: 0;
  306. top: 12%;
  307. width: 70rpx;
  308. .letter-bg {
  309. background-color: rgba(34, 172, 56, 0.7);
  310. border-radius: 10rpx 0 0 10rpx;
  311. font-weight: 500;
  312. color: #ffffff;
  313. padding: 12rpx 0;
  314. padding-bottom: 6rpx;
  315. }
  316. .letter-item {
  317. padding-bottom: 12rpx;
  318. }
  319. }
  320. }
  321. </style>