Opendocument时, KEY DATE参数传递的问题

今天遇到一问题, 通过OPENDOCUMENT.JSP打开WEBI报表时, 普通的参数都可以传进去. 可是KEY DATE无法传递. 查了一下SDN, 找到一个方法, 下午试一下.
1/ 先修改UNIVERSE的参数设置, 将KEYDATE_DEFAULT_VALUE" and KEYDATE_ENABLED 设置 "No".
2/ 在UNIVERSE上增加一个FILTER. 过滤关键日期对应的IO.

原文(https://forums.sdn.sap.com/thread.jspa?messageID=7748811):
There is 5 parameters, which describe a key date in a Designer:
KEYDATE_CAPTION
KEYDATE_DEFAULT_VALUE
KEYDATE_ENABLED
KEYDATE_MANDATORY
KEYDATE_NAME
You can get them in file -> parameters -> Parameter.
I filled out the field "KEYDATE_DEFAULT_VALUE" and KEYDATE_ENABLED I set "No".
Then go to filters in your univers.
Open the required filter and add this line before last </OPERATOR>:
<FILTER KEY="0P_KEYDA"><CONDITION OPERATORCONDITION="Equal"><CONSTANT TECH_NAME="@Prompt('Key Date:','D',,,)"/></CONDITION></FILTER>.
you should get approximately the following:

<OPERATOR VALUE="AND"><FILTER KEY="!V000003"><CONDITION OPERATORCONDITION="Between"><CONSTANT TECH_NAME="@Prompt('Балансовая единица From','A',,,)"/><CONSTANT TECH_NAME="@Prompt('Балансовая единица To','A',,,)"/></CONDITION></FILTER><FILTER KEY="!V000002"><CONDITION OPERATORCONDITION="Equal"><CONSTANT TECH_NAME="@Prompt('Главная БЕ (опции выбора, обязательно)','A',,,)"/></CONDITION></FILTER><FILTER KEY="0P_KEYDA"><CONDITION OPERATORCONDITION="Equal"><CONSTANT TECH_NAME="@Prompt('Key Date','D',,,)"/></CONDITION></FILTER></OPERATOR>

Then save and export univers.

This should help.
Timur Khayaliev


补充: 在DESIGNER里, 应先到UNIVERSE里的属性里, 找到KEY_DATE对应的变量名称或信息对象名称, 再根据这个名称建FILTER, 建完FILTER后, 该FILTER无法通过DESIGNER的分析检查, 但是不影响正常的使用(奇怪的问题).
PDF 下载错误详情:, TypeError: undefined is not a function (near &#39;...uni.base64ToPath...&#39;) at pages/home/components/Imagepreview.vue:800 __ERROR <template> <view class="evidence-card-container"> <!-- 原有卡片布局 --> <view class="card-row"> <view class="card-item" v-for="(item, index) in evidenceList.slice(0, 3)" :key="index" @click="handleClick(item)" > <image v-if="item.icon" class="item-icon" :src="item.icon" mode="aspectFit" /> <text class="item-text">{{ item.text }}</text> </view> </view> <view class="card-row"> <view class="card-item" v-for="(item, index) in evidenceList.slice(3, 6)" :key="index + 3" @click="handleClick(item)" > <image v-if="item.icon" class="item-icon" :src="item.icon" mode="aspectFit" /> <text class="item-text">{{ item.text }}</text> </view> </view> <!-- 拍照预览弹窗 --> <view v-if="showPhotoPreview" class="photo-preview-mask"> <view class="preview-content"> <!-- 图片预览区域 --> <image class="preview-image" :src="currentPreviewImg" mode="aspectFit" @click="handleImageClick" ></image> <!-- 底部操作按钮 --> <view class="preview-footer"> <button class="preview-btn cancel-btn" @click="cancelPreview">取消</button> <button class="preview-btn confirm-btn" @click="confirmPreview">固化</button> </view> </view> </view> </view> </template> <script setup lang="ts"> import { ref } from &#39;vue&#39; const showPhotoPreview = ref(false) // 控制预览弹窗显示 const currentPreviewImg = ref(&#39;&#39;) // 当前预览的图片地址 const tempPhotoPath = ref(&#39;&#39;) // 临存储拍照路径(用于H5) // 定义单个卡片数据结构 interface EvidenceItem { text: string icon?: string // 图标地址,可选 action?: () => void // 点击回调,可选 } // 合并所有取证选项到一个列表 const evidenceList = ref<EvidenceItem[]>([ { text: &#39;拍照取证&#39;, icon: &#39;/static/home/ObtainEvidence/takepictures.svg&#39; }, { text: &#39;录像取证&#39;, icon: &#39;/static/home/ObtainEvidence/picturerecording.svg&#39; }, { text: &#39;录音取证&#39;, icon: &#39;/static/home/ObtainEvidence/soundrecording.svg&#39; }, { text: &#39;网页取证&#39;, icon: &#39;/static/home/ObtainEvidence/Webpage.svg&#39; }, { text: &#39;录屏取证&#39;, icon: &#39;/static/home/ObtainEvidence/screencap.svg&#39; }, { text: &#39;委托取证&#39;, icon: &#39;/static/home/ObtainEvidence/commission.svg&#39; }, ]) const showProgress = ref(false) // 控制进度条是否显示 const progress = ref(0) // 上传进度(0-100) const isUploading = ref(false) // 标记是否正在上传(避免重复上传) // 录像取证 const uploadVideo = (filePath: string, duration: number, size: number) => { // 1. 处理文件名 const originalFileName = filePath.substring(filePath.lastIndexOf(&#39;/&#39;) + 1) const fileExtension = originalFileName.includes(&#39;.&#39;) ? originalFileName.split(&#39;.&#39;).pop() : &#39;mp4&#39; const timestamp = new Date().getTime() const newFileName = `video_evidence_${timestamp}.${fileExtension}` // 2. 显示进度 showProgress.value = true progress.value = 0 isUploading.value = true // 3. 显示加载提示 let loadingVisible = false // 标记loading是否显示 const showLoading = (title: string) => { if (!loadingVisible) { uni.showLoading({ title, mask: true }) loadingVisible = true } else { // uni.setLoadingText(title); // 已有loading,只更新文本 } } showLoading(&#39;准备上传...&#39;) // 4. 创建上传任务 const uploadTask = uni.uploadFile({ // url: &#39;http://192.168.1.80:1592/api/upload&#39;, url: &#39;http://192.168.0.111:1592/api/upload&#39;, filePath: filePath, name: &#39;file&#39;, formData: { originalFileName: originalFileName, customFileName: newFileName, duration: duration, size: size, type: &#39;video&#39;, uploadTime: new Date().toISOString(), }, header: { // &#39;Authorization&#39;: &#39;Bearer your-token-here&#39; // 如果需要身份验证 }, timeout: 300000, // 5分钟超 success: (uploadRes) => { console.log(&#39;上传成功,原始响应:&#39;, uploadRes.data) try { const data = JSON.parse(uploadRes.data) if (data.code === 200) { if (loadingVisible) { uni.hideLoading() loadingVisible = false } // 显示成功提示 uni.showModal({ title: &#39;固化成功!&#39;, content: &#39;您的证据已保存至“我的证据”&#39;, confirmText: &#39;查看证据&#39;, cancelText: &#39;继续取证&#39;, success: (res) => { if (res.confirm) { // 后端返回的单个证据对象(含 base64Data、webpagePdfBase64 等字段) const singleEvidence = { ...data.data, // 合并previewImage、filePreview等基础信息 // 明确提取PDF相关字段(关键:以你的后端实际返回层级为准) pdfData : data.data.pdfData, // 若后端在data.data下 webpagePdfBase64: data.data.webpagePdfBase64 , // 补充必要字段(确保详情页能正常显示) evidenceType: data.data.evidenceType, evidenceName: data.data.evidenceName, acquisitionTime: data.data.acquisitionTime, // 取证间(后端未返回则前端生成) timestamp: new Date().getTime() // 用于生成唯一storageKey }; const storageKey = `evidence_single_${singleEvidence.timestamp}`; // 存储完整数据到本地 uni.setStorageSync(storageKey, singleEvidence); console.log(&#39;存储的完整证据数据:&#39;, singleEvidence); // 跳转传递 storageKey uni.navigateTo({ url: `/pages/home/components/Imagepreview?storageKey=${storageKey}` }); // 清理临数据 cancelPreview(); } else { uni.navigateTo({ url: &#39;/pages/home/home&#39; }); } } }); } else { throw new Error(data.msg || `上传失败,状态码: ${data.code}`) } } catch (e) { console.error(&#39;解析响应失败&#39;, e) if (loadingVisible) { uni.hideLoading() loadingVisible = false } // 显示错误提示 uni.showToast({ title: e.message || &#39;处理响应失败&#39;, icon: &#39;none&#39;, duration: 3000, }) } }, fail: (err) => { console.error(&#39;上传失败:&#39;, err) if (loadingVisible) { uni.hideLoading() loadingVisible = false } // 显示失败提示 uni.showToast({ title: `上传失败: ${err.errMsg || &#39;网络错误&#39;}`, icon: &#39;none&#39;, duration: 3000, }) }, complete: () => { // 确保loading被关闭 if (loadingVisible) { uni.hideLoading() loadingVisible = false } showProgress.value = false isUploading.value = false }, }) // 5. 监听上传进度 uploadTask.onProgressUpdate((res) => { console.log(&#39;上传进度:&#39;, res.progress) progress.value = res.progress }) } //拍照取证 const takePhotoAndPreviewPDF = () => { // #ifdef APP uni.chooseImage({ count: 1, sizeType: [&#39;compressed&#39;], sourceType: [&#39;camera&#39;], // 仅调用相机 success: (res) => { console.log(&#39;APP端拍照成功,临路径:&#39;, res.tempFilePaths[0]); const tempFilePath = res.tempFilePaths[0]; tempPhotoPath.value = tempFilePath; currentPreviewImg.value = tempFilePath; showPhotoPreview.value = true; // 显示预览弹窗 }, fail: (err) => { console.error(&#39;APP端相机调用失败:&#39;, err); // 若用户拒绝权限,引导去设置页 if (err.errMsg.includes(&#39;deny&#39;) || err.errMsg.includes(&#39;denied&#39;)) { uni.showModal({ title: &#39;权限不足&#39;, content: &#39;拍照取证需要相机权限,请在手机设置中开启&#39;, confirmText: &#39;去设置&#39;, success: (res) => { if (res.confirm) uni.openSetting(); // 打开应用设置 } }); } else { uni.showToast({ title: `拍照失败:${err.errMsg}`, icon: &#39;none&#39; }); } } }); // #endif // #ifdef H5 uni.chooseImage({ count: 1, sizeType: [&#39;original&#39;, &#39;compressed&#39;], sourceType: [&#39;camera&#39;], success: async (res) => { console.log(&#39;H5拍照结果:&#39;, res.tempFilePaths) const tempFilePath = res.tempFilePaths[0] tempPhotoPath.value = tempFilePath // 存储临路径 currentPreviewImg.value = tempFilePath // 直接使用本地临路径预览 showPhotoPreview.value = true // 显示预览弹窗 }, fail: (err) => { console.error(&#39;H5拍照失败:&#39;, err) uni.showToast({ title: &#39;拍照失败&#39;, icon: &#39;none&#39; }) } }) //// #endif } const handleImageClick = () => { // showPhotoPreview.value = false } // 取消预览 const cancelPreview = () => { showPhotoPreview.value = false currentPreviewImg.value = &#39;&#39; tempPhotoPath.value = &#39;&#39; } // 确认预览(可扩展为提交证据等操作) const confirmPreview = () => { // 1. 校验:无图片路径或正在上传,不执行操作 if (!tempPhotoPath.value || isUploading.value) return; // 2. 处理文件名(与APP端格式一致) const originalFileName = tempPhotoPath.value.substring(tempPhotoPath.value.lastIndexOf(&#39;/&#39;) + 1); const fileExtension = originalFileName.includes(&#39;.&#39;) ? originalFileName.split(&#39;.&#39;).pop() : &#39;jpg&#39;; const timestamp = new Date().getTime(); const newFileName = `evidence_${timestamp}.${fileExtension}`; // 3. 初始化上传状态 showProgress.value = true; progress.value = 0; isUploading.value = true; uni.showLoading({ title: &#39;图片上传中...&#39;, mask: true }); // 4. 调用后端接口上传图片 const uploadTask = uni.uploadFile({ // url: &#39;http://192.168.1.80:1592/api/upload&#39;, url: &#39;http://192.168.0.111:1592/api/upload&#39;, filePath: tempPhotoPath.value, name: &#39;file&#39;, formData: { originalFileName: originalFileName, customFileName: newFileName, type: &#39;image&#39;, uploadTime: new Date().toISOString() }, timeout: 15000, // 15秒超(图片上传合理长) success: (uploadFileRes) => { console.log(&#39;确认上传-后端原始响应:&#39;, uploadFileRes.data); try { const data = JSON.parse(uploadFileRes.data); if (data.code === 200) { uni.navigateTo({ url: &#39;/pages/home/home&#39; }); uni.showModal({ title: &#39;固化成功!&#39;, content: &#39;您的证据已保存至“我的证据”&#39;, confirmText: &#39;查看证据&#39;, cancelText: &#39;继续取证&#39;, success: (res) => { if (res.confirm) { // 后端返回的单个证据对象(含 base64Data、webpagePdfBase64 等字段) const singleEvidence = { ...data.data, // 合并previewImage、filePreview等基础信息 // 明确提取PDF相关字段(关键:以你的后端实际返回层级为准) pdfData : data.data.pdfData, // 若后端在data.data下 webpagePdfBase64: data.data.webpagePdfBase64 , // 补充必要字段(确保详情页能正常显示) evidenceType: data.data.evidenceType, evidenceName: data.data.evidenceName, acquisitionTime: data.data.acquisitionTime, // 取证间(后端未返回则前端生成) timestamp: new Date().getTime() // 用于生成唯一storageKey }; const storageKey = `evidence_single_${singleEvidence.timestamp}`; // 存储完整数据到本地 uni.setStorageSync(storageKey, singleEvidence); console.log(&#39;存储的完整证据数据:&#39;, singleEvidence); // 跳转传递 storageKey uni.navigateTo({ url: `/pages/home/components/Imagepreview?storageKey=${storageKey}` }); // 清理临数据 cancelPreview(); } else { uni.navigateTo({ url: &#39;/pages/home/home&#39; }); } } }); uni.hideLoading() } else { throw new Error(data.msg || `上传失败,状态码: ${data.code}`); } } catch (e) { uni.hideLoading(); uni.showToast({ title: `解析失败: ${e.message}`, icon: &#39;none&#39;, duration: 3000 }); } }, fail: (err) => { // 9. 上传失败处理(网络错误等) console.error(&#39;H5确认上传-失败:&#39;, err); uni.hideLoading(); uni.showToast({ title: `上传失败: ${err.errMsg}`, icon: &#39;none&#39;, duration: 3000 }); }, complete: () => { // 10. 无论成功失败,重置状态 showProgress.value = false; isUploading.value = false; } }); // 11. 监听上传进度(更新进度条) uploadTask.onProgressUpdate((res) => { progress.value = res.progress; }); }; //视频取证 const takevideo = () => { uni.chooseVideo({ sourceType: [&#39;camera&#39;], compressed: true, maxDuration: 180, camera: &#39;back&#39;, success: (res) => { console.log(&#39;录像结果:&#39;, res.tempFilePath) if (!res.tempFilePath) { uni.showToast({ title: &#39;未获取到视频文件&#39;, icon: &#39;none&#39; }) return } // 检查视频大小 (限制为100MB) if (res.size > 100 * 1024 * 1024) { uni.showToast({ title: &#39;视频大小不能超过100MB&#39;, icon: &#39;none&#39; }) return } // 准备上传 uploadVideo(res.tempFilePath, res.duration, res.size) }, fail: (err) => { console.error(&#39;录像失败:&#39;, err) uni.showToast({ title: &#39;录像失败&#39;, icon: &#39;none&#39;, }) }, }) } // const downloadAndPreview = (pdfUrl) => { uni.downloadFile({ url: pdfUrl, success: (res) => { if (res.statusCode === 200) { uni.openDocument({ filePath: res.tempFilePath, success: () => console.log(&#39;预览成功&#39;), fail: (err) => console.error(&#39;打开失败&#39;, err), }) } }, }) } // 点击事件处理 const handleClick = (item: EvidenceItem) => { console.log(`点击了:${item.text}`) if (item.action) { item.action() // 如果有自定义回调,优先执行 return } // 默认处理逻辑 switch (item.text) { case &#39;拍照取证&#39;: takePhotoAndPreviewPDF() break case &#39;录像取证&#39;: takevideo() break case &#39;录音取证&#39;: uni.showToast({ title: &#39;录音取证功能开发中&#39;, icon: &#39;none&#39;, }) break case &#39;网页取证&#39;: uni.navigateTo({ url: &#39;/pages/home/components/Webforensics&#39; }) break case &#39;录屏取证&#39;: // uni.showToast({ // title: &#39;录屏取证功能开发中&#39;, // icon: &#39;none&#39; // }); uni.navigateTo({ url: &#39;/pages/home/components/Screenrecord&#39; }) break case &#39;委托取证&#39;: uni.showToast({ title: &#39;请联系客服&#39;, icon: &#39;none&#39;, }) break default: console.warn(&#39;未知的取证类型:&#39;, item.text) } } </script> <style scoped> .evidence-card-container { } .card-row { display: flex; flex-direction: row; justify-content: space-around; margin-bottom: 30rpx; } .card-row:last-child { margin-bottom: 0; } .card-item { width: 30%; background-color: #ffffff; display: flex; flex-direction: column; align-items: center; border-radius: 16rpx; text-align: center; margin-right: 20rpx; padding: 20rpx 10rpx; box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); transition: all 0.3s ease; } .card-item:last-child { margin-right: 0; } /* .card-item:hover { transform: translateY(-3rpx); box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.15); } */ .item-icon { width: 80rpx; height: 80rpx; margin-bottom: 10rpx; } .item-text { font-size: 24rpx; color: #333; line-height: 1.4; } .photo-preview-mask { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-color: rgba(0, 0, 0, 1); z-index: 9999; display: flex; flex-direction: column; align-items: center; justify-content: center; } .preview-content { width: 90%; max-width: 600px; position: relative; } .preview-image { width: 100%; height: 90vh; object-fit: contain; margin-bottom: 20px; border-radius: 8px; } .preview-footer { width: 100%; display: flex; justify-content: space-between; } .preview-btn { flex: 1; height: 44px; line-height: 44px; border-radius: 8px; font-size: 16px; margin: 0 10px; } .cancel-btn { background-color: #2e8bff; color: #fff; } .confirm-btn { background-color: #2e8bff; color: #fff; } </style>
08-29
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值