混凝土运输管理微信小程序、替班
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.

397 lines
8.8 KiB

2 weeks ago
  1. <template>
  2. <view class="content">
  3. <navbar title="拒单申请管理" leftClick @leftClick="$utils.navigateBack" />
  4. <view class="header">
  5. <view class="title">拒单申请管理</view>
  6. <view class="subtitle">处理司机和企业的拒单申请</view>
  7. </view>
  8. <!-- 筛选栏 -->
  9. <view class="filter-bar">
  10. <view class="filter-item" :class="{active: currentStatus === 'all'}" @click="setStatus('all')">
  11. 全部
  12. </view>
  13. <view class="filter-item" :class="{active: currentStatus === 'pending'}" @click="setStatus('pending')">
  14. 待处理
  15. </view>
  16. <view class="filter-item" :class="{active: currentStatus === 'approved'}" @click="setStatus('approved')">
  17. 已通过
  18. </view>
  19. <view class="filter-item" :class="{active: currentStatus === 'rejected'}" @click="setStatus('rejected')">
  20. 已拒绝
  21. </view>
  22. </view>
  23. <!-- 申请列表 -->
  24. <view class="apply-list">
  25. <view v-if="filteredList.length === 0" class="empty-state">
  26. <view class="empty-icon">📋</view>
  27. <view class="empty-text">暂无拒单申请</view>
  28. </view>
  29. <view v-for="(item, index) in filteredList" :key="index" class="apply-item">
  30. <view class="item-header">
  31. <view class="applicant-info">
  32. <view class="name">{{ item.applicantName }}</view>
  33. <view class="role">{{ item.applicantRole }}</view>
  34. </view>
  35. <view class="apply-time">{{ item.applyTime }}</view>
  36. </view>
  37. <view class="order-info">
  38. <view class="order-title">{{ item.orderTitle }}</view>
  39. <view class="order-details">
  40. <text>订单编号{{ item.orderNo }}</text>
  41. <text>工作地点{{ item.workLocation }}</text>
  42. </view>
  43. </view>
  44. <view class="reject-reason">
  45. <view class="reason-label">拒单原因</view>
  46. <view class="reason-content">{{ item.rejectReason }}</view>
  47. </view>
  48. <view class="item-footer">
  49. <view class="status-badge" :class="item.status">
  50. {{ getStatusText(item.status) }}
  51. </view>
  52. <view v-if="item.status === 'pending'" class="action-buttons">
  53. <view class="btn approve" @click="approveApply(item)">通过</view>
  54. <view class="btn reject" @click="rejectApply(item)">拒绝</view>
  55. </view>
  56. <view v-else class="result-info">
  57. <text v-if="item.status === 'approved'">处理人{{ item.handler }}</text>
  58. <text v-if="item.status === 'rejected'">拒绝原因{{ item.handleReason }}</text>
  59. <text>处理时间{{ item.handleTime }}</text>
  60. </view>
  61. </view>
  62. </view>
  63. </view>
  64. </view>
  65. </template>
  66. <script>
  67. import navbar from '@/components/base/navbar.vue'
  68. export default {
  69. name: 'RejectApply',
  70. components: {
  71. navbar
  72. },
  73. data() {
  74. return {
  75. currentStatus: 'all',
  76. applyList: [
  77. {
  78. id: 1,
  79. applicantName: '张师傅',
  80. applicantRole: '泵车司机',
  81. applyTime: '2024-01-15 14:30',
  82. orderTitle: '雨花区建设项目混凝土运输',
  83. orderNo: 'ORD202401150001',
  84. workLocation: '长沙市雨花区某某路123号',
  85. rejectReason: '车辆故障,无法按时到达现场',
  86. status: 'pending'
  87. },
  88. {
  89. id: 2,
  90. applicantName: '李总',
  91. applicantRole: '企业负责人',
  92. applyTime: '2024-01-14 16:20',
  93. orderTitle: '岳麓区商业中心项目',
  94. orderNo: 'ORD202401140002',
  95. workLocation: '长沙市岳麓区某某大道456号',
  96. rejectReason: '天气原因,现场无法施工',
  97. status: 'approved',
  98. handler: '区域管理员王某',
  99. handleTime: '2024-01-14 17:00'
  100. },
  101. {
  102. id: 3,
  103. applicantName: '王师傅',
  104. applicantRole: '搅拌车司机',
  105. applyTime: '2024-01-13 10:15',
  106. orderTitle: '开福区住宅项目',
  107. orderNo: 'ORD202401130003',
  108. workLocation: '长沙市开福区某某街789号',
  109. rejectReason: '个人原因,无法完成订单',
  110. status: 'rejected',
  111. handler: '区域管理员王某',
  112. handleReason: '理由不充分',
  113. handleTime: '2024-01-13 11:30'
  114. }
  115. ]
  116. }
  117. },
  118. computed: {
  119. filteredList() {
  120. if (this.currentStatus === 'all') {
  121. return this.applyList;
  122. }
  123. return this.applyList.filter(item => item.status === this.currentStatus);
  124. }
  125. },
  126. onLoad() {
  127. uni.setNavigationBarTitle({
  128. title: '拒单申请管理'
  129. });
  130. },
  131. methods: {
  132. setStatus(status) {
  133. this.currentStatus = status;
  134. },
  135. getStatusText(status) {
  136. switch(status) {
  137. case 'pending': return '待处理';
  138. case 'approved': return '已通过';
  139. case 'rejected': return '已拒绝';
  140. default: return '未知状态';
  141. }
  142. },
  143. approveApply(item) {
  144. uni.showModal({
  145. title: '确认通过',
  146. content: `确定通过${item.applicantName}的拒单申请吗?`,
  147. success: (res) => {
  148. if (res.confirm) {
  149. item.status = 'approved';
  150. item.handler = '区域管理员';
  151. item.handleTime = new Date().toLocaleString();
  152. uni.showToast({
  153. title: '已通过申请',
  154. icon: 'success'
  155. });
  156. }
  157. }
  158. });
  159. },
  160. rejectApply(item) {
  161. uni.showModal({
  162. title: '拒绝申请',
  163. content: '请输入拒绝原因',
  164. editable: true,
  165. placeholderText: '请输入拒绝原因',
  166. success: (res) => {
  167. if (res.confirm) {
  168. item.status = 'rejected';
  169. item.handler = '区域管理员';
  170. item.handleReason = res.content || '无具体原因';
  171. item.handleTime = new Date().toLocaleString();
  172. uni.showToast({
  173. title: '已拒绝申请',
  174. icon: 'success'
  175. });
  176. }
  177. }
  178. });
  179. }
  180. }
  181. }
  182. </script>
  183. <style scoped lang="scss">
  184. .content {
  185. padding: 20rpx;
  186. min-height: 100vh;
  187. background-color: #f5f5f5;
  188. }
  189. .header {
  190. background-color: #fff;
  191. padding: 30rpx;
  192. border-radius: 10rpx;
  193. margin-bottom: 20rpx;
  194. text-align: center;
  195. .title {
  196. font-size: 36rpx;
  197. font-weight: bold;
  198. color: #333;
  199. margin-bottom: 10rpx;
  200. }
  201. .subtitle {
  202. font-size: 28rpx;
  203. color: #666;
  204. }
  205. }
  206. .filter-bar {
  207. display: flex;
  208. background-color: #fff;
  209. border-radius: 10rpx;
  210. padding: 20rpx;
  211. margin-bottom: 20rpx;
  212. gap: 20rpx;
  213. .filter-item {
  214. flex: 1;
  215. text-align: center;
  216. padding: 15rpx 0;
  217. border-radius: 25rpx;
  218. font-size: 28rpx;
  219. color: #666;
  220. background-color: #f8f8f8;
  221. transition: all 0.3s;
  222. &.active {
  223. color: #007AFF;
  224. background-color: #e6f3ff;
  225. border: 1rpx solid #007AFF;
  226. }
  227. }
  228. }
  229. .apply-list {
  230. .empty-state {
  231. text-align: center;
  232. padding: 100rpx 0;
  233. background-color: #fff;
  234. border-radius: 10rpx;
  235. .empty-icon {
  236. font-size: 120rpx;
  237. margin-bottom: 20rpx;
  238. }
  239. .empty-text {
  240. font-size: 28rpx;
  241. color: #999;
  242. }
  243. }
  244. .apply-item {
  245. background-color: #fff;
  246. border-radius: 10rpx;
  247. padding: 30rpx;
  248. margin-bottom: 20rpx;
  249. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
  250. .item-header {
  251. display: flex;
  252. justify-content: space-between;
  253. align-items: center;
  254. margin-bottom: 20rpx;
  255. .applicant-info {
  256. .name {
  257. font-size: 32rpx;
  258. font-weight: bold;
  259. color: #333;
  260. }
  261. .role {
  262. font-size: 24rpx;
  263. color: #666;
  264. margin-top: 5rpx;
  265. }
  266. }
  267. .apply-time {
  268. font-size: 24rpx;
  269. color: #999;
  270. }
  271. }
  272. .order-info {
  273. margin-bottom: 20rpx;
  274. padding: 20rpx;
  275. background-color: #f8f8f8;
  276. border-radius: 8rpx;
  277. .order-title {
  278. font-size: 30rpx;
  279. font-weight: bold;
  280. color: #333;
  281. margin-bottom: 10rpx;
  282. }
  283. .order-details {
  284. font-size: 26rpx;
  285. color: #666;
  286. line-height: 1.5;
  287. text {
  288. display: block;
  289. }
  290. }
  291. }
  292. .reject-reason {
  293. margin-bottom: 20rpx;
  294. .reason-label {
  295. font-size: 28rpx;
  296. color: #333;
  297. margin-bottom: 10rpx;
  298. }
  299. .reason-content {
  300. font-size: 26rpx;
  301. color: #666;
  302. line-height: 1.5;
  303. padding: 15rpx;
  304. background-color: #fff3cd;
  305. border-radius: 8rpx;
  306. border-left: 4rpx solid #ffc107;
  307. }
  308. }
  309. .item-footer {
  310. display: flex;
  311. justify-content: space-between;
  312. align-items: center;
  313. .status-badge {
  314. padding: 8rpx 16rpx;
  315. border-radius: 20rpx;
  316. font-size: 24rpx;
  317. color: #fff;
  318. &.pending {
  319. background-color: #ff9500;
  320. }
  321. &.approved {
  322. background-color: #34c759;
  323. }
  324. &.rejected {
  325. background-color: #ff3b30;
  326. }
  327. }
  328. .action-buttons {
  329. display: flex;
  330. gap: 15rpx;
  331. .btn {
  332. padding: 12rpx 24rpx;
  333. border-radius: 20rpx;
  334. font-size: 26rpx;
  335. color: #fff;
  336. &.approve {
  337. background-color: #34c759;
  338. }
  339. &.reject {
  340. background-color: #ff3b30;
  341. }
  342. }
  343. }
  344. .result-info {
  345. font-size: 24rpx;
  346. color: #666;
  347. line-height: 1.4;
  348. text {
  349. display: block;
  350. }
  351. }
  352. }
  353. }
  354. }
  355. </style>