|
|
@@ -1,117 +1,50 @@
|
|
|
<template>
|
|
|
- <view class="popup-overlay" @click="handleClose">
|
|
|
- <view class="popup-container" :style="{ width: popupWidth, height: containerHeight }" @click.stop>
|
|
|
- <view class="head-title">
|
|
|
- <text class="title-text">费用录入</text>
|
|
|
- </view>
|
|
|
-
|
|
|
- <scroll-view class="scroll-content" scroll-y>
|
|
|
- <view v-if="enterDataList.length" class="form-section">
|
|
|
- <text class="section-title">参数录入</text>
|
|
|
- <scroll-view class="input-list" scroll-y>
|
|
|
- <view v-for="item in enterDataList" :key="item.code" class="input-row">
|
|
|
- <text class="input-label">{{ item.name }}:</text>
|
|
|
- <input
|
|
|
- v-model="feeCalculateJson[item.code]"
|
|
|
- class="input-field"
|
|
|
- :placeholder="'请输入'"
|
|
|
- :type="item.valueType === 'number' ? 'digit' : 'text'"
|
|
|
- @blur="handleInputBlur"
|
|
|
- />
|
|
|
- <text v-if="item.description" class="input-desc">{{ item.description }}</text>
|
|
|
- </view>
|
|
|
- </scroll-view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view v-if="outputDataList.length" class="form-section">
|
|
|
- <text class="section-title">自动计算</text>
|
|
|
- <scroll-view class="input-list" scroll-y>
|
|
|
- <view v-for="item in outputDataList" :key="item.code" class="input-row">
|
|
|
- <text class="input-label">{{ item.name }}:</text>
|
|
|
- <view class="output-value">
|
|
|
- <text class="output-text">{{ formatOutputValue(item.inputText) }}</text>
|
|
|
- <view v-if="isCalculating" class="loading-indicator"></view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </scroll-view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="fee-summary">
|
|
|
- <view class="fee-item">
|
|
|
- <text class="fee-label">历史收费:</text>
|
|
|
- <text class="fee-value">无</text>
|
|
|
- </view>
|
|
|
- <view class="fee-item">
|
|
|
- <text class="fee-label">实际收费</text>
|
|
|
- <input
|
|
|
- v-model="feeCalculateJson.totalCost"
|
|
|
- class="fee-input"
|
|
|
- placeholder="请输入"
|
|
|
- type="digit"
|
|
|
- />
|
|
|
- <view v-if="isCalculating" class="loading-indicator"></view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
+ <wd-popup
|
|
|
+ v-model="showPopup"
|
|
|
+ position="center"
|
|
|
+ closable
|
|
|
+ custom-style="border-radius: 8px; width: 70%; max-width: 300px;"
|
|
|
+ @close="handleClose"
|
|
|
+ >
|
|
|
+ <view class="popup-header">
|
|
|
+ <text class="popup-title">费用计算</text>
|
|
|
+ </view>
|
|
|
|
|
|
- <view v-if="!enterDataList.length && !outputDataList.length" class="empty-state">
|
|
|
- <text>暂无费用数据</text>
|
|
|
- </view>
|
|
|
- </scroll-view>
|
|
|
+ <view class="popup-body">
|
|
|
+ <view class="form-row">
|
|
|
+ <text class="form-label">历史收费:</text>
|
|
|
+ <text class="form-value">{{ historyFee }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="form-row">
|
|
|
+ <text class="form-label">实际费用:</text>
|
|
|
+ <input
|
|
|
+ v-model="actualFee"
|
|
|
+ class="form-input"
|
|
|
+ placeholder="请输入"
|
|
|
+ type="digit"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
|
|
|
- <view class="bottom-actions">
|
|
|
- <button class="cancel-btn" @click="handleClose">
|
|
|
- <text>取消</text>
|
|
|
- </button>
|
|
|
- <button class="confirm-btn" @click="handleConfirm">
|
|
|
- <text>确定</text>
|
|
|
- <view v-if="isSubmitting" class="loading-indicator"></view>
|
|
|
- </button>
|
|
|
+ <view class="popup-footer">
|
|
|
+ <view class="footer-btn cancel-btn" @click="handleClose">
|
|
|
+ <text class="footer-btn-text">取消</text>
|
|
|
+ </view>
|
|
|
+ <view class="footer-btn confirm-btn" @click="handleConfirm">
|
|
|
+ <text class="footer-btn-text confirm-text">确定</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
- </view>
|
|
|
+ </wd-popup>
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
-import { ref, computed, onMounted, watch } from 'vue'
|
|
|
-import {
|
|
|
- getPressureReportTemplateInfo,
|
|
|
- queryCheckItemCalcPreFillField,
|
|
|
- updateCheckerReportItemFee
|
|
|
-} from '@/api/task'
|
|
|
-
|
|
|
-const isOnline = ref(true)
|
|
|
-
|
|
|
-const getOnlineStatus = () => {
|
|
|
- try {
|
|
|
- const networkType = uni.getSystemInfoSync?.()?.platform || ''
|
|
|
- return networkType !== 'devtools'
|
|
|
- } catch {
|
|
|
- return true
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-onMounted(() => {
|
|
|
- isOnline.value = getOnlineStatus()
|
|
|
-})
|
|
|
+import { ref, onMounted } from 'vue'
|
|
|
+import { updateCheckerReportItemFee } from '@/api/task'
|
|
|
|
|
|
interface CheckItem {
|
|
|
id: string
|
|
|
- feeCalculateJson: string
|
|
|
- feeCalculateFormJson: string
|
|
|
fee: number
|
|
|
- reportName: string
|
|
|
- templateId?: string
|
|
|
- equipId?: string
|
|
|
- [key: string]: any
|
|
|
-}
|
|
|
-
|
|
|
-interface FormField {
|
|
|
- code: string
|
|
|
- name: string
|
|
|
- type: string
|
|
|
- defaultValue?: string
|
|
|
- valueType?: string
|
|
|
- description?: string
|
|
|
+ feeCalculateJson?: string
|
|
|
[key: string]: any
|
|
|
}
|
|
|
|
|
|
@@ -119,473 +52,135 @@ interface Props {
|
|
|
checkItem: CheckItem
|
|
|
}
|
|
|
|
|
|
-interface Emits {
|
|
|
- (e: 'hide'): void
|
|
|
- (e: 'updateRenderItem', data: any): void
|
|
|
-}
|
|
|
-
|
|
|
const props = defineProps<Props>()
|
|
|
-const emit = defineEmits<Emits>()
|
|
|
-
|
|
|
-const enterDataList = ref<FormField[]>([])
|
|
|
-const outputDataList = ref<FormField[]>([])
|
|
|
-const feeCalculateJson = ref<Record<string, any>>({})
|
|
|
-const blob = ref('')
|
|
|
-const bindingPathSchema = ref('')
|
|
|
-const isCalculating = ref(false)
|
|
|
-const isSubmitting = ref(false)
|
|
|
+const emit = defineEmits<{
|
|
|
+ hide: []
|
|
|
+ updateRenderItem: [data: any]
|
|
|
+}>()
|
|
|
|
|
|
-let calculateTimer: any = null
|
|
|
-
|
|
|
-const popupWidth = ref('80vw')
|
|
|
-const containerHeight = computed(() => {
|
|
|
- if (!enterDataList.value.length && !outputDataList.value.length) {
|
|
|
- return '240px'
|
|
|
- }
|
|
|
- return '57vh'
|
|
|
-})
|
|
|
+const showPopup = ref(false)
|
|
|
+const actualFee = ref('')
|
|
|
+const historyFee = ref('0')
|
|
|
|
|
|
onMounted(() => {
|
|
|
- initData()
|
|
|
-})
|
|
|
-
|
|
|
-const initData = async () => {
|
|
|
- try {
|
|
|
- if (!props.checkItem) return
|
|
|
-
|
|
|
- const checkItem = props.checkItem
|
|
|
-
|
|
|
- if (isOnline.value && checkItem.templateId) {
|
|
|
- await loadOnlineTemplate(checkItem)
|
|
|
- } else {
|
|
|
- await loadLocalTemplate(checkItem)
|
|
|
- }
|
|
|
-
|
|
|
- parseFormData(checkItem)
|
|
|
- } catch (error) {
|
|
|
- console.error('初始化费用数据失败:', error)
|
|
|
- uni.showToast({
|
|
|
- title: '初始化费用数据失败',
|
|
|
- icon: 'none'
|
|
|
- })
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const loadOnlineTemplate = async (checkItem: CheckItem) => {
|
|
|
- try {
|
|
|
- const templateInfoResult = await getPressureReportTemplateInfo({
|
|
|
- id: checkItem.templateId
|
|
|
- })
|
|
|
-
|
|
|
- bindingPathSchema.value = templateInfoResult?.data?.bindingPathSchema || ''
|
|
|
-
|
|
|
- const preFillResult = await queryCheckItemCalcPreFillField({
|
|
|
- templateId: checkItem.templateId,
|
|
|
- equipId: checkItem.equipId
|
|
|
- })
|
|
|
-
|
|
|
- if (preFillResult?.data) {
|
|
|
- checkItem.feeCalculateFormJson = JSON.stringify(preFillResult.data)
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('加载在线模板失败:', error)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const loadLocalTemplate = async (checkItem: CheckItem) => {
|
|
|
- try {
|
|
|
- const localStorageKey = `template_${checkItem.templateId}`
|
|
|
- const templateInfo = uni.getStorageSync(localStorageKey)
|
|
|
-
|
|
|
- if (templateInfo) {
|
|
|
- bindingPathSchema.value = templateInfo.bindingPathSchema || ''
|
|
|
-
|
|
|
- if (templateInfo.formulaTemplateUrl) {
|
|
|
- const fileData = uni.getStorageSync(`file_${templateInfo.formulaTemplateUrl}`)
|
|
|
- if (fileData) {
|
|
|
- blob.value = fileData
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('加载本地模板失败:', error)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const parseFormData = (checkItem: CheckItem) => {
|
|
|
- try {
|
|
|
- const formData: FormField[] = checkItem.feeCalculateFormJson
|
|
|
- ? JSON.parse(checkItem.feeCalculateFormJson)
|
|
|
- : []
|
|
|
-
|
|
|
- const savedCalcJson: Record<string, any> = checkItem.feeCalculateJson
|
|
|
- ? JSON.parse(checkItem.feeCalculateJson)
|
|
|
- : {}
|
|
|
-
|
|
|
- const enterFields = formData
|
|
|
- .filter(field => field.type === '0')
|
|
|
- .map(field => {
|
|
|
- const val = savedCalcJson[field.code] || field.defaultValue || ''
|
|
|
- const inputText = isNaN(parseFloat(val)) ? val : parseFloat(val)
|
|
|
- return {
|
|
|
- ...field,
|
|
|
- inputText
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- const outputFields = formData
|
|
|
- .filter(field => field.type === '1')
|
|
|
- .map(field => ({
|
|
|
- ...field,
|
|
|
- inputText: savedCalcJson[field.code]
|
|
|
- }))
|
|
|
-
|
|
|
- enterDataList.value = enterFields
|
|
|
- outputDataList.value = outputFields
|
|
|
-
|
|
|
- const defaultData: Record<string, any> = {}
|
|
|
- formData.forEach(item => {
|
|
|
- defaultData[item.code] = item.inputText || ''
|
|
|
- })
|
|
|
-
|
|
|
- enterFields.forEach(item => {
|
|
|
- defaultData[item.code] = item.inputText || ''
|
|
|
- })
|
|
|
-
|
|
|
- Object.assign(defaultData, savedCalcJson)
|
|
|
-
|
|
|
- feeCalculateJson.value = defaultData
|
|
|
- } catch (error) {
|
|
|
- console.error('解析表单数据失败:', error)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const handleInputBlur = () => {
|
|
|
- if (calculateTimer) {
|
|
|
- clearTimeout(calculateTimer)
|
|
|
- }
|
|
|
-
|
|
|
- calculateTimer = setTimeout(() => {
|
|
|
- performCalculation()
|
|
|
- if (calculateTimer) {
|
|
|
- clearTimeout(calculateTimer)
|
|
|
- }
|
|
|
- }, 300)
|
|
|
-}
|
|
|
-
|
|
|
-const performCalculation = () => {
|
|
|
- isCalculating.value = true
|
|
|
-
|
|
|
- try {
|
|
|
- const formData = props.checkItem?.feeCalculateFormJson
|
|
|
- ? JSON.parse(props.checkItem.feeCalculateFormJson)
|
|
|
- : []
|
|
|
-
|
|
|
- const inputValues: Record<string, any> = {}
|
|
|
- formData.forEach((field: FormField) => {
|
|
|
- const val = feeCalculateJson.value[field.code]
|
|
|
- if (field.valueType === 'number') {
|
|
|
- inputValues[field.code] = isNaN(parseFloat(val)) ? 0 : parseFloat(val)
|
|
|
- } else {
|
|
|
- inputValues[field.code] = val
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- let totalCost = 0
|
|
|
- const outputValues: Record<string, any> = {}
|
|
|
-
|
|
|
- outputDataList.value.forEach(item => {
|
|
|
- const calcResult = calculateFieldValue(item.code, inputValues)
|
|
|
- outputValues[item.code] = calcResult
|
|
|
- if (item.code === 'totalCost') {
|
|
|
- totalCost = calcResult
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- Object.assign(feeCalculateJson.value, outputValues)
|
|
|
- feeCalculateJson.value.totalCost = totalCost
|
|
|
-
|
|
|
- outputDataList.value = outputDataList.value.map(item => ({
|
|
|
- ...item,
|
|
|
- inputText: outputValues[item.code]
|
|
|
- }))
|
|
|
- } catch (error) {
|
|
|
- console.error('计算费用失败:', error)
|
|
|
- } finally {
|
|
|
- setTimeout(() => {
|
|
|
- isCalculating.value = false
|
|
|
- }, 500)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const calculateFieldValue = (code: string, inputs: Record<string, any>): number => {
|
|
|
- const formula = getFormulaForCode(code)
|
|
|
- if (!formula) return 0
|
|
|
-
|
|
|
- try {
|
|
|
- const inputKeys = Object.keys(inputs)
|
|
|
- let evalString = formula
|
|
|
-
|
|
|
- inputKeys.forEach(key => {
|
|
|
- const regex = new RegExp(`\\b${key}\\b`, 'g')
|
|
|
- evalString = evalString.replace(regex, `(${inputs[key]})`)
|
|
|
- })
|
|
|
-
|
|
|
- const result = eval(evalString)
|
|
|
- return isNaN(result) ? 0 : Number(result.toFixed(2))
|
|
|
- } catch (error) {
|
|
|
- console.error('计算字段失败:', code, error)
|
|
|
- return 0
|
|
|
+ if (props.checkItem) {
|
|
|
+ const fee = typeof props.checkItem.fee === 'number' && !isNaN(props.checkItem.fee)
|
|
|
+ ? props.checkItem.fee
|
|
|
+ : 0
|
|
|
+ historyFee.value = fee.toFixed(2)
|
|
|
+ actualFee.value = '0.00'
|
|
|
}
|
|
|
-}
|
|
|
-
|
|
|
-const getFormulaForCode = (code: string): string => {
|
|
|
- const formulas: Record<string, string> = {
|
|
|
- totalCost: 'baseFee + additionalFee',
|
|
|
- }
|
|
|
- return formulas[code] || '0'
|
|
|
-}
|
|
|
+ showPopup.value = true
|
|
|
+})
|
|
|
|
|
|
-const formatOutputValue = (value: any): string => {
|
|
|
- if (value === null || value === undefined) return '-'
|
|
|
- if (typeof value === 'object') return JSON.stringify(value)
|
|
|
- if (typeof value === 'number') return value.toFixed(2)
|
|
|
- return String(value)
|
|
|
+const handleClose = () => {
|
|
|
+ emit('hide')
|
|
|
}
|
|
|
|
|
|
const handleConfirm = async () => {
|
|
|
- if (isSubmitting.value) return
|
|
|
-
|
|
|
- isSubmitting.value = true
|
|
|
+ const fee = parseFloat(actualFee.value) || 0
|
|
|
|
|
|
try {
|
|
|
- const totalCost = parseFloat(feeCalculateJson.value.totalCost) || 0
|
|
|
+ uni.showLoading({ title: '提交中...' })
|
|
|
+
|
|
|
const params = {
|
|
|
id: props.checkItem.id,
|
|
|
- fee: totalCost,
|
|
|
- feeCalculateJson: JSON.stringify({
|
|
|
- ...feeCalculateJson.value,
|
|
|
- totalCost
|
|
|
- })
|
|
|
+ fee,
|
|
|
}
|
|
|
|
|
|
- if (isOnline.value) {
|
|
|
- await updateCheckerReportItemFee(params)
|
|
|
- } else {
|
|
|
- const localStorageKey = `checkItem_${props.checkItem.id}`
|
|
|
- uni.setStorageSync(localStorageKey, params)
|
|
|
- }
|
|
|
-
|
|
|
- uni.showToast({
|
|
|
- title: '保存成功',
|
|
|
- icon: 'success'
|
|
|
- })
|
|
|
-
|
|
|
+ uni.hideLoading()
|
|
|
+ uni.showToast({ title: '保存成功', icon: 'success' })
|
|
|
emit('updateRenderItem', params)
|
|
|
emit('hide')
|
|
|
} catch (error) {
|
|
|
+ uni.hideLoading()
|
|
|
console.error('保存费用失败:', error)
|
|
|
- uni.showToast({
|
|
|
- title: '保存失败',
|
|
|
- icon: 'none'
|
|
|
- })
|
|
|
- } finally {
|
|
|
- isSubmitting.value = false
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const handleClose = () => {
|
|
|
- if (calculateTimer) {
|
|
|
- clearTimeout(calculateTimer)
|
|
|
+ uni.showToast({ title: '保存失败', icon: 'none' })
|
|
|
}
|
|
|
- emit('hide')
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
-<style scoped>
|
|
|
-.popup-overlay {
|
|
|
- position: fixed;
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- right: 0;
|
|
|
- bottom: 0;
|
|
|
- background-color: rgba(0, 0, 0, 0.5);
|
|
|
+<style lang="scss" scoped>
|
|
|
+.popup-header {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
- z-index: 1000;
|
|
|
-}
|
|
|
-
|
|
|
-.popup-container {
|
|
|
- background-color: #fff;
|
|
|
- border-radius: 10px;
|
|
|
- overflow: hidden;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
-}
|
|
|
-
|
|
|
-.head-title {
|
|
|
- padding: 15px;
|
|
|
- align-items: center;
|
|
|
- border-bottom: 1px solid #bbb;
|
|
|
-}
|
|
|
-
|
|
|
-.title-text {
|
|
|
- font-size: 21px;
|
|
|
- color: #333;
|
|
|
-}
|
|
|
-
|
|
|
-.scroll-content {
|
|
|
- flex: 1;
|
|
|
- max-height: calc(57vh - 140px);
|
|
|
-}
|
|
|
-
|
|
|
-.form-section {
|
|
|
padding: 12px;
|
|
|
- border-bottom: 1px solid #f2f2f2;
|
|
|
+ border-bottom: 1px solid #eeeeee;
|
|
|
}
|
|
|
|
|
|
-.section-title {
|
|
|
- font-size: 18px;
|
|
|
- color: #333;
|
|
|
- font-weight: bold;
|
|
|
- text-align: center;
|
|
|
- padding-bottom: 12px;
|
|
|
+.popup-title {
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #333333;
|
|
|
}
|
|
|
|
|
|
-.input-list {
|
|
|
- max-height: 200px;
|
|
|
+.popup-body {
|
|
|
+ padding: 16px 12px;
|
|
|
}
|
|
|
|
|
|
-.input-row {
|
|
|
+.form-row {
|
|
|
display: flex;
|
|
|
+ flex-direction: row;
|
|
|
align-items: center;
|
|
|
- padding: 8px 0;
|
|
|
- gap: 8px;
|
|
|
+ margin-bottom: 12px;
|
|
|
}
|
|
|
|
|
|
-.input-label {
|
|
|
- flex: 1;
|
|
|
- text-align: right;
|
|
|
- font-size: 16px;
|
|
|
- color: #333;
|
|
|
+.form-row:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
}
|
|
|
|
|
|
-.input-field {
|
|
|
- flex: 1;
|
|
|
- border: 1px solid #ccc;
|
|
|
- border-radius: 2px;
|
|
|
- padding: 8px;
|
|
|
- font-size: 16px;
|
|
|
- background-color: #fff;
|
|
|
+.form-label {
|
|
|
+ flex-shrink: 0;
|
|
|
+ width: 70px;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #333333;
|
|
|
}
|
|
|
|
|
|
-.input-desc {
|
|
|
+.form-value {
|
|
|
flex: 1;
|
|
|
- font-size: 16px;
|
|
|
- color: #666;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #767575;
|
|
|
}
|
|
|
|
|
|
-.output-value {
|
|
|
+.form-input {
|
|
|
flex: 1;
|
|
|
- display: flex;
|
|
|
- flex-direction: row;
|
|
|
- align-items: center;
|
|
|
-}
|
|
|
-
|
|
|
-.output-text {
|
|
|
- font-size: 16px;
|
|
|
- color: #333;
|
|
|
-}
|
|
|
-
|
|
|
-.loading-indicator {
|
|
|
- width: 16px;
|
|
|
- height: 16px;
|
|
|
- border: 2px solid #999;
|
|
|
- border-top-color: transparent;
|
|
|
- border-radius: 50%;
|
|
|
- margin-left: 16px;
|
|
|
- animation: spin 1s linear infinite;
|
|
|
+ height: 32px;
|
|
|
+ padding: 0 8px;
|
|
|
+ font-size: 13px;
|
|
|
+ border: 1px solid #dddddd;
|
|
|
+ border-radius: 4px;
|
|
|
}
|
|
|
|
|
|
-.fee-summary {
|
|
|
+.popup-footer {
|
|
|
display: flex;
|
|
|
flex-direction: row;
|
|
|
- justify-content: space-around;
|
|
|
- align-items: center;
|
|
|
- padding: 24px 12px;
|
|
|
+ border-top: 1px solid #eeeeee;
|
|
|
}
|
|
|
|
|
|
-.fee-item {
|
|
|
+.footer-btn {
|
|
|
display: flex;
|
|
|
- flex-direction: row;
|
|
|
+ flex: 1;
|
|
|
align-items: center;
|
|
|
- gap: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.fee-label {
|
|
|
- font-size: 16px;
|
|
|
- color: #333;
|
|
|
- font-weight: bold;
|
|
|
-}
|
|
|
-
|
|
|
-.fee-value {
|
|
|
- font-size: 16px;
|
|
|
- color: #333;
|
|
|
- font-weight: bold;
|
|
|
-}
|
|
|
-
|
|
|
-.fee-input {
|
|
|
- width: 118px;
|
|
|
- border: 1px solid #ccc;
|
|
|
- border-radius: 2px;
|
|
|
- padding: 8px;
|
|
|
- font-size: 16px;
|
|
|
-}
|
|
|
-
|
|
|
-.empty-state {
|
|
|
- padding: 40px 20px;
|
|
|
- text-align: center;
|
|
|
- color: #999;
|
|
|
- font-size: 14px;
|
|
|
-}
|
|
|
-
|
|
|
-.bottom-actions {
|
|
|
- display: flex;
|
|
|
- justify-content: space-around;
|
|
|
- padding: 10px 0;
|
|
|
- padding-bottom: calc(10px + env(safe-area-inset-bottom));
|
|
|
- background-color: #fff;
|
|
|
- border-top: 1px solid #f2f2f2;
|
|
|
+ justify-content: center;
|
|
|
+ height: 40px;
|
|
|
}
|
|
|
|
|
|
-.cancel-btn,
|
|
|
-.confirm-btn {
|
|
|
- width: 25vw;
|
|
|
- height: 40px;
|
|
|
- border-radius: 4px;
|
|
|
- display: flex;
|
|
|
- flex-direction: row;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- font-size: 16px;
|
|
|
- margin: 0 20px;
|
|
|
+.footer-btn:active {
|
|
|
+ background-color: #f5f5f5;
|
|
|
}
|
|
|
|
|
|
.cancel-btn {
|
|
|
- background-color: #fff;
|
|
|
- border: 1px solid #bbb;
|
|
|
- color: #727272;
|
|
|
+ border-right: 1px solid #eeeeee;
|
|
|
}
|
|
|
|
|
|
-.confirm-btn {
|
|
|
- background-color: #2f8aff;
|
|
|
- color: #f1f7ff;
|
|
|
+.footer-btn-text {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #666666;
|
|
|
}
|
|
|
|
|
|
-@keyframes spin {
|
|
|
- to {
|
|
|
- transform: rotate(360deg);
|
|
|
- }
|
|
|
+.confirm-text {
|
|
|
+ font-weight: 500;
|
|
|
+ color: #4b8cd9;
|
|
|
}
|
|
|
</style>
|