const fs = require('fs'); const path = require('path'); let passed = 0; let failed = 0; function assert(condition, testName, detail = '') { if (condition) { console.log(` [PASS] ${testName}`); passed++; } else { console.error(` [FAIL] ${testName} - ${detail}`); failed++; } } console.log("========================================================"); console.log(" 抽屉说明文字后台配置与端到端动态展示规格测试"); console.log("========================================================\n"); // 1. 验证 PartnerConfig.php 规则读取与容错兜底机制 console.log("--- 1. PartnerConfig 规则读取与容错逻辑 ---"); const partnerConfigPath = path.resolve(__dirname, '../../addons/shopro/service/partner/PartnerConfig.php'); assert(fs.existsSync(partnerConfigPath), 'PartnerConfig.php 文件存在'); const partnerConfigContent = fs.readFileSync(partnerConfigPath, 'utf-8'); assert( partnerConfigContent.includes('function madowRuleTitle') && partnerConfigContent.includes('function madowRules'), 'PartnerConfig 包含 madowRuleTitle() 和 madowRules() 读取方法' ); assert( partnerConfigContent.includes('function voucherRuleTitle') && partnerConfigContent.includes('function voucherRules'), 'PartnerConfig 包含 voucherRuleTitle() 和 voucherRules() 读取方法' ); assert( partnerConfigContent.includes('function normalizeRules'), 'PartnerConfig 包含 normalizeRules 对 JSON 字符串、纯文本换行与数组的智能格式化及容错' ); assert( /DMEPA获取与核算/i.test(partnerConfigContent) && (partnerConfigContent.includes('市值动态增值') || partnerConfigContent.includes('马币市值动态增值')) && partnerConfigContent.includes('价值说明与权益'), '默认兜底规则完整覆盖规则条目' ); // 2. 验证 后台 Config 控制器白名单与数据自愈 console.log("\n--- 2. 后台 Config 控制器白名单与自愈机制 ---"); const configPhpPath = path.resolve(__dirname, '../../application/admin/controller/shopro/Config.php'); assert(fs.existsSync(configPhpPath), 'Config.php 文件存在'); const configPhpContent = fs.readFileSync(configPhpPath, 'utf-8'); assert( configPhpContent.includes('partner_madow_rule_title') && configPhpContent.includes('partner_madow_rules'), 'Config.php 白名单及默认值包含 partner_madow_rule_title 和 partner_madow_rules' ); assert( configPhpContent.includes('partner_voucher_rule_title') && configPhpContent.includes('partner_voucher_rules'), 'Config.php 白名单及默认值包含 partner_voucher_rule_title 和 partner_voucher_rules' ); assert( configPhpContent.includes('shop.commission.partner_madow_rule_title') && configPhpContent.includes('shop.commission.partner_madow_rules'), 'Config.php 包含数据库配置缺失时的自动创建与自愈机制' ); // 3. 验证 后台视图与 JS 前端交互绑定 console.log("\n--- 3. 后台配置视图与交互脚本 ---"); const indexHtmlPath = path.resolve(__dirname, '../../application/admin/view/shopro/config/index.html'); assert(fs.existsSync(indexHtmlPath), 'config/index.html 文件存在'); const indexHtmlContent = fs.readFileSync(indexHtmlPath, 'utf-8'); assert( indexHtmlContent.includes('form.model.partner_madow_rule_title') && indexHtmlContent.includes('form.model.partner_madow_rules'), '后台视图包含 dmepa 市值规则弹窗标题输入框与规则说明条目编辑' ); assert( indexHtmlContent.includes('onDeleteMadowRule') && indexHtmlContent.includes('onAddMadowRule'), '后台视图提供 dmepa 规则条目的新增和删除操作入口' ); const configJsPath = path.resolve(__dirname, '../../public/assets/js/backend/shopro/config.js'); assert(fs.existsSync(configJsPath), 'config.js 文件存在'); const configJsContent = fs.readFileSync(configJsPath, 'utf-8'); assert( configJsContent.includes('form.model.partner_madow_rule_title') && configJsContent.includes('form.model.partner_madow_rules'), 'config.js 在加载配置时包含 dmepa 规则默认结构初始化' ); assert( configJsContent.includes('onAddMadowRule') && configJsContent.includes('onDeleteMadowRule'), 'config.js 定义并暴露了 onAddMadowRule 和 onDeleteMadowRule 方法' ); // 4. 验证 用户端接口 partner/Index.php console.log("\n--- 4. 用户端 partner/Index.php 接口输出 ---"); const partnerIndexPath = path.resolve(__dirname, '../../addons/shopro/controller/partner/Index.php'); assert(fs.existsSync(partnerIndexPath), 'partner/Index.php 文件存在'); const partnerIndexContent = fs.readFileSync(partnerIndexPath, 'utf-8'); assert( partnerIndexContent.includes("'rule_title' => PartnerConfig::madowRuleTitle()") && partnerIndexContent.includes("'rules' => PartnerConfig::madowRules()"), 'madow() 接口返回 rule_title 与 rules 规则数据' ); assert( partnerIndexContent.includes("'rule_title' => PartnerConfig::voucherRuleTitle()") && partnerIndexContent.includes("'rules' => PartnerConfig::voucherRules()"), 'voucher() 接口返回 rule_title 与 rules 规则数据' ); // 5. 验证 移动端 madow.vue 与 voucher.vue 抽屉弹窗动态渲染 console.log("\n--- 5. 移动端抽屉弹窗动态渲染与保底 ---"); const madowVuePath = path.resolve(__dirname, '../../uniapp/pages/commission/madow.vue'); assert(fs.existsSync(madowVuePath), 'madow.vue 文件存在'); const madowVueContent = fs.readFileSync(madowVuePath, 'utf-8'); assert( madowVueContent.includes('state.ruleTitle') && madowVueContent.includes('v-for="(item, index) in state.rules"') && madowVueContent.includes('item.title') && madowVueContent.includes('item.desc'), 'madow.vue 抽屉弹窗支持标题与规则条目动态循环渲染' ); assert( madowVueContent.includes('defaultRules') && madowVueContent.includes('dmepa获取与核算') && (madowVueContent.includes('市值动态增值') || madowVueContent.includes('马币市值动态增值')) && madowVueContent.includes('价值说明与权益'), 'madow.vue 保留本地 defaultRules,在无网络或首次加载时提供稳健保底' ); assert( madowVueContent.includes('data.rule_title') && madowVueContent.includes('data.rules'), 'madow.vue getMadow() 成功接收并更新 state.ruleTitle 与 state.rules' ); const voucherVuePath = path.resolve(__dirname, '../../uniapp/pages/commission/voucher.vue'); assert(fs.existsSync(voucherVuePath), 'voucher.vue 文件存在'); const voucherVueContent = fs.readFileSync(voucherVuePath, 'utf-8'); assert( voucherVueContent.includes('state.ruleTitle') && voucherVueContent.includes('v-for="(item, index) in state.rules"'), 'voucher.vue 抽屉弹窗支持标题与规则条目动态循环渲染' ); // 6. 验证 upgrade SQL 初始化 console.log("\n--- 6. upgrade SQL 初始配置项覆盖 ---"); const sqlPath = path.resolve(__dirname, '../../addons/shopro/upgrade/partner_v2.sql'); assert(fs.existsSync(sqlPath), 'partner_v2.sql 文件存在'); const sqlContent = fs.readFileSync(sqlPath, 'utf-8'); assert( sqlContent.includes('shop.commission.partner_madow_rule_title') && sqlContent.includes('shop.commission.partner_madow_rules'), 'partner_v2.sql 包含 dmepa 规则初始配置行' ); console.log("\n--------------------------------------------------------"); console.log(`测试执行结果: 通过 ${passed} 项, 失败 ${failed} 项`); console.log("========================================================"); process.exit(failed === 0 ? 0 : 1);