From 5845474be391fd0be4cb93c77df2fe9451d8521f Mon Sep 17 00:00:00 2001 From: ZF sun <34314687@qq.com> Date: Sat, 24 Oct 2026 09:49:49 +0800 Subject: [PATCH] =?UTF-8?q?feat(diy-card):=20=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E6=89=A9=E8=87=B3=208=20=E7=B1=BB(2.19.3)=20?= =?UTF-8?q?=E2=80=94=20sms/map/link=20=E7=99=BD=E5=90=8D=E5=8D=95=20+=20do?= =?UTF-8?q?Act=20=E5=88=86=E6=94=AF=20+=20map=20=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E5=9B=9E=E8=90=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components-diy/diy-card-common.js | 5 +++-- components-diy/diy-card-self.vue | 34 +++++++++++++++++++++++++++++++ components-diy/diy-card-show.vue | 34 +++++++++++++++++++++++++++++++ tests/diy-card-style-v2.test.js | 14 +++++++++++++ 4 files changed, 85 insertions(+), 2 deletions(-) diff --git a/components-diy/diy-card-common.js b/components-diy/diy-card-common.js index 7bb89a2..e1d04b2 100644 --- a/components-diy/diy-card-common.js +++ b/components-diy/diy-card-common.js @@ -353,8 +353,9 @@ export function hexToRgba(hex, alpha) { /** 默认动作类型序(图层面板行序与 C 端合并序一致) */ export const ACT_TYPES = ['tel', 'wx', 'mail', 'web', 'save']; -/** 自定义动作类型白名单(doAct 天然消费: tel/wx/mail/copy 分支 + else 兜底) */ -export const ACT_ACTION_TYPES = ['tel', 'wx', 'mail', 'web', 'copy']; +/** 自定义动作类型白名单(doAct 天然消费: tel/wx/mail/copy 分支 + else 兜底; + * 2.19.3 扩展: sms 短信/map 导航/link 页面链接(系统链接对话框)) */ +export const ACT_ACTION_TYPES = ['tel', 'wx', 'mail', 'web', 'copy', 'sms', 'map', 'link']; export const ACT_LABEL_DEFAULTS = { tel: '打电话', diff --git a/components-diy/diy-card-self.vue b/components-diy/diy-card-self.vue index 5fad331..e394880 100644 --- a/components-diy/diy-card-self.vue +++ b/components-diy/diy-card-self.vue @@ -217,6 +217,10 @@ export default { this.goSaveContact(); return; } + // map(导航): value 留空回落名片地址(2.19.3) + if (act.type === 'map' && !act.value && this.card && this.card.address) { + act = Object.assign({}, act, { value: this.card.address }); + } if (!act.value) return; if (act.type === 'tel') { uni.makePhoneCall({ phoneNumber: act.value, fail: () => {} }); @@ -235,6 +239,36 @@ export default { success: () => uni.showToast({ title: '邮箱已复制', icon: 'none' }), }); // #endif + } else if (act.type === 'sms') { + // #ifdef H5 + window.location.href = 'sms:' + act.value; + // #endif + // #ifndef H5 + uni.setClipboardData({ + data: act.value, + success: () => uni.showToast({ title: '号码已复制,请到短信粘贴', icon: 'none' }), + }); + // #endif + } else if (act.type === 'map') { + uni.setClipboardData({ + data: act.value, + success: () => uni.showToast({ title: '地址已复制,可粘贴到地图导航', icon: 'none' }), + }); + } else if (act.type === 'link') { + var isHttp = act.value.indexOf('http://') === 0 || act.value.indexOf('https://') === 0; + if (isHttp) { + // #ifdef H5 + window.location.href = act.value; + // #endif + // #ifndef H5 + uni.setClipboardData({ + data: act.value, + success: () => uni.showToast({ title: '链接已复制,请在浏览器打开', icon: 'none' }), + }); + // #endif + } else { + this.$util.redirectTo(act.value, {}); + } } else { uni.setClipboardData({ data: act.value, diff --git a/components-diy/diy-card-show.vue b/components-diy/diy-card-show.vue index e8765e7..ddb696b 100644 --- a/components-diy/diy-card-show.vue +++ b/components-diy/diy-card-show.vue @@ -129,6 +129,10 @@ export default { this.goSaveContact(); return; } + // map(导航): value 留空回落名片地址(2.19.3) + if (act.type === 'map' && !act.value && this.card && this.card.address) { + act = Object.assign({}, act, { value: this.card.address }); + } if (!act.value) return; if (act.type === 'tel') { uni.makePhoneCall({ phoneNumber: act.value, fail: () => {} }); @@ -147,6 +151,36 @@ export default { success: () => uni.showToast({ title: '邮箱已复制', icon: 'none' }), }); // #endif + } else if (act.type === 'sms') { + // #ifdef H5 + window.location.href = 'sms:' + act.value; + // #endif + // #ifndef H5 + uni.setClipboardData({ + data: act.value, + success: () => uni.showToast({ title: '号码已复制,请到短信粘贴', icon: 'none' }), + }); + // #endif + } else if (act.type === 'map') { + uni.setClipboardData({ + data: act.value, + success: () => uni.showToast({ title: '地址已复制,可粘贴到地图导航', icon: 'none' }), + }); + } else if (act.type === 'link') { + var isHttp = act.value.indexOf('http://') === 0 || act.value.indexOf('https://') === 0; + if (isHttp) { + // #ifdef H5 + window.location.href = act.value; + // #endif + // #ifndef H5 + uni.setClipboardData({ + data: act.value, + success: () => uni.showToast({ title: '链接已复制,请在浏览器打开', icon: 'none' }), + }); + // #endif + } else { + this.$util.redirectTo(act.value, {}); + } } else { uni.setClipboardData({ data: act.value, diff --git a/tests/diy-card-style-v2.test.js b/tests/diy-card-style-v2.test.js index e69fc25..0f70ba6 100644 --- a/tests/diy-card-style-v2.test.js +++ b/tests/diy-card-style-v2.test.js @@ -226,6 +226,11 @@ test('mini.vue + show/self: save(存通讯录)动作全链路(2.17.1)', () => { } assert.match(vue, /Array\.isArray\(c\.rows\)[\s\S]*?map\[r\.field\]/, file + ' 字段从 rows(白名单)提取'); assert.doesNotMatch(vue, /doAct\(act\)\s*\{\s*if \(!act \|\| !act\.value\) return;/, file + ' doAct 不再拦 value 为空的 save'); + // 2.19.3 扩展类型: sms/map/link 分支 + map 空值回落名片地址 + assert.match(vue, /act\.type === 'map' && !act\.value && this\.card && this\.card\.address/, file + ' map 空值回落名片地址'); + assert.match(vue, /act\.type === 'sms'\)\s*\{[\s\S]*?window\.location\.href = 'sms:' \+ act\.value;[\s\S]*?号码已复制/, file + ' sms 分支(H5 sms: 链接/非 H5 复制)'); + assert.match(vue, /act\.type === 'map'\)\s*\{[\s\S]*?地址已复制,可粘贴到地图导航/, file + ' map 分支(复制地址)'); + assert.match(vue, /act\.type === 'link'\)\s*\{[\s\S]*?indexOf\('http:\/\/'\) === 0 [\s\S]*?\$util\.redirectTo\(act\.value, \{\}\)/, file + ' link 分支(外链 H5 跳转/小程序复制, 站内 redirectTo)'); } }); @@ -461,6 +466,8 @@ test('common.js: normalizeActVis / normalizeActLabels / normalizeCustomActs / no assert.equal(list[0].label, '加群', 'label 保留'); assert.equal(list[1].label, '自定义', 'label 缺省'); assert.equal(list[1].type, 'tel', '合法 type 保留'); + // 2.19.3 扩展类型白名单 + assert.deepEqual(customFn([{ type: 'sms', value: '139' }, { type: 'map', value: '某某大厦' }, { type: 'link', value: '/pages/index/index' }]).map(x => x.type), ['sms', 'map', 'link'], 'sms/map/link 新类型通过白名单'); // actOrder(2.19.1): 缺省=历史顺序; 去重+白名单+缺失尾补 assert.deepEqual(orderFn(undefined), ['tel', 'wx', 'mail', 'web', 'save'], 'actOrder 缺省=历史顺序'); assert.deepEqual(orderFn(['save', 'tel', 'bogus', 'save', 'mail']), ['save', 'tel', 'mail', 'wx', 'web'], '重排去重+非法剔除+缺失尾补'); @@ -541,6 +548,8 @@ test('design.html ×2: 图层式管理面板 + 素材图标库 + 预览显隐/ // 自定义动作行: 类型 chips / 取值 / 排序 / 删除 / 添加 assert.match(html, /diy-card-layer--custom" v-for="\(c, ci\) in nc\.customActs"/, comp + ' 自定义动作图层行'); assert.match(html, /:class="\{ active: c\.type === t\.v \}"/, comp + ' 自定义动作类型 chips'); + assert.match(html, /\{v:'copy',lb:'复制'\},\{v:'sms',lb:'短信'\},\{v:'map',lb:'导航'\},\{v:'link',lb:'页面'\}\]/, comp + ' 类型 chips 含 2.19.3 扩展(短信/导航/页面, web 文案改网址)'); + assert.match(html, /js-act-syslink" data-scope="custom" :data-idx="ci" v-if="c\.type === 'link'"/, comp + ' link 类型出现「系统链接」选择按钮'); assert.match(html, /v-model="c\.value" maxlength="200"/, comp + ' 自定义动作取值输入'); assert.match(html, /js-act-lib" data-scope="custom" :data-idx="ci"/, comp + ' 素材图标按钮(自定义动作)'); assert.match(html, /nc\.customActs\.splice\(ci - 1, 0, nc\.customActs\.splice\(ci, 1\)\[0\]\)/, comp + ' 上移排序'); @@ -612,6 +621,11 @@ test('card-act-icon.js: 类名委托修 2.18 选图标 Bug + $set 写回 + 素 assert.match(src, /iconKey: '', svg: '', color: ''/, '缺行防御补齐含 svg 键'); assert.match(src, /window\.CARD_ICON_LIB \|\| \{\}/, '弹层渲染消费同源图标库'); assert.match(src, /cal-item" data-key=/, '弹层图标网格'); + // 2.19.3 系统链接对话框委托(link 类型) + assert.match(src, /on\('click', '\.js-act-syslink'/, '系统链接走类名委托'); + assert.match(src, /ns\.select_link\(\{\}, function \(data\)/, '调全局 ns.select_link 打开系统链接对话框'); + assert.match(src, /data\.wap_url \|\| data\.url/, '回执取 wap_url 写入 value'); + assert.match(src, /window\.vue\.\$set\(target\.item, 'value', url\)/, '系统链接结果 $set 写回 value'); // 反例: 面板不再内联调 openAlbum 选快捷操作图标(2.18 Bug 根因规避) for (const comp of ['show', 'self']) { const html = readFileSync(resolve(BE, 'component/view/diy-card-' + comp + '/design.html'), 'utf8');