| | |
| | | </el-tooltip> |
| | | <el-tooltip content="查看行程" placement="top"> |
| | | <el-link size="small" type="primary" v-if="![0, 1].includes(row.status)" @click="handleLogItinerary(row)" |
| | | v-hasPermi="['tms:tmsTrip:list']" class="link-btn" underline="never" icon="el-icon-view"> |
| | | v-hasPermi="['tms:tmsTrip:list']" class="link-btn" underline="never" icon="Finished"> |
| | | |
| | | </el-link> |
| | | </el-tooltip> |
| | |
| | | |
| | | </el-link> |
| | | </el-tooltip> |
| | | |
| | | <!-- |
| | | <el-tooltip content="完成行程" placement="top"> |
| | | <el-link size="small" type="primary" v-if="[2].includes(row.status)" @click="handleOk(row)" class="link-btn" |
| | | v-hasPermi="['tms:tmsDispatchOrder:okOrder']" underline="never" icon="el-icon-circle-check"> |
| | | |
| | | </el-link> |
| | | </el-tooltip> |
| | | </el-tooltip> --> |
| | | |
| | | <el-tooltip content="日志" placement="top"> |
| | | <el-link size="small" type="primary" @click="handleFlow(row)" class="link-btn" |
| | |
| | | min="0"></el-input-number> |
| | | </template> |
| | | </avue-crud> |
| | | <h2 v-if="optionType == 'addFinance'">实报实销费用1</h2> |
| | | <h2 v-if="optionType == 'addFinance'">实报实销费用</h2> |
| | | <avue-form v-if="optionType == 'addItinerary' || optionType == 'addFinance'" v-model="boxForm" ref="boxFormRef" |
| | | :option="boxFormOption"> |
| | | |
| | |
| | | </avue-crud> |
| | | |
| | | <div v-if="active === 'tab4'"> |
| | | <h2>实报实销费用</h2> |
| | | <h2>实报实销费用3</h2> |
| | | <!-- <avue-form v-model="boxForm" ref="boxFormRef" :option="boxFormOption"> |
| | | |
| | | </avue-form> --> |
| | |
| | | <el-input-number v-model="row.actualFeeAmount" :precision="2" :min="0" controls-position="right" |
| | | placeholder="输入金额" style="width: 100%" /> |
| | | </template> |
| | | |
| | | <template #currency="{ row }"> |
| | | <el-radio-group v-model="row.currency"> |
| | | <el-radio v-for="item in sys_currency" :key="item.value" :label="item.value"> |
| | |
| | | </el-radio-group> |
| | | </template> |
| | | <template #voucherUrl="{ row }"> |
| | | <avue-upload v-model="row.voucherUrl" :action="'/common/upload2'" type="upload" accept="image/*" |
| | | @upload-after="(res, done, loading, column) => handleUploadAfter(res, done, loading, column, row)"></avue-upload> |
| | | <!-- <avue-upload v-model="row.voucherUrl" :action="'/common/upload2'" type="upload" accept="image/*" |
| | | @upload-after="(res, done, loading, column) => handleUploadAfter(res, done, loading, column, row)"></avue-upload> --> |
| | | |
| | | <!-- 凭证图片 --> |
| | | <el-upload class="upload-demo" ref="uploadRef" :limit="1" drag :action="urlApi + '/common/upload2'" multiple |
| | | :show-file-list="true" :on-success="(res) => handleUploadAfter(res, row)" |
| | | :on-exceed="(files) => handleExceed(files, row)"> |
| | | <el-icon class="el-icon--upload"><upload-filled /></el-icon> |
| | | <div class="el-upload__text"> |
| | | 点击或将图片拖拽到此区域上传 |
| | | </div> |
| | | |
| | | </el-upload> |
| | | </template> |
| | | <template #remark="{ row }"> |
| | | <el-input v-model="row.remark" placeholder="填写备注" clearable /> |
| | |
| | | <div class="dialog-footer"> |
| | | <el-button @click="print = 0" v-if="print == 1">重新填写</el-button> |
| | | <el-button type="primary" :loading="pageF.isUploading" @click="submitForm6"> |
| | | {{ pageF.isUploading ? '提交中' : '确 定2' }} |
| | | {{ pageF.isUploading ? '提交中' : '确 定' }} |
| | | </el-button> |
| | | |
| | | <el-button @click="open6 = false">取 消</el-button> |
| | |
| | | printDispatchOrder, |
| | | importTemplateTmsDispatchOrder, ypdddjSumbit, |
| | | tmsTmsDispatchOrderImportLog, |
| | | saveTmsFinanceDetail2 |
| | | saveTmsFinanceDetail2, |
| | | getLastLicensePlate |
| | | } from "@/api/tms/tmsDispatchOrder"; |
| | | import useCurrentInstance from "@/utils/useCurrentInstance"; |
| | | import { computed, onMounted, reactive, ref, toRefs, watch, getCurrentInstance, nextTick } from "vue"; |
| | | import { computed, onMounted, onBeforeUnmount, reactive, ref, toRefs, watch, getCurrentInstance, nextTick } from "vue"; |
| | | import { PagesInterface, PageQueryInterface } from "@/utils/globalInterface"; |
| | | import { usePagePlus } from "@/hooks/usePagePlus"; |
| | | import { hasPermission } from "@/utils/permissionUtils"; |
| | |
| | | labelWidth: 130, |
| | | searchSpan: 6, |
| | | searchLabelWidth: 150, |
| | | menuWidth: 300, |
| | | menuWidth: 350, |
| | | height: 530, |
| | | group: [ |
| | | { |
| | |
| | | } |
| | | ], |
| | | change: ({ value }: any) => { |
| | | console.log(value) |
| | | option.value.group.forEach((item: any) => { |
| | | if (item.prop == 'pcxx') { |
| | | item.column.commissionModel.display = value != 1; |
| | |
| | | } |
| | | ], |
| | | change: (val: any) => { |
| | | // 防止重复执行 |
| | | if (data.isChanging) return; |
| | | data.isChanging = true; |
| | | |
| | | const table = crudRef.value?.getPropRef?.('mainDriverId')?.$refs?.temp; |
| | | if (!table) return; |
| | | if (!table) { |
| | | data.isChanging = false; |
| | | return; |
| | | } |
| | | |
| | | let active = table.active; |
| | | if (Array.isArray(active)) active = active[0]; |
| | | |
| | | if (active) { |
| | | Object.assign(form.value, { |
| | | mainDriverId: active.id, |
| | | mainDriverName: active.driverName, |
| | | }); |
| | | |
| | | // 获取车牌号并赋值 |
| | | getLastLicensePlate(active.driverName).then(res => { |
| | | if (res.code == 200) { |
| | | form.value.licensePlate = res.data.licensePlate; |
| | | form.value.vehicleId = res.data.vehicleId |
| | | } |
| | | }).finally(() => { |
| | | data.isChanging = false; |
| | | }); |
| | | } else { |
| | | data.isChanging = false; |
| | | } |
| | | }, |
| | | // change: (val: any) => { |
| | | // const table = crudRef.value?.getPropRef?.('mainDriverId')?.$refs?.temp; |
| | | // if (!table) return; |
| | | // let active = table.active; |
| | | // if (Array.isArray(active)) active = active[0]; |
| | | // console.log(active,'888'); |
| | | |
| | | // if (active) { |
| | | // Object.assign(form.value, { |
| | | // mainDriverId: active.id, |
| | | // mainDriverName: active.driverName, |
| | | // }); |
| | | // console.log(active.driverName,'44'); |
| | | // getLastLicensePlate(active.driverName).then(res => { |
| | | // console.log(res); |
| | | |
| | | // }) |
| | | // } |
| | | // }, |
| | | type: 'table', suffixIcon: 'search', |
| | | children: { |
| | | border: true, |
| | | searchMenuSpan: 5, |
| | | column: { |
| | | vehicleProviderName: { |
| | | label: '车辆服务商', minWidth: 130, |
| | | label: '车辆服务商1', minWidth: 130, |
| | | search: true, |
| | | }, |
| | | driverName: { |
| | |
| | | |
| | | }, |
| | | vehicleId: { |
| | | label: '车牌号', dataType: 'string', |
| | | label: '车牌号1', dataType: 'string', |
| | | display: true, |
| | | rules: [ |
| | | { |
| | |
| | | }, |
| | | } |
| | | }) |
| | | |
| | | const urlApi = ref(import.meta.env.VITE_APP_BASE_API) |
| | | const itineraryTableOption = ref({ |
| | | menu: false, |
| | | addBtn: false, |
| | |
| | | ], |
| | | }, |
| | | currency: { |
| | | label: '币种', |
| | | label: '币制', |
| | | display: true, |
| | | type: 'radio', dataType: 'string', dicUrl: '/system/dict/data/type/sys_currency', |
| | | rules: [ |
| | | { |
| | | required: true, |
| | | message: "币种不能为空", trigger: "change" |
| | | message: "币制不能为空", trigger: "change" |
| | | } |
| | | ], |
| | | |
| | | }, |
| | | voucherUrl: { |
| | | label: '费用凭证', |
| | | label: '费用凭证1', |
| | | display: true, |
| | | accept: 'string', dataType: 'string', |
| | | type: 'upload', |
| | |
| | | display: true, |
| | | }, |
| | | currency: { |
| | | label: '币种', |
| | | label: '币制', |
| | | display: true, |
| | | type: 'radio', dataType: 'string', dicUrl: '/system/dict/data/type/sys_currency', |
| | | }, |
| | |
| | | getBeginListFunc: (params = {}) => { |
| | | // 1. 日期转换 |
| | | let newParams = <any>{ ...params }; |
| | | console.log(newParams, '2'); |
| | | if (newParams) { |
| | | // 1. 定义日期字段映射 (数组名 : 接口需要的前缀) |
| | | // 这样写的好处是:如果你有多个日期,直接在这里添加一行即可 |
| | | const dateMap = { |
| | | confirmTimeRangeArray: 'confirmTimeRange', |
| | | createTimeRangeArray: 'createTime', |
| | | updateTimeRangeArray: 'updateTimeRange', |
| | | okTimeRangeArray: 'okTime', |
| | | orderTimeRangeArray: 'orderTime' |
| | | }; |
| | | if (newParams) { |
| | | // 1. 定义日期字段映射 (数组名 : 接口需要的前缀) |
| | | // 这样写的好处是:如果你有多个日期,直接在这里添加一行即可 |
| | | const dateMap = { |
| | | confirmTimeRangeArray: 'confirmTimeRange', |
| | | createTimeRangeArray: 'createTime', |
| | | updateTimeRangeArray: 'updateTimeRange', |
| | | okTimeRangeArray: 'okTime', |
| | | orderTimeRangeArray: 'orderTime' |
| | | }; |
| | | |
| | | // 2. 遍历处理日期 |
| | | Object.keys(dateMap).forEach(arrayKey => { |
| | | const prefix = dateMap[arrayKey]; |
| | | const range = newParams[arrayKey]; |
| | | // 2. 遍历处理日期 |
| | | Object.keys(dateMap).forEach(arrayKey => { |
| | | const prefix = dateMap[arrayKey]; |
| | | const range = newParams[arrayKey]; |
| | | |
| | | if (Array.isArray(range) && range.length > 0) { |
| | | // 赋值 Begin 和 End |
| | | newParams[`${prefix}Begin`] = range[0]; |
| | | newParams[`${prefix}End`] = range[1]; |
| | | if (Array.isArray(range) && range.length > 0) { |
| | | // 赋值 Begin 和 End |
| | | newParams[`${prefix}Begin`] = range[0]; |
| | | newParams[`${prefix}End`] = range[1]; |
| | | } |
| | | |
| | | // 【核心改动】:无论是否有值,处理完后都把原始的 Array 字段删掉 |
| | | // 这样请求里就不会出现 confirmTimeRangeArray: [...] |
| | | delete newParams[arrayKey]; |
| | | }); |
| | | |
| | | // 3. 通用清洗:删除所有空字符串、null 或 undefined 的其他字段 |
| | | Object.keys(newParams).forEach(key => { |
| | | const val = newParams[key]; |
| | | if (val === '' || val === null || val === undefined) { |
| | | delete newParams[key]; |
| | | } |
| | | }); |
| | | |
| | | } else { |
| | | newParams = {}; |
| | | } |
| | | |
| | | // 【核心改动】:无论是否有值,处理完后都把原始的 Array 字段删掉 |
| | | // 这样请求里就不会出现 confirmTimeRangeArray: [...] |
| | | delete newParams[arrayKey]; |
| | | }); |
| | | |
| | | // 3. 通用清洗:删除所有空字符串、null 或 undefined 的其他字段 |
| | | Object.keys(newParams).forEach(key => { |
| | | const val = newParams[key]; |
| | | if (val === '' || val === null || val === undefined) { |
| | | delete newParams[key]; |
| | | } |
| | | }); |
| | | |
| | | } else { |
| | | newParams = {}; |
| | | } |
| | | |
| | | console.log('最终发送给接口的参数:', newParams); |
| | | return newParams; |
| | | return newParams; |
| | | // newParams = proxy.addDateRangeNew(queryParams.value, queryParams.value?.createTimeRangeArray, 'createTime'); |
| | | // newParams = proxy.addDateRangeNew(queryParams.value, queryParams.value?.updateTimeRangeArray, 'updateTime'); |
| | | // newParams = proxy.addDateRangeNew(queryParams.value, queryParams.value?.confirmTimeRangeArray, 'confirmTime'); |
| | |
| | | const handleUploadItinerary = (row: any) => { |
| | | optionType.value = 'addItinerary'; |
| | | boxFormOption.value = itineraryOption.value; |
| | | console.log(itineraryOption.value); |
| | | |
| | | boxTableOption.value = itineraryTableOption.value; |
| | | listTmsTrip({ dispatchOrderId: row.id, pageNum: 1, pageSize: 999 }).then(res => { |
| | |
| | | vehicleNumber: row.licensePlate, |
| | | vehicleId: row.vehicleId, |
| | | } |
| | | console.log(boxForm.value); |
| | | |
| | | }) |
| | | } |
| | |
| | | form2.value.districtId = districtCode; |
| | | form2.value.streetId = townshipCode; |
| | | form2.value.dispatchTransportArea = params.regeocode.formatted_address || params.regeocode.formattedAddress; |
| | | console.log(form2.value, "form2") |
| | | } |
| | | }); |
| | | } |
| | |
| | | getQuotationItems(); |
| | | |
| | | const getTabData = (val: string) => { |
| | | console.log(val) |
| | | let filter = quotationItems.value.filter((item: any) => { |
| | | return item.remark == val; |
| | | }); |
| | |
| | | dispatchOrderId: form.value.id, financeType: 2, |
| | | pageNum: 1, pageSize: 999 |
| | | }).then(async res => { |
| | | |
| | | boxTableData.value = res.rows || []; |
| | | |
| | | boxForm.value = { |
| | | dispatchOrderId: form.value.id, |
| | | dataSource: 0, |
| | |
| | | |
| | | // 3. 处理凭证 URL (如果有单张或多张上传的逻辑) |
| | | // 假设后端需要的是逗号分隔的字符串 |
| | | const submitData = validDetails.map(item => { |
| | | const submitData = validDetails.map((item: any) => { |
| | | let url = item.voucherUrl; |
| | | item.dispatchOrderId = form.value.id; |
| | | item.financeType = 2; |
| | | item.status = 0; |
| | | item.dataSource = 1; |
| | | if (Array.isArray(url)) { |
| | | url = url.join(','); |
| | | } |
| | |
| | | }, |
| | | { |
| | | |
| | | label: '费用凭证', |
| | | label: '费用凭证2', |
| | | display: true, |
| | | span: 24, |
| | | accept: 'string', dataType: 'object', |
| | | type: 'upload', |
| | | // action: '/common/upload2', |
| | | |
| | | prop: 'voucherUrl', // 这里改成 prop 属性 |
| | | slot: true, // 开启插槽 |
| | | width: 200 |
| | |
| | | }); |
| | | // 3. 回显初始化 |
| | | const initExpenditureData = () => { |
| | | tmsFinanceDetails.value = [] |
| | | if (fee_type.value && fee_type.value.length > 0 && tmsFinanceDetails.value.length === 0) { |
| | | tmsFinanceDetails.value = fee_type.value.map(item => ({ |
| | | feeType: item.value, |
| | |
| | | initExpenditureData(); |
| | | } |
| | | }); |
| | | const handleUploadAfter = (res, done, loading, column, row) => { |
| | | const handleUploadAfter = (res: any, row: any) => { |
| | | // res 是接口返回的完整数据 |
| | | if (res && res.url) { |
| | | if (res.code === 200) { |
| | | // 手动给这一行的数据赋值 |
| | | row.voucherUrl = res.url; |
| | | console.log('上传成功,当前行数据:', row); |
| | | row.voucherUrl = res.data.url; |
| | | } else if (res.data && res.data.url) { |
| | | // 如果返回的数据包裹在 data 里 |
| | | row.voucherUrl = res.data.url; |
| | | } |
| | | done(); // 必须调用 done 结束上传状态 |
| | | }; |
| | | |
| | | /** 当文件超出限制时(实现自动替换逻辑) */ |
| | | const handleExceed = (files: any, row: any) => { |
| | | // 1. 清除当前显示的文件列表 |
| | | uploadRef.value.clearFiles(); |
| | | // 2. 手动把新选择的文件添加进去重新上传 |
| | | const file = files[0]; |
| | | uploadRef.value.handleStart(file); |
| | | uploadRef.value.submit(); |
| | | }; |
| | | |
| | | const flowLogIshow = ref() |
| | | const flowParams = ref([]) |
| | |
| | | .link-btn { |
| | | font-size: 18px; |
| | | } |
| | | |
| | | /* */ |
| | | /* 现有的样式保持不变... */ |
| | | .specific-drag-area { |
| | | width: 100%; |
| | | |
| | | :deep(.full-width-drag) { |
| | | |
| | | // 1. 核心:隐藏 Avue 默认在 dragger 下方生成的那个“点击上传”按钮 |
| | | // 在 3.x 版本中,它是 el-upload 后的一个兄弟节点或者是内部节点 |
| | | .el-button--primary { |
| | | display: none !important; |
| | | } |
| | | |
| | | .el-upload { |
| | | width: 100%; |
| | | display: block; // 确保块级显示 |
| | | |
| | | .el-upload-dragger { |
| | | width: 100%; |
| | | height: 120px; |
| | | background-color: #fcfdfe; |
| | | border: 2px dashed #dcdfe6; |
| | | border-radius: 8px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 0 !important; |
| | | |
| | | // 覆盖 Element Plus 默认的内部文字排版,防止冲突 |
| | | .el-upload__text { |
| | | display: none !important; |
| | | } |
| | | |
| | | &:hover { |
| | | border-color: #409eff; |
| | | background-color: #f5f7fa; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 3. 自定义内容的样式(确保它不被 display:none 影响) |
| | | .drag-zone-inner { |
| | | pointer-events: none; |
| | | text-align: center; |
| | | |
| | | .upload-icon { |
| | | font-size: 32px !important; |
| | | color: #909399; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .drag-text { |
| | | .main-title { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | font-weight: bold; |
| | | line-height: 1.5; |
| | | } |
| | | |
| | | .sub-title { |
| | | font-size: 12px; |
| | | color: #a8abb2; |
| | | margin-top: 4px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |