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

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,15 +256,21 @@
</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,
@ -278,22 +285,25 @@ const data = reactive({
offsetY: 0, offsetY: 0,
itemHeight: 0 itemHeight: 0
} }
}) })
const { ticketsInfo, collapsed, dragInfo } = toRefs(data) const {
ticketsInfo,
collapsed,
dragInfo
} = toRefs(data)
const onAirlineChange = (e) => { const onAirlineChange = (e) => {
const index = e.detail.value; const index = e.detail.value;
const selected = airLineList[index]; const selected = airLineList[index];
if (selected) { if (selected) {
data.ticketsInfo.flightInfo.airline = selected.name; data.ticketsInfo.flightInfo.airline = selected.name;
data.ticketsInfo.flightInfo.airlineCode = selected.code; data.ticketsInfo.flightInfo.airlineCode = selected.code;
} }
} }
// //
const ctripLevelList = [ const ctripLevelList = [{
{
label: "白银", label: "白银",
value: 1 value: 1
}, },
@ -309,21 +319,21 @@ const ctripLevelList = [
label: "钻石", label: "钻石",
value: 4 value: 4
} }
] ]
const onLevelChange = (e) => { const onLevelChange = (e) => {
const index = e.detail.value; const index = e.detail.value;
ticketsInfo.value.ctripOrderInfo.level = ctripLevelList[index].value; ticketsInfo.value.ctripOrderInfo.level = ctripLevelList[index].value;
} }
const getLevelLabel = (value) => { const getLevelLabel = (value) => {
const item = ctripLevelList.find(i => i.value == value); const item = ctripLevelList.find(i => i.value == value);
return item ? item.label : ''; return item ? item.label : '';
} }
const addTip = () => { const addTip = () => {
if (!ticketsInfo.value.ctripOrderInfo.tips) { if (!ticketsInfo.value.ctripOrderInfo.tips) {
ticketsInfo.value.ctripOrderInfo.tips = [] ticketsInfo.value.ctripOrderInfo.tips = []
} }
@ -331,13 +341,13 @@ const addTip = () => {
id: Date.now().toString(), id: Date.now().toString(),
content: '' content: ''
}) })
} }
const removeTip = (index) => { const removeTip = (index) => {
ticketsInfo.value.ctripOrderInfo.tips.splice(index, 1) ticketsInfo.value.ctripOrderInfo.tips.splice(index, 1)
} }
const addFliggyTip = () => { const addFliggyTip = () => {
if (!ticketsInfo.value.fligggyOrderInfo.tips) { if (!ticketsInfo.value.fligggyOrderInfo.tips) {
ticketsInfo.value.fligggyOrderInfo.tips = [] ticketsInfo.value.fligggyOrderInfo.tips = []
} }
@ -345,16 +355,16 @@ const addFliggyTip = () => {
id: Date.now().toString(), id: Date.now().toString(),
content: '' content: ''
}) })
} }
const removeFliggyTip = (index) => { const removeFliggyTip = (index) => {
ticketsInfo.value.fligggyOrderInfo.tips.splice(index, 1) ticketsInfo.value.fligggyOrderInfo.tips.splice(index, 1)
} }
// Drag Sorting Logic // Drag Sorting Logic
let dragTimer = null let dragTimer = null
const onDragStart = (e, index, type) => { const onDragStart = (e, index, type) => {
const touch = e.touches[0] const touch = e.touches[0]
// Get item height first - assuming fixed height or query first item // Get item height first - assuming fixed height or query first item
// Better to query the specific item height // Better to query the specific item height
@ -370,9 +380,9 @@ const onDragStart = (e, index, type) => {
dragInfo.value.offsetY = 0 dragInfo.value.offsetY = 0
} }
}).exec() }).exec()
} }
const onDragMove = (e) => { const onDragMove = (e) => {
if (dragInfo.value.index === -1) return if (dragInfo.value.index === -1) return
const touch = e.touches[0] const touch = e.touches[0]
const deltaY = touch.clientY - dragInfo.value.startY const deltaY = touch.clientY - dragInfo.value.startY
@ -409,16 +419,16 @@ const onDragMove = (e) => {
dragInfo.value.offsetY = 0 dragInfo.value.offsetY = 0
} }
} }
} }
const onDragEnd = () => { const onDragEnd = () => {
dragInfo.value.index = -1 dragInfo.value.index = -1
dragInfo.value.listType = '' dragInfo.value.listType = ''
dragInfo.value.offsetY = 0 dragInfo.value.offsetY = 0
} }
// //
const deepMerge = (target, source) => { const deepMerge = (target, source) => {
for (const key in source) { for (const key in source) {
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) { if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
if (!target[key] || typeof target[key] !== 'object') { if (!target[key] || typeof target[key] !== 'object') {
@ -430,9 +440,9 @@ const deepMerge = (target, source) => {
} }
} }
return target; return target;
}; };
onLoad((options) => { onLoad((options) => {
console.log('options', options) console.log('options', options)
if (options.storageKey) { if (options.storageKey) {
data.storageKey = options.storageKey data.storageKey = options.storageKey
@ -462,13 +472,13 @@ onLoad((options) => {
data.ticketsInfo.ctripOrderInfo.tips = [] data.ticketsInfo.ctripOrderInfo.tips = []
} }
} }
}) })
const toggleSection = (key) => { const toggleSection = (key) => {
data.collapsed[key] = !data.collapsed[key] data.collapsed[key] = !data.collapsed[key]
} }
const handleRightButtonClick = () => { const handleRightButtonClick = () => {
const orderInfo = data.ticketsInfo.orderInfo; const orderInfo = data.ticketsInfo.orderInfo;
const flightInfo = data.ticketsInfo.flightInfo; const flightInfo = data.ticketsInfo.flightInfo;
@ -499,9 +509,9 @@ const handleRightButtonClick = () => {
icon: 'success' icon: 'success'
}) })
uni.navigateBack() uni.navigateBack()
} }
const addPassenger = () => { const addPassenger = () => {
const lastP = data.ticketsInfo.passengersInfo[data.ticketsInfo.passengersInfo.length - 1] const lastP = data.ticketsInfo.passengersInfo[data.ticketsInfo.passengersInfo.length - 1]
data.ticketsInfo.passengersInfo.push({ data.ticketsInfo.passengersInfo.push({
name: '新乘客', name: '新乘客',
@ -509,9 +519,9 @@ const addPassenger = () => {
idNumber: lastP ? lastP.idNumber : '123123********6352', idNumber: lastP ? lastP.idNumber : '123123********6352',
ticketNo: lastP ? lastP.ticketNo : '12345678901' ticketNo: lastP ? lastP.ticketNo : '12345678901'
}) })
} }
const removePassenger = (index) => { const removePassenger = (index) => {
uni.showModal({ uni.showModal({
title: '提示', title: '提示',
content: '确定要删除该乘客吗?', content: '确定要删除该乘客吗?',
@ -521,18 +531,18 @@ const removePassenger = (index) => {
} }
} }
}) })
} }
// Helper to extract YYYY-MM-DD from YYYY-MM-DD HH:mm or similar // Helper to extract YYYY-MM-DD from YYYY-MM-DD HH:mm or similar
const getDateFromStr = (str) => { const getDateFromStr = (str) => {
if (!str) return '' if (!str) return ''
// Try to match date pattern // Try to match date pattern
const dateMatch = str.match(/\d{4}[-.]\d{2}[-.]\d{2}/) const dateMatch = str.match(/\d{4}[-.]\d{2}[-.]\d{2}/)
if (dateMatch) return dateMatch[0].replace(/\./g, '-') if (dateMatch) return dateMatch[0].replace(/\./g, '-')
return '' return ''
} }
const onOrderDateChange = (e) => { const onOrderDateChange = (e) => {
const val = e.detail.value // YYYY-MM-DD const val = e.detail.value // YYYY-MM-DD
// orderTime format in default is "YYYY-MM-DD HH:mm" // orderTime format in default is "YYYY-MM-DD HH:mm"
// We need to keep the time part if possible, or default to current time // We need to keep the time part if possible, or default to current time
@ -541,40 +551,44 @@ const onOrderDateChange = (e) => {
oldTime = data.ticketsInfo.orderInfo.orderTime.split(' ')[1] oldTime = data.ticketsInfo.orderInfo.orderTime.split(' ')[1]
} }
data.ticketsInfo.orderInfo.orderTime = val + ' ' + oldTime data.ticketsInfo.orderInfo.orderTime = val + ' ' + oldTime
} }
const onFlightDateChange = (e) => { const onFlightDateChange = (e) => {
data.ticketsInfo.flightInfo.date = e.detail.value data.ticketsInfo.flightInfo.date = e.detail.value
} }
// Custom Time Picker Data // Custom Time Picker Data
const hours = Array.from({ length: 24 }, (_, i) => i.toString().padStart(2, '0')); const hours = Array.from({
const minutes = Array.from({ length: 60 }, (_, i) => i.toString().padStart(2, '0')); length: 24
const timeRange = [hours, minutes]; }, (_, 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) => { const getTimeIndex = (timeStr) => {
if (!timeStr) return [0, 0]; if (!timeStr) return [0, 0];
const [h, m] = timeStr.split(':'); const [h, m] = timeStr.split(':');
const hIndex = hours.findIndex(item => item === h); const hIndex = hours.findIndex(item => item === h);
const mIndex = minutes.findIndex(item => item === m); const mIndex = minutes.findIndex(item => item === m);
return [hIndex === -1 ? 0 : hIndex, mIndex === -1 ? 0 : mIndex]; return [hIndex === -1 ? 0 : hIndex, mIndex === -1 ? 0 : mIndex];
}; };
const onStartTimeChange = (e) => { const onStartTimeChange = (e) => {
const [hIndex, mIndex] = e.detail.value; const [hIndex, mIndex] = e.detail.value;
const time = `${hours[hIndex]}:${minutes[mIndex]}`; const time = `${hours[hIndex]}:${minutes[mIndex]}`;
data.ticketsInfo.flightInfo.startTime = time; data.ticketsInfo.flightInfo.startTime = time;
updateDuration(); updateDuration();
} }
const onEndTimeChange = (e) => { const onEndTimeChange = (e) => {
const [hIndex, mIndex] = e.detail.value; const [hIndex, mIndex] = e.detail.value;
const time = `${hours[hIndex]}:${minutes[mIndex]}`; const time = `${hours[hIndex]}:${minutes[mIndex]}`;
data.ticketsInfo.flightInfo.endTime = time; data.ticketsInfo.flightInfo.endTime = time;
updateDuration(); updateDuration();
} }
const updateDuration = () => { const updateDuration = () => {
// Simple calc if same day or we can just leave it to user to input manually (which we support via input) // 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 // But let's try a best effort calc
const ft = data.ticketsInfo.flightInfo const ft = data.ticketsInfo.flightInfo
@ -586,55 +600,59 @@ const updateDuration = () => {
const h = Math.floor(diffMin / 60) const h = Math.floor(diffMin / 60)
const m = diffMin % 60 const m = diffMin % 60
if (h > 0) {
ft.duration = `${h}${m}` ft.duration = `${h}${m}`
} else {
ft.duration = `${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; display: flex;
flex-direction: column; flex-direction: column;
height: 100vh; height: 100vh;
} }
.form-content { .form-content {
flex: 1; flex: 1;
height: 0; height: 0;
padding: 24rpx; padding: 24rpx;
box-sizing: border-box; box-sizing: border-box;
} }
.section-container { .section-container {
margin-bottom: 24rpx; margin-bottom: 24rpx;
} }
.section-header { .section-header {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 24rpx 12rpx 16rpx; padding: 24rpx 12rpx 16rpx;
background-color: transparent; background-color: transparent;
} }
.section-title { .section-title {
font-size: 28rpx; font-size: 28rpx;
color: #666; color: #666;
font-weight: 500; font-weight: 500;
} }
.card { .card {
background-color: #fff; background-color: #fff;
border-radius: 16rpx; border-radius: 16rpx;
padding: 0 24rpx; padding: 0 24rpx;
@ -661,9 +679,9 @@ page {
color: #FF4D4F; color: #FF4D4F;
padding: 4rpx 12rpx; padding: 4rpx 12rpx;
} }
} }
.form-item { .form-item {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
@ -684,9 +702,9 @@ page {
color: #333; color: #333;
text-align: right; text-align: right;
} }
} }
.add-btn-box { .add-btn-box {
background-color: #fff; background-color: #fff;
border-radius: 16rpx; border-radius: 16rpx;
padding: 24rpx; padding: 24rpx;
@ -701,13 +719,13 @@ page {
font-size: 30rpx; font-size: 30rpx;
margin-left: 8rpx; margin-left: 8rpx;
} }
} }
.placeholder { .placeholder {
height: 60rpx; height: 60rpx;
} }
.tips-container { .tips-container {
padding: 24rpx 0; padding: 24rpx 0;
border-bottom: 1rpx solid #F5F5F5; border-bottom: 1rpx solid #F5F5F5;
@ -748,5 +766,5 @@ page {
transition: transform 0.1s; transition: transform 0.1s;
} }
} }
} }
</style> </style>