| | |
| | | |
| | | <view v-if="contract.billStatusTip" :class="['cu-bill-tip', 'cu-bill-tip--inset', billTipClass(contract.billStatusType)]"> |
| | | |
| | | <text class="cu-bill-tip__icon">{{ billTipIcon(contract.billStatusType) }}</text> |
| | | <view class="cu-bill-tip__icon-box"> |
| | | |
| | | <u-icon :name="billTipIconName(contract.billStatusType)" color="#ffffff" size="18" /> |
| | | |
| | | </view> |
| | | |
| | | <text class="cu-bill-tip__text">{{ contract.billStatusTip }}</text> |
| | | |
| | |
| | | |
| | | <view class="cu-panel"> |
| | | |
| | | <view class="cu-panel__title">房源信息</view> |
| | | <view class="cu-panel__head"> |
| | | |
| | | <view class="cu-panel__icon cu-panel__icon--room"> |
| | | |
| | | <u-icon name="home-fill" color="#ffffff" size="20" /> |
| | | |
| | | </view> |
| | | |
| | | <text class="cu-panel__title-text">房源信息</text> |
| | | |
| | | </view> |
| | | |
| | | <view v-if="contract.roomList && contract.roomList.length" class="cu-room-list"> |
| | | |
| | |
| | | |
| | | <view class="cu-panel"> |
| | | |
| | | <view class="cu-panel__title">基本信息</view> |
| | | <view class="cu-panel__head"> |
| | | |
| | | <view class="cu-panel__icon cu-panel__icon--info"> |
| | | |
| | | <u-icon name="file-text-fill" color="#ffffff" size="20" /> |
| | | |
| | | </view> |
| | | |
| | | <text class="cu-panel__title-text">基本信息</text> |
| | | |
| | | </view> |
| | | |
| | | <view class="cu-kv__item"> |
| | | |
| | |
| | | |
| | | |
| | | |
| | | <view v-if="showZlClause" class="cu-panel cu-clause-panel cu-clause-panel--zl"> |
| | | |
| | | <view class="cu-clause-panel__head"> |
| | | |
| | | <view class="cu-clause-panel__badge"> |
| | | |
| | | <u-icon name="red-packet-fill" color="#ffffff" size="22" /> |
| | | |
| | | </view> |
| | | |
| | | <text class="cu-clause-panel__title">租赁条款</text> |
| | | |
| | | </view> |
| | | |
| | | |
| | | |
| | | <view class="cu-clause-summary"> |
| | | |
| | | <view class="cu-clause-chip"> |
| | | |
| | | <text class="cu-clause-chip__label">押金金额</text> |
| | | |
| | | <text class="cu-clause-chip__value">{{ formatDeposit(contract.zlDeposit) }}</text> |
| | | |
| | | </view> |
| | | |
| | | <view class="cu-clause-chip"> |
| | | |
| | | <text class="cu-clause-chip__label">付款方式</text> |
| | | |
| | | <text class="cu-clause-chip__value">{{ formatPayType(contract.zlPayType) }}</text> |
| | | |
| | | </view> |
| | | |
| | | <view class="cu-clause-chip cu-clause-chip--wide"> |
| | | |
| | | <text class="cu-clause-chip__label">免租期</text> |
| | | |
| | | <text class="cu-clause-chip__value">{{ formatFreePeriod(contract.zlFreeStartDate, contract.zlFreeEndDate) }}</text> |
| | | |
| | | </view> |
| | | |
| | | </view> |
| | | |
| | | |
| | | |
| | | <view v-if="contract.zlDetailList && contract.zlDetailList.length" class="cu-clause-detail-list"> |
| | | |
| | | <view v-for="(item, idx) in contract.zlDetailList" :key="item.id || idx" class="cu-clause-detail-card"> |
| | | |
| | | <view class="cu-clause-detail-grid"> |
| | | |
| | | <view class="cu-clause-detail-grid__item"> |
| | | |
| | | <text class="cu-clause-detail-grid__label">开始日期</text> |
| | | |
| | | <text class="cu-clause-detail-grid__value">{{ formatDate(item.startDate) || '-' }}</text> |
| | | |
| | | </view> |
| | | |
| | | <view class="cu-clause-detail-grid__item"> |
| | | |
| | | <text class="cu-clause-detail-grid__label">结束日期</text> |
| | | |
| | | <text class="cu-clause-detail-grid__value">{{ formatDate(item.endDate) || '-' }}</text> |
| | | |
| | | </view> |
| | | |
| | | <view class="cu-clause-detail-grid__item cu-clause-detail-grid__item--highlight"> |
| | | |
| | | <text class="cu-clause-detail-grid__label">合同单价</text> |
| | | |
| | | <text class="cu-clause-detail-grid__value">{{ formatPrice(item.price, item.circleType) }}</text> |
| | | |
| | | </view> |
| | | |
| | | <view class="cu-clause-detail-grid__item cu-clause-detail-grid__item--highlight"> |
| | | |
| | | <text class="cu-clause-detail-grid__label">付款提前天数</text> |
| | | |
| | | <text class="cu-clause-detail-grid__value">{{ item.advanceDays != null ? item.advanceDays + '天' : '-' }}</text> |
| | | |
| | | </view> |
| | | |
| | | </view> |
| | | |
| | | </view> |
| | | |
| | | </view> |
| | | |
| | | <view v-else class="cu-clause-empty">暂无条款明细</view> |
| | | |
| | | </view> |
| | | |
| | | |
| | | |
| | | <view v-if="showWyClause" class="cu-panel cu-clause-panel cu-clause-panel--wy"> |
| | | |
| | | <view class="cu-clause-panel__head"> |
| | | |
| | | <view class="cu-clause-panel__badge"> |
| | | |
| | | <u-icon name="tags-fill" color="#ffffff" size="22" /> |
| | | |
| | | </view> |
| | | |
| | | <text class="cu-clause-panel__title">物业费条款</text> |
| | | |
| | | </view> |
| | | |
| | | |
| | | |
| | | <view class="cu-clause-summary"> |
| | | |
| | | <view class="cu-clause-chip"> |
| | | |
| | | <text class="cu-clause-chip__label">押金金额</text> |
| | | |
| | | <text class="cu-clause-chip__value">{{ formatDeposit(contract.wyDeposit) }}</text> |
| | | |
| | | </view> |
| | | |
| | | <view class="cu-clause-chip"> |
| | | |
| | | <text class="cu-clause-chip__label">付款方式</text> |
| | | |
| | | <text class="cu-clause-chip__value">{{ formatPayType(contract.wyPayType) }}</text> |
| | | |
| | | </view> |
| | | |
| | | <view class="cu-clause-chip cu-clause-chip--wide"> |
| | | |
| | | <text class="cu-clause-chip__label">免租期</text> |
| | | |
| | | <text class="cu-clause-chip__value">{{ formatFreePeriod(contract.wyFreeStartDate, contract.wyFreeEndDate) }}</text> |
| | | |
| | | </view> |
| | | |
| | | </view> |
| | | |
| | | |
| | | |
| | | <view v-if="contract.wyDetailList && contract.wyDetailList.length" class="cu-clause-detail-list"> |
| | | |
| | | <view v-for="(item, idx) in contract.wyDetailList" :key="item.id || idx" class="cu-clause-detail-card"> |
| | | |
| | | <view class="cu-clause-detail-grid"> |
| | | |
| | | <view class="cu-clause-detail-grid__item"> |
| | | |
| | | <text class="cu-clause-detail-grid__label">开始日期</text> |
| | | |
| | | <text class="cu-clause-detail-grid__value">{{ formatDate(item.startDate) || '-' }}</text> |
| | | |
| | | </view> |
| | | |
| | | <view class="cu-clause-detail-grid__item"> |
| | | |
| | | <text class="cu-clause-detail-grid__label">结束日期</text> |
| | | |
| | | <text class="cu-clause-detail-grid__value">{{ formatDate(item.endDate) || '-' }}</text> |
| | | |
| | | </view> |
| | | |
| | | <view class="cu-clause-detail-grid__item cu-clause-detail-grid__item--highlight"> |
| | | |
| | | <text class="cu-clause-detail-grid__label">合同单价</text> |
| | | |
| | | <text class="cu-clause-detail-grid__value">{{ formatPrice(item.price, item.circleType) }}</text> |
| | | |
| | | </view> |
| | | |
| | | <view class="cu-clause-detail-grid__item cu-clause-detail-grid__item--highlight"> |
| | | |
| | | <text class="cu-clause-detail-grid__label">付款提前天数</text> |
| | | |
| | | <text class="cu-clause-detail-grid__value">{{ item.advanceDays != null ? item.advanceDays + '天' : '-' }}</text> |
| | | |
| | | </view> |
| | | |
| | | </view> |
| | | |
| | | </view> |
| | | |
| | | </view> |
| | | |
| | | <view v-else class="cu-clause-empty">暂无条款明细</view> |
| | | |
| | | </view> |
| | | |
| | | |
| | | |
| | | <view class="cu-panel"> |
| | | |
| | | <view class="cu-panel__title">合同附件</view> |
| | | <view class="cu-panel__head"> |
| | | |
| | | <view class="cu-panel__icon cu-panel__icon--file"> |
| | | |
| | | <u-icon name="folder" color="#ffffff" size="20" /> |
| | | |
| | | </view> |
| | | |
| | | <text class="cu-panel__title-text">合同附件</text> |
| | | |
| | | </view> |
| | | |
| | | <view v-if="contract.fileList && contract.fileList.length"> |
| | | |
| | |
| | | |
| | | > |
| | | |
| | | <text class="cu-file-item__icon">📎</text> |
| | | <view class="cu-file-item__icon-box"> |
| | | |
| | | <u-icon name="attach" color="#ffffff" size="22" /> |
| | | |
| | | </view> |
| | | |
| | | <view class="cu-file-item__main"> |
| | | |
| | |
| | | <script> |
| | | |
| | | import { customerContractDetail } from '@/api' |
| | | import { baseUrl } from '@/utils/config.js' |
| | | |
| | | const COST_TYPE_MAP = { |
| | | 0: '租赁费', |
| | |
| | | computed: { |
| | | receivableLabel () { return this.billType === 0 ? '应付金额' : '应收金额' }, |
| | | receivedLabel () { return this.billType === 0 ? '实付金额' : '实收金额' }, |
| | | dueDateLabel () { return this.billType === 0 ? '应付日期' : '应收日期' } |
| | | dueDateLabel () { return this.billType === 0 ? '应付日期' : '应收日期' }, |
| | | showZlClause () { |
| | | if (!this.contract) return false |
| | | const t = this.contract.type |
| | | return t === 0 || t === 2 |
| | | }, |
| | | showWyClause () { |
| | | if (!this.contract) return false |
| | | const t = this.contract.type |
| | | return t === 0 || t === 1 |
| | | } |
| | | }, |
| | | |
| | | onLoad (q) { this.id = q.id; this.load() }, |
| | |
| | | |
| | | if (reloadContract) this.contract = res.data.contract |
| | | |
| | | this.bills = res.data.bills || [] |
| | | this.bills = this.sortBillsByPlanPayDate(res.data.bills || []) |
| | | |
| | | }).finally(() => { |
| | | |
| | |
| | | |
| | | }, |
| | | |
| | | sortBillsByPlanPayDate (list) { |
| | | |
| | | return [...list].sort((a, b) => { |
| | | |
| | | const pa = this.formatDate(a.planPayDate) || '' |
| | | |
| | | const pb = this.formatDate(b.planPayDate) || '' |
| | | |
| | | if (pb !== pa) return pb.localeCompare(pa) |
| | | |
| | | return (b.id || 0) - (a.id || 0) |
| | | |
| | | }) |
| | | |
| | | }, |
| | | |
| | | costTypeText (type) { return COST_TYPE_MAP[type] || '账单' }, |
| | | |
| | | formatMoney (val) { |
| | |
| | | if (!val) return '' |
| | | |
| | | return String(val).replace('T', ' ').substring(0, 10) |
| | | |
| | | }, |
| | | |
| | | formatDeposit (val) { |
| | | |
| | | if (val === null || val === undefined || val === '') return '-' |
| | | |
| | | return `${val}元` |
| | | |
| | | }, |
| | | |
| | | formatPayType (payType) { |
| | | |
| | | if (payType === 1) return '每三个月一付' |
| | | |
| | | if (payType === 2) return '六个月一付' |
| | | |
| | | if (payType === 3) return '一年一付' |
| | | |
| | | if (payType === 0) return '一次性付款' |
| | | |
| | | return '-' |
| | | |
| | | }, |
| | | |
| | | formatFreePeriod (start, end) { |
| | | |
| | | const s = this.formatDate(start) |
| | | |
| | | const e = this.formatDate(end) |
| | | |
| | | if (!s && !e) return '-' |
| | | |
| | | return `${s || '-'} ~ ${e || '-'}` |
| | | |
| | | }, |
| | | |
| | | circleTypeUnit (type) { |
| | | |
| | | const map = { |
| | | |
| | | 0: '元/m²·天', |
| | | |
| | | 1: '元/m²·月', |
| | | |
| | | 2: '元/m²·年', |
| | | |
| | | 3: '元/天', |
| | | |
| | | 4: '元/月', |
| | | |
| | | 5: '元/年', |
| | | |
| | | 6: '元/场' |
| | | |
| | | } |
| | | |
| | | return map[type] || '' |
| | | |
| | | }, |
| | | |
| | | formatPrice (price, circleType) { |
| | | |
| | | if (price === null || price === undefined || price === '') return '-' |
| | | |
| | | const unit = this.circleTypeUnit(circleType) |
| | | |
| | | return unit ? `${price} ${unit}` : String(price) |
| | | |
| | | }, |
| | | |
| | |
| | | |
| | | }, |
| | | |
| | | billTipIcon (type) { |
| | | billTipIconName (type) { |
| | | |
| | | if (type === 'danger') return '⚠️' |
| | | if (type === 'danger') return 'close-circle-fill' |
| | | |
| | | if (type === 'warn') return '⏰' |
| | | if (type === 'warn') return 'clock-fill' |
| | | |
| | | return '✅' |
| | | return 'checkmark-circle-fill' |
| | | |
| | | }, |
| | | |
| | | resolveFileUrl (raw) { |
| | | |
| | | if (!raw) return '' |
| | | |
| | | const url = String(raw).trim() |
| | | |
| | | if (/^https?:\/\//i.test(url)) return url |
| | | |
| | | if (typeof window === 'undefined') return url |
| | | |
| | | if (url.startsWith('//')) return `${window.location.protocol}${url}` |
| | | |
| | | if (url.startsWith('/')) return `${window.location.origin}${url}` |
| | | |
| | | try { |
| | | |
| | | const origin = new URL(baseUrl, window.location.href).origin |
| | | |
| | | return `${origin}/${url.replace(/^\/+/, '')}` |
| | | |
| | | } catch (e) { |
| | | |
| | | return `${window.location.origin}/${url.replace(/^\/+/, '')}` |
| | | |
| | | } |
| | | |
| | | }, |
| | | |
| | | openFile (file) { |
| | | |
| | | const url = file.fileurlFull || file.fileurl |
| | | const url = this.resolveFileUrl(file.fileurlFull || file.fileurl) |
| | | |
| | | if (!url) { |
| | | |
| | |
| | | |
| | | } |
| | | |
| | | // #ifdef H5 |
| | | if (typeof window !== 'undefined' && window.document) { |
| | | |
| | | window.open(url, '_blank') |
| | | const link = document.createElement('a') |
| | | |
| | | // #endif |
| | | link.style.display = 'none' |
| | | |
| | | // #ifndef H5 |
| | | link.href = url |
| | | |
| | | link.target = '_blank' |
| | | |
| | | link.rel = 'noopener noreferrer' |
| | | |
| | | if (file.name) link.setAttribute('download', file.name) |
| | | |
| | | document.body.appendChild(link) |
| | | |
| | | link.click() |
| | | |
| | | document.body.removeChild(link) |
| | | |
| | | return |
| | | |
| | | } |
| | | |
| | | uni.showLoading({ title: '下载中' }) |
| | | |
| | |
| | | complete: () => uni.hideLoading() |
| | | |
| | | }) |
| | | |
| | | // #endif |
| | | |
| | | } |
| | | |