机票时长默认自动计算,可修改

This commit is contained in:
tangxinyue 2026-02-27 10:04:19 +08:00
parent c6dcc7ab4d
commit 3da8a73f1d
1 changed files with 459 additions and 441 deletions

View File

@ -86,10 +86,10 @@
<text class="label">到达机场</text> <text class="label">到达机场</text>
<input class="input" v-model="ticketsInfo.flightInfo.endAirport" /> <input class="input" v-model="ticketsInfo.flightInfo.endAirport" />
</view> </view>
<!-- <view class="form-item"> <view class="form-item">
<text class="label">时长</text> <text class="label">时长</text>
<input class="input" v-model="ticketsInfo.flightInfo.duration" placeholder="例: 2时5分" /> <input class="input" v-model="ticketsInfo.flightInfo.duration" placeholder="例: 2时5分" />
</view> --> </view>
<view class="form-item"> <view class="form-item">
<text class="label">机型</text> <text class="label">机型</text>
<input class="input" v-model="ticketsInfo.flightInfo.aircraftType" /> <input class="input" v-model="ticketsInfo.flightInfo.aircraftType" />
@ -218,7 +218,8 @@
<text class="label">等级</text> <text class="label">等级</text>
<view class="input" <view class="input"
:style="{ color: !ticketsInfo.ctripOrderInfo.level ? '#999' : '#333' }"> :style="{ color: !ticketsInfo.ctripOrderInfo.level ? '#999' : '#333' }">
{{ getLevelLabel(ticketsInfo.ctripOrderInfo.level) || '请选择等级' }}</view> {{ getLevelLabel(ticketsInfo.ctripOrderInfo.level) || '请选择等级' }}
</view>
</view> </view>
</picker> </picker>
<view class="tips-container"> <view class="tips-container">
@ -255,498 +256,515 @@
</template> </template>
<script setup> <script setup>
import NavBar from '@/components/nav-bar/nav-bar.vue' import NavBar from '@/components/nav-bar/nav-bar.vue'
import { reactive, toRefs, onMounted } from 'vue'; import {
import { onLoad } from '@dcloudio/uni-app'; reactive,
import defualtData from '@/pages/other/air-tickets/commom/defualt.json'; toRefs,
import airlineJson from '@/static/json/air-line.json'; onMounted
} from 'vue';
import {
onLoad
} from '@dcloudio/uni-app';
import defualtData from '@/pages/other/air-tickets/commom/defualt.json';
import airlineJson from '@/static/json/air-line.json';
const airLineList = airlineJson.airLine; const airLineList = airlineJson.airLine;
const data = reactive({ const data = reactive({
ticketsInfo: JSON.parse(JSON.stringify(defualtData)), ticketsInfo: JSON.parse(JSON.stringify(defualtData)),
collapsed: { collapsed: {
orderInfo: false, orderInfo: false,
flightInfo: false, flightInfo: false,
passengersInfo: false passengersInfo: false
}, },
storageKey: 'airTicketsInfo', storageKey: 'airTicketsInfo',
dragInfo: { dragInfo: {
index: -1, index: -1,
listType: '', // 'ctrip' or 'fliggy' listType: '', // 'ctrip' or 'fliggy'
startY: 0, startY: 0,
offsetY: 0, offsetY: 0,
itemHeight: 0 itemHeight: 0
} }
})
const { ticketsInfo, collapsed, dragInfo } = toRefs(data)
const onAirlineChange = (e) => {
const index = e.detail.value;
const selected = airLineList[index];
if (selected) {
data.ticketsInfo.flightInfo.airline = selected.name;
data.ticketsInfo.flightInfo.airlineCode = selected.code;
}
}
//
const ctripLevelList = [
{
label: "白银",
value: 1
},
{
label: "黄金",
value: 2
},
{
label: "铂金",
value: 3
},
{
label: "钻石",
value: 4
}
]
const onLevelChange = (e) => {
const index = e.detail.value;
ticketsInfo.value.ctripOrderInfo.level = ctripLevelList[index].value;
}
const getLevelLabel = (value) => {
const item = ctripLevelList.find(i => i.value == value);
return item ? item.label : '';
}
const addTip = () => {
if (!ticketsInfo.value.ctripOrderInfo.tips) {
ticketsInfo.value.ctripOrderInfo.tips = []
}
ticketsInfo.value.ctripOrderInfo.tips.push({
id: Date.now().toString(),
content: ''
}) })
}
const removeTip = (index) => { const {
ticketsInfo.value.ctripOrderInfo.tips.splice(index, 1) ticketsInfo,
} collapsed,
dragInfo
} = toRefs(data)
const addFliggyTip = () => { const onAirlineChange = (e) => {
if (!ticketsInfo.value.fligggyOrderInfo.tips) { const index = e.detail.value;
ticketsInfo.value.fligggyOrderInfo.tips = [] const selected = airLineList[index];
} if (selected) {
ticketsInfo.value.fligggyOrderInfo.tips.push({ data.ticketsInfo.flightInfo.airline = selected.name;
id: Date.now().toString(), data.ticketsInfo.flightInfo.airlineCode = selected.code;
content: ''
})
}
const removeFliggyTip = (index) => {
ticketsInfo.value.fligggyOrderInfo.tips.splice(index, 1)
}
// Drag Sorting Logic
let dragTimer = null
const onDragStart = (e, index, type) => {
const touch = e.touches[0]
// Get item height first - assuming fixed height or query first item
// Better to query the specific item height
// For simplicity, let's assume item height is consistent or query dynamically
const query = uni.createSelectorQuery().in(this)
query.selectAll('.tip-item').boundingClientRect(data => {
if (data && data.length > 0) {
const itemRect = data[index]
dragInfo.value.itemHeight = itemRect.height
dragInfo.value.index = index
dragInfo.value.listType = type
dragInfo.value.startY = touch.clientY
dragInfo.value.offsetY = 0
}
}).exec()
}
const onDragMove = (e) => {
if (dragInfo.value.index === -1) return
const touch = e.touches[0]
const deltaY = touch.clientY - dragInfo.value.startY
dragInfo.value.offsetY = deltaY
// Calculate if we moved enough to swap
const itemHeight = dragInfo.value.itemHeight || 50 // fallback height
const moveSteps = Math.round(deltaY / itemHeight)
if (moveSteps !== 0) {
const newIndex = dragInfo.value.index + moveSteps
let tips = []
if (dragInfo.value.listType === 'ctrip') {
tips = ticketsInfo.value.ctripOrderInfo.tips
} else if (dragInfo.value.listType === 'fliggy') {
tips = ticketsInfo.value.fligggyOrderInfo.tips
}
if (newIndex >= 0 && newIndex < tips.length) {
// Debounce swap or swap immediately if safe?
// Immediate swap might feel jittery if not careful
// Let's swap data and update startY to reflect new position
// Logic: Swap data, reset offset (because the item moved in DOM)
// Simple swap
const temp = tips[dragInfo.value.index]
tips[dragInfo.value.index] = tips[newIndex]
tips[newIndex] = temp
// Update current index to new index
dragInfo.value.index = newIndex
// Reset startY to current touch position relative to new item position
dragInfo.value.startY = touch.clientY
dragInfo.value.offsetY = 0
} }
} }
}
const onDragEnd = () => { //
dragInfo.value.index = -1 const ctripLevelList = [{
dragInfo.value.listType = '' label: "白银",
dragInfo.value.offsetY = 0 value: 1
} },
{
label: "黄金",
value: 2
},
{
label: "铂金",
value: 3
},
{
label: "钻石",
value: 4
}
]
// const onLevelChange = (e) => {
const deepMerge = (target, source) => { const index = e.detail.value;
for (const key in source) { ticketsInfo.value.ctripOrderInfo.level = ctripLevelList[index].value;
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) { }
if (!target[key] || typeof target[key] !== 'object') {
target[key] = {}; const getLevelLabel = (value) => {
const item = ctripLevelList.find(i => i.value == value);
return item ? item.label : '';
}
const addTip = () => {
if (!ticketsInfo.value.ctripOrderInfo.tips) {
ticketsInfo.value.ctripOrderInfo.tips = []
}
ticketsInfo.value.ctripOrderInfo.tips.push({
id: Date.now().toString(),
content: ''
})
}
const removeTip = (index) => {
ticketsInfo.value.ctripOrderInfo.tips.splice(index, 1)
}
const addFliggyTip = () => {
if (!ticketsInfo.value.fligggyOrderInfo.tips) {
ticketsInfo.value.fligggyOrderInfo.tips = []
}
ticketsInfo.value.fligggyOrderInfo.tips.push({
id: Date.now().toString(),
content: ''
})
}
const removeFliggyTip = (index) => {
ticketsInfo.value.fligggyOrderInfo.tips.splice(index, 1)
}
// Drag Sorting Logic
let dragTimer = null
const onDragStart = (e, index, type) => {
const touch = e.touches[0]
// Get item height first - assuming fixed height or query first item
// Better to query the specific item height
// For simplicity, let's assume item height is consistent or query dynamically
const query = uni.createSelectorQuery().in(this)
query.selectAll('.tip-item').boundingClientRect(data => {
if (data && data.length > 0) {
const itemRect = data[index]
dragInfo.value.itemHeight = itemRect.height
dragInfo.value.index = index
dragInfo.value.listType = type
dragInfo.value.startY = touch.clientY
dragInfo.value.offsetY = 0
} }
deepMerge(target[key], source[key]); }).exec()
}
const onDragMove = (e) => {
if (dragInfo.value.index === -1) return
const touch = e.touches[0]
const deltaY = touch.clientY - dragInfo.value.startY
dragInfo.value.offsetY = deltaY
// Calculate if we moved enough to swap
const itemHeight = dragInfo.value.itemHeight || 50 // fallback height
const moveSteps = Math.round(deltaY / itemHeight)
if (moveSteps !== 0) {
const newIndex = dragInfo.value.index + moveSteps
let tips = []
if (dragInfo.value.listType === 'ctrip') {
tips = ticketsInfo.value.ctripOrderInfo.tips
} else if (dragInfo.value.listType === 'fliggy') {
tips = ticketsInfo.value.fligggyOrderInfo.tips
}
if (newIndex >= 0 && newIndex < tips.length) {
// Debounce swap or swap immediately if safe?
// Immediate swap might feel jittery if not careful
// Let's swap data and update startY to reflect new position
// Logic: Swap data, reset offset (because the item moved in DOM)
// Simple swap
const temp = tips[dragInfo.value.index]
tips[dragInfo.value.index] = tips[newIndex]
tips[newIndex] = temp
// Update current index to new index
dragInfo.value.index = newIndex
// Reset startY to current touch position relative to new item position
dragInfo.value.startY = touch.clientY
dragInfo.value.offsetY = 0
}
}
}
const onDragEnd = () => {
dragInfo.value.index = -1
dragInfo.value.listType = ''
dragInfo.value.offsetY = 0
}
//
const deepMerge = (target, source) => {
for (const key in source) {
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
if (!target[key] || typeof target[key] !== 'object') {
target[key] = {};
}
deepMerge(target[key], source[key]);
} else {
target[key] = source[key];
}
}
return target;
};
onLoad((options) => {
console.log('options', options)
if (options.storageKey) {
data.storageKey = options.storageKey
}
const stored = uni.getStorageSync(data.storageKey)
if (stored) {
// 使
//
// data.ticketsInfo reactive defualtData
// defaultData ticketsInfo
// ticketsInfo setup defaultData
// stored merge ticketsInfo deepMerge
// defaultData
const baseData = JSON.parse(JSON.stringify(defualtData));
const mergedData = deepMerge(baseData, stored);
// reactive
// ticketsInfo reactive Object.assign
Object.assign(data.ticketsInfo, mergedData)
// tips stored defaultData - defaultData
if (data.storageKey === 'fliggyAirTicketsInfo' && !data.ticketsInfo.fligggyOrderInfo.tips) {
data.ticketsInfo.fligggyOrderInfo.tips = []
}
if (data.storageKey === 'ctripAirTicketsInfo' && !data.ticketsInfo.ctripOrderInfo.tips) {
data.ticketsInfo.ctripOrderInfo.tips = []
}
}
})
const toggleSection = (key) => {
data.collapsed[key] = !data.collapsed[key]
}
const handleRightButtonClick = () => {
const orderInfo = data.ticketsInfo.orderInfo;
const flightInfo = data.ticketsInfo.flightInfo;
if (orderInfo.orderTime && flightInfo.date && flightInfo.startTime) {
const orderDate = new Date(orderInfo.orderTime.replace(/-/g, '/'));
const flightDate = new Date((flightInfo.date + ' ' + flightInfo.startTime).replace(/-/g, '/'));
if (orderDate > flightDate) {
uni.showToast({
title: '下单时间不能晚于起飞时间',
icon: 'none'
});
return;
}
}
if (data.storageKey === 'ctripAirTicketsInfo') {
delete data.ticketsInfo.fligggyOrderInfo
} else if (data.storageKey === 'fliggyAirTicketsInfo') {
delete data.ticketsInfo.ctripOrderInfo
} else { } else {
target[key] = source[key]; delete data.ticketsInfo.fligggyOrderInfo
delete data.ticketsInfo.ctripOrderInfo
} }
console.log('data.ticketsInfo', data.ticketsInfo)
uni.setStorageSync(data.storageKey, data.ticketsInfo)
uni.showToast({
title: '保存成功',
icon: 'success'
})
uni.navigateBack()
} }
return target;
};
onLoad((options) => { const addPassenger = () => {
console.log('options', options) const lastP = data.ticketsInfo.passengersInfo[data.ticketsInfo.passengersInfo.length - 1]
if (options.storageKey) { data.ticketsInfo.passengersInfo.push({
data.storageKey = options.storageKey name: '新乘客',
idType: lastP ? lastP.idType : '身份证',
idNumber: lastP ? lastP.idNumber : '123123********6352',
ticketNo: lastP ? lastP.ticketNo : '12345678901'
})
} }
const stored = uni.getStorageSync(data.storageKey)
if (stored) {
// 使
//
// data.ticketsInfo reactive defualtData
// defaultData ticketsInfo
// ticketsInfo setup defaultData
// stored merge ticketsInfo deepMerge
// defaultData const removePassenger = (index) => {
const baseData = JSON.parse(JSON.stringify(defualtData)); uni.showModal({
const mergedData = deepMerge(baseData, stored); title: '提示',
content: '确定要删除该乘客吗?',
success: (res) => {
if (res.confirm) {
data.ticketsInfo.passengersInfo.splice(index, 1)
}
}
})
}
// reactive // Helper to extract YYYY-MM-DD from YYYY-MM-DD HH:mm or similar
// ticketsInfo reactive Object.assign const getDateFromStr = (str) => {
Object.assign(data.ticketsInfo, mergedData) if (!str) return ''
// Try to match date pattern
const dateMatch = str.match(/\d{4}[-.]\d{2}[-.]\d{2}/)
if (dateMatch) return dateMatch[0].replace(/\./g, '-')
return ''
}
// tips stored defaultData - defaultData const onOrderDateChange = (e) => {
if (data.storageKey === 'fliggyAirTicketsInfo' && !data.ticketsInfo.fligggyOrderInfo.tips) { const val = e.detail.value // YYYY-MM-DD
data.ticketsInfo.fligggyOrderInfo.tips = [] // orderTime format in default is "YYYY-MM-DD HH:mm"
} // We need to keep the time part if possible, or default to current time
if (data.storageKey === 'ctripAirTicketsInfo' && !data.ticketsInfo.ctripOrderInfo.tips) { let oldTime = '00:00'
data.ticketsInfo.ctripOrderInfo.tips = [] if (data.ticketsInfo.orderInfo.orderTime && data.ticketsInfo.orderInfo.orderTime.includes(' ')) {
oldTime = data.ticketsInfo.orderInfo.orderTime.split(' ')[1]
} }
data.ticketsInfo.orderInfo.orderTime = val + ' ' + oldTime
} }
})
const toggleSection = (key) => { const onFlightDateChange = (e) => {
data.collapsed[key] = !data.collapsed[key] data.ticketsInfo.flightInfo.date = e.detail.value
}
const handleRightButtonClick = () => {
const orderInfo = data.ticketsInfo.orderInfo;
const flightInfo = data.ticketsInfo.flightInfo;
if (orderInfo.orderTime && flightInfo.date && flightInfo.startTime) {
const orderDate = new Date(orderInfo.orderTime.replace(/-/g, '/'));
const flightDate = new Date((flightInfo.date + ' ' + flightInfo.startTime).replace(/-/g, '/'));
if (orderDate > flightDate) {
uni.showToast({
title: '下单时间不能晚于起飞时间',
icon: 'none'
});
return;
}
} }
if (data.storageKey === 'ctripAirTicketsInfo') {
delete data.ticketsInfo.fligggyOrderInfo // Custom Time Picker Data
} else if (data.storageKey === 'fliggyAirTicketsInfo') { const hours = Array.from({
delete data.ticketsInfo.ctripOrderInfo length: 24
} else { }, (_, i) => i.toString().padStart(2, '0'));
delete data.ticketsInfo.fligggyOrderInfo const minutes = Array.from({
delete data.ticketsInfo.ctripOrderInfo length: 60
}, (_, i) => i.toString().padStart(2, '0'));
const timeRange = [hours, minutes];
const getTimeIndex = (timeStr) => {
if (!timeStr) return [0, 0];
const [h, m] = timeStr.split(':');
const hIndex = hours.findIndex(item => item === h);
const mIndex = minutes.findIndex(item => item === m);
return [hIndex === -1 ? 0 : hIndex, mIndex === -1 ? 0 : mIndex];
};
const onStartTimeChange = (e) => {
const [hIndex, mIndex] = e.detail.value;
const time = `${hours[hIndex]}:${minutes[mIndex]}`;
data.ticketsInfo.flightInfo.startTime = time;
updateDuration();
} }
console.log('data.ticketsInfo', data.ticketsInfo)
uni.setStorageSync(data.storageKey, data.ticketsInfo)
uni.showToast({
title: '保存成功',
icon: 'success'
})
uni.navigateBack()
}
const addPassenger = () => { const onEndTimeChange = (e) => {
const lastP = data.ticketsInfo.passengersInfo[data.ticketsInfo.passengersInfo.length - 1] const [hIndex, mIndex] = e.detail.value;
data.ticketsInfo.passengersInfo.push({ const time = `${hours[hIndex]}:${minutes[mIndex]}`;
name: '新乘客', data.ticketsInfo.flightInfo.endTime = time;
idType: lastP ? lastP.idType : '身份证', updateDuration();
idNumber: lastP ? lastP.idNumber : '123123********6352', }
ticketNo: lastP ? lastP.ticketNo : '12345678901'
})
}
const removePassenger = (index) => { const updateDuration = () => {
uni.showModal({ // Simple calc if same day or we can just leave it to user to input manually (which we support via input)
title: '提示', // But let's try a best effort calc
content: '确定要删除该乘客吗?', const ft = data.ticketsInfo.flightInfo
success: (res) => { if (ft.startTime && ft.endTime) {
if (res.confirm) { const [sh, sm] = ft.startTime.split(':').map(Number)
data.ticketsInfo.passengersInfo.splice(index, 1) const [eh, em] = ft.endTime.split(':').map(Number)
let diffMin = (eh * 60 + em) - (sh * 60 + sm)
if (diffMin < 0) diffMin += 24 * 60 // Assume next day if cross midnight
const h = Math.floor(diffMin / 60)
const m = diffMin % 60
if (h > 0) {
ft.duration = `${h}${m}`
} else {
ft.duration = `${m}`
} }
} }
})
}
// Helper to extract YYYY-MM-DD from YYYY-MM-DD HH:mm or similar
const getDateFromStr = (str) => {
if (!str) return ''
// Try to match date pattern
const dateMatch = str.match(/\d{4}[-.]\d{2}[-.]\d{2}/)
if (dateMatch) return dateMatch[0].replace(/\./g, '-')
return ''
}
const onOrderDateChange = (e) => {
const val = e.detail.value // YYYY-MM-DD
// orderTime format in default is "YYYY-MM-DD HH:mm"
// We need to keep the time part if possible, or default to current time
let oldTime = '00:00'
if (data.ticketsInfo.orderInfo.orderTime && data.ticketsInfo.orderInfo.orderTime.includes(' ')) {
oldTime = data.ticketsInfo.orderInfo.orderTime.split(' ')[1]
} }
data.ticketsInfo.orderInfo.orderTime = val + ' ' + oldTime
}
const onFlightDateChange = (e) => {
data.ticketsInfo.flightInfo.date = e.detail.value
}
// Custom Time Picker Data
const hours = Array.from({ length: 24 }, (_, i) => i.toString().padStart(2, '0'));
const minutes = Array.from({ length: 60 }, (_, i) => i.toString().padStart(2, '0'));
const timeRange = [hours, minutes];
const getTimeIndex = (timeStr) => {
if (!timeStr) return [0, 0];
const [h, m] = timeStr.split(':');
const hIndex = hours.findIndex(item => item === h);
const mIndex = minutes.findIndex(item => item === m);
return [hIndex === -1 ? 0 : hIndex, mIndex === -1 ? 0 : mIndex];
};
const onStartTimeChange = (e) => {
const [hIndex, mIndex] = e.detail.value;
const time = `${hours[hIndex]}:${minutes[mIndex]}`;
data.ticketsInfo.flightInfo.startTime = time;
updateDuration();
}
const onEndTimeChange = (e) => {
const [hIndex, mIndex] = e.detail.value;
const time = `${hours[hIndex]}:${minutes[mIndex]}`;
data.ticketsInfo.flightInfo.endTime = time;
updateDuration();
}
const updateDuration = () => {
// Simple calc if same day or we can just leave it to user to input manually (which we support via input)
// But let's try a best effort calc
const ft = data.ticketsInfo.flightInfo
if (ft.startTime && ft.endTime) {
const [sh, sm] = ft.startTime.split(':').map(Number)
const [eh, em] = ft.endTime.split(':').map(Number)
let diffMin = (eh * 60 + em) - (sh * 60 + sm)
if (diffMin < 0) diffMin += 24 * 60 // Assume next day if cross midnight
const h = Math.floor(diffMin / 60)
const m = diffMin % 60
ft.duration = `${h}${m}`
}
}
</script> </script>
<style> <style>
@import "@/common/main.css"; @import "@/common/main.css";
page { page {
background-color: #F8F8F8; background-color: #F8F8F8;
height: 100vh; height: 100vh;
overflow: hidden; overflow: hidden;
} }
</style> </style>
<style lang="less" scoped> <style lang="less" scoped>
.container { .container {
display: flex;
flex-direction: column;
height: 100vh;
}
.form-content {
flex: 1;
height: 0;
padding: 24rpx;
box-sizing: border-box;
}
.section-container {
margin-bottom: 24rpx;
}
.section-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 24rpx 12rpx 16rpx;
background-color: transparent;
}
.section-title {
font-size: 28rpx;
color: #666;
font-weight: 500;
}
.card {
background-color: #fff;
border-radius: 16rpx;
padding: 0 24rpx;
margin-bottom: 24rpx;
overflow: hidden;
.card-header-row {
display: flex; display: flex;
justify-content: space-between; flex-direction: column;
align-items: center; height: 100vh;
padding: 24rpx 0 12rpx;
border-bottom: 1rpx solid #f5f5f5;
margin-bottom: 12rpx;
} }
.card-header { .form-content {
font-size: 30rpx;
font-weight: bold;
color: #333;
}
.delete-btn {
font-size: 26rpx;
color: #FF4D4F;
padding: 4rpx 12rpx;
}
}
.form-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 0;
border-bottom: 1rpx solid #F5F5F5;
.label {
font-size: 30rpx;
color: #333;
width: 240rpx;
}
.input {
flex: 1; flex: 1;
font-size: 30rpx; height: 0;
color: #333; padding: 24rpx;
text-align: right; box-sizing: border-box;
} }
}
.add-btn-box { .section-container {
background-color: #fff; margin-bottom: 24rpx;
border-radius: 16rpx;
padding: 24rpx;
display: flex;
justify-content: center;
align-items: center;
border: 2rpx dashed #1677FF;
margin-bottom: 24rpx;
.add-text {
color: #1677FF;
font-size: 30rpx;
margin-left: 8rpx;
} }
}
.placeholder { .section-header {
height: 60rpx;
}
.tips-container {
padding: 24rpx 0;
border-bottom: 1rpx solid #F5F5F5;
.tips-header {
display: flex; display: flex;
flex-direction: row;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 16rpx; padding: 24rpx 12rpx 16rpx;
background-color: transparent;
} }
.tip-list { .section-title {
.tip-item { font-size: 28rpx;
color: #666;
font-weight: 500;
}
.card {
background-color: #fff;
border-radius: 16rpx;
padding: 0 24rpx;
margin-bottom: 24rpx;
overflow: hidden;
.card-header-row {
display: flex; display: flex;
align-items: center;
justify-content: space-between; justify-content: space-between;
align-items: center;
padding: 24rpx 0 12rpx;
border-bottom: 1rpx solid #f5f5f5;
margin-bottom: 12rpx;
}
.card-header {
font-size: 30rpx;
font-weight: bold;
color: #333;
}
.delete-btn {
font-size: 26rpx;
color: #FF4D4F;
padding: 4rpx 12rpx;
}
}
.form-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 0;
border-bottom: 1rpx solid #F5F5F5;
.label {
font-size: 30rpx;
color: #333;
width: 240rpx;
}
.input {
flex: 1;
font-size: 30rpx;
color: #333;
text-align: right;
}
}
.add-btn-box {
background-color: #fff;
border-radius: 16rpx;
padding: 24rpx;
display: flex;
justify-content: center;
align-items: center;
border: 2rpx dashed #1677FF;
margin-bottom: 24rpx;
.add-text {
color: #1677FF;
font-size: 30rpx;
margin-left: 8rpx;
}
}
.placeholder {
height: 60rpx;
}
.tips-container {
padding: 24rpx 0;
border-bottom: 1rpx solid #F5F5F5;
.tips-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx; margin-bottom: 16rpx;
background-color: #F8F8F8; }
padding: 12rpx 16rpx;
border-radius: 8rpx;
.tip-input { .tip-list {
flex: 1; .tip-item {
font-size: 26rpx;
color: #333;
margin-right: 16rpx;
}
.tip-actions {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 16rpx; justify-content: space-between;
margin-bottom: 16rpx;
background-color: #F8F8F8;
padding: 12rpx 16rpx;
border-radius: 8rpx;
.tip-input {
flex: 1;
font-size: 26rpx;
color: #333;
margin-right: 16rpx;
}
.tip-actions {
display: flex;
align-items: center;
gap: 16rpx;
}
}
.sort-active {
background-color: #E6F2FF;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
transition: transform 0.1s;
} }
} }
.sort-active {
background-color: #E6F2FF;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
transition: transform 0.1s;
}
} }
} </style>
</style>