diff --git a/README.md b/README.md index e24feaad7..8713f80ab 100644 --- a/README.md +++ b/README.md @@ -162,19 +162,42 @@ lilishop-ui ## 8. 升级计划 -> 更新日期:2026-11-04,依据各端近期提交及当前代码实现同步。 - ### ✅ 已完成特性 -| 功能模块 | 功能模块 | -| :--- | :--- | -| ✅ 商品定时上下架 | ✅ 商品分组 / 会员分组 | -| ✅ 商品虚拟销量 | ✅ 专用发票(发票上传) | -| ✅ 置顶评论 | ✅ 客户等级体系 | -| ✅ 购物卡 | ✅ 腾讯云-云直播 | -| ✅ 卡密商品 | ✅ 二级分销 | -| ✅ 定时任务管理(数据库配置驱动) | ✅ 预约服务商品 | -| ✅ 主题色管理 | ✅ 立减优惠券 | -| ✅ 小程序订单管理(简单版) | ✅ 微信订单自动上报开关 | + +按可核实的实现或完善时间倒序记录;日期表示代码完成或功能更新时间,不代表生产上线时间。 + +| 时间 | 功能模块 | 完成内容 | +| :--- | :--- | :--- | +| 2026-11-05 | ✅ 付费会员 | 单一付费会员、开通与续费、有效期、关联权益、商家与商品折扣、平台补贴及付费记录。 | +| 2026-11-04 | ✅ 客户等级体系 / 客户权益 | 等级配置、权益介绍、经验值任务与明细、权益发放及重试,提供默认等级与权益数据。 | +| 2026-11-04 | ✅ 小程序订单管理 | 增加小程序订单查询入口及微信订单自动上报开关。 | +| 2026-11-04 | ✅ 立减优惠券 | 新增立减券,完善优惠券校验、领取与订单优惠计算。 | +| 2026-11-04 | ✅ 商品定时上下架 | 完善定时上下架计划管理、独立列表及执行校验。 | +| 2026-11-04 | ✅ 微信小程序原生能力 | 接入微信地址导入、头像选择和昵称填写。 | +| 2026-11-02 | ✅ 消息模板 | 支持多渠道模板矩阵维护,统一站内信、短信、微信公众号及小程序订阅消息的场景配置和异步发送。 | +| 2026-10-30 | ✅ PC 页面装修 | 重构楼层组件,支持自适应高度、可视化热区绘制及配置交互优化。 | +| 2026-10-29 | ✅ 定时任务管理 | 重构为数据库配置驱动,支持运营后台维护任务。 | +| 2026-10-29 | ✅ 敏感词管理 | 支持按业务场景配置过滤开关,并优化词库加载。 | +| 2026-10-29 | ✅ PC 店铺搜索 | 新增店铺列表,支持商品与店铺双模式搜索。 | +| 2026-10-22 | ✅ 分类设置 | 支持四种分类页模板选择、商品列表展示字段开关及模板图片预览。 | +| 2026-10-20 | ✅ 移动端页面装修 | 完善可视化编辑器,新增首页组合组件及优惠券、店铺、文章等楼层。 | +| 2026-10-09 | ✅ 主题色管理 | 完善主题设置,支持自定义模式。 | +| 2026-10-02 | ✅ 预约服务商品 | 完善预约商品、预约交易及订单详情功能。 | +| 2026-08-05 | ✅ 二级分销 | 由一级分销扩展为二级分销,增加节点配置及分销员中心。 | +| 2026-08-03 | ✅ 卡密商品 | 完善电子卡券履约、订单状态及卡池管理。 | +| 2026-07-23 | ✅ 素材库管理 | 增加文件分类、目录管理及目录归属校验。 | +| 2026-07-20 | ✅ 经营统计报表 | 新增店铺业绩、商品同比环比、销售订单明细及商品销售汇总报表。 | +| 2026-07-13 | ✅ 腾讯云直播 | 接入并完善直播、聊天与直播商品相关功能。 | +| 2026-06-30 | ✅ 移动端技术升级 | 升级 Vue 3 与 uView Plus,适配组件和页面。 | +| 2026-06-29 | ✅ 电子面单发货 | 完善快递鸟电子面单,支持自动携带运单号发货。 | +| 2026-06-05 | ✅ 后端与管理端框架升级 | 5 月 25 日至 6 月 5 日完成 Spring Boot 4、管理端 Vue 3 与 Element Plus 升级。 | +| 2026-05-22 | ✅ 购物卡 | 新增礼品卡接口,以及选择、绑定、激活和列表管理。 | +| 2026-05-20 | ✅ 微信提现 | 完善转账状态查询、确认回调和重试处理,后续补充提现规则说明配置。 | +| 2026-04-16 | ✅ 置顶评论 | 支持评论置顶及商品评价管理。 | +| 2026-04-13 | ✅ 专用发票(发票上传) | 完善发票信息字段、发票详情及管理展示。 | +| 2026-04-01 | ✅ 商品虚拟销量 | 支持按商品规格设置虚拟销量,提供单个及批量设置入口。 | +| 2026-03-30 | ✅ 商品分组 | 新增商品分组管理及商品关联功能。 | +| 2026-03-24 | ✅ 会员分组 | 新增会员分组管理。 | ### 🔜 近期规划中 - 🔜 微信小店对接 diff --git a/manager/src/api/paid-member.js b/manager/src/api/paid-member.js new file mode 100644 index 000000000..89ff161e9 --- /dev/null +++ b/manager/src/api/paid-member.js @@ -0,0 +1,6 @@ +import { getRequest, putRequestWithNoForm } from '@/libs/axios'; +export const getPaidConfig = () => getRequest('/member/paid/config'); +export const savePaidConfig = data => putRequestWithNoForm('/member/paid/config', data); +export const getPaidOrders = params => getRequest('/member/paid/orders', params); +export const getPaidResources = (type, ids) => getRequest('/member/paid/resources', { type, ids: ids.join(',') }); +export const getPaidDiscountSkus = params => getRequest('/member/paid/discount-skus', params); diff --git a/manager/src/components/lili-dialog/goods-dialog.vue b/manager/src/components/lili-dialog/goods-dialog.vue index 498088384..9a3ded903 100644 --- a/manager/src/components/lili-dialog/goods-dialog.vue +++ b/manager/src/components/lili-dialog/goods-dialog.vue @@ -92,6 +92,9 @@ {{ row.simpleSpecs || "默认规格" }} + + + - diff --git a/manager/src/components/store-selector/README.md b/manager/src/components/store-selector/README.md new file mode 100644 index 000000000..cf7ab8afb --- /dev/null +++ b/manager/src/components/store-selector/README.md @@ -0,0 +1,25 @@ +# 统一店铺选择器 + +作者:Bulbasaur;2026-11-05。 + +默认从右侧打开抽屉,支持搜索、分页、多选和已选回显。取消不提交,确认通过 `selected` 返回完整已选店铺数组。店铺类型、状态均为普通文字,无右侧预览区。 + +```vue + +``` + +导入 `@/components/store-selector/index.vue`,通过 `selector.value.open(selectedRows)` 打开。`selectedRows` 为包含 `id` 的店铺对象数组;每次打开建立独立选择草稿。 + +| 参数 | 默认值 | 用途 | +| --- | --- | --- | +| multiple | true | false 时单选,返回数组最多一项 | +| embedded | false | true 时在父容器展示列表,并在选择时立即通知;适用于装修链接面板 | +| selectedWay | [] | 初始店铺数组;内嵌模式监听外部选择变化 | +| queryParams | {} | 店铺查询限制,例如 `{ storeDisable: 'OPEN' }` | +| title | 选择店铺 | 抽屉标题 | +| size | 1080px | 抽屉宽度,最大为视口宽度 | +| tableHeight | 自动 | 可选表格高度 | + +已接入付费会员、装修链接单选、移动端装修店铺列表配置。查询复用 `getShopListData`(`/store/store`),不新增后端接口。 + +验证:在工作区根目录运行 `node scripts/test-store-selector.cjs`。 diff --git a/manager/src/components/store-selector/index.vue b/manager/src/components/store-selector/index.vue new file mode 100644 index 000000000..37bc88f53 --- /dev/null +++ b/manager/src/components/store-selector/index.vue @@ -0,0 +1,115 @@ + + + diff --git a/manager/src/router/router.js b/manager/src/router/router.js index b815c1533..6f50f663a 100644 --- a/manager/src/router/router.js +++ b/manager/src/router/router.js @@ -224,6 +224,14 @@ export const otherRouter = { name: "member-benefit", component: () => import("@/views/member/benefit/index.vue") }, + { + path: "paid-member-settings", title: "付费会员", name: "paid-member-settings", + component: () => import("@/views/member/paid/settings.vue") + }, + { + path: "paid-member-records", title: "付费记录", name: "paid-member-records", + component: () => import("@/views/member/paid/records.vue") + }, { path: "member-benefit-deliveries", title: "权益发放明细", @@ -242,7 +250,7 @@ export const otherRouter = { name: "member-grade-experience-log", component: () => import("@/views/member/grade/experience-log.vue") }, - + { path: "goods/goods-info/goodsDetail", diff --git a/manager/src/views/member/benefit/index.vue b/manager/src/views/member/benefit/index.vue index d57b37504..3ccabfa5c 100644 --- a/manager/src/views/member/benefit/index.vue +++ b/manager/src/views/member/benefit/index.vue @@ -111,7 +111,7 @@ - + @@ -1585,3 +1585,6 @@ onMounted(() => { } + + + diff --git a/manager/src/views/member/paid/records.vue b/manager/src/views/member/paid/records.vue new file mode 100644 index 000000000..09363ba47 --- /dev/null +++ b/manager/src/views/member/paid/records.vue @@ -0,0 +1,47 @@ + + + diff --git a/manager/src/views/member/paid/settings.vue b/manager/src/views/member/paid/settings.vue new file mode 100644 index 000000000..b00f1b61f --- /dev/null +++ b/manager/src/views/member/paid/settings.vue @@ -0,0 +1,159 @@ + + + diff --git a/manager/src/views/page-decoration/wap/config-panel/PanelShop.vue b/manager/src/views/page-decoration/wap/config-panel/PanelShop.vue index d5cc6104f..639765408 100644 --- a/manager/src/views/page-decoration/wap/config-panel/PanelShop.vue +++ b/manager/src/views/page-decoration/wap/config-panel/PanelShop.vue @@ -80,7 +80,7 @@
选择店铺
- 选择店铺 + 选择店铺
@@ -176,38 +176,7 @@ /> - - - - - - - - - - - - +
@@ -217,7 +186,7 @@ import ColorField from "../controls/ColorField.vue"; import SliderField from "../controls/SliderField.vue"; import ossManage from "@/views/sys/oss-manage/ossManage"; import ways from "@/components/lili-dialog/wap.js"; -import { getShopListData } from "@/api/shops"; +import StoreSelector from "@/components/store-selector/index.vue"; const DEFAULTS = { bgColor1: "#FFFFFF", @@ -247,7 +216,7 @@ const DEFAULT_ITEM = { export default { name: "PanelShop", hideDecorateTitle: true, - components: { GradientField, ColorField, SliderField, ossManage }, + components: { GradientField, ColorField, SliderField, ossManage, StoreSelector }, props: { res: { type: Object, required: true }, }, @@ -260,10 +229,6 @@ export default { { key: "style", title: "样式" }, ], picModelFlag: false, - shopDialogVisible: false, - shopLoading: false, - shopOptions: [], - selectedShops: [], }; }, computed: { @@ -284,30 +249,15 @@ export default { if (!Array.isArray(item.shopList)) item.shopList = []; }, methods: { - // 加载店铺列表供选择 - loadShops() { - this.shopLoading = true; - this.selectedShops = []; - getShopListData({ pageNumber: 1, pageSize: 100, status: "OPEN" }) - .then((res) => { - this.shopOptions = (res && res.result && res.result.records) || []; - }) - .finally(() => { - this.shopLoading = false; - }); - }, - onShopSelection(rows) { - this.selectedShops = rows; - }, - confirmShops() { - this.firstItem.shopList = this.selectedShops.map((s) => ({ + openShops() { this.$refs.storeSelector.open(this.firstItem.shopList); }, + confirmShops(rows) { + this.firstItem.shopList = rows.map((s) => ({ id: s.id, storeName: s.storeName, storeLogo: s.storeLogo, selfOperated: s.selfOperated, storeBanner: s.storeBanner || "", })); - this.shopDialogVisible = false; }, removeShop(index) { this.firstItem.shopList.splice(index, 1);