history.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. <template>
  2. <view class="common-page" style="padding: 0;">
  3. <view class="header">
  4. <u-navbar title="历史工单" :border="false" fixed safe-area-inset-top>
  5. <template #left>
  6. <u-icon name="arrow-left" color="#333333" size="20" @click="goBack"></u-icon>
  7. </template>
  8. </u-navbar>
  9. </view>
  10. <view class="content" v-if="workOrderDetail">
  11. <!-- 工单信息 -->
  12. <view class="info-section">
  13. <view class="info-row">
  14. <text class="label">快递单号:</text>
  15. <text class="value">{{ workOrderDetail.waybillCode }}</text>
  16. </view>
  17. <view class="info-row" v-if="workOrderDetail.orderId">
  18. <text class="label">订单编号:</text>
  19. <text class="value link-text" @click="goToOrderDetail">{{ workOrderDetail.orderId }}</text>
  20. </view>
  21. <view class="info-row">
  22. <text class="label">任务类型:</text>
  23. <text class="value">{{ workOrderDetail.taskTypeName || '-' }}</text>
  24. </view>
  25. <view class="info-row">
  26. <text class="label">验货状态:</text>
  27. <text class="value">{{ workOrderDetail.inspectionStatusName || '-' }}</text>
  28. </view>
  29. <view class="info-row">
  30. <text class="label">任务详情:</text>
  31. <text class="value">{{ workOrderDetail.deatil || '-' }}</text>
  32. </view>
  33. <view class="info-row">
  34. <text class="label">创建人:</text>
  35. <text class="value">{{ workOrderDetail.createUserName || '-' }}</text>
  36. </view>
  37. <view class="info-row">
  38. <text class="label">创建时间:</text>
  39. <text class="value">{{ formatTime(workOrderDetail.createTime) }}</text>
  40. </view>
  41. <view class="info-row">
  42. <text class="label">任务状态:</text>
  43. <text class="value status-text" :class="'status-' + workOrderDetail.status">{{ getStatusText(workOrderDetail.status) }}</text>
  44. </view>
  45. <view class="info-row">
  46. <text class="label">指派人:</text>
  47. <text class="value">{{ (workOrderDetail.handleUsers || []).map(item => item.userName).filter(Boolean).join(',') || '-' }}</text>
  48. </view>
  49. <!-- 图片展示 -->
  50. <view class="image-list" v-if="workOrderDetail.imgInfo && workOrderDetail.imgInfo.imgUrlList && workOrderDetail.imgInfo.imgUrlList.length > 0">
  51. <image
  52. v-for="(img, index) in workOrderDetail.imgInfo.imgUrlList"
  53. :key="index"
  54. :src="img"
  55. mode="aspectFill"
  56. class="work-order-image"
  57. @click="previewImage(index)"
  58. ></image>
  59. </view>
  60. </view>
  61. </view>
  62. <!-- 工单变更记录 -->
  63. <TrackRecord :records="records" />
  64. <!-- 底部操作按钮 -->
  65. <view class="fixed-bottom" v-if="showButtons">
  66. <template v-if="isCreator">
  67. <!-- 创建人按钮 -->
  68. <template v-if="workOrderDetail.status === 1 || workOrderDetail.status === 2 || workOrderDetail.status === 3">
  69. <!-- 待处理、处理中、仓库处理状态 -->
  70. <u-button type="warning" size="large" text="编辑" @click="handleEdit"></u-button>
  71. <u-button type="primary" size="large" text="完成" @click="handleFinish"></u-button>
  72. <u-button type="error" size="large" text="作废" @click="handleCancel"></u-button>
  73. </template>
  74. <template v-else-if="workOrderDetail.status === 4 || workOrderDetail.status === 5">
  75. <!-- 已完成、已作废状态 -->
  76. <u-button type="primary" size="large" text="重开" @click="handleReopen"></u-button>
  77. </template>
  78. </template>
  79. <template v-else>
  80. <!-- 被指派人按钮 -->
  81. <template v-if="workOrderDetail.status === 1 || workOrderDetail.status === 2 || workOrderDetail.status === 3">
  82. <!-- 未处理、处理中、仓库处理状态 -->
  83. <u-button type="warning" size="large" text="编辑" @click="handleEdit"></u-button>
  84. <u-button type="primary" size="large" text="完成" @click="handleFinish"></u-button>
  85. </template>
  86. <!-- 已完成、已作废状态无操作按钮 -->
  87. </template>
  88. </view>
  89. </view>
  90. </template>
  91. <script setup>
  92. import { ref, computed, onMounted } from 'vue'
  93. import { onLoad } from '@dcloudio/uni-app'
  94. import TrackRecord from '@/pages/order/components/track-record.vue'
  95. const workOrderId = ref('')
  96. const orderType = ref('') // 1-卖书 2-回收
  97. const waybillCode = ref('')
  98. const orderId = ref('')
  99. const workOrderDetail = ref(null)
  100. const currentUserId = ref(null)
  101. const records = ref([])
  102. // 判断是否为创建人
  103. const isCreator = computed(() => {
  104. if (!workOrderDetail.value || !currentUserId.value) return false
  105. return workOrderDetail.value.createUserId === currentUserId.value
  106. })
  107. // 是否显示按钮
  108. const showButtons = computed(() => {
  109. if (!workOrderDetail.value) return false
  110. const status = workOrderDetail.value.status
  111. // 状态:1-待处理 2-处理中 3-仓库处理 4-完成 5-作废
  112. return [1, 2, 3, 4, 5].includes(status)
  113. })
  114. // 获取状态文本
  115. const getStatusText = (status) => {
  116. const statusMap = {
  117. 1: '待处理',
  118. 2: '处理中',
  119. 3: '仓库处理',
  120. 4: '已完成',
  121. 5: '已作废'
  122. }
  123. return statusMap[status] || '未知状态'
  124. }
  125. // 格式化时间
  126. const formatTime = (time) => {
  127. if (!time) return '-'
  128. return time.replace('T', ' ').substring(0, 19)
  129. }
  130. // 获取工单详情
  131. const getWorkOrderDetail = async () => {
  132. try {
  133. uni.showLoading({ title: '加载中...' })
  134. const res = await uni.$u.http.get('/app/workOrder/getWorkOrderDetail', {
  135. params: { workOrderId: workOrderId.value }
  136. })
  137. if (res.code === 200 && res.data) {
  138. workOrderDetail.value = res.data
  139. records.value = res.data.changeRecords || []
  140. } else {
  141. uni.$u.toast(res.msg || '获取工单详情失败')
  142. }
  143. } catch (error) {
  144. console.error(error)
  145. uni.$u.toast(error?.data?.msg || error?.msg || '网络错误')
  146. } finally {
  147. uni.hideLoading()
  148. }
  149. }
  150. // 预览图片
  151. const getImageUrlList = () => {
  152. const info = workOrderDetail.value?.imgInfo
  153. if (!info) return []
  154. if (Array.isArray(info?.imgUrlList)) return info.imgUrlList.filter(Boolean)
  155. if (Array.isArray(info)) return info.map(v => (typeof v === 'string' ? v : v?.url)).filter(Boolean)
  156. if (typeof info === 'string') return info.split(',').map(s => s.trim()).filter(Boolean)
  157. return []
  158. }
  159. const previewImage = (index) => {
  160. const urls = getImageUrlList()
  161. if (urls.length > 0) {
  162. uni.previewImage({ urls, current: index })
  163. }
  164. }
  165. // 返回上一页
  166. const goBack = () => {
  167. uni.navigateBack()
  168. }
  169. // 跳转到订单详情
  170. const goToOrderDetail = () => {
  171. if (!workOrderDetail.value?.orderId) return
  172. uni.navigateTo({
  173. url: `/pages/index/detail/index?id=${workOrderDetail.value.orderId}`
  174. })
  175. }
  176. // 编辑工单
  177. const handleEdit = () => {
  178. uni.navigateTo({
  179. url: `/pages/order/${orderType.value == 1 ? 'mall' : 'recycle'}/created?waybillCode=${waybillCode.value}&orderId=${orderId.value}&workOrderId=${workOrderId.value}&mode=edit`
  180. })
  181. }
  182. // 完成工单
  183. const handleFinish = async () => {
  184. uni.showModal({
  185. title: '提示',
  186. content: '确定要完成该工单吗?',
  187. success: async (res) => {
  188. if (res.confirm) {
  189. try {
  190. uni.showLoading({ title: '提交中...' })
  191. const result = await uni.$u.http.post('/app/workOrder/finish', {
  192. ids: [workOrderId.value]
  193. })
  194. if (result.code === 200) {
  195. uni.$u.ttsModule.speak('提交成功')
  196. uni.$u.toast('操作成功')
  197. getWorkOrderDetail()
  198. } else {
  199. uni.$u.toast(result.msg || '操作失败')
  200. }
  201. } catch (error) {
  202. console.error(error)
  203. uni.$u.toast(error?.data?.msg || error?.msg || '网络错误')
  204. } finally {
  205. uni.hideLoading()
  206. }
  207. }
  208. }
  209. })
  210. }
  211. // 作废工单
  212. const handleCancel = async () => {
  213. uni.showModal({
  214. title: '提示',
  215. content: '确定要作废该工单吗?',
  216. success: async (res) => {
  217. if (res.confirm) {
  218. try {
  219. uni.showLoading({ title: '提交中...' })
  220. const result = await uni.$u.http.post('/app/workOrder/cancel', {
  221. id: workOrderId.value
  222. })
  223. if (result.code === 200) {
  224. uni.$u.ttsModule.speak('操作成功')
  225. uni.$u.toast('操作成功')
  226. getWorkOrderDetail()
  227. } else {
  228. uni.$u.toast(result.msg || '操作失败')
  229. }
  230. } catch (error) {
  231. console.error(error)
  232. uni.$u.toast(error?.data?.msg || error?.msg || '网络错误')
  233. } finally {
  234. uni.hideLoading()
  235. }
  236. }
  237. }
  238. })
  239. }
  240. // 重开工单(重新打开已完成的工单)
  241. const handleReopen = async () => {
  242. uni.showModal({
  243. title: '提示',
  244. content: '确定要重开该工单吗?',
  245. success: async (res) => {
  246. if (res.confirm) {
  247. try {
  248. uni.showLoading({ title: '提交中...' })
  249. const result = await uni.$u.http.post('/app/workOrder/reopen', {
  250. id: workOrderId.value
  251. })
  252. if (result.code === 200) {
  253. uni.$u.ttsModule.speak('操作成功')
  254. uni.$u.toast('操作成功')
  255. getWorkOrderDetail()
  256. } else {
  257. uni.$u.toast(result.msg || '操作失败')
  258. }
  259. } catch (error) {
  260. console.error(error)
  261. uni.$u.toast(error?.data?.msg || error?.msg || '网络错误')
  262. } finally {
  263. uni.hideLoading()
  264. }
  265. }
  266. }
  267. })
  268. }
  269. onLoad((options) => {
  270. workOrderId.value = options.workOrderId
  271. orderType.value = options.type
  272. waybillCode.value = options.waybillCode || ''
  273. orderId.value = options.orderId || ''
  274. // 获取当前用户ID(这里需要从用户信息中获取,暂时使用固定值或从缓存读取)
  275. const userInfo = uni.getStorageSync('userInfo') || {}
  276. currentUserId.value = userInfo.userId || null
  277. // 加载工单详情
  278. getWorkOrderDetail()
  279. })
  280. </script>
  281. <style lang="scss" scoped>
  282. .content {
  283. padding-top: 12px;
  284. border-radius: 0;
  285. /* #ifdef APP-PLUS */
  286. padding-top: 100px;
  287. /* #endif */
  288. }
  289. .info-section {
  290. background-color: #ffffff;
  291. padding: 20px;
  292. margin-bottom: 12px;
  293. }
  294. .info-row {
  295. display: flex;
  296. align-items: flex-start;
  297. margin-bottom: 16px;
  298. line-height: 1.5;
  299. &:last-child {
  300. margin-bottom: 0;
  301. }
  302. }
  303. .label {
  304. color: #666;
  305. font-size: 28rpx;
  306. width: 160rpx;
  307. flex-shrink: 0;
  308. }
  309. .value {
  310. color: #333;
  311. font-size: 28rpx;
  312. flex: 1;
  313. word-break: break-all;
  314. }
  315. .link-text {
  316. color: #2979ff;
  317. cursor: pointer;
  318. &:active {
  319. opacity: 0.7;
  320. }
  321. }
  322. .status-text {
  323. &.status-1 {
  324. color: #e6a23c; // 待处理 - 橙色
  325. }
  326. &.status-2 {
  327. color: #409eff; // 处理中 - 蓝色
  328. }
  329. &.status-3 {
  330. color: #909399; // 仓库处理 - 灰色
  331. }
  332. &.status-4 {
  333. color: #67c23a; // 已完成 - 绿色
  334. }
  335. &.status-5 {
  336. color: #f56c6c; // 已作废 - 红色
  337. }
  338. }
  339. .image-list {
  340. display: flex;
  341. flex-wrap: wrap;
  342. gap: 20rpx;
  343. margin-top: 20rpx;
  344. }
  345. .work-order-image {
  346. width: 180rpx;
  347. height: 180rpx;
  348. border-radius: 8rpx;
  349. }
  350. </style>