|
|
@@ -0,0 +1,803 @@
|
|
|
+<template>
|
|
|
+ <div class="facilities-dialog-container">
|
|
|
+ <div class="container">
|
|
|
+ <h4 class="tit">委托基本信息</h4>
|
|
|
+ <van-cell-group>
|
|
|
+ <van-cell
|
|
|
+ class="cell-item"
|
|
|
+ title="委托人(甲方)"
|
|
|
+ :value="state.form?.commitName"
|
|
|
+ />
|
|
|
+ <van-cell
|
|
|
+ class="cell-item"
|
|
|
+ title="委托人电话"
|
|
|
+ :value="state.form?.commitContact"
|
|
|
+ />
|
|
|
+ <van-cell
|
|
|
+ class="cell-item"
|
|
|
+ title="导师(经费人)"
|
|
|
+ :value="state.form?.teacherName"
|
|
|
+ />
|
|
|
+ <van-cell
|
|
|
+ class="cell-item"
|
|
|
+ title="导师电话"
|
|
|
+ :value="state.form?.teacherContact"
|
|
|
+ />
|
|
|
+ <van-cell
|
|
|
+ class="cell-item"
|
|
|
+ title="单位/科室"
|
|
|
+ :value="state.form?.deptName"
|
|
|
+ />
|
|
|
+ <van-cell
|
|
|
+ class="cell-item"
|
|
|
+ title="委托人邮箱"
|
|
|
+ :value="state.form?.commitMail"
|
|
|
+ />
|
|
|
+ <van-cell
|
|
|
+ class="cell-item"
|
|
|
+ title="课题组"
|
|
|
+ :value="state.form?.projName"
|
|
|
+ />
|
|
|
+ <van-cell
|
|
|
+ class="cell-item"
|
|
|
+ title="证件号"
|
|
|
+ :value="state.form?.studentNo"
|
|
|
+ />
|
|
|
+ </van-cell-group>
|
|
|
+ <h4 class="tit">委托实验信息</h4>
|
|
|
+ <div class="plat-wrap">
|
|
|
+ <div
|
|
|
+ v-for="(plat, platIdx) in platformDataReduce(state.form.service)"
|
|
|
+ :key="platIdx"
|
|
|
+ >
|
|
|
+ <div class="plat-items">
|
|
|
+ <h3 class="mb20">{{ `${platIdx + 1}、${plat.platName}` }}</h3>
|
|
|
+ <div class="mb14">
|
|
|
+ <!-- <span class="label">选择课题:</span>
|
|
|
+ <el-select v-model="plat.service.projectId" placeholder="Select" style="width: 400px">
|
|
|
+ <el-option-group v-for="group in projectGroupProjectList" :key="group.groupName" :label="group.groupName">
|
|
|
+ <el-option v-for="item in group.projects" :key="item.id" :label="item.projectName" :value="item.id" />
|
|
|
+ </el-option-group>
|
|
|
+ </el-select> -->
|
|
|
+ </div>
|
|
|
+ <van-empty
|
|
|
+ v-if="!plat.service.length"
|
|
|
+ description="暂无数据"
|
|
|
+ class="mt20 mb20"
|
|
|
+ />
|
|
|
+ <ul
|
|
|
+ v-else
|
|
|
+ class="service-list"
|
|
|
+ >
|
|
|
+ <li
|
|
|
+ v-for="(service, serviceIdx) in plat.service"
|
|
|
+ :key="serviceIdx"
|
|
|
+ class="service-card"
|
|
|
+ >
|
|
|
+ <div class="service-header">
|
|
|
+ <div class="service-title">{{ service.serviceName }}</div>
|
|
|
+ <span
|
|
|
+ v-if="service.detail?.projectSource"
|
|
|
+ class="tag"
|
|
|
+ >
|
|
|
+ {{ service.detail.projectSource }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="kv-row">
|
|
|
+ <span class="kv-label">实验类型</span>
|
|
|
+ <span class="kv-value">{{ service.serviceName }}</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="kv-row">
|
|
|
+ <span class="kv-label">实验项目</span>
|
|
|
+ <div class="chip-list">
|
|
|
+ <span
|
|
|
+ v-for="(itemRow, itemIdx) in filterItems(service.item)"
|
|
|
+ :key="itemIdx"
|
|
|
+ class="chip"
|
|
|
+ >
|
|
|
+ {{ itemRow.itemName }} · {{ itemRow.itemCount }} 次
|
|
|
+ </span>
|
|
|
+ <span
|
|
|
+ v-if="!filterItems(service.item).length"
|
|
|
+ class="text-muted"
|
|
|
+ >
|
|
|
+ 暂无
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ class="kv-row"
|
|
|
+ v-if="service.detail.commissionContent"
|
|
|
+ >
|
|
|
+ <span class="kv-label">委托内容</span>
|
|
|
+ <span class="kv-value">{{ service.detail.commissionContent }}</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ class="kv-row"
|
|
|
+ v-if="service.detail.experimentalPeriod"
|
|
|
+ >
|
|
|
+ <span class="kv-label">实验周期</span>
|
|
|
+ <span class="kv-value">{{ service.detail.experimentalPeriod }} 个月</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ class="kv-row"
|
|
|
+ v-if="service.detail.animalType"
|
|
|
+ >
|
|
|
+ <span class="kv-label">动物种类</span>
|
|
|
+ <span class="kv-value">{{ service.detail.animalType }}</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ class="kv-row"
|
|
|
+ v-if="service.detail.animalCount"
|
|
|
+ >
|
|
|
+ <span class="kv-label">动物数量</span>
|
|
|
+ <span class="kv-value">{{ service.detail.animalCount }} 只</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ class="kv-row"
|
|
|
+ v-if="service.detail.estimateCost"
|
|
|
+ >
|
|
|
+ <span class="kv-label">预估费用</span>
|
|
|
+ <span class="kv-value">{{ service.detail.estimateCost }} 元</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ class="kv-row"
|
|
|
+ v-if="service.detail.settlementCost"
|
|
|
+ >
|
|
|
+ <span class="kv-label">结算费用</span>
|
|
|
+ <span class="kv-value">{{ service.detail.settlementCost }} 元</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ class="kv-row"
|
|
|
+ v-if="service.detail.other"
|
|
|
+ >
|
|
|
+ <span class="kv-label">其它</span>
|
|
|
+ <span class="kv-value">{{ service.detail.other }}</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="kv-row attach-row">
|
|
|
+ <span class="kv-label">附件</span>
|
|
|
+ <a
|
|
|
+ v-if="service?.file?.[0]?.fileUrl"
|
|
|
+ :href="service?.file[0]?.fileUrl"
|
|
|
+ target="_blank"
|
|
|
+ class="file-link"
|
|
|
+ >
|
|
|
+ {{ service?.file[0]?.fileName }}
|
|
|
+ </a>
|
|
|
+ <span
|
|
|
+ v-else
|
|
|
+ class="text-muted"
|
|
|
+ >
|
|
|
+ 暂无
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <h4 class="tit">费用及支付方式</h4>
|
|
|
+ <p class="mb10">本项技术服务项目费用构成如下:</p>
|
|
|
+ <p class="mb10 desc">
|
|
|
+ 说明:以下费用是根据标准情况得出的预估费用,实际实验过程中根据实验流程不同,可能存在项目和耗材的增加或减少,最终费用请以实验完成后的结算单为准。
|
|
|
+ </p>
|
|
|
+ <div class="bill-list">
|
|
|
+ <div
|
|
|
+ v-for="(row, index) in flattenedData(state.form.bill)"
|
|
|
+ :key="index"
|
|
|
+ class="bill-row"
|
|
|
+ >
|
|
|
+ <div class="bill-header">
|
|
|
+ <span class="bill-index">{{ index + 1 }}</span>
|
|
|
+ <span class="bill-title">{{ `${row.serviceName}-${row.itemName}` }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="bill-line">
|
|
|
+ <span class="label">费用类型</span>
|
|
|
+ <span class="value">{{ row.chargeName }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="bill-line">
|
|
|
+ <span class="label">单价</span>
|
|
|
+ <span class="value">{{ formatAmount(row.amount) }} 元</span>
|
|
|
+ </div>
|
|
|
+ <div class="bill-line">
|
|
|
+ <span class="label">数量</span>
|
|
|
+ <span class="value">{{ row.itemCount }} 次</span>
|
|
|
+ </div>
|
|
|
+ <div class="bill-line total">
|
|
|
+ <span class="label">小计</span>
|
|
|
+ <span class="value highlight">{{ formatAmount(row.itemCount * row.amount) }} 元</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="bill-summary">
|
|
|
+ <span>合计次数:{{ totalBillCount }} 次</span>
|
|
|
+ <span class="summary-amount">合计金额:{{ totalBillAmount }} 元</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <van-cell-group class="amount-info mt20 mb20">
|
|
|
+ <van-cell title="本次技术服务费总金额">
|
|
|
+ <template #right-icon>
|
|
|
+ <van-button
|
|
|
+ type="warning"
|
|
|
+ size="small"
|
|
|
+ link
|
|
|
+ >
|
|
|
+ {{ state.form.amount }}元
|
|
|
+ </van-button>
|
|
|
+ </template>
|
|
|
+ </van-cell>
|
|
|
+ <van-cell title="大写金额">
|
|
|
+ <template #right-icon>
|
|
|
+ <van-button
|
|
|
+ type="warning"
|
|
|
+ size="small"
|
|
|
+ link
|
|
|
+ >
|
|
|
+ {{ numberToChinese(state.form.amount) }}
|
|
|
+ </van-button>
|
|
|
+ </template>
|
|
|
+ </van-cell>
|
|
|
+ <van-cell
|
|
|
+ title="其他事项"
|
|
|
+ :value="state.form.otherInfo"
|
|
|
+ />
|
|
|
+ </van-cell-group>
|
|
|
+ <van-cell-group
|
|
|
+ class="mt20 mb20"
|
|
|
+ v-if="state.form.finallyAmount"
|
|
|
+ >
|
|
|
+ <van-cell title="本次技术服务费最终总金额">
|
|
|
+ <template #right-icon>
|
|
|
+ <van-button
|
|
|
+ type="warning"
|
|
|
+ size="small"
|
|
|
+ link
|
|
|
+ >
|
|
|
+ {{ state.form.finallyAmount / 100 }}元
|
|
|
+ </van-button>
|
|
|
+ </template>
|
|
|
+ </van-cell>
|
|
|
+ <van-cell title="大写金额">
|
|
|
+ <template #right-icon>
|
|
|
+ <van-button
|
|
|
+ type="warning"
|
|
|
+ size="small"
|
|
|
+ link
|
|
|
+ >
|
|
|
+ {{ numberToChinese(state.form.finallyAmount / 100) }}
|
|
|
+ </van-button>
|
|
|
+ </template>
|
|
|
+ </van-cell>
|
|
|
+ <van-cell
|
|
|
+ title="最终费用备注"
|
|
|
+ :value="state.form.finallyAmountRemark"
|
|
|
+ />
|
|
|
+ </van-cell-group>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts" name="systemProDialog">
|
|
|
+ import to from 'await-to-js'
|
|
|
+ import { nextTick, reactive, watch, computed } from 'vue'
|
|
|
+ import { usePlatCommissionApi } from '/@/api/platform/techService/commission'
|
|
|
+
|
|
|
+ // 定义子组件向父组件传值/事件
|
|
|
+ const props = defineProps({
|
|
|
+ code: { type: String, default: '' },
|
|
|
+ })
|
|
|
+
|
|
|
+ // 定义变量内容
|
|
|
+ const platCommissionApi = usePlatCommissionApi()
|
|
|
+ const state = reactive({
|
|
|
+ form: {
|
|
|
+ id: 0,
|
|
|
+ serviceName: '',
|
|
|
+ serviceImg: '',
|
|
|
+ serviceDesc: '',
|
|
|
+ serviceContract: '',
|
|
|
+ serviceNotice: '',
|
|
|
+ serviceContent: '',
|
|
|
+ serviceResult: '',
|
|
|
+ service: [],
|
|
|
+ bill: [],
|
|
|
+ } as any,
|
|
|
+ dialog: {
|
|
|
+ approveDialog: false,
|
|
|
+ type: '',
|
|
|
+ title: '',
|
|
|
+ submitTxt: '',
|
|
|
+ },
|
|
|
+ disabled: false,
|
|
|
+ })
|
|
|
+
|
|
|
+ // 打开弹窗
|
|
|
+ const initForm = async (code: string) => {
|
|
|
+ state.dialog.title = '委托信息'
|
|
|
+ state.disabled = true
|
|
|
+ const [err, res]: ToResponse = await to(platCommissionApi.getEntityById({ id: parseInt(code) }))
|
|
|
+ if (err) return
|
|
|
+ const data = res?.data
|
|
|
+
|
|
|
+ // 如果是加急委托,添加加急费用
|
|
|
+ if (data && data.isUrgent === 1) {
|
|
|
+ // 计算现有项目费用总和(单位:分)
|
|
|
+ const existingTotal = data.bill.reduce((total: number, item: any) => {
|
|
|
+ return (
|
|
|
+ total +
|
|
|
+ item.charge.reduce((chargeTotal: number, charge: any) => {
|
|
|
+ return chargeTotal + item.itemCount * charge.amount
|
|
|
+ }, 0)
|
|
|
+ )
|
|
|
+ }, 0)
|
|
|
+
|
|
|
+ // 计算加急费用(总费用减去现有费用,单位:分)
|
|
|
+ const urgentFee = data.amount - existingTotal
|
|
|
+
|
|
|
+ // 如果加急费用大于0,添加加急费用项目
|
|
|
+ if (urgentFee > 0) {
|
|
|
+ const urgentItem = {
|
|
|
+ id: 'urgent_' + data.id,
|
|
|
+ platformId: data.platformId,
|
|
|
+ platformName: data.platformName,
|
|
|
+ serviceId: 'urgent',
|
|
|
+ serviceName: '加急服务',
|
|
|
+ commissionId: data.id,
|
|
|
+ commissionName: data.commissionName,
|
|
|
+ itemId: 'urgent_fee',
|
|
|
+ itemName: '加急费用',
|
|
|
+ itemDesc: '加急处理费用',
|
|
|
+ itemCount: 1,
|
|
|
+ remark: '加急服务费用',
|
|
|
+ charge: [
|
|
|
+ {
|
|
|
+ chargeName: '加急费用',
|
|
|
+ amount: urgentFee,
|
|
|
+ itemId: 'urgent_fee',
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ }
|
|
|
+
|
|
|
+ // 将加急费用添加到 bill 数组的开头
|
|
|
+ data.bill.push(urgentItem)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ data.service = data.service.map((item: any) => ({
|
|
|
+ ...item,
|
|
|
+ detail: JSON.parse(item.detail || '{}'),
|
|
|
+ }))
|
|
|
+
|
|
|
+ state.form = data
|
|
|
+ await nextTick()
|
|
|
+ state.form = data
|
|
|
+ }
|
|
|
+ const platformDataReduce = (data: any) => {
|
|
|
+ if (!data) return
|
|
|
+ const groupedData = data.reduce((acc: any, current: any) => {
|
|
|
+ // 查找是否已存在对应platformId的项
|
|
|
+ const existingPlatform = acc.find((platform: any) => platform.platid === current.platformId)
|
|
|
+
|
|
|
+ if (existingPlatform) {
|
|
|
+ // 如果存在,则将当前服务添加到services数组中
|
|
|
+ existingPlatform.service.push(current)
|
|
|
+ } else {
|
|
|
+ // 如果不存在,则创建新的对象并添加到acc数组中
|
|
|
+ acc.push({ platid: current.platformId, platName: current.platformName, service: [current] })
|
|
|
+ }
|
|
|
+
|
|
|
+ return acc
|
|
|
+ }, [])
|
|
|
+ console.log(groupedData)
|
|
|
+ return groupedData
|
|
|
+ }
|
|
|
+ // 拍平bill数据
|
|
|
+ const flattenedData = (data: any) => {
|
|
|
+ if (!data) return
|
|
|
+ return data.flatMap((item: any) =>
|
|
|
+ item.charge.map((charge: any) => ({
|
|
|
+ ...item,
|
|
|
+ chargeName: charge.chargeName,
|
|
|
+ amount: charge.amount,
|
|
|
+ // 移除原始的 charge 数组
|
|
|
+ })),
|
|
|
+ )
|
|
|
+ }
|
|
|
+ // 计算总金额
|
|
|
+ const getTotalAmount = () => {
|
|
|
+ const data = flattenedData(state.form.bill)
|
|
|
+ if (!data) return 0
|
|
|
+ const total = data.reduce((prev: number, curr: any) => {
|
|
|
+ const itemCount = Number(curr.itemCount)
|
|
|
+ const amount = Number(curr.amount)
|
|
|
+ if (!isNaN(itemCount) && !isNaN(amount)) {
|
|
|
+ return prev + itemCount * amount
|
|
|
+ } else {
|
|
|
+ return prev
|
|
|
+ }
|
|
|
+ }, 0)
|
|
|
+ state.form.amount = total / 100 // 更新总金额
|
|
|
+ return total
|
|
|
+ }
|
|
|
+
|
|
|
+ const totalBillCount = computed(() => {
|
|
|
+ const data = flattenedData(state.form.bill)
|
|
|
+ if (!data) return 0
|
|
|
+ return data.reduce((sum: number, row: any) => sum + Number(row.itemCount || 0), 0)
|
|
|
+ })
|
|
|
+
|
|
|
+ const totalBillAmount = computed(() => formatAmount(getTotalAmount()))
|
|
|
+
|
|
|
+ const filterItems = (items: any[]) => {
|
|
|
+ if (!items) return []
|
|
|
+ return items.filter((it: any) => Number(it?.itemCount) > 0)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 格式化金额为千分位
|
|
|
+ const formatAmount = (amount: number | string) => {
|
|
|
+ // 确保输入是数字
|
|
|
+ let amountInFen = typeof amount === 'string' ? parseInt(amount, 10) : amount
|
|
|
+
|
|
|
+ // 将分转换为元(保留两位小数)
|
|
|
+ let amountInYuan = amountInFen / 100
|
|
|
+
|
|
|
+ // 使用 Intl.NumberFormat 进行千分位格式化,并保留两位小数
|
|
|
+ let formattedAmount = new Intl.NumberFormat('en-US', {
|
|
|
+ minimumFractionDigits: 2, // 最小小数位数
|
|
|
+ maximumFractionDigits: 2, // 最大小数位数
|
|
|
+ }).format(amountInYuan)
|
|
|
+
|
|
|
+ return formattedAmount
|
|
|
+ }
|
|
|
+
|
|
|
+ // 将数字转换为中文大写金额
|
|
|
+ const numberToChinese = (num: number) => {
|
|
|
+ console.log('num', num)
|
|
|
+ if (!num) return
|
|
|
+ if (num == 0) return '零元整'
|
|
|
+ const digits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
|
|
|
+ const units = ['', '拾', '佰', '仟']
|
|
|
+ const bigUnits = ['', '万', '亿', '兆']
|
|
|
+ const decimalUnits = ['角', '分']
|
|
|
+ const integerPartName = '元'
|
|
|
+ const zeroChar = '零'
|
|
|
+
|
|
|
+ let result = ''
|
|
|
+ let integerPart = Math.floor(num) // 整数部分
|
|
|
+ let decimalPart = Math.round((num - integerPart) * 100) // 小数部分,保留两位
|
|
|
+
|
|
|
+ // 处理整数部分
|
|
|
+ if (integerPart === 0) {
|
|
|
+ result += zeroChar + integerPartName
|
|
|
+ } else {
|
|
|
+ let integerStr = integerPart.toString()
|
|
|
+ let length = integerStr.length
|
|
|
+
|
|
|
+ for (let i = 0; i < length; i++) {
|
|
|
+ let digit = parseInt(integerStr[i])
|
|
|
+ let unitIndex = (length - i - 1) % 4
|
|
|
+ let bigUnitIndex = Math.floor((length - i - 1) / 4)
|
|
|
+
|
|
|
+ if (digit === 0) {
|
|
|
+ // 如果当前位是零,并且不是最后一位,避免连续多个零
|
|
|
+ if (result.slice(-1) !== zeroChar && result.slice(-1) !== integerPartName) {
|
|
|
+ result += zeroChar
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ result += digits[digit] + units[unitIndex]
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加大单位(万、亿等)
|
|
|
+ if (unitIndex === 0 && result.slice(-1) !== zeroChar) {
|
|
|
+ result += bigUnits[bigUnitIndex]
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ result += integerPartName
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理小数部分
|
|
|
+ if (decimalPart > 0) {
|
|
|
+ let decimalStr = decimalPart.toString().padStart(2, '0') // 补齐两位小数
|
|
|
+ let jiao = parseInt(decimalStr[0])
|
|
|
+ let fen = parseInt(decimalStr[1])
|
|
|
+
|
|
|
+ if (jiao > 0) {
|
|
|
+ result += digits[jiao] + decimalUnits[0]
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fen > 0) {
|
|
|
+ result += digits[fen] + decimalUnits[1]
|
|
|
+ } else if (jiao > 0) {
|
|
|
+ result += '整' // 如果有角但没有分,则加“整”
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ result += '整' // 没有小数部分时加“整”
|
|
|
+ }
|
|
|
+
|
|
|
+ return result
|
|
|
+ }
|
|
|
+ watch(
|
|
|
+ () => props.code,
|
|
|
+ (val) => {
|
|
|
+ initForm(val)
|
|
|
+ },
|
|
|
+ {
|
|
|
+ deep: true,
|
|
|
+ immediate: true,
|
|
|
+ },
|
|
|
+ )
|
|
|
+ // 暴露变量
|
|
|
+ defineExpose({
|
|
|
+ initForm,
|
|
|
+ })
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+ .tit {
|
|
|
+ margin-bottom: 20px;
|
|
|
+ margin-top: 20px;
|
|
|
+ color: #1c9bfd;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 描述列表布局样式 */
|
|
|
+ .descriptions-row {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ margin: -8px 0;
|
|
|
+
|
|
|
+ .cell-item {
|
|
|
+ flex: 0 0 50%;
|
|
|
+ padding: 8px 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .base-info {
|
|
|
+ margin-top: 20px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+
|
|
|
+ :deep(.van-cell) {
|
|
|
+ border-bottom: 1px solid #ebedf0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .amount-info {
|
|
|
+ margin-top: 20px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+
|
|
|
+ :deep(.van-cell) {
|
|
|
+ border-bottom: 1px solid #ebedf0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .plat-wrap {
|
|
|
+ .plat-items {
|
|
|
+ width: 100%;
|
|
|
+ border-radius: 4px;
|
|
|
+ background: #fff;
|
|
|
+ padding: 20px;
|
|
|
+ padding-right: 0;
|
|
|
+ box-shadow: 0px 6px 20px rgba(0, 0, 0, 0.06);
|
|
|
+ margin-bottom: 20px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ ul {
|
|
|
+ height: 100%;
|
|
|
+ overflow: auto;
|
|
|
+ padding-right: 20px;
|
|
|
+ li {
|
|
|
+ margin-bottom: 20px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .charge {
|
|
|
+ border-bottom: 2px dashed rgba(112, 112, 112, 0.18);
|
|
|
+ .charge-name {
|
|
|
+ width: 200px;
|
|
|
+ margin: 0 10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ul,
|
|
|
+ li {
|
|
|
+ list-style: none;
|
|
|
+ }
|
|
|
+ .label {
|
|
|
+ display: inline-block;
|
|
|
+ width: 100px;
|
|
|
+ }
|
|
|
+ .dashed-border {
|
|
|
+ border-bottom: 2px dashed rgba(112, 112, 112, 0.18);
|
|
|
+ }
|
|
|
+ .desc {
|
|
|
+ color: #f59a23;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 自定义表格样式 */
|
|
|
+ .bill-list {
|
|
|
+ margin-top: 12px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .bill-row {
|
|
|
+ padding: 12px;
|
|
|
+ border: 1px solid #ebedf0;
|
|
|
+ border-radius: 8px;
|
|
|
+ background: #fff;
|
|
|
+ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.04);
|
|
|
+ }
|
|
|
+
|
|
|
+ .bill-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ margin-bottom: 6px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .bill-index {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ border-radius: 10px;
|
|
|
+ background: #1c9bfd;
|
|
|
+ color: #fff;
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .bill-title {
|
|
|
+ font-weight: 600;
|
|
|
+ color: #323233;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .bill-line {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #646566;
|
|
|
+ padding: 4px 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .bill-line .value {
|
|
|
+ color: #323233;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
+
|
|
|
+ .bill-line.total {
|
|
|
+ border-top: 1px dashed #ebedf0;
|
|
|
+ margin-top: 4px;
|
|
|
+ padding-top: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .highlight {
|
|
|
+ color: #f59a23;
|
|
|
+ font-weight: 600;
|
|
|
+ }
|
|
|
+
|
|
|
+ .bill-summary {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 6px;
|
|
|
+ padding: 12px;
|
|
|
+ border-radius: 8px;
|
|
|
+ background: #f7f8fa;
|
|
|
+ color: #323233;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .summary-amount {
|
|
|
+ color: #f59a23;
|
|
|
+ font-weight: 700;
|
|
|
+ }
|
|
|
+
|
|
|
+ .file-link {
|
|
|
+ color: #1989fa;
|
|
|
+ text-decoration: underline;
|
|
|
+ }
|
|
|
+
|
|
|
+ .text-muted {
|
|
|
+ color: #969799;
|
|
|
+ }
|
|
|
+
|
|
|
+ .service-list {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .service-card {
|
|
|
+ background: #fff;
|
|
|
+ border: 1px solid #ebedf0;
|
|
|
+ border-radius: 10px;
|
|
|
+ padding: 14px;
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.04);
|
|
|
+ }
|
|
|
+
|
|
|
+ .service-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 8px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .service-title {
|
|
|
+ font-weight: 700;
|
|
|
+ font-size: 15px;
|
|
|
+ color: #323233;
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ .tag {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 4px 8px;
|
|
|
+ border-radius: 999px;
|
|
|
+ background: #e8f4ff;
|
|
|
+ color: #1c9bfd;
|
|
|
+ font-size: 12px;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ .kv-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 10px;
|
|
|
+ padding: 6px 0;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #646566;
|
|
|
+ border-bottom: 1px dashed #f0f1f5;
|
|
|
+ }
|
|
|
+
|
|
|
+ .kv-row:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .kv-label {
|
|
|
+ flex: 0 0 80px;
|
|
|
+ color: #969799;
|
|
|
+ }
|
|
|
+
|
|
|
+ .kv-value {
|
|
|
+ flex: 1;
|
|
|
+ color: #323233;
|
|
|
+ text-align: right;
|
|
|
+ }
|
|
|
+
|
|
|
+ .attach-row .kv-value,
|
|
|
+ .attach-row .file-link,
|
|
|
+ .attach-row .text-muted {
|
|
|
+ text-align: right;
|
|
|
+ }
|
|
|
+
|
|
|
+ .chip-list {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 6px;
|
|
|
+ justify-content: flex-end;
|
|
|
+ }
|
|
|
+
|
|
|
+ .chip {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 4px 8px;
|
|
|
+ border-radius: 999px;
|
|
|
+ background: #f5f7fa;
|
|
|
+ color: #323233;
|
|
|
+ font-size: 12px;
|
|
|
+ border: 1px solid #ebedf0;
|
|
|
+ }
|
|
|
+</style>
|