diff --git a/power_leasing/package-lock.json b/power_leasing/package-lock.json index 037c489..beb7f4b 100644 --- a/power_leasing/package-lock.json +++ b/power_leasing/package-lock.json @@ -5171,6 +5171,11 @@ "esprima": "^4.0.0" } }, + "jsencrypt": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/jsencrypt/-/jsencrypt-3.5.4.tgz", + "integrity": "sha512-kNjfYEMNASxrDGsmcSQh/rUTmcoRfSUkxnAz+MMywM8jtGu+fFEZ3nJjHM58zscVnwR0fYmG9sGkTDjqUdpiwA==" + }, "jsesc": { "version": "3.1.0", "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.1.0.tgz", diff --git a/power_leasing/package.json b/power_leasing/package.json index a9db986..8b08824 100644 --- a/power_leasing/package.json +++ b/power_leasing/package.json @@ -12,6 +12,7 @@ "axios": "^1.11.0", "core-js": "^3.8.3", "element-ui": "^2.15.14", + "jsencrypt": "^3.5.4", "vue": "^2.6.14", "vue-router": "^3.5.1", "vuex": "^3.6.2" diff --git a/power_leasing/src/api/order.js b/power_leasing/src/api/order.js index 771dae4..ecbc093 100644 --- a/power_leasing/src/api/order.js +++ b/power_leasing/src/api/order.js @@ -108,5 +108,17 @@ export function getPurchasedItems(data) { }) } +//已购商品详情 +export function getPurchasedInfoV2(data) { + return request({ + url: `/lease/v2/order/info/getPurchasedInfo`, + method: 'post', + data + }) +} + + + + diff --git a/power_leasing/src/api/wallet.js b/power_leasing/src/api/wallet.js index ef2c36a..babab04 100644 --- a/power_leasing/src/api/wallet.js +++ b/power_leasing/src/api/wallet.js @@ -154,6 +154,15 @@ export function balanceWithdrawListV2(data) { }) } +// 修改店铺钱包配置 V2 +export function updateShopConfigV2(data) { + return request({ + url: `/lease/v2/shop/updateShopConfigV2`, + method: 'post', + data + }) +} + diff --git a/power_leasing/src/main.js b/power_leasing/src/main.js index de11259..641604d 100644 --- a/power_leasing/src/main.js +++ b/power_leasing/src/main.js @@ -9,7 +9,7 @@ import './utils/loginInfo.js'; // 全局输入防表情守卫(极简、无侵入) import { initNoEmojiGuard } from './utils/noEmojiGuard.js'; -// console.log = ()=>{} //全局关闭打印 +console.log = ()=>{} //全局关闭打印 Vue.config.productionTip = false diff --git a/power_leasing/src/router/routes.js b/power_leasing/src/router/routes.js index f2373fe..b46d974 100644 --- a/power_leasing/src/router/routes.js +++ b/power_leasing/src/router/routes.js @@ -100,9 +100,13 @@ export const accountRoutes = [ } }, { + // 兼容旧入口:收款记录 -> 卖家资金流水(收款tab) path: 'receipt-record', name: 'accountReceiptRecord', - component: () => import('../views/account/receiptRecord.vue'), + redirect: (to) => ({ + path: '/account/seller-funds-flow', + query: { ...(to && to.query ? to.query : {}), tab: 'receipt' } + }), meta: { title: '收款记录', description: '卖家收款流水记录', @@ -110,15 +114,29 @@ export const accountRoutes = [ } }, { + // 兼容旧入口:提现记录 -> 卖家资金流水(提现tab) path: 'withdraw-record', name: 'accountWithdrawRecord', - component: () => import('../views/account/withdrawRecord.vue'), + redirect: (to) => ({ + path: '/account/seller-funds-flow', + query: { ...(to && to.query ? to.query : {}), tab: 'withdraw' } + }), meta: { title: '提现记录', description: '卖家提现流水记录', allAuthority: ['all'] } }, + { + path: 'seller-funds-flow', + name: 'accountSellerFundsFlow', + component: () => import('../views/account/sellerFundsFlow.vue'), + meta: { + title: '资金流水', + description: '卖家收款/提现记录切换查看', + allAuthority: ['all'] + } + }, { path: 'shop-new', name: 'accountShopNew', @@ -169,23 +187,23 @@ export const accountRoutes = [ allAuthority: ['all'] } }, - { - path: 'purchased', - name: 'accountPurchased', - component: () => import('../views/account/purchased.vue'), - meta: { - title: '已购商品', - description: '查看已购买的商品列表', - allAuthority: ['all'] - } - }, { path: 'purchased-machine-config', name: 'accountPurchasedMachineConfig', component: () => import('../views/account/purchasedMachineConfig.vue'), meta: { - title: '已购矿机配置', - description: '查看已购买矿机的配置信息', + title: '已购商品', + description: '查看已购买商品的配置信息', + allAuthority: ['all'] + } + }, + { + path: 'purchased-machine-detail/:id', + name: 'purchasedMachineDetail', + component: () => import('../views/account/purchasedMachineDetail.vue'), + meta: { + title: '已购商品详情', + description: '查看已购买商品的详细信息', allAuthority: ['all'] } }, @@ -199,16 +217,6 @@ export const accountRoutes = [ allAuthority: ['all'] } }, - { - path: 'purchased-detail/:id', - name: 'PurchasedDetail', - component: () => import('../views/account/purchasedDetail.vue'), - meta: { - title: '已购商品详情', - description: '查看已购商品详细信息', - allAuthority: ['all'] - } - }, { path: 'orders', name: 'accountOrders', diff --git a/power_leasing/src/utils/rsaEncrypt.js b/power_leasing/src/utils/rsaEncrypt.js new file mode 100644 index 0000000..daeaedb --- /dev/null +++ b/power_leasing/src/utils/rsaEncrypt.js @@ -0,0 +1,101 @@ +/** + * RSA 加密工具 + * 使用 jsencrypt 库进行 RSA 公钥加密 + */ + +// 导入 jsencrypt +import JSEncrypt from 'jsencrypt' + +// RSA 公钥(Base64 格式,不带 BEGIN/END 标记) +const RSA_PUBLIC_KEY_BASE64 = `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsQVIKYozXCfnXUw8+omYLdcdL1pTzmQh35YPsvn22wM4SQJKvMmXmcS6bI5Bu+5zCjL0F56DzfKz0BNZEwb46UshUOO+KFBUr8CxjYE8NOgIsoe5FUn57O6er9/KySaWlkpGZX49K+l3e90R+dFUEfRE/ijYpeZWkLRwcgWZ+2u6HGpl9h/eF6XD0aW9asDjdAbxUQ48TlaWgfP+OHC+Zy2GKGQG16EcDMczrN6a2HbFnwRIUKrFP67UqyRq11BTUziOhXLY8J0MFuwXUk2OY4VpqjrJjHHjlHYADjIL/5K4Io2AhRU9+QSsKFR2wGxi4e8vw2IXDzscrDuah/7YSwIDAQAB` + +// RSA 公钥(PEM 格式) +const RSA_PUBLIC_KEY = `-----BEGIN PUBLIC KEY----- +${RSA_PUBLIC_KEY_BASE64} +-----END PUBLIC KEY-----` + +/** + * 获取 JSEncrypt 构造函数 + * @returns {Function} JSEncrypt 构造函数 + */ +function getJSEncrypt() { + // 优先使用已导入的 JSEncrypt + if (JSEncrypt) { + return JSEncrypt + } + + // 尝试从全局获取(可能通过 CDN 引入) + if (typeof window !== 'undefined' && window.JSEncrypt) { + return window.JSEncrypt + } + + return null +} + +/** + * RSA 加密函数(同步版本) + * @param {string} plainText - 要加密的明文 + * @returns {string|null} 加密后的密文(Base64 编码),失败返回 null + */ +export function rsaEncryptSync(plainText) { + if (!plainText || typeof plainText !== 'string') { + console.error('RSA 加密:输入必须是非空字符串') + return null + } + + try { + const Encrypt = getJSEncrypt() + if (!Encrypt) { + console.error('JSEncrypt 未加载') + return null + } + + const encrypt = new Encrypt() + encrypt.setPublicKey(RSA_PUBLIC_KEY) + const encrypted = encrypt.encrypt(plainText) + + if (!encrypted) { + console.error('RSA 加密失败:返回值为空') + return null + } + + return encrypted + } catch (error) { + console.error('RSA 加密异常:', error) + return null + } +} + +/** + * RSA 加密函数(异步版本,兼容同步调用) + * @param {string} plainText - 要加密的明文 + * @returns {Promise} 加密后的密文(Base64 编码),失败返回 null + */ +export async function rsaEncrypt(plainText) { + if (!plainText || typeof plainText !== 'string') { + console.error('RSA 加密:输入必须是非空字符串') + return null + } + + try { + const Encrypt = getJSEncrypt() + if (!Encrypt) { + console.error('JSEncrypt 未加载') + return null + } + + const encrypt = new Encrypt() + encrypt.setPublicKey(RSA_PUBLIC_KEY) + const encrypted = encrypt.encrypt(plainText) + + if (!encrypted) { + console.error('RSA 加密失败:返回值为空') + return null + } + + return encrypted + } catch (error) { + console.error('RSA 加密异常:', error) + return null + } +} diff --git a/power_leasing/src/views/account/index.vue b/power_leasing/src/views/account/index.vue index 272adee..3f8eb8b 100644 --- a/power_leasing/src/views/account/index.vue +++ b/power_leasing/src/views/account/index.vue @@ -63,8 +63,7 @@ export default { // 买家侧导航 buyerLinks: [ { label: '我的钱包', to: '/account/wallet' }, - { label: '已购商品', to: '/account/purchased' }, - { label: '已购矿机配置', to: '/account/purchased-machine-config' }, + { label: '已购商品', to: '/account/purchased-machine-config' }, { label: '订单列表', to: '/account/orders' }, // { label: '充值记录', to: '/account/rechargeRecord' }, // { label: '提现记录', to: '/account/withdrawalHistory' }, @@ -76,8 +75,7 @@ export default { { label: '我的店铺', to: '/account/shops' }, { label: '商品列表', to: '/account/products' }, { label: '已售出订单', to: '/account/seller-orders' }, - { label: '收款记录', to: '/account/receipt-record' }, - { label: '提现记录', to: '/account/withdraw-record' }, + { label: '资金流水', to: '/account/seller-funds-flow' }, ], } @@ -158,9 +156,8 @@ export default { // 买家前缀优先匹配,确保"已购详情"等页面归属买家侧 const buyerPrefixes = [ '/account/wallet', - '/account/purchased', - '/account/purchased-detail', '/account/purchased-machine-config', + '/account/purchased-machine-detail', '/account/orders', '/account/funds-flow' ] @@ -172,6 +169,8 @@ export default { '/account/product-detail', '/account/product-machine-add', '/account/seller-orders', + '/account/seller-funds-flow', + // 兼容旧路径(会被路由重定向到 seller-funds-flow) '/account/receipt-record', '/account/withdraw-record', '/account/shop-config' @@ -208,16 +207,18 @@ export default { const map = { '/account/seller-orders': ['/account/seller-orders'], '/account/products': ['/account/products', '/account/product-detail'], - '/account/purchased': ['/account/purchased', '/account/purchased-detail'], - '/account/purchased-machine-config': ['/account/purchased-machine-config'] + '/account/purchased-machine-config': ['/account/purchased-machine-config', '/account/purchased-machine-detail'] } const prefixes = map[pathLike] if (Array.isArray(prefixes)) { return prefixes.some(p => { // 精确匹配 if (current === p) return true - // 对于详情页路径,使用前缀匹配(支持 /account/purchased-detail/:id) - if (p === '/account/purchased-detail' || p === '/account/product-detail') { + // 对于详情页路径,使用前缀匹配(支持 /account/product-detail/:id) + if (p === '/account/product-detail') { + return current.indexOf(p) === 0 + } + if (p === '/account/purchased-machine-detail') { return current.indexOf(p) === 0 } // 列表页已经在上面精确匹配了,这里不需要额外处理 @@ -225,8 +226,6 @@ export default { }) } // 不在 map 中的路径,精确匹配 - // 特别注意:避免 /account/purchased 匹配到 /account/purchased-machine-config - // 使用精确匹配而不是前缀匹配 return current === pathLike } }, diff --git a/power_leasing/src/views/account/myShops.vue b/power_leasing/src/views/account/myShops.vue index 58cd0d3..7eb68e5 100644 --- a/power_leasing/src/views/account/myShops.vue +++ b/power_leasing/src/views/account/myShops.vue @@ -13,13 +13,17 @@ 请在本页点击 钱包绑定,配置自己的收款地址(支持不同链与币种)。
  • - 商品:完成钱包绑定后,即可在“我的店铺”页面 创建商品。 - 商品可按 币种 进行分类管理,创建的商品会在商城对买家展示。 - 商品可理解为“不同算法、币种的机器集合分类”。 -
  • -
  • - 出售机器:创建商品后,请进入 商品列表 为该商品 添加出售机器明细。 - 必须添加出售机器,否则买家无法下单。买家点击某个商品后,会看到该商品下的机器明细并进行选购。 + 创建商品:完成钱包绑定后,即可在“我的店铺”页面 点击新增商品按钮。 +
  • 提示:建议先创建店铺 → 完成钱包绑定 → 创建商品的顺序,避免漏配导致无法收款或无法下单。
    @@ -245,6 +249,7 @@ import { getMyShop, updateShop, deleteShop, queryShop, closeShop ,updateShopConf import { coinList } from '@/utils/coinList' import { getShopConfig,getShopConfigV2 ,withdrawBalanceForSeller,updateShopConfigV2} from '@/api/wallet' +import { rsaEncrypt, rsaEncryptSync } from '@/utils/rsaEncrypt' export default { @@ -434,12 +439,55 @@ export default { this.withdrawLoading = true try { const row = this.currentWithdrawRow || {} + + /** + * 提现地址 RSA 加密(与“钱包绑定”页面保持一致:同步优先,异步兜底) + * - toAddress: 用户输入/默认地址 + * - fromAddress: 当前绑定的钱包地址(后端可能用于校验来源) + */ + const toAddressPlain = String(this.withdrawForm.toAddress || '').trim() + const fromAddressPlain = String(row.payAddress || this.withdrawForm.toAddress || '').trim() + + /** @type {string} */ + let encryptedToAddress = toAddressPlain + if (encryptedToAddress) { + const syncEncrypted = rsaEncryptSync(encryptedToAddress) + if (syncEncrypted) { + encryptedToAddress = syncEncrypted + } else { + const asyncEncrypted = await rsaEncrypt(encryptedToAddress) + if (asyncEncrypted) { + encryptedToAddress = asyncEncrypted + } else { + this.$message.error('钱包地址加密失败,请重试') + return + } + } + } + + /** @type {string} */ + let encryptedFromAddress = fromAddressPlain + if (encryptedFromAddress) { + const syncEncrypted = rsaEncryptSync(encryptedFromAddress) + if (syncEncrypted) { + encryptedFromAddress = syncEncrypted + } else { + const asyncEncrypted = await rsaEncrypt(encryptedFromAddress) + if (asyncEncrypted) { + encryptedFromAddress = asyncEncrypted + } else { + this.$message.error('钱包地址加密失败,请重试') + return + } + } + } + const payload = { toChain: row.chain, toSymbol: row.payCoin, amount: Number(this.withdrawForm.amount), - toAddress: this.withdrawForm.toAddress, - fromAddress: row.payAddress || this.withdrawForm.toAddress || '', + toAddress: encryptedToAddress, + fromAddress: encryptedFromAddress, code: this.withdrawForm.googleCode, serviceCharge: Number(this.withdrawForm.fee) || 0 } @@ -679,26 +727,53 @@ export default { this.deleteShopConfig({id:row.id}) }, - submitConfigEdit() { + /** + * 提交配置修改 + */ + async submitConfigEdit() { // 仅校验钱包地址 const addr = (this.configForm.payAddress || '').trim() if (!addr) { this.$message.warning('请输入钱包地址') return } + + /** + * 使用 RSA 加密钱包地址(与“钱包绑定”页面保持一致:同步优先,异步兜底) + * @type {string} + */ + let encryptedPayAddress = addr + if (encryptedPayAddress) { + const syncEncrypted = rsaEncryptSync(encryptedPayAddress) + if (syncEncrypted) { + encryptedPayAddress = syncEncrypted + } else { + const asyncEncrypted = await rsaEncrypt(encryptedPayAddress) + if (asyncEncrypted) { + encryptedPayAddress = asyncEncrypted + } else { + this.$message.error('钱包地址加密失败,请重试') + return + } + } + } + const payload = { id: this.configForm.id, chain: this.configForm.chainValue || this.configForm.chainLabel || '', - payAddress: this.configForm.payAddress + payAddress: encryptedPayAddress } - ;(async () => { + try { const res = await updateShopConfigV2(payload) if (res && (res.code === 0 || res.code === 200)) { this.$message.success('保存成功') this.visibleConfigEdit = false this.fetchShopConfigs(this.shop.id) - } - })() + } + } catch (e) { + console.error('修改配置失败', e) + this.$message.error('修改配置失败,请重试') + } }, removeSelectedCoin(labelUpper) { const label = String(labelUpper || '').toLowerCase() @@ -935,6 +1010,8 @@ export default { .guide-steps { margin: 0; padding-left: 18px; color: #374151; } .guide-steps li { line-height: 1.9; margin: 6px 0; } .guide-steps b { color: #111827; } +.guide-substeps { margin: 6px 0 0 0; padding-left: 18px; list-style: disc; } +.guide-substeps li { line-height: 1.8; margin: 4px 0; } .guide-note { margin-top: 10px; color: #6b7280; font-size: 13px; background: #f9fafb; border: 1px dashed #e5e7eb; padding: 8px 10px; border-radius: 8px; } .coin-list { display: flex; align-items: center; gap: 8px; } .coin-img { width: 20px; height: 20px; border-radius: 4px; display: inline-block; } diff --git a/power_leasing/src/views/account/productMachineAdd.vue b/power_leasing/src/views/account/productMachineAdd.vue index 88109a9..70e0c48 100644 --- a/power_leasing/src/views/account/productMachineAdd.vue +++ b/power_leasing/src/views/account/productMachineAdd.vue @@ -2,7 +2,7 @@
    返回 -

    添加出售机器

    +

    创建商品

    @@ -236,7 +236,7 @@
    取消 确认添加确认创建
    @@ -1531,7 +1531,7 @@ export default { const res = await addAsicMachine(payload); if (res && (res.code === 0 || res.code === 200)) { this.$message({ - message: "添加成功", + message: "创建成功", duration: 3000, showClose: true, type: "success", @@ -1540,8 +1540,8 @@ export default { this.$router.push("/account/products"); } } catch (e) { - console.error("添加出售机器失败", e); - console.log("添加失败"); + console.error("创建商品失败", e); + console.log("创建失败"); } finally { this.saving = false; } diff --git a/power_leasing/src/views/account/products.vue b/power_leasing/src/views/account/products.vue index 1fcbc2a..6595773 100644 --- a/power_leasing/src/views/account/products.vue +++ b/power_leasing/src/views/account/products.vue @@ -196,7 +196,7 @@