| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561 |
- <template>
- <view class="container">
- <!-- 内容区域 -->
- <scroll-view class="content" scroll-y>
- <view class="detail-section">
- <!-- 服务单标题和已确认标识 -->
- <view class="order-header">
- <view class="order-title-text">服务单</view>
- <image class="w144 h144" v-if="serviceOrder.doctorConfirm === 1" src="@/static/image/img_confirmed.png" mode=""></image>
- </view>
-
- <!-- 服务内容 -->
- <view class="service-content">
- <view class="content-title">尊敬的用户: 本次劳务内容:</view>
-
- <!-- 服务表格 -->
- <view class="service-table">
- <view class="table-header">
- <view class="table-cell">具体实施项目</view>
- <view class="table-cell">单场金额</view>
- <view class="table-cell">完成时间</view>
- <view class="table-cell">单位</view>
- <view class="table-cell">数量</view>
- <view class="table-cell">总金额</view>
- </view>
- <view class="table-row" v-for="(item, index) in orderDetail.serviceItems" :key="index">
- <view class="table-cell x-c">{{ item.projectName }}</view>
- <view class="table-cell x-c">{{ item.taskIntegral}}</view>
- <view class="table-cell x-c">{{ formatDate(item.planEndTime) }}</view>
- <view class="table-cell x-c">{{ item.taskUnit}}</view>
- <view class="table-cell x-c">{{ item.taskCount }}</view>
- <view class="table-cell x-c">{{ totalAmount }}</view>
- </view>
- </view>
- </view>
-
- <!-- 协议内容 -->
- <view class="agreement-content">
- <view class="agreement-text">
- 甲乙双方已签订《服务协议》,乙方实际向甲方提供上述服务,现双方确认该工作已全部完成。乙方确认该笔收入为自己的合理劳动所得,并同意依法纳税,乙方提供银行卡、身份证信息给甲方用于报税,甲方承诺为乙方个人信息保密。
- </view>
-
- <view class="payment-info">
- <view class="payment-text">
- 我司将向您支付人民币[{{ totalAmount || 0 }}]元(大写:{{ convertToChineseAmount(totalAmount) || '-' }})作为此次劳务报酬(该服务报酬为我司代扣代缴相关税款后的金额),款项将汇入如下账户:
- </view>
-
- <view class="account-info">
- <view class="account-item">
- <text class="account-label">姓名:</text>
- <text class="account-value">{{ serviceOrder.initiatorName || '王小明' }}</text>
- </view>
- <view class="account-item">
- <text class="account-label">开户行:</text>
- <text class="account-value">{{ orderDetail.bankName || '中国农业银行' }}</text>
- </view>
- <view class="account-item">
- <text class="account-label">账号:</text>
- <text class="account-value">{{ orderDetail.bankCardNo || '6524012536580258' }}</text>
- </view>
- </view>
- </view>
- </view>
- </view>
- </scroll-view>
-
- <view class="confirm-box" v-if="serviceOrder.doctorConfirm === 0">
- <!-- 确认选项(仅待确认状态显示) -->
- <view class="confirm-options">
- <view class="option-item">
- <checkbox-group @change="onOptionChange">
- <label class="option-label">
- <checkbox value="promise" :checked="confirmOptions.promise" color="#388BFF" />
- <text class="option-text">承诺上述服务已真实发生;</text>
- </label>
- </checkbox-group>
- </view>
- <view class="option-item">
- <checkbox-group @change="onOptionChange">
- <label class="option-label">
- <checkbox value="lecture" :checked="confirmOptions.lecture" color="#388BFF" />
- <text class="option-text">【适用于提供讲课服务的情形】在提供本次服务之前,已充分悉知和了解讲课内容的材料。</text>
- </label>
- </checkbox-group>
- </view>
- </view>
- <!-- 底部按钮(仅待确认状态显示) -->
- <view class="bottom-bar" v-if="orderDetail.status === 0">
- <view class="btn btn-cancel" @click="goBack">返回</view>
- <view class="btn btn-confirm" @click="handleConfirm">确认</view>
- </view>
- </view>
-
- </view>
- </template>
- <script>
- import { getServiceOrderDetail, confirmServiceOrder } from '@/api/serviceOrder'
- import utils from '@/utils/common.js'
- export default {
- data() {
- return {
- serviceOrderId:null,
- serviceOrder:{},
- totalAmount:0,
- orderDetail: {
- status: 0,
- totalAmount: '1534',
- amountInWords: '壹仟伍佰叁拾肆元整',
- accountName: '王小明',
- bankName: '中国农业银行',
- accountNumber: '6524012536580258',
- serviceItems: []
- },
- confirmOptions: {
- promise: false,
- lecture: false
- },
- user:{},
- utils: utils // 将 utils 挂载到 data 中,以便在模板中使用
- }
- },
- onLoad(options) {
- if (options.id) {
- this.serviceOrderId = options.id
- }
- this.loadOrderDetail()
- },
- methods: {
- async loadOrderDetail() {
- try {
- uni.showLoading({ title: '加载中...' })
- const res = await getServiceOrderDetail({ serviceOrderId: this.serviceOrderId })
- uni.hideLoading()
-
- if (res.code === 200 && res.data) {
- this.orderDetail = { ...this.orderDetail, ...res.data }
- if (res.data.serviceOrderInfoVO) {
- this.orderDetail.serviceItems = res.data.serviceOrderInfoVO.taskInfos
- this.serviceOrder = res.data.serviceOrderInfoVO.serviceOrder
- this.totalAmount = this.serviceOrder.totalAmount
- }
- } else {
- uni.hideLoading();
- uni.showToast({
- icon:'none',
- title: res.msg,
- });
- }
- } catch (e) {
- uni.hideLoading()
- console.error('加载服务单详情失败', e)
- }
- },
- onOptionChange(e) {
- const values = e.detail.value
- this.confirmOptions.promise = values.includes('promise')
- this.confirmOptions.lecture = values.includes('lecture')
- },
- // 格式化日期字符串为年月日格式
- formatDate(dateStr) {
- if (!dateStr) return ''
- // 处理 "2026-02-05" 格式的日期字符串
- if (typeof dateStr === 'string' && dateStr.includes('-')) {
- // 将 "2026-02-05" 转换为 Date 对象
- const date = new Date(dateStr.replace(/-/g, '/'))
- // 使用 utils.timeFormat 格式化
- return utils.timeFormat(date.getTime(), 'yyyy年mm月dd日')
- }
- // 如果是时间戳,直接使用
- return utils.timeFormat(dateStr, 'yyyy年mm月dd日')
- },
- // 将数字金额转换为中文大写
- convertToChineseAmount(amount) {
- if (!amount && amount !== 0) return ''
-
- // 转换为数字
- const num = Number(amount)
- if (isNaN(num) || num < 0) return ''
-
- // 中文数字
- const chineseNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
- // 单位
- const units = ['', '拾', '佰', '仟']
- const bigUnits = ['', '万', '亿']
-
- // 处理小数部分
- const parts = num.toString().split('.')
- const integerPart = Math.floor(num)
- const decimalPart = parts[1] ? parts[1].substring(0, 2) : '' // 最多两位小数
-
- // 转换整数部分
- let integerStr = integerPart.toString()
- let result = ''
-
- if (integerPart === 0) {
- result = '零'
- } else {
- // 每4位一组处理
- const groups = []
- while (integerStr.length > 0) {
- groups.unshift(integerStr.slice(-4))
- integerStr = integerStr.slice(0, -4)
- }
-
- groups.forEach((group, groupIndex) => {
- const groupNum = parseInt(group)
- if (groupNum === 0) {
- // 如果这一组是0,且不是最后一组,添加"零"
- if (groupIndex < groups.length - 1) {
- result += '零'
- }
- return
- }
-
- let groupStr = ''
- for (let i = 0; i < group.length; i++) {
- const digit = parseInt(group[i])
- const pos = group.length - 1 - i
-
- if (digit === 0) {
- // 如果当前位是0,且下一位不是0,添加"零"
- if (i < group.length - 1 && parseInt(group[i + 1]) !== 0) {
- groupStr += '零'
- }
- } else {
- groupStr += chineseNums[digit] + units[pos]
- }
- }
-
- result += groupStr
- // 添加大单位(万、亿)
- if (groupIndex < groups.length - 1) {
- const bigUnitIndex = groups.length - 1 - groupIndex - 1
- if (bigUnitIndex < bigUnits.length) {
- result += bigUnits[bigUnitIndex]
- }
- }
- })
- }
-
- result += '元'
-
- // 处理小数部分
- if (decimalPart) {
- if (decimalPart.length === 1) {
- const d1 = parseInt(decimalPart[0])
- if (d1 !== 0) {
- result += chineseNums[d1] + '角'
- }
- } else if (decimalPart.length === 2) {
- const d1 = parseInt(decimalPart[0])
- const d2 = parseInt(decimalPart[1])
- if (d1 !== 0) {
- result += chineseNums[d1] + '角'
- }
- if (d2 !== 0) {
- result += chineseNums[d2] + '分'
- }
- }
- } else {
- result += '整'
- }
-
- return result
- },
- goBack() {
- uni.navigateBack()
- },
- async handleConfirm() {
- var user = JSON.parse(uni.getStorageSync('userInfo'))
- // 验证至少选中一个选项(二选一)
- if (!this.confirmOptions.promise && !this.confirmOptions.lecture) {
- uni.showToast({
- icon: 'none',
- title: '请至少选择一个确认选项'
- })
- return
- }
-
- try {
- uni.showLoading({ title: '确认中...' })
- const res = await confirmServiceOrder({
- serviceOrderId: this.serviceOrderId,
- totalAmount:this.totalAmount,
- userId:user.id
- })
- uni.hideLoading()
-
- if (res.code === 200) {
- uni.showToast({
- icon: 'success',
- title: '确认成功'
- })
- setTimeout(() => {
- uni.navigateBack()
- }, 1000)
- } else {
- uni.showToast({
- icon: 'none',
- title: res.msg || '确认失败'
- })
- }
- } catch (e) {
- uni.hideLoading()
- uni.showToast({
- icon: 'none',
- title: '确认失败'
- })
- }
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .container {
- min-height: 100vh;
- background: #fff;
- display: flex;
- flex-direction: column;
- }
- .navbar {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 20rpx 24rpx;
- background: #fff;
- border-bottom: 1rpx solid #f0f0f0;
-
- .nav-left {
- width: 60rpx;
-
- .back-icon {
- font-size: 36rpx;
- color: #333;
- font-weight: bold;
- }
- }
-
- .nav-title {
- flex: 1;
- text-align: center;
- font-size: 36rpx;
- font-weight: bold;
- color: #333;
- }
-
- .nav-right {
- display: flex;
- align-items: center;
- gap: 24rpx;
- width: 60rpx;
- justify-content: flex-end;
-
- .more-icon {
- font-size: 32rpx;
- color: #333;
- }
-
- .eye-icon {
- font-size: 32rpx;
- color: #333;
- }
- }
- }
- .content {
- flex: 1;
- padding-bottom: 400rpx;
- }
- .detail-section {
- background: #fff;
- // margin: 24rpx;
- // border-radius: 16rpx;
- padding: 32rpx;
- }
- .order-header {
- position: relative;
- text-align: center;
- margin-bottom: 32rpx;
- image{
- position: absolute;
- right: 0;
- top: 0;
- }
- .order-title-text {
- font-size: 36rpx;
- font-weight: bold;
- color: #333;
- }
-
- .confirmed-stamp {
- position: absolute;
- right: 0;
- top: 50%;
- transform: translateY(-50%) rotate(-15deg);
- width: 120rpx;
- height: 120rpx;
- border: 4rpx solid rgba(0, 0, 0, 0.1);
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 24rpx;
- color: rgba(0, 0, 0, 0.4);
- background: rgba(255, 255, 255, 0.8);
- }
- }
- .service-content {
- margin-bottom: 32rpx;
-
- .content-title {
- font-size: 28rpx;
- color: #333;
- margin-bottom: 24rpx;
- }
-
- .service-table {
- border: 1rpx solid #EBEDF0;
- border-radius: 8rpx;
- overflow: hidden;
- width: 100%;
-
- .table-header,
- .table-row {
- display: flex;
- width: 100%;
-
- .table-cell {
- flex: 1;
- padding: 16rpx 8rpx;
- font-size: 22rpx;
- text-align: center;
- border-right: 1rpx solid #EBEDF0;
- word-break: break-all;
- box-sizing: border-box;
-
- &:last-child {
- border-right: none;
- }
- }
- }
-
- .table-header {
- background: #f5f5f5;
-
- .table-cell {
- font-weight: 500;
- color: #333;
- }
- }
-
- .table-row {
- border-top: 1rpx solid #EBEDF0;
-
- .table-cell {
- color: #666;
- }
- }
- }
- }
- .agreement-content {
- .agreement-text,
- .payment-text {
- font-size: 26rpx;
- color: #666;
- line-height: 1.8;
- margin-bottom: 24rpx;
- }
-
- .account-info {
- margin-top: 24rpx;
-
- .account-item {
- margin-bottom: 16rpx;
- font-size: 26rpx;
-
- .account-label {
- color: #666;
- }
-
- .account-value {
- color: #333;
- margin-left: 8rpx;
- }
- }
- }
- }
- .confirm-box{
- position: fixed;
- bottom: 0;
- left: 0;
- right: 0;
- background: #fff;
- // padding: 24rpx;
- border-top: 1rpx solid #f0f0f0;
- z-index: 100;
- box-shadow: 0rpx -4rpx 16rpx 0rpx rgba(0,0,0,0.04);
- }
- .confirm-options {
- background: #fff;
- border-radius: 16rpx;
- padding: 32rpx;
- .option-item {
- margin-bottom: 24rpx;
-
- &:last-child {
- margin-bottom: 0;
- }
-
- .option-label {
- display: flex;
- align-items: flex-start;
-
- .option-text {
- flex: 1;
- margin-left: 8rpx;
- font-size: 26rpx;
- color: #333;
- line-height: 1.8;
- }
- }
- }
- }
- .bottom-bar {
- padding:24rpx 32rpx;
- display: flex;
- gap: 24rpx;
- margin-bottom: 40rpx;
- .btn {
- flex: 1;
- height: 88rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 44rpx;
- font-size: 32rpx;
- font-weight: 500;
-
- &.btn-cancel {
- background: #fff;
- border: 2rpx solid #388BFF;
- color: #388BFF;
- }
-
- &.btn-confirm {
- background: #388BFF;
- color: #fff;
- }
- }
- }
- </style>
|