|
|
@@ -1,682 +1,1161 @@
|
|
|
-<!DOCTYPE html>
|
|
|
-<html lang="zh-CN">
|
|
|
-<head>
|
|
|
- <meta charset="UTF-8">
|
|
|
- <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
|
|
- <title>审核</title>
|
|
|
- <script src="/js/mp_base/base.js"></script>
|
|
|
-
|
|
|
- <style>
|
|
|
- /* 防止Vue模板闪烁 */
|
|
|
- [v-cloak] {
|
|
|
- display: none !important;
|
|
|
- }
|
|
|
-
|
|
|
- #app {
|
|
|
- background: #f5f5f5;
|
|
|
- height: 100vh;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- overflow: hidden; /* 防止页面级别滚动 */
|
|
|
- box-sizing: border-box; /* 确保padding计算在高度内 */
|
|
|
- }
|
|
|
-
|
|
|
- /* iframe样式 */
|
|
|
- .top-iframe {
|
|
|
- background: #fff;
|
|
|
- overflow: hidden;
|
|
|
- border: none;
|
|
|
- display: block;
|
|
|
- box-sizing: border-box;
|
|
|
- }
|
|
|
-
|
|
|
- .bottom-iframe {
|
|
|
- background: #fff;
|
|
|
- overflow: hidden;
|
|
|
- border: none;
|
|
|
- display: block;
|
|
|
- box-sizing: border-box;
|
|
|
- }
|
|
|
-
|
|
|
- .title{
|
|
|
- flex-shrink: 0;
|
|
|
- box-sizing: border-box;
|
|
|
- font-size: 16px;
|
|
|
- text-align: center;
|
|
|
- /* margin: 16px auto; */
|
|
|
- height: 48px;
|
|
|
- line-height: 48px;
|
|
|
- }
|
|
|
-
|
|
|
- /* 录入div样式 */
|
|
|
- .review-input-popup {
|
|
|
- position: fixed;
|
|
|
- bottom: 0;
|
|
|
- left: 0;
|
|
|
- right: 0;
|
|
|
- height: 50px;
|
|
|
- background: #e6e6e6;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- padding: 0 0 0 10px;
|
|
|
- z-index: 1000;
|
|
|
- transform: translateY(100%);
|
|
|
- transition: transform 0.3s ease;
|
|
|
- box-sizing: border-box;
|
|
|
- }
|
|
|
-
|
|
|
- .review-input-popup.show {
|
|
|
- transform: translateY(0);
|
|
|
- }
|
|
|
-
|
|
|
- .review-input-wrapper {
|
|
|
- flex: 1;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 4px;
|
|
|
- }
|
|
|
-
|
|
|
- .review-input {
|
|
|
- flex: 1;
|
|
|
- height: 32px;
|
|
|
- border: none;
|
|
|
- padding: 0 10px;
|
|
|
- font-size: 16px;
|
|
|
- background: #fff;
|
|
|
- outline: none;
|
|
|
- box-sizing: border-box;
|
|
|
- }
|
|
|
-
|
|
|
- .common-phrases-btn {
|
|
|
- padding: 6px 12px;
|
|
|
- background: #fff;
|
|
|
- border: none;
|
|
|
- font-size: 16px;
|
|
|
- color: #333;
|
|
|
- cursor: pointer;
|
|
|
- white-space: nowrap;
|
|
|
- margin-right: 4px;
|
|
|
- }
|
|
|
-
|
|
|
- .common-phrases-btn:hover {
|
|
|
- background: #e0e0e0;
|
|
|
- }
|
|
|
-
|
|
|
- .submit-btn {
|
|
|
- box-sizing: border-box;
|
|
|
- height: 50px;
|
|
|
- padding: 6px 16px;
|
|
|
- border: none;
|
|
|
- font-size: 16px;
|
|
|
- color: #fff;
|
|
|
- cursor: pointer;
|
|
|
- white-space: nowrap;
|
|
|
- transition: background-color 0.2s;
|
|
|
- }
|
|
|
-
|
|
|
- .submit-btn.agree {
|
|
|
- background: #585e6e;
|
|
|
- }
|
|
|
-
|
|
|
- .submit-btn.agree:active {
|
|
|
- background: #242835;
|
|
|
- }
|
|
|
-
|
|
|
- .submit-btn.reject {
|
|
|
- background: #e58846;
|
|
|
- }
|
|
|
-
|
|
|
- .submit-btn.reject:active {
|
|
|
- background: #eb6100;
|
|
|
- }
|
|
|
-
|
|
|
- /* 常用语popup */
|
|
|
- .common-phrases-popup {
|
|
|
- position: fixed;
|
|
|
- bottom: 50px;
|
|
|
- left: 10px;
|
|
|
- right: 10px;
|
|
|
- background: #fff;
|
|
|
- border-radius: 4px;
|
|
|
- box-shadow: 0 -2px 10px rgba(0,0,0,0.1);
|
|
|
- max-height: 200px;
|
|
|
- overflow-y: auto;
|
|
|
- z-index: 1001;
|
|
|
- display: none;
|
|
|
- }
|
|
|
-
|
|
|
- .common-phrases-popup.show {
|
|
|
- display: block;
|
|
|
- }
|
|
|
-
|
|
|
- .phrase-item {
|
|
|
- padding: 12px 16px;
|
|
|
- border-bottom: 1px solid #f0f0f0;
|
|
|
- cursor: pointer;
|
|
|
- font-size: 14px;
|
|
|
- }
|
|
|
-
|
|
|
- .phrase-item:hover {
|
|
|
- background: #f8f8f8;
|
|
|
- }
|
|
|
-
|
|
|
- .phrase-item:last-child {
|
|
|
- border-bottom: none;
|
|
|
- }
|
|
|
-
|
|
|
- /* 原ss-bottom隐藏 */
|
|
|
- .ss-bottom.hidden {
|
|
|
- display: none;
|
|
|
- }
|
|
|
- </style>
|
|
|
-</head>
|
|
|
-<body>
|
|
|
- <div id="app" v-cloak>
|
|
|
- <div class="title" @click="callApi">
|
|
|
- {{jdmc}}
|
|
|
- </div>
|
|
|
- <!-- 上方iframe - 基本信息区域 -->
|
|
|
- <iframe
|
|
|
- ref="topIframe"
|
|
|
- class="top-iframe"
|
|
|
- :src="`/page/mp_objInfo.html?sqid=${sqid}&shid=${shid}&bdlbm=${bdlbm}&dataType=${dataType}&encode_shid=${encode_shid}&ssObjName=${ssObjName}&ssObjId=${ssObjId}`"
|
|
|
- width="100%"
|
|
|
- frameborder="0">
|
|
|
- </iframe>
|
|
|
-
|
|
|
- <!-- 下方iframe - 审核列表区域 -->
|
|
|
- <iframe
|
|
|
- ref="bottomIframe"
|
|
|
- class="bottom-iframe"
|
|
|
- :src="`/page/mp_shList.html?sqid=${sqid}&shid=${shid}&bdlbm=${bdlbm}&dataType=${dataType}&encode_shid=${encode_shid}&ssObjName=${ssObjName}&ssObjId=${ssObjId}`"
|
|
|
- width="100%"
|
|
|
- frameborder="0">
|
|
|
- </iframe>
|
|
|
-
|
|
|
- <!-- 底部按钮 -->
|
|
|
- <ss-bottom
|
|
|
- :show-shyj="false"
|
|
|
- :buttons="bottomButtons"
|
|
|
- @button-click="handleBottomAction"
|
|
|
- :divider="false"
|
|
|
- :disabled="submitting"
|
|
|
- v-if="bottomButtons.length > 0"
|
|
|
- ></ss-bottom>
|
|
|
- </div>
|
|
|
-
|
|
|
- <script>
|
|
|
- // 等待SS框架加载完成
|
|
|
- window.SS.ready(function () {
|
|
|
- // 使用SS框架的方式创建Vue实例
|
|
|
- window.SS.dom.initializeFormApp({
|
|
|
- el: '#app',
|
|
|
- data() {
|
|
|
- return {
|
|
|
- pageParams: {},
|
|
|
- loading: false,
|
|
|
- jdmc:'',
|
|
|
- sqid: '',
|
|
|
- shid: '',
|
|
|
- bdlbm: '',
|
|
|
- dataType:'bdplay',
|
|
|
- encode_shid:'',
|
|
|
- ssObjName:'',
|
|
|
- ssObjId:'',
|
|
|
- agrCcData: null, // 存储agrCc返回的数据
|
|
|
-
|
|
|
-
|
|
|
- // 底部按钮相关
|
|
|
- submitting: false,
|
|
|
- bottomButtons: [],
|
|
|
-
|
|
|
- // iframe布局相关
|
|
|
- layoutCalculated: false,
|
|
|
- headerSectionHeight: 0,
|
|
|
- availableHeight: 0,
|
|
|
- topIframeHeight: 0,
|
|
|
- bottomIframeHeight: 0,
|
|
|
- bottomIframeMinHeight: 0,
|
|
|
- isExpanded: false,
|
|
|
-
|
|
|
- // 拖拽相关
|
|
|
- isDragging: false,
|
|
|
- dragStartY: 0,
|
|
|
- dragStartBottomHeight: 0,
|
|
|
- }
|
|
|
- },
|
|
|
- mounted() {
|
|
|
- // 获取URL参数
|
|
|
- this.pageParams = this.getUrlParams()
|
|
|
- console.log('🔗 mp_ccChk页面接收到参数:', this.pageParams)
|
|
|
-
|
|
|
- // 打印所有参数到控制台
|
|
|
- Object.keys(this.pageParams).forEach(key => {
|
|
|
- console.log(`参数 ${key}:`, this.pageParams[key])
|
|
|
- })
|
|
|
-
|
|
|
- this.callApi()
|
|
|
-
|
|
|
- // 添加iframe消息监听器
|
|
|
- window.addEventListener('message', this.handleIframeMessage)
|
|
|
-
|
|
|
- // 初始化布局计算
|
|
|
- this.$nextTick(() => {
|
|
|
- setTimeout(() => {
|
|
|
- this.initializeLayout()
|
|
|
- }, 500) // 等待iframe加载完成
|
|
|
- })
|
|
|
- },
|
|
|
- beforeDestroy() {
|
|
|
- // 清理事件监听器
|
|
|
- window.removeEventListener('message', this.handleIframeMessage)
|
|
|
- },
|
|
|
- methods: {
|
|
|
- // 获取URL参数
|
|
|
- getUrlParams() {
|
|
|
- const params = {}
|
|
|
- const urlSearchParams = new URLSearchParams(window.location.search)
|
|
|
- for (const [key, value] of urlSearchParams) {
|
|
|
- params[key] = decodeURIComponent(value)
|
|
|
- }
|
|
|
- return params
|
|
|
- },
|
|
|
-
|
|
|
- // 调用API
|
|
|
- async callApi() {
|
|
|
- if (!this.pageParams.ssToken) {
|
|
|
- alert('未找到ssToken参数')
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- this.loading = true
|
|
|
- this.apiResult = null
|
|
|
-
|
|
|
- try {
|
|
|
- console.log('🚀 开始调用API,ssToken:', this.pageParams.ssToken)
|
|
|
- const apiResponse = await request.post(
|
|
|
- `/service?ssToken=${this.pageParams.ssToken}`,
|
|
|
- {},
|
|
|
- { loading: false }
|
|
|
- )
|
|
|
- console.log('✅ 原有API响应:', apiResponse)
|
|
|
- this.sqid = apiResponse.data.sqid
|
|
|
- this.shid = apiResponse.data.shid
|
|
|
- this.ssObjName = apiResponse.data.ssObjName
|
|
|
- this.ssObjId = apiResponse.data.ssObjId
|
|
|
- this.bdlbm = apiResponse.data.bdlbm
|
|
|
- this.jdmc = decodeURIComponent(apiResponse.data.jdmc)
|
|
|
-
|
|
|
-
|
|
|
- console.log('📋 调用dataTag服务获取agrCc数据...')
|
|
|
- const agrCcResponse = await request.post(
|
|
|
- `/service?ssServ=dataTag&ssDest=data&name=agrCc&ssObjName=${this.ssObjName}&ssObjId=${this.ssObjId}&sqid=${this.sqid}&shid=${this.shid}&bdlbm=${this.bdlbm}&dataType=${this.dataType}&encode_shid=${this.encode_shid}`,
|
|
|
-
|
|
|
- { loading: false,formData:true }
|
|
|
- )
|
|
|
-
|
|
|
- // 保存agrCc数据并设置底部按钮
|
|
|
- if (agrCcResponse && agrCcResponse.data && agrCcResponse.data.agrCc) {
|
|
|
- this.agrCcData = agrCcResponse.data.agrCc
|
|
|
- console.log('📦 agrCc数据:', this.agrCcData)
|
|
|
-
|
|
|
- // 根据agrCc数据设置底部按钮
|
|
|
- this.bottomButtons = [{
|
|
|
- text: '确认',
|
|
|
- action: 'submit',
|
|
|
- backgroundColor: '#585e6e',
|
|
|
- color: '#fff',
|
|
|
- clickBgColor: '#242835'
|
|
|
- }]
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- } catch (error) {
|
|
|
- console.error('❌ API调用失败:', error)
|
|
|
- } finally {
|
|
|
- this.loading = false
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- // 处理底部按钮点击
|
|
|
- handleBottomAction(data) {
|
|
|
- if (data.action === 'submit') {
|
|
|
- this.handleConfirm()
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- // 处理确认提交
|
|
|
- async handleConfirm() {
|
|
|
- if (!this.agrCcData) {
|
|
|
- alert('缺少必要的配置信息')
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- if (this.submitting) return
|
|
|
-
|
|
|
- try {
|
|
|
- this.submitting = true
|
|
|
- console.log('📝 开始提交...')
|
|
|
- console.log('📦 提交参数:', {
|
|
|
- service: this.agrCcData.service,
|
|
|
- dest: this.agrCcData.dest,
|
|
|
- shid: this.shid
|
|
|
- })
|
|
|
-
|
|
|
- const response = await request.post(
|
|
|
- `/service?ssServ=${this.agrCcData.service}&ssDest=${this.agrCcData.dest}`,
|
|
|
- { shid: this.shid },
|
|
|
- { loading: true, formData: true }
|
|
|
- )
|
|
|
- console.log('✅ 提交成功:', response)
|
|
|
-
|
|
|
-
|
|
|
- NavigationManager.goBack({ refreshParent: true })
|
|
|
-
|
|
|
-
|
|
|
- } catch (error) {
|
|
|
- console.error('❌ 提交失败:', error)
|
|
|
- alert('提交失败: ' + (error.message || '未知错误'))
|
|
|
- } finally {
|
|
|
- this.submitting = false
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- // ===== 布局相关方法 =====
|
|
|
- // 初始化布局计算
|
|
|
- initializeLayout() {
|
|
|
- console.log('🔄 开始初始化布局计算')
|
|
|
-
|
|
|
- try {
|
|
|
- // 获取bottom iframe
|
|
|
- const bottomIframe = document.querySelector('.bottom-iframe')
|
|
|
- const bottomWindow = bottomIframe?.contentWindow
|
|
|
-
|
|
|
- if (!bottomWindow) {
|
|
|
- console.error('无法获取bottom iframe的contentWindow')
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- // 等待iframe加载完成,然后检查header-section
|
|
|
- const waitForIframeLoad = () => {
|
|
|
- if (!bottomIframe.contentWindow) {
|
|
|
- console.log('⏳ 等待iframe contentWindow...')
|
|
|
- setTimeout(waitForIframeLoad, 100)
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- const bottomWindow = bottomIframe.contentWindow
|
|
|
- console.log('✅ 获取到iframe contentWindow')
|
|
|
-
|
|
|
- // 等待iframe中的DOM加载完成
|
|
|
- const checkHeaderSection = () => {
|
|
|
- try {
|
|
|
- const headerSection = bottomWindow.document.querySelector('.header-section')
|
|
|
- if (headerSection) {
|
|
|
- const headerHeight = headerSection.offsetHeight
|
|
|
- console.log('✅ 计算到header-section高度:', headerHeight)
|
|
|
-
|
|
|
- // 计算布局参数
|
|
|
- const viewportHeight = window.innerHeight
|
|
|
-
|
|
|
- // 动态获取title的实际高度
|
|
|
- const titleElement = document.querySelector('.title')
|
|
|
- const actualTitleHeight = titleElement ? titleElement.offsetHeight : 0
|
|
|
-
|
|
|
- // 等待bottom按钮渲染完成并获取实际高度
|
|
|
- const checkBottomButton = () => {
|
|
|
- try {
|
|
|
- const bottomElement = document.querySelector('ss-bottom')
|
|
|
- const actualBottomHeight = bottomElement ? bottomElement.offsetHeight : 50
|
|
|
-
|
|
|
- this.headerSectionHeight = headerHeight
|
|
|
- this.bottomIframeMinHeight = headerHeight
|
|
|
- this.availableHeight = viewportHeight - actualTitleHeight - actualBottomHeight
|
|
|
-
|
|
|
- // 初始状态:底部iframe刚好显示header-section高度
|
|
|
- this.bottomIframeHeight = this.bottomIframeMinHeight
|
|
|
- this.topIframeHeight = this.availableHeight - this.bottomIframeMinHeight
|
|
|
- this.isExpanded = false // 初始为收起状态
|
|
|
- this.layoutCalculated = true
|
|
|
-
|
|
|
- // 应用计算后的高度
|
|
|
- this.applyIframeHeights()
|
|
|
-
|
|
|
- console.log('📊 初始布局计算完成(仅显示header-section):', {
|
|
|
- '视口高度': viewportHeight,
|
|
|
- '标题实际高度': actualTitleHeight,
|
|
|
- '底部按钮实际高度': actualBottomHeight,
|
|
|
- '可用总高度': this.availableHeight,
|
|
|
- 'header-section高度': headerHeight,
|
|
|
- '上iframe高度': this.topIframeHeight,
|
|
|
- '下iframe高度': this.bottomIframeHeight,
|
|
|
- 'iframe总高度': this.topIframeHeight + this.bottomIframeHeight,
|
|
|
- '是否超限': (this.topIframeHeight + this.bottomIframeHeight) > this.availableHeight,
|
|
|
- '差额': (this.topIframeHeight + this.bottomIframeHeight) - this.availableHeight,
|
|
|
- isExpanded: this.isExpanded
|
|
|
- })
|
|
|
- } catch (bottomError) {
|
|
|
- console.error('❌ 获取底部按钮高度时出错:', bottomError)
|
|
|
- // 使用默认高度50px重试
|
|
|
- const defaultBottomHeight = 50
|
|
|
- this.headerSectionHeight = headerHeight
|
|
|
- this.bottomIframeMinHeight = headerHeight
|
|
|
- this.availableHeight = viewportHeight - actualTitleHeight - defaultBottomHeight
|
|
|
- this.bottomIframeHeight = this.bottomIframeMinHeight
|
|
|
- this.topIframeHeight = this.availableHeight - this.bottomIframeMinHeight
|
|
|
- this.isExpanded = false
|
|
|
- this.layoutCalculated = true
|
|
|
- this.applyIframeHeights()
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 如果bottom按钮还没加载,稍后重试
|
|
|
- if (!document.querySelector('ss-bottom')) {
|
|
|
- setTimeout(checkBottomButton, 100)
|
|
|
- } else {
|
|
|
- checkBottomButton()
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 如果还没有加载完成,继续等待
|
|
|
- console.log('⏳ 等待header-section加载...')
|
|
|
- setTimeout(checkHeaderSection, 100)
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('❌ 访问iframe DOM时出错:', error)
|
|
|
- console.log('⏳ 重试中...')
|
|
|
- setTimeout(checkHeaderSection, 200)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- checkHeaderSection()
|
|
|
- }
|
|
|
-
|
|
|
- waitForIframeLoad()
|
|
|
-
|
|
|
- } catch (error) {
|
|
|
- console.error('❌ 布局初始化失败:', error)
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- // 应用iframe高度
|
|
|
- applyIframeHeights() {
|
|
|
- const topIframe = document.querySelector('.top-iframe')
|
|
|
- const bottomIframe = document.querySelector('.bottom-iframe')
|
|
|
-
|
|
|
- if (topIframe && bottomIframe) {
|
|
|
- console.log('📏 设置iframe高度前:', {
|
|
|
- topIframe: {
|
|
|
- currentHeight: topIframe.style.height,
|
|
|
- offsetHeight: topIframe.offsetHeight
|
|
|
- },
|
|
|
- bottomIframe: {
|
|
|
- currentHeight: bottomIframe.style.height,
|
|
|
- offsetHeight: bottomIframe.offsetHeight
|
|
|
- },
|
|
|
- newTopHeight: this.topIframeHeight,
|
|
|
- newBottomHeight: this.bottomIframeHeight
|
|
|
- })
|
|
|
-
|
|
|
- // 直接应用新高度到iframe
|
|
|
- topIframe.style.height = `${this.topIframeHeight}px`
|
|
|
- bottomIframe.style.height = `${this.bottomIframeHeight}px`
|
|
|
-
|
|
|
- console.log('🎯 应用iframe高度:', {
|
|
|
- top: this.topIframeHeight,
|
|
|
- bottom: this.bottomIframeHeight
|
|
|
- })
|
|
|
-
|
|
|
- // 强制重新计算iframe内容
|
|
|
- this.$nextTick(() => {
|
|
|
- try {
|
|
|
- topIframe.contentWindow.dispatchEvent(new Event('resize'))
|
|
|
- } catch (e) {
|
|
|
- // 忽略跨域错误
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
- bottomIframe.contentWindow.dispatchEvent(new Event('resize'))
|
|
|
- } catch (e) {
|
|
|
- // 忽略跨域错误
|
|
|
- }
|
|
|
-
|
|
|
- console.log('✅ iframe高度更新完成')
|
|
|
- })
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- // 快速版本的高度应用,用于拖拽时减少延迟
|
|
|
- applyIframeHeightsFast() {
|
|
|
- const topIframe = document.querySelector('.top-iframe')
|
|
|
- const bottomIframe = document.querySelector('.bottom-iframe')
|
|
|
-
|
|
|
- if (topIframe && bottomIframe) {
|
|
|
- // 直接设置高度,不进行日志和额外的处理
|
|
|
- topIframe.style.height = `${this.topIframeHeight}px`
|
|
|
- bottomIframe.style.height = `${this.bottomIframeHeight}px`
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- // 计算iframe高度分配
|
|
|
- calculateHeights(bottomHeight) {
|
|
|
- // 计算实际可用的bottom iframe高度
|
|
|
- // 当bottom iframe展开时,可以覆盖top iframe,所以最大高度就是availableHeight
|
|
|
- // 最小高度不能小于header-section高度
|
|
|
- const bottomActualHeight = Math.max(
|
|
|
- this.bottomIframeMinHeight,
|
|
|
- Math.min(bottomHeight, this.availableHeight)
|
|
|
- )
|
|
|
-
|
|
|
- this.bottomIframeHeight = bottomActualHeight
|
|
|
- this.topIframeHeight = this.availableHeight - bottomActualHeight
|
|
|
-
|
|
|
- console.log('📐 高度分配计算:', {
|
|
|
- requestedBottom: bottomHeight,
|
|
|
- availableHeight: this.availableHeight,
|
|
|
- minBottomHeight: this.bottomIframeMinHeight,
|
|
|
- actualBottom: this.bottomIframeHeight,
|
|
|
- actualTop: this.topIframeHeight,
|
|
|
- isExpanded: this.isExpanded
|
|
|
- })
|
|
|
-
|
|
|
- this.applyIframeHeights()
|
|
|
-
|
|
|
- return {
|
|
|
- top: this.topIframeHeight,
|
|
|
- bottom: this.bottomIframeHeight
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- // 切换展开/收起状态
|
|
|
- toggleExpand() {
|
|
|
- if (!this.layoutCalculated) {
|
|
|
- console.warn('布局尚未计算完成')
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- this.isExpanded = !this.isExpanded
|
|
|
-
|
|
|
- if (this.isExpanded) {
|
|
|
- // 展开:bottom iframe占用所有可用高度,覆盖top iframe到title底部
|
|
|
- // 也就是bottom iframe高度 = availableHeight (title + button之间的所有空间)
|
|
|
- this.calculateHeights(this.availableHeight)
|
|
|
- console.log('📈 展开状态 - 覆盖到title底部,高度:', this.availableHeight)
|
|
|
- } else {
|
|
|
- // 收起:bottom iframe占用最小高度(header-section高度)
|
|
|
- this.calculateHeights(this.bottomIframeMinHeight)
|
|
|
- console.log('📉 收起状态 - 最小高度:', this.bottomIframeMinHeight)
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- // 处理来自iframe的消息
|
|
|
- handleIframeMessage(event) {
|
|
|
- // 安全检查:只接受同源的消息
|
|
|
- if (event.origin !== window.location.origin) {
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- const { type, data } = event.data
|
|
|
-
|
|
|
- switch (type) {
|
|
|
- case 'header-section-click':
|
|
|
- console.log('📱 收到header-section点击事件')
|
|
|
- this.toggleExpand()
|
|
|
- break
|
|
|
- case 'header-section-drag-start':
|
|
|
- console.log('🔄 开始拖拽header-section')
|
|
|
- this.handleDragStart(data)
|
|
|
- break
|
|
|
- case 'header-section-drag-move':
|
|
|
- console.log('🔄 拖拽中:', data.deltaY)
|
|
|
- this.handleDragMove(data.deltaY)
|
|
|
- break
|
|
|
- case 'header-section-drag-end':
|
|
|
- console.log('🔚 结束拖拽')
|
|
|
- this.handleDragEnd()
|
|
|
- break
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- // 处理拖拽开始
|
|
|
- handleDragStart(data) {
|
|
|
- if (!this.layoutCalculated) return
|
|
|
-
|
|
|
- this.isDragging = true
|
|
|
- this.dragStartY = data.startY
|
|
|
- this.dragStartBottomHeight = this.bottomIframeHeight
|
|
|
- },
|
|
|
-
|
|
|
- // 处理拖拽移动
|
|
|
- handleDragMove(deltaY) {
|
|
|
- if (!this.isDragging || !this.layoutCalculated) return
|
|
|
-
|
|
|
- // 计算新的底部高度
|
|
|
- const newBottomHeight = this.dragStartBottomHeight - deltaY
|
|
|
-
|
|
|
- // 直接设置高度,避免复杂的计算导致的延迟
|
|
|
- const bottomActualHeight = Math.max(
|
|
|
- this.bottomIframeMinHeight,
|
|
|
- Math.min(newBottomHeight, this.availableHeight)
|
|
|
- )
|
|
|
-
|
|
|
- this.bottomIframeHeight = bottomActualHeight
|
|
|
- this.topIframeHeight = this.availableHeight - bottomActualHeight
|
|
|
-
|
|
|
- // 直接应用高度,减少延迟
|
|
|
- this.applyIframeHeightsFast()
|
|
|
- },
|
|
|
-
|
|
|
- // 处理拖拽结束
|
|
|
- handleDragEnd() {
|
|
|
- this.isDragging = false
|
|
|
- this.dragStartY = 0
|
|
|
- this.dragStartBottomHeight = 0
|
|
|
-
|
|
|
- // 拖拽结束后用完整的方法确保状态正确
|
|
|
- this.applyIframeHeights()
|
|
|
- },
|
|
|
- }
|
|
|
- })
|
|
|
- })
|
|
|
- </script>
|
|
|
-</body>
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="zh-CN">
|
|
|
+ <head>
|
|
|
+ <meta charset="UTF-8" />
|
|
|
+ <meta
|
|
|
+ name="viewport"
|
|
|
+ content="width=device-width, initial-scale=1.0, user-scalable=no"
|
|
|
+ />
|
|
|
+ <title>审核</title>
|
|
|
+ <script src="/js/mp_base/base.js"></script>
|
|
|
+
|
|
|
+ <style>
|
|
|
+ /* 防止Vue模板闪烁 */
|
|
|
+ [v-cloak] {
|
|
|
+ display: none !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ #app {
|
|
|
+ background: #f5f5f5;
|
|
|
+ height: 100vh;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden; /* 防止页面级别滚动 */
|
|
|
+ box-sizing: border-box; /* 确保padding计算在高度内 */
|
|
|
+ }
|
|
|
+
|
|
|
+ /* iframe样式 */
|
|
|
+ .top-iframe {
|
|
|
+ background: #fff;
|
|
|
+ overflow: hidden;
|
|
|
+ border: none;
|
|
|
+ display: block;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ .bottom-iframe {
|
|
|
+ background: #fff;
|
|
|
+ overflow: hidden;
|
|
|
+ border: none;
|
|
|
+ display: block;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ .title {
|
|
|
+ flex-shrink: 0;
|
|
|
+ box-sizing: border-box;
|
|
|
+ font-size: 16px;
|
|
|
+ text-align: center;
|
|
|
+ /* margin: 16px auto; */
|
|
|
+ height: 48px;
|
|
|
+ line-height: 48px;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 录入div样式 */
|
|
|
+ .review-input-popup {
|
|
|
+ position: fixed;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ height: 50px;
|
|
|
+ background: #e6e6e6;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 0 0 0 10px;
|
|
|
+ z-index: 1000;
|
|
|
+ transform: translateY(100%);
|
|
|
+ transition: transform 0.3s ease;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ .review-input-popup.show {
|
|
|
+ transform: translateY(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ .review-input-wrapper {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .review-input {
|
|
|
+ flex: 1;
|
|
|
+ height: 32px;
|
|
|
+ border: none;
|
|
|
+ padding: 0 10px;
|
|
|
+ font-size: 16px;
|
|
|
+ background: #fff;
|
|
|
+ outline: none;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ .common-phrases-btn {
|
|
|
+ padding: 6px 12px;
|
|
|
+ background: #fff;
|
|
|
+ border: none;
|
|
|
+ font-size: 16px;
|
|
|
+ color: #333;
|
|
|
+ cursor: pointer;
|
|
|
+ white-space: nowrap;
|
|
|
+ margin-right: 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .common-phrases-btn:hover {
|
|
|
+ background: #e0e0e0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .submit-btn {
|
|
|
+ box-sizing: border-box;
|
|
|
+ height: 50px;
|
|
|
+ padding: 6px 16px;
|
|
|
+ border: none;
|
|
|
+ font-size: 16px;
|
|
|
+ color: #fff;
|
|
|
+ cursor: pointer;
|
|
|
+ white-space: nowrap;
|
|
|
+ transition: background-color 0.2s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .submit-btn.agree {
|
|
|
+ background: #585e6e;
|
|
|
+ }
|
|
|
+
|
|
|
+ .submit-btn.agree:active {
|
|
|
+ background: #242835;
|
|
|
+ }
|
|
|
+
|
|
|
+ .submit-btn.reject {
|
|
|
+ background: #e58846;
|
|
|
+ }
|
|
|
+
|
|
|
+ .submit-btn.reject:active {
|
|
|
+ background: #eb6100;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 常用语popup */
|
|
|
+ .common-phrases-popup {
|
|
|
+ position: fixed;
|
|
|
+ bottom: 50px;
|
|
|
+ left: 10px;
|
|
|
+ right: 10px;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 4px;
|
|
|
+ box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
|
|
|
+ max-height: 200px;
|
|
|
+ overflow-y: auto;
|
|
|
+ z-index: 1001;
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .common-phrases-popup.show {
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+
|
|
|
+ .phrase-item {
|
|
|
+ padding: 12px 16px;
|
|
|
+ border-bottom: 1px solid #f0f0f0;
|
|
|
+ cursor: pointer;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .phrase-item:hover {
|
|
|
+ background: #f8f8f8;
|
|
|
+ }
|
|
|
+
|
|
|
+ .phrase-item:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 原ss-bottom隐藏 */
|
|
|
+ .ss-bottom.hidden {
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .url-log-fab {
|
|
|
+ position: fixed;
|
|
|
+ right: 12px;
|
|
|
+ bottom: 72px;
|
|
|
+ z-index: 1200;
|
|
|
+ border: none;
|
|
|
+ border-radius: 16px;
|
|
|
+ background: rgba(36, 40, 53, 0.88);
|
|
|
+ color: #fff;
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 1;
|
|
|
+ padding: 8px 10px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
|
|
|
+ }
|
|
|
+
|
|
|
+ .url-log-panel {
|
|
|
+ position: fixed;
|
|
|
+ left: 12px;
|
|
|
+ right: 12px;
|
|
|
+ bottom: 116px;
|
|
|
+ z-index: 1200;
|
|
|
+ background: rgba(36, 40, 53, 0.96);
|
|
|
+ color: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 10px;
|
|
|
+ max-height: 42vh;
|
|
|
+ overflow: auto;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ .url-log-panel__head {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .url-log-panel__close {
|
|
|
+ border: none;
|
|
|
+ background: transparent;
|
|
|
+ color: #fff;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ .url-log-panel__body {
|
|
|
+ margin: 0;
|
|
|
+ white-space: pre-wrap;
|
|
|
+ word-break: break-all;
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 1.5;
|
|
|
+ }
|
|
|
+
|
|
|
+ .review-section {
|
|
|
+ flex-shrink: 0;
|
|
|
+ background: #f5f5f5;
|
|
|
+ }
|
|
|
+
|
|
|
+ .review-section .ss-sub-tab__bar {
|
|
|
+ margin-bottom: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .review-section__card {
|
|
|
+ width: 95%;
|
|
|
+ margin: 0 auto 8px;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ overflow: hidden;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ .review-section__form {
|
|
|
+ width: 100%;
|
|
|
+ border-collapse: collapse;
|
|
|
+ }
|
|
|
+
|
|
|
+ .review-section__form th {
|
|
|
+ width: 140px;
|
|
|
+ max-width: 170px;
|
|
|
+ }
|
|
|
+ </style>
|
|
|
+ </head>
|
|
|
+ <body>
|
|
|
+ <div id="app" v-cloak>
|
|
|
+ <!-- 新增抄送审核结果展示区 by xu 2026-03-06 -->
|
|
|
+ <div ref="reviewSection" class="review-section" v-if="showReviewSection">
|
|
|
+ <div class="ss-sub-tab__bar">
|
|
|
+ <div class="ss-sub-tab__item ss-sub-tab__item--active">审核情况</div>
|
|
|
+ </div>
|
|
|
+ <div class="review-section__card">
|
|
|
+ <table class="form review-section__form">
|
|
|
+ <tr>
|
|
|
+ <th>审核结果</th>
|
|
|
+ <td>{{ reviewResultText || '-' }}</td>
|
|
|
+ </tr>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 上方iframe - 基本信息区域 -->
|
|
|
+ <iframe
|
|
|
+ ref="topIframe"
|
|
|
+ class="top-iframe"
|
|
|
+ :src="topIframeSrc || 'about:blank'"
|
|
|
+ width="100%"
|
|
|
+ frameborder="0"
|
|
|
+ >
|
|
|
+ </iframe>
|
|
|
+
|
|
|
+ <!-- 下方iframe - 审核列表区域 -->
|
|
|
+ <iframe
|
|
|
+ ref="bottomIframe"
|
|
|
+ class="bottom-iframe"
|
|
|
+ :src="bottomIframeSrc || 'about:blank'"
|
|
|
+ width="100%"
|
|
|
+ frameborder="0"
|
|
|
+ >
|
|
|
+ </iframe>
|
|
|
+
|
|
|
+ <!-- 底部按钮 -->
|
|
|
+ <ss-bottom
|
|
|
+ :show-shyj="false"
|
|
|
+ :buttons="bottomButtons"
|
|
|
+ @button-click="handleBottomAction"
|
|
|
+ :divider="false"
|
|
|
+ :disabled="submitting"
|
|
|
+ v-if="bottomButtons.length > 0"
|
|
|
+ ></ss-bottom>
|
|
|
+
|
|
|
+ <button class="url-log-fab" type="button" @click="showCurrentUrls">
|
|
|
+ URL
|
|
|
+ </button>
|
|
|
+ <div class="url-log-panel" v-if="urlLogVisible">
|
|
|
+ <div class="url-log-panel__head">
|
|
|
+ <span>当前 URL</span>
|
|
|
+ <button
|
|
|
+ class="url-log-panel__close"
|
|
|
+ type="button"
|
|
|
+ @click="urlLogVisible = false"
|
|
|
+ >
|
|
|
+ ×
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <pre class="url-log-panel__body">{{ urlLogText }}</pre>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <script>
|
|
|
+ // 等待SS框架加载完成
|
|
|
+ window.SS.ready(function () {
|
|
|
+ // 使用SS框架的方式创建Vue实例
|
|
|
+ window.SS.dom.initializeFormApp({
|
|
|
+ el: "#app",
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ pageParams: {},
|
|
|
+ loading: false,
|
|
|
+ jdmc: "",
|
|
|
+ sqid: "",
|
|
|
+ shid: "",
|
|
|
+ shyjm: "",
|
|
|
+ bdlbm: "",
|
|
|
+ dataType: "bdplay",
|
|
|
+ encode_shid: "",
|
|
|
+ ssObjName: "",
|
|
|
+ ssObjId: "",
|
|
|
+ infoData: null,
|
|
|
+ agrCcData: null, // 存储agrCc返回的数据
|
|
|
+ topIframeSrc: "",
|
|
|
+ bottomIframeSrc: "",
|
|
|
+
|
|
|
+ // 底部按钮相关
|
|
|
+ submitting: false,
|
|
|
+ bottomButtons: [],
|
|
|
+
|
|
|
+ // iframe布局相关
|
|
|
+ layoutCalculated: false,
|
|
|
+ headerSectionHeight: 0,
|
|
|
+ availableHeight: 0,
|
|
|
+ topIframeHeight: 0,
|
|
|
+ bottomIframeHeight: 0,
|
|
|
+ bottomIframeMinHeight: 0,
|
|
|
+ isExpanded: false,
|
|
|
+
|
|
|
+ // 拖拽相关
|
|
|
+ isDragging: false,
|
|
|
+ dragStartY: 0,
|
|
|
+ dragStartBottomHeight: 0,
|
|
|
+
|
|
|
+ urlLogVisible: false,
|
|
|
+ urlLogText: "",
|
|
|
+ reviewResultText: "",
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ showReviewSection() {
|
|
|
+ return (
|
|
|
+ this.shyjm !== undefined &&
|
|
|
+ this.shyjm !== null &&
|
|
|
+ this.shyjm !== ""
|
|
|
+ );
|
|
|
+ },
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ // 获取URL参数
|
|
|
+ this.pageParams = this.getUrlParams();
|
|
|
+ this.shyjm = this.pageParams.shyjm || "";
|
|
|
+ console.log("🔗 mp_ccChk页面接收到参数:", this.pageParams);
|
|
|
+
|
|
|
+ // 打印所有参数到控制台
|
|
|
+ Object.keys(this.pageParams).forEach((key) => {
|
|
|
+ console.log(`参数 ${key}:`, this.pageParams[key]);
|
|
|
+ });
|
|
|
+
|
|
|
+ this.syncReviewResultText();
|
|
|
+ this.callApi();
|
|
|
+
|
|
|
+ // 添加iframe消息监听器
|
|
|
+ window.addEventListener("message", this.handleIframeMessage);
|
|
|
+
|
|
|
+ // 初始化布局计算
|
|
|
+ this.$nextTick(() => {
|
|
|
+ setTimeout(() => {
|
|
|
+ this.initializeLayout();
|
|
|
+ }, 500); // 等待iframe加载完成
|
|
|
+ });
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ // 清理事件监听器
|
|
|
+ window.removeEventListener("message", this.handleIframeMessage);
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 翻译审核结果并在页面顶部展示 by xu 2026-03-06
|
|
|
+ async syncReviewResultText() {
|
|
|
+ this.reviewResultText = await this.translateReviewResult(
|
|
|
+ this.shyjm
|
|
|
+ );
|
|
|
+ this.$nextTick(() => {
|
|
|
+ if (this.layoutCalculated) {
|
|
|
+ this.initializeLayout();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ async translateReviewResult(shyjm) {
|
|
|
+ if (shyjm === undefined || shyjm === null || shyjm === "") {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ if (typeof window.getDictOptions === "function") {
|
|
|
+ const options = await window.getDictOptions("shyj");
|
|
|
+ const target = (options || []).find(
|
|
|
+ (item) => String(item.v) === String(shyjm)
|
|
|
+ );
|
|
|
+ if (target && target.n) return target.n;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("审核结果翻译失败:", error);
|
|
|
+ }
|
|
|
+ if (String(shyjm) === "1") return "通过";
|
|
|
+ return String(shyjm);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取URL参数
|
|
|
+ getUrlParams() {
|
|
|
+ const params = {};
|
|
|
+ const aliasMap = {
|
|
|
+ ssobjname: "ssObjName",
|
|
|
+ ssobjid: "ssObjId",
|
|
|
+ sqid: "sqid",
|
|
|
+ shid: "shid",
|
|
|
+ shyjm: "shyjm",
|
|
|
+ bdlbm: "bdlbm",
|
|
|
+ datatype: "dataType",
|
|
|
+ encode_shid: "encode_shid",
|
|
|
+ jdmc: "jdmc",
|
|
|
+ };
|
|
|
+ const urlSearchParams = new URLSearchParams(
|
|
|
+ window.location.search
|
|
|
+ );
|
|
|
+ for (const [rawKey, rawValue] of urlSearchParams) {
|
|
|
+ const decodedValue = this.safeDecode(rawValue);
|
|
|
+ params[rawKey] = decodedValue;
|
|
|
+ const normalizedKey = aliasMap[String(rawKey).toLowerCase()];
|
|
|
+ if (normalizedKey) {
|
|
|
+ params[normalizedKey] = decodedValue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return params;
|
|
|
+ },
|
|
|
+
|
|
|
+ safeDecode(text) {
|
|
|
+ if (text === undefined || text === null || text === "") return "";
|
|
|
+ try {
|
|
|
+ return decodeURIComponent(String(text));
|
|
|
+ } catch (_) {
|
|
|
+ return String(text);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ pickFirstValue(sources, keys) {
|
|
|
+ const srcArr = Array.isArray(sources) ? sources : [];
|
|
|
+ const keyArr = Array.isArray(keys) ? keys : [];
|
|
|
+ for (let i = 0; i < srcArr.length; i += 1) {
|
|
|
+ const src = srcArr[i];
|
|
|
+ if (!src || typeof src !== "object") continue;
|
|
|
+ for (let j = 0; j < keyArr.length; j += 1) {
|
|
|
+ const key = keyArr[j];
|
|
|
+ const value = src[key];
|
|
|
+ if (value !== undefined && value !== null && value !== "") {
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ },
|
|
|
+
|
|
|
+ extractTokenData(apiResponse) {
|
|
|
+ const wantedKeys = [
|
|
|
+ "sqid",
|
|
|
+ "shid",
|
|
|
+ "ssObjName",
|
|
|
+ "ssObjId",
|
|
|
+ "jdmc",
|
|
|
+ "bdlbm",
|
|
|
+ "dataType",
|
|
|
+ "encode_shid",
|
|
|
+ ];
|
|
|
+ const candidates = [
|
|
|
+ apiResponse && apiResponse.data && apiResponse.data.ssData,
|
|
|
+ apiResponse && apiResponse.ssData,
|
|
|
+ apiResponse && apiResponse.data,
|
|
|
+ apiResponse,
|
|
|
+ ];
|
|
|
+ let best = {};
|
|
|
+ let bestScore = -1;
|
|
|
+ candidates.forEach((item) => {
|
|
|
+ if (!item || typeof item !== "object") return;
|
|
|
+ let score = 0;
|
|
|
+ wantedKeys.forEach((key) => {
|
|
|
+ if (
|
|
|
+ item[key] !== undefined &&
|
|
|
+ item[key] !== null &&
|
|
|
+ item[key] !== ""
|
|
|
+ ) {
|
|
|
+ score += 1;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (score > bestScore) {
|
|
|
+ best = item;
|
|
|
+ bestScore = score;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return best;
|
|
|
+ },
|
|
|
+
|
|
|
+ resolveBusinessContext(apiResponse) {
|
|
|
+ const tokenData = this.extractTokenData(apiResponse);
|
|
|
+ const sources = [tokenData, this.pageParams];
|
|
|
+ return {
|
|
|
+ sqid: String(this.pickFirstValue(sources, ["sqid"]) || ""),
|
|
|
+ shid: String(this.pickFirstValue(sources, ["shid"]) || ""),
|
|
|
+ shyjm: String(this.pickFirstValue(sources, ["shyjm"]) || ""),
|
|
|
+ ssObjName: String(
|
|
|
+ this.pickFirstValue(sources, ["ssObjName", "ssobjname"]) || ""
|
|
|
+ ),
|
|
|
+ ssObjId: String(
|
|
|
+ this.pickFirstValue(sources, ["ssObjId", "ssobjid"]) || ""
|
|
|
+ ),
|
|
|
+ bdlbm: String(this.pickFirstValue(sources, ["bdlbm"]) || ""),
|
|
|
+ dataType:
|
|
|
+ String(
|
|
|
+ this.pickFirstValue(sources, ["dataType", "datatype"]) ||
|
|
|
+ this.dataType ||
|
|
|
+ "bdplay"
|
|
|
+ ) || "bdplay",
|
|
|
+ encode_shid: String(
|
|
|
+ this.pickFirstValue(sources, ["encode_shid"]) || ""
|
|
|
+ ),
|
|
|
+ jdmc: this.safeDecode(
|
|
|
+ this.pickFirstValue(sources, ["jdmc"]) || ""
|
|
|
+ ),
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ parseInfoParm(rawParm) {
|
|
|
+ if (!rawParm) return {};
|
|
|
+ if (typeof rawParm === "object") return rawParm;
|
|
|
+ const text = String(rawParm).trim();
|
|
|
+ if (!text) return {};
|
|
|
+ try {
|
|
|
+ return JSON.parse(text);
|
|
|
+ } catch (_) {}
|
|
|
+ try {
|
|
|
+ const normalized = text
|
|
|
+ .replace(/([{,]\s*)([A-Za-z0-9_]+)\s*:/g, '$1"$2":')
|
|
|
+ .replace(/'/g, '"');
|
|
|
+ return JSON.parse(normalized);
|
|
|
+ } catch (_) {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ resolveInfoDestPath(destName) {
|
|
|
+ const raw = String(destName || "").trim();
|
|
|
+ if (!raw) return "";
|
|
|
+ if (/^https?:\/\//i.test(raw)) return raw;
|
|
|
+ if (raw.startsWith("/")) return raw;
|
|
|
+ if (raw.endsWith(".html")) return `/page/${raw}`;
|
|
|
+ if (raw.startsWith("mp_")) return `/page/${raw}.html`;
|
|
|
+ return `/page/mp_${raw}.html`;
|
|
|
+ },
|
|
|
+
|
|
|
+ buildInfoIframeSrc(infoData, fallbackQuery) {
|
|
|
+ const conf =
|
|
|
+ infoData && typeof infoData === "object" ? infoData : {};
|
|
|
+ const serviceName = conf.service || conf.servName || "";
|
|
|
+ const destName = conf.dest || "";
|
|
|
+ const parmObj = this.parseInfoParm(conf.parm);
|
|
|
+ const mergedQuery = {
|
|
|
+ ...(fallbackQuery || {}),
|
|
|
+ ...(parmObj || {}),
|
|
|
+ };
|
|
|
+ if (!serviceName || !destName) {
|
|
|
+ return this.buildIframeSrc(
|
|
|
+ "/page/mp_objInfo.html",
|
|
|
+ mergedQuery
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ const pagePath = this.resolveInfoDestPath(destName);
|
|
|
+ if (!pagePath) {
|
|
|
+ return this.buildIframeSrc(
|
|
|
+ "/page/mp_objInfo.html",
|
|
|
+ mergedQuery
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ const paramText =
|
|
|
+ typeof conf.parm === "string"
|
|
|
+ ? conf.parm
|
|
|
+ : JSON.stringify(parmObj || {});
|
|
|
+ const iframeQuery = {
|
|
|
+ ...mergedQuery,
|
|
|
+ ssServ: serviceName,
|
|
|
+ ssDest: destName,
|
|
|
+ service: serviceName,
|
|
|
+ dest: destName,
|
|
|
+ param: paramText,
|
|
|
+ };
|
|
|
+ return this.buildIframeSrc(pagePath, iframeQuery);
|
|
|
+ },
|
|
|
+
|
|
|
+ buildIframeSrc(path, queryObj) {
|
|
|
+ const search = new URLSearchParams();
|
|
|
+ Object.keys(queryObj || {}).forEach((key) => {
|
|
|
+ const value = queryObj[key];
|
|
|
+ if (value === undefined || value === null) return;
|
|
|
+ search.set(key, String(value));
|
|
|
+ });
|
|
|
+ return `${path}?${search.toString()}`;
|
|
|
+ },
|
|
|
+
|
|
|
+ buildCommonQuery() {
|
|
|
+ return {
|
|
|
+ sqid: this.sqid,
|
|
|
+ shid: this.shid,
|
|
|
+ shyjm: this.shyjm,
|
|
|
+ bdlbm: this.bdlbm,
|
|
|
+ dataType: this.dataType,
|
|
|
+ encode_shid: this.encode_shid,
|
|
|
+ ssObjName: this.ssObjName,
|
|
|
+ ssObjId: this.ssObjId,
|
|
|
+ jdmc: this.jdmc,
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ // 调用API
|
|
|
+ async callApi() {
|
|
|
+ this.loading = true;
|
|
|
+ this.apiResult = null;
|
|
|
+ this.infoData = null;
|
|
|
+ this.agrCcData = null;
|
|
|
+ this.bottomButtons = [];
|
|
|
+ this.topIframeSrc = "";
|
|
|
+ this.bottomIframeSrc = "";
|
|
|
+
|
|
|
+ try {
|
|
|
+ let apiResponse = null;
|
|
|
+ if (this.pageParams.ssToken) {
|
|
|
+ console.log(
|
|
|
+ "🚀 开始调用API,ssToken:",
|
|
|
+ this.pageParams.ssToken
|
|
|
+ );
|
|
|
+ apiResponse = await request.post(
|
|
|
+ `/service?ssToken=${this.pageParams.ssToken}`,
|
|
|
+ {},
|
|
|
+ { loading: false }
|
|
|
+ );
|
|
|
+ console.log("✅ 原有API响应:", apiResponse);
|
|
|
+ }
|
|
|
+
|
|
|
+ const context = this.resolveBusinessContext(apiResponse);
|
|
|
+ this.sqid = context.sqid;
|
|
|
+ this.shid = context.shid;
|
|
|
+ this.shyjm = context.shyjm;
|
|
|
+ await this.syncReviewResultText();
|
|
|
+ this.ssObjName = context.ssObjName;
|
|
|
+ this.ssObjId = context.ssObjId;
|
|
|
+ this.bdlbm = context.bdlbm;
|
|
|
+ this.dataType = context.dataType;
|
|
|
+ this.encode_shid = context.encode_shid;
|
|
|
+ this.jdmc = context.jdmc || "";
|
|
|
+
|
|
|
+ if (!this.sqid || !this.shid || !this.ssObjId) {
|
|
|
+ const missingMessage = "缺少必要参数:sqid / shid / ssObjId";
|
|
|
+ if (typeof showToastEffect === "function") {
|
|
|
+ showToastEffect(missingMessage, 2200, "error");
|
|
|
+ } else {
|
|
|
+ this.urlLogText = missingMessage;
|
|
|
+ this.urlLogVisible = true;
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const query = this.buildCommonQuery();
|
|
|
+ const infoUrl = `/service?ssServ=dataTag&ssDest=data&name=info&ssObjName=${encodeURIComponent(
|
|
|
+ this.ssObjName
|
|
|
+ )}&ssObjId=${encodeURIComponent(
|
|
|
+ this.ssObjId
|
|
|
+ )}&sqid=${encodeURIComponent(
|
|
|
+ this.sqid
|
|
|
+ )}&shid=${encodeURIComponent(this.shid)}`;
|
|
|
+ const infoRes = await request.post(
|
|
|
+ infoUrl,
|
|
|
+ {},
|
|
|
+ { loading: false, formData: true }
|
|
|
+ );
|
|
|
+ this.infoData =
|
|
|
+ infoRes && infoRes.data ? infoRes.data.info : null;
|
|
|
+ this.topIframeSrc = this.buildInfoIframeSrc(
|
|
|
+ this.infoData,
|
|
|
+ query
|
|
|
+ );
|
|
|
+ this.bottomIframeSrc = this.buildIframeSrc(
|
|
|
+ "/page/mp_shList.html",
|
|
|
+ query
|
|
|
+ );
|
|
|
+
|
|
|
+ console.log("📋 调用dataTag服务获取agrCc数据...");
|
|
|
+ const agrCcResponse = await request.post(
|
|
|
+ `/service?ssServ=dataTag&ssDest=data&name=agrCc&ssObjName=${this.ssObjName}&ssObjId=${this.ssObjId}&sqid=${this.sqid}&shid=${this.shid}&bdlbm=${this.bdlbm}&dataType=${this.dataType}&encode_shid=${this.encode_shid}`,
|
|
|
+ {},
|
|
|
+ { loading: false, formData: true }
|
|
|
+ );
|
|
|
+
|
|
|
+ // 保存agrCc数据并设置底部按钮
|
|
|
+ if (
|
|
|
+ agrCcResponse &&
|
|
|
+ agrCcResponse.data &&
|
|
|
+ agrCcResponse.data.agrCc
|
|
|
+ ) {
|
|
|
+ this.agrCcData = agrCcResponse.data.agrCc;
|
|
|
+ console.log("📦 agrCc数据:", this.agrCcData);
|
|
|
+
|
|
|
+ // 根据agrCc数据设置底部按钮
|
|
|
+ this.bottomButtons = [
|
|
|
+ {
|
|
|
+ text: "确认",
|
|
|
+ action: "submit",
|
|
|
+ backgroundColor: "#585e6e",
|
|
|
+ color: "#fff",
|
|
|
+ clickBgColor: "#242835",
|
|
|
+ },
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("❌ API调用失败:", error);
|
|
|
+ } finally {
|
|
|
+ this.loading = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 处理底部按钮点击
|
|
|
+ handleBottomAction(data) {
|
|
|
+ if (data.action === "submit") {
|
|
|
+ this.handleConfirm();
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ showCurrentUrls() {
|
|
|
+ const topIframe = this.$refs.topIframe;
|
|
|
+ const bottomIframe = this.$refs.bottomIframe;
|
|
|
+ const lines = [
|
|
|
+ `page: ${window.location.href}`,
|
|
|
+ `top: ${(topIframe && topIframe.src) || "(empty)"}`,
|
|
|
+ `bottom: ${(bottomIframe && bottomIframe.src) || "(empty)"}`,
|
|
|
+ ];
|
|
|
+ this.urlLogText = lines.join("\n");
|
|
|
+ this.urlLogVisible = true;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 处理确认提交
|
|
|
+ async handleConfirm() {
|
|
|
+ if (!this.agrCcData) {
|
|
|
+ if (typeof showToastEffect === "function") {
|
|
|
+ showToastEffect("缺少必要的配置信息", 2200, "error");
|
|
|
+ } else {
|
|
|
+ this.urlLogText = "缺少必要的配置信息";
|
|
|
+ this.urlLogVisible = true;
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.submitting) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ this.submitting = true;
|
|
|
+ console.log("📝 开始提交...");
|
|
|
+ console.log("📦 提交参数:", {
|
|
|
+ service: this.agrCcData.service,
|
|
|
+ dest: this.agrCcData.dest,
|
|
|
+ shid: this.shid,
|
|
|
+ });
|
|
|
+
|
|
|
+ const response = await request.post(
|
|
|
+ `/service?ssServ=${this.agrCcData.service}&ssDest=${this.agrCcData.dest}`,
|
|
|
+ { shid: this.shid },
|
|
|
+ { loading: true, formData: true }
|
|
|
+ );
|
|
|
+ console.log("✅ 提交成功:", response);
|
|
|
+
|
|
|
+ NavigationManager.goBack({ refreshParent: true });
|
|
|
+ } catch (error) {
|
|
|
+ console.error("❌ 提交失败:", error);
|
|
|
+ const message =
|
|
|
+ "提交失败: " + ((error && error.message) || "未知错误");
|
|
|
+ if (typeof showToastEffect === "function") {
|
|
|
+ showToastEffect(message, 2200, "error");
|
|
|
+ } else {
|
|
|
+ this.urlLogText = message;
|
|
|
+ this.urlLogVisible = true;
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ this.submitting = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // ===== 布局相关方法 =====
|
|
|
+ // 初始化布局计算
|
|
|
+ initializeLayout() {
|
|
|
+ console.log("🔄 开始初始化布局计算");
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 获取bottom iframe
|
|
|
+ const bottomIframe = document.querySelector(".bottom-iframe");
|
|
|
+ const bottomWindow = bottomIframe?.contentWindow;
|
|
|
+
|
|
|
+ if (!bottomWindow) {
|
|
|
+ console.error("无法获取bottom iframe的contentWindow");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 等待iframe加载完成,然后检查header-section
|
|
|
+ const waitForIframeLoad = () => {
|
|
|
+ if (!bottomIframe.contentWindow) {
|
|
|
+ console.log("⏳ 等待iframe contentWindow...");
|
|
|
+ setTimeout(waitForIframeLoad, 100);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const bottomWindow = bottomIframe.contentWindow;
|
|
|
+ console.log("✅ 获取到iframe contentWindow");
|
|
|
+
|
|
|
+ // 等待iframe中的DOM加载完成
|
|
|
+ const checkHeaderSection = () => {
|
|
|
+ try {
|
|
|
+ const headerSection =
|
|
|
+ bottomWindow.document.querySelector(".header-section");
|
|
|
+ if (headerSection) {
|
|
|
+ const headerHeight = headerSection.offsetHeight;
|
|
|
+ console.log(
|
|
|
+ "✅ 计算到header-section高度:",
|
|
|
+ headerHeight
|
|
|
+ );
|
|
|
+
|
|
|
+ // 计算布局参数
|
|
|
+ const viewportHeight = window.innerHeight;
|
|
|
+
|
|
|
+ // 动态获取顶部审核情况区域高度 by xu 2026-03-06
|
|
|
+ const reviewSectionElement = this.$refs.reviewSection;
|
|
|
+ const actualReviewSectionHeight = reviewSectionElement
|
|
|
+ ? reviewSectionElement.offsetHeight
|
|
|
+ : 0;
|
|
|
+
|
|
|
+ // 等待bottom按钮渲染完成并获取实际高度
|
|
|
+ const checkBottomButton = () => {
|
|
|
+ try {
|
|
|
+ const bottomElement =
|
|
|
+ document.querySelector("ss-bottom");
|
|
|
+ const actualBottomHeight = bottomElement
|
|
|
+ ? bottomElement.offsetHeight
|
|
|
+ : 50;
|
|
|
+
|
|
|
+ this.headerSectionHeight = headerHeight;
|
|
|
+ this.bottomIframeMinHeight = headerHeight;
|
|
|
+ this.availableHeight =
|
|
|
+ viewportHeight -
|
|
|
+ actualReviewSectionHeight -
|
|
|
+ actualBottomHeight;
|
|
|
+
|
|
|
+ // 初始状态:底部iframe刚好显示header-section高度
|
|
|
+ this.bottomIframeHeight =
|
|
|
+ this.bottomIframeMinHeight;
|
|
|
+ this.topIframeHeight =
|
|
|
+ this.availableHeight - this.bottomIframeMinHeight;
|
|
|
+ this.isExpanded = false; // 初始为收起状态
|
|
|
+ this.layoutCalculated = true;
|
|
|
+
|
|
|
+ // 应用计算后的高度
|
|
|
+ this.applyIframeHeights();
|
|
|
+
|
|
|
+ console.log(
|
|
|
+ "📊 初始布局计算完成(仅显示header-section):",
|
|
|
+ {
|
|
|
+ 审核情况区域高度: actualReviewSectionHeight,
|
|
|
+ 底部按钮实际高度: actualBottomHeight,
|
|
|
+ 可用总高度: this.availableHeight,
|
|
|
+ "header-section高度": headerHeight,
|
|
|
+ 上iframe高度: this.topIframeHeight,
|
|
|
+ 下iframe高度: this.bottomIframeHeight,
|
|
|
+ iframe总高度:
|
|
|
+ this.topIframeHeight +
|
|
|
+ this.bottomIframeHeight,
|
|
|
+ 是否超限:
|
|
|
+ this.topIframeHeight +
|
|
|
+ this.bottomIframeHeight >
|
|
|
+ this.availableHeight,
|
|
|
+ 差额:
|
|
|
+ this.topIframeHeight +
|
|
|
+ this.bottomIframeHeight -
|
|
|
+ this.availableHeight,
|
|
|
+ isExpanded: this.isExpanded,
|
|
|
+ }
|
|
|
+ );
|
|
|
+ } catch (bottomError) {
|
|
|
+ console.error(
|
|
|
+ "❌ 获取底部按钮高度时出错:",
|
|
|
+ bottomError
|
|
|
+ );
|
|
|
+ // 使用默认高度50px重试
|
|
|
+ const defaultBottomHeight = 50;
|
|
|
+ this.headerSectionHeight = headerHeight;
|
|
|
+ this.bottomIframeMinHeight = headerHeight;
|
|
|
+ this.availableHeight =
|
|
|
+ viewportHeight -
|
|
|
+ actualReviewSectionHeight -
|
|
|
+ defaultBottomHeight;
|
|
|
+ this.bottomIframeHeight =
|
|
|
+ this.bottomIframeMinHeight;
|
|
|
+ this.topIframeHeight =
|
|
|
+ this.availableHeight - this.bottomIframeMinHeight;
|
|
|
+ this.isExpanded = false;
|
|
|
+ this.layoutCalculated = true;
|
|
|
+ this.applyIframeHeights();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 如果bottom按钮还没加载,稍后重试
|
|
|
+ if (!document.querySelector("ss-bottom")) {
|
|
|
+ setTimeout(checkBottomButton, 100);
|
|
|
+ } else {
|
|
|
+ checkBottomButton();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 如果还没有加载完成,继续等待
|
|
|
+ console.log("⏳ 等待header-section加载...");
|
|
|
+ setTimeout(checkHeaderSection, 100);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("❌ 访问iframe DOM时出错:", error);
|
|
|
+ console.log("⏳ 重试中...");
|
|
|
+ setTimeout(checkHeaderSection, 200);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ checkHeaderSection();
|
|
|
+ };
|
|
|
+
|
|
|
+ waitForIframeLoad();
|
|
|
+ } catch (error) {
|
|
|
+ console.error("❌ 布局初始化失败:", error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 应用iframe高度
|
|
|
+ applyIframeHeights() {
|
|
|
+ const topIframe = document.querySelector(".top-iframe");
|
|
|
+ const bottomIframe = document.querySelector(".bottom-iframe");
|
|
|
+
|
|
|
+ if (topIframe && bottomIframe) {
|
|
|
+ console.log("📏 设置iframe高度前:", {
|
|
|
+ topIframe: {
|
|
|
+ currentHeight: topIframe.style.height,
|
|
|
+ offsetHeight: topIframe.offsetHeight,
|
|
|
+ },
|
|
|
+ bottomIframe: {
|
|
|
+ currentHeight: bottomIframe.style.height,
|
|
|
+ offsetHeight: bottomIframe.offsetHeight,
|
|
|
+ },
|
|
|
+ newTopHeight: this.topIframeHeight,
|
|
|
+ newBottomHeight: this.bottomIframeHeight,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 直接应用新高度到iframe
|
|
|
+ topIframe.style.height = `${this.topIframeHeight}px`;
|
|
|
+ bottomIframe.style.height = `${this.bottomIframeHeight}px`;
|
|
|
+
|
|
|
+ console.log("🎯 应用iframe高度:", {
|
|
|
+ top: this.topIframeHeight,
|
|
|
+ bottom: this.bottomIframeHeight,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 强制重新计算iframe内容
|
|
|
+ this.$nextTick(() => {
|
|
|
+ try {
|
|
|
+ topIframe.contentWindow.dispatchEvent(new Event("resize"));
|
|
|
+ } catch (e) {
|
|
|
+ // 忽略跨域错误
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ bottomIframe.contentWindow.dispatchEvent(
|
|
|
+ new Event("resize")
|
|
|
+ );
|
|
|
+ } catch (e) {
|
|
|
+ // 忽略跨域错误
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log("✅ iframe高度更新完成");
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 快速版本的高度应用,用于拖拽时减少延迟
|
|
|
+ applyIframeHeightsFast() {
|
|
|
+ const topIframe = document.querySelector(".top-iframe");
|
|
|
+ const bottomIframe = document.querySelector(".bottom-iframe");
|
|
|
+
|
|
|
+ if (topIframe && bottomIframe) {
|
|
|
+ // 直接设置高度,不进行日志和额外的处理
|
|
|
+ topIframe.style.height = `${this.topIframeHeight}px`;
|
|
|
+ bottomIframe.style.height = `${this.bottomIframeHeight}px`;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 计算iframe高度分配
|
|
|
+ calculateHeights(bottomHeight) {
|
|
|
+ // 计算实际可用的bottom iframe高度
|
|
|
+ // 当bottom iframe展开时,可以覆盖top iframe,所以最大高度就是availableHeight
|
|
|
+ // 最小高度不能小于header-section高度
|
|
|
+ const bottomActualHeight = Math.max(
|
|
|
+ this.bottomIframeMinHeight,
|
|
|
+ Math.min(bottomHeight, this.availableHeight)
|
|
|
+ );
|
|
|
+
|
|
|
+ this.bottomIframeHeight = bottomActualHeight;
|
|
|
+ this.topIframeHeight = this.availableHeight - bottomActualHeight;
|
|
|
+
|
|
|
+ console.log("📐 高度分配计算:", {
|
|
|
+ requestedBottom: bottomHeight,
|
|
|
+ availableHeight: this.availableHeight,
|
|
|
+ minBottomHeight: this.bottomIframeMinHeight,
|
|
|
+ actualBottom: this.bottomIframeHeight,
|
|
|
+ actualTop: this.topIframeHeight,
|
|
|
+ isExpanded: this.isExpanded,
|
|
|
+ });
|
|
|
+
|
|
|
+ this.applyIframeHeights();
|
|
|
+
|
|
|
+ return {
|
|
|
+ top: this.topIframeHeight,
|
|
|
+ bottom: this.bottomIframeHeight,
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ // 切换展开/收起状态
|
|
|
+ toggleExpand() {
|
|
|
+ if (!this.layoutCalculated) {
|
|
|
+ console.warn("布局尚未计算完成");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.isExpanded = !this.isExpanded;
|
|
|
+
|
|
|
+ if (this.isExpanded) {
|
|
|
+ // 展开:bottom iframe占用所有可用高度,覆盖top iframe到title底部
|
|
|
+ // 也就是bottom iframe高度 = availableHeight (title + button之间的所有空间)
|
|
|
+ this.calculateHeights(this.availableHeight);
|
|
|
+ console.log(
|
|
|
+ "📈 展开状态 - 覆盖到title底部,高度:",
|
|
|
+ this.availableHeight
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ // 收起:bottom iframe占用最小高度(header-section高度)
|
|
|
+ this.calculateHeights(this.bottomIframeMinHeight);
|
|
|
+ console.log(
|
|
|
+ "📉 收起状态 - 最小高度:",
|
|
|
+ this.bottomIframeMinHeight
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 处理来自iframe的消息
|
|
|
+ handleIframeMessage(event) {
|
|
|
+ // 安全检查:只接受同源的消息
|
|
|
+ if (event.origin !== window.location.origin) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const { type, data } = event.data;
|
|
|
+
|
|
|
+ switch (type) {
|
|
|
+ case "header-section-click":
|
|
|
+ console.log("📱 收到header-section点击事件");
|
|
|
+ this.toggleExpand();
|
|
|
+ break;
|
|
|
+ case "header-section-drag-start":
|
|
|
+ console.log("🔄 开始拖拽header-section");
|
|
|
+ this.handleDragStart(data);
|
|
|
+ break;
|
|
|
+ case "header-section-drag-move":
|
|
|
+ console.log("🔄 拖拽中:", data.deltaY);
|
|
|
+ this.handleDragMove(data.deltaY);
|
|
|
+ break;
|
|
|
+ case "header-section-drag-end":
|
|
|
+ console.log("🔚 结束拖拽");
|
|
|
+ this.handleDragEnd();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 处理拖拽开始
|
|
|
+ handleDragStart(data) {
|
|
|
+ if (!this.layoutCalculated) return;
|
|
|
+
|
|
|
+ this.isDragging = true;
|
|
|
+ this.dragStartY = data.startY;
|
|
|
+ this.dragStartBottomHeight = this.bottomIframeHeight;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 处理拖拽移动
|
|
|
+ handleDragMove(deltaY) {
|
|
|
+ if (!this.isDragging || !this.layoutCalculated) return;
|
|
|
+
|
|
|
+ // 计算新的底部高度
|
|
|
+ const newBottomHeight = this.dragStartBottomHeight - deltaY;
|
|
|
+
|
|
|
+ // 直接设置高度,避免复杂的计算导致的延迟
|
|
|
+ const bottomActualHeight = Math.max(
|
|
|
+ this.bottomIframeMinHeight,
|
|
|
+ Math.min(newBottomHeight, this.availableHeight)
|
|
|
+ );
|
|
|
+
|
|
|
+ this.bottomIframeHeight = bottomActualHeight;
|
|
|
+ this.topIframeHeight = this.availableHeight - bottomActualHeight;
|
|
|
+
|
|
|
+ // 直接应用高度,减少延迟
|
|
|
+ this.applyIframeHeightsFast();
|
|
|
+ },
|
|
|
+
|
|
|
+ // 处理拖拽结束
|
|
|
+ handleDragEnd() {
|
|
|
+ this.isDragging = false;
|
|
|
+ this.dragStartY = 0;
|
|
|
+ this.dragStartBottomHeight = 0;
|
|
|
+
|
|
|
+ // 拖拽结束后用完整的方法确保状态正确
|
|
|
+ this.applyIframeHeights();
|
|
|
+ },
|
|
|
+ },
|
|
|
+ });
|
|
|
+ });
|
|
|
+ </script>
|
|
|
+ </body>
|
|
|
+</html>
|