serviceOrderDetail.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. <template>
  2. <view class="container">
  3. <!-- 导航栏 -->
  4. <view class="navbar">
  5. <view class="nav-left" @click="goBack">
  6. <text class="back-icon"><</text>
  7. </view>
  8. <view class="nav-title">服务单详情</view>
  9. <view class="nav-right">
  10. <text class="more-icon">...</text>
  11. <text class="eye-icon">O</text>
  12. </view>
  13. </view>
  14. <!-- 内容区域 -->
  15. <scroll-view class="content" scroll-y>
  16. <view class="detail-section">
  17. <!-- 服务单标题和已确认标识 -->
  18. <view class="order-header">
  19. <view class="order-title-text">服务单</view>
  20. <view class="confirmed-stamp" v-if="orderDetail.status === 1">已确认</view>
  21. </view>
  22. <!-- 服务内容 -->
  23. <view class="service-content">
  24. <view class="content-title">尊敬的用户: 本次劳务内容:</view>
  25. <!-- 服务表格 -->
  26. <view class="service-table">
  27. <view class="table-header">
  28. <view class="table-cell">具体实施项目</view>
  29. <view class="table-cell">单场金额</view>
  30. <view class="table-cell">完成时间</view>
  31. <view class="table-cell">单位</view>
  32. <view class="table-cell">数量</view>
  33. <view class="table-cell">总金额</view>
  34. </view>
  35. <view class="table-row" v-for="(item, index) in orderDetail.serviceItems" :key="index">
  36. <view class="table-cell">{{ item.projectName }}</view>
  37. <view class="table-cell">{{ item.singleAmount }}</view>
  38. <view class="table-cell">{{ item.completeTime }}</view>
  39. <view class="table-cell">{{ item.unit }}</view>
  40. <view class="table-cell">{{ item.quantity }}</view>
  41. <view class="table-cell">{{ item.totalAmount }}</view>
  42. </view>
  43. </view>
  44. </view>
  45. <!-- 协议内容 -->
  46. <view class="agreement-content">
  47. <view class="agreement-text">
  48. 甲乙双方已签订《服务协议》,乙方实际向甲方提供上述服务,现双方确认该工作已全部完成。乙方确认该笔收入为自己的合理劳动所得,并同意依法纳税,乙方提供银行卡、身份证信息给甲方用于报税,甲方承诺为乙方个人信息保密。
  49. </view>
  50. <view class="payment-info">
  51. <view class="payment-text">
  52. 我司将向您支付人民币[{{ orderDetail.totalAmount || '1534' }}]元(大写:{{ orderDetail.amountInWords || '壹仟伍佰叁拾肆元整' }})作为此次劳务报酬(该服务报酬为我司代扣代缴相关税款后的金额),款项将汇入如下账户:
  53. </view>
  54. <view class="account-info">
  55. <view class="account-item">
  56. <text class="account-label">姓名:</text>
  57. <text class="account-value">{{ orderDetail.accountName || '王小明' }}</text>
  58. </view>
  59. <view class="account-item">
  60. <text class="account-label">开户行:</text>
  61. <text class="account-value">{{ orderDetail.bankName || '中国农业银行' }}</text>
  62. </view>
  63. <view class="account-item">
  64. <text class="account-label">账号:</text>
  65. <text class="account-value">{{ orderDetail.accountNumber || '6524012536580258' }}</text>
  66. </view>
  67. </view>
  68. </view>
  69. </view>
  70. </view>
  71. <!-- 确认选项(仅待确认状态显示) -->
  72. <view class="confirm-options" v-if="orderDetail.status === 0">
  73. <view class="option-item">
  74. <checkbox-group @change="onOptionChange">
  75. <label class="option-label">
  76. <checkbox value="promise" :checked="confirmOptions.promise" color="#388BFF" />
  77. <text class="option-text">承诺上述服务已真实发生;</text>
  78. </label>
  79. </checkbox-group>
  80. </view>
  81. <view class="option-item">
  82. <checkbox-group @change="onOptionChange">
  83. <label class="option-label">
  84. <checkbox value="lecture" :checked="confirmOptions.lecture" color="#388BFF" />
  85. <text class="option-text">【适用于提供讲课服务的情形】在提供本次服务之前,已充分悉知和了解讲课内容的材料。</text>
  86. </label>
  87. </checkbox-group>
  88. </view>
  89. </view>
  90. </scroll-view>
  91. <!-- 底部按钮(仅待确认状态显示) -->
  92. <view class="bottom-bar" v-if="orderDetail.status === 0">
  93. <view class="btn btn-cancel" @click="goBack">返回</view>
  94. <view class="btn btn-confirm" @click="handleConfirm">确认</view>
  95. </view>
  96. </view>
  97. </template>
  98. <script>
  99. import { getServiceOrderDetail, confirmServiceOrder } from '@/api-js/serviceOrder'
  100. export default {
  101. data() {
  102. return {
  103. orderId: '',
  104. orderDetail: {
  105. status: 0,
  106. totalAmount: '1534',
  107. amountInWords: '壹仟伍佰叁拾肆元整',
  108. accountName: '王小明',
  109. bankName: '中国农业银行',
  110. accountNumber: '6524012536580258',
  111. serviceItems: []
  112. },
  113. confirmOptions: {
  114. promise: false,
  115. lecture: false
  116. }
  117. }
  118. },
  119. onLoad(options) {
  120. if (options.id) {
  121. this.orderId = options.id
  122. }
  123. if (options.status) {
  124. this.orderDetail.status = parseInt(options.status)
  125. }
  126. this.loadOrderDetail()
  127. },
  128. methods: {
  129. async loadOrderDetail() {
  130. try {
  131. uni.showLoading({ title: '加载中...' })
  132. const res = await getServiceOrderDetail({ id: this.orderId })
  133. uni.hideLoading()
  134. if (res.code === 200 && res.data) {
  135. this.orderDetail = { ...this.orderDetail, ...res.data }
  136. } else {
  137. // 使用示例数据
  138. this.orderDetail.serviceItems = [
  139. { projectName: '病例征集', singleAmount: '111.00', completeTime: '2023年9月12日', unit: '个', quantity: 1, totalAmount: '111.00' },
  140. { projectName: '病例征集', singleAmount: '100.00', completeTime: '2023年9月12日', unit: '个', quantity: 1, totalAmount: '100.00' },
  141. { projectName: '病例征集', singleAmount: '100.00', completeTime: '2023年9月12日', unit: '个', quantity: 1, totalAmount: '100.00' },
  142. { projectName: '病例征集', singleAmount: '1200.00', completeTime: '2023年9月12日', unit: '个', quantity: 1, totalAmount: '1200.00' },
  143. { projectName: '病例征集', singleAmount: '23.00', completeTime: '2023年9月12日', unit: '个', quantity: 1, totalAmount: '23.00' }
  144. ]
  145. }
  146. } catch (e) {
  147. uni.hideLoading()
  148. console.error('加载服务单详情失败', e)
  149. // 使用示例数据
  150. this.orderDetail.serviceItems = [
  151. { projectName: '病例征集', singleAmount: '111.00', completeTime: '2023年9月12日', unit: '个', quantity: 1, totalAmount: '111.00' },
  152. { projectName: '病例征集', singleAmount: '100.00', completeTime: '2023年9月12日', unit: '个', quantity: 1, totalAmount: '100.00' },
  153. { projectName: '病例征集', singleAmount: '100.00', completeTime: '2023年9月12日', unit: '个', quantity: 1, totalAmount: '100.00' },
  154. { projectName: '病例征集', singleAmount: '1200.00', completeTime: '2023年9月12日', unit: '个', quantity: 1, totalAmount: '1200.00' },
  155. { projectName: '病例征集', singleAmount: '23.00', completeTime: '2023年9月12日', unit: '个', quantity: 1, totalAmount: '23.00' }
  156. ]
  157. }
  158. },
  159. onOptionChange(e) {
  160. const values = e.detail.value
  161. this.confirmOptions.promise = values.includes('promise')
  162. this.confirmOptions.lecture = values.includes('lecture')
  163. },
  164. goBack() {
  165. uni.navigateBack()
  166. },
  167. async handleConfirm() {
  168. if (!this.confirmOptions.promise) {
  169. uni.showToast({
  170. icon: 'none',
  171. title: '请确认上述服务已真实发生'
  172. })
  173. return
  174. }
  175. try {
  176. uni.showLoading({ title: '确认中...' })
  177. const res = await confirmServiceOrder({
  178. id: this.orderId,
  179. confirmOptions: this.confirmOptions
  180. })
  181. uni.hideLoading()
  182. if (res.code === 200) {
  183. uni.showToast({
  184. icon: 'success',
  185. title: '确认成功'
  186. })
  187. setTimeout(() => {
  188. uni.navigateBack()
  189. }, 1500)
  190. } else {
  191. uni.showToast({
  192. icon: 'none',
  193. title: res.msg || '确认失败'
  194. })
  195. }
  196. } catch (e) {
  197. uni.hideLoading()
  198. uni.showToast({
  199. icon: 'none',
  200. title: '确认失败'
  201. })
  202. }
  203. }
  204. }
  205. }
  206. </script>
  207. <style lang="scss" scoped>
  208. .container {
  209. min-height: 100vh;
  210. background: #f5f5f5;
  211. display: flex;
  212. flex-direction: column;
  213. }
  214. .navbar {
  215. display: flex;
  216. align-items: center;
  217. justify-content: space-between;
  218. padding: 20rpx 24rpx;
  219. background: #fff;
  220. border-bottom: 1rpx solid #f0f0f0;
  221. .nav-left {
  222. width: 60rpx;
  223. .back-icon {
  224. font-size: 36rpx;
  225. color: #333;
  226. font-weight: bold;
  227. }
  228. }
  229. .nav-title {
  230. flex: 1;
  231. text-align: center;
  232. font-size: 36rpx;
  233. font-weight: bold;
  234. color: #333;
  235. }
  236. .nav-right {
  237. display: flex;
  238. align-items: center;
  239. gap: 24rpx;
  240. width: 60rpx;
  241. justify-content: flex-end;
  242. .more-icon {
  243. font-size: 32rpx;
  244. color: #333;
  245. }
  246. .eye-icon {
  247. font-size: 32rpx;
  248. color: #333;
  249. }
  250. }
  251. }
  252. .content {
  253. flex: 1;
  254. padding-bottom: 140rpx;
  255. }
  256. .detail-section {
  257. background: #fff;
  258. margin: 24rpx;
  259. border-radius: 16rpx;
  260. padding: 32rpx;
  261. }
  262. .order-header {
  263. position: relative;
  264. text-align: center;
  265. margin-bottom: 32rpx;
  266. .order-title-text {
  267. font-size: 36rpx;
  268. font-weight: bold;
  269. color: #333;
  270. }
  271. .confirmed-stamp {
  272. position: absolute;
  273. right: 0;
  274. top: 50%;
  275. transform: translateY(-50%) rotate(-15deg);
  276. width: 120rpx;
  277. height: 120rpx;
  278. border: 4rpx solid rgba(0, 0, 0, 0.1);
  279. border-radius: 50%;
  280. display: flex;
  281. align-items: center;
  282. justify-content: center;
  283. font-size: 24rpx;
  284. color: rgba(0, 0, 0, 0.4);
  285. background: rgba(255, 255, 255, 0.8);
  286. }
  287. }
  288. .service-content {
  289. margin-bottom: 32rpx;
  290. .content-title {
  291. font-size: 28rpx;
  292. color: #333;
  293. margin-bottom: 24rpx;
  294. }
  295. .service-table {
  296. border: 1rpx solid #EBEDF0;
  297. border-radius: 8rpx;
  298. overflow: hidden;
  299. overflow-x: auto;
  300. .table-header,
  301. .table-row {
  302. display: flex;
  303. min-width: 1000rpx;
  304. .table-cell {
  305. flex: 1;
  306. min-width: 140rpx;
  307. padding: 16rpx 8rpx;
  308. font-size: 22rpx;
  309. text-align: center;
  310. border-right: 1rpx solid #EBEDF0;
  311. word-break: break-all;
  312. &:first-child {
  313. min-width: 200rpx;
  314. }
  315. &:last-child {
  316. border-right: none;
  317. }
  318. }
  319. }
  320. .table-header {
  321. background: #f5f5f5;
  322. .table-cell {
  323. font-weight: 500;
  324. color: #333;
  325. }
  326. }
  327. .table-row {
  328. border-top: 1rpx solid #EBEDF0;
  329. .table-cell {
  330. color: #666;
  331. }
  332. }
  333. }
  334. }
  335. .agreement-content {
  336. .agreement-text,
  337. .payment-text {
  338. font-size: 26rpx;
  339. color: #666;
  340. line-height: 1.8;
  341. margin-bottom: 24rpx;
  342. }
  343. .account-info {
  344. margin-top: 24rpx;
  345. .account-item {
  346. margin-bottom: 16rpx;
  347. font-size: 26rpx;
  348. .account-label {
  349. color: #666;
  350. }
  351. .account-value {
  352. color: #333;
  353. margin-left: 8rpx;
  354. }
  355. }
  356. }
  357. }
  358. .confirm-options {
  359. background: #fff;
  360. margin: 0 24rpx 24rpx;
  361. border-radius: 16rpx;
  362. padding: 32rpx;
  363. .option-item {
  364. margin-bottom: 24rpx;
  365. &:last-child {
  366. margin-bottom: 0;
  367. }
  368. .option-label {
  369. display: flex;
  370. align-items: flex-start;
  371. .option-text {
  372. flex: 1;
  373. margin-left: 8rpx;
  374. font-size: 26rpx;
  375. color: #333;
  376. line-height: 1.8;
  377. }
  378. }
  379. }
  380. }
  381. .bottom-bar {
  382. position: fixed;
  383. bottom: 0;
  384. left: 0;
  385. right: 0;
  386. background: #fff;
  387. padding: 24rpx;
  388. border-top: 1rpx solid #f0f0f0;
  389. z-index: 100;
  390. display: flex;
  391. gap: 24rpx;
  392. .btn {
  393. flex: 1;
  394. height: 88rpx;
  395. display: flex;
  396. align-items: center;
  397. justify-content: center;
  398. border-radius: 44rpx;
  399. font-size: 32rpx;
  400. font-weight: 500;
  401. &.btn-cancel {
  402. background: #fff;
  403. border: 2rpx solid #388BFF;
  404. color: #388BFF;
  405. }
  406. &.btn-confirm {
  407. background: #388BFF;
  408. color: #fff;
  409. }
  410. }
  411. }
  412. </style>