# -*- coding: utf-8 -*- """Patch waybill index.vue and WaybillDetail.vue for attachment and list columns.""" import os import re ROOT = os.path.dirname(os.path.dirname(__file__)) INDEX = os.path.join(ROOT, "ruoyi-ui", "src", "views", "basic", "waybill", "index.vue") DETAIL = os.path.join(ROOT, "ruoyi-ui", "src", "views", "basic", "waybill", "components", "WaybillDetail.vue") TABLE_OLD = r''' ''' TABLE_NEW = r''' ''' FORM_INSERT = r''' \u8fd0\u5355\u9644\u4ef6 ''' METHODS_INSERT = r''' formatRoute(row) { const from = row.senderCity || row.senderDistrict || row.senderProvince || ""; const to = row.receiverCity || row.receiverDistrict || row.receiverProvince || ""; return from && to ? from + " \u2192 " + to : "-"; }, transportStatusText(row) { const audit = row.auditStatus; const now = Date.now(); const depart = row.planDepartTime ? new Date(row.planDepartTime).getTime() : null; const arrive = row.planArriveTime ? new Date(row.planArriveTime).getTime() : null; if (audit === 0) return "\u8349\u7a3f"; if (audit === 1) return "\u5f85\u5ba1\u6838"; if (depart && now < depart) return "\u5df2\u786e\u8ba4"; if (arrive && now < arrive) return "\u5728\u9014"; if (arrive && now >= arrive) return "\u5df2\u5230\u8fbe"; return "\u5df2\u901a\u8fc7"; }, transportStatusTag(row) { const text = this.transportStatusText(row); const map = { "\u8349\u7a3f": "info", "\u5f85\u5ba1\u6838": "warning", "\u5df2\u786e\u8ba4": "success", "\u5728\u9014": "success", "\u5df2\u5230\u8fbe": "success", "\u5df2\u901a\u8fc7": "success" }; return map[text] || "info"; }, displayCurrentTemp(row) { if (row.currentTemp != null && row.currentTemp !== "") { return Number(row.currentTemp).toFixed(1) + "\u00b0C"; } const max = row.tempMax != null ? Number(row.tempMax) : null; const min = row.tempMin != null ? Number(row.tempMin) : 0; const audit = row.auditStatus; const now = Date.now(); const depart = row.planDepartTime ? new Date(row.planDepartTime).getTime() : null; const arrive = row.planArriveTime ? new Date(row.planArriveTime).getTime() : null; const inTransit = audit === 2 && depart && now > depart && arrive && now < arrive; let ratio = depart && arrive ? (now - depart) / (arrive - depart) : 0.5; ratio = Math.max(0, Math.min(1, ratio || 0.5)); const temp = inTransit && ratio > 0.4 && max != null ? max + 2.2 : (min + (max || 6)) / 2; return Number(temp).toFixed(1) + "\u00b0C"; }, isTempOverLimit(row) { const max = row.tempMax != null ? Number(row.tempMax) : null; const min = row.tempMin != null ? Number(row.tempMin) : null; const cur = parseFloat(this.displayCurrentTemp(row)); if (isNaN(cur)) return false; return (max != null && cur > max) || (min != null && cur < min); }, ''' DETAIL_ATTACHMENTS = r''' attachments() { const raw = this.detail.attachment; const base = this.formatDateTime(this.detail.createTime) || ""; const baseUrl = process.env.VUE_APP_BASE_API || ""; if (!raw) return []; return String(raw).split(",").filter(Boolean).map((url) => { const path = url.trim(); const name = path.lastIndexOf("/") >= 0 ? path.substring(path.lastIndexOf("/") + 1) : path; return { name, url: path, fullUrl: path.startsWith("http") ? path : baseUrl + path, time: base }; }); },''' DETAIL_PREVIEW = r''' previewFile(file) { const url = file.fullUrl || file.url; if (url) window.open(url, "_blank"); else this.$modal.msgInfo("\u9884\u89c8\uff1a" + file.name); }, downloadFile(file) { const url = file.fullUrl || file.url; if (url) window.open(url, "_blank"); else this.$modal.msgInfo("\u4e0b\u8f7d\uff1a" + file.name); }''' def patch_index(): text = open(INDEX, encoding="utf-8").read() # table: replace between selection and ???? column m = re.search( r'" alt = " \n " insert = FORM_INSERT.encode("utf-8").decode("unicode_escape") if marker in text: text = text.replace(marker, insert + marker, 1) else: idx = text.rfind('label="\u9884\u4f30\u91cc\u7a0b') if idx < 0: idx = text.rfind("estimateDistance") end = text.find("", idx) text = text[: end + len("")] + insert + text[end + len("") :] if "formatRoute(row)" not in text: text = text.replace( " canEdit(row) {", METHODS_INSERT.encode("utf-8").decode("unicode_escape") + " canEdit(row) {", 1, ) if 'attachment: ""' not in text and "attachment:" not in text.split("reset()")[1][:800]: text = text.replace( 'remark: "",', 'remark: "",\n attachment: "",', 1, ) text = text.replace( "planSignTime: undefined,", "planSignTime: undefined,\n currentTemp: undefined,", 1, ) open(INDEX, "w", encoding="utf-8", newline="\n").write(text) print("patched index.vue") def patch_detail(): text = open(DETAIL, encoding="utf-8").read() # replace attachments computed pat = r"attachments\(\) \{[\s\S]*?\n \},\n watch:" rep = DETAIL_ATTACHMENTS.encode("utf-8").decode("unicode_escape") + " watch:" if re.search(pat, text): text = re.sub(pat, rep, text, count=1) # replace preview/download pat2 = r"previewFile\(file\) \{[\s\S]*?downloadFile\(file\) \{[\s\S]*?\n \}\n \}\n\};" rep2 = DETAIL_PREVIEW.encode("utf-8").decode("unicode_escape") + "\n }\n};" if re.search(pat2, text): text = re.sub(pat2, rep2, text, count=1) open(DETAIL, "w", encoding="utf-8", newline="\n").write(text) print("patched WaybillDetail.vue") if __name__ == "__main__": patch_index() patch_detail()