| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894 |
- <script setup>
- import { onLoad } from "@dcloudio/uni-app";
- import { useDataDictStore } from "@/store/modules/dataDict";
- import {
- onMounted,
- reactive,
- ref,
- computed,
- getCurrentInstance,
- watch,
- } from "vue";
- import { useDebounceFn } from "@/utils/useDebounceFn.js";
- import tpfTimeRange from "@/components/tpf-time-range/tpf-time-range.vue";
- import deviceTransfer from "@/components/device-transfer/index.vue";
- import { getRuiDuReportAttrs, updateRuiDuReportBatch } from "@/api/ruiDu.js";
- import config from "@/utils/config";
- import dayjs from "dayjs";
- import { getTenantId, getAccessToken } from "@/utils/auth.js";
- const istime = ref("false");
- onLoad(options => {
- istime.value = options.istime;
- });
- const NON_PROD_FIELDS = [
- { key: "repairTime", label: "设备故障" },
- { key: "selfStopTime", label: "设备保养" },
- { key: "accidentTime", label: "工程质量" },
- { key: "complexityTime", label: "技术受限" },
- { key: "rectificationTime", label: "生产组织" },
- { key: "waitingStopTime", label: "不可抗力" },
- { key: "partyaDesign", label: "甲方设计" },
- { key: "partyaPrepare", label: "甲方准备" },
- { key: "partyaResource", label: "甲方资源" },
- { key: "relocationTime", label: "生产配合" },
- { key: "winterBreakTime", label: "待命" },
- { key: "otherNptTime", label: "其他非生产时间" },
- ];
- const { appContext } = getCurrentInstance();
- const t = appContext.config.globalProperties.$t;
- const { getIntDictOptions, getStrDictOptions, loadDataDictList } =
- useDataDictStore();
- const rdStatusRange = ref([]);
- const techniqueRange = ref([]);
- const handleInitSelect = () => {
- rdStatusRange.value = getStrDictOptions("rdStatus").map(item => {
- return {
- ...item,
- text: item.label,
- };
- });
- // 施工工艺
- techniqueRange.value = getIntDictOptions("rq_iot_project_technology_rd").map(
- item => {
- return {
- ...item,
- text: item.label,
- };
- }
- );
- };
- onMounted(() => {
- loadDataDictList().then(() => {
- handleInitSelect();
- });
- });
- const selectPlaceholder = computed(() => {
- return props.formDisable ? " " : t("operation.PleaseSelect");
- });
- const inputPlaceholder = computed(() => {
- return props.formDisable ? " " : t("operation.PleaseInput");
- });
- const props = defineProps({
- reportId: {
- type: String,
- default: "",
- },
- reportData: {
- type: Object,
- default: () => {},
- },
- formDisable: {
- type: Boolean,
- default: false, // 是否禁用表单
- },
- type: {
- type: String,
- default: "edit",
- },
- });
- const isRequired = computed(() => {
- return props.formDisable ? false : true;
- });
- const reportFormRef = ref(null);
- // 设备选择器
- const deviceTransferRef = ref(null);
- // 已选择的设备(名称)
- const selectedEquipmentNames = ref("");
- // 未选择的设备(名称)
- const unselectedEquipmentNames = ref("");
- const timeRangeRef = ref(null);
- const startTime = ref("00:00");
- const startDefaultTime = ref("08:00");
- const endTime = ref("24:00");
- const endDefaultTime = ref("08:00");
- const timeRange = data => {
- form.startTime = data[0];
- form.endTime = data[1];
- };
- const dailyFuel = ref(0);
- const form = reactive({
- startTime: startDefaultTime.value,
- endTime: endDefaultTime.value,
- platformIds: [],
- deviceIds: [],
- productionStatus: "",
- nextPlan: "",
- externalRental: "",
- faultDowntime: "",
- malfunction: "",
- attachments: [],
- reportFuels: [],
- reportDetails: [],
- });
- const formDataBaseRules = reactive({
- // 时间节点 - 开始时间
- startTime: {
- rules: [
- {
- required: true,
- errorMessage: `${t("operation.PleaseSelect")}${t("ruiDu.timeNode")}`,
- },
- ],
- },
- // 时间节点 - 结束时间
- endTime: {
- rules: [
- {
- required: true,
- errorMessage: `${t("operation.PleaseSelect")}${t("ruiDu.timeNode")}`,
- },
- ],
- },
- // 当日生产动态
- // productionStatus: {
- // rules: [
- // {
- // required: true,
- // errorMessage: `${t("operation.PleaseFillIn")}${t(
- // "ruiDu.dailyProductionDynamic"
- // )}`,
- // },
- // ],
- // },
- nextPlan: {
- rules: [
- {
- required: true,
- errorMessage: `请输入下步工作计划`,
- },
- ],
- },
- });
- function debounce(func, delay) {
- let timer;
- return function (...args) {
- if (timer) clearTimeout(timer);
- timer = setTimeout(() => func.apply(this, args), delay);
- };
- }
- const handleInputRaw = (val, id, field) => {
- let num = Number(val);
- if (val === "" || isNaN(num) || num < 0) {
- num = 0;
- } else if (num > 24) {
- num = 24;
- }
- form[id][field] = num;
- };
- const onInputChange = debounce(handleInputRaw, 500);
- const validate = async () => {
- if (istime.value === "true") {
- return await reportFormRef.value.validateField([
- "constructionBrief",
- ...form.platformIds.flatMap(pid => [
- ...NON_PROD_FIELDS.map(item => `${pid}.${item.key}`),
- `${pid}.otherNptReason`,
- ]),
- ]);
- } else return await reportFormRef.value.validate();
- };
- const submitForm = async () => {
- const deleteId = wellOptions.value.filter(
- o => !form.platformIds.includes(o.value)
- );
- deleteId.forEach(o => {
- delete form[o.value];
- });
- await validate();
- let error = false;
- form.platformIds.forEach(id => {
- const pair = form[id];
- // 计算所有时间字段的总和
- const totalTime =
- (pair.repairTime || 0) +
- (pair.selfStopTime || 0) +
- (pair.accidentTime || 0) +
- (pair.complexityTime || 0) +
- (pair.rectificationTime || 0) +
- (pair.waitingStopTime || 0) +
- (pair.partyaDesign || 0) +
- (pair.partyaPrepare || 0) +
- (pair.partyaResource || 0) +
- (pair.relocationTime || 0) +
- (pair.winterBreakTime || 0) +
- (pair.otherNptTime || 0);
- const wellName =
- wellOptions.value.find(item => item.value === id)?.text ??
- props.reportData.wellName ??
- "";
- // 检查总和是否超过24小时
- if (totalTime > 24) {
- error = true;
- uni.showToast({
- title: `${wellName || "平台井"}的时间总和不能超过24小时`,
- icon: "none",
- });
- return;
- }
- // 检查otherNptTime>0时是否填写了otherNptReason
- if ((pair.otherNptTime || 0) > 0 && !pair.otherNptReason) {
- error = true;
- uni.showToast({
- title: `${wellName || "平台井"}的其他时间大于0时必须填写原因`,
- icon: "none",
- });
- return;
- }
- });
- if (error) {
- return;
- }
- // // 处理表单数据
- const formDataCopy = JSON.parse(JSON.stringify(form));
- if (!formDataCopy.dailyFuel && formDataCopy.dailyFuel !== 0) {
- uni.showToast({
- title: "请输入当日油耗",
- icon: "none",
- });
- return;
- }
- const responseData = [];
- // // 处理施工工艺
- form.platformIds.forEach(id => {
- formDataCopy[id].extProperty.forEach(attr => {
- if (attr.dataType === "double") {
- attr.actualValue = Number(attr.actualValue);
- }
- });
- const attachments = JSON.parse(
- JSON.stringify(formDataCopy.attachments)
- ).map(item => {
- item.bizId = id;
- return item;
- });
- let platformWell = props.reportData.platformWell;
- if (platformWell === 1) {
- platformWell = id === props.reportData.id ? 1 : 2;
- }
- const data = {
- id,
- timeRange: ["1970-01-01T00:00:00.008Z", "1970-01-01T00:00:00.008Z"],
- projectDepartment: "",
- costCenter: "",
- dynamicFields: {},
- platformWell,
- companyId: props.reportData.companyId,
- deptId: props.reportData.deptId,
- attachments,
- deviceIds: formDataCopy.deviceIds,
- startTime: formDataCopy.startTime,
- endTime: formDataCopy.endTime,
- extProperty: formDataCopy[id].extProperty,
- externalRental: formDataCopy.externalRental,
- faultDowntime: formDataCopy.faultDowntime,
- malfunction: formDataCopy.malfunction,
- nextPlan: formDataCopy.nextPlan,
- ...(props.reportData.platformWell === 1
- ? {
- platformId: props.reportData.platforms.find(v => v.reportId === id)
- .id,
- }
- : {}),
- productionStatus: formDataCopy.productionStatus,
- rdStatus: formDataCopy[id].rdStatus,
- techniqueIds: formDataCopy[id].techniqueIds.map(v => v.toString()),
- reportFuels: formDataCopy.reportFuels.map(item => ({
- ...item,
- customFuel: Number(item.customFuel),
- reportId: id,
- })),
- dailyFuel: Number(formDataCopy.dailyFuel),
- reportDetails: formDataCopy.reportDetails,
- constructionBrief: formDataCopy.constructionBrief || "",
- repairTime: formDataCopy[id].repairTime || 0,
- selfStopTime: formDataCopy[id].selfStopTime || 0,
- accidentTime: formDataCopy[id].accidentTime || 0,
- complexityTime: formDataCopy[id].complexityTime || 0,
- rectificationTime: formDataCopy[id].rectificationTime || 0,
- waitingStopTime: formDataCopy[id].waitingStopTime || 0,
- partyaDesign: formDataCopy[id].partyaDesign || 0,
- partyaPrepare: formDataCopy[id].partyaPrepare || 0,
- partyaResource: formDataCopy[id].partyaResource || 0,
- relocationTime: formDataCopy[id].relocationTime || 0,
- winterBreakTime: formDataCopy[id].winterBreakTime || 0,
- otherNptTime: formDataCopy[id].otherNptTime || 0,
- otherNptReason: formDataCopy[id].otherNptReason || "",
- nonProduct: props.reportData.auditStatus === 20 ? "Y" : "",
- };
- responseData.push(data);
- });
- // 提交表单
- updateRuiDuReportBatch(responseData).then(res => {
- // 提交成功
- if (res.code === 0) {
- uni.showToast({ title: t("operation.success"), icon: "none" });
- // 返回上一页
- uni.navigateBack();
- } else {
- uni.showToast({ title: res.msg, icon: "none" });
- }
- });
- };
- const handleClickSelectDevice = () => {
- deviceTransferRef.value.open();
- };
- const handleEquipmentNames = deviceIds => {
- form.deviceIds = deviceIds || []; //施工设备
- const { selectedDevices = [] } = props.reportData || {};
- const deviceIdSet = new Set(deviceIds);
- // 已选择的设备(名称)
- selectedEquipmentNames.value = selectedDevices
- .filter(item => deviceIdSet.has(item.id))
- .map(item => item.deviceName)
- .join(",");
- // 未选择的设备(名称)
- unselectedEquipmentNames.value =
- selectedDevices
- .filter(item => !deviceIdSet.has(item.id))
- .map(item => item.deviceName)
- .join(",") || t("ruiDu.allEquipmentConstructed");
- };
- // 设备选择器回调
- const handleTransferChange = selectedIds => {
- // 更新已选择的设备及名称
- handleEquipmentNames(selectedIds);
- };
- const steps = ref([]);
- const formatT = arr =>
- `${arr[0].toString().padStart(2, "0")}:${arr[1].toString().padStart(2, "0")}`;
- const addReportDetailRow = () => {
- if (!form.reportDetails) {
- form.reportDetails = [];
- }
- form.reportDetails.push({
- startTime: "08:00",
- endTime: "08:00",
- duration: 0,
- constructionDetail: "",
- });
- };
- const removeReportDetailRow = index => {
- if (index === 0) {
- uni.showToast({ title: "至少填写一条生产动态", icon: "none" });
- return;
- }
- form.reportDetails?.splice(index, 1);
- };
- const formDataFormat = () => {
- // 处理时间范围
- timeRangeFormat();
- // 处理已选择的设备
- if (props.reportData?.deviceIds) {
- const { deviceIds = [] } = props.reportData || {};
- handleEquipmentNames(deviceIds);
- }
- if (props.reportData.platformWell === 1) {
- form.platformIds = props.reportData.platforms?.map(v => v.reportId) ?? [];
- } else {
- form.platformIds = [props.reportData.id];
- }
- // if (props.formDisable) {
- // } else {
- // form.platformIds = [props.reportData.id];
- // }
- if (props.reportData.platformWell === 1) {
- props.reportData.platforms.forEach(p => {
- form[p.reportId] = {
- rdStatus: p.rdStatus,
- techniqueIds: p.techniqueIds,
- extProperty: p.extProperty,
- repairTime: p.repairTime || 0,
- selfStopTime: p.selfStopTime || 0,
- accidentTime: p.accidentTime || 0,
- complexityTime: p.complexityTime || 0,
- rectificationTime: p.rectificationTime || 0,
- waitingStopTime: p.waitingStopTime || 0,
- partyaDesign: p.partyaDesign || 0,
- partyaPrepare: p.partyaPrepare || 0,
- partyaResource: p.partyaResource || 0,
- relocationTime: p.relocationTime || 0,
- winterBreakTime: p.winterBreakTime || 0,
- otherNptTime: p.otherNptTime || 0,
- otherNptReason: p.otherNptReason || "",
- };
- });
- } else {
- form[props.reportData.id] = {
- rdStatus: props.reportData.rdStatus,
- techniqueIds: props.reportData.techniqueIds,
- extProperty: props.reportData.extProperty,
- repairTime: props.reportData.repairTime || 0,
- selfStopTime: props.reportData.selfStopTime || 0,
- accidentTime: props.reportData.accidentTime || 0,
- complexityTime: props.reportData.complexityTime || 0,
- rectificationTime: props.reportData.rectificationTime || 0,
- waitingStopTime: props.reportData.waitingStopTime || 0,
- partyaDesign: props.reportData.partyaDesign || 0,
- partyaPrepare: props.reportData.partyaPrepare || 0,
- partyaResource: props.reportData.partyaResource || 0,
- relocationTime: props.reportData.relocationTime || 0,
- winterBreakTime: props.reportData.winterBreakTime || 0,
- otherNptTime: props.reportData.otherNptTime || 0,
- otherNptReason: props.reportData.otherNptReason || "",
- };
- }
- form.constructionBrief = props.reportData.constructionBrief || ""; // 施工简介
- form.reportDetails = (props.reportData.reportDetails || []).map(item => ({
- duration: item.duration || 0,
- constructionDetail: item.constructionDetail || "",
- startTime: formatT(item.startTime),
- endTime: formatT(item.endTime),
- }));
- if (!form.reportDetails.length) {
- addReportDetailRow();
- }
- // 当日生产动态
- form.productionStatus = props.reportData.productionStatus || ""; //当日生产动态
- // 下步工作计划
- form.nextPlan = props.reportData.nextPlan || ""; //下步工作计划
- // 外租设备
- form.externalRental = props.reportData.externalRental || ""; //外租设备
- // 故障情况
- form.malfunction = props.reportData.malfunction || ""; //故障情况
- // 故障误工H
- form.faultDowntime = props.reportData.faultDowntime || ""; //故障误工H
- // 附件
- form.attachments = props.reportData.attachments || [];
- // 提取变量,方便阅读
- const list1 = props.reportData.reportFuels;
- const list2 = props.reportData.reportedFuels;
- const validList = list1?.length > 0 ? list1 : list2?.length > 0 ? list2 : [];
- form.reportFuels = validList.map(v => ({
- ...v,
- // 这里保持你原有的数值处理逻辑
- customFuel: Number(
- Number(
- props.formDisable
- ? (v.customFuel ?? 0)
- : (v.customFuel ?? v.zhbdFuel ?? 0)
- ).toFixed(2)
- ),
- }));
- steps.value = (props.reportData.taskProgresses ?? []).map(v => ({
- title: v.rdStatusLabel,
- desc: v.createTime,
- }));
- initDailyFuel();
- // form.
- // 展示用的文件列表
- // attachmentsFileList.value =
- // props.reportData?.attachments?.map(item => ({
- // ...item,
- // name: item.filename,
- // url: item.filePath,
- // })) || [];
- };
- // 初始化时间范围
- const timeRangeFormat = () => {
- if (props.reportData.startTime) {
- const startArr = props.reportData.startTime;
- form.startTime = `${startArr[0].toString().padStart(2, "0")}:${startArr[1]
- .toString()
- .padStart(2, "0")}`;
- }
- if (props.reportData.endTime) {
- const endArr = props.reportData.endTime;
- form.endTime = `${endArr[0].toString().padStart(2, "0")}:${endArr[1]
- .toString()
- .padStart(2, "0")}`;
- }
- };
- watch(
- () => props.reportData,
- val => {
- if (val.id) {
- formDataFormat();
- }
- },
- { deep: true, immediate: true }
- );
- const wellOptions = computed(() => {
- return (
- props.reportData.platforms?.map(v => ({
- text: v.wellName,
- value: v.reportId,
- })) ?? []
- );
- });
- const handleClickTimeRange = () => {
- // 打开时间范围选择器
- timeRangeRef.value.open();
- };
- const reportDetailsTimeRangeRef = ref(null);
- const reportDetailIndex = ref(0);
- const handleClickTimeRangeItem = index => {
- reportDetailIndex.value = index;
- reportDetailsTimeRangeRef.value.open();
- };
- const calculateDuration = row => {
- if (!row.startTime || !row.endTime) {
- row.duration = 0;
- return;
- }
- const todayStr = dayjs().format("YYYY-MM-DD");
- const start = dayjs(`${todayStr} ${row.startTime}`);
- const end = dayjs(`${todayStr} ${row.endTime}`);
- let diffMinutes = end.diff(start, "minute");
- if (diffMinutes < 0) {
- diffMinutes += 1440;
- }
- row.duration = Number((diffMinutes / 60).toFixed(2));
- };
- const reportDetailsTimeRange = data => {
- form.reportDetails[reportDetailIndex.value].startTime = data[0];
- form.reportDetails[reportDetailIndex.value].endTime = data[1];
- calculateDuration(form.reportDetails[reportDetailIndex.value]);
- };
- const uploadRef = ref(null);
- const attachmentList = ref([]);
- const chooseFile = () => {
- uploadRef.value.chooseFile({
- count: 9,
- size: 50,
- success: files => {
- attachmentList.value = attachmentList.value.concat(files);
- attachmentList.value.forEach(file => {
- // 将等待上传和上传失败的文件提交上传到服务器
- // 提示:::如果接口不支持跨域,改成调用this.getTempFilePath(file)
- if (file.status === "waiting" || file.status === "fail") {
- uploadHandle(file);
- }
- });
- },
- });
- };
- const uploadHandle = file => {
- uploadRef.value.upload({
- url:
- config.default.apiUrl + config.default.apiUrlSuffix + "/rq/file/upload",
- file,
- name: "files",
- header: {
- "Authorization": getAccessToken() ? "Bearer " + getAccessToken() : "",
- "Tenant-id": getTenantId() ? getTenantId() : "1",
- "Device-id": "undefined",
- },
- method: "post",
- success: e => {
- file.status = "success";
- const result = JSON.parse(e.result);
- if (result.code !== 0) {
- uni.showToast({
- title: `【${file.name}】${t("operation.uploadFail")}`,
- icon: "none",
- });
- return;
- }
- form.attachments.push({
- bizId: props.reportId,
- category: "daily_report",
- filePath: result.data.files[0].filePath,
- filename: result.data.files[0].name,
- // fileSize: data.files[0].size,
- // fileType: data.files[0].type,
- remark: "",
- type: "attachment",
- });
- },
- fail: e => {
- file.status = "fail";
- console.error("上传异常:", err);
- uni.showToast({ title: t("operation.uploadFail"), icon: "none" });
- },
- });
- };
- // const uploadHandle = file => {
- // uploadRef.value.getTempFilePath({
- // file,
- // success: e => {
- // uni.uploadFile({
- // url: config.default.apiUrl + config.default.apiUrlSuffix + '/rq/file/upload',
- // header: {
- // 'Authorization': getAccessToken() ? 'Bearer ' + getAccessToken() : '',
- // 'tenant-id': getTenantId() ? getTenantId() : '1',
- // 'device-id': undefined,
- // },
- // name: 'files',
- // // #ifdef H5
- // file: e.result,
- // // #endif
- // // #ifndef H5
- // filePath: e.result,
- // // #endif
- // success: e => {
- // console.log('e :>> ', e);
- // // file.status = 'success';
- // // const result = JSON.parse(e.result);
- // // if (e.code !== 0) {
- // // uni.showToast({
- // // title: `【${file.name}】${t('operation.uploadFail')}`,
- // // icon: 'none',
- // // });
- // // return;
- // // }
- // // form.attachments.push({
- // // bizId: props.reportId,
- // // category: 'daily_report',
- // // filePath: data.files[0].filePath,
- // // filename: data.files[0].name,
- // // // fileSize: data.files[0].size,
- // // // fileType: data.files[0].type,
- // // remark: '',
- // // type: 'attachment',
- // // });
- // },
- // fail: e => {
- // console.log('e :>> ', e);
- // },
- // });
- // },
- // });
- // };
- // 删除附件
- const deleteFiles = index => {
- // 1. 从formData.attachments中移除选中项
- form.attachments.splice(index, 1);
- };
- function copyToPublicAndOpen(sourcePath, fileName) {
- // 获取 _downloads/ (公共下载目录) 的目录对象
- plus.io.resolveLocalFileSystemURL(
- "_downloads/",
- entryDir => {
- // 获取源文件对象
- plus.io.resolveLocalFileSystemURL(
- sourcePath,
- entryFile => {
- // 执行复制操作:将 sourcePath 复制到 _downloads/ 下,并重命名
- entryFile.copyTo(
- entryDir,
- fileName,
- newEntry => {
- console.log("文件已复制到公共目录:", newEntry.fullPath);
- uni.showToast({
- title: "已保存到下载目录",
- icon: "none",
- duration: 3000,
- });
- // 3. 预览打开
- // 注意:打开公共目录的文件推荐用 plus.runtime.openFile
- // uni.openDocument 有时对公共路径支持不好
- plus.runtime.openFile(
- newEntry.fullPath,
- {},
- e => {
- console.log("打开成功");
- },
- e => {
- console.error("打开失败", e);
- uni.showToast({ title: "无法打开文件", icon: "none" });
- }
- );
- },
- e => {
- console.error("复制文件失败:", e);
- uni.showToast({ title: "保存到公共目录失败", icon: "none" });
- }
- );
- },
- e => {
- console.error("读取源文件失败:", e);
- }
- );
- },
- e => {
- console.error("读取下载目录失败:", e);
- }
- );
- }
- function saveTempFileToDownloads(tempPath, fileName) {
- // 1. 获取系统 Downloads 目录对象
- // "_downloads/" 是 H5+ API 对安卓公共下载目录的映射
- plus.io.resolveLocalFileSystemURL(
- "_downloads/",
- entryDir => {
- // 2. 获取临时文件对象
- plus.io.resolveLocalFileSystemURL(
- tempPath,
- entryFile => {
- // 3. 执行复制:将临时文件复制到 Downloads 目录
- entryFile.copyTo(
- entryDir,
- fileName,
- newEntry => {
- console.log("文件路径:" + newEntry.fullPath);
- uni.showToast({
- title: "已保存至Downloads",
- icon: "none",
- });
- // 4. (可选) 打开预览
- plus.runtime.openFile(newEntry.fullPath);
- },
- e => {
- console.error("复制失败", e);
- uni.showToast({ title: "保存失败", icon: "none" });
- }
- );
- },
- e => {
- console.error("读取临时文件失败", e);
- }
- );
- },
- e => {
- console.error("无法访问下载目录", e);
- // 这里如果报错,通常是权限没给或者 Android 11+ 读写受限
- }
- );
- }
- // 下载文件
- const downloadFile = async file => {
- console.log("🚀 ~ downloadFile ~ file:", file);
- const { filePath: fileUrl, name: fileName } = file;
- if (!fileUrl) {
- uni.showToast({ title: t("operation.fileUrlEmpty"), icon: "none" });
- return;
- }
- // 获取平台
- const platform = uni.getSystemInfoSync().platform;
- console.log("🚀 ~ downloadFile ~ platform:", platform);
- // 判断平台
- if (platform === "android") {
- uni.downloadFile({
- url: fileUrl,
- success: res => {
- console.log("🚀 ~ downloadFile ~ res:", res);
- if (res.statusCode === 200) {
- saveTempFileToDownloads(res.tempFilePath, fileName);
- // uni.saveFile({
- // tempFilePath: res.tempFilePath,
- // success: res => {
- // // console.log('🚀 ~ downloadFile saveFile ~ res:', res);
- // uni.showToast({
- // title: t('operation.downloadSuccess'),
- // icon: 'none',
- // });
- // copyToPublicAndOpen(res.savedFilePath, fileName);
- // },
- // fail: err => {
- // console.log('🚀 ~ downloadFile saveFile ~ err:', err);
- // uni.showToast({
- // title: t('operation.downloadFail'),
- // icon: 'none',
- // });
- // },
- // });
- }
- },
- fail: err => {
- console.log("🚀 ~ downloadFile ~ err:", err);
- uni.showToast({
- title: t("operation.downloadFail"),
- icon: "none",
- });
- },
- });
- } else {
- try {
- // 2.1 处理文件名(避免特殊字符乱码,如中文、空格)
- const safeFileName = decodeURIComponent(fileName || "未命名文件"); // 解码URL编码的文件名
- // 2.2 创建隐藏的 <a> 标签(核心:利用 download 属性触发下载)
- const link = document.createElement("a");
- // 关键:设置 download 属性指定文件名(Web 端独有)
- link.download = safeFileName;
- // 设置文件地址(若跨域,需后端配置 CORS + Content-Disposition 响应头)
- link.href = fileUrl;
- // 隐藏 <a> 标签(不影响页面布局)
- link.style.display = "none";
- // 将 <a> 标签添加到文档中(否则部分浏览器无法触发点击)
- document.body.appendChild(link);
- // 2.3 模拟点击 <a> 标签触发下载
- link.click();
- // 2.4 下载后清理资源(避免内存泄漏)
- setTimeout(() => {
- document.body.removeChild(link); // 移除 <a> 标签
- URL.revokeObjectURL(link.href); // 释放 URL 资源(若使用 Blob 时必需)
- }, 100);
- } catch (err) {
- console.error("🚀 ~ Web 端下载失败:", err);
- // 若直接通过 <a> 标签下载失败(如跨域),尝试通过 Blob 流下载(场景2兼容)
- await downloadFileByBlob(fileUrl, fileName);
- }
- }
- };
- // 兼容场景2:通过 Blob 流下载(解决跨域或后端返回流的情况)
- const downloadFileByBlob = async (fileUrl, fileName) => {
- try {
- // 1. 发起请求获取文件流(注意:需设置 responseType: 'blob')
- const response = await fetch(fileUrl, {
- method: "GET",
- headers: {
- // 若需要登录态,添加 token(根据项目授权方式调整)
- Authorization: `Bearer ${uni.getStorageSync("token")}`,
- },
- });
- if (!response.ok) {
- throw new Error(`请求失败: ${response.status}`);
- }
- // 2. 将响应转换为 Blob 对象(根据文件类型设置 MIME,如 PDF 为 'application/pdf')
- const blob = await response.blob();
- // 3. 生成 Blob 临时 URL
- const blobUrl = URL.createObjectURL(blob);
- // 4. 用 <a> 标签触发下载(同场景1逻辑)
- const safeFileName = decodeURIComponent(fileName || "未命名文件");
- const link = document.createElement("a");
- link.download = safeFileName;
- link.href = blobUrl;
- link.style.display = "none";
- document.body.appendChild(link);
- link.click();
- // 5. 清理资源
- setTimeout(() => {
- document.body.removeChild(link);
- URL.revokeObjectURL(blobUrl); // 必须释放 Blob URL,避免内存泄漏
- uni.hideLoading();
- // uni.showToast({ title: t("operation.downloadSuccess"), icon: "success" });
- }, 100);
- } catch (err) {
- console.error("🚀 ~ Blob 下载失败:", err);
- uni.hideLoading();
- // uni.showToast({ title: t("operation.downloadFail"), icon: "error" });
- }
- };
- const removeSelectedItem = (platformId, value) => {
- form[platformId].techniqueIds = form[platformId].techniqueIds.filter(
- item => item !== value
- );
- getWorkloadInfoByTechnique(platformId);
- };
- const getWorkloadInfoByTechnique = platformId => {
- const ids = form[platformId].techniqueIds;
- if (!ids.length) {
- form[platformId].extProperty = [];
- return;
- }
- getRuiDuReportAttrs({
- techniqueIds: ids.join(","),
- }).then(res => {
- const { data = [] } = res;
- // 1. 按 "identifier+unit" 去重:用Map保证唯一,key为拼接字段
- const uniqueMap = new Map();
- data.forEach(item => {
- // 生成去重key(identifier和unit都存在才拼接,避免异常)
- const key =
- item.identifier && item.unit
- ? `${item.identifier}-${item.unit}`
- : Math.random().toString(36).slice(2, 11); // 异常情况用随机key避免重复
- uniqueMap.set(key, item); // 重复key会覆盖,实现去重
- });
- // 去重后的数组
- const uniqueData = Array.from(uniqueMap.values());
- // 2. 对比formData.extProperty,保留已有actualValue(避免覆盖用户输入)
- const handledData = uniqueData.map(newItem => {
- // 生成当前新项的去重key
- const newKey =
- newItem.identifier && newItem.unit
- ? `${newItem.identifier}-${newItem.unit}`
- : "";
- // 在原有extProperty中找匹配项
- const oldItem = form[platformId].extProperty.find(old => {
- const oldKey =
- old.identifier && old.unit ? `${old.identifier}-${old.unit}` : "";
- return newKey && oldKey && newKey === oldKey;
- });
- // 有匹配项则复用原有actualValue,无则用新项的(默认空)
- return {
- ...newItem,
- actualValue: oldItem?.actualValue ?? newItem.actualValue,
- };
- });
- // 3. 重新赋值给formData.extProperty(更新页面展示)
- form[platformId].extProperty = handledData;
- });
- };
- defineExpose({
- submitForm,
- });
- // 假设你已经定义了 props
- // const props = defineProps({ reportData: Object });
- // --- 1. 公共工具函数 (保持不变) ---
- const parseNumber = val => {
- let num = parseFloat(val);
- if (isNaN(num)) num = 0;
- if (num < 0) num = 0;
- return Number(num.toFixed(2));
- };
- // --- 2. 防抖逻辑定义 (保持不变) ---
- // 列表变化 -> 算总和
- const handleListChange = useDebounceFn(() => {
- let total = 0;
- form.reportFuels.forEach(item => {
- const formattedVal = parseNumber(item.customFuel);
- if (item.customFuel !== formattedVal) {
- item.customFuel = formattedVal;
- }
- total += formattedVal;
- });
- // 更新 dailyFuel,这会触发下面的 dailyFuel watcher
- dailyFuel.value = parseNumber(total);
- }, 500);
- // dailyFuel 变化 -> 格式化自身 & 同步 form
- const handleDailyFuelChange = useDebounceFn(() => {
- const formattedVal = parseNumber(dailyFuel.value);
- if (dailyFuel.value !== formattedVal) {
- dailyFuel.value = formattedVal;
- }
- form.dailyFuel = formattedVal;
- }, 500);
- // --- 3. 关键修改:初始化逻辑 ---
- const initDailyFuel = () => {
- // 获取 props 中的值 (转为数字以做判断)
- const propVal = props.reportData?.dailyFuel;
- const numPropVal = parseFloat(propVal);
- // 判断规则:如果有值且不是 NaN (根据需求,你也可以加上 > 0 的判断)
- // 这里假设只要 props 里有有效数字,就以 props 为准
- const hasPropValue = !isNaN(numPropVal) && propVal !== null && propVal !== "";
- if (hasPropValue) {
- // 【情况A】Props 有值:直接使用 Props
- const val = parseNumber(numPropVal);
- dailyFuel.value = val;
- form.dailyFuel = val;
- // // 顺便把列表里的每一项也格式化一下(可选)
- // form.reportFuels.forEach(item => {
- // item.customFuel = parseNumber(item.customFuel);
- // });
- } else {
- // 【情况B】Props 没值:根据列表计算初始值
- // 这里我们不使用防抖,直接立即计算一次,确保显示正确
- let total = 0;
- form.reportFuels.forEach(item => {
- // 初始化时顺便把列表里的脏数据格式化了
- const val = parseNumber(item.customFuel);
- item.customFuel = val;
- total += val;
- });
- const finalTotal = parseNumber(total);
- dailyFuel.value = finalTotal;
- form.dailyFuel = finalTotal;
- }
- };
- // --- 4. 监听器 (关键修改) ---
- // 监听列表:【注意】这里去掉了 immediate: true
- // 因为初始化我们已经在上面手动 initDailyFuel() 里做过了
- // 现在只监听用户后续的“修改”操作
- // watch(
- // () => form.reportFuels,
- // () => {
- // handleListChange();
- // },
- // { deep: true } // 只有 deep,没有 immediate
- // );
- // 监听 dailyFuel
- watch(
- () => dailyFuel.value,
- (newVal, oldVal) => {
- // 只有当值真的变了,才触发防抖更新
- // 避免初始化赋值时触发不必要的逻辑
- if (newVal !== oldVal) {
- handleDailyFuelChange();
- }
- }
- );
- </script>
- <template>
- <scroll-view scroll-y="true" class="report-form">
- <scroll-view class="steps" scroll-x :scroll-y="false">
- <uni-steps
- :options="steps"
- :active="steps.length - 1"
- :style="{ width: `${steps.length * 100}px` }" />
- </scroll-view>
- <uni-forms
- ref="reportFormRef"
- labelWidth="140px"
- :modelValue="form"
- :rules="formDataBaseRules"
- err-show-type="toast">
- <uni-forms-item
- v-if="reportData.platformWell === 1"
- class="form-item well-form-item"
- label="平台井"
- :required="isRequired">
- <uni-data-select
- class="form-item-select"
- :clear="false"
- align="right"
- placeholder="请选择平台井"
- :disabled="formDisable && istime !== 'true'"
- :localdata="wellOptions"
- multiple
- v-model="form.platformIds" />
- </uni-forms-item>
- <div class="content">
- <uni-forms-item
- class="form-item"
- :label="`${$t('ruiDu.timeNode')}:`"
- :required="isRequired">
- <view
- class="item-content"
- @click="props.formDisable ? '' : handleClickTimeRange()">
- <view class="time-range-item" v-if="form.startTime && form.endTime">
- {{ form.startTime }} 至 {{ form.endTime }}
- </view>
- <view class="time-range-item" v-else>
- {{ selectPlaceholder }}
- </view>
- </view>
- </uni-forms-item>
- <uni-forms-item
- class="form-item"
- :label="`${$t('ruiDu.constructionEquipment')}:`">
- <view>
- <uni-row class="item-content">
- <button
- class="mini-btn form-item-btn"
- type="primary"
- :disabled="formDisable"
- v-if="!formDisable"
- @click="handleClickSelectDevice">
- {{ $t("device.selectDevice") }}
- </button>
- </uni-row>
- <uni-row>
- <uni-easyinput
- style="text-align: right"
- type="textarea"
- :autoHeight="true"
- :inputBorder="false"
- :clearable="false"
- :styles="{ disableColor: '#fff' }"
- :placeholder="$t('ruiDu.unselectedEquipment')"
- :disabled="true"
- v-model="selectedEquipmentNames" />
- </uni-row>
- </view>
- </uni-forms-item>
- <uni-forms-item
- class="form-item"
- :label="`${$t('ruiDu.unselectedEquipment')}:`">
- <uni-easyinput
- style="text-align: right"
- type="textarea"
- :autoHeight="true"
- :inputBorder="false"
- :clearable="false"
- :styles="{ disableColor: '#fff' }"
- :placeholder="' '"
- :disabled="true"
- v-model="unselectedEquipmentNames" />
- </uni-forms-item>
- <uni-forms-item
- :required="isRequired"
- class="form-item"
- label="当日油耗(L):">
- <uni-easyinput
- class="digit-item"
- type="number"
- :inputBorder="false"
- :clearable="false"
- :styles="{ disableColor: '#fff' }"
- :placeholder="inputPlaceholder"
- :disabled="formDisable"
- v-model.number="dailyFuel" />
- </uni-forms-item>
- <!-- <uni-forms-item
- class="form-item"
- :label="`${$t('ruiDu.dailyProductionDynamic')}:`"
- :required="isRequired"
- name="productionStatus">
- <uni-easyinput
- style="text-align: right"
- type="textarea"
- :autoHeight="true"
- :inputBorder="false"
- :clearable="false"
- :styles="{ disableColor: '#fff' }"
- :placeholder="inputPlaceholder"
- :disabled="formDisable"
- v-model="form.productionStatus"
- :maxlength="1000" />
- </uni-forms-item> -->
- <!-- 下步工作计划 -->
- <uni-forms-item
- class="form-item"
- :required="isRequired"
- :label="`${$t('ruiDu.nextWorkPlan')}:`"
- name="nextPlan">
- <uni-easyinput
- style="text-align: right"
- type="textarea"
- :autoHeight="true"
- :inputBorder="false"
- :clearable="false"
- :styles="{ disableColor: '#fff' }"
- :placeholder="inputPlaceholder"
- :disabled="formDisable"
- v-model="form.nextPlan"
- :maxlength="1000" />
- </uni-forms-item>
- <!-- 外租设备 -->
- <uni-forms-item
- class="form-item"
- :label="`${$t('ruiDu.externalRentalEquipment')}:`"
- name="externalRental">
- <uni-easyinput
- style="text-align: right"
- type="textarea"
- :autoHeight="true"
- :inputBorder="false"
- :clearable="false"
- :styles="{ disableColor: '#fff' }"
- :placeholder="inputPlaceholder"
- :disabled="formDisable"
- v-model="form.externalRental"
- :maxlength="1000" />
- </uni-forms-item>
- <!-- 故障情况 -->
- <uni-forms-item
- class="form-item"
- :label="`${$t('ruiDu.faultSituation')}:`"
- name="malfunction">
- <uni-easyinput
- style="text-align: right"
- type="textarea"
- :autoHeight="true"
- :inputBorder="false"
- :clearable="false"
- :styles="{ disableColor: '#fff' }"
- :placeholder="inputPlaceholder"
- :disabled="formDisable"
- v-model="form.malfunction"
- :maxlength="1000" />
- </uni-forms-item>
- <!-- 故障误工H -->
- <uni-forms-item
- class="form-item"
- :label="`${$t('ruiDu.faultDowntimeH')}:`"
- name="faultDowntime">
- <uni-easyinput
- class="digit-item"
- type="digit"
- :inputBorder="false"
- :clearable="true"
- :styles="{ disableColor: '#fff' }"
- :placeholder="inputPlaceholder"
- :disabled="formDisable"
- v-model="form.faultDowntime"
- :maxlength="1000" />
- </uni-forms-item>
- <uni-forms-item
- v-if="type !== 'edit' || istime === 'true'"
- class="form-item"
- label="当日施工简报"
- required
- name="constructionBrief"
- :rules="[
- { required: istime === 'true', errorMessage: '请输入当日施工简报' },
- ]">
- <uni-easyinput
- class="digit-item"
- type="textarea"
- :autoHeight="true"
- :inputBorder="false"
- :clearable="true"
- :styles="{ disableColor: '#fff' }"
- :placeholder="inputPlaceholder"
- :disabled="istime !== 'true'"
- v-model="form.constructionBrief"
- :maxlength="2000" />
- </uni-forms-item>
- <uni-forms-item
- class="form-item"
- :label="`${$t('ruiDu.attachment')}:`"
- :required="false"
- name="attachments">
- <view v-if="!formDisable" class="file-parent">
- <view class="file-picker-container item-end">
- <view class="file-size-limit">
- {{ $t("ruiDu.fileSizeLimit") }}
- </view>
- <button
- type="primary"
- size="mini"
- class="file-picker-btn"
- @click="chooseFile">
- {{ $t("ruiDu.selectFile") }}
- </button>
- </view>
- <view class="file-list">
- <view v-for="(file, index) in form.attachments" :key="index">
- {{ file.filename }}
- <button
- @click="deleteFiles"
- type="primary"
- size="mini"
- class="file-picker-btn"
- >删除文件
- </button>
- </view>
- </view>
- </view>
- <view class="file-list item-col" v-else>
- <view v-for="(file, index) in form.attachments" :key="index">
- <span>{{ file.filename }}</span>
- <button
- @click="downloadFile(file)"
- type="primary"
- size="mini"
- class="file-picker-btn"
- >下载文件</button
- >
- </view>
- </view>
- </uni-forms-item>
- <!-- 附件 -->
- </div>
- <div class="content">
- <div class="content-title">
- 生产动态
- <button
- v-if="!formDisable && istime !== 'true'"
- type="primary"
- size="mini"
- class="detail-btn"
- @click="addReportDetailRow()">
- 添加一行
- </button>
- </div>
- <template v-for="(item, index) in form.reportDetails" :key="index">
- <uv-divider v-if="index !== 0" class="divider"></uv-divider>
- <uni-forms-item class="form-item" label="日期">
- <uni-easyinput
- class="digit-item"
- :inputBorder="false"
- :clearable="false"
- :styles="{ disableColor: '#fff' }"
- :placeholder="inputPlaceholder"
- :disabled="true"
- :model-value="
- dayjs(reportData.createTime).format('YYYY-MM-DD')
- " />
- </uni-forms-item>
- <uni-forms-item
- class="form-item"
- :label="`${$t('ruiDu.timeNode')}:`"
- required>
- <view
- class="item-content"
- @click="props.formDisable ? '' : handleClickTimeRangeItem(index)">
- <view
- class="time-range-item"
- v-if="item.startTime && item.endTime">
- {{ item.startTime }} 至 {{ item.endTime }}
- </view>
- <view class="time-range-item" v-else>
- {{ selectPlaceholder }}
- </view>
- </view>
- </uni-forms-item>
- <uni-forms-item class="form-item" label="时长(H)">
- <uni-easyinput
- class="digit-item"
- :inputBorder="false"
- :clearable="false"
- :styles="{ disableColor: '#fff' }"
- :placeholder="inputPlaceholder"
- :disabled="true"
- :model-value="item.duration" />
- </uni-forms-item>
- <uni-forms-item
- class="form-item"
- label="施工详情"
- required
- :name="['reportDetails', index, 'constructionDetail']"
- :rules="[{ required: true, errorMessage: '请输入施工详情' }]">
- <uni-easyinput
- class="digit-item"
- type="textarea"
- autoHeight
- :inputBorder="false"
- :clearable="true"
- :styles="{ disableColor: '#fff' }"
- :placeholder="inputPlaceholder"
- :disabled="formDisable"
- v-model="item.constructionDetail"
- :maxlength="2000" />
- </uni-forms-item>
- <uni-forms-item
- v-if="!formDisable && istime !== 'true'"
- class="form-item"
- label="操作">
- <button
- type="warn"
- size="mini"
- class="detail-btn"
- @click="removeReportDetailRow(index)">
- 删除
- </button>
- </uni-forms-item>
- </template>
- </div>
- <div
- v-for="(platformId, index) in form.platformIds"
- :key="platformId"
- class="content">
- <div class="content-title">{{
- wellOptions.find(item => item.value === platformId)?.text ??
- reportData.wellName ??
- ""
- }}</div>
- <uni-forms-item
- class="form-item"
- :label="`${$t('ruiDu.constructionStatus')}:`"
- :required="isRequired"
- :name="[platformId, 'rdStatus']"
- :rules="[
- {
- required: true,
- errorMessage: `${t('operation.PleaseSelect')}${t(
- 'ruiDu.constructionStatus'
- )}`,
- },
- ]">
- <uni-data-select
- class="form-item-select items-center"
- :clear="false"
- :align="'right'"
- placement="top"
- :localdata="rdStatusRange"
- :placeholder="selectPlaceholder"
- :disabled="formDisable"
- v-model="form[platformId].rdStatus">
- </uni-data-select>
- </uni-forms-item>
- <uni-forms-item
- class="form-item"
- :label="`${$t('ruiDu.constructionProcess')}:`"
- :required="reportData.virtualProject !== 'Y' ? isRequired : false"
- :name="[platformId, 'techniqueIds']"
- :rules="
- reportData.virtualProject !== 'Y'
- ? [
- {
- required: true,
- errorMessage: `${t('operation.PleaseSelect')}${t(
- 'ruiDu.constructionProcess'
- )}`,
- },
- ]
- : []
- ">
- <uni-data-select
- ref="uniDataSelect"
- mode="underline"
- :multiple="true"
- :clear="false"
- :localdata="techniqueRange"
- :disabled="formDisable"
- placement="top"
- @change="getWorkloadInfoByTechnique(platformId)"
- v-model="form[platformId].techniqueIds">
- <template v-slot:selected="{ selectedItems }" class="form-item">
- <view class="slot-box flex flex-row items-center justify-end">
- <view
- v-for="item in selectedItems"
- :key="item.value"
- class="slot-content-item selected items-center justify-start">
- {{ item.text }}
- <uni-icons
- type="close"
- size="18"
- color="#909399"
- v-if="!formDisable"
- @click="
- removeSelectedItem(platformId, item.value)
- "></uni-icons>
- </view>
- <view
- v-if="selectedItems.length == 0"
- class="slot-content-item items-center justify-start">
- {{ selectPlaceholder }}
- </view>
- </view>
- </template>
- <template v-slot:option="{ item, itemSelected }">
- <view class="slot-item">
- <uni-list-item class="flex-row items-center justify-between">
- <template v-slot:body>
- <text
- class="slot-item-text justify-start"
- :style="{ color: itemSelected ? '#007aff' : '#303133' }">
- {{ item.text }}
- </text>
- </template>
- <template v-slot:footer>
- <uni-icons
- class="items-center justify-center"
- v-if="itemSelected"
- type="checkmarkempty"
- size="20"
- color="#007aff"></uni-icons>
- </template>
- </uni-list-item>
- </view>
- </template>
- <template v-slot:empty>
- <view class="empty-box">
- <view>{{ $t("common.noData") }}</view>
- </view>
- </template>
- </uni-data-select>
- </uni-forms-item>
- <uni-forms-item
- class="form-item"
- v-for="(attr, index) in form[platformId].extProperty"
- :key="index"
- :label="`${attr.name}(${attr.unit}):`"
- :required="attr.required == 1 && isRequired"
- :name="[platformId, 'extProperty', index, 'actualValue']"
- :rules="[
- {
- required: true,
- errorMessage: `${t('operation.PleaseFillIn')}${attr.name}`,
- },
- ]">
- <uni-easyinput
- v-if="attr.dataType === 'double'"
- class="digit-item"
- type="digit"
- :inputBorder="false"
- :clearable="true"
- :styles="{ disableColor: '#fff' }"
- :placeholder="inputPlaceholder"
- :disabled="formDisable"
- v-model.number="form[platformId].extProperty[index].actualValue" />
- <uni-easyinput
- v-else
- style="text-align: right"
- :styles="{ disableColor: '#fff' }"
- :inputBorder="false"
- :clearable="true"
- :placeholder="inputPlaceholder"
- :disabled="formDisable"
- v-model="form[platformId].extProperty[index].actualValue"
- :type="'textarea'"></uni-easyinput>
- </uni-forms-item>
- <uv-divider text="非生产时间" textPosition="left"></uv-divider>
- <uni-forms-item
- class="form-item"
- v-for="field in NON_PROD_FIELDS"
- :key="field.key"
- :label="field.label + '(H)'"
- :name="[platformId, field.key]">
- <uni-easyinput
- type="number"
- style="text-align: right"
- :inputBorder="false"
- :clearable="false"
- :styles="{ disableColor: '#fff' }"
- :disabled="istime !== 'true'"
- v-model.number="form[platformId][field.key]"
- @input="val => onInputChange(val, platformId, field.key)" />
- </uni-forms-item>
- <uni-forms-item
- class="form-item"
- label="其他非生产原因"
- :name="[platformId, 'otherNptReason']">
- <uni-easyinput
- style="text-align: right"
- type="textarea"
- autoHeight
- :inputBorder="false"
- :clearable="false"
- :styles="{ disableColor: '#fff' }"
- v-model="form[platformId].otherNptReason"
- :disabled="istime !== 'true'"
- :maxlength="1000" />
- </uni-forms-item>
- </div>
- <div
- v-for="(fuel, index) in form.reportFuels"
- :key="index"
- class="content">
- <div class="content-title">{{ fuel.deviceCode }}</div>
- <uni-forms-item class="form-item" label="设备名称:">
- <view
- style="
- text-align: right;
- width: 100%;
- padding-right: 10px;
- box-sizing: border-box;
- "
- >{{ fuel.deviceName }}</view
- >
- </uni-forms-item>
- <uni-forms-item class="form-item" label="发生日期:">
- <view
- style="
- text-align: right;
- width: 100%;
- padding-right: 10px;
- box-sizing: border-box;
- "
- >{{ dayjs(fuel.queryDate).format("YYYY-MM-DD") }}</view
- >
- </uni-forms-item>
- <uni-forms-item class="form-item" label="中航北斗油耗(L):">
- <view
- style="
- text-align: right;
- width: 100%;
- padding-right: 10px;
- box-sizing: border-box;
- "
- >{{ (fuel.zhbdFuel ?? 0).toFixed(2) }}</view
- >
- </uni-forms-item>
- <uni-forms-item class="form-item" label="实际油耗(L):">
- <uni-easyinput
- class="digit-item"
- type="number"
- :inputBorder="false"
- :clearable="false"
- :styles="{ disableColor: '#fff' }"
- :placeholder="inputPlaceholder"
- :disabled="formDisable"
- v-model.number="fuel.customFuel"
- @input="handleListChange" />
- </uni-forms-item>
- </div>
- </uni-forms>
- </scroll-view>
- <lsj-upload ref="uploadRef"></lsj-upload>
- <tpf-time-range
- ref="timeRangeRef"
- :startTime="startTime"
- :startDefaultTime="startDefaultTime"
- :endTime="endTime"
- :endDefaultTime="endDefaultTime"
- @timeRange="timeRange"></tpf-time-range>
- <tpf-time-range
- ref="reportDetailsTimeRangeRef"
- :startTime="startTime"
- :startDefaultTime="startDefaultTime"
- :endTime="endTime"
- :endDefaultTime="endDefaultTime"
- @timeRange="reportDetailsTimeRange"></tpf-time-range>
- <device-transfer
- ref="deviceTransferRef"
- :allList="reportData.selectedDevices"
- :selected="form.deviceIds"
- @confirm="handleTransferChange" />
- </template>
- <style lang="scss" scoped>
- @import "@/style/work-order-form.scss";
- .report-form {
- height: 100%;
- color: #333;
- }
- .steps {
- :deep(.uni-scroll-view > .uni-scroll-view) {
- padding: 10px 0 20px 0;
- }
- }
- :deep(.uni-textarea-textarea:disabled),
- :deep(.uni-input-input:disabled) {
- color: #333;
- }
- :deep(.uni-date-x) {
- color: #333;
- }
- .digit-item {
- text-align: right;
- :deep(.uni-easyinput__content-input) {
- padding-right: 10px;
- }
- }
- .well-form-item {
- background-color: #fff;
- border-bottom: none;
- padding: 0 10px;
- }
- .form-item-select {
- width: 100%;
- }
- .form-item-btn {
- margin: 10px 0 0 0;
- width: 80px;
- text-align: center;
- }
- .digit-item {
- text-align: right;
- :deep(.uni-easyinput__content-input) {
- padding-right: 10px;
- }
- }
- .file-picker-container {
- width: 100%;
- }
- .file-picker-btn {
- margin-left: unset;
- margin-right: unset;
- }
- .file-size-limit {
- font-size: 10px;
- color: #ff4500;
- padding: 0 10px;
- }
- .file-parent {
- display: flex;
- flex-direction: column;
- align-items: end;
- padding: 10px 0;
- }
- .file-list {
- display: flex;
- flex-direction: column;
- align-items: end;
- justify-content: end;
- max-width: 100%;
- & > view {
- width: 100%;
- padding: 10px;
- padding-right: 0;
- display: flex;
- align-items: center;
- justify-content: space-between;
- & > span {
- flex: 1;
- word-break: break-all;
- overflow-wrap: anywhere;
- margin-right: 10px;
- }
- & > .file-picker-btn {
- flex-shrink: 0;
- margin-left: 0;
- }
- }
- }
- .slot-box {
- width: 100%;
- flex-wrap: wrap;
- }
- .slot-content-item {
- font-size: 12px;
- color: #6a6a6a;
- &.selected {
- background: #f4f4f5;
- // color: #909399;
- margin: 5px;
- padding: 5px;
- border-radius: 3px;
- }
- }
- .slot-item-text {
- width: 90%;
- }
- .content {
- margin-top: 10px;
- padding: 8px;
- background-color: #fff;
- }
- .content-title {
- font-weight: 600;
- height: 44px;
- display: flex;
- align-items: center;
- border-bottom: 1px dashed #cacccf;
- }
- .item-content {
- display: flex;
- align-items: center;
- justify-content: end;
- }
- .item-end {
- display: flex;
- align-items: end;
- justify-content: end;
- }
- .item-col {
- justify-content: end;
- }
- .time-range-item {
- margin: 10px;
- }
- .detail-btn {
- margin: 0;
- margin-left: auto;
- float: right;
- }
- .divider {
- margin: 0;
- transform: translateY(-1px);
- :deep(.uv-line) {
- border-width: 2px !important;
- border-color: rgb(41, 121, 255) !important;
- }
- }
- </style>
|