diff --git a/README.md b/README.md index b975ce3..3291160 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ #### 1 下载安装包 下载安装包: -[阿里云](https://dev-sidecar.docmirror.cn/update/DevSidecar-1.2.1.exe) +[阿里云](https://dev-sidecar.docmirror.cn/update/DevSidecar-1.2.2.exe) [Gitee Release](https://gitee.com/docmirror/dev-sidecar/releases) [Github Release](https://github.com/docmirror/dev-sidecar/releases) diff --git a/lerna.json b/lerna.json index a205513..1520f62 100644 --- a/lerna.json +++ b/lerna.json @@ -14,5 +14,5 @@ "ignore": [] } }, - "version": "1.2.1" + "version": "1.2.2" } diff --git a/packages/core/package-lock.json b/packages/core/package-lock.json index 2873ad7..0ac3d8c 100644 --- a/packages/core/package-lock.json +++ b/packages/core/package-lock.json @@ -1,6 +1,6 @@ { "name": "@docmirror/dev-sidecar", - "version": "1.2.1", + "version": "1.2.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/core/package.json b/packages/core/package.json index 9242539..b1ec296 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@docmirror/dev-sidecar", - "version": "1.2.1", + "version": "1.2.2", "description": "给开发者的加速代理工具", "main": "src/index.js", "keywords": [ @@ -16,7 +16,7 @@ "start": "node ./start" }, "dependencies": { - "@docmirror/mitmproxy": "^1.2.1", + "@docmirror/mitmproxy": "^1.2.2", "agentkeepalive": "^2.1.1", "charset": "^1.0.0", "child_process": "^1.0.2", diff --git a/packages/core/src/config/index.js b/packages/core/src/config/index.js index 2bf7a88..45af6b7 100644 --- a/packages/core/src/config/index.js +++ b/packages/core/src/config/index.js @@ -49,11 +49,11 @@ module.exports = { desc: 'clone加速复制链接脚本' }, '/.*': { - proxy: 'github.com', + proxy: 'gh.docmirror.top/_proxy', backup: [ - 'gh.docmirror.top/_proxy' + 'github.com' ], - desc: '如果出现dev-sidecar报错,可能是备用加速地址dns被污染了,需要将本条配置删除' + desc: '如果出现dev-sidecar报错,可能是加速地址dns被污染了,需要将本条配置删除' } }, 'api.github.com': { @@ -77,6 +77,13 @@ module.exports = { '.*': { proxy: 'customer-stories-feed.fastgit.org' } }, // google cdn + 'www.google.com': { + '/recaptcha/.*': { proxy: 'www.recaptcha.net' }, + '.*': { + proxy: 'gg.docmirror.top/_yxorp', + desc: '呀,被你发现了,偷偷的用,别声张' + } + }, 'ajax.googleapis.com': { '.*': { proxy: 'ajax.loli.net', @@ -99,9 +106,6 @@ module.exports = { 'themes.googleusercontent.com': { '.*': { proxy: 'google-themes.proxy.ustclug.org' } }, - 'www.google.com': { - '/recaptcha/.*': { proxy: 'www.recaptcha.net' } - }, 'fonts.gstatic.com': { '.*': { proxy: 'gstatic.loli.net', diff --git a/packages/core/src/shell/scripts/set-system-proxy/index.js b/packages/core/src/shell/scripts/set-system-proxy/index.js index e712be4..1800ea3 100644 --- a/packages/core/src/shell/scripts/set-system-proxy/index.js +++ b/packages/core/src/shell/scripts/set-system-proxy/index.js @@ -3,11 +3,12 @@ */ const Shell = require('../../shell') const execute = Shell.execute +const execFile = Shell.execFile const Registry = require('winreg') -// const cmd = require('node-cmd') const refreshInternetPs = require('./refresh-internet') const PowerShell = require('node-powershell') const log = require('../../../utils/util.log') +const path = require('path') const _lanIP = [ 'localhost', '127.*', @@ -33,6 +34,12 @@ const _lanIP = [ ] async function _winUnsetProxy (exec) { + // eslint-disable-next-line no-constant-condition + if (true) { + const proxyPath = getProxyExePath() + await execFile(proxyPath, ['set', '1']) + return + } const regKey = new Registry({ hive: Registry.HKCU, key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings' @@ -48,16 +55,31 @@ async function _winUnsetProxy (exec) { return true } +function getProxyExePath () { + const proxyPath = process.env.DS_SYSPROXY_PATH + log.info('proxyPath', proxyPath) + if (proxyPath) { + return proxyPath + } + return path.join(__dirname, './sysproxy.exe') +} + async function _winSetProxy (exec, ip, port) { + let lanIpStr = '' + for (const string of _lanIP) { + lanIpStr += string + ';' + } + // eslint-disable-next-line no-constant-condition + if (true) { + const proxyPath = getProxyExePath() + await execFile(proxyPath, ['global', `${ip}:${port}`, lanIpStr]) + return + } const regKey = new Registry({ hive: Registry.HKCU, key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings' }) - let lanIpStr = '' - for (const string of _lanIP) { - lanIpStr += string + ';' - } // log.info('lanIps:', lanIpStr, ip, port) await Promise.all([ _winAsyncRegSet(regKey, 'MigrateProxy', Registry.REG_DWORD, 1), diff --git a/packages/core/src/shell/scripts/set-system-proxy/sysproxy.exe b/packages/core/src/shell/scripts/set-system-proxy/sysproxy.exe new file mode 100644 index 0000000..979858b Binary files /dev/null and b/packages/core/src/shell/scripts/set-system-proxy/sysproxy.exe differ diff --git a/packages/core/src/shell/shell.js b/packages/core/src/shell/shell.js index 600e54a..15e658c 100644 --- a/packages/core/src/shell/shell.js +++ b/packages/core/src/shell/shell.js @@ -2,6 +2,7 @@ const util = require('util') const os = require('os') const childProcess = require('child_process') const _exec = childProcess.exec +const _execFile = childProcess.execFile const exec = util.promisify(_exec) const PowerShell = require('node-powershell') const log = require('../utils/util.log') @@ -119,8 +120,23 @@ async function execute (executor, args) { return executor[getSystemPlatform()](getSystemShell().exec, args) } +async function execFile (file, args, options) { + return new Promise((resolve, reject) => { + _execFile(file, args, options, (err, stdout) => { + if (err) { + log.error('文件执行出错:', file, err) + reject(err) + return + } + log.debug('执行成功:', stdout) + resolve(stdout) + }) + }) +} + module.exports = { getSystemShell, getSystemPlatform, - execute + execute, + execFile } diff --git a/packages/core/src/utils/util.log.js b/packages/core/src/utils/util.log.js index f729307..a0e5c71 100644 --- a/packages/core/src/utils/util.log.js +++ b/packages/core/src/utils/util.log.js @@ -3,11 +3,12 @@ const config = require('../config/index') function getDefaultConfigBasePath () { return config.server.setting.userBasePath } +const level = process.env.NODE_ENV === 'development' ? 'debug' : 'info' const path = require('path') const filename = path.join(getDefaultConfigBasePath(), '/logs/core.log') log4js.configure({ - appenders: { std: { type: 'stdout' }, file: { type: 'file', pattern: 'yyyy-MM-dd', daysToKeep: 3, filename } }, - categories: { default: { appenders: ['file', 'std'], level: 'info' } } + appenders: { std: { type: 'stdout' }, file: { type: 'file', pattern: 'yyyy-MM-dd', daysToKeep: 3, filename} }, + categories: { default: { appenders: ['file', 'std'], level: level } } }) const logger = log4js.getLogger('server') module.exports = logger diff --git a/packages/gui/extra/scripts/google.js b/packages/gui/extra/scripts/google.js new file mode 100644 index 0000000..41b9ad7 --- /dev/null +++ b/packages/gui/extra/scripts/google.js @@ -0,0 +1,20 @@ +// ==UserScript== +// @name google增强 +// @version 1.2.4 +// @author Greper +// @description 去除ping链接 +// @match https://www.google.com/*/* +// @icon https://www.google.com/favicon.ico +// @license GPL-3.0 License +// @run-at document-end +// @namespace +// ==/UserScript== + +(function () { + console.log('google script loaded') + const aList = document.getElementsByTagName('a') + for (let i = 0; i <= aList.length; i++) { + console.log(aList[i].href) + aList[i].ping = undefined + } +})() diff --git a/packages/gui/extra/sysproxy.exe b/packages/gui/extra/sysproxy.exe new file mode 100644 index 0000000..979858b Binary files /dev/null and b/packages/gui/extra/sysproxy.exe differ diff --git a/packages/gui/package.json b/packages/gui/package.json index f6d09cf..4b2e562 100644 --- a/packages/gui/package.json +++ b/packages/gui/package.json @@ -1,6 +1,6 @@ { "name": "@docmirror/dev-sidecar-gui", - "version": "1.2.1", + "version": "1.2.2", "private": false, "license": "MPL-2.0", "scripts": { @@ -12,10 +12,11 @@ "postuninstall": "electron-builder install-app-deps", "electron:generate-icons": "electron-icon-builder --input=./public/icon.png --output=build --flatten" }, + "author": "docmirror.cn", "main": "background.js", "dependencies": { - "@docmirror/dev-sidecar": "^1.2.1", - "@docmirror/mitmproxy": "^1.2.1", + "@docmirror/dev-sidecar": "^1.2.2", + "@docmirror/mitmproxy": "^1.2.2", "ant-design-vue": "^1.6.5", "core-js": "^3.6.5", "electron-baidu-tongji": "^1.0.5", diff --git a/packages/gui/src/background.js b/packages/gui/src/background.js index 531878c..dcefa2d 100644 --- a/packages/gui/src/background.js +++ b/packages/gui/src/background.js @@ -1,11 +1,10 @@ 'use strict' /* global __static */ import path from 'path' -import { app, protocol, BrowserWindow, Menu, Tray, ipcMain } from 'electron' +import { app, protocol, BrowserWindow, Menu, Tray, ipcMain, dialog } from 'electron' import { createProtocol } from 'vue-cli-plugin-electron-builder/lib' -import bridge from './bridge/index' -import updateHandle from './bridge/update-handle' -import { ebtMain } from './tongji' +import backend from './bridge/backend' +import DevSidecar from '@docmirror/dev-sidecar' import log from './utils/util.log' // eslint-disable-next-line no-unused-vars const isMac = process.platform === 'darwin' @@ -113,7 +112,7 @@ function createWindow () { } async function beforeQuit () { - return bridge.devSidecar.api.shutdown() + return DevSidecar.api.shutdown() } async function quit (app, callback) { if (tray) { @@ -136,12 +135,6 @@ if (!isFirstInstance) { } else { app.on('before-quit', async (event) => { log.info('before-quit') - // event.preventDefault() - // // if (tray) { - // // tray.displayBalloon({ title: '正在关闭,请稍候...', content: '正在关闭中,请稍候。。。' }) - // // } - // await bridge.devSidecar.api.shutdown() - // app.exit() }) app.on('second-instance', (event, commandLine, workingDirectory) => { log.info('new app started', commandLine) @@ -180,24 +173,13 @@ if (!isFirstInstance) { // log.error('Vue Devtools failed to install:', e.toString()) // } } - createWindow() - bridge.init(win) - - let updateUrl = 'https://dev-sidecar.docmirror.cn/update/' - if (process.env.NODE_ENV === 'development') { - Object.defineProperty(app, 'isPackaged', { - get () { - return true - } - }) - updateUrl = 'https://dev-sidecar.docmirror.cn/update/' - // updateUrl = 'http://localhost/dev-sidecar/' + try { + createWindow() + const context = { win, app, beforeQuit, ipcMain, dialog,log } + backend.install(context) // 模块安装 + } catch (err) { + log.info('err', err) } - // 自动更新 - updateHandle(app, win, beforeQuit, updateUrl) - - // 百度分析 - ebtMain(ipcMain, isDevelopment) try { // 最小化到托盘 diff --git a/packages/gui/src/bridge/index.js b/packages/gui/src/bridge/api/backend.js similarity index 88% rename from packages/gui/src/bridge/index.js rename to packages/gui/src/bridge/api/backend.js index caa6fd4..727bb1c 100644 --- a/packages/gui/src/bridge/index.js +++ b/packages/gui/src/bridge/api/backend.js @@ -1,12 +1,13 @@ import lodash from 'lodash' import DevSidecar from '@docmirror/dev-sidecar' -import { ipcMain, Menu } from 'electron' +import { ipcMain } from 'electron' import fs from 'fs' import JSON5 from 'json5' import path from 'path' -const pk = require('../../package.json') +const pk = require('../../../package.json') const mitmproxyPath = path.join(__dirname, 'mitmproxy.js') -const log = require('../utils/util.log') +process.env.DS_SYSPROXY_PATH = path.join(__dirname, '../extra/sysproxy.exe') +const log = require('../../utils/util.log') const getDefaultConfigBasePath = function () { return DevSidecar.api.config.get().server.setting.userBasePath } @@ -170,25 +171,29 @@ function doMerge (defObj, newObj) { return newObj2 } +function invoke (api, param) { + let target = lodash.get(localApi, api) + if (target == null) { + target = lodash.get(DevSidecar.api, api) + } + if (target == null) { + log.info('找不到此接口方法:', api) + } + const ret = target(param) + // log.info('api:', api, 'ret:', ret) + return ret +} + export default { - init (win) { + install ({ win }) { // 接收view的方法调用 ipcMain.handle('apiInvoke', async (event, args) => { const api = args[0] - let target = lodash.get(localApi, api) - if (target == null) { - target = lodash.get(DevSidecar.api, api) - } - if (target == null) { - log.info('找不到此接口方法:', api) - } let param if (args.length >= 2) { param = args[1] } - const ret = target(param) - // log.info('api:', api, 'ret:', ret) - return ret + return invoke(api, param) }) // 注册从core里来的事件,并转发给view DevSidecar.api.event.register('status', (event) => { @@ -205,5 +210,6 @@ export default { // 启动所有 localApi.startup() }, - devSidecar: DevSidecar + devSidecar: DevSidecar, + invoke } diff --git a/packages/gui/src/bridge/backend.js b/packages/gui/src/bridge/backend.js new file mode 100644 index 0000000..3976466 --- /dev/null +++ b/packages/gui/src/bridge/backend.js @@ -0,0 +1,19 @@ +import api from './api/backend' +import tongji from './tongji/backend' +import update from './update/backend' +import fileSelector from './file-selector/backend' + +const modules = { + api, // 核心接口模块 + fileSelector, // 文件选择模块 + tongji, // 统计模块 + update // 自动更新 +} +export default { + install (context) { + for (const module in modules) { + modules[module].install(context) + } + }, + ...modules +} diff --git a/packages/gui/src/view/modules/error/index.js b/packages/gui/src/bridge/error/front.js similarity index 100% rename from packages/gui/src/view/modules/error/index.js rename to packages/gui/src/bridge/error/front.js diff --git a/packages/gui/src/bridge/file-selector/backend.js b/packages/gui/src/bridge/file-selector/backend.js new file mode 100644 index 0000000..63ba83d --- /dev/null +++ b/packages/gui/src/bridge/file-selector/backend.js @@ -0,0 +1,21 @@ +export default { + install (context) { + const { ipcMain, dialog, log } = context + ipcMain.on('file-selector', function (event, message) { + if (message.key === 'open') { + dialog.showOpenDialog({ + properties: ['openFile'], + ...message + }).then(result => { + if (result.canceled) { + event.sender.send('file-selector', { key: 'canceled' }) + } else { + event.sender.send('file-selector', { key: 'selected', value: result.filePaths }) + } + }).catch(err => { + log.error('选择文件失败', err) + }) + } + }) + } +} diff --git a/packages/gui/src/bridge/file-selector/front.js b/packages/gui/src/bridge/file-selector/front.js new file mode 100644 index 0000000..284cdce --- /dev/null +++ b/packages/gui/src/bridge/file-selector/front.js @@ -0,0 +1,23 @@ + +function install (app, api) { + api.fileSelector = { + open (value, options) { + return new Promise((resolve, reject) => { + api.ipc.send('file-selector', { key: 'open', value: value, ...options }) + api.ipc.on('file-selector', (event, message) => { + console.log('selector', message) + if (message.key === 'selected') { + resolve(message.value) + } else { + reject(new Error('没有选择文件')) + } + api.ipc.on('file-selector', () => {}) + }) + }) + } + } +} + +export default { + install +} diff --git a/packages/gui/src/bridge/front.js b/packages/gui/src/bridge/front.js new file mode 100644 index 0000000..18e360a --- /dev/null +++ b/packages/gui/src/bridge/front.js @@ -0,0 +1,21 @@ +// import api from './api/front' +import error from './error/front' +import tongji from './tongji/front' +import update from './update/front' +import fileSelector from './file-selector/front' + +const modules = { + // api, // 核心接口模块 + error, + fileSelector, // 文件选择模块 + tongji, // 统计模块 + update // 自动更新 +} +export default { + install (app, api, router) { + for (const module in modules) { + modules[module].install(app, api, router) + } + }, + ...modules +} diff --git a/packages/gui/src/bridge/mitmproxy.js b/packages/gui/src/bridge/mitmproxy.js index acd487a..9cef1d7 100644 --- a/packages/gui/src/bridge/mitmproxy.js +++ b/packages/gui/src/bridge/mitmproxy.js @@ -1,15 +1,14 @@ // eslint-disable-next-line no-unused-vars const server = require('@docmirror/mitmproxy') const configPath = process.argv[2] - const fs = require('fs') const path = require('path') const configJson = fs.readFileSync(configPath) const config = JSON.parse(configJson) - let scriptDir = '../extra/scripts/' if (process.env.NODE_ENV === 'development') { scriptDir = '../extra/scripts/' } config.setting.script.defaultDir = path.join(__dirname, scriptDir) + server.start(config) diff --git a/packages/gui/src/bridge/tongji/backend.js b/packages/gui/src/bridge/tongji/backend.js new file mode 100644 index 0000000..294badb --- /dev/null +++ b/packages/gui/src/bridge/tongji/backend.js @@ -0,0 +1,55 @@ + +/** + * first step + * @param {*} ipcMain + */ +const ebtMain = (ipcMain) => { + const isDevelopment = process.env.NODE_ENV !== 'production' + const request = require('request') + /* istanbul ignore else */ + if (!(ipcMain && ipcMain.on)) { + throw new TypeError('require ipcMain') + } + + // step 2 + ipcMain.on('electron-baidu-tongji-message', (event, arg) => { + // electron 生产模式下是直接请求文件系统,没有 http 地址 + // 前台拿不到 hm.js 的内容 + request({ + url: `https://hm.baidu.com/hm.js?${arg}`, + method: 'GET', + headers: { + Referer: 'https://hm.baidu.com/' + } + }, + (err, response, body) => { + if (err) { + console.error('百度统计请求出错', err) + return + } + const rource = '(h.c.b.su=h.c.b.u||document.location.href),h.c.b.u=f.protocol+"//"+document.location.host+' + /* istanbul ignore else */ + if (body && body.indexOf(rource) >= 0) { + // step 3 + let text = body + + /* istanbul ignore else */ + if (!isDevelopment) { + // 百度统计可能改规则了,不统计 file:// 开始的请求 + // 这里强制替换为 https + const target = '(h.c.b.su=h.c.b.u||"https://"+c.dm[0]+a[1]),h.c.b.u="https://"+c.dm[0]+' + const target2 = '"https://"+c.dm[0]+window.location.pathname+window.location.hash' + text = body.replace(rource, target).replace(/window.location.href/g, target2) + } + console.log('baidu tonji: ret') + event.sender.send('electron-baidu-tongji-reply', { text, isDevelopment }) + } + }) + }) +} + +export default { + install (context) { + ebtMain(context.ipcMain) + } +} diff --git a/packages/gui/src/bridge/tongji/front.js b/packages/gui/src/bridge/tongji/front.js new file mode 100644 index 0000000..023db8b --- /dev/null +++ b/packages/gui/src/bridge/tongji/front.js @@ -0,0 +1,62 @@ + +/** + * second step + * @param {*} ipcRenderer + * @param {*} siteId + * @param {*} router + */ +const ebtRenderer = (ipcRenderer, siteId, router) => { + /* istanbul ignore else */ + if (!(ipcRenderer && ipcRenderer.on && ipcRenderer.send)) { + throw new TypeError('require ipcRenderer') + } + + /* istanbul ignore else */ + if (!(siteId && typeof siteId === 'string')) { + throw new TypeError('require siteId') + } + + // step 4 + ipcRenderer.on('electron-baidu-tongji-reply', (_, { text, isDevelopment }) => { + console.log('electron-baidu-tongji-reply') + /* istanbul ignore else */ + if (isDevelopment) { document.body.classList.add('electron-baidu-tongji_dev') } + + window._hmt = window._hmt || [] + + const hm = document.createElement('script') + hm.text = text + + const head = document.getElementsByTagName('head')[0] + head.appendChild(hm) + + // Vue单页应用时,监听router的每次变化 + // 把虚拟的url地址赋给百度统计的API接口 + + /* istanbul ignore else */ + if (router && router.beforeEach) { + router.beforeEach((to, _, next) => { + /* istanbul ignore else */ + if (to.path) { + window._hmt.push(['_trackPageview', '/#' + to.fullPath]) + console.log('baidu trace', to.fullPath) + } + + next() + }) + } + }) + + // step 1 + ipcRenderer.send('electron-baidu-tongji-message', siteId) +} + +export default { + install (app, api, router) { + const BAIDU_SITE_ID = 'f2d170ce560aef0005b689f28697f852' + // 百度统计 + const { ipcRenderer } = require('electron') + ebtRenderer(ipcRenderer, BAIDU_SITE_ID, router) + }, + ebtRenderer +} diff --git a/packages/gui/src/bridge/update-handle.js b/packages/gui/src/bridge/update/backend.js similarity index 84% rename from packages/gui/src/bridge/update-handle.js rename to packages/gui/src/bridge/update/backend.js index 1dc2d2f..0237b6d 100644 --- a/packages/gui/src/bridge/update-handle.js +++ b/packages/gui/src/bridge/update/backend.js @@ -1,6 +1,5 @@ -import { ipcMain, dialog } from 'electron' +import { ipcMain } from 'electron' import { autoUpdater } from 'electron-updater' -import log from '../utils/util.log' import path from 'path' // win是所有窗口的引用 // const path = require('path') // 引入path模块 @@ -8,7 +7,7 @@ import path from 'path' // eslint-disable-next-line no-unused-vars const isMac = process.platform === 'darwin' // 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写 -function updateHandle (app, win, beforeQuit, updateUrl) { +function updateHandle (app, win, beforeQuit, updateUrl, log) { // // 更新前,删除本地安装包 ↓ // const updaterCacheDirName = 'dev-sidecar-updater' // const updatePendingPath = path.join(autoUpdater.app.baseCachePath, updaterCacheDirName, 'pending') @@ -58,10 +57,7 @@ function updateHandle (app, win, beforeQuit, updateUrl) { log.info('download complete', info.version) win.webContents.send('update', { key: 'downloaded', - value: { - version: info.version, - releaseData: info.releaseDate - } + value: info }) }) @@ -95,4 +91,20 @@ function updateHandle (app, win, beforeQuit, updateUrl) { log.info('auto update inited') return autoUpdater } -export default updateHandle + +export default { + install (context) { + const { app, win, beforeQuit, log } = context + let updateUrl = 'https://dev-sidecar.docmirror.cn/update/' + if (process.env.NODE_ENV === 'development') { + Object.defineProperty(app, 'isPackaged', { + get () { + return true + } + }) + // updateUrl = 'https://dev-sidecar.docmirror.cn/update/' + updateUrl = 'http://localhost/dev-sidecar/' + } + updateHandle(app, win, beforeQuit, updateUrl, log) + } +} diff --git a/packages/gui/src/view/modules/update/index.js b/packages/gui/src/bridge/update/front.js similarity index 87% rename from packages/gui/src/view/modules/update/index.js rename to packages/gui/src/bridge/update/front.js index 960f9db..79f609a 100644 --- a/packages/gui/src/view/modules/update/index.js +++ b/packages/gui/src/bridge/update/front.js @@ -78,11 +78,19 @@ function install (app, api) { function newUpdateIsReady (value) { updateParams.downloading = false app.$confirm({ - title: '新版本已准备好', - content: `是否立即升级安装v${value.version}?`, + title: `新版本(v${value.version})已准备好,是否立即升级?`, cancelText: '暂不升级', okText: '立即升级', - // content: h =>