|
|
@@ -0,0 +1,433 @@
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <el-table
|
|
|
+ :data="tableData"
|
|
|
+ style="width: 100%"
|
|
|
+ size="mini"
|
|
|
+ border>
|
|
|
+ <el-table-column
|
|
|
+ prop="transportation"
|
|
|
+ align="center"
|
|
|
+ label="交通工具">
|
|
|
+ <template slot="header" slot-scope="scope">
|
|
|
+ <div><span class="required">*</span>交通工具</div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ prop="isRoundTrip"
|
|
|
+ align="center"
|
|
|
+ label="单程往返">
|
|
|
+ <template slot="header" slot-scope="scope">
|
|
|
+ <div><span class="required">*</span>单程往返</div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ prop="departureCity"
|
|
|
+ align="center"
|
|
|
+ label="出发城市">
|
|
|
+ <template slot="header" slot-scope="scope">
|
|
|
+ <div><span class="required">*</span>出发城市</div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ prop="destinationCity"
|
|
|
+ align="center"
|
|
|
+ label="目的城市">
|
|
|
+ <template slot="header" slot-scope="scope">
|
|
|
+ <div><span class="required">*</span>目的城市</div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ prop="startTime"
|
|
|
+ align="center"
|
|
|
+ label="开始时间">
|
|
|
+ <template slot="header" slot-scope="scope">
|
|
|
+ <div><span class="required">*</span>开始时间</div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ prop="endTime"
|
|
|
+ align="center"
|
|
|
+ label="结束时间">
|
|
|
+ <template slot="header" slot-scope="scope">
|
|
|
+ <div><span class="required">*</span>结束时间</div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ prop="duration"
|
|
|
+ align="center"
|
|
|
+ label="时长">
|
|
|
+ <template slot="header" slot-scope="scope">
|
|
|
+ <div><span class="required">*</span>时长</div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ label="操作"
|
|
|
+ align="center"
|
|
|
+ width="90"
|
|
|
+ v-if="!view">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-button @click="editRow(scope.row, scope.$index)" type="text" size="mini">编辑</el-button>
|
|
|
+ <el-button @click="deleteRow(scope.$index)" type="text" size="mini">删除</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <div v-if="!view" style="text-align: center;">
|
|
|
+ <el-button type="text" icon="el-icon-plus" @click="addRow">添加</el-button>
|
|
|
+ </div>
|
|
|
+ <ele-modal
|
|
|
+ title="明细"
|
|
|
+ custom-class="ele-dialog-form long-dialog-form"
|
|
|
+ :visible.sync="visible"
|
|
|
+ :before-close="handleClose"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ top="5vh"
|
|
|
+ :close-on-press-escape="false"
|
|
|
+ append-to-body
|
|
|
+ width="70%"
|
|
|
+ :maxable="true"
|
|
|
+ destroy-on-close
|
|
|
+ >
|
|
|
+ <el-card shadow="never">
|
|
|
+ <el-form ref="form" :model="form">
|
|
|
+ <el-form-item
|
|
|
+ label="交通工具"
|
|
|
+ label-width="110px"
|
|
|
+ prop="transportation"
|
|
|
+ :rules="{
|
|
|
+ required: true,
|
|
|
+ message: '请输入交通工具',
|
|
|
+ trigger: 'change'
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ v-model="form.transportation"
|
|
|
+ placeholder="请输入"
|
|
|
+ ></el-input>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item
|
|
|
+ label="单程往返"
|
|
|
+ label-width="110px"
|
|
|
+ prop="isRoundTrip"
|
|
|
+ :rules="{
|
|
|
+ required: true,
|
|
|
+ message: '请输入单程往返',
|
|
|
+ trigger: 'change'
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ v-model="form.isRoundTrip"
|
|
|
+ placeholder="请输入"
|
|
|
+ ></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item
|
|
|
+ label="出发城市"
|
|
|
+ label-width="110px"
|
|
|
+ prop="departureCity"
|
|
|
+ :rules="{
|
|
|
+ required: true,
|
|
|
+ message: '请输入出发城市',
|
|
|
+ trigger: 'change'
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ v-model="form.departureCity"
|
|
|
+ placeholder="请输入"
|
|
|
+ ></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item
|
|
|
+ label="目的城市"
|
|
|
+ label-width="110px"
|
|
|
+ prop="destinationCity"
|
|
|
+ :rules="{
|
|
|
+ required: true,
|
|
|
+ message: '请输入目的城市',
|
|
|
+ trigger: 'change'
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ v-model="form.destinationCity"
|
|
|
+ placeholder="请输入"
|
|
|
+ ></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item
|
|
|
+ label="开始时间"
|
|
|
+ label-width="110px"
|
|
|
+ prop="startTime"
|
|
|
+ :rules="{
|
|
|
+ required: true,
|
|
|
+ message: '请输入开始时间',
|
|
|
+ trigger: 'change'
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <el-date-picker
|
|
|
+ style="width: 100%"
|
|
|
+ v-model="form.startTime"
|
|
|
+ value-format="yyyy-MM-dd HH:mm:ss"
|
|
|
+ type="datetime"
|
|
|
+ placeholder="选择日期"
|
|
|
+ >
|
|
|
+ </el-date-picker>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item
|
|
|
+ label="结束时间"
|
|
|
+ label-width="110px"
|
|
|
+ prop="endTime"
|
|
|
+ :rules="{
|
|
|
+ required: true,
|
|
|
+ message: '请输入结束时间',
|
|
|
+ trigger: 'change'
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <el-date-picker
|
|
|
+ style="width: 100%"
|
|
|
+ v-model="form.endTime"
|
|
|
+ value-format="yyyy-MM-dd HH:mm:ss"
|
|
|
+ type="datetime"
|
|
|
+ placeholder="选择日期"
|
|
|
+ >
|
|
|
+ </el-date-picker>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item
|
|
|
+ label="时长"
|
|
|
+ label-width="110px"
|
|
|
+ prop="duration"
|
|
|
+ :rules="{
|
|
|
+ required: true,
|
|
|
+ message: '请选择开始/结束时间',
|
|
|
+ trigger: 'change'
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ v-model="form.duration"
|
|
|
+ placeholder="自动计算"
|
|
|
+ disabled
|
|
|
+ ></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <div slot="footer">
|
|
|
+ <el-button type="primary" size="small" @click="save">保存</el-button>
|
|
|
+ <el-button size="small" @click="handleClose">关闭</el-button>
|
|
|
+ </div>
|
|
|
+ </ele-modal>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+export default {
|
|
|
+ props: {
|
|
|
+ info: {
|
|
|
+ type: Object,
|
|
|
+ default: () => {}
|
|
|
+ },
|
|
|
+ generateForm: {
|
|
|
+ type: Object,
|
|
|
+ default: () => {}
|
|
|
+ },
|
|
|
+ id: {
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
+ },
|
|
|
+ view: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ info: {
|
|
|
+ handler(newVal, oldVal) {
|
|
|
+ console.log('info', newVal);
|
|
|
+ this.tableData = newVal[this.id] || [];
|
|
|
+ },
|
|
|
+ deep: true,
|
|
|
+ immediate: true
|
|
|
+ },
|
|
|
+ // 监听开始/结束时间自动计算时长
|
|
|
+ 'form.startTime': {
|
|
|
+ handler() {
|
|
|
+ this.calcDuration();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ 'form.endTime': {
|
|
|
+ handler() {
|
|
|
+ this.calcDuration();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ const formItem = {
|
|
|
+ productName: '',
|
|
|
+ quantity: '',
|
|
|
+ specification: ''
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ form: {},
|
|
|
+ formItem,
|
|
|
+ tableData: [],
|
|
|
+ visible: false,
|
|
|
+ currentItem: {},
|
|
|
+ currentIndex: null,
|
|
|
+ type: 'add'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ // console.log('info~~~', this.info);
|
|
|
+ // this.initForm();
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ async updateRowInfo() {
|
|
|
+ let data = await this.generateForm.getData(false);
|
|
|
+ this.generateForm.setData({
|
|
|
+ [this.id]: this.tableData
|
|
|
+ });
|
|
|
+ console.log('updateRowInfo', this.tableData, data);
|
|
|
+ },
|
|
|
+ validateForm() {
|
|
|
+ //开始表单校验
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ this.$refs.form.validate((valid) => {
|
|
|
+ if (!valid) {
|
|
|
+ reject(false);
|
|
|
+ } else {
|
|
|
+ resolve(true);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 根据开始/结束时间自动计算时长
|
|
|
+ calcDuration() {
|
|
|
+ if (this.form.startTime && this.form.endTime) {
|
|
|
+ const start = new Date(this.form.startTime).getTime();
|
|
|
+ const end = new Date(this.form.endTime).getTime();
|
|
|
+ if (isNaN(start) || isNaN(end) || end <= start) {
|
|
|
+ this.form.duration = '';
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const diff = Math.floor((end - start) / 1000); // 秒差
|
|
|
+ const days = Math.floor(diff / 86400);
|
|
|
+ const hours = Math.floor((diff % 86400) / 3600);
|
|
|
+ const minutes = Math.floor((diff % 3600) / 60);
|
|
|
+ const seconds = diff % 60;
|
|
|
+
|
|
|
+ const parts = [];
|
|
|
+ if (days > 0) parts.push(`${days}天`);
|
|
|
+ if (hours > 0) parts.push(`${hours}时`);
|
|
|
+ if (minutes > 0) parts.push(`${minutes}分`);
|
|
|
+ if (seconds > 0) parts.push(`${seconds}秒`);
|
|
|
+ this.form.duration = parts.join('');
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 将 "X天X时X分X秒" 解析为总秒数
|
|
|
+ parseDurationToSeconds(duration) {
|
|
|
+ if (!duration) return 0;
|
|
|
+ const match = {
|
|
|
+ days: duration.match(/(\d+)天/),
|
|
|
+ hours: duration.match(/(\d+)时/),
|
|
|
+ minutes: duration.match(/(\d+)分/),
|
|
|
+ seconds: duration.match(/(\d+)秒/)
|
|
|
+ };
|
|
|
+ return (
|
|
|
+ (parseInt(match.days?.[1]) || 0) * 86400 +
|
|
|
+ (parseInt(match.hours?.[1]) || 0) * 3600 +
|
|
|
+ (parseInt(match.minutes?.[1]) || 0) * 60 +
|
|
|
+ (parseInt(match.seconds?.[1]) || 0)
|
|
|
+ );
|
|
|
+ },
|
|
|
+ // 计算多行时长累加,赋值给 input_if1cav3p
|
|
|
+ async calculateTotalDays() {
|
|
|
+ let totalSeconds = 0;
|
|
|
+ this.tableData.forEach((item) => {
|
|
|
+ totalSeconds += this.parseDurationToSeconds(item.duration);
|
|
|
+ });
|
|
|
+ // 转换回 "X天X时X分X秒" 格式
|
|
|
+ const days = Math.floor(totalSeconds / 86400);
|
|
|
+ const hours = Math.floor((totalSeconds % 86400) / 3600);
|
|
|
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
|
+ const seconds = totalSeconds % 60;
|
|
|
+ const parts = [];
|
|
|
+ if (days > 0) parts.push(`${days}天`);
|
|
|
+ if (hours > 0) parts.push(`${hours}时`);
|
|
|
+ if (minutes > 0) parts.push(`${minutes}分`);
|
|
|
+ if (seconds > 0 || parts.length === 0) parts.push(`${seconds}秒`);
|
|
|
+ const totalDuration = parts.join('');
|
|
|
+
|
|
|
+ this.generateForm.setData({
|
|
|
+ input_if1cav3p: totalDuration
|
|
|
+ });
|
|
|
+ },
|
|
|
+ addRow() {
|
|
|
+ this.type = 'add';
|
|
|
+ this.form = JSON.parse(JSON.stringify(this.formItem));
|
|
|
+ this.visible = true;
|
|
|
+
|
|
|
+ },
|
|
|
+ handleClose() {
|
|
|
+ this.visible = false;
|
|
|
+ },
|
|
|
+ editRow(row, index) {
|
|
|
+ this.type = 'edit';
|
|
|
+ console.log('编辑行', row, index);
|
|
|
+ this.currentItem = row;
|
|
|
+ this.currentIndex = index;
|
|
|
+ this.visible = true;
|
|
|
+ this.form = JSON.parse(JSON.stringify(row));
|
|
|
+ },
|
|
|
+ deleteRow(index) {
|
|
|
+ this.tableData.splice(index, 1);
|
|
|
+ this.updateRowInfo();
|
|
|
+ this.calculateTotalDays();
|
|
|
+ },
|
|
|
+ async save() {
|
|
|
+ try {
|
|
|
+ await this.validateForm();
|
|
|
+ console.log('表单验证通过');
|
|
|
+ // 深拷贝form对象,避免引用问题
|
|
|
+ const newForm = JSON.parse(JSON.stringify(this.form));
|
|
|
+ console.log('newForm', newForm);
|
|
|
+ if(this.type === 'add') {
|
|
|
+ this.tableData.push(newForm);
|
|
|
+ } else {
|
|
|
+ this.tableData[this.currentIndex] = newForm;
|
|
|
+ }
|
|
|
+ console.log('this.tableData', this.tableData);
|
|
|
+ this.updateRowInfo()
|
|
|
+ this.calculateTotalDays();
|
|
|
+ this.handleClose(); // 保存后关闭弹窗
|
|
|
+ // 重置form
|
|
|
+ // this.form = {};
|
|
|
+ } catch (error) {
|
|
|
+ console.log('表单验证失败', error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+<style scoped>
|
|
|
+.header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+.blank_business_component {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+.label {
|
|
|
+ width: 80px;
|
|
|
+}
|
|
|
+.value {
|
|
|
+ flex: 1;
|
|
|
+ width: calc(100% - 80px);
|
|
|
+}
|
|
|
+:deep(.el-form-box .el-table .el-table__row .el-table__cell .cell) {
|
|
|
+ padding-left: 10px;
|
|
|
+ padding-right: 10px;
|
|
|
+}
|
|
|
+.required {
|
|
|
+ color: red;
|
|
|
+}
|
|
|
+</style>
|