mp_stateChgChk.html 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta
  6. name="viewport"
  7. content="width=device-width, initial-scale=1.0, user-scalable=no"
  8. />
  9. <title>审核</title>
  10. <script src="/js/mp_base/base.js"></script>
  11. <style>
  12. [v-cloak] {
  13. display: none !important;
  14. }
  15. #app {
  16. background: #f5f5f5;
  17. height: 100vh;
  18. display: flex;
  19. flex-direction: column;
  20. overflow: hidden;
  21. box-sizing: border-box;
  22. }
  23. .content-wrap {
  24. flex: 1;
  25. display: flex;
  26. flex-direction: column;
  27. gap: 8px;
  28. padding: 8px;
  29. box-sizing: border-box;
  30. overflow: hidden;
  31. }
  32. .frame-card {
  33. background: #fff;
  34. border-radius: 8px;
  35. overflow: hidden;
  36. box-sizing: border-box;
  37. }
  38. .info-frame-wrap {
  39. flex: 0 0 176px;
  40. }
  41. .sh-frame-wrap {
  42. flex: 1;
  43. min-height: 0;
  44. }
  45. .info-iframe,
  46. .sh-iframe {
  47. width: 100%;
  48. height: 100%;
  49. border: none;
  50. display: block;
  51. background: #fff;
  52. }
  53. .status-wrap {
  54. flex: 1;
  55. display: flex;
  56. align-items: center;
  57. justify-content: center;
  58. padding: 16px;
  59. box-sizing: border-box;
  60. }
  61. .status-card {
  62. width: 100%;
  63. max-width: 520px;
  64. background: #fff;
  65. border-radius: 8px;
  66. padding: 16px;
  67. box-sizing: border-box;
  68. box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
  69. }
  70. .status-title {
  71. font-size: 15px;
  72. font-weight: 600;
  73. color: #2d3748;
  74. }
  75. .status-text {
  76. margin-top: 8px;
  77. line-height: 1.6;
  78. color: #4a5568;
  79. font-size: 13px;
  80. word-break: break-all;
  81. }
  82. .status-retry {
  83. margin-top: 12px;
  84. height: 34px;
  85. padding: 0 14px;
  86. border: none;
  87. border-radius: 4px;
  88. background: #4a5568;
  89. color: #fff;
  90. font-size: 13px;
  91. }
  92. .url-log-fab {
  93. position: fixed;
  94. right: 12px;
  95. bottom: 72px;
  96. z-index: 1200;
  97. border: none;
  98. border-radius: 16px;
  99. background: rgba(36, 40, 53, 0.88);
  100. color: #fff;
  101. font-size: 12px;
  102. line-height: 1;
  103. padding: 8px 10px;
  104. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
  105. }
  106. .url-log-panel {
  107. position: fixed;
  108. left: 12px;
  109. right: 12px;
  110. bottom: 116px;
  111. z-index: 1200;
  112. background: rgba(36, 40, 53, 0.96);
  113. color: #fff;
  114. border-radius: 8px;
  115. padding: 10px;
  116. max-height: 42vh;
  117. overflow: auto;
  118. box-sizing: border-box;
  119. }
  120. .url-log-panel__head {
  121. display: flex;
  122. align-items: center;
  123. justify-content: space-between;
  124. margin-bottom: 8px;
  125. font-size: 12px;
  126. }
  127. .url-log-panel__close {
  128. border: none;
  129. background: transparent;
  130. color: #fff;
  131. font-size: 14px;
  132. line-height: 1;
  133. }
  134. .url-log-panel__body {
  135. margin: 0;
  136. white-space: pre-wrap;
  137. word-break: break-all;
  138. font-size: 12px;
  139. line-height: 1.5;
  140. }
  141. </style>
  142. </head>
  143. <body>
  144. <div id="app" v-cloak>
  145. <div class="content-wrap" v-if="initStatus === 'ready'">
  146. <div class="frame-card info-frame-wrap">
  147. <iframe
  148. ref="infoIframe"
  149. class="info-iframe"
  150. :src="topIframeSrc || 'about:blank'"
  151. frameborder="0"
  152. ></iframe>
  153. </div>
  154. <div class="frame-card sh-frame-wrap">
  155. <iframe
  156. ref="shIframe"
  157. class="sh-iframe"
  158. :src="shIframeSrc || 'about:blank'"
  159. frameborder="0"
  160. ></iframe>
  161. </div>
  162. </div>
  163. <div class="status-wrap" v-else>
  164. <div class="status-card">
  165. <div class="status-title">{{ initStatusTitle }}</div>
  166. <div class="status-text">{{ initStatusMessage }}</div>
  167. <div class="status-text" v-if="missingParams.length > 0">
  168. 缺少参数:{{ missingParams.join('、') }}
  169. </div>
  170. <button class="status-retry" type="button" @click="callApi">
  171. 重新加载
  172. </button>
  173. </div>
  174. </div>
  175. <ss-bottom
  176. :buttons="bottomButtons"
  177. :show-shyj="true"
  178. @button-click="handleBottomAction"
  179. :disabled="submitting"
  180. v-if="initStatus === 'ready' && bottomButtons.length > 0"
  181. ></ss-bottom>
  182. <button class="url-log-fab" type="button" @click="showCurrentUrls">
  183. URL
  184. </button>
  185. <div class="url-log-panel" v-if="urlLogVisible">
  186. <div class="url-log-panel__head">
  187. <span>当前 URL</span>
  188. <button
  189. class="url-log-panel__close"
  190. type="button"
  191. @click="urlLogVisible = false"
  192. >
  193. ×
  194. </button>
  195. </div>
  196. <pre class="url-log-panel__body">{{ urlLogText }}</pre>
  197. </div>
  198. </div>
  199. <script>
  200. window.SS.ready(function () {
  201. window.SS.dom.initializeFormApp({
  202. el: '#app',
  203. data() {
  204. return {
  205. pageParams: {},
  206. loading: false,
  207. submitting: false,
  208. jdmc: '',
  209. sqid: '',
  210. shid: '',
  211. shyjm: '',
  212. bdlbm: '',
  213. dataType: 'bdplay',
  214. encode_shid: '',
  215. ssObjName: '',
  216. ssObjId: '',
  217. initStatus: 'loading',
  218. initStatusTitle: '页面初始化中',
  219. initStatusMessage: '正在加载审核数据,请稍候...',
  220. missingParams: [],
  221. infoData: null,
  222. actionAgreeData: null,
  223. actionRejectData: null,
  224. bottomButtons: [],
  225. topIframeSrc: '',
  226. shIframeSrc: '',
  227. urlLogVisible: false,
  228. urlLogText: '',
  229. };
  230. },
  231. mounted() {
  232. this.pageParams = this.getUrlParams();
  233. this.callApi();
  234. },
  235. methods: {
  236. // 功能说明:stateChgSure 改为复用 chgChk 审核结构,只保留概要信息和审核记录 by xu 2026-03-09
  237. setInitStatus(status, title, message) {
  238. this.initStatus = status;
  239. this.initStatusTitle = title || '';
  240. this.initStatusMessage = message || '';
  241. },
  242. normalizeError(error) {
  243. return {
  244. message: (error && error.message) || String(error),
  245. };
  246. },
  247. getUrlParams() {
  248. const params = {};
  249. const aliasMap = {
  250. ssobjname: 'ssObjName',
  251. ssobjid: 'ssObjId',
  252. sqid: 'sqid',
  253. shid: 'shid',
  254. shyjm: 'shyjm',
  255. bdlbm: 'bdlbm',
  256. datatype: 'dataType',
  257. encode_shid: 'encode_shid',
  258. jdmc: 'jdmc',
  259. };
  260. const urlSearchParams = new URLSearchParams(window.location.search);
  261. for (const [rawKey, rawValue] of urlSearchParams) {
  262. const decodedValue = this.safeDecode(rawValue);
  263. params[rawKey] = decodedValue;
  264. const normalizedKey = aliasMap[String(rawKey).toLowerCase()];
  265. if (normalizedKey) {
  266. params[normalizedKey] = decodedValue;
  267. }
  268. }
  269. return params;
  270. },
  271. safeDecode(text) {
  272. if (text === undefined || text === null || text === '') return '';
  273. try {
  274. return decodeURIComponent(String(text));
  275. } catch (_) {
  276. return String(text);
  277. }
  278. },
  279. pickFirstValue(sources, keys) {
  280. const srcArr = Array.isArray(sources) ? sources : [];
  281. const keyArr = Array.isArray(keys) ? keys : [];
  282. for (let i = 0; i < srcArr.length; i += 1) {
  283. const src = srcArr[i];
  284. if (!src || typeof src !== 'object') continue;
  285. for (let j = 0; j < keyArr.length; j += 1) {
  286. const key = keyArr[j];
  287. const value = src[key];
  288. if (value !== undefined && value !== null && value !== '') {
  289. return value;
  290. }
  291. }
  292. }
  293. return '';
  294. },
  295. extractTokenData(apiResponse) {
  296. const wantedKeys = [
  297. 'sqid',
  298. 'shid',
  299. 'ssObjName',
  300. 'ssObjId',
  301. 'jdmc',
  302. 'bdlbm',
  303. 'dataType',
  304. 'encode_shid',
  305. ];
  306. const candidates = [
  307. apiResponse && apiResponse.data && apiResponse.data.ssData,
  308. apiResponse && apiResponse.ssData,
  309. apiResponse && apiResponse.data,
  310. apiResponse,
  311. ];
  312. let best = {};
  313. let bestScore = -1;
  314. candidates.forEach((item) => {
  315. if (!item || typeof item !== 'object') return;
  316. let score = 0;
  317. wantedKeys.forEach((key) => {
  318. if (
  319. item[key] !== undefined &&
  320. item[key] !== null &&
  321. item[key] !== ''
  322. ) {
  323. score += 1;
  324. }
  325. });
  326. if (score > bestScore) {
  327. best = item;
  328. bestScore = score;
  329. }
  330. });
  331. return best;
  332. },
  333. resolveBusinessContext(apiResponse) {
  334. const tokenData = this.extractTokenData(apiResponse);
  335. const sources = [tokenData, this.pageParams];
  336. return {
  337. sqid: String(this.pickFirstValue(sources, ['sqid']) || ''),
  338. shid: String(this.pickFirstValue(sources, ['shid']) || ''),
  339. shyjm: String(this.pickFirstValue(sources, ['shyjm']) || ''),
  340. ssObjName: String(
  341. this.pickFirstValue(sources, ['ssObjName', 'ssobjname']) || ''
  342. ),
  343. ssObjId: String(
  344. this.pickFirstValue(sources, ['ssObjId', 'ssobjid']) || ''
  345. ),
  346. bdlbm: String(this.pickFirstValue(sources, ['bdlbm']) || ''),
  347. dataType:
  348. String(
  349. this.pickFirstValue(sources, ['dataType', 'datatype']) ||
  350. this.dataType ||
  351. 'bdplay'
  352. ) || 'bdplay',
  353. encode_shid: String(
  354. this.pickFirstValue(sources, ['encode_shid']) || ''
  355. ),
  356. jdmc: String(this.pickFirstValue(sources, ['jdmc']) || ''),
  357. };
  358. },
  359. parseInfoParm(rawParm) {
  360. if (!rawParm) return {};
  361. if (typeof rawParm === 'object') return rawParm;
  362. const text = String(rawParm).trim();
  363. if (!text) return {};
  364. try {
  365. return JSON.parse(text);
  366. } catch (_) {}
  367. try {
  368. const normalized = text
  369. .replace(/([{,]\s*)([A-Za-z0-9_]+)\s*:/g, '$1"$2":')
  370. .replace(/'/g, '"');
  371. return JSON.parse(normalized);
  372. } catch (_) {
  373. return {};
  374. }
  375. },
  376. resolveInfoDestPath(destName) {
  377. const raw = String(destName || '').trim();
  378. if (!raw) return '';
  379. if (/^https?:\/\//i.test(raw)) return raw;
  380. if (raw.startsWith('/')) return raw;
  381. if (raw.endsWith('.html')) return `/page/${raw}`;
  382. if (raw.startsWith('mp_')) return `/page/${raw}.html`;
  383. return `/page/mp_${raw}.html`;
  384. },
  385. buildInfoIframeSrc(infoData, fallbackQuery) {
  386. const conf = infoData && typeof infoData === 'object' ? infoData : {};
  387. const serviceName = conf.service || conf.servName || '';
  388. const destName = conf.dest || '';
  389. const parmObj = this.parseInfoParm(conf.parm);
  390. const mergedQuery = {
  391. ...(fallbackQuery || {}),
  392. ...(parmObj || {}),
  393. };
  394. if (!serviceName || !destName) {
  395. return this.buildIframeSrc('/page/mp_objInfo.html', mergedQuery);
  396. }
  397. const pagePath = this.resolveInfoDestPath(destName);
  398. if (!pagePath) {
  399. return this.buildIframeSrc('/page/mp_objInfo.html', mergedQuery);
  400. }
  401. const paramText =
  402. typeof conf.parm === 'string'
  403. ? conf.parm
  404. : JSON.stringify(parmObj || {});
  405. const iframeQuery = {
  406. ...mergedQuery,
  407. ssServ: serviceName,
  408. ssDest: destName,
  409. service: serviceName,
  410. dest: destName,
  411. param: paramText,
  412. };
  413. return this.buildIframeSrc(pagePath, iframeQuery);
  414. },
  415. buildIframeSrc(path, queryObj) {
  416. const search = new URLSearchParams(queryObj);
  417. return `${path}?${search.toString()}`;
  418. },
  419. buildCommonQuery() {
  420. return {
  421. sqid: this.sqid,
  422. shid: this.shid,
  423. shyjm: this.shyjm,
  424. bdlbm: this.bdlbm,
  425. dataType: this.dataType,
  426. encode_shid: this.encode_shid,
  427. ssObjName: this.ssObjName,
  428. ssObjId: this.ssObjId,
  429. jdmc: this.jdmc,
  430. };
  431. },
  432. normalizeActionConfig(config) {
  433. if (!config || typeof config !== 'object') return null;
  434. const normalized = { ...config };
  435. if (!normalized.service && normalized.servName) {
  436. normalized.service = normalized.servName;
  437. }
  438. return normalized;
  439. },
  440. async fetchActionConfigs() {
  441. // 功能说明:沿用 chgChk 的 bdlbm 动作规则,支持同意/退回 by xu 2026-03-09
  442. const query = `ssObjName=${encodeURIComponent(
  443. this.ssObjName
  444. )}&ssObjId=${encodeURIComponent(
  445. this.ssObjId
  446. )}&sqid=${encodeURIComponent(
  447. this.sqid
  448. )}&shid=${encodeURIComponent(
  449. this.shid
  450. )}&bdlbm=${encodeURIComponent(
  451. this.bdlbm
  452. )}&dataType=${encodeURIComponent(
  453. this.dataType
  454. )}&encode_shid=${encodeURIComponent(this.encode_shid)}`;
  455. let agreeTag = '';
  456. let rejectTag = '';
  457. if (String(this.bdlbm) === '55') {
  458. agreeTag = 'agrRes';
  459. rejectTag = 'rejRes';
  460. } else if (String(this.bdlbm) === '51') {
  461. agreeTag = 'agrSus';
  462. rejectTag = 'rejSus';
  463. } else if (!['1', '51', '55'].includes(String(this.bdlbm))) {
  464. agreeTag = 'agrChg';
  465. rejectTag = 'rejChg';
  466. }
  467. this.actionAgreeData = null;
  468. this.actionRejectData = null;
  469. const buttons = [];
  470. if (rejectTag) {
  471. const rejectRes = await request.post(
  472. `/service?ssServ=dataTag&ssDest=data&name=${rejectTag}&${query}`,
  473. {},
  474. { loading: false, formData: true }
  475. );
  476. this.actionRejectData = this.normalizeActionConfig(
  477. rejectRes && rejectRes.data ? rejectRes.data[rejectTag] : null
  478. );
  479. if (
  480. this.actionRejectData &&
  481. this.actionRejectData.service &&
  482. this.actionRejectData.dest
  483. ) {
  484. buttons.push({ text: '退回', action: 'reject' });
  485. }
  486. }
  487. if (agreeTag) {
  488. const agreeRes = await request.post(
  489. `/service?ssServ=dataTag&ssDest=data&name=${agreeTag}&${query}`,
  490. {},
  491. { loading: false, formData: true }
  492. );
  493. this.actionAgreeData = this.normalizeActionConfig(
  494. agreeRes && agreeRes.data ? agreeRes.data[agreeTag] : null
  495. );
  496. if (
  497. this.actionAgreeData &&
  498. this.actionAgreeData.service &&
  499. this.actionAgreeData.dest
  500. ) {
  501. buttons.push({ text: '同意', action: 'agree' });
  502. }
  503. }
  504. this.bottomButtons = buttons;
  505. },
  506. async callApi() {
  507. this.loading = true;
  508. this.infoData = null;
  509. this.actionAgreeData = null;
  510. this.actionRejectData = null;
  511. this.bottomButtons = [];
  512. this.topIframeSrc = '';
  513. this.shIframeSrc = '';
  514. this.missingParams = [];
  515. this.setInitStatus(
  516. 'loading',
  517. '页面初始化中',
  518. '正在加载审核数据,请稍候...'
  519. );
  520. let apiResponse = null;
  521. try {
  522. if (this.pageParams.ssToken) {
  523. const tokenUrl = `/service?ssToken=${this.pageParams.ssToken}`;
  524. apiResponse = await request.post(tokenUrl, {}, { loading: false });
  525. }
  526. const context = this.resolveBusinessContext(apiResponse);
  527. this.sqid = context.sqid;
  528. this.shid = context.shid;
  529. this.shyjm = context.shyjm;
  530. this.ssObjName = context.ssObjName;
  531. this.ssObjId = context.ssObjId;
  532. this.bdlbm = context.bdlbm;
  533. this.dataType = context.dataType || 'bdplay';
  534. this.encode_shid = context.encode_shid;
  535. this.jdmc = context.jdmc;
  536. ['sqid', 'shid', 'ssObjName', 'ssObjId'].forEach((key) => {
  537. if (!this[key]) this.missingParams.push(key);
  538. });
  539. if (this.missingParams.length > 0) {
  540. this.setInitStatus(
  541. 'error',
  542. '页面参数不完整',
  543. '缺少关键参数,无法加载审核数据'
  544. );
  545. return;
  546. }
  547. const query = this.buildCommonQuery();
  548. const infoUrl = `/service?ssServ=dataTag&ssDest=data&name=info&ssObjName=${encodeURIComponent(
  549. this.ssObjName
  550. )}&ssObjId=${encodeURIComponent(
  551. this.ssObjId
  552. )}&sqid=${encodeURIComponent(
  553. this.sqid
  554. )}&shid=${encodeURIComponent(this.shid)}`;
  555. const infoRes = await request.post(
  556. infoUrl,
  557. {},
  558. { loading: false, formData: true }
  559. );
  560. this.infoData = infoRes && infoRes.data ? infoRes.data.info : null;
  561. this.topIframeSrc = this.buildInfoIframeSrc(this.infoData, query);
  562. // 功能说明:按你的要求,不显示 chgChk.ss.jsp 中“变动属性对比”的中间 iframe by xu 2026-03-09
  563. this.shIframeSrc = this.buildIframeSrc('/page/mp_shList.html', query);
  564. await this.fetchActionConfigs();
  565. this.setInitStatus('ready', '页面已就绪', '审核数据加载完成');
  566. } catch (error) {
  567. const normalized = this.normalizeError(error);
  568. this.setInitStatus(
  569. 'error',
  570. '页面初始化失败',
  571. normalized.message || '页面初始化失败,请稍后重试'
  572. );
  573. console.error('[mp_stateChgSure] 初始化失败', error);
  574. if (typeof showToastEffect === 'function') {
  575. showToastEffect('页面初始化失败,请稍后重试', 2200, 'error');
  576. }
  577. } finally {
  578. this.loading = false;
  579. }
  580. },
  581. buildSubmitPayload(actionPayload) {
  582. const submitPayload = {};
  583. if (this.shid) submitPayload.shid = this.shid;
  584. if (this.sqid) submitPayload.sqid = this.sqid;
  585. if (this.ssObjName) submitPayload.ssObjName = this.ssObjName;
  586. if (this.ssObjId) submitPayload.ssObjId = this.ssObjId;
  587. const payloadObj =
  588. actionPayload && typeof actionPayload === 'object'
  589. ? actionPayload
  590. : {};
  591. const reviewValue = this.pickFirstValue(
  592. [payloadObj],
  593. [
  594. 'shsm',
  595. 'shyjValue',
  596. 'shyj',
  597. 'spyj',
  598. 'opinion',
  599. 'comment',
  600. 'remark',
  601. 'reason',
  602. 'yj',
  603. ]
  604. );
  605. if (
  606. reviewValue !== undefined &&
  607. reviewValue !== null &&
  608. reviewValue !== ''
  609. ) {
  610. submitPayload.shsm = String(reviewValue);
  611. }
  612. return submitPayload;
  613. },
  614. goBackWithRefresh() {
  615. if (
  616. window.NavigationManager &&
  617. typeof window.NavigationManager.goBack === 'function'
  618. ) {
  619. window.NavigationManager.goBack({ refreshParent: true });
  620. return;
  621. }
  622. window.history.back();
  623. },
  624. async submitByConfig(conf, actionPayload) {
  625. const serviceName = conf && (conf.service || conf.servName);
  626. const destName = conf && conf.dest;
  627. if (!conf || !serviceName || !destName) {
  628. if (typeof showToastEffect === 'function') {
  629. showToastEffect('缺少提交配置', 2200, 'error');
  630. }
  631. return;
  632. }
  633. if (this.submitting) return;
  634. try {
  635. this.submitting = true;
  636. await request.post(
  637. `/service?ssServ=${encodeURIComponent(
  638. serviceName
  639. )}&ssDest=${encodeURIComponent(destName)}`,
  640. this.buildSubmitPayload(actionPayload),
  641. {
  642. loading: true,
  643. formData: true,
  644. }
  645. );
  646. if (typeof showToastEffect === 'function') {
  647. showToastEffect('提交成功', 1200, 'success');
  648. }
  649. setTimeout(() => {
  650. this.goBackWithRefresh();
  651. }, 300);
  652. } catch (error) {
  653. console.error('[mp_stateChgSure] 提交失败', error);
  654. if (typeof showToastEffect === 'function') {
  655. showToastEffect('提交失败,请稍后重试', 2200, 'error');
  656. }
  657. } finally {
  658. this.submitting = false;
  659. }
  660. },
  661. handleBottomAction(payload) {
  662. if (!payload || !payload.action) return;
  663. if (payload.action === 'agree') {
  664. this.submitByConfig(this.actionAgreeData, payload);
  665. return;
  666. }
  667. if (payload.action === 'reject') {
  668. this.submitByConfig(this.actionRejectData, payload);
  669. }
  670. },
  671. showCurrentUrls() {
  672. const lines = [
  673. `page: ${window.location.href}`,
  674. `info: ${
  675. (this.$refs.infoIframe && this.$refs.infoIframe.src) ||
  676. this.topIframeSrc ||
  677. '(empty)'
  678. }`,
  679. `sh: ${
  680. (this.$refs.shIframe && this.$refs.shIframe.src) ||
  681. this.shIframeSrc ||
  682. '(empty)'
  683. }`,
  684. ];
  685. this.urlLogText = lines.join('\n');
  686. this.urlLogVisible = true;
  687. },
  688. },
  689. });
  690. });
  691. </script>
  692. </body>
  693. </html>