mirror of
https://gitee.com/ShopeX/ECShopX_admin-frontend
synced 2026-08-06 04:46:24 +08:00
This merge bundles multiple fixes and UX improvements across decoration, routing/path picker behavior, i18n, goods/category management, coupon detail filtering, and system config pages.
This commit is contained in:
19
.cursor/commit-summary/2026-04-20-coupon-mobile-erp-tip.md
Normal file
19
.cursor/commit-summary/2026-04-20-coupon-mobile-erp-tip.md
Normal file
@@ -0,0 +1,19 @@
|
||||
## 本次变更总结
|
||||
|
||||
**时间**: 2026-04-20
|
||||
|
||||
**涉及文件**:
|
||||
- `src/view/member/cardticket/detail/receive.vue` (修改)
|
||||
- `src/view/member/cardticket/detail/used.vue` (修改)
|
||||
- `src/views/settings/systemConfig/wdtSetting.vue` (修改)
|
||||
- `src/views/settings/systemConfig/jstSetting.vue` (修改)
|
||||
- `src/i18n/locales/zh-CN.json` (修改)
|
||||
- `src/i18n/locales/en.json` (修改)
|
||||
- `src/i18n/locales/ar.json` (修改)
|
||||
|
||||
**主要改动**:
|
||||
- 优惠券管理「查看优惠券数据」两个子列表新增手机号查询能力,支持输入手机号后搜索、回车搜索和清空后重查。
|
||||
- 旺店通与聚水潭系统配置页顶部新增服务商模式提示,采用 `SpPlatformTip` 方式展示并与现有页面风格对齐。
|
||||
- 补充三语文案键 `59579ae2.c5d4d8` 与 `20f6ad88.c5d4d8`,用于两处服务商提示文案。
|
||||
|
||||
**一句话概括**: feat: 优惠券数据列表支持手机号查询并补充 ERP 服务商提示
|
||||
@@ -0,0 +1,12 @@
|
||||
## 本次变更总结
|
||||
|
||||
**时间**: 2026-04-21
|
||||
|
||||
**涉及文件**:
|
||||
- `src/view/goods/saleCategory.vue` (修改)
|
||||
|
||||
**主要改动**:
|
||||
- 在销售分类列表中移除平台端限制条件,原本仅非平台端显示的操作列改为全端可见。
|
||||
- 通过删除 `v-if="!VERSION_PLATFORM()"`,让平台账号也能看到该列中的相关操作入口。
|
||||
|
||||
**一句话概括**: fix: 放开平台端销售分类列表操作列显示限制
|
||||
@@ -0,0 +1,16 @@
|
||||
## 本次变更总结
|
||||
|
||||
**时间**: 2026-04-21
|
||||
|
||||
**涉及文件**:
|
||||
- `src/view/mall/goods/physical/list.vue` (修改)
|
||||
- `src/i18n/locales/zh-CN.json` (修改)
|
||||
- `src/i18n/locales/en.json` (修改)
|
||||
- `src/i18n/locales/ar.json` (修改)
|
||||
|
||||
**主要改动**:
|
||||
- 修复“商品管理 > 自营商品”中点击“同步至所有店铺”时确认弹窗文案错误(显示为“审核失败”)的问题。
|
||||
- 新增独立 i18n key `6f19b2ab.6b3d7e` 作为同步确认文案,避免复用冲突 key 导致串文案。
|
||||
- 同步补齐中/英/阿三语文案,并将确认框标题改为稳定的提示文案 key。
|
||||
|
||||
**一句话概括**: fix: 修复自营商品同步所有店铺时弹窗误显示审核失败
|
||||
19
.cursor/commit-summary/2026-04-23-goodsCard-decorate.md
Normal file
19
.cursor/commit-summary/2026-04-23-goodsCard-decorate.md
Normal file
@@ -0,0 +1,19 @@
|
||||
## 本次变更总结
|
||||
|
||||
**时间**: 2026-04-23
|
||||
|
||||
**涉及文件**:
|
||||
- `src/components/sp-decorate/index.vue` (修改)
|
||||
- `src/view/decorate/index.vue` (修改)
|
||||
- `src/view/decorate/comps/configsetting.js` (修改)
|
||||
- `src/view/decorate/wgts/wgt_goodsCard/config.js` (修改)
|
||||
- `src/view/decorate/wgts/wgt_goodsCard/index.vue` (修改)
|
||||
|
||||
**主要改动**:
|
||||
- **落库名与组件名对齐**:`goodsCard` 挂件 Vue `name` 改为 `goodsCard`,与 `config.name` 一致,避免与商城 `Goods` 混淆;保存/预览通过 `findWidgetForPersistedName` 用 `config.name` 解析挂件。
|
||||
- **装修保存与回显**:`SpDecorate`、`decorate/index` 的 `onSave` / `onSaveTemplate` 等改为按 `persistedName` 查找挂件并调用 `transformOut`,场景 `1005` 下旧数据 `goods` 兼容映射到 `goodsCard`。
|
||||
- **商品卡片配置**:`transformIn`/`transformOut` 接入 `transformInBase`、`createTransformOutBase`,正确读写外边距/内边距及内外背景;移除误标为「组件间距」的 `padded` 开关项。
|
||||
- **商品卡片 UI**:去掉标题区与 `padded` 相关样式;卡片块用 `getInnerStyle` + 默认白底与圆角;列表项信息区改为纵向 flex 布局。
|
||||
- **全局样式注入**:`configsetting` 为 `goodsCard` 增加与 `goods` 相同的内边距(`innerPadding`)自动配置。
|
||||
|
||||
**一句话概括**: fix: 软文商品卡片 goodsCard 落库解析、样式转换与预览保存一致
|
||||
@@ -0,0 +1,11 @@
|
||||
## 本次变更总结
|
||||
|
||||
**时间**: 2026-04-23
|
||||
|
||||
**涉及文件**:
|
||||
- `src/view/goods/saleCategory.vue` (修改)
|
||||
|
||||
**主要改动**:
|
||||
- 销售分类编辑表单中「前台是否显示」(`is_show_front`) 表单项去掉 `isShow: () => !this.VERSION_PLATFORM()`,**平台版**下也会展示该开关,与标准版一致可配置。
|
||||
|
||||
**一句话概括**: fix: 销售分类「前台是否显示」在平台版不再隐藏
|
||||
20
.cursor/commit-summary/2026-04-23-summary.md
Normal file
20
.cursor/commit-summary/2026-04-23-summary.md
Normal file
@@ -0,0 +1,20 @@
|
||||
## 本次变更总结
|
||||
|
||||
**时间**: 2026-04-23
|
||||
|
||||
**涉及文件**:
|
||||
- `src/components/sp-picker/pickers/picker-path.vue` (修改)
|
||||
- `src/components/sp-decorate/index.vue` (修改)
|
||||
- `src/view/decorate/index.vue` (修改)
|
||||
- `src/view/decorate/wgts/wgt_goodsCard/config.js` (修改)
|
||||
- `src/i18n/locales/zh-CN.json` (修改)
|
||||
- `src/i18n/locales/en.json` (修改)
|
||||
- `src/i18n/locales/ar.json` (修改)
|
||||
|
||||
**主要改动**:
|
||||
- **设置路径弹窗**:移除「文章」Tab 及 `PickerArticle`;历史 `tab === 'article'` 时打开弹窗默认切到「商品」。
|
||||
- **软文装修预览**:`SpDecorate` 增加 `findWidgetForPersistedName`,scene 1005 下旧数据 `name: goods` 映射为 `GoodsCard` 挂件。
|
||||
- **商品卡片挂件**:`config.name` 由 `goods` 改为 `goodsCard`,与商城商品列表挂件区分;装修左侧分类 `functionalNames` 增加 `goodsCard`。
|
||||
- **文案**:商城商品挂件 `8865eba5.9897d8` 改为「商品列表」等;新增 `8f58e7cb.d4e5f6`「商品卡片(正文)」三语(若 `wgt_goodsCard` 已改用该 key 则用于展示名)。
|
||||
|
||||
**一句话概括**: feat: 路径弹窗下线文章;软文商品卡片与商品列表区分及 i18n
|
||||
@@ -1,12 +1,7 @@
|
||||
## 本次变更总结
|
||||
## 最近一次变更(2026-04-23)
|
||||
|
||||
**时间**: 2026-04-16
|
||||
**一句话概括**: fix: 软文商品卡片 goodsCard 落库解析、样式转换与预览保存一致
|
||||
|
||||
**涉及文件**:
|
||||
- `src/i18n/locales/zh-CN.json`、`en.json`、`ar.json`
|
||||
**要点**: `findWidgetForPersistedName` 统一按 `config.name` 找挂件;`goodsCard` 组件名与 transform 对齐;内层样式走 `getInnerStyle`;去掉「组件间距」开关与标题区 UI。
|
||||
|
||||
**主要改动**:
|
||||
- `223cc8af.e366cc` → 切换语言(及 en/ar 对应译文)。
|
||||
- `d81d8932.4f2c29` → 设置路径(路径选择器标题,三语与语义对齐)。
|
||||
|
||||
**一句话概括**: i18n: 路径弹窗标题恢复为设置路径;链接项 223cc8af 改为切换语言
|
||||
详见: `.cursor/commit-summary/2026-04-23-goodsCard-decorate.md`
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,4 +21,5 @@ release.*
|
||||
AGENTS.md
|
||||
openspec/
|
||||
dist/
|
||||
.cursor/commit-summary/
|
||||
|
||||
|
||||
@@ -133,10 +133,26 @@ export default {
|
||||
this.registerWgts()
|
||||
},
|
||||
methods: {
|
||||
findWidgetForPersistedName(persistedName) {
|
||||
const key = String(persistedName || '').toLowerCase()
|
||||
if (!key || !this.widgets.length) return null
|
||||
let w = this.widgets.find((item) => (item.name || '').toLowerCase() === key)
|
||||
if (w) return w
|
||||
w = this.widgets.find((item) => String(item.config?.name || '').toLowerCase() === key)
|
||||
if (w) return w
|
||||
if (String(this.scene) === '1005' && key === 'goods') {
|
||||
return (
|
||||
this.widgets.find((item) => String(item.config?.name || '').toLowerCase() === 'goodscard') ||
|
||||
this.widgets.find((item) => (item.name || '').toLowerCase() === 'goods') ||
|
||||
null
|
||||
)
|
||||
}
|
||||
return null
|
||||
},
|
||||
getWgtsValue(val) {
|
||||
const filterWidget = []
|
||||
val.forEach((k) => {
|
||||
const wgt = this.widgets.find((item) => item.name.toLowerCase() == k.name.toLowerCase())
|
||||
const wgt = this.findWidgetForPersistedName(k.name)
|
||||
if (wgt) {
|
||||
const wgtInitParams = this.cloneDefaultField(wgt)
|
||||
const params = wgt.config.transformIn(k)
|
||||
@@ -175,10 +191,10 @@ export default {
|
||||
},
|
||||
onSave(data) {
|
||||
const result = data.map((item) => {
|
||||
const { transformOut } = this.widgets.find(
|
||||
(wgt) => wgt.name.toLowerCase() == item.name.toLowerCase()
|
||||
)?.config
|
||||
return transformOut(item)
|
||||
// item.name 为 config.name(如 goodsCard),与 Vue 组件名(如 Goods)可能不一致,需与 getWgtsValue 相同解析
|
||||
const wgt = this.findWidgetForPersistedName(item.name)
|
||||
const { transformOut } = wgt?.config || {}
|
||||
return transformOut ? transformOut(item) : item
|
||||
})
|
||||
this.$emit('input', result)
|
||||
this.$emit('change', result) // 导购货架,传change事件,为了点击保存直接调接口,页面不需要加保存按钮
|
||||
|
||||
@@ -62,9 +62,6 @@
|
||||
<el-tab-pane :label="$t('d81d8932.0f394b')" name="tag">
|
||||
<PickerTag v-if="tabValue == 'tag'" ref="tag" :value="value" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('d81d8932.c75625')" name="article">
|
||||
<PickerArticle v-if="tabValue == 'article'" ref="article" :value="value" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('d81d8932.e8f87a')" name="planting">
|
||||
<PickerPlanting v-if="tabValue == 'planting'" ref="planting" :value="value" />
|
||||
</el-tab-pane>
|
||||
@@ -118,7 +115,6 @@ import PickerGoods from './picker-goods'
|
||||
import PickerSaleCategory from './picker-saleCategory'
|
||||
import PickerCategory from './picker-category'
|
||||
import PickerTag from './picker-tag'
|
||||
import PickerArticle from './picker-article'
|
||||
import PickerPlanting from './picker-planting'
|
||||
import PickerLink from './picker-link'
|
||||
import PickerMarketing from './picker-marketing'
|
||||
@@ -143,7 +139,6 @@ export default {
|
||||
PickerSaleCategory,
|
||||
PickerCategory,
|
||||
PickerTag,
|
||||
PickerArticle,
|
||||
PickerPlanting,
|
||||
PickerLink,
|
||||
PickerMarketing,
|
||||
@@ -172,9 +167,11 @@ export default {
|
||||
},
|
||||
data() {
|
||||
const { tab } = this.value
|
||||
// 已下线「文章」路径;历史数据若仍为 article,打开弹窗时落到默认 tab
|
||||
const safeTab = tab === 'article' ? 'goods' : tab
|
||||
return {
|
||||
pathValue: null,
|
||||
tabValue: tab || 'goods'
|
||||
tabValue: safeTab || 'goods'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -229,12 +226,6 @@ export default {
|
||||
title: 'tag_name'
|
||||
})
|
||||
},
|
||||
article: () => {
|
||||
return pickBy(data, {
|
||||
id: 'article_id',
|
||||
title: 'title'
|
||||
})
|
||||
},
|
||||
planting: () => {
|
||||
return pickBy(data, {
|
||||
id: 'article_id',
|
||||
|
||||
@@ -4839,6 +4839,7 @@
|
||||
"59579ae2.be5fbb": "حفظ",
|
||||
"59579ae2.53c3dd": "تفعيل",
|
||||
"59579ae2.3b1083": "تم الحفظ بنجاح",
|
||||
"59579ae2.c5d4d8": "وضع واجهة مزود الخدمة، يُرجى التواصل مع ShopeX لاستكمال إعداد الربط",
|
||||
"fea687f2.be5fbb": "حفظ",
|
||||
"fea687f2.aea08c": "بيان خصوصية متجر PC",
|
||||
"fea687f2.ae004d": "بيان خصوصية متجر H5",
|
||||
@@ -7672,6 +7673,7 @@
|
||||
"d41d8cd9.s3t4u5": "قيد المراجعة",
|
||||
"d41d8cd9.v6w7x8": "تمت الموافقة",
|
||||
"d41d8cd9.y9z0a1": "فشلت المراجعة",
|
||||
"6f19b2ab.6b3d7e": "هل تريد مزامنة جميع المنتجات إلى المتاجر؟",
|
||||
"d41d8cd9.b2c3d4": "رسوم شحن مخصصة",
|
||||
"d41d8cd9.e5f6g7": "تمت الإضافة إلى قائمة التنفيذ، يرجى التحميل من الإعدادات - قائمة التصدير",
|
||||
"d41d8cd9.f8g9h0": "وقت الرد:",
|
||||
@@ -12070,9 +12072,10 @@
|
||||
"62d2fa27.351201": "لون الزر",
|
||||
"62d2fa27.4d775d": "عرض",
|
||||
"62d2fa27.dce537": "إخفاء",
|
||||
"8865eba5.9897d8": "سلع",
|
||||
"8865eba5.9897d8": "قائمة المنتجات",
|
||||
"8f58e7cb.4707ba": "تباعد المكونات",
|
||||
"8f58e7cb.43d1e2": "اختر السلع",
|
||||
"8f58e7cb.d4e5f6": "بطاقة منتج (نص المقال)",
|
||||
"bfabc536.319337": "إضافة مباشرة إلى السلة",
|
||||
"bfabc536.390037": "النمط",
|
||||
"bfabc536.412d79": "اثنان في الصف",
|
||||
@@ -21268,6 +21271,7 @@
|
||||
"20f6ad88.4a1c90": "تفويض",
|
||||
"20f6ad88.53c3dd": "ما إذا كان مفعلاً",
|
||||
"20f6ad88.3b1083": "تم الحفظ بنجاح",
|
||||
"20f6ad88.c5d4d8": "وضع واجهة مزود الخدمة، يُرجى التواصل مع ShopeX لاستكمال إعداد الربط",
|
||||
"20f6ad88.20a495": "تم النسخ بنجاح",
|
||||
"caf9668f.626669": "مفتاح خدمة موقع Tencent:",
|
||||
"caf9668f.e4f07d": "وحدة تحكم خدمة موقع Tencent",
|
||||
|
||||
@@ -4839,6 +4839,7 @@
|
||||
"59579ae2.be5fbb": "Save",
|
||||
"59579ae2.53c3dd": "Enable",
|
||||
"59579ae2.3b1083": "Saved successfully",
|
||||
"59579ae2.c5d4d8": "Service provider API mode, contact ShopeX for binding configuration",
|
||||
"fea687f2.be5fbb": "Save",
|
||||
"fea687f2.aea08c": "PC store privacy statement",
|
||||
"fea687f2.ae004d": "H5 store privacy statement",
|
||||
@@ -7672,6 +7673,7 @@
|
||||
"d41d8cd9.s3t4u5": "Under review",
|
||||
"d41d8cd9.v6w7x8": "Review passed",
|
||||
"d41d8cd9.y9z0a1": "Review failed",
|
||||
"6f19b2ab.6b3d7e": "Sync all products to stores?",
|
||||
"d41d8cd9.b2c3d4": "Custom shipping fee",
|
||||
"d41d8cd9.e5f6g7": "Added to execution queue, please download in Settings - Export list",
|
||||
"d41d8cd9.f8g9h0": "Reply time:",
|
||||
@@ -12070,9 +12072,10 @@
|
||||
"62d2fa27.351201": "Button color",
|
||||
"62d2fa27.4d775d": "Display",
|
||||
"62d2fa27.dce537": "Hide",
|
||||
"8865eba5.9897d8": "Goods",
|
||||
"8865eba5.9897d8": "Goods list",
|
||||
"8f58e7cb.4707ba": "Component Spacing",
|
||||
"8f58e7cb.43d1e2": "Select goods",
|
||||
"8f58e7cb.d4e5f6": "Product card (article body)",
|
||||
"bfabc536.319337": "Direct Add to Cart",
|
||||
"bfabc536.390037": "Style",
|
||||
"bfabc536.412d79": "Two per Row",
|
||||
@@ -21270,6 +21273,7 @@
|
||||
"20f6ad88.4a1c90": "Authorize",
|
||||
"20f6ad88.53c3dd": "Whether enabled",
|
||||
"20f6ad88.3b1083": "Saved successfully",
|
||||
"20f6ad88.c5d4d8": "Service provider API mode, contact ShopeX for binding configuration",
|
||||
"20f6ad88.20a495": "Copy successfully",
|
||||
"caf9668f.626669": "Tencent Location Service Key:",
|
||||
"caf9668f.e4f07d": "Tencent Location Service Console",
|
||||
|
||||
@@ -4796,6 +4796,7 @@
|
||||
"59579ae2.be5fbb": "保存",
|
||||
"59579ae2.53c3dd": "是否启用",
|
||||
"59579ae2.3b1083": "保存成功",
|
||||
"59579ae2.c5d4d8": "服务商接口模式,需联系商派,配合绑定配置",
|
||||
"fea687f2.be5fbb": "保存",
|
||||
"fea687f2.aea08c": "PC商城隐私声明",
|
||||
"fea687f2.ae004d": "H5商城隐私声明",
|
||||
@@ -7697,6 +7698,7 @@
|
||||
"d41d8cd9.s3t4u5": "提示",
|
||||
"d41d8cd9.v6w7x8": "所有商品, 是否继续?",
|
||||
"d41d8cd9.y9z0a1": "是否将所有商品的都同步至店铺?",
|
||||
"6f19b2ab.6b3d7e": "是否将所有商品同步至店铺?",
|
||||
"d41d8cd9.b2c3d4": "确认是否批量提交?",
|
||||
"d41d8cd9.e5f6g7": "已加入执行队列,请在设置-导出列表中下载",
|
||||
"d41d8cd9.h8i9j0": "导出失败",
|
||||
@@ -12168,9 +12170,10 @@
|
||||
"62d2fa27.351201": "按钮颜色",
|
||||
"62d2fa27.4d775d": "显示",
|
||||
"62d2fa27.dce537": "隐藏",
|
||||
"8865eba5.9897d8": "商品",
|
||||
"8865eba5.9897d8": "商品列表",
|
||||
"8f58e7cb.4707ba": "组件间距",
|
||||
"8f58e7cb.43d1e2": "选择商品",
|
||||
"8f58e7cb.d4e5f6": "商品卡片(正文)",
|
||||
"bfabc536.319337": "直接加购",
|
||||
"bfabc536.390037": "样式",
|
||||
"bfabc536.412d79": "一行两个",
|
||||
@@ -21472,6 +21475,7 @@
|
||||
"20f6ad88.4a1c90": "去授权",
|
||||
"20f6ad88.53c3dd": "是否启用",
|
||||
"20f6ad88.3b1083": "保存成功",
|
||||
"20f6ad88.c5d4d8": "服务商接口模式,需联系商派,配合绑定配置",
|
||||
"20f6ad88.20a495": "复制成功",
|
||||
"caf9668f.626669": "腾讯位置服务Key获取路径:",
|
||||
"caf9668f.e4f07d": "腾讯位置服务控制台",
|
||||
|
||||
@@ -79,6 +79,7 @@ function processConfig(config) {
|
||||
'ranking',
|
||||
'hotranking',
|
||||
'goods',
|
||||
'goodsCard',
|
||||
'shop',
|
||||
'couponCard',
|
||||
'classify',
|
||||
|
||||
@@ -265,7 +265,8 @@ export default {
|
||||
'Group',
|
||||
'hotranking',
|
||||
'Ranking',
|
||||
'goods'
|
||||
'goods',
|
||||
'goodsCard'
|
||||
]
|
||||
// 专用挂件:订单导航
|
||||
const dedicatedNames = ['OrderNavigation']
|
||||
@@ -354,19 +355,32 @@ export default {
|
||||
})
|
||||
},
|
||||
resetDecorateTheme() {},
|
||||
// 落库 name 多为 config.name(如 goodsCard),与 Vue 组件名(如 Goods)可能不一致
|
||||
findWidgetForPersistedName(persistedName) {
|
||||
const key = String(persistedName || '').toLowerCase()
|
||||
if (!key || !this.widgets.length) return null
|
||||
let w = this.widgets.find((item) => (item.name || '').toLowerCase() === key)
|
||||
if (w) return w
|
||||
w = this.widgets.find((item) => String(item.config?.name || '').toLowerCase() === key)
|
||||
if (w) return w
|
||||
if (String(this.localScene) === '1005' && key === 'goods') {
|
||||
return (
|
||||
this.widgets.find((item) => String(item.config?.name || '').toLowerCase() === 'goodscard') ||
|
||||
this.widgets.find((item) => (item.name || '').toLowerCase() === 'goods') ||
|
||||
null
|
||||
)
|
||||
}
|
||||
return null
|
||||
},
|
||||
// 用 widgets 中注册的组件名(如 LocationModule)渲染,避免 config.name(如 locationModule)与 Vue 注册名大小写不一致导致预览不显示
|
||||
getComponentName(item) {
|
||||
if (!item?.name || !this.widgets.length) return item?.name || ''
|
||||
const w = this.widgets.find(
|
||||
(wgt) => (wgt.name || '').toLowerCase() === (item.name || '').toLowerCase()
|
||||
)
|
||||
const w = this.findWidgetForPersistedName(item.name)
|
||||
return w ? w.name : item.name
|
||||
},
|
||||
getComponentAttr(item) {
|
||||
if (!item) return { wgtName: '', config: {} }
|
||||
const wgt = this.widgets.find((wgt) => {
|
||||
return wgt.name?.toLowerCase() == item.name?.toLowerCase()
|
||||
})
|
||||
const wgt = this.findWidgetForPersistedName(item.name)
|
||||
if (!wgt) return { wgtName: item.wgtName || item.name || '', ...(item.config || {}) }
|
||||
return {
|
||||
wgtName: wgt.wgtName,
|
||||
@@ -470,7 +484,7 @@ export default {
|
||||
|
||||
list.forEach((li) => {
|
||||
// 是否存在挂件
|
||||
const wgt = this.widgets.find((item) => item.name?.toLowerCase() == li.name?.toLowerCase())
|
||||
const wgt = this.findWidgetForPersistedName(li.name)
|
||||
if (wgt) {
|
||||
// console.log('getTemplateDetial wgt:', wgt)
|
||||
const wgtInitParams = this.cloneDefaultField(wgt)
|
||||
@@ -575,7 +589,7 @@ export default {
|
||||
// 是否为有效挂件(在 widgets 中注册且可渲染)
|
||||
isValidContentComp(c) {
|
||||
if (!c || typeof c !== 'object' || !c.name) return false
|
||||
return this.widgets.some((w) => (w.name || '').toLowerCase() === (c.name || '').toLowerCase())
|
||||
return !!this.findWidgetForPersistedName(c.name)
|
||||
},
|
||||
// 检查是否可以添加挂件(互斥逻辑:店铺字母列表、整屏滑动 与其余挂件互斥)
|
||||
canAddWgt(wgtName) {
|
||||
@@ -640,10 +654,9 @@ export default {
|
||||
return
|
||||
}
|
||||
const data = this.contentComps.map((item) => {
|
||||
const { transformOut } = this.widgets.find(
|
||||
(wgt) => wgt.name?.toLowerCase() == item.name?.toLowerCase()
|
||||
)?.config
|
||||
return transformOut(item, this.widgets)
|
||||
const wgt = this.findWidgetForPersistedName(item.name)
|
||||
const { transformOut } = wgt?.config || {}
|
||||
return transformOut ? transformOut(item, this.widgets) : item
|
||||
})
|
||||
data.unshift(this.headerAttr.transformOut(this.headerData, this.widgets))
|
||||
const { id } = this.$route.query
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
import { pickBy } from '@/utils'
|
||||
import { i18n } from '@/i18n'
|
||||
import AttrGoods from './attr-goods'
|
||||
import { transformInBase, createTransformOutBase } from '../../comps/transform-utils'
|
||||
|
||||
const config = {
|
||||
name: 'goods',
|
||||
name: 'goodsCard',
|
||||
setting: [
|
||||
{ label: i18n.t('8f58e7cb.4707ba'), key: 'padded', component: 'switch', value: true },
|
||||
{
|
||||
label: i18n.t('8f58e7cb.43d1e2'),
|
||||
key: 'data',
|
||||
@@ -21,10 +21,11 @@ const config = {
|
||||
],
|
||||
transformIn: (v) => {
|
||||
const { name, base, data, track, tagsType, meber_tags, no_meber_tags } = v
|
||||
const transformedBase = transformInBase(base || {}, ['outerMargin', 'innerPadding'])
|
||||
return {
|
||||
id: v?.id,
|
||||
name,
|
||||
...base,
|
||||
...transformedBase,
|
||||
data,
|
||||
track,
|
||||
tags: {
|
||||
@@ -39,12 +40,20 @@ const config = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
base: (v) => {
|
||||
return pickBy(v, {
|
||||
const styleBase = createTransformOutBase(
|
||||
['outerMargin', 'innerPadding', 'outerBackground', 'innerBackground'],
|
||||
['outerMargin', 'innerPadding']
|
||||
)(v)
|
||||
const contentBase = pickBy(v, {
|
||||
title: 'title',
|
||||
subtitle: 'subtitle',
|
||||
padded: 'padded',
|
||||
proportion: 'proportion'
|
||||
})
|
||||
return {
|
||||
...styleBase,
|
||||
...contentBase
|
||||
}
|
||||
},
|
||||
data: 'data',
|
||||
track: 'track',
|
||||
|
||||
@@ -5,37 +5,21 @@
|
||||
|
||||
<style lang="scss">
|
||||
.wgt-goods-card {
|
||||
&.padded {
|
||||
padding: 10px 0;
|
||||
}
|
||||
.wgt-hd {
|
||||
padding: 10px;
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
.sub-title {
|
||||
color: #666;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
.wgt-bd {
|
||||
padding: 0 10px;
|
||||
.goods-card {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
&__header {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
&__info {
|
||||
padding-left: 10px;
|
||||
height: 80px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
&__info-title {
|
||||
font-size: 14px;
|
||||
@@ -66,17 +50,17 @@
|
||||
<div
|
||||
:class="{
|
||||
'wgt-goods-card': true,
|
||||
padded: value.padded
|
||||
}"
|
||||
:style="outerStyle"
|
||||
>
|
||||
<div v-if="value.title || value.subtitle" class="wgt-hd">
|
||||
<span class="title">{{ value.title }}</span>
|
||||
<span class="sub-title">{{ value.subtitle }}</span>
|
||||
</div>
|
||||
<div class="wgt-bd">
|
||||
<!-- 挂件自定义部分 -->
|
||||
<div v-for="(item, index) in value.data" :key="`goods-card__${index}`" class="goods-card">
|
||||
<div
|
||||
v-for="(item, index) in value.data"
|
||||
:key="`goods-card__${index}`"
|
||||
class="goods-card"
|
||||
:style="goodsCardInnerStyle"
|
||||
>
|
||||
<div class="goods-card__header">
|
||||
<SpImage :src="item.img_url" width="80" height="80" />
|
||||
<div class="goods-card__info">
|
||||
@@ -102,9 +86,11 @@
|
||||
<script>
|
||||
import { i18n } from '@/i18n'
|
||||
import config from './config'
|
||||
import { getOuterStyle } from '../../comps/style-utils'
|
||||
import { getOuterStyle, getInnerStyle } from '../../comps/style-utils'
|
||||
export default {
|
||||
name: 'Goods',
|
||||
// 与 config.name 一致(落库 goodsCard);与商城 Goods 区分
|
||||
// eslint-disable-next-line vue/component-definition-name-casing -- 要求小驼峰 goodsCard
|
||||
name: 'goodsCard',
|
||||
wgtName: '商品卡片',
|
||||
wgtDesc: '',
|
||||
wgtIcon: 'wgt-goods-card',
|
||||
@@ -113,9 +99,20 @@ export default {
|
||||
value: [Object, Array]
|
||||
},
|
||||
data() {
|
||||
return { i18n, currentIndex: 1 }
|
||||
return {
|
||||
i18n,
|
||||
currentIndex: 1
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
/** 商品卡片块背景:走全局 innerPadding/内层背景配置(与 goods 等挂件一致),未配置时默认白底 */
|
||||
goodsCardInnerStyle() {
|
||||
const s = { ...getInnerStyle(this.value), borderRadius: '8px' }
|
||||
if (!s.backgroundColor && !s.backgroundImage) {
|
||||
s.backgroundColor = '#fff'
|
||||
}
|
||||
return s
|
||||
},
|
||||
outerStyle() {
|
||||
return getOuterStyle(this.value)
|
||||
},
|
||||
|
||||
@@ -111,7 +111,6 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="!VERSION_PLATFORM()"
|
||||
:label="$t('0e7dabe2.e8f9a1')"
|
||||
width="120"
|
||||
align="center"
|
||||
@@ -197,10 +196,7 @@ export default {
|
||||
{
|
||||
label: this.$t('0e7dabe2.e8f9a1'),
|
||||
key: 'is_show_front',
|
||||
isShow: () => !this.VERSION_PLATFORM(),
|
||||
component: ({ key }, value) => (
|
||||
<el-switch v-model={value[key]} active-value='1' inactive-value='0' />
|
||||
)
|
||||
component: ({ key }, value) => <el-switch v-model={value[key]} active-value="1" inactive-value="0"/>,
|
||||
},
|
||||
{
|
||||
label: this.$t('0e7dabe2.dc1eed'),
|
||||
|
||||
@@ -1890,7 +1890,7 @@ export default {
|
||||
distributorIds = data.map((item) => item.distributor_id)
|
||||
}
|
||||
if (this.selectionItems.length == 0) {
|
||||
await this.$confirm(this.$t('d41d8cd9.y9z0a1'), this.$t('d41d8cd9.s3t4u5'))
|
||||
await this.$confirm(this.$t('6f19b2ab.6b3d7e'), this.$t('d41d8cd9.02d981'))
|
||||
await this.$api.marketing.saveDistributorItems({
|
||||
distributor_ids: distributorIds,
|
||||
item_ids: '_all',
|
||||
|
||||
@@ -5,6 +5,17 @@
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="search-bar">
|
||||
<el-input
|
||||
v-model="params.mobile"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
:placeholder="$t('ff557c54.6e4f4b')"
|
||||
@keyup.enter.native="onSearch"
|
||||
@clear="onSearch"
|
||||
/>
|
||||
<el-button type="primary" @click="onSearch">{{ $t('223cc8af.e5f71f') }}</el-button>
|
||||
</div>
|
||||
<el-table v-loading="loading" :data="cardList" style="width: 100%" border height="600">
|
||||
<el-table-column prop="username" :label="$t('7c2974e3.5b95ee')" />
|
||||
<el-table-column prop="mobile" :label="$t('7c2974e3.8098e2')" />
|
||||
@@ -43,6 +54,7 @@ export default {
|
||||
cardList: [],
|
||||
params: {
|
||||
card_id: 0,
|
||||
mobile: '',
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
@@ -61,6 +73,10 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onSearch() {
|
||||
this.params.page = 1
|
||||
this.getCardUserList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.params.page = val
|
||||
this.getCardUserList()
|
||||
@@ -90,4 +106,10 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
<style scoped lang="scss">
|
||||
.search-bar {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,6 +5,17 @@
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="search-bar">
|
||||
<el-input
|
||||
v-model="params.mobile"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
:placeholder="$t('ff557c54.6e4f4b')"
|
||||
@keyup.enter.native="onSearch"
|
||||
@clear="onSearch"
|
||||
/>
|
||||
<el-button type="primary" @click="onSearch">{{ $t('223cc8af.e5f71f') }}</el-button>
|
||||
</div>
|
||||
<el-table v-loading="loading" :data="cardList" style="width: 100%" border height="600">
|
||||
<!-- <el-table-column prop="title" label="优惠券名称" width="200"></el-table-column> -->
|
||||
<el-table-column prop="code" :label="$t('de5acab9.390c08')" width="120" />
|
||||
@@ -47,6 +58,7 @@ export default {
|
||||
params: {
|
||||
card_id: 0,
|
||||
is_use: true,
|
||||
mobile: '',
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
@@ -65,6 +77,10 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onSearch() {
|
||||
this.params.page = 1
|
||||
this.getCardUserList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.params.page = val
|
||||
this.getCardUserList()
|
||||
@@ -94,4 +110,10 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
<style scoped lang="scss">
|
||||
.search-bar {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -38,9 +38,11 @@
|
||||
<el-table-column prop="status" :label="$t('8b0d1458.53c3dd')">
|
||||
<template slot-scope="scope">
|
||||
<div>
|
||||
<el-tag v-if="scope.row.status === '1'" type="success">
|
||||
{{ $t('8b0d1458.7854b5') }}
|
||||
</el-tag>
|
||||
<el-tag v-if="isTemplateEnabled(scope.row.status)" type="success">
|
||||
{{
|
||||
$t('8b0d1458.7854b5')
|
||||
}}
|
||||
</el-tag>
|
||||
<el-tag v-else type="info">{{ $t('8b0d1458.463776') }}</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
@@ -50,7 +52,9 @@
|
||||
<div>
|
||||
<el-button type="text" size="mini" @click="handleDisable(scope.row)">
|
||||
{{
|
||||
scope.row.status === '1' ? $t('8b0d1458.710ad0') : $t('8b0d1458.7854b5')
|
||||
isTemplateEnabled(scope.row.status)
|
||||
? $t('8b0d1458.710ad0')
|
||||
: $t('8b0d1458.7854b5')
|
||||
}}
|
||||
</el-button>
|
||||
<el-button type="text" size="mini" @click="handleDelete(scope.row)">
|
||||
@@ -191,6 +195,10 @@ export default {
|
||||
this.getTemplateList()
|
||||
},
|
||||
methods: {
|
||||
/** 接口可能返回 number 1 或 string '1' */
|
||||
isTemplateEnabled(status) {
|
||||
return status === 1 || status === '1' || status === true || status === 'true'
|
||||
},
|
||||
handleDialogClose() {
|
||||
this.dialogVisible = false
|
||||
this.resetForm('myForm')
|
||||
@@ -207,7 +215,7 @@ export default {
|
||||
this.formData.template_title = row.template_title
|
||||
this.formData.template_description = row.template_description
|
||||
this.formData.page_type = row.page_type
|
||||
this.formData.status = row.status === '1'
|
||||
this.formData.status = this.isTemplateEnabled(row.status)
|
||||
})
|
||||
},
|
||||
handleRenovation({ theme_pc_template_id }) {
|
||||
@@ -217,7 +225,7 @@ export default {
|
||||
try {
|
||||
this.loading = true
|
||||
const res = await editPageTemplate({
|
||||
status: status === '1' ? '2' : '1',
|
||||
status: this.isTemplateEnabled(status) ? '2' : '1',
|
||||
...rest
|
||||
})
|
||||
this.loading = false
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
|
||||
<template>
|
||||
<SpPage>
|
||||
<SpPlatformTip
|
||||
v-if="!VERSION_SHUYUN()"
|
||||
h5
|
||||
app
|
||||
alipay
|
||||
:text-val="$t('20f6ad88.c5d4d8')"
|
||||
/>
|
||||
<SpFormPlus
|
||||
ref="form"
|
||||
v-model="form"
|
||||
|
||||
@@ -6,6 +6,13 @@
|
||||
<template>
|
||||
<SpPage>
|
||||
<div v-loading="loading">
|
||||
<SpPlatformTip
|
||||
v-if="!VERSION_SHUYUN()"
|
||||
h5
|
||||
app
|
||||
alipay
|
||||
:text-val="$t('59579ae2.c5d4d8')"
|
||||
/>
|
||||
<SpFormPlus
|
||||
ref="form"
|
||||
v-model="form"
|
||||
|
||||
Reference in New Issue
Block a user