diff --git a/packages/app-client/src/app.config.ts b/packages/app-client/src/app.config.ts index fd203e3..a1f3479 100644 --- a/packages/app-client/src/app.config.ts +++ b/packages/app-client/src/app.config.ts @@ -85,7 +85,7 @@ config = { // 发货单 { root: "pages/delivery", - pages: ["all", "document/delivery", "document/purchase"], + pages: ["all", "document"], }, // 瓜农 { diff --git a/packages/app-client/src/components/delivery/Step3Success.tsx b/packages/app-client/src/components/delivery/Step3Success.tsx index 69c848b..69a947f 100644 --- a/packages/app-client/src/components/delivery/Step3Success.tsx +++ b/packages/app-client/src/components/delivery/Step3Success.tsx @@ -1,121 +1,197 @@ import { useState } from "react"; -import { Text, View } from "@tarojs/components"; +import { Image, Text, View } from "@tarojs/components"; import { Button } from "@nutui/nutui-react-taro"; import Taro from "@tarojs/taro"; +import { Icon } from "@/components"; interface Step3SuccessProps { - document: string; + pdfUrl: string; + picUrl?: string; } export default function Step3Success(props: Step3SuccessProps) { - const { document } = props; + const { pdfUrl, picUrl } = props; const [tempFilePath, setTempFilePath] = useState(); - // 查看文档 - const handleView = async () => { - if (!tempFilePath) { + // 保存图片 + const handleSaveImage = async () => { + if (!picUrl) { Taro.showToast({ - title: "请先下载发货单据", + title: "没有可保存的预览图片", icon: "none", duration: 2000, }); return; } - Taro.openDocument({ - filePath: tempFilePath, - showMenu: true, - }); + try { + // 下载文件 + const downloadRes = await Taro.downloadFile({ + url: picUrl!, + }); + // 保存图片到相册 + await Taro.saveImageToPhotosAlbum({ + filePath: downloadRes.tempFilePath, + }); + + Taro.showToast({ + title: "图片已保存到相册", + icon: "success", + duration: 2000, + }); + } catch (error) { + console.error("保存图片失败:", error); + Taro.showToast({ + title: "保存图片失败,请检查相册权限", + icon: "none", + duration: 2000, + }); + } }; - // 处理下载功能 - const handleDownload = async () => { + // 下载PDF + const handleDownloadPDF = async () => { Taro.showToast({ - title: "正在生成并下载发货单据", - icon: "none", + title: "正在下载PDF文件", + icon: "loading", duration: 2000, }); - // 下载文件 - Taro.downloadFile({ - url: document!, - }).then((downloadRes) => { + try { + // 下载文件 + const downloadRes = await Taro.downloadFile({ + url: pdfUrl!, + }); + if (downloadRes.tempFilePath) { setTempFilePath(downloadRes.tempFilePath); - Taro.showToast({ - title: "发货单据已下载成功,您可以将生成的PDF发送给好友", - icon: "none", - duration: 3000, - }); - } - }); - }; - // 处理分享功能 - const handleShare = async () => { - if (!tempFilePath) { + // 保存PDF到手机 + if (Taro.saveFile) { + await Taro.saveFile({ + tempFilePath: downloadRes.tempFilePath, + }); + + Taro.showToast({ + title: "PDF下载成功", + icon: "success", + duration: 2000, + }); + } else { + // 如果不支持saveFile,直接提示下载完成 + Taro.openDocument({ + filePath: downloadRes.tempFilePath, + showMenu: true, + }); + } + } + } catch (error) { + console.error("下载PDF失败:", error); Taro.showToast({ - title: "请先下载发货单据", + title: "下载PDF失败", icon: "none", duration: 2000, }); - return; + } + }; + + // 查看PDF文档 + const handleViewPDF = async () => { + if (!tempFilePath) { + await handleDownloadPDF(); } - Taro.showToast({ - title: "正在分享到微信", - icon: "none", - duration: 2000, - }); - - // 下载完成后转发 - Taro.shareFileMessage({ - filePath: tempFilePath, - fileName: `发货单据.pdf`, - complete: (res) => { - console.log("complete", res); - }, - }); + if (tempFilePath) { + Taro.openDocument({ + filePath: tempFilePath, + showMenu: true, + }); + } }; return ( - - - - - - 发货单据生成成功 - - - 您的发货单据已生成,可以下载或转发给好友 + + {/* 预览区域 */} + + + {picUrl ? ( + + { + Taro.previewImage({ + urls: [picUrl], + current: picUrl, + }); + }} + /> + + ) : ( + + 暂无预览图片 + + )} + - - {document && !tempFilePath && ( - - - - )} - {document && tempFilePath && ( - <> - - - - - - - - )} - + )} - - 提示:您可以随时在发货单据列表中重新下载 + {/* PDF操作按钮 */} + + + + + {tempFilePath && ( + + + + )} + + + {/* 提示信息 */} + + + 点击预览图片可放大查看 + + + ); diff --git a/packages/app-client/src/components/icon/Icon.tsx b/packages/app-client/src/components/icon/Icon.tsx index d6bb074..2783fa1 100644 --- a/packages/app-client/src/components/icon/Icon.tsx +++ b/packages/app-client/src/components/icon/Icon.tsx @@ -3,6 +3,8 @@ import classNames from "classnames"; import React from "react"; export type IconNames = + | "download" + | "file-pdf" | "check-circle" | "exclamation" | "arrow-up" diff --git a/packages/app-client/src/iconfont.css b/packages/app-client/src/iconfont.css index 84b3be3..17c185e 100644 --- a/packages/app-client/src/iconfont.css +++ b/packages/app-client/src/iconfont.css @@ -1,8 +1,8 @@ @font-face { font-family: "iconfont"; /* Project id 5042354 */ - src: url('//at.alicdn.com/t/c/font_5042354_6imvn9bni2l.woff2?t=1766198766212') format('woff2'), - url('//at.alicdn.com/t/c/font_5042354_6imvn9bni2l.woff?t=1766198766212') format('woff'), - url('//at.alicdn.com/t/c/font_5042354_6imvn9bni2l.ttf?t=1766198766212') format('truetype'); + src: url('//at.alicdn.com/t/c/font_5042354_mzxt7rknws.woff2?t=1766213275700') format('woff2'), + url('//at.alicdn.com/t/c/font_5042354_mzxt7rknws.woff?t=1766213275700') format('woff'), + url('//at.alicdn.com/t/c/font_5042354_mzxt7rknws.ttf?t=1766213275700') format('truetype'); } .iconfont { @@ -13,6 +13,14 @@ -moz-osx-font-smoothing: grayscale; } +.icon-download:before { + content: "\e636"; +} + +.icon-file-pdf:before { + content: "\e634"; +} + .icon-exclamation:before { content: "\e635"; } diff --git a/packages/app-client/src/pages/approval/result.tsx b/packages/app-client/src/pages/approval/result.tsx index 41fbef9..84079bb 100644 --- a/packages/app-client/src/pages/approval/result.tsx +++ b/packages/app-client/src/pages/approval/result.tsx @@ -121,7 +121,7 @@ export default hocAuth(function Page(props: CommonComponent) { onClick={async () => { // 跳转到发货单据生成页面 await Taro.navigateTo({ - url: buildUrl("/pages/delivery/document/delivery", { + url: buildUrl("/pages/delivery/document", { orderShipId: orderShip.orderShipId, orderId: orderShip.orderId, }), diff --git a/packages/app-client/src/pages/delivery/all.tsx b/packages/app-client/src/pages/delivery/all.tsx index d7d305c..a7f2260 100644 --- a/packages/app-client/src/pages/delivery/all.tsx +++ b/packages/app-client/src/pages/delivery/all.tsx @@ -184,7 +184,7 @@ export default hocAuth(function Page(props: CommonComponent) { onClick={async (e) => { // 跳转到发货单据生成页面 await Taro.navigateTo({ - url: buildUrl("/pages/delivery/document/delivery", { + url: buildUrl("/pages/delivery/document", { orderShipId: shipOrderVO.orderShipId, orderId: shipOrderVO.orderId, }), diff --git a/packages/app-client/src/pages/delivery/document/delivery.config.ts b/packages/app-client/src/pages/delivery/document.config.ts similarity index 100% rename from packages/app-client/src/pages/delivery/document/delivery.config.ts rename to packages/app-client/src/pages/delivery/document.config.ts diff --git a/packages/app-client/src/pages/delivery/document/delivery.tsx b/packages/app-client/src/pages/delivery/document.tsx similarity index 81% rename from packages/app-client/src/pages/delivery/document/delivery.tsx rename to packages/app-client/src/pages/delivery/document.tsx index 655c1b0..ffb47ce 100644 --- a/packages/app-client/src/pages/delivery/document/delivery.tsx +++ b/packages/app-client/src/pages/delivery/document.tsx @@ -18,6 +18,7 @@ import { DeliveryStep2Preview, DeliveryStep3Success, } from "@/components"; +import dayjs from "dayjs"; // 特殊处理:其他费用要实时获取费用项目 const updateOtherFeesModule = async ( @@ -76,13 +77,13 @@ export default hocAuth(function Page(props: CommonComponent) { const [step, setStep] = useState(1); const [moduleList, setModuleList] = useState([]); - const [height, setHeight] = useState(); const [purchaseOrderVO, setPurchaseOrderVO] = useState(); const [orderShipVO, setOrderShipVO] = useState(); const [deliveryTemplate, setDeliveryTemplate] = useState(); - const [document, setDocument] = useState(); + const [pdfUrl, setPdfUrl] = useState(); + const [picUrl, setPicUrl] = useState(); const step1FormRef = useRef(null); @@ -102,9 +103,10 @@ export default hocAuth(function Page(props: CommonComponent) { setPurchaseOrderVO(purchaseOrderVO); const shipOrderVO = purchaseOrderVO.orderShipList[0]; setOrderShipVO(shipOrderVO); - if (shipOrderVO.document) { + if (shipOrderVO.pdfUrl || shipOrderVO.picUrl) { setStep(3); - setDocument(shipOrderVO.document); + setPdfUrl(shipOrderVO.pdfUrl); + setPicUrl(shipOrderVO.picUrl); } const { data } = await business.dealer.showDealer({ @@ -188,7 +190,6 @@ export default hocAuth(function Page(props: CommonComponent) { }, onCancel: () => { Dialog.close("dialog"); - console.log("12123"); }, }); return; @@ -231,16 +232,29 @@ export default hocAuth(function Page(props: CommonComponent) { // 截图预览内容 const capturePreview = async () => { const template = new PdfTemplate(moduleList); - const { data } = await poster.pdf.postApiV1Pdf({ + const { + data: { data: pdfData }, + } = await poster.pdf.postApiV1Pdf({ html: template.generateHtmlString(), }); + const { + data: { data: picData }, + } = await poster.poster.postApiV1Poster({ + html: template.generateHtmlString(), + format: "a4", + }); + + setPdfUrl(pdfData?.path); + setPicUrl(picData?.path); + const orderShip = purchaseOrderVO?.orderShipList[0]; // 存储 至 shipOrder previewUrl if (orderShip) { let formData: BusinessAPI.OrderShipGenerateDocumentCmd = { orderShipId: orderShip?.orderShipId, - document: data?.data?.path, + pdfUrl: pdfData?.path as string, + picUrl: picData?.path as string, }; // 检查各模块中的必填字段是否已填写 for (const module of moduleList) { @@ -267,7 +281,9 @@ export default hocAuth(function Page(props: CommonComponent) { } // 检查预计到仓时间字段是否开启且已填写 else if (column.dataIndex === "requiredEstimatedArrivalTime") { - formData.estimatedArrivalDate = orderShip?.estimatedArrivalDate; + formData.estimatedArrivalDate = dayjs( + orderShip?.estimatedArrivalDate, + ).format("YYYY-MM-DD"); } // 检查备注字段是否开启且已填写 else if (column.dataIndex === "requiredRemarks") { @@ -281,10 +297,6 @@ export default hocAuth(function Page(props: CommonComponent) { } business.orderShip.generateDocumentOrderShip(formData).then(); } - - if (data && data?.data?.path) { - setDocument(data?.data?.path); - } }; // 返回上一步 @@ -308,47 +320,13 @@ export default hocAuth(function Page(props: CommonComponent) { setStep(1); }; - const [topBarHeight, setTopBarHeight] = useState(0); - const [bottomBarHeight, setBottomBarHeight] = useState(0); - const topBarRef = useRef(null); - const bottomBarRef = useRef(null); - - useEffect(() => { - // 获取 topBar 和 bottomBar 的实际高度 - const queryTopBar = Taro.createSelectorQuery(); - queryTopBar - .select("#topBar") - .boundingClientRect((rect: any) => { - if (rect) { - setTopBarHeight(rect.height); - } - }) - .exec(); - - const queryBottomBar = Taro.createSelectorQuery(); - queryBottomBar - .select("#bottomBar") - .boundingClientRect((rect: any) => { - if (rect) { - setBottomBarHeight(rect.height); - } - }) - .exec(); - }, [step]); - - useEffect(() => { - // 计算滚动区域高度:窗口高度 - topBar高度 - bottomBar高度 - const windowHeight = Taro.getSystemInfoSync().windowHeight; - setHeight(windowHeight - topBarHeight - bottomBarHeight); - }, [topBarHeight, bottomBarHeight]); - return ( - - + <> + @@ -358,37 +336,32 @@ export default hocAuth(function Page(props: CommonComponent) { + + + {step === 1 && ( + + + + )} + + {step === 2 && } + + {step === 3 && pdfUrl && ( + + )} + - - {step === 1 && ( - - - - )} - - {step === 2 && } - - {step === 3 && document && } - - - + {step == 1 && ( @@ -464,6 +437,6 @@ export default hocAuth(function Page(props: CommonComponent) { - + ); }); diff --git a/packages/app-client/src/pages/delivery/document/purchase.config.ts b/packages/app-client/src/pages/delivery/document/purchase.config.ts deleted file mode 100644 index 41c4dc2..0000000 --- a/packages/app-client/src/pages/delivery/document/purchase.config.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default definePageConfig({ - navigationBarTitleText: "采购底单单据生成", - navigationBarBackgroundColor: "#fff", -}); diff --git a/packages/app-client/src/pages/delivery/document/purchase.tsx b/packages/app-client/src/pages/delivery/document/purchase.tsx deleted file mode 100644 index cea6739..0000000 --- a/packages/app-client/src/pages/delivery/document/purchase.tsx +++ /dev/null @@ -1,390 +0,0 @@ -import hocAuth from "@/hocs/auth"; -import { CommonComponent } from "@/types/typings"; -import { useEffect, useRef, useState } from "react"; -import { View } from "@tarojs/components"; -import { Button, Dialog, SafeArea, Step, Steps } from "@nutui/nutui-react-taro"; -import shipOrder from "@/constant/orderShip"; -import Taro from "@tarojs/taro"; -import classNames from "classnames"; -import { business, poster } from "@/services"; -import { buildUrl, PdfTemplate } from "@/utils"; -import { - Icon, - PurchaseStep1Form, - PurchaseStep1FormRef, - PurchaseStep2Preview, - PurchaseStep3Success, -} from "@/components"; - -export default hocAuth(function Page(props: CommonComponent) { - const { router, setLoading } = props; - const orderId = router.params - .orderId as BusinessAPI.PurchaseOrderVO["orderId"]; - - const [step, setStep] = useState(1); - const [moduleList, setModuleList] = useState([]); - const [document, setDocument] = - useState(); - const [height, setHeight] = useState(); - const [purchaseOrderVO, setPurchaseOrderVO] = - useState(); - const [shipOrderVO, setShipOrderVO] = useState(); - - const step1FormRef = useRef(null); - - const init = async (orderId: BusinessAPI.PurchaseOrderVO["orderId"]) => { - setLoading(true); - const { - data: { data: purchaseOrderVO }, - } = await business.purchaseOrder.showPurchaseOrder({ - purchaseOrderShowQry: { - orderId, - }, - }); - setPurchaseOrderVO(purchaseOrderVO); - setLoading(false); - }; - - useEffect(() => { - if (orderId) { - init(orderId).then(); - } - }, [orderId]); - - // 预览确认 - const previewAndConfirm = () => { - if (step === 2) { - // 显示确认对话框 - Dialog.open("dialog", { - title: "生成发货单据", - content: "即将生成发货单据,请确认发货单据是否正确。", - confirmText: "确认生成", - cancelText: "取消", - onConfirm: async () => { - // 截图预览内容 - await capturePreview(); - Dialog.close("dialog"); - // 进入第三步 - setStep(3); - }, - onCancel: () => { - Dialog.close("dialog"); - }, - }); - return; - } - - if (step === 1) { - // 调用 Step1Form 的表单校验方法 - if (step1FormRef.current && step1FormRef.current.validateForm()) { - setStep(2); - } - return; - } - - if (step < 3) { - setStep(step + 1); - } - }; - - // 生成发货单据 - const generateShippingDocument = async () => { - // 显示确认对话框 - Dialog.open("dialog", { - title: "生成发货单据", - content: "即将生成发货单据,请确认发货单据是否正确。", - confirmText: "确认生成", - cancelText: "取消", - onConfirm: async () => { - // 截图预览内容 - await capturePreview(); - Dialog.close("dialog"); - // 进入第三步 - setStep(3); - }, - onCancel: () => { - Dialog.close("dialog"); - }, - }); - }; - - // 截图预览内容 - const capturePreview = async () => { - const template = new PdfTemplate(moduleList); - console.log("generateHtmlString", template.generateHtmlString()); - const { data } = await poster.pdf.postApiV1Pdf({ - html: template.generateHtmlString(), - }); - - // 存储 至 shipOrder previewUrl - if (shipOrderVO) { - let formData: BusinessAPI.OrderShipGenerateDocumentCmd = { - orderShipId: shipOrderVO?.orderShipId, - document: data?.data?.path, - }; - // 检查各模块中的必填字段是否已填写 - for (const module of moduleList) { - const contentSchema = module.schemas.find( - (schema) => schema.title === "内容配置", - ); - - if ( - !contentSchema || - !contentSchema.columns || - contentSchema.columns.length === 0 - ) { - continue; - } - - for (const column of contentSchema.columns) { - // 检查西瓜品级字段是否开启且已填写 - if (column.dataIndex === "requiredWatermelonGrade") { - formData.watermelonGrade = shipOrderVO?.watermelonGrade; - } - // 检查发货地字段是否开启且已填写 - else if (column.dataIndex === "requiredShippingFrom") { - formData.shippingAddress = shipOrderVO?.shippingAddress; - } - // 检查预计到仓时间字段是否开启且已填写 - else if (column.dataIndex === "requiredEstimatedArrivalTime") { - formData.estimatedArrivalDate = shipOrderVO?.estimatedArrivalDate; - } - // 检查备注字段是否开启且已填写 - else if (column.dataIndex === "requiredRemarks") { - formData.remark = shipOrderVO?.remark; - } - // 检查品级字段是否开启且已填写 - else if (column.dataIndex === "requiredGrade") { - formData.orderShipItemList = shipOrderVO?.orderShipItemList; - } - } - } - business.orderShip.generateDocumentOrderShip(formData).then(); - } - - if (data && data?.data?.path) { - setDocument(data?.data?.path); - } - }; - - // 返回上一步 - const goToPrevStep = () => { - if (step > 0) { - setStep(step - 1); - } - }; - - // 重置表单 - const resetForm = () => { - setStep(1); - // 重新加载初始数据 - if (orderId) { - init(orderId).then(); - } - }; - - // 重新生成单据 - const regenerateDocument = () => { - setStep(1); - }; - - const [topBarHeight, setTopBarHeight] = useState(0); - const [bottomBarHeight, setBottomBarHeight] = useState(0); - const topBarRef = useRef(null); - const bottomBarRef = useRef(null); - - useEffect(() => { - // 获取 topBar 和 bottomBar 的实际高度 - const queryTopBar = Taro.createSelectorQuery(); - queryTopBar - .select("#topBar") - .boundingClientRect((rect: any) => { - if (rect) { - setTopBarHeight(rect.height); - } - }) - .exec(); - - const queryBottomBar = Taro.createSelectorQuery(); - queryBottomBar - .select("#bottomBar") - .boundingClientRect((rect: any) => { - if (rect) { - setBottomBarHeight(rect.height); - } - }) - .exec(); - }, [step]); - - useEffect(() => { - // 计算滚动区域高度:窗口高度 - topBar高度 - bottomBar高度 - const windowHeight = Taro.getSystemInfoSync().windowHeight; - setHeight(windowHeight - topBarHeight - bottomBarHeight); - }, [topBarHeight, bottomBarHeight]); - - if (!purchaseOrderVO) { - return; - } - - return ( - - - - - - {shipOrder.steps.map((item, index) => ( - - ))} - - - - - - - {step === 1 && ( - - - - - - - 添加分单 - - - - - 黄花仓 - - - - - 晋州仓 - - - - - 石家庄仓 - - - - - 保定仓 - - - - - 唐山仓 - - - - - - - - - )} - - {step === 2 && } - - {step === 3 && document && } - - - - - {step == 1 && ( - - - - )} - {step == 1 && ( - - - - )} - {step == 2 && ( - - - - )} - {step == 2 && ( - - - - )} - {step == 3 && ( - - - - )} - {step == 3 && ( - - - - )} - - - - - ); -}); diff --git a/packages/app-client/src/services/business/typings.d.ts b/packages/app-client/src/services/business/typings.d.ts index 61dd3be..8fae0ae 100644 --- a/packages/app-client/src/services/business/typings.d.ts +++ b/packages/app-client/src/services/business/typings.d.ts @@ -3131,7 +3131,9 @@ declare namespace BusinessAPI { /** 瓜农姓名逗号隔开 */ farmerInfo?: string; /** 发货单据 */ - document: string; + pdfUrl: string; + picUrl: string; + /** 发货单状态:0_草稿;1_待发货;2_待回款;3_待改签;4_部分回款;5_已回款;6_拒收完结;7_已完结; */ state: | "DRAFT" @@ -3200,7 +3202,9 @@ declare namespace BusinessAPI { /** 发货单明细 */ orderShipItemList?: OrderShipItem[]; /** 发货单据 */ - document?: string; + picUrl?: string; + /** 发货单据 */ + pdfUrl?: string; }; type OrderShipItem = { diff --git a/packages/app-client/src/services/poster/poster.ts b/packages/app-client/src/services/poster/poster.ts index c7f7d7f..1bbce79 100644 --- a/packages/app-client/src/services/poster/poster.ts +++ b/packages/app-client/src/services/poster/poster.ts @@ -19,6 +19,7 @@ export async function postApiV1Poster( type?: string; /** 编码类型 */ encoding?: string; + format?: 'custom' | 'a4'; }, options?: { [key: string]: any }, ) {