Skip to content

Commit b18fd0f

Browse files
committed
新增火车票、卧铺、学生票、各种优惠选项
1 parent d76ea52 commit b18fd0f

File tree

2 files changed

+183
-20
lines changed

2 files changed

+183
-20
lines changed

package/website/src/components/TrainTicket.vue

Lines changed: 91 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
</div>
7171

7272
<!-- 第二行:时间 / 车厢座位 / 价格 / 座位类型 -->
73-
<div class="second-row flex justify-between pr-[120px]">
73+
<div class="second-row flex justify-between pr-[100px]">
7474
<div class="datetime">
7575
{{ dateTime.year }}
7676
<span class="small-fix text-[24px]">年</span>
@@ -81,11 +81,20 @@
8181
{{ dateTime.time }}
8282
<span class="small-fix text-[24px]">开</span>
8383
</div>
84-
<div class="seat">{{ carriage }}<span class="small-fix text-[24px]">车</span>{{ seatNumber }}<span class="small-fix text-[24px]">号</span></div>
84+
<div class="seat">{{ carriage }}<span class="small-fix text-[24px]">车</span>{{ seatNumber }}<span class="small-fix text-[24px]">号</span><span v-if="berthType">{{ berthType }}</span><span v-if="berthType" class="small-fix text-[24px]">铺</span></div>
8585
</div>
86-
<div class="second-row flex justify-between pr-[120px]">
87-
<div class="datetime">¥{{ price }}<span class="small-fix text-[24px]">元</span></div>
88-
<div class="seat">{{ seatType }}</div>
86+
<!-- 价格和座位类型行:添加优惠标识 -->
87+
<div class="second-row flex justify-between pr-[100px] items-center">
88+
<div class="datetime flex items-center gap-[12px]">
89+
¥{{ price }}<span class="small-fix text-[24px]">元</span>
90+
</div>
91+
<div>
92+
<!-- 优惠标识 -->
93+
<span v-for="(text, index) in discountTexts" :key="index" class="discount-badge">{{ text }}</span>
94+
</div>
95+
<div class="seat flex items-center gap-[12px]">
96+
{{ seatType }}
97+
</div>
8998
</div>
9099
</div>
91100

@@ -120,7 +129,8 @@
120129
</template>
121130

122131
<script setup>
123-
import { ref, computed, defineProps, onMounted, onUnmounted } from 'vue'
132+
133+
import { ref, computed, onMounted, onUnmounted } from 'vue'
124134
125135
// 基础尺寸
126136
const BASE_WIDTH = 856
@@ -159,11 +169,26 @@ const props = defineProps({
159169
dateTime: { type: String, default: '2017-06-06 16:46' },
160170
carriage: { type: String, default: '03' },
161171
seatNumber: { type: String, default: '04D' },
172+
berthType: { type: String, default: '' },
173+
berthNumber: { type: String, default: '' },
162174
price: { type: String, default: '239.0' },
163175
seatType: { type: String, default: '二等座' },
164176
idNumber: { type: String, default: '14041111985****0854' },
165177
passengerName: { type: String, default: '李小二' },
166-
footerInfo: { type: String, default: '65773311920607J093984 郑州东售' }
178+
footerInfo: { type: String, default: '65773311920607J093984 郑州东售' },
179+
// 修改:支持传入数组(多个优惠类型)或字符串(单个优惠类型)
180+
discountType: {
181+
type: [String, Array],
182+
default: '',
183+
validator: (value) => {
184+
// 允许的优惠类型(支持单个或数组)
185+
const validTypes = ['student', 'discount', 'child', 'elder', 'military', 'disabled', 'group', 'worker-group', 'student-group', '']
186+
if (Array.isArray(value)) {
187+
return value.every(item => validTypes.includes(item))
188+
}
189+
return validTypes.includes(value)
190+
}
191+
}
167192
})
168193
169194
// 拆分时间
@@ -176,6 +201,50 @@ const dateTime = computed(() => {
176201
}
177202
})
178203
204+
// 修改:计算优惠显示文字(支持多个)
205+
const discountTexts = computed(() => {
206+
const texts = []
207+
const types = Array.isArray(props.discountType) ? props.discountType : props.discountType ? [props.discountType] : []
208+
209+
types.forEach(type => {
210+
switch(type) {
211+
case 'student':
212+
texts.push('', '') // 学生票同时添加"学"和"惠"
213+
break
214+
case 'discount':
215+
texts.push('')
216+
break
217+
case 'child':
218+
texts.push('')
219+
break
220+
case 'elder':
221+
texts.push('')
222+
break
223+
case 'military':
224+
texts.push('')
225+
break
226+
case 'disabled':
227+
texts.push('')
228+
break
229+
case 'group':
230+
texts.push('')
231+
break
232+
case 'worker-group':
233+
texts.push('')
234+
break
235+
case 'student-group':
236+
texts.push('', '')
237+
break
238+
default:
239+
// 支持直接传入文字(如['优', '惠'])
240+
if (type && !validTypes.includes(type)) {
241+
texts.push(type)
242+
}
243+
}
244+
})
245+
return texts
246+
})
247+
179248
defineExpose({ wrapper, exporting }) // ✅ 暴露内部DOM给父组件访问
180249
</script>
181250

@@ -249,4 +318,19 @@ defineExpose({ wrapper, exporting }) // ✅ 暴露内部DOM给父组件访问
249318
border-top: 8px solid #3a5874; /* 箭头颜色(与拼音同色) */
250319
margin-top: 6px; /* 箭头与文字的间距(可按需调整) */
251320
}
321+
/* 新增:优惠标识圆圈样式 */
322+
.discount-badge {
323+
display: inline-flex;
324+
align-items: center;
325+
justify-content: center;
326+
width: 36px;
327+
height: 36px;
328+
border: 3px solid #1f1d1d;
329+
border-radius: 50%;
330+
font-size: 24px;
331+
/* font-weight: 600; */
332+
line-height: 1;
333+
text-align: center;
334+
/* background-color: rgba(227, 87, 87, 0.08); */
335+
}
252336
</style>

package/website/src/views/tools/TrainTicketGengrate.vue

Lines changed: 92 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
>
3232
</div>
3333
<div class="form-group">
34-
<label class="block text-sm font-medium text-gray-600 dark:text-gray-300 mb-1">出发站拼音(全小写)</label>
34+
<label class="block text-sm font-medium text-gray-600 dark:text-gray-300 mb-1">出发站拼音</label>
3535
<input
3636
v-model="form.fromPinyin"
3737
type="text"
@@ -53,7 +53,7 @@
5353
>
5454
</div>
5555
<div class="form-group">
56-
<label class="block text-sm font-medium text-gray-600 dark:text-gray-300 mb-1">到达站拼音(全小写)</label>
56+
<label class="block text-sm font-medium text-gray-600 dark:text-gray-300 mb-1">到达站拼音</label>
5757
<input
5858
v-model="form.toPinyin"
5959
type="text"
@@ -122,6 +122,16 @@
122122
<option value="二等座">二等座</option>
123123
<option value="商务座">商务座</option>
124124
<option value="无座">无座</option>
125+
<!-- 新增卧铺类型 -->
126+
<option value="硬座">硬座</option>
127+
<option value="软座">软座</option>
128+
<option value="特等座">特等座</option>
129+
<option value="软卧">软卧</option>
130+
<option value="硬卧">硬卧</option>
131+
<option value="动卧">动卧</option>
132+
<option value="高级软卧">高级软卧</option>
133+
<option value="一等卧">一等卧</option>
134+
<option value="二等卧">二等卧</option>
125135
</select>
126136
</div>
127137
</div>
@@ -148,8 +158,24 @@
148158
required
149159
>
150160
</div>
161+
<!-- 铺位类型选择(卧铺专用,上/中/下) -->
162+
<!-- 铺位类型(卧铺专用,上/中/下铺选择) -->
163+
<div class="form-group" v-if="sleeperTypes.includes(form.seatType)">
164+
<label class="block text-sm font-medium text-gray-600 dark:text-gray-300 mb-1">铺位类型</label>
165+
<select
166+
v-model="form.berthType"
167+
class="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-800 dark:text-gray-100 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all appearance-none"
168+
required
169+
>
170+
<option value="">选择铺位</option>
171+
<option value="">上铺</option>
172+
<option value="">中铺</option>
173+
<option value="">下铺</option>
174+
</select>
175+
</div>
151176
<div class="form-group">
152-
<label class="block text-sm font-medium text-gray-600 dark:text-gray-300 mb-1">座位号</label>
177+
<label v-if="sleeperTypes.includes(form.seatType)" class="block text-sm font-medium text-gray-600 dark:text-gray-300 mb-1">铺位号</label>
178+
<label v-else class="block text-sm font-medium text-gray-600 dark:text-gray-300 mb-1">座位号</label>
153179
<input
154180
v-model="form.seatNumber"
155181
type="text"
@@ -162,10 +188,10 @@
162188
</div>
163189
<div class="form-group">
164190
<label class="block text-sm font-medium text-gray-600 dark:text-gray-300 mb-1">票价(元)</label>
165-
<input
166-
v-model="form.price"
167-
type="number"
168-
step="0.5"
191+
<input
192+
v-model="form.price"
193+
type="number"
194+
step="0.5"
169195
min="0"
170196
class="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-800 dark:text-gray-100 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
171197
placeholder="例:443.5"
@@ -175,14 +201,33 @@
175201
</div>
176202
<div class="form-group">
177203
<label class="block text-sm font-medium text-gray-600 dark:text-gray-300 mb-1">票号</label>
178-
<input
179-
v-model="form.serial"
180-
type="text"
204+
<input
205+
v-model="form.serial"
206+
type="text"
181207
class="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-800 dark:text-gray-100 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
182208
placeholder="例:283K104567"
183209
required
184210
>
185211
</div>
212+
<!-- 座位/价格信息区域 - 新增优惠类型选择 -->
213+
<div class="form-group">
214+
<label class="block text-sm font-medium text-gray-600 dark:text-gray-300 mb-1">优惠类型</label>
215+
<select
216+
v-model="form.discountType"
217+
class="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-800 dark:text-gray-100 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all appearance-none"
218+
>
219+
<option value="">无优惠</option>
220+
<option value="student">学生票(学+惠)</option>
221+
<option value="child">儿童票(儿)</option>
222+
<option value="military">残疾军人票(军)</option>
223+
<option value="disabled">残疾人票(残)</option>
224+
<option value="elder">老人优惠票(老)</option>
225+
<option value="discount">普通优惠票(惠)</option>
226+
<option value="group">团体票(团)</option>
227+
<option value="worker-group">务工团体票(工)</option>
228+
<option value="student-group">学生团体票(学+团)</option>
229+
</select>
230+
</div>
186231
</div>
187232
</div>
188233

@@ -263,11 +308,13 @@
263308
:dateTime="form.dateTime"
264309
:carriage="form.carriage"
265310
:seatNumber="form.seatNumber"
311+
:berthType="form.berthType"
266312
:price="form.price"
267313
:seatType="form.seatType"
268314
:idNumber="form.idNumber"
269315
:passengerName="form.passengerName"
270316
:footerInfo="form.footerInfo"
317+
:discountType="form.discountType"
271318
/>
272319
</div>
273320
<!-- 隐藏的原始尺寸车票,用于导出 -->
@@ -287,11 +334,13 @@
287334
:dateTime="form.dateTime"
288335
:carriage="form.carriage"
289336
:seatNumber="form.seatNumber"
337+
:berthType="form.berthType"
290338
:price="form.price"
291339
:seatType="form.seatType"
292340
:idNumber="form.idNumber"
293341
:passengerName="form.passengerName"
294342
:footerInfo="form.footerInfo"
343+
:discountType="form.discountType"
295344
/>
296345
</div>
297346
</div>
@@ -302,9 +351,8 @@
302351

303352

304353
<script setup>
305-
import { ref, reactive, onMounted, nextTick } from 'vue';
354+
import { ref, reactive, onMounted, nextTick, watch, computed} from 'vue';
306355
import TrainTicket from '@/components/TrainTicket.vue';
307-
import html2canvas from 'html2canvas';
308356
import { toPng } from "html-to-image";
309357
310358
@@ -324,7 +372,38 @@ const form = reactive({
324372
seatType: '一等座',
325373
idNumber: '3201021990****5678',
326374
passengerName: '张三',
327-
footerInfo: '65773311920607K104567 北京南售'
375+
footerInfo: '65773311920607K104567 北京南售',
376+
discountType: 'student', // 示例:学生票
377+
berthType: '', // 铺位类型(上/中/下)
378+
berthNumber: '', // 铺位号(数字部分)
379+
});
380+
381+
// 定义卧铺类型列表(用于判断是否显示铺位选择)
382+
const sleeperTypes = ref([
383+
'软卧', '硬卧', '动卧', '高级软卧', '一等卧', '二等卧'
384+
]);
385+
386+
// 铺位类型选项
387+
const berthOptions = ref([
388+
{ label: '上铺', value: '' },
389+
{ label: '中铺', value: '' },
390+
{ label: '下铺', value: '' }
391+
]);
392+
393+
// 监听座位类型变化,重置铺位信息
394+
watch(() => form.seatType, (newVal) => {
395+
if (!sleeperTypes.value.includes(newVal)) {
396+
form.berthType = '';
397+
form.berthNumber = '';
398+
}
399+
});
400+
401+
// 计算最终座位号(铺位号+铺位类型)
402+
const finalSeatNumber = computed(() => {
403+
if (sleeperTypes.value.includes(form.seatType) && form.berthNumber && form.berthType) {
404+
return `${form.berthNumber}${form.berthType}`;
405+
}
406+
return form.seatNumber;
328407
});
329408
330409
// 火车票组件ref

0 commit comments

Comments
 (0)