1108 Commits

Author SHA1 Message Date
pikachu1995@126.com
2563f122fc feat(manager): 优化定时任务管理、敏感词场景配置与商品选择器多规格匹配 2026-10-29 17:06:21 +08:00
pikachu1995@126.com
8739811b04 feat(pc-decorate): PC端楼层装修组件体系规范默认行高与各楼层组件重构 2026-10-29 17:06:08 +08:00
pikachu1995@126.com
5973d43b9d feat(buyer): 统一全站页面顶部为现代TopBar与SearchHeader,支持商品/店铺双模搜索与占位词规范 2026-10-29 17:05:53 +08:00
pikachu1995@126.com
d113f5c553 feat(buyer): 新增PC端店铺列表页面并优化搜索与商品缩略图 2026-10-29 17:00:03 +08:00
pikachu1995@126.com
5c7b109be6 fix(manager): 修复 walletLog 和 recharge 页面缺少 onMounted 导入的问题 2026-10-29 14:17:54 +08:00
pikachu1995@126.com
97e611c072 refactor(im): 重构聊天面板UI组件并修复多处交互问题
- 将头像组件从 dicebear 外链改为本地首字+底色生成,新增 avatarColor 工具函数
- 重构订单卡片(footPrint.vue)布局,优化商品与订单信息展示结构
- 重构店铺详情卡片(storeDetail.vue),统一信息行与评分行样式
- 移除消息气泡中的昵称时间行,调整气泡背景色与头像内边距
- 修复 face 变量名与全局组件 <face> 冲突导致头像URL被当作标签渲染
- 将 unload 事件监听替换为 pagehide,兼容 Chrome 弃用策略
- 修复搜索关键词未转义正则元字符导致输入特殊字符时抛异常
- 修复 WebSocket onMessage 对无 text 字段的推送消息误调用 JSON.parse
- 将 setup 中同步调用全局 mixin 方法移至 onMounted,避免代理未就绪
- 商品/订单图片统一添加 onerror 默认图兜底
- 聊天列表消息预览支持 emoji 图片渲染(textReplaceEmoji)
- 搜索框增加 clearable 属性及"没有找到相关好友"空态提示
- 锁定 element-plus 版本为 2.14.1 防止自动升级引入兼容问题
- 日期格式化分隔符由斜杠改为横杠
- 提现设置页新增提现规则说明字段,满足微信审核公示要求
2026-10-29 10:56:28 +08:00
pikachu1995@126.com
68dfae9a62 refactor(indexDecorate): 将静态资源迁移至OSS并优化轮播组件样式
- 将所有组件中的静态图片路径从本地 /static 迁移至 OSS 远程地址
- 更新 ChannelFloor、BrandWall 等组件的默认图片资源路径
- 更新 page-decoration/pc/config.js 中所有默认配置的图片路径
- 优化 Carousel 组件:fitMode 默认改为 contain,添加圆角与阴影样式
- Carousel 新增 banners 字段兼容映射,支持多种数据格式
- Carousel 指示器颜色改为深色,布局改为 flex 居中展示
2026-10-29 09:36:01 +08:00
pikachu1995@126.com
bb8e9a0d3d feat(buyer,manager): 楼层装修组件体系与平台端页面优化
- buyer:楼层装修组件(RowWrapper、组件库、预设、注册表)及首页/商品列表适配
- manager:PC端楼层装修页面、店铺设置、OSS素材管理等页面样式优化
2026-10-28 17:41:03 +08:00
pikachu1995@126.com
f4fd1c1acd feat(seller): 营销页面体验优化与列表页样式统一
- 拼团:去除拼团规则字段、编辑页商品表补SKU编码/规格/图片、提交按钮失败卡死修复
- 秒杀:活动详情改描述列表、场次商品数徽标、当前场次提示、页签标题动态显示活动名称
- 满额:卡片分区布局、查看模式只读描述视图、去除活动描述、新建默认近七天时间
- 优惠券:查看模式只读描述视图、去除店铺承担比例与范围描述、指定商品表加SKU/规格/图片
- 商品选择器:首列改SKU编码、弹层z-index修复
- 分销订单:商品信息列重构、卡片间距、状态筛选Tab
- 库存管理:筛选与列表分区、行高压缩、SPU/SKU编码列
- 全局:所有列表操作列统一右对齐
2026-10-28 17:40:50 +08:00
pikachu1995@126.com
21abd26b1f feat(buyer): 商品视频内嵌相册展示(天猫风格)
- 视频作为相册第一项,进页静音自动循环播放,控制条可开声音
- 竖视频两侧黑边改为封面高斯模糊填充(覆盖 DPlayer 运行时注入的黑底)
- 缩略图显示视频第一帧,居中透明播放图标
- 悬停切换相册时自动暂停/续播,播放器容器常驻避免实例丢失
- 移除购买区观看视频按钮与弹窗
- isCollection 收藏状态查询补充 catch,避免未捕获报错
2026-10-28 15:09:52 +08:00
pikachu1995@126.com
a55c8356c8 fix(buyer): 修复商品详情页未登录时调用评价接口导致的登录弹窗与未捕获报错
- goodsComment/goodsCommentNum 改为 needToken,未登录时不再发起请求
- 评价/收藏状态等后台查询增加 skipAuthHandler+skipMessage,token 失效时静默失败
- ShowGoodsDetail 评价接口调用补充 catch 并增加登录守卫
2026-10-28 15:09:28 +08:00
pikachu1995@126.com
b025ab804e feat(seller): 评价管理列表增强(回复状态/有无图片筛选、评价分级 Tab、会员头像列)及多页面样式优化(商品列表、部门管理、OSS 素材、运费模板、页头页脚等) 2026-10-27 16:05:36 +08:00
pikachu1995@126.com
700c709afd style(after-sale): 重构售后详情页为左主右辅布局(顶部摘要条、售后进度时间线、退款信息卡、订单编号跳转) 2026-10-27 16:01:44 +08:00
pikachu1995@126.com
8d0788e09b style(order): 优化订单详情页样式(按钮分组右置、分组标题、金额汇总负号红字、优惠明细直出) 2026-10-27 16:01:44 +08:00
pikachu1995@126.com
55a431ddd5 fix(order): 区分订单操作按钮颜色、待支付不显示退款标签、列表移除售后/投诉入口、修复详情页商品列表被全局样式压缩 2026-10-26 17:01:44 +08:00
pikachu1995@126.com
b72c792ade style(member): 统一会员中心页面风格(卡片面板/状态标签/链接按钮/右对齐分页) 2026-10-26 17:01:30 +08:00
pikachu1995@126.com
1f872254cc style(member): 优化申诉详情、会员等级、优惠券、礼品卡页面样式 2026-10-26 17:01:08 +08:00
pikachu1995@126.com
99e7f6ed47 feat(home): 丰富PC买家中心主页,增加订单快捷入口与资产卡片 2026-10-26 17:00:57 +08:00
pikachu1995@126.com
06e02998aa feat(shopEntry): 优化店铺入驻页面视觉与流程
- 新增品牌头部与自定义步骤条,已完成步骤支持点击回跳修改
- 审核状态页改用 el-result 图标结果页(审核中/已通过/已拒绝/已关闭)
- 分区标题改为主题色竖线样式,表单加宽,地址选择改为输入框样式
- 上传组件改为虚线卡片,补充上传失败与业务失败的错误提示
- 第2、3步补齐 sessionStorage 草稿保存,表单校验失败自动滚动到错误项
- 地址选择弹窗去除横向滚动,超长名称省略并支持悬停显示
- 注册 ElResult 组件;公司电话/营业执照号/法人证件号放宽为仅必填
2026-10-26 16:47:35 +08:00
pikachu1995@126.com
1395f2ad24 refactor(goods): 重构分类页面装修,使用图片预览替代CSS示意图
- 将"货号"统一重命名为"SKU编码"
- 重构分类页面装修,使用图片预览替代CSS示意图
- 修复商家端主容器横向溢出隐藏问题
2026-10-22 16:37:54 +08:00
pikachu1995@126.com
67e8c86b5b feat: 新增页面装修-分类设置页(模板选择+商品列表字段开关) 2026-10-22 09:15:44 +08:00
pikachu1995@126.com
9fcd325df9 fix(goods): 修复商品发布校验失败后保存按钮一直处于loading的问题 2026-10-22 08:52:16 +08:00
pikachu1995@126.com
f21ce6e252 refactor(decoration): 重构店铺装修组件配置并规范化环境变量
- 重构装修组件配置,新增 icon 与 group 分类字段
- 将组件"图片"重命名为"热区","图片轮播"重命名为"轮播图"
- 新增搜索、公告、视频组件配置项
- 统一为各图片项添加 model 字段标识跳转模式
- 将装修页面组件间 pageGap 间距由 10 调整为 0
- 移除 im 模块中 VUE_APP_COMMON 变量,统一使用 VUE_APP_BUYER
- 为 im 环境变量与配置文件添加详细注释说明
2026-10-21 15:17:05 +08:00
pikachu1995@126.com
da95f17885 docs: 更新项目 README 与开源许可说明 2026-10-20 19:07:47 +08:00
pikachu1995@126.com
0f9593d5ed feat(page-decoration): 新增移动端头部综合组件并重构各楼层模板尺寸与排版 2026-10-20 19:07:43 +08:00
pikachu1995@126.com
088a2bb308 feat(oss): 优化素材库上传格式限制及组件模式下的 Tab 显示 2026-10-20 19:07:35 +08:00
pikachu1995@126.com
d29ad9c99b refactor(page-decoration): 重构装修页面组件与交互方式
- 统一 liliDialog ref 命名为 liliDialogRef,避免与组件 import 冲突
- 商品选择弹窗改为 el-table 表格形式展示
- 链接选择器从 el-dialog 改为 el-drawer 抽屉形式
- 为所有 img 标签添加 alt 属性提升可访问性
- 新增拼团、直播、秒杀、砍价、积分商城、优惠券等营销组件默认配置
- 删除商品分类组件,新增商品列表组件配置
- i18n 配置从 legacy 模式切换为 composition 模式
- 注册 PanelSearch、PanelNotice、PanelVideo 等新面板组件
- 优化画布预览区域样式并添加页面设置入口
2026-10-20 16:13:28 +08:00
pikachu1995@126.com
d87e0c5f6b fix(seller): 修正 serviceStaffList 中 getUserListData 的导入路径为 @/api/index 2026-10-20 15:48:39 +08:00
pikachu1995@126.com
5e74e356e0 refactor(manager): 重构商品/审核/品牌/分词/分销提现与等级等7个核心列表页为 useTable
- 重构商品管理(商品总览、商品审核)列表页为 useTable

- 重构商品维护(品牌管理、评价管理)列表页为 useTable

- 重构分销管理(分销提现、等级变动历史)与自定义分词列表页为 useTable

- 消除 150+ 行重复样板代码,统一竞态防护与分页查询规范
2026-10-20 14:56:06 +08:00
pikachu1995@126.com
cba624f480 refactor(seller): 重构预约服务、分销与商品库存等8个列表页为 useTable
- 重构预约服务模块(服务人员、系统表单、服务工单)列表页为 useTable

- 重构分销管理模块(分销商品、分销订单)列表页为 useTable

- 重构商品与库存模块(库存导出导入、库存预警管理、商品草稿模版)列表页为 useTable

- 消除 180+ 行模板重复代码,规范分页、防抖与请求竞态防护
2026-10-20 14:28:29 +08:00
pikachu1995@126.com
ba964ff478 refactor(manager): 重构统计报表、促销活动与工单审核等12个列表页为 useTable
- 重构统计报表(销售订单明细、商品销售汇总、店铺业绩)列表页为 useTable

- 重构营销活动(秒杀、第N件优惠、积分商品)列表页为 useTable

- 重构财务流水(钱包日志)、服务工单、分销导入、店铺审核、商品参数、订单投诉列表页

- 消除约 210+ 行分页/防抖/竞态重复样板代码,统一加载与查询状态规范
2026-10-20 14:20:36 +08:00
pikachu1995@126.com
45338c9d70 style(seller): 重构订单统计页转化漏斗与指标卡样式 2026-10-20 14:15:07 +08:00
pikachu1995@126.com
6b6dc2c4f3 refactor(manager): 引入 useTable 并重构采购/财务/会员等10个列表页
- 引入通用 useTable composable 实现分页与查询标准化
- 重构采购单/入库单/报损单/盘点单4个采购管理列表页
- 重构退款日志/预存款流水/会员充值/会员经验等财务与会员日志列表页
- 重构支付流水与退款流水列表页
- 统一竞态防护与 loading 状态管理,消除 150+ 行冗余样板代码
2026-10-20 14:02:03 +08:00
pikachu1995@126.com
8fd353a766 refactor(manager): 优化全局空状态、错误图片占位并升级遗留消息语法
- 增加表格与树组件全局空状态 (el-empty) 样式规范
- 补齐视图图片语义化 alt,并添加全局图片加载异常 SVG 占位兜底
- 将砍价/秒杀/自定义面板中的 $Message 兼容语法替换为 ElMessage
- 清理冗余依赖 vuex,将 sass-loader 调整至 devDependencies
2026-10-20 13:51:21 +08:00
pikachu1995@126.com
3cb60139d5 refactor(seller): 列表页抽离 useTable 重构与通用 UI 规范优化
- 抽离通用 useTable composable,并迁移 13 个典型列表页(采购/报损/订单/售后/统计/营销等)
- 增加表格与树组件全局空状态 (el-empty) 样式规范
- 补齐视图图片语义化 alt,并添加全局图片加载异常 SVG 占位兜底
- 替换遗留的 $Message 兼容语法为 ElMessage
- 将 WAP 店铺装修模板的 Options API 统一为 defineOptions
- 优化数据报表卡片视觉样式,并移除失效的品牌筛选选项
- 清理冗余依赖 vuex,将 sass-loader 调整至 devDependencies
2026-10-20 13:51:04 +08:00
pikachu1995@126.com
7d9bf776db feat(seller): 素材管理页重构布局并统一主色交互
- 双层卡片嵌套改为单面板,tabs 与操作按钮并入顶部工具栏
- 悬停/选中红色描边统一为 Element Plus 主色
- 复选框改为悬停/选中时显示,选中增加淡蓝遮罩
- 分组行编辑入口悬停显示,添加分组改为置顶虚线按钮
- 分页增加总数显示,空列表显示空状态
2026-10-20 13:42:46 +08:00
pikachu1995@126.com
0c814ec956 feat(seller): 系统消息页改为顶部 tab 筛选与卡片式列表
- 左侧菜单改为顶部 pill tab(未读带数量角标)
- 表格改为卡片列表:类型图标 + 标题加粗 + 内容摘要 + 时间操作
- 点击消息就地展开内容,去掉返回按钮
- 修复标为已读后错误刷新全量列表的问题
2026-10-20 13:42:37 +08:00
pikachu1995@126.com
322e357398 Merge branch 'feat/appointment-goods' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui into feat/appointment-goods 2026-10-15 10:04:53 +08:00
lifenlong
cc4a94da40 fix(seller): shopSetting tab 事件改为 @tab-click
上一笔只把判断改成了 pane.paneName,但 @click 对未声明该 emit 的 el-tabs
会退化为原生 DOM 点击(handler 收到 MouseEvent),仍不生效。
@tab-click 才是 Element Plus 的自定义事件,handler 能拿到 pane 对象。
2026-10-14 21:22:05 +08:00
lifenlong
36648f065b fix(seller): 清理直播商品页的悬空模板引用
liveGoods 是从 addLive 复制来的纯只读详情页(所有表单项均 disabled),
但模板残留了三个不存在的引用:date-picker 的 @change="handleChangeTime"、
el-form 的 :rules="liveRulesForm"、"保存"按钮的 @click="createLives()"
(点击会抛 is not a function)。只读页无需保存入口,移除上述引用及该按钮。
2026-10-14 21:14:07 +08:00
lifenlong
9893494cf1 fix(seller): 修复店员管理页部门筛选失效
clerkManage 中 department-choose 监听器写的是 @change,而组件实际 emit 的是
on-change(与同目录 department-tree-choose 的约定一致),导致搜索区的部门筛选
永不触发。改为 @on-change 后恢复联动。
2026-10-14 21:09:49 +08:00
lifenlong
906cda0385 fix(seller): 修复三处历史遗留的恒假条件
- coupon-receive: 路由监听中 couponId 判断取错了来源(实际应判断 query.couponId),
  导致优惠券列表页切换时永不刷新;changeSelect 中 getType 判断改为读表单值 searchForm.getType
- addLive: 添加直播商品时 roomId 取 route.query.roomId 恒为 undefined,改为页面实际参数 route.query.id
- shopSetting: tab 切换回调 v == "INFO" 恒为 false(Element Plus 传 pane 对象),
  改为读 pane.paneName,基本信息/退货地址 tab 的数据重载恢复正常
2026-10-14 21:06:44 +08:00
lifenlong
92dd179525 chore(seller): 清理死代码与失效机制,生产构建剥离 console
- 删除零引用组件 main-components/message-tip.vue
- 清理 113 处 no-unused-vars(重点 goodsOperationSec 20+ 项、ossManage 25 项,含死代码链级联删除;renovation 的 ModelForm 为 vue-eslint-parser 误报,保留并核实)
- stores/app.js 移除只写不读的死字段(currNavTitle/menuTheme/themeColor/isFullScreen/messageCount/currentPageName/currentPath)及失效的 cachePage/dontCache 缓存页机制(无 keep-alive 消费方),同步清理 util.js/App.vue/Main.vue/shrinkable-menu/tags-page-opened 的调用点
- 删除 30 处 console.log 调试残留;生产构建 terser 配置 drop_console 兜底
2026-10-14 20:31:25 +08:00
pikachu1995@126.com
fefb748864 merge: 合并远端 script setup + pinia 迁移,保留装修编辑器 CRMEB 化功能 2026-10-13 11:28:23 +08:00
pikachu1995@126.com
0b644a1722 feat(manager): 移动端装修编辑器 CRMEB 化迭代
- 轮播图:双 tab 面板(内容/样式)、轮播风格(通栏/卡片)、指示器样式/位置/色调、渐变背景、边距圆角
- 图片魔方:9 种风格收进样式 tab,拖入默认左一右二,内容 tab 固定槽位配置,新增颜色/边距/圆角设置
- 宫格导航:双 tab 面板,菜单管理 + 颜色/边距/圆角设置
- 编辑器整体:灰底卡片模块化、顶栏页面名称编辑、画布操作条/名称标签外置、组件列表三列通高卡片
- 预览模板同步应用各组件样式字段
2026-10-13 11:07:30 +08:00
lifenlong
2a2c3f8174 perf(seller): Element Plus 按需引入 + 移除未使用的 vue-lazyload
- plugins/element.js 不再全量注册,组件由 unplugin-vue-components 按模板自动按需解析;
  v-loading 指令与全局配置(zhCn/size)单独保留
- chunk-framework 344KB → 279KB(gzip,-19%);样式仍走全量 CSS 保证覆盖顺序不变
- 修复 unplugin-vue-components 与 minimatch 的版本兼容(锁定 0.27.5 + resolutions 嵌套 v9)
- 移除全局注册但零使用的 vue-lazyload
2026-10-13 07:39:35 +08:00
lifenlong
88fc1b0b2a refactor: 四端完成 Options API → script setup + vuex → pinia 迁移
- buyer(95) / seller(169) / im(53) / manager(280) 共 597 个组件全部从 Options API 转换为 <script setup>
- 四端 vuex 全部移除,状态管理统一迁移至 pinia 4(stores/ 目录)
- util.js 等基础设施去除 vm 首参依赖;全局属性($Message/$filters 等)在 script 内改为具名导入
- 被外部 ref 访问的公共组件均已补齐 defineExpose(清单见各端 MIGRATION-VUE3.md)
- 各端 eslint 启用 vue/component-api-style 防止新代码回退 Options API
- 四端 yarn build 全部通过;迁移约定与注意事项已更新至各端 MIGRATION-VUE3.md
2026-10-13 07:06:59 +08:00
pikachu1995@126.com
b45910a35f style(manager): 左侧组件列表合并为一张通高卡片 2026-10-12 16:29:15 +08:00
pikachu1995@126.com
758f09a291 style(manager): 楼层操作条图标调大 2026-10-12 16:28:15 +08:00
pikachu1995@126.com
fce063642d style(manager): 左侧组件列表按分组模块化卡片展示 2026-10-12 16:27:03 +08:00
pikachu1995@126.com
c832350dd3 style(manager): 装修页整体间距梳理,三列与顶栏留 12px 间隔 2026-10-12 16:25:17 +08:00
pikachu1995@126.com
5169d4ac43 style(manager): 装修页顶栏改为卡片模块,页面换浅灰底 2026-10-12 16:21:29 +08:00
pikachu1995@126.com
d80ead4d94 style(manager): 热区面板标题行加白色卡片底色 2026-10-12 16:19:12 +08:00
pikachu1995@126.com
62700162d5 feat(manager): 装修页左上角支持设置页面名称 2026-10-12 16:17:57 +08:00
pikachu1995@126.com
a568131b7c style(manager): 热区设置面板按模块卡片形式展示 2026-10-12 16:14:40 +08:00
pikachu1995@126.com
27ca53068b style(manager): 左侧组件列表改为一行三个 2026-10-12 16:10:47 +08:00
pikachu1995@126.com
1d946a9616 style(manager): 组件分组标题与楼层名称标签字号调大 2026-10-12 16:09:45 +08:00
pikachu1995@126.com
f31669cba6 style(manager): 楼层名称标签与操作条移至预览区外两侧 2026-10-12 16:07:18 +08:00
pikachu1995@126.com
005006adf7 style(manager): 画布移除 iPhone 边框背景,改为简洁屏幕容器 2026-10-12 16:02:07 +08:00
pikachu1995@126.com
2f097ace49 feat(manager): 画布楼层加名称标签与悬浮操作条
- 每楼层左上角显示组件名标签
- 选中楼层右侧竖排操作条:上移/下移/复制/删除/隐藏,替代原右上角关闭图标
- 隐藏楼层变暗并显示已隐藏蒙层,hidden 随 pageData 保存
2026-10-12 15:59:58 +08:00
pikachu1995@126.com
654839b247 style(manager): 选择照片/绘制热区按钮改默认尺寸、自然宽度 2026-10-12 15:49:52 +08:00
pikachu1995@126.com
8ed67847dd style(manager): 滑块旁数字输入框放大(去 small 尺寸,宽 130px) 2026-10-12 15:48:30 +08:00
pikachu1995@126.com
47974dddab chore(manager): 设置热区按钮改名绘制热区 2026-10-12 15:47:03 +08:00
pikachu1995@126.com
76cc10c6af style(manager): 热区面板标题与 tab 同行展示
- 面板契约新增 hideDecorateTitle 标记,面板可自行接管标题行
- tab 分段控件改为自然宽度,右对齐
2026-10-12 15:46:02 +08:00
pikachu1995@126.com
ae08a568bd style(manager): 保存页面按钮右间距调整为 2% 2026-10-12 15:43:02 +08:00
pikachu1995@126.com
2bb3a71460 style(manager): 热区面板 tab 切换改为分段控件样式 2026-10-12 15:41:59 +08:00
pikachu1995@126.com
ce03b13718 feat(manager): 热区组件配置面板重做为内容/样式双 tab
- 新增 PanelFlexOne:内容 tab(选图+设置热区,复用 ossManage 与 hotzone 编辑器),样式 tab(背景颜色/上下左右边距/页面间距/背景圆角/内容圆角)
- 注册进 panelMap 替换 flexOne 的通用老面板
- 画布预览 tpl_flex_one 应用相同样式字段,缺字段兜底保持原样
2026-10-12 15:38:25 +08:00
pikachu1995@126.com
0ad79157d3 feat(manager): 图片组件更名为热区 2026-10-12 15:26:19 +08:00
pikachu1995@126.com
bdae07e585 feat(manager): 图片组件选择模式只保留热区
- 移除链接/热区单选,新增图片组件默认 hotzone 直接进绘制热区
- 链接区标题随模式显示热区/选择链接
- 存量 link 数据不受影响(uniapp 端热区由 tpl_hot_zone 渲染;原生小程序暂无热区渲染,待补)
2026-10-12 15:25:14 +08:00
pikachu1995@126.com
7fa6c2d84c style(manager): 保存页面按钮右间距调整为 5% 2026-10-12 15:22:19 +08:00
pikachu1995@126.com
59bd1b8c78 style(manager): 保存模板改名保存页面并往左收 15% 2026-10-12 15:17:58 +08:00
pikachu1995@126.com
18eb79054f feat(manager): 移动端装修编辑器改为全屏独立页
- /floorList/main 移出 Main 布局注册为顶层路由,不再显示左侧菜单/header/标签栏
- 编辑器容器铺满全屏,右侧面板高度同步调整
- 顶栏左侧新增返回按钮(goBack 复用已有方法)
- 路径/name/query 不变,列表页 4 处跳转零改动
2026-10-12 15:13:48 +08:00
pikachu1995@126.com
b5047a7a7a chore(manager): 移除装修页顶栏的页面切换按钮
watcher 会按 pagetype 重置为单 tab,切换入口实际不可用,且 main.vue 已按路由直接定页面
2026-10-12 15:05:13 +08:00
pikachu1995@126.com
45b83d0fe4 style(manager): 优化组件面板卡片质感
- 白底圆角卡片 + 淡蓝图标底块,hover 浮起、图标反白、投影
- 组标题加蓝色竖条点缀
2026-10-12 15:03:00 +08:00
pikachu1995@126.com
a804120fa2 feat(manager): 组件面板改为图标+文字双列布局
- config.js 21 个面板条目新增 icon 字段(element-plus 图标)
- 面板 item 渲染 el-icon + 名称,替换死的 img 占位
- 面板容器改 grid 两列,卡片式样式含 hover 高亮
2026-10-12 14:59:47 +08:00
pikachu1995@126.com
ebbf42cb76 chore(manager): 移除装修页顶栏的店铺装修标题 2026-10-12 14:51:45 +08:00
pikachu1995@126.com
1e7e78a841 fix(manager): 修复楼层装修审查发现的问题
- PanelArticle 文章分类字段名改为后端的 articleCategoryName
- blank/line/richText 预览组件补默认值兜底,避免拼出 undefinedpx
- 画布未知组件渲染可点击删除的占位条并 console.warn
2026-10-12 11:01:19 +08:00
pikachu1995@126.com
350e79895d feat(manager): 新增店铺列表装修组件 2026-10-12 10:23:00 +08:00
pikachu1995@126.com
2bee689198 feat(manager): 新增文章列表装修组件 2026-10-12 10:21:40 +08:00
pikachu1995@126.com
de333c2d34 feat(manager): 新增优惠券装修组件 2026-10-12 10:19:52 +08:00
pikachu1995@126.com
0c7ecbe039 feat(manager): 新增积分商城装修组件 2026-10-12 10:18:18 +08:00
pikachu1995@126.com
7a1ae5d5da feat(manager): 新增富文本装修组件 2026-10-12 10:16:45 +08:00
pikachu1995@126.com
2bbec5b9e5 feat(manager): 新增辅助线装修组件 2026-10-12 10:15:08 +08:00
pikachu1995@126.com
b4d67859da feat(manager): 新增辅助空白装修组件 2026-10-12 10:13:59 +08:00
pikachu1995@126.com
15c229fa62 feat(manager): 装修右栏按type分发配置面板机制 2026-10-12 10:12:11 +08:00
pikachu1995@126.com
3278726a25 feat(manager): 装修组件面板三类分组,移除促销活动组件,画布对未知类型增加守卫 2026-10-12 10:10:22 +08:00
pikachu1995@126.com
5df1ab6993 feat(manager): 装修编辑器共享控件库 ColorField/SliderField/SegmentField 2026-10-12 10:05:11 +08:00
pikachu1995@126.com
870bacdd8c refactor(seller): 重构店铺详情页面并优化表格列宽度
- 调整售后订单和订单列表中会员ID列宽度从120到185
- 将主题色管理状态从待办改为已完成
- 重构店铺详情页面UI组件结构和样式
- 更新店铺详情页面为卡片式布局并添加标签页功能
- 优化店铺详情信息展示为描述列表形式
- 修改订单类型选项将赠品订单和拼团订单替换为电子卡券订单和预约服务订单
- 重命名退款退货相关组件和变量为售后相关命名
- 添加店员列表标签页展示店铺员工信息
- 实现空白值过滤工具函数处理空数据展示
- 更新页面默认激活标签页为基本信息页
2026-10-09 17:06:59 +08:00
pikachu1995@126.com
bbe336d902 fix(theme): 优化主题色设置功能并修复令牌刷新逻辑
- 移除楼层列表中的主题色设置按钮及路由
- 重构主题色设置页面,新增系统预设色系和自定义模式
- 添加移动端真实页面预览功能,支持商品详情和订单页面预览
- 优化商品详情页优惠券展示样式和布局
- 修复买家端API刷新令牌请求的拦截器递归死锁问题
- 添加无refreshToken时的刷新请求保护机制
2026-10-09 15:50:56 +08:00
pikachu1995@126.com
1bd50cee45 fix(buyer): 修复商品列表路由变化时重复请求
- $route watcher 中 handleSearch 与末尾兜底调用重叠,带 keyword 时同一请求发两次,改为互斥分支
- 修复从关键词搜索切换到分类/促销路由时 params.keyword 残留旧值的问题
2026-10-09 09:50:38 +08:00
pikachu1995@126.com
b639bc36eb fix(buyer): 结算页异常兜底与白屏防御
- 1 处裸 await 包 try/catch,12 条 .then 链全部补 catch(原仅 2 条)
- 结算数据加载失败给用户可见提示并保持页面可操作,不再白屏;错误提示与 request 层拦截器去重
- 约 20 处深链式访问加可选链/默认值(含模板渲染层)
- 修复无效商品跳回购物车后缺少 return 导致的 TypeError
2026-10-09 09:46:06 +08:00
pikachu1995@126.com
89711af0e6 chore(buyer): 落地 ESLint 9 并清理调试代码
- 新增 eslint.config.js(flat config, vue3-essential),移除废弃的 .eslintrc.js/.eslintignore(引用已废弃的 babel-eslint),package.json 增加 lint/lint:fix 脚本
- 清理 17 处调试 console.log;修复 24 处空 catch(15 处补 console.warn 业务提示,9 处加注释说明可安全忽略)
- 修复存量 lint error:9 处 prop 默认值改为函数形式、3 处未使用组件、1 处 v-if/v-for 同级、1 处空 else
- vue.config.js 生产环境 terser 开启 drop_console 兜底
2026-10-09 09:45:59 +08:00
pikachu1995@126.com
3ec3f11d5b chore(seller): yarn.lock 入库,锁定依赖版本 2026-10-08 15:24:26 +08:00
pikachu1995@126.com
5fcc26a866 refactor(seller): 商家端系统性优化与 Vue3 迁移遗留问题修复
- 清理:删除 4 个未使用依赖、约 2700 行死代码(shop/ossManage 等)、tree-table 死组件、37 处未使用 import
- ESLint 9 flat config 升级(.eslintrc.js -> eslint.config.js),修复迁移遗留的 34 处真实 bug
- axios 重构:拦截器不再吞错、refreshToken 单例共享 Promise、超时收敛、form 序列化抽公共函数、vue-router 4 失效 API 修正
- 安全:4 处 v-html 增加 xss 过滤;logout 改为精确删除 localStorage 键
- API 重复定义收敛(delSpec/insertOrUpdateSpec、getDictData、ws)
- 首屏瘦身:tinymce 懒加载(约省 7.4MB)、core-js 按需 polyfill、vendor chunk 合并、dplayer/@antv/g2 动态 import、3 张大图压缩
- 页面修复:发布商品表单布局(iview 遗留 margin 移除)、beforeVideoUpload 补定义、el-tag type 空值、lili-dialog emits 声明、消息中心布局塌陷修复与样式重构、department-choose 空值、affix-time 不再发多余店铺请求、goods/distributionGoods 去掉品牌筛选
2026-10-08 15:22:56 +08:00
pikachu1995@126.com
8484936e3d refactor(axios): 优化HTTP请求拦截器和错误处理机制
- 移除调试用的console.log语句
- 调整表格列对齐方式,将操作列从居中改为右对齐
- 添加搜索表单功能,包括账单号、店铺名称、生成时间等筛选条件
- 重构axios拦截器逻辑,简化错误处理流程
- 实现统一的token刷新机制,使用单例模式避免重复请求
- 优化防抖函数实现,提高性能表现
- 添加401和403状态码的特殊处理逻辑
- 统一错误提示信息的显示方式
- 优化表格列宽度设置,调整金额相关列的显示效果
- 删除未使用的组件文件和样式代码
- 移除调试相关的代码和注释
- 优化图标组件的导入方式,使用markRaw包装
- 优化热词统计图表的数据显示逻辑,添加空数据提示
2026-10-08 14:39:12 +08:00
pikachu1995@126.com
1b275cf592 perf(image): 优化图片加载性能
- 为所有商品图片添加 loading="lazy" 属性实现懒加载
- 为所有图片元素添加 decoding="async" 属性实现异步解码
- 优化购物车页面的商品缩略图加载方式
- 改进订单中心各页面的图片加载策略
- 提升评价系统中图片的加载性能
- 优化会员中心收藏和足迹功能的图片加载
- 改善促销活动页面的图片加载体验
- 更新首页装饰组件中的图片加载属性
- 提高地址管理页面的界面展示效果
2026-10-08 14:36:22 +08:00
pikachu1995@126.com
4c232284f8 feat(goods, order): 完善预约与订单详情功能
- 预约规则区域的说明中补充可预约时段
- 价格区域的标题和说明改为根据商品类型动态展示
- 优化订单详情中配送信息的展示,仅在实物订单中显示
- 核销记录新增搜索功能,支持按商品名称和核销人筛选
- 精简订单列表搜索表单,移除不必要的字段,界面更简洁
2026-10-02 15:28:25 +08:00
pikachu1995@126.com
326ccea1b4 feat(router, appointment, procurement): 完善功能并优化界面
- 新增采购订单列表路由
- 预约工单列表新增状态筛选,搜索更方便
- 首页新增未完成预约工单和待审核采购的提醒
- 优化多个组件的样式与布局,提升用户体验和全站一致性
2026-10-02 15:27:52 +08:00
pikachu1995@126.com
8410179885 feat(buyer): 增强搜索功能并提升用户体验
- 新增 `getStoreById` 接口方法,用于获取包含评分在内的店铺信息
- `Search.vue` 新增搜索建议面板,展示搜索历史和热词,优化搜索体验
- 新增 `SearchSuggest.vue` 组件,用于展示搜索建议和搜索历史
- `App.vue` 根据路由元信息按条件设置页面标题
- 优化多个组件的布局与样式,让整体风格更统一
- 重构多个组件的跳转逻辑,改用路由跳转(`router.push`)替代新开窗口(`window.open`),提升用户体验
2026-10-02 15:26:58 +08:00
pikachu1995@126.com
4777eb2dd6 feat(buyer): 新增功能并优化样式,提升用户体验
- 新增 `getMemberMessage` 接口方法,用于获取会员消息
- 调整全局及商品列表样式,提升可读性与一致性
- 精简 `Search.vue`,移除不必要的店铺搜索切换
- 放宽 `addressManage` 中地址别名的输入长度
- 优化 `ShowGoods.vue` 和 `ShowGoodsDetail.vue` 的布局与样式
- 更新 `Cart.vue` 中的购物车步骤展示,让流程导航更清晰
- 调整多个组件,统一字号并优化界面元素
2026-09-29 18:11:31 +08:00
pikachu1995@126.com
867b03ebfc refactor(buyer): 优化组件结构并提升用户体验
- Main.vue 路由逻辑改为使用当前路由信息
- 简化 Header.vue 中的购物车展示,优化布局与可访问性
- GoodsClassNav.vue 改为按条件渲染分类信息
- 完善 MyOrder.vue 的订单展示与交互,优化样式与结构
- 调整 message.js,更稳妥地处理 Promise 拒绝

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-29 10:48:44 +08:00
pikachu1995@126.com
a6063874c7 Merge branch 'master' into feat/appointment-goods 2026-09-28 14:25:59 +08:00
pikachu1995@126.com
037fd0caa0 refactor(goods): 重构商品管理模块的API接口和页面结构
- 移除manager端的预约改期日志相关API接口
- 移除seller端的预约改期相关API接口
- 更新seller端API请求方法,将putRequest替换为putRequestWithNoForm
- 修改服务人员更新接口,使用POST方式并传入ID参数
- 重构seller端商品搜索表单,增加SKU名称、SKU货号、店铺分类等搜索条件
- 新增商品创建时间范围选择器和库存状态筛选功能
- 优化商品表格列结构,调整销售模式与商品类型显示逻辑
- 添加商品复制功能按钮
- 重构manager端商品详情页面,实现新的详情展示布局
- 新增商品审核弹窗和时段可约数量抽屉组件
- 优化商品详情页的商品参数展示逻辑
- 添加预约商品相关的特殊处理逻辑
2026-09-28 14:24:24 +08:00
田香琪
ea897b154b Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2026-09-24 17:49:09 +08:00
田香琪
54c72239d4 refactor(page-decoration): 用 beforeRelease 替换发布开关逻辑
- 楼层与移动端装修列表改用 before-change,避免开关被直接切换
- 唯一页面禁止关闭,已开启页面提示改开其他页
- 按接口成功/失败再决定是否切换开关
2026-09-24 17:45:46 +08:00
pikachu1995@126.com
1bad9a14db feat(appointment): 预约商品发布改为可视化配置,并接入表单设计器
商家端补齐预约规则、时段库存与系统表单设计;运营端增加预约工单与订单设置。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 17:06:16 +08:00
pikachu1995@126.com
50ebc7d6df refactor(buyer): 移除 PC 商城分销推荐入口与相关接口
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 09:55:20 +08:00
田香琪
ff38cf52b4 feat(distribution): 添加自动申请模式提示信息 2026-09-18 17:50:34 +08:00
Ryan Ran
2fdab71d14 fix(manager): 钉住 webpack 5.108.4,修复生产构建 $filters 全部报错
webpack 5.108.0 回归(webpack/webpack#21278):生产构建在 mangleExports 下遇到 namespace import 整体逃逸(app.config.globalProperties.$filters = filters)时,会把混淆后的导出名当属性路径渲染(u6 -> .u[6]),导致 $filters.unitPrice 等全部报 Cannot read properties of undefined (reading '6');dev server 不启用 mangleExports,本地无法复现。

- manager:webpack 固定 5.108.4(devDependencies + resolutions),pnpm-lock 同步更新
- buyer:纳入 pnpm-lock.yaml(webpack 5.111.0)

Refs: https://github.com/webpack/webpack/issues/21278
2026-09-18 11:29:18 +08:00
田香琪
b51148f520 Merge branch 'fix/distribution-statistics-v2-empty-date' 2026-09-15 10:43:26 +08:00
田香琪
87db9dbb12 Merge branch 'fix/featured-goods-display-count-limit' 2026-09-15 10:24:45 +08:00
田香琪
fb979ea514 feat(distribution): 增强主推商品选择功能与同步逻辑
- 添加 row-key 属性以优化表格行选择
- 引入 featuredPickerDraft 用于临时存储选择的商品
- 实现同步选择逻辑,确保用户在选择商品时状态一致
- 更新确认逻辑,确保用户选择的商品数量不超过限制
- 优化用户交互体验,提升选择反馈
2026-09-15 10:24:12 +08:00
田香琪
8d18f05085 feat(login): 增强扫码登录功能与会话管理
- 登录接口增加 loading 与超时配置,改善请求体验
- 根据服务端返回处理二维码过期,并动态设置有效时长
- 重构二维码刷新逻辑,改用 setTimeout 控制过期
- 合并会话管理与错误处理,简化扫码登录流程
- 移除多余 watch,精简组件行为
2026-09-15 09:46:45 +08:00
田香琪
dfb790e713 refactor(distribution): 移除不必要的时间参数构建逻辑
- 删除 buildQueryParams 方法及相关的 startTime 和 endTime 参数,简化数据查询逻辑
- 更新 loadOverviewData 和 loadBehavior 方法,直接调用 getDistributionOverviewV2,无需构建额外的查询参数
- 优化代码结构,提高可读性和维护性
2026-09-13 17:06:41 +08:00
田香琪
62d55e2b92 feat(distribution): 添加主推商品数量设置与超限提示
- 新增主推商品数量选择功能,用户可选择显示5个或10个商品
- 增加超限提示,确保用户在自定义商品选择时不超过限制
- 更新相关描述信息,提升用户体验与交互反馈
2026-09-13 10:06:33 +08:00
田香琪
f4a50cd854 refactor(distribution): 更新分销资格提示与申诉逻辑
- 修改分销资格被清退的提示信息,明确只可通过后台恢复,不再提供申诉功能
- 移除申诉相关的逻辑与按钮,简化用户交互
- 调整状态管理,去除不再使用的申诉状态
2026-09-09 15:21:07 +08:00
田香琪
47a2c40ffd feat(distribution): 添加百分比与分数转换功能
- 新增 toPercent 和 toFraction 函数,分别用于将小数转换为百分比和将百分比转换为小数
- 更新 distributionGrade.vue 中的佣金率处理逻辑,确保数据在保存和展示时正确转换
- 修改 distributionGradeHistory.vue 中的百分比显示逻辑,确保格式一致性
2026-09-07 11:12:55 +08:00
田香琪
fddb82e680 refactor(GoodsClassNav): 优化品牌ID处理与选择逻辑
- 重构品牌ID的获取方式,使用新方法 appendBrandIdsByNames 简化逻辑
- 更新多选确认逻辑,避免重复选择相同类型
- 调整标签内容显示逻辑,确保品牌标签在选择时正确显示
- 修复商品列表页的分页参数,确保从第一页开始加载数据
2026-09-03 17:17:11 +08:00
田香琪
2d80a795a7 feat(goodsOperation): 完善商品发布流程与分类选择界面
- 引入商品类型选择对话框,增强用户体验
- 重新组织商品发布步骤,优化步骤指示器
- 更新商品分类选择逻辑,确保用户选择到三级分类
- 调整数据传递与状态管理,支持商品编辑与复制功能
- 优化样式与布局,提高界面可用性
2026-08-27 17:48:16 +08:00
田香琪
ffdae4a332 refactor(renovation): 重构页面数据处理逻辑
- 将页面数据处理逻辑提取到 applyPageData 方法中,简化 onOk 和 getTemplateItem 方法
- 增强数据解析和错误处理,确保在无数据或解析失败时正确初始化 modelForm
- 优化对 topAdvert 类型的处理逻辑,提高代码可读性和维护性
2026-08-25 10:46:44 +08:00
田香琪
3ca9aad9be feat(editor): 增强 TinyMCE 编辑器功能与内容同步
- 提交前同步 PC 与移动端编辑器内容
- 增加编辑器未初始化时的待写入内容处理
- 优化内容读写方法,保证数据绑定准确
- 重构事件处理,避免初始化时覆盖 v-model 值
2026-08-24 12:46:39 +08:00
田香琪
085674dfa7 fix: 修复入驻误校验与商品品牌显示 0,并优化分类、运费模板交互
- 入驻第三步改为先回填再渲染,避免空字段进页即提示
- 入驻协议无内容时按空字符串处理,避免读取 null
- 商品品牌空值展示占位符,提交时再转为 0
- 店内分类为空时横向展示「暂无分类」
- 运费模板选择地址默认折叠,操作文案改为「选择地址」
2026-08-20 16:55:05 +08:00
田香琪
9540a1b98b refactor(goodsOperationSec): 优化批发规则表单与预览展示
- 调整批发规则表单的样式与结构,增强可读性
- 更新批发规则预览逻辑,确保信息准确展示
- 增加样式类以改善用户体验,确保输入框与按钮布局合理
2026-08-17 12:57:58 +08:00
田香琪
b9d48fab05 为保持开发环境一致性,将管理端与商家端的 API 基础地址均从 localhost 修改为生产环境地址。
说明:
fix(config):配置类修复,保留 git commit 前缀规范
manager:管理端
seller:商家端
localhost:本地地址
2026-08-17 11:18:08 +08:00
田香琪
6552767823 Merge branch 'salesman' 2026-08-17 11:05:22 +08:00
田香琪
f42f5903d3 fix(userManage): 提交前对密码进行 MD5 加密
- 用户管理表单在注册或更新用户时,先将密码 MD5 加密后再提交服务端,提升密码传输安全性
2026-08-13 19:20:08 +08:00
田香琪
0c94b67ad9 Merge branch 'feature/order-delivery-fulfillment' 2026-08-13 17:19:53 +08:00
田香琪
3b665f6d8c feat(orderFulfill): 增强订单发货逻辑与界面
- 新增无需配送场景及发货模式相关工具函数
- 更新订单详情与订单管理页,支持整单发货、分包裹发货、无需配送
- 优化物流信息与订单日志展示
- 重构订单发货 API 以适配新逻辑
- 增强订单列表与详情页的发货选项与操作展示
2026-08-13 17:19:06 +08:00
田香琪
420e8a84e5 fix(goodsOperationSec): 修复商品编辑页店内分类无法回填的问题
- 初始化店内分类 ID 列表时过滤空值
- 分类树数据加载完成后调用 setCheckedKeys 回填勾选状态
- 使用 const 声明 shopCategories 提升可读性
2026-08-13 16:37:52 +08:00
pikachu1995@126.com
05b14ada18 fix(promotion): 打开商品选择器前先初始化已选 SKU 列表
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-11 15:35:34 +08:00
pikachu1995@126.com
aed9d86ada Merge branch 'master' into salesman 2026-08-11 15:34:46 +08:00
pikachu1995@126.com
6933fb79ec feat(distribution): 优化分销提现页面功能
fix(setting): 更新海报和邀请卡背景图尺寸说明
style(table): 统一全局表格表头样式
refactor(home): 优化首页待办事项点击跳转
refactor(main): 优化主布局侧边栏收起动画
chore(menu): 优化菜单导航结构
docs(readme): 更新项目文档信息
feat(task): 新增定时任务管理页面
2026-08-11 15:16:32 +08:00
pikachu1995@126.com
4be36d61c7 增加二级分销相关设置以及页面 2026-08-05 18:03:45 +08:00
田香琪
d4cd6e0936 feat(buyer): 增强商品详情与支付逻辑
- 引入 buyerLogin 工具,优化商品详情页的链接跳转逻辑,确保未登录用户能正确重定向到登录页面
- 更新商品 SKU 详情 API,支持未登录状态下的访问
- 修改支付 API,新增 skipMessage 参数以控制支付提示信息
- 改进商品列表与支付页面的用户体验,确保更流畅的操作流程
- 规范化商品类型与库存提示,提升用户体验
2026-08-05 14:17:39 +08:00
田香琪
c0b00999c5 refactor(goodsType): 删除冗余的 promotionPriceMin 函数定义
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-03 16:13:01 +08:00
田香琪
1accdf5826 feat(buyer): 更新电子卡券(E_COUPON)相关逻辑与展示
- 优化购物车与支付页面,确保电子卡券只能通过立即购买结算
- 增强商品详情页,添加限时折扣与第N件优惠展示
- 更新促销逻辑,支持拼团与积分购买选项
- 规范化商品类型与库存提示,提升用户体验
2026-08-02 13:55:19 +08:00
田香琪
1ae7ab3036 feat(buyer): 添加电子卡券(E_COUPON)支持
- 新增 E_COUPON 商品类型,支持电子卡券的展示与购买逻辑
- 优化商品详情页,调整促销、库存和购买按钮逻辑以适应电子卡券
- 增加卡密信息展示与管理功能,支持商家端卡池管理
- 更新相关页面以处理电子卡券的特殊逻辑,如免地址、隐藏优惠券等
2026-07-31 13:44:56 +08:00
田香琪
36878e6f7f Merge branch 'fix/promotion-datetime-format' 2026-07-28 10:30:44 +08:00
田香琪
09b735e82a feat(buyer): 增加短信验证码发送状态管理
- 新增 codeSent 状态以跟踪短信验证码是否已发送
- 在登录流程中添加验证,确保用户完成安全验证和获取验证码
- 优化验证码发送逻辑,确保用户体验
2026-07-28 10:29:14 +08:00
pikachu1995@126.com
24f829033f Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2026-07-23 09:30:26 +08:00
pikachu1995@126.com
a72ff640cc feat(ossManage): 进行商家 素材管理 功能改造与界面优化 2026-07-23 09:29:47 +08:00
田香琪
68a791a439 Merge branch 'fix/im-vue3-migration' 2026-07-22 18:10:04 +08:00
田香琪
c0ca9672a1 fix(buyer): 未登录联系客服时提示登录
- 将登录提示由 Message 改为 Modal
- 新增 promptLogin 方法处理登录跳转
- IMService 增加 accessToken 校验,未登录时提示登录
- 改进用户信息获取的错误处理
- 重构 IM 链接 URL 拼接,提升可读性
2026-07-22 18:08:42 +08:00
pikachu1995@126.com
6ee49ce9ac feat:优化店铺管理相关功能并进行界面改造 2026-07-22 17:52:11 +08:00
pikachu1995@126.com
c83d715234 feat (router): 新增采购详情路由,优化预警数量管理功能
在管理员模块与商家模块中新增采购详情页面路由。
升级预警数量管理组件,优化交互体验与功能逻辑。
2026-07-22 15:52:15 +08:00
田香琪
4bcaf14bad fix(im): 迁移 Element UI 图标并修复 Vue 3 兼容问题
- 新增 migrate-legacy-icons 脚本,批量将旧图标替换为 legacy-el-icon 组件
- 多个组件中将 <i class="el-icon-*"> 统一改为 <legacy-el-icon name="el-icon-*">
- 将 size="mini"/"medium" 调整为 Element Plus 的 small/default
- 新增 legacy-el-icon 全局组件及图标映射逻辑
2026-07-22 13:36:44 +08:00
pikachu1995@126.com
e91d783e22 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2026-07-21 18:46:39 +08:00
pikachu1995@126.com
4bb3d33f89 fix: 复选框的值双向绑定,并补充 tbody 标签,保证表格结构规范统一 2026-07-21 18:46:33 +08:00
田香琪
12291ad4d5 feat(invoiceModal): 发票弹窗组件新增 change 事件
- 在发票弹窗中增加 change 事件 emit,便于父组件监听数据变化
- 优化 coupon-publish 组件的 selectedMember、selectedList 绑定,完善会员选择功能
2026-07-21 17:01:38 +08:00
田香琪
829d3e65e7 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2026-07-21 13:29:47 +08:00
pikachu1995@126.com
3be9aa5c14 feat(statistics): 添加店铺业绩、商品同比环比、销售订单明细及商品销售汇总报表视图和相关 API 接口 2026-07-20 15:31:41 +08:00
pikachu1995@126.com
6c9a3820e8 feat(statistics): 添加统计模块及相关视图 2026-07-20 09:10:56 +08:00
田香琪
d172a1c9b8 fix(cart): 调整错误提示展示并优化已下架商品遮罩样式
简化 Cart.vue 中错误文案展示,移除多余 margin
优化 error-goods 样式:使用 inset 定位,并通过 box-sizing 管理 padding,改善布局与响应表现
2026-07-17 17:35:42 +08:00
田香琪
59c98d1289 chore(config): 更新开发环境的 API 基础地址
将 manager 与 seller 配置中的 API 基础地址由本地开发地址改为生产地址,以统一各环境配置。
2026-07-17 11:46:56 +08:00
田香琪
b7235f5644 refactor(orderDetail): 迁移 UI 组件并优化订单信息展示
将 Card、Button 等组件替换为 el-card、el-button,与 Element Plus 保持一致
优化订单信息展示,补充备注缺省值,并改进发票信息处理
根据订单类型与可操作权限调整按钮显示条件
2026-07-17 11:11:23 +08:00
田香琪
9dc4829f1f fix(buyer): 解决 Profile.vue 合并冲突标记导致的编译错误
保留 getMemberMsg 安全加载用户信息逻辑,并统一使用 buyerUrl 上传接口。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-16 21:13:06 +08:00
田香琪
843134c82a Merge branch 'vue3' 2026-07-16 16:56:45 +08:00
田香琪
7e87214b6d refactor: 移除未使用的商品规格相关 API 接口与组件,优化用户管理与物流功能
- 删除了与商品规格相关的 API 接口和组件,简化代码结构。
- 更新用户管理功能,确保表单字段与验证规则一致。
- 优化物流添加与编辑功能,确保请求参数的正确性与一致性。
2026-07-16 16:52:55 +08:00
田香琪
192a9ca53f fix(manager): 解决 util.js 合并冲突标记导致的编译错误 2026-07-15 17:07:46 +08:00
田香琪
1df821aa0c Merge branch 'vue3' 2026-07-15 16:50:18 +08:00
田香琪
3e3644f4a4 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2026-07-15 16:40:44 +08:00
田香琪
b1f62d599b feat(manager): 增强运营后台表单校验与页面体验
- 富文本编辑器支持 Vue3 modelValue 双向绑定
- 补充 lazyLoading 路径别名,跳过已弃用的分销等级菜单
- 完善文章、优惠券活动、砍价活动、商品参数等表单校验
- 修复文章管理布局遮挡、店铺选会员弹窗及操作列分隔符显示问题

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-15 16:39:10 +08:00
chc
4e0ee8e899 移除直播中控台消息发送按钮 2026-07-15 13:48:30 +08:00
田香琪
7804d4eba6 refactor: 移除已弃用的商品规格相关 API 接口与菜单路由检查 2026-07-15 11:03:45 +08:00
田香琪
1fa3a91979 解决 Profile.vue 合并冲突,同步master代码 2026-07-14 16:45:10 +08:00
pikachu1995@126.com
29d5ba98ff Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2026-07-13 17:38:20 +08:00
pikachu1995@126.com
c25c16adf3 替换登录背景图 2026-07-13 17:38:17 +08:00
chc
de9bf1902a Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2026-07-13 17:37:22 +08:00
chc
f2ec4530ed 直播功能完善提交 2026-07-13 17:37:10 +08:00
pikachu1995@126.com
7bbcab7679 feat: 更新 API 路径与文档 2026-07-13 17:36:11 +08:00
pikachu1995@126.com
f646022926 Merge branch 'vue3' 2026-07-13 16:56:36 +08:00
pikachu1995@126.com
f6037dc18b refactor: 更新 README 文档与后端服务配置 2026-07-13 16:49:49 +08:00
pikachu1995@126.com
29acc7f0ee Merge branch 'vue3' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui into vue3 2026-07-13 16:48:47 +08:00
chc
5ef5adf9be Merge branch 'vue3' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2026-07-13 15:28:32 +08:00
chc
9647e7614b 直播功能补充提交 2026-07-13 15:26:56 +08:00
pikachu1995@126.com
fb7c0c9ca2 refactor: 更新文件上传路径配置
- 将文件上传路径从 commonUrl 更新为 sellerUrl,确保 API 请求的正确性。
2026-07-13 14:32:34 +08:00
pikachu1995@126.com
0002a39fc4 Merge branch 'vue3' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui into vue3 2026-07-13 14:32:20 +08:00
pikachu1995@126.com
e67ea56651 refactor: 更新 API 请求路径与配置 2026-07-13 14:30:09 +08:00
田香琪
4cd96980ba Merge branch 'fix-vue3-left-bug' 2026-07-10 13:32:53 +08:00
田香琪
d648855533 feat: 增强用户登录体验与组件逻辑优化
- 在多个组件中添加用户登录状态检查,确保用户在进行特定操作前已登录。
- 更新购物车、消息中心等组件的点击事件,未登录时提示用户登录。
- 优化优惠券领取逻辑,未登录时引导用户登录。
- 调整样式以提升组件一致性,确保用户界面友好。
2026-07-10 13:31:14 +08:00
田香琪
9bed373ec1 Merge branch 'fix-vue3-left-bug' 2026-07-09 17:59:19 +08:00
田香琪
c355194aba feat: 优化商品详情与购物车功能
- 更新 ShowGoods.vue 和 ShowGoodsDetail.vue 中的按钮样式,统一使用 goods-action-btn 类。
- 在 Cart.vue 中实现商品收藏状态的同步与处理,优化收藏功能的用户体验。
- 调整 GoodsDetail.vue 中的店铺收藏按钮样式,提升视觉一致性。
- 在多个评价组件中引入主题色,增强评分组件的视觉效果。
2026-07-09 17:58:01 +08:00
田香琪
15fa1a5e52 Merge branch 'vue3' 2026-07-09 11:03:16 +08:00
田香琪
ecf11ae2d2 feat: 添加直播间推荐功能与视频上传优化
- 在 promotion.js 中新增 whetherStar 函数,用于更新直播间推荐状态。
- 在 goodsOperationSec.vue 中优化视频上传组件的样式与逻辑,增加视频删除功能。
- 在 live.vue 中集成 whetherStar 函数,优化直播间推荐状态切换逻辑。
2026-07-09 10:49:55 +08:00
田香琪
fb2a9e7a9f feat: 添加图标映射功能
- 新增 iconMap.js 文件,集中管理应用中的图标资源。
- 提供 getIconUrl 函数以便根据名称获取对应图标的 URL,提升代码可维护性。
2026-07-08 18:37:20 +08:00
田香琪
106e059d1a refactor: 统一组件导入与消息提示方式
- 将多个组件中的 require 替换为 import,提升代码一致性。
- 更新消息提示方式,使用统一的 Message 和 Modal 组件,增强用户体验。
- 调整部分组件的样式和逻辑,确保界面一致性与可读性。
2026-07-08 18:36:06 +08:00
田香琪
f6ddcf4f99 Merge branch 'vue3' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui into vue3 2026-07-08 16:23:15 +08:00
田香琪
a4659ed1a2 refactor: 统一组件导入方式与样式调整
- 将多个组件中的 require 替换为 import,提升代码一致性。
- 更新上传组件中的回调函数,简化图片选择逻辑。
- 调整样式以适配 Element Plus 组件,确保界面一致性。
- 删除不再使用的样式,优化项目结构。
2026-07-08 16:22:44 +08:00
pikachu1995@126.com
c90559981e Merge branch 'vue3' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui into vue3 2026-07-08 09:59:08 +08:00
pikachu1995@126.com
b299507df9 feat: 更新登录页面与底部信息展示 2026-07-08 09:56:25 +08:00
田香琪
cf92d9d939 Merge branch 'vue3' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui into vue3 2026-07-07 19:51:17 +08:00
田香琪
6b61b86585 feat: 优化组件导入与样式调整
- 在多个组件中将 require 替换为 import,提升代码可读性和一致性。
- 在 App.vue 中添加分类树的 API 请求,优化分类数据的加载逻辑。
- 更新样式以适配 Element Plus 组件,确保界面一致性。
- 删除不再使用的样式文件,简化项目结构。
2026-07-07 19:50:07 +08:00
Ryan Ran
ae896ff42c Merge branch 'vue3' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui into vue3 2026-07-07 16:40:19 +08:00
Ryan Ran
709d114986 feat: 添加直播聊天功能与相关配置
- 在 LiveChatPanel.vue 中实现直播间聊天功能,支持发送和接收消息。
- 新增 useChat.js 组合式 API,管理聊天逻辑与状态。
- 更新 Live.vue 控制面板,集成聊天组件并优化直播状态显示。
- 更新 package.json 和 pnpm-lock.yaml,添加 @tencentcloud/chat 和 hls.js 依赖。
2026-07-07 16:40:09 +08:00
pikachu1995@126.com
cc86430ea4 Merge branch 'vue3' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui into vue3 2026-07-07 10:56:17 +08:00
pikachu1995@126.com
295aaf1a01 feat: 添加主题色设置功能 2026-07-07 10:56:14 +08:00
田香琪
548335b658 feat: 优化售后服务页面与上传组件
- 在 AfterSaleDetail.vue 中添加样式以增强商品信息展示的可读性。
- 在 ApplyAfterSale.vue 中更新选择原因的下拉框,确保与服务类型关联。
- 在多个上传组件中添加图片选择与确认功能,提升用户体验。
- 在订单投诉与退款页面中调整表格列宽,确保信息展示的清晰性。
2026-07-07 10:38:59 +08:00
pikachu1995@126.com
df35a26f9e Merge branch 'vue3' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui into vue3 2026-07-07 09:40:52 +08:00
pikachu1995@126.com
c277cf1121 feat: 新增视频组件及配置功能
- 在 config.js 中添加视频类型配置,支持视频上传和样式设置。
- 创建 video-config.vue 组件,提供视频内容和样式的配置选项。
- 更新 decorate.vue 以支持视频类型的渲染和配置。
2026-07-07 09:39:00 +08:00
田香琪
297bdd95dd feat: 更新 API 请求参数与组件样式优化
- 在 account.js 和 member.js 中添加 loading 和 skipMessage 参数,提升 API 调用的用户体验。
- 在 ShowGoods.vue 中优化商品详情展示样式,增强可读性和交互性。
- 在 Cart.vue 中重构购物车商品列表结构,提升布局一致性。
- 在多个页面中修复了提示信息的内容,确保用户操作的清晰反馈。
2026-07-06 16:33:21 +08:00
pikachu1995@126.com
e13ca6281d feat: 更新登录页面与API逻辑 2026-07-06 15:59:14 +08:00
chc
235362d5b0 Merge branch 'vue3' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui into vue3 2026-07-06 14:48:47 +08:00
chc
fc5fb3832d 直播功能菜单调整 2026-07-06 14:48:40 +08:00
田香琪
bd9a5f75b0 fix: 增强错误处理与组件逻辑优化
- 在 App.vue 中添加 JSON 解析错误处理,确保站点信息获取的稳定性。
- 更新多个 API 请求,添加 loading 状态管理,提升用户体验。
- 在 Search.vue 中优化热词列表的解析逻辑,增强容错性。
- 改进购物车、地址管理等 API 请求参数,确保一致性与可用性。
- 新增用户中心布局组件,提升用户界面的一致性与可读性。
2026-07-03 18:29:41 +08:00
田香琪
99de0d4722 style: 更新短信设置页面样式以增强可读性和一致性
- 将 .card 类名更改为 .sms-setting-card,以更好地描述其功能。
- 移除不必要的样式定义,简化代码结构。
2026-07-01 17:30:33 +08:00
田香琪
726d563e1a style: 更新首页样式以增强布局和响应式表现
- 调整了 .flow-list、.flow-item 和 .today-item 的样式,优化了布局和间距。
- 增加了 .flow-box 和 .today-box 的 padding 和 flex 属性,提升了视觉一致性。
- 更新了 .today-list 的布局,确保更好的响应式设计。
- 修复了 .today-item 的样式,确保内容在不同屏幕尺寸下的可读性。
2026-07-01 17:00:30 +08:00
田香琪
7ce1ea8fa4 fix: 修复 formatPrice 对空值和非数字价格的处理
避免表格调用 unitPrice 时因 price 为 undefined/null/非法字符串导致报错。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 15:09:05 +08:00
田香琪
2e5be29a43 feat: 新增消息模板聚合接口及通知类站内信邮箱状态更新功能
- 在 setting.js 中添加了消息模板聚合分页接口和更新通知类站内信邮箱渠道开关的功能。
- 在 axios.js 中重构了 token 刷新和登录重定向逻辑,避免循环依赖。
- 新增 router-holder.js 文件以延迟持有 router 实例,优化依赖管理。
- 更新 util.js 中的动态路由管理逻辑,确保在无 router 实例时不执行相关操作。
2026-07-01 11:41:49 +08:00
chc
ac77acd888 快递鸟电子面单不进入打印页面 2026-07-01 10:39:54 +08:00
田香琪
f4b17254ec Merge branch 'vue3' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui into vue3 2026-06-30 21:10:06 +08:00
田香琪
28a857249a refactor: 重构组件逻辑与样式优化
- 在 App.vue 中重构站点信息的获取与应用逻辑,提升代码可读性与维护性。
- 更新 Search.vue 组件,优化搜索框的样式与结构,增强用户体验。
- 在 element.scss 中注释掉不再使用的样式,并新增确认收货按钮的样式。
- 改进多个页面的布局与样式,确保响应式设计的一致性与美观性。
- 更新订单相关组件的按钮样式,提升视觉一致性与可用性。
2026-06-30 21:09:28 +08:00
chc
22f7b1a343 腾讯云直播 2026-06-29 11:31:29 +08:00
田香琪
ec948b5496 feat: 增强组件功能与样式优化
- 在多个组件中添加了新的属性和方法以提升功能性,如在卡片组件中引入 _ActiveTab 属性以管理活动标签。
- 优化了商品详情和商户页面的收藏逻辑,确保在未登录状态下引导用户登录。
- 更新了轮播组件的路由解析逻辑,增强了用户体验。
- 改进了投诉列表和收藏列表的样式,提升了响应式布局和可读性。
- 在全局配置中添加了对开发环境的错误处理,提升了调试体验。
2026-06-25 16:52:46 +08:00
田香琪
1b2e980fb6 fix: 更新 API 请求参数格式及优化组件样式
- 将 addEvaluation API 的参数从 params 修改为 data,以符合标准请求格式
- 在多个组件中调整样式,提升响应式布局和用户体验
- 优化商品详情页的倒计时显示,增强视觉效果
- 更新购物车操作按钮样式,提升一致性和可用性
2026-06-23 14:13:25 +08:00
田香琪
8a60e23214 feat: 新增全局布局样式并提升组件响应式表现
- 在 global-layout.scss 中引入全局布局样式,统一页面宽度与对齐方式
- 更新多个组件与页面以优化响应式,包括宽度、间距及 flex 布局等调整
- 在 API 请求中增加 loading 状态管理,改善用户体验
- 优化领券中心与商品详情页,提升功能与 UI 一致性
2026-06-23 10:17:35 +08:00
Chopper711
ff55a0fade 完善首页 All-In-One 说明 2026-06-14 15:51:33 +08:00
lifenlong
c1447b4376 feat(促销管理): 添加限时直降和第N件优惠功能 2026-06-07 17:17:19 +08:00
lifenlong
734825ba9b 优化财务相关功能 2026-06-07 16:57:23 +08:00
lifenlong
0da6ef99af 升级Vue3,iView替换ElementPlus
- 删除babel配置、更新依赖与入口初始化
- 全量替换UI组件、样式适配,新增迁移文档与标签/过滤器自动化替换脚本
2026-06-05 17:50:17 +08:00
lifenlong
832fda813b 升级Vue3,iView替换ElementPlus
- 删除babel配置、更新依赖与入口初始化
- 全量替换UI组件、样式适配,新增迁移文档与标签/过滤器自动化替换脚本
2026-06-05 17:49:43 +08:00
pikachu1995@126.com
615ee91511 manager 升级到vue3 2026-05-25 10:49:09 +08:00
pikachu1995@126.com
e7350899bf Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2026-05-22 11:48:29 +08:00
pikachu1995@126.com
ad0522335e feat(礼品卡管理): 添加礼品卡选择、绑定、激活及列表功能
- 在购物车API中新增选择礼品卡的接口
- 在促销API中添加获取、绑定和激活礼品卡的接口
- 在订单详情和支付页面中展示礼品卡抵扣信息
- 新增“我的礼品卡”页面,支持礼品卡的查看、绑定和激活功能
- 更新路由配置以支持礼品卡相关页面
2026-05-22 11:48:19 +08:00
pikachu1995@126.com
38da0d9f3a fix(member/advance/withdrawApply): 完善提现申请审核提交逻辑
- 调整加载状态为submitLoading,通过finally确保加载状态正确关闭
- 优化成功判断逻辑,兼容布尔值和带success字段的响应结果
- 提交成功后重置更多表单状态并关闭相关弹窗
2026-05-20 11:26:52 +08:00
田香琪
020b413e20 feat(提现管理): 更新提现状态显示和逻辑
- 修改提现状态标签为“提现状态”
- 新增“用户确认”状态选项
- 更新状态显示逻辑以支持新状态
2026-05-19 20:35:05 +08:00
Chopper711
1750f04d0b update readme 2026-05-17 19:54:58 +08:00
Chopper711
14d53fa48d Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2026-05-17 19:54:19 +08:00
pikachu1995@126.com
aa4bc81da4 feat(会员管理): 添加第三方账户绑定和会员等级功能
- 在登录API中新增获取第三方账户绑定列表、绑定和解绑功能
- 在会员API中新增获取当前会员等级、等级规则和等级列表的接口
- 在会员中心页面中添加第三方账户绑定的UI和逻辑
- 新增会员等级页面,展示当前等级、经验值和经验值记录
2026-05-13 18:53:33 +08:00
田香琪
fe4e0ce75c feat(商品评价管理): 添加商品名称搜索功能和评论置顶功能
- 在商品评价页面中新增商品名称搜索框
- 在评论列表中添加是否置顶的显示和操作功能
- 实现评论置顶状态的更新逻辑
2026-04-16 17:55:16 +08:00
田香琪
052c6e153d fix(会员积分管理): 更新分页设置,调整默认每页显示条目数为20 2026-04-15 16:27:37 +08:00
田香琪
60479b44b1 feat(会员积分管理): 添加会员积分分页功能和总数显示 2026-04-15 16:15:54 +08:00
田香琪
8e0d9148b1 运营后台,积分记录展示会员剩余积分列表 2026-04-15 15:06:33 +08:00
田香琪
fc471a17a0 Merge branch 'invoice_view' 2026-04-14 18:06:59 +08:00
田香琪
b6a2dbc23a feat(发票管理): 新增发票详情功能和优化发票信息展示
- 在会员API中添加获取发票详情的接口
- 更新发票模态框,支持电子普通发票和增值税专用发票的详细信息展示
- 在订单详情页和支付页面优化发票信息的显示逻辑
- 增加发票信息的校验和格式化处理
2026-04-13 18:52:32 +08:00
田香琪
b854f40cc7 feat(虚拟销量管理): 新增单个及批量设置商品规格虚拟销量的API接口 2026-04-01 19:00:58 +08:00
田香琪
a2cd9aebe8 Merge branch 'virtual_sales_volume' 2026-04-01 17:30:10 +08:00
田香琪
2e8d257140 refactor(router): remove unused message template route 2026-04-01 17:29:19 +08:00
田香琪
379fed15b3 feat(虚拟销量管理): 新增虚拟销量设置页面 2026-04-01 17:14:08 +08:00
pikachu1995@126.com
afa3290f11 refactor(router): 移除消息模版路由配置 2026-03-31 16:02:11 +08:00
田香琪
5593ebe574 feat(商品分组): 新增商品分组管理功能
- 添加商品分组相关API接口,包括分页获取、详情查询、增删改操作
- 在商品管理页面支持批量设置商品分组功能
- 新增商品分组管理页面,支持分组的增删改查
- 配置路由以支持商品分组页面访问
2026-03-27 17:40:36 +08:00
pikachu1995@126.com
b18999900d feat(会员): 新增会员分组功能
- 添加会员分组管理页面,支持增删改查
- 在会员列表页新增分组筛选和批量设置分组功能
- 扩展会员管理 API,添加分组相关接口
- 配置路由以支持分组页面访问
2026-03-24 16:24:50 +08:00
pikachu1995@126.com
03ccdf2d43 feat: 添加微信视频号管理模块和商品定时上下架功能
- 新增微信视频号管理页面,包含概况、订单、退单、商品、分类和设置六个标签页
- 实现微信视频号相关API接口,包括类目、商品、订单、退单和概况数据查询
- 在商品管理页面添加批量定时上下架功能,支持选择状态和触发时间
- 优化批量操作下拉菜单,整合上架、下架、定时上下架、物流模板设置和删除功能
- 改进设置页面样式,增强按钮布局的响应式设计
2026-03-15 17:34:50 +08:00
misworga831
40dc2b5d2f feat(商品参数): 优化销售模式处理及商品参数验证逻辑 2026-01-08 09:29:39 +09:00
misworga831
50960ed899 fix(客服跳转): 修复IM链接中ID的获取逻辑 2026-01-07 17:34:34 +09:00
misworga831
ede1de664a feat(商品详情): 增加商品参数初始化和详细信息获取的参数检查 2026-01-07 16:52:18 +09:00
pikachu1995@126.com
6884a89fe5 feat(会员积分): 添加会员积分统计功能
- 新增查询会员积分统计的API接口
- 在积分页面添加积分统计卡片展示总发放积分和未使用积分
- 调整表格列宽样式
2025-12-26 14:04:29 +08:00
pikachu1995@126.com
676410a108 feat(会员管理): 新增会员余额和积分管理功能
- 添加会员余额增加和积分修改的API接口
- 在会员列表页增加余额显示列
- 新增余额增加和积分修改的弹窗及操作逻辑
- 优化会员列表操作列,使用下拉菜单整合更多操作
2025-12-26 12:37:58 +08:00
pikachu1995@126.com
b37e12b7a7 feat(商品参数): 新增参数管理功能并优化相关页面
- 新增参数编辑页面,支持参数名称、必填、索引等属性配置
- 优化参数列表页面,增加搜索和分页功能
- 重构商品发布页面的参数展示逻辑
- 移除商品模板相关功能
- 优化品牌管理页面的分类关联功能
- 调整商品详情页参数展示样式
2025-12-22 14:38:52 +08:00
pikachu1995@126.com
8a0f5ff120 fix(goods): 移除下载结算单接口URL中的多余斜杠 2025-12-09 16:44:18 +08:00
chc
c5fecda212 先注释掉未实际使用功能,后续优化密码修改内容 2025-12-01 18:55:46 +08:00
pikachu1995@126.com
e5d98d022e feat(manager): 调整分页组件默认页面大小为20
- 将所有页面的默认页面大小从10调整为20
- 更新分页选项数组,将最小值从10改为20
- 统一所有分页相关组件的pageSize默认值为20
- 修改pageSizeOpts选项为[20, 50, 100]
- 确保所有涉及分页的业务逻辑使用新的默认值
2025-11-24 13:09:11 +08:00
pikachu1995@126.com
799184fd21 style(components): 将按钮组件替换为链接样式
- 统一将页面中的 Button 组件替换为 a 标签,保持样式一致
- 添加统一的链接样式类 ops-link 和分隔符样式类 ops-sep
- 更新操作列中按钮的样式,使用颜色、光标和文本装饰属性替代原有 props 配置
- 在多个文件中调整了操作项之间的分隔符显示逻辑
- 优化表格操作列渲染函数,去除冗余的 Button 属性配置
- 保持功能不变的前提下提升界面视觉一致性
2025-11-24 11:33:54 +08:00
pikachu1995@126.com
756cb28daa fix(api): 修正更新隐私协议的API路径格式
feat(ui): 在顶部导航栏添加客服按钮及样式
添加客服按钮功能,包括获取IM链接和用户信息验证

refactor(order): 重构分销订单状态显示逻辑
统一订单状态显示为"未完成"、"完成"和"退款",并调整对应颜色
2025-11-23 16:30:41 +08:00
lifenlong
5f6eb6a26d feat(积分商品分类): 添加分页功能并支持按排序值排序
在积分商品分类页面添加分页组件,支持分页查询和排序
新增排序值字段展示,并对分类列表按排序值进行递归排序
2025-11-20 15:32:46 +08:00
pikachu1995@126.com
4efbec5741 refactor(分页): 统一调整分页大小选项为[20, 50, 100]并更新默认pageSize
style(售后订单): 优化商品图片样式,添加圆角和固定宽高
docs(售后订单): 更新售后状态显示文本,使其更清晰易懂
2025-10-27 18:34:01 +08:00
Ryan Ran
86dbc0d86e docs(README): 更新安装指导,新增yarn安装和启动步骤,移除npm相关内容以简化用户体验 2025-10-22 15:01:21 +08:00
pikachu1995@126.com
c32d011851 docs(readme): 更新交流方式和联系方式- 移除了旧的QQ群交流信息
- 新增微信交流群二维码
- 添加在线客服链接
- 精简了联系方式展示方式
- 统一了交流渠道描述格式
2025-10-20 14:52:33 +08:00
pikachu1995@126.com
311ca35afc feat(商品设置): 添加ES商品索引管理功能
新增三个API接口用于管理ES商品索引:
1. 删除ES中下架的商品
2. 删除不存在的索引
3. 生成所有商品的缓存
同时在商品设置页面添加对应操作按钮
2025-10-20 13:43:34 +08:00
Ryan Ran
1a3fae6501 fix(README & package.json): 更新 README 文档以反映 Node.js 版本兼容性,移除 NODE_OPTIONS 环境变量的依赖,确保项目在 Node.js 16 及以上版本下正常运行,优化用户安装指导。 2025-10-10 15:23:27 +08:00
Ryan Ran
3432530de7 fix(README.md): 更新文档以兼容更高的 Node.js 版本(20、18、16),并提供安装指导,确保用户能够顺利拉取最新代码和处理依赖问题。 2025-09-30 14:03:43 +08:00
Ryan Ran
af85493863 fix(buyer端升级node版本): 添加 .npmrc 和 .yarnrc 文件以支持引擎配置,更新 package.json 中的 NODE_OPTIONS 环境变量,替换多个组件中的 /deep/ 选择器为 ::v-deep,优化依赖管理,确保兼容性,兼容node16版本 2025-09-30 13:33:22 +08:00
Ryan Ran
ae85f0d612 fix(manager端升级node版本): 更新多个组件的样式,替换 /deep/ 选择器为 ::v-deep,替换 node-sass 为 sass,优化依赖管理和兼容性,兼容node16版本 2025-09-30 11:38:38 +08:00
Ryan Ran
16c4a78e29 fix(兼容性): 更新 seller 项目的 package.json 和 README.md,添加 NODE_OPTIONS 环境变量以支持 Node.js 版本 20 和 18 的运行,详细说明各版本的兼容性和安装要求,优化文档以提升用户体验。 2025-09-30 11:04:12 +08:00
Ryan Ran
8fb87aa64d feat(seller端升级node版本): 添加 .npmrc 和 .yarnrc 文件以支持引擎配置,更新 package.json 中的引擎要求并替换 node-sass 为 sass,优化依赖管理和兼容性,兼容node16版本 2025-09-29 18:26:52 +08:00
Ryan Ran
c5d675b6d2 fix(商品规格): 优化规格值处理逻辑,确保在规格值为空时移除对应行并更新表格数据,增强用户体验 2025-09-23 19:17:24 +08:00
Ryan Ran
f4d06b2d7b fix(商品审核): 更新审核功能,添加请求头以支持表单数据提交,提升接口兼容性 2025-09-23 14:14:43 +08:00
Ryan Ran
bb610a7cd8 fix(商品审核): 优化审核功能,使用FormData处理请求数据,提升代码可读性和维护性 2025-09-23 14:01:53 +08:00
misworga831
bb864e72b3 fix(商品规格): 优化规格值编辑逻辑,避免空值提交并清理错误提示 2025-09-15 21:45:47 +09:00
misworga831
c6c4797d87 fix(商品规格): 修复规格值过滤逻辑,确保移除空值并更新表格数据 2025-09-15 21:03:33 +09:00
misworga831
25fed42395 fix(商品规格): 添加内联错误提示,优化规格值验证逻辑 2025-09-15 16:04:48 +09:00
misworga831
66c4676493 fix(商品规格): 更新规格值提示信息,增加用户操作指导 2025-09-12 22:35:03 +09:00
misworga831
f8747b5d5d fix(商品操作): 优化模板和方法中的代码格式,提升可读性 2025-09-12 22:19:38 +09:00
misworga831
0eb58d4b8a fix(商品规格): 修复规格值编辑逻辑,避免对未定义索引的访问 2025-09-11 19:52:35 +09:00
pikachu1995@126.com
7b30ea343f feat(商品管理): 添加商品复制功能并优化批量操作
- 在商品操作页面添加复制商品功能,通过copyId参数区分复制操作
- 复制商品时自动清除原商品ID确保提交为新商品
- 优化批量操作按钮功能,包括上架、下架、删除和设置物流模板
- 移除未使用的批量规格更新功能
- 调整商品列表操作按钮布局,将复制功能加入操作列
2025-09-09 17:04:58 +08:00
pikachu1995@126.com
7db8484a7c feat(售后订单): 添加售后数量统计功能并显示在标签页
- 在manager和seller端添加获取售后数量统计的API接口
- 修改售后订单页面,显示各状态对应的数量统计
- 新增计算属性serviceStatusWithCount动态生成带数量的标签页
- 在初始化、搜索和状态切换时调用统计接口更新数据
2025-08-29 11:36:45 +08:00
pikachu1995@126.com
78b058009b feat(订单/商品): 添加数量统计功能并优化列表展示
- 在订单和商品管理页面添加数量统计功能
- 优化订单和商品列表的筛选和展示样式
- 统一API接口参数传递方式
- 移除重复代码和无用代码
2025-08-29 09:40:36 +08:00
pikachu1995@126.com
05abad3905 feat(会员管理): 新增会员ID搜索和头像显示功能
refactor(订单管理): 移除表格边框并优化分页选项

feat(售后订单): 添加关键字搜索字段并移除二维码功能

feat(商品管理): 新增批量操作和审核功能,优化商品列表展示

style: 移除多余的margin-top样式
2025-08-27 16:15:11 +08:00
pikachu1995@126.com
ad178b1806 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2025-08-27 10:12:05 +08:00
pikachu1995@126.com
075c20ae41 feat(订单列表): 新增搜索字段和支付方式筛选功能
- 添加关键字、商品名称、收货人和支付方式搜索字段
- 增加支付方式显示列和筛选功能
- 调整默认分页大小为20并增加100条选项
- 优化订单状态筛选逻辑
2025-08-27 10:11:40 +08:00
Ryan Ran
56420bd4d0 feat: 添加pageClientType属性以支持页面类型设置
在`renovation.vue`文件中,新增`pageClientType`属性并设置为'PC',以便于在页面数据中区分客户端类型,提升页面功能的灵活性。
2025-08-26 10:40:19 +08:00
pikachu1995@126.com
a18fc729c0 style(oss-manage): 调整表单元素宽度并优化布局结构
将日期选择器和输入框的宽度从200px统一调整为240px,提升表单元素的一致性
拆分操作区域到单独的Card组件中,改善页面布局结构
2025-08-21 16:41:46 +08:00
pikachu1995@126.com
099941a54e style: 统一输入框和选择器宽度为240px并优化卡片布局
- 将多处输入框和选择器的宽度从200px调整为240px
- 优化卡片布局结构,添加分割卡片提升可读性
- 移除部分冗余的刷新按钮和样式代码
- 调整日期选择器等表单元素的宽度为240px
2025-08-21 16:41:27 +08:00
Ryan Ran
3867d51d92 fix: 移除管理端会员列表,回收站username字段,优化成员列表组件的属性结构 2025-08-13 18:18:41 +08:00
Ryan Ran
f1be18b7e3 添加vue-virtual-scroller依赖并在消息视图中实现虚拟滚动功能,以优化对话列表的渲染性能。同时,为manager和seller项目添加minimatch依赖项的解析版本以解决潜在的版本冲突。 2025-07-15 16:16:42 +08:00
Ryan Ran
ef46380f9e 添加minimatch依赖项的解析版本以解决潜在的版本冲突 2025-07-04 17:16:47 +08:00
chc
d711273cf0 商品发布参数项校验无法some问题 2025-03-12 10:28:59 +08:00
chc
5e7cf2d679 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2025-03-11 19:09:39 +08:00
chc
11319ba21f 分类参数必填校验 2025-03-11 19:09:05 +08:00
Chopper711
9c51523352 refactor(coupon-activity): 注释掉邀新赠券选项 (master)
注释掉了"邀新赠券"的Radio按钮,以简化界面。
2025-02-21 18:44:21 +08:00
Chopper711
b4a706820e ### feat: 优化优惠折扣输入组件 (master)
- 将`Input`组件替换为`InputNumber`组件,以确保输入的优惠折扣
  在0.1到9.9之间,并支持一位小数。
- 在`full-discount-add.vue`和`full-discount-detail.vue`文件中,
  更新了`FormItem`组件的`优惠折扣`输入逻辑。
- 在`coupon-publish.vue`文件中,更新了描述文本以强调输入
  范围和格式。
- 在`coupon.vue`文件中,修复了优惠券类型判断逻辑,增加了
  "DISCOUNT"类型和未知类型的处理。
2025-02-21 17:34:58 +08:00
Chopper711
376a3223dc fix: 优化积分商品添加页面和对账单详情页面的功能 (master)
- 移除积分商品添加页面的冗余标题
- 将兑换时间选择器替换为活动时间范围选择器
- 简化验证规则,使用rangeTime替代单独的开始和结束时间
- 调整批量删除按钮和其他按钮的样式格式
- 在对账单详情页面添加删除消息提示框功能
2025-02-21 16:09:14 +08:00
Chopper711
a85ec69549 fix: 消息提示框以及消息点击查看后需要标记已读按钮优化 2025-02-20 15:48:19 +08:00
Chopper711
ebf4d6d3eb Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2025-02-20 14:57:21 +08:00
Chopper711
2ccd8265b9 fix: 消息提示框以及消息点击查看后需要标记已读按钮优化 2025-02-20 14:52:53 +08:00
chc
fb1671d062 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2025-02-17 13:41:42 +08:00
chc
95e37df2ec 电子面单物流选中错误问题 2025-02-17 13:41:05 +08:00
pikachu1995@126.com
cfde72f1ab Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2025-02-11 15:43:20 +08:00
pikachu1995@126.com
efc778acbc 微信支付配置,添加配置使用公钥还是证书 2025-02-11 15:43:09 +08:00
misworga831
37384ebadd fix: 优化商品编辑 2025-01-21 13:53:07 +08:00
misworga831
9a7aee7e97 fix: 优化商品编辑 2025-01-20 18:43:21 +08:00
chc
1a56534d28 提现设置增加校验 2025-01-20 18:12:41 +08:00
chc
79e7e5f087 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2025-01-17 17:42:58 +08:00
chc
aea03cf975 支付设置选中状态错误问题 2025-01-17 17:42:49 +08:00
pikachu1995@126.com
8ef6f944dc 微信支付配置,添加微信支付公钥 2025-01-08 16:14:14 +08:00
pikachu1995@126.com
e18d243961 优化微信支付配置,不读取密钥文件,改成读配置文件 2024-12-27 11:01:53 +08:00
chc
765b633cea Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-12-25 10:35:50 +08:00
chc
9c402a3878 1.查看物流信息
2.直播图片选择器修改
3.管理端隐藏会员详情
2024-12-25 10:35:40 +08:00
Chopper711
86426b087a feat: 使用InputNumber组件替换折扣输入框 (master)
在coupon-publish.vue中,将折扣输入框从Input组件更改为
InputNumber组件,以便更好地控制折扣值的输入范围。
2024-12-23 11:51:05 +08:00
chc
c5aaa2f3e2 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-12-02 18:05:51 +08:00
chc
cc59bb6094 售后实际退款金额显示错误问题 2024-12-02 18:05:43 +08:00
Ryan Ran
5662da1210 fix: 修改商家端分销商品列表点击链接商品不展示问题 2024-11-25 10:43:49 +08:00
Ryan Ran
863725d3ba 优化管理端活动楼层装修 2024-11-11 15:23:32 +08:00
Yer11214
b1acfbdd4b !40 修复了行政地区切换验证状态没更新的问题
Merge pull request !40 from 孟锴/feature/mengkai-master-branch
2024-10-14 07:34:03 +00:00
mengkai
001f9c3f30 修复了行政地区切换验证状态没更新的问题 2024-10-14 11:26:26 +08:00
Yer11214
8d4df4b66e Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-10-07 22:26:15 +08:00
Yer11214
604447508a fix: oss选择图片不展示报错bug 2024-10-07 22:26:13 +08:00
misworga831
6f30949620 fix: 移动端楼层装修促销活动移除优惠券.pc端楼层装修快捷导航外部链接无法填写问题 2024-09-23 21:18:27 +08:00
chc
10e8e82fe4 增加部分发货状态 2024-09-18 15:25:04 +08:00
Yer11214
5227e0ae13 优惠券列表样式修改 2024-09-08 23:10:23 +08:00
misworga831
cf193f4eab fix: 优化店铺oss分组删除问题 2024-09-05 14:29:10 +08:00
RyanRan
708ae53fe2 docs: seller 端 axios修改 timeout过期时间 2024-07-24 14:45:46 +08:00
Yer11214
aed57177dd update README.md.
Signed-off-by: Yer11214 <17633066053@163.com>
2024-07-19 02:12:28 +00:00
Yer11214
e916a03ff8 update README.md.
Signed-off-by: Yer11214 <17633066053@163.com>
2024-07-19 02:10:18 +00:00
pikachu1995@126.com
859d60c0bf Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-07-18 14:30:27 +08:00
pikachu1995@126.com
1eeaf38638 优化店铺资源管理页面 2024-07-18 14:30:14 +08:00
RyanRan
ca09bbe3fc Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-07-18 14:05:02 +08:00
RyanRan
57b42bdc66 删除.npmrc以及.yarnrc命令 2024-07-18 14:05:00 +08:00
misworga831
88c31d157e fix: 修复商品编辑规格第一个规格值无效问题 2024-07-18 09:44:46 +08:00
RyanRan
c738274423 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-07-17 14:52:42 +08:00
RyanRan
1c62ee6efe docs: 删除package.json中无用的引用导致报错 2024-07-17 14:52:22 +08:00
Yer11214
4fcb24607d update README.md.
修改readme文档

Signed-off-by: Yer11214 <17633066053@163.com>
2024-07-12 06:26:28 +00:00
RyanRan
52ce1e795c fix: buyer端删除 package-lock.json 2024-07-10 13:15:29 +08:00
pikachu1995@126.com
39c4593d9e 优化支付、短信的配置内容 2024-07-07 14:04:19 +08:00
pikachu1995@126.com
6ae288cf01 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-07-02 14:56:20 +08:00
pikachu1995@126.com
bab54570fe 优化结算单详情以及分销相关页面展示 2024-07-02 14:56:10 +08:00
Yer11214
2551c76d97 删除文件 buyer/yarn.lock 2024-07-02 03:15:18 +00:00
pikachu1995@126.com
e3a5583802 商家增加库存导出导入api 2024-06-28 10:44:53 +08:00
pikachu1995@126.com
b03adc1b1f 优化微信支付的参数配置 2024-06-28 09:09:01 +08:00
pikachu1995@126.com
6e9d725f6d 支持店铺通过excel批量更新商品库存功能 2024-06-27 17:09:58 +08:00
pikachu1995@126.com
92559ca9e7 优化订单导出功能 2024-06-26 11:51:22 +08:00
misworga831
3bfa99f578 fix: 修复优惠券使用范围中的部分商品分类 2024-06-14 11:30:53 +08:00
misworga831
30b85163b7 fix: 临时注释优惠券使用范围中的部分商品分类(后续改为部分店铺分类) 2024-06-13 16:11:00 +08:00
15386982806
ef528a2952 OSS资源修改分组 2024-05-27 16:41:34 +08:00
lele0521
907e9d35a7 fix: 增加订单备注 2024-05-15 17:56:06 +08:00
lele0521
d003e5da70 fix: 增加订单备注 2024-05-15 16:57:27 +08:00
lele0521
19530988ce Merge remote-tracking branch 'origin/master' 2024-05-15 15:57:00 +08:00
lele0521
4e9baebcf5 fix: 增加订单备注 2024-05-15 15:56:50 +08:00
RyanRan
3a1cbfe8bb fix: 🐛 修改昨天提交判断出错bug 2024-05-10 17:36:55 +08:00
RyanRan
c16b37c8bc feat: ✨ pc端新增专题功能 2024-05-09 18:38:22 +08:00
15386982806
0c6703f04d 修改促销活动展示问题 2024-04-23 11:28:44 +08:00
lele0521
3471caf00a fix: 商品导入后,导入动态样式未取消 2024-04-22 16:34:09 +08:00
lele0521
ad28e70a07 fix: 运营后台首页统计数据,处理默认数据显示 2024-03-29 11:46:34 +08:00
lele0521
47315963f1 fix: 订单支付超时跳转对应页面 2024-03-27 15:36:56 +08:00
15386982806
fb8fa9e787 修改OSS资源回显 2024-03-26 18:07:20 +08:00
lele0521
223fa7ca05 fix: 修复商品评价中商家回复信息的展示 2024-03-25 16:31:03 +08:00
Yer
b568c242e3 perf: 🐛 修改个人资料后应该直接刷新页面,获取最新数据 2024-03-24 09:02:15 +08:00
15386982806
e4283e1c53 修改编辑会员地址 2024-03-21 19:19:59 +08:00
15386982806
25f9cc1095 修改编辑店铺入参 2024-03-21 18:51:39 +08:00
15386982806
85729e3761 我的评价展示商家回复 2024-03-21 17:38:47 +08:00
15386982806
fa0a0cb1d8 优化订单统计展示、修改店铺校验 2024-03-21 17:12:16 +08:00
15386982806
e7ee256b80 会员回收站列表 修改器启用提示信息 2024-03-21 16:19:02 +08:00
lele0521
36190438f0 fix: OSS资源管理运营端增加按店铺名称搜索 2024-03-19 17:58:45 +08:00
chc
ce629a1fb6 PC端增加修改价格字段 2024-03-15 16:29:13 +08:00
15386982806
f989d1ef4e OSS资源回显问题 2024-03-15 10:35:25 +08:00
chc
99455dee58 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-03-11 16:08:13 +08:00
chc
c7bd7223bc 多货物订单无售后按钮 2024-03-11 16:08:05 +08:00
chc
8166f90f0f 多SKU订单无申请售后按钮 2024-03-11 15:49:35 +08:00
15386982806
8b2587daa7 修改商家端素材管理样式 2024-03-07 19:32:25 +08:00
Yer
82e047c797 style: 2024-03-07 15:48:22 +08:00
misworga831
3cefb40ccb merge conflict 2024-02-28 09:14:38 +08:00
misworga831
8bba4a1e48 fix: 修复编辑商品sku规格项时,值为空鼠标移出后显示错误问题 2024-02-28 09:13:16 +08:00
Yer
a12f317aa8 fix: 🐛 修改部分页面点击回车刷新页面bug 2024-02-27 11:56:43 +08:00
Chopper711
1d133af38d fix: 淘宝镜像源地址https证书过期问题处理 2024-02-19 18:06:26 +08:00
chc
9cab354cbb 去除商家修改收货地址的长度限制 2024-02-19 15:04:05 +08:00
chc
c0385414ca 隐藏普通发货功能,使用分包裹发货 2024-02-18 16:12:26 +08:00
Yer
4f7846dc4e Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2024-02-02 18:29:12 +08:00
Yer
01beac9265 fix: 🐛 优化管理端商品分类添加/修改/删除 之后原有的 层级关闭问题 2024-02-02 18:29:10 +08:00
15386982806
77ad146e24 商家端优化OSS资源管理 2024-02-02 18:09:29 +08:00
15386982806
6c1c47de1d 管理端优化OSS资源管理 2024-02-02 17:24:57 +08:00
lele0521
b3cac070df fix: 管理端-结算单流水去除(flowType: "PAY") 2024-01-30 09:39:37 +08:00
Yer
daf1b20f67 fix: 🐛 修改订单设置退单描述问题 2024-01-29 14:53:04 +08:00
Yer
2316fb8d11 fix: 🐛 修改订单配置中描述错误bug 2024-01-29 14:08:24 +08:00
lele0521
43159335f8 Revert "分销结构优化"
This reverts commit 63b22f4c86.
2024-01-26 13:35:47 +08:00
misworga831
0e56c2038d Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2024-01-25 17:51:09 +08:00
misworga831
0840740e2c fix: 优化秒杀展示 2024-01-25 17:50:55 +08:00
15386982806
e2404f0f3b Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-01-25 13:20:57 +08:00
15386982806
5e9a258cc8 隐私协议右侧添加手机查看效果 2024-01-25 13:20:46 +08:00
misworga831
8cfc420085 fix: 买家端虚拟商品订单不显示地址信息 2024-01-25 09:36:04 +08:00
misworga831
83593bd015 fix: 优化虚拟商品不需要收货地址 2024-01-24 19:23:34 +08:00
pikachu1995@126.com
c1cdf97edb Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-01-24 14:58:11 +08:00
pikachu1995@126.com
eca8370c70 结算单详情调优 2024-01-24 14:58:01 +08:00
chc
54502b331f Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-01-24 11:33:21 +08:00
chc
0ec5955ea0 库存预警,分类搜索问题 2024-01-24 11:33:12 +08:00
pikachu1995@126.com
b70a9bf0c0 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-01-24 09:47:11 +08:00
pikachu1995@126.com
fb20cb32da 结算单详情调优 2024-01-24 09:46:59 +08:00
chc
a314373e64 商品编辑数据可能被覆盖问题 2024-01-23 16:51:10 +08:00
pikachu1995@126.com
4976b87c4e Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-01-23 10:33:08 +08:00
misworga831
3b9e54375a fix: 修复删除sku图片无效问题 2024-01-23 10:06:36 +08:00
misworga831
8b15cfb0b1 fix: 兼容旧版本图片格式 2024-01-22 18:11:25 +08:00
pikachu1995@126.com
ff02cce191 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-01-22 15:24:41 +08:00
misworga831
83beb81a3b fix: 兼容旧版本图片格式 2024-01-22 14:39:43 +08:00
misworga831
de89249d3e improved: 优化sku编辑 2024-01-22 14:09:00 +08:00
chc
77732e766a Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-01-18 11:46:30 +08:00
chc
21c91cfcf1 库存预警 2024-01-18 11:46:11 +08:00
Yer
ebaf5e34d8 fix: 🐛 修改商家端订单评论发现的bug 和后端字段不统一 2024-01-17 18:35:11 +08:00
15386982806
94e389ab23 编辑商品字符长度限制 2024-01-16 18:09:11 +08:00
15386982806
7ba94c7fe1 编辑商品详情 2024-01-16 17:54:28 +08:00
15386982806
c47394a162 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-01-16 17:29:39 +08:00
15386982806
bf8afdc0f4 买家端订单状态 2024-01-16 17:29:19 +08:00
chc
3df17ed33f Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-01-16 17:28:33 +08:00
chc
dc6d3b3743 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2024-01-16 17:28:25 +08:00
15386982806
6e626f6e11 买家端订单退款状态 2024-01-16 17:27:05 +08:00
chc
d20da31f2c 库存预警 2024-01-16 17:26:09 +08:00
15386982806
2182cd012a 商品详情展示此规格的价格 2024-01-16 16:33:43 +08:00
15386982806
71c629cb06 运费模板 品牌 计量单位刷新成功提醒 2024-01-16 11:12:07 +08:00
15386982806
185d675abf 库存预警还原 2024-01-16 10:45:03 +08:00
chc
6221b59b21 库存预警回退 2024-01-16 10:18:39 +08:00
15386982806
07f320ca2f 修改订单查询物流样式 2024-01-11 14:45:17 +08:00
15386982806
9908b83b18 商家端优化库存预警,管理端 商家端隐藏所有促销活动的删除按钮 2024-01-11 13:32:39 +08:00
15386982806
9ce1c966eb 订单支持分包裹发货 2024-01-10 19:15:24 +08:00
15386982806
c81eff58d3 上传图片采用素材管理 2024-01-09 17:09:23 +08:00
15386982806
92b61a203f 商家端图片上传采用素材管理上传 2024-01-09 16:39:52 +08:00
15386982806
b1f9c0adf2 商家端添加OSS资源素材管理 2024-01-08 17:59:49 +08:00
15386982806
c5d75a3570 运营后台商品详情展示此规格的价格 2024-01-05 16:28:36 +08:00
15386982806
42c64920b1 商品规格字符长度限制 2024-01-05 15:54:10 +08:00
15386982806
77e7d095a7 运费模板 品牌 计量单位 支持刷新功能 2024-01-05 15:10:48 +08:00
15386982806
560199944d PC端订单货物展示退款状态与实际退款金额 2024-01-05 14:00:22 +08:00
15386982806
21ae217369 订单取消状态改为已关闭、订单货物展示退款数量 2024-01-05 10:08:37 +08:00
mahe
4565297fe6 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-12-22 17:41:30 +08:00
mahe
118e68b8ac fix: 修复楼层装修跳转错误 2023-12-22 17:41:19 +08:00
Yer
a03f908e96 style: 🐛 修改店铺入驻协议样式问题 2023-12-22 17:35:51 +08:00
Yer
0b6dcf17d1 fix: 🐛 修改 im cdn 2023-12-22 17:13:18 +08:00
Yer
5136f8b3dd fix: 🐛 修改商家端楼层装修bug 2023-12-22 14:31:39 +08:00
mahe
286295393d 发布商品增加局部刷新与去除成本价 2023-12-18 18:04:44 +08:00
mahe
195ea35798 修改图片超出内容问题 2023-12-18 15:35:20 +08:00
mahe
053279f60d 修改店铺分类未展示 2023-12-18 14:43:58 +08:00
Chopper711
9bfb7e8b69 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-12-11 07:58:28 +08:00
Chopper711
c82f8a6de3 fix: 部门搜索功能bug修复 2023-12-11 07:58:22 +08:00
Yer
749147cfad feat: ✨ 商家端富文本改为本地引入 2023-12-01 11:38:31 +08:00
Yer
4429227665 feat: ✨ 商家端富文本改为本地引入 2023-12-01 11:38:01 +08:00
Yer
3ec0e9d997 feat: ✨ 新增富文本本地引入 2023-12-01 10:47:33 +08:00
Chopper711
904046f02c Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-11-30 18:50:01 +08:00
pikachu1995@126.com
5a29215b80 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-10-26 14:34:49 +08:00
misworga831
508a00d103 fix: 优化编译脚本 2023-10-18 08:14:54 +08:00
misworga831
5385d10bc8 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-10-16 18:20:34 +08:00
misworga831
08b4a04791 resolve conflict 2023-10-16 18:20:29 +08:00
misworga831
218cee2aef fix: 优化售后订单搜索 2023-10-16 18:16:28 +08:00
pikachu1995@126.com
63b22f4c86 分销结构优化 2023-10-16 16:00:15 +08:00
Chopper711
709a3f71fd Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-10-13 11:14:19 +08:00
Yer
f7589e42ab Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-10-11 16:36:38 +08:00
Yer
0e7008862e feat: 新增弹出页以及广告页面开启关闭提示 2023-10-11 16:36:36 +08:00
misworga831
7e88ee930b resolve conflict 2023-10-11 10:11:11 +08:00
chc
e935f2a3e3 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-10-10 11:29:15 +08:00
chc
9d442a2aa1 订单统计切换分页问题处理 2023-10-10 11:26:50 +08:00
Yer
eed6ba43d9 合并提交 2023-10-09 13:30:56 +08:00
Yer
b2c286f0f5 fix: 🐛 修复在统计图中可能出现的Bug 2023-10-09 13:27:13 +08:00
misworga831
2aae5a4bff fix: 修复拼团批量删除,所选数量不正确问题 2023-09-30 17:48:35 +08:00
“Yer”
c88c1865e7 fix: 🐛 修改统计图已发现的问题 2023-09-30 16:18:27 +08:00
Chopper711
7152e339e5 fix: 前后端交互数据出现问题处理 2023-09-27 07:07:22 +08:00
pikachu1995@126.com
46143beb83 添加文件-文件夹 2023-09-26 18:48:55 +08:00
Yer
2c66eaae2b fix: 🐛 修复已知统计问题 2023-09-26 15:53:13 +08:00
Yer
b8c74ac84c Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-09-26 15:02:20 +08:00
Yer
cb210916eb style: 调整投诉详情页面的样式 2023-09-26 15:02:17 +08:00
Chopper711
f968f3d20d refactor: 重构PC分享页面,优化布局展示,增加移动端二维码展示 2023-09-25 15:02:57 +08:00
Chopper711
4ef2496221 店铺菜单管api 补充提交 2023-09-25 12:13:07 +08:00
Chopper711
b2b56178a2 菜单权限url增加长度限制 2023-09-25 12:05:05 +08:00
Chopper711
525838468c refactor: 增加店铺菜单维护页面 2023-09-25 11:58:34 +08:00
Yer
ef92bcfe3a fix: 🐛 修改部分已知的Bug 2023-09-25 10:05:41 +08:00
Yer
ed72c2ffc2 style: 关闭文章列表在楼层中添加文章功能 2023-09-22 11:51:18 +08:00
Yer
9f94c2013a style: 调整商品选择器,店铺选择器代码 2023-09-22 10:49:11 +08:00
misworga831
8666254ffe Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-09-19 09:37:04 +08:00
Yer
e13fc57ae7 fix: 🐛 修复已知的bug 2023-09-19 09:25:57 +08:00
misworga831
c6cf90fb4e fix: 优化统计数据文本显示 2023-09-18 16:59:23 +08:00
Yer
fff086a3a1 feat: 新增商品审核中多个规格以及库存展示 2023-09-18 16:45:30 +08:00
misworga831
b7a2a5af6d fix: 修复管理端商品分类,编辑时状态显示错误问题及佣金比例限制 2023-09-18 16:04:25 +08:00
Yer
1786dfeee2 fix: 🐛 修复几个已知的bug 2023-09-18 15:36:46 +08:00
Yer
2c32088f4c feat: 优化部分代码,新增审核商品视频 2023-09-15 19:43:41 +08:00
Yer
71f61461ce Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-09-14 18:07:44 +08:00
Yer
54be87efea fix: 🐛 解决几个发现的重置bug 2023-09-14 18:07:42 +08:00
misworga831
76fc55fdd0 improve: 统一物流单号名词 2023-09-14 16:58:35 +08:00
misworga831
5d5a845523 fix: 完善文字性描述 2023-09-14 15:06:59 +08:00
Yer
4f915a32b6 fix: 🐛 解决几个已知的bug 2023-09-14 13:58:50 +08:00
Yer
78df54d153 fix: 🐛 修复几个已知bug 2023-09-14 09:11:25 +08:00
Yer
24554a0768 feat: ✨ 编辑会员新增默认头像展示 2023-09-13 17:25:35 +08:00
Yer
ffe03fd785 feat: ✨ 买家端查看商品详情新增商品参数功能,修复几个已知的bug 2023-09-13 16:06:42 +08:00
Yer
4b635735ae Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-09-05 11:28:26 +08:00
Yer
79c1e2c5bb fix: 🐛 修复填写支付宝微信支付秘钥被截断问题 2023-09-05 11:28:23 +08:00
Yer11214
cf9f9fb7dd style: 💄 PC端收藏商品中收藏店铺添加跳转以及优化样式 2023-08-26 13:48:04 +08:00
Yer
2bcefc1306 fix: 🐛 解决商品编辑中重新选择分类、商品参数不更新问题 2023-08-24 16:40:28 +08:00
Chopper711
39547b542c style: 默认描述增加 2023-08-22 16:08:54 +08:00
Yer
8c9246faa4 fix: 🐛 修复商家端菜单切换之后active样式丢失问题 2023-08-16 16:29:45 +08:00
Yer
74b180f6d3 fix: 🐛 修改展示字错误 2023-08-14 15:53:44 +08:00
Yer
ac26690e78 fix: 🐛 修改部分已知的bug 2023-08-11 17:41:44 +08:00
Yer
d642e00844 fix: 🐛 修改订单详情因为发票信息可能出现的bug 2023-08-10 16:53:14 +08:00
Yer
7bbb657379 perf: ⚡ 优化地区选择器代码 2023-08-10 11:29:57 +08:00
Yer
00a56473f1 fix: 🐛 优化买家端首页点击回到顶部的判断 2023-08-09 15:32:44 +08:00
Yer
e138275c0a fix: 📝 补充提交 2023-08-09 14:57:35 +08:00
Yer
9e7a1b3ee3 feat: ✨ 商家端新增楼层数据保存到本地功能 2023-08-09 14:56:57 +08:00
Yer
c5e06ad1f2 feat: ✨ 新增管理端楼层装修保存到本地功能 2023-08-09 14:42:23 +08:00
Yer
128ad892d1 feat: ✨ 买家端使用最新地址选择器,默认在config关闭高德地图功能,开启后可继续使用 2023-08-03 16:36:41 +08:00
Yer
552b4c605d feat: ✨ 地图选择器 2023-08-03 10:38:07 +08:00
Yer
8b33dbe8d7 feat: ✨ 管理端使用最新地址选择器,默认在config关闭高德地图功能,开启后可继续使用 2023-08-03 10:37:53 +08:00
Yer
8a43335b75 feat: ✨ 商家端使用最新地址选择器,默认在config关闭高德地图功能,开启后可继续使用 2023-08-02 10:53:14 +08:00
“Yer”
a4d17102f1 style: 💄 修改文章页面红线突兀样式 2023-07-31 17:48:30 +08:00
Yer
d02d0adb39 fix: 🐛 修改PC首页跳转bug 2023-07-28 17:11:19 +08:00
Yer
c86cecf4f0 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-07-25 10:10:22 +08:00
Yer
7bc5d67efc feat: ✨ 商家端新增redirect登录功能 2023-07-25 10:10:20 +08:00
misworga831
d058d7d6e8 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-07-24 15:11:03 +08:00
misworga831
914fa0a324 fix: 优化统计数据文本展示 2023-07-24 15:10:52 +08:00
Yer
4389911436 买家端展示视频判断 2023-07-24 14:26:07 +08:00
Yer
841d48e2a7 style: 🐛 修改几个console警告问题 2023-07-21 11:17:40 +08:00
Yer
b6c16e7048 提交优化一个小问题 2023-07-20 18:10:16 +08:00
Yer
9fce33ca18 买家端新增视频播放功能 2023-07-20 16:50:43 +08:00
Yer
6a653198c3 商家端新增上传视频功能 2023-07-19 14:08:32 +08:00
Yer
2c8e34008f 轮播图 string类型改成 number类型 要不然有警告 2023-07-14 13:45:00 +08:00
Yer
6feb650f06 优化Buyer端展示 2023-07-14 13:42:35 +08:00
Yer
873764b59e feat: ✨ 管理端添加多标签Tab页内嵌模式设置 2023-07-14 09:19:52 +08:00
Yer
36ef331b94 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-07-13 17:24:03 +08:00
Yer
308619fbdd feat: ✨ buyer端新增 平台/店铺切换搜索,管理端意见按照时间反馈排序展示 2023-07-13 17:24:00 +08:00
pikachu1995@126.com
6dec218e81 删除无用的配置项 2023-07-13 16:00:09 +08:00
Yer
f9717eb7ac 微信消息订阅模板 描述文字更换 订阅 改成 初始化 2023-07-11 17:10:54 +08:00
Chopper711
cb10bd97a0 店铺编辑管理端排版处理 2023-07-11 15:35:25 +08:00
Yer
430894eb69 删除管理端中 物流公司中需要填写的电子表单 2023-07-11 15:07:10 +08:00
Yer
34cb3b4a29 style: 💄 优化PC首页展示以及店铺中搜索商品未携带id问题 2023-07-11 11:45:29 +08:00
Yer
b89f81e5d6 fix: 🐛 修复日志管理中开发人员操作时间展示问题 2023-07-10 10:13:38 +08:00
Yer
604bdcaf77 fix: 🐛 修改日志模块中操作时间展示问题 2023-07-10 09:49:14 +08:00
Yer
a46cd8ee97 优化最新pc首页展示的问题 ,删除秒杀活动默认展示以及轮播图新增自动滚动 2023-07-07 09:21:07 +08:00
Yer
7e14569479 补充提交 2023-07-06 17:23:46 +08:00
Yer
3c296ea011 feat: ✨ 新增楼层装修 更改部分买家端UI 2023-07-06 17:21:38 +08:00
Yer
8529641145 优化了部分展示功能 2023-07-06 16:21:25 +08:00
Yer
b133502062 补充提交 2023-07-06 15:37:59 +08:00
Yer
5470253626 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-07-06 11:44:17 +08:00
Yer
6b697f9ecd feat: ✨ 新增多标签Tab页内嵌模式 2023-07-06 11:44:15 +08:00
pikachu1995@126.com
44558d9072 运营后台-售后列表,售后状态展示优化 2023-07-05 11:42:25 +08:00
pikachu1995@126.com
8dbd5429f0 运营后台-订单列表,订单状态展示优化 2023-07-05 11:11:39 +08:00
Yer
3c83179579 feat: ✨ 管理端新增格式化价格文件插件并在代码中引入,更新代码需要install插件 2023-07-04 10:24:21 +08:00
Yer
bf70527c58 feat: ✨ 商家端新增格式化价格文件插件并在代码中引入,更新代码需要install插件 2023-07-03 16:28:58 +08:00
Yer
26a539662e fix: 🐛 修改在买家端商品详情中因为categoryName为空导致页面出错不展示bug 2023-06-16 10:58:06 +08:00
mahe
48f2bd82a1 修改热区无法跳转专题问题 2023-06-15 09:44:46 +08:00
mahe
73c2654cc5 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-06-09 17:42:16 +08:00
mahe
49dfd644a2 修改优惠券展示问题 2023-06-09 17:39:59 +08:00
chc
09ce16dc95 IM携带商品信息 2023-06-01 10:10:51 +08:00
Chopper711
5b58d1de5e fix:之前的部分售后逻辑补足,不过代码判定存在问题,需要未来进行优化 2023-05-31 15:04:46 +08:00
Yer
775b339c17 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-05-26 16:54:29 +08:00
Yer
1ef8dd26cf fix: 🐛 修改店铺详情bug 2023-05-26 16:54:26 +08:00
yeliang-king
b36be16f38 会员修改刷新列表 2023-05-16 17:10:48 +08:00
Yer
1c765f37cf feat: ✨ 新增pc端 商品下架功能 2023-05-10 13:51:24 +08:00
Yer
724922dddc Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-05-09 11:42:44 +08:00
Yer
9dece4dd2c fix: 🐛 修复规格列表中,第一次新增规格点击编辑不回显问题 2023-05-09 11:42:41 +08:00
mahe
4a628acd37 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-05-09 11:05:49 +08:00
mahe
5c3501f08d 优化系统设置中的警告 2023-05-09 11:05:40 +08:00
misworga831
ad09b38ed5 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-05-08 18:42:09 +08:00
misworga831
c60a54b8f9 fix: 修复满减活动没有传递范围参数 2023-05-08 18:41:56 +08:00
Chopper711
056386e8e9 fix:用户端提现状态展示问题处理 2023-05-06 16:34:33 +08:00
Chopper711
8ad79b8728 fix: 兼容提现失败前端的展示 2023-05-06 16:23:29 +08:00
Chopper711
a78374910f fix: 兼容提现失败前端的展示 2023-05-06 16:23:27 +08:00
mahe
4318e8d0da 修改店铺装修选择链接问题 2023-05-06 16:07:30 +08:00
mahe
4ace1a9cca 增加店铺楼层装修图片热区功能 2023-05-06 15:57:34 +08:00
chc
7ded1c564e 类型保存问题 2023-04-26 11:02:24 +08:00
chc
28d68bdca6 去除电子面单必填校验 2023-04-25 10:40:31 +08:00
程
9181befdf9 秒杀增加card,满额详情不展示操作列 2023-04-23 10:23:32 +08:00
程
87b3cbe344 满额活动增加card样式 2023-04-23 09:33:16 +08:00
Yer
8b0ca5ba7e Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-04-21 17:36:05 +08:00
Yer
b30be8efb2 优化商城端可以重复搜索内容 2023-04-21 17:36:02 +08:00
Yer
2213f0d0ce 新版楼层装修样式修改以及链接修改 2023-04-21 17:25:16 +08:00
夜良king
0883a967b6 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-04-19 10:34:43 +08:00
夜良king
c8e8685586 删除多余的文字 2023-04-19 10:34:32 +08:00
程
73ce45aff9 虚拟订单展示物流bug 2023-04-17 17:41:16 +08:00
程
e954cf4d92 订单详情重复展示问题 2023-04-17 11:31:52 +08:00
程
d1a974f6b0 规格列表,编辑不回显问题 2023-04-17 10:13:29 +08:00
程
39f7f1ed38 修改规格列表多余提示 2023-04-17 09:29:26 +08:00
lemon橪
5380cf9ba9 Merge remote-tracking branch 'refs/remotes/origin/master' 2023-04-15 09:37:13 +08:00
lemon橪
6e9ca81b58 fix: 🐛 修改系统设置oss设置表单校验不通过问题 2023-04-15 09:36:36 +08:00
学习很差啦
531ed5b2dd Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui into dev-feature 2023-04-12 11:07:47 +08:00
学习很差啦
ebc79da0fc feat: ✨ 对原有填写金额的input框进行改进,优化部分样式问题 2023-04-12 11:06:25 +08:00
学习很差啦
1cbafbce25 最新楼层装修模块 2023-04-07 16:47:27 +08:00
学习很差啦
816d842a57 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui into dev-feature 2023-04-07 10:12:01 +08:00
misworga831
e5c25895a0 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-04-04 15:15:09 +08:00
misworga831
1abc7a5a52 fix: 适配新获取商品返回结果 2023-04-04 15:14:41 +08:00
学习很差啦
170244cc9c style: ✨ 修改部分页面中展示细节,分销订单中新增状态展示,统计模块优化代码,热词模块 历史热词默认展示昨天热词,以及优化热词统计 2023-04-03 14:22:07 +08:00
学习很差啦
3498de4529 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-03-31 18:16:37 +08:00
学习很差啦
16b0d457fc style: ✨ 新增部分代码注释 页面新增部分提示 2023-03-31 18:16:33 +08:00
misworga831
87b6ddbaa6 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-03-31 17:14:29 +08:00
misworga831
2f6e50cc1c fix: 适配新获取商品返回结果 2023-03-31 17:14:22 +08:00
Chopper711
aa196918bf update README.md.
Signed-off-by: Chopper711 <1814994716@qq.com>
2023-03-31 07:23:51 +00:00
学习很差啦
5958353383 楼层装修新增内容 2023-03-31 15:22:38 +08:00
lemon橪
f37f633f51 新增部分楼层 2023-03-29 14:05:31 +08:00
chc
8c286610ba 待自提状态 2023-03-29 10:06:59 +08:00
chc
d2540733dc fix: 电子面单参数显示错误 2023-03-28 17:00:19 +08:00
chc
ab56bdfcad 规格问题 2023-03-27 19:45:53 +08:00
Chopper711
803eae5c7d style:按钮空格 2023-03-23 16:44:28 +08:00
学习很差啦
6b3892e17d 楼层装修新特征 2023-03-22 16:22:10 +08:00
学习很差啦
500afcc33f 楼层装修新特征 2023-03-22 16:22:01 +08:00
pikachu1995@126.com
64c61d5365 Merge branch 'master' into Bulbasaur 2023-03-22 08:43:05 +08:00
chc
bf58711c88 -fix APP版本时间问题,微信消息修改时间问题 2023-03-15 19:41:08 +08:00
学习很差啦
48b3e3246c Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-03-15 10:44:05 +08:00
学习很差啦
8f629db5ab feat: ✨ 新增全局Input表单默认最大输入值,开放config全局配置 2023-03-15 10:44:02 +08:00
Chopper711
1ca94d289a fix: 关闭优惠券按钮状态判定未判定新活动状态导致新活动点击关闭按钮无效 2023-03-15 10:19:03 +08:00
17600048398
3159c325e3 商品分类移除多余字符 2023-03-14 11:18:17 +08:00
17600048398
b51040c73e 物流管理-关闭物流传参错误问题, 2023-03-14 09:10:18 +08:00
17600048398
f4ddeaa5c5 前端问题处理 2023-03-09 18:16:10 +08:00
misworga831
8599708af3 Increase payment support and update parameters
- Improved payment system with WeChat and AliPay support
- Increased minimum recharge amount to `1`
- Added maximum of `9` characters for the recharge amount
- Added minimum withdraw amount setting
- Added real name field for AliPay
- Added third-party login field for AliPay
- Added maxlength of `9` characters for the withdraw amount
- Added a span tag to append '元' to the recharge amount
- Added a new function `with

[buyer/src/pages/home/userCenter/MoneyManagement.vue]
- Raise the minimum recharge amount to `1`
- Allow for a maximum of `9` characters for the recharge amount
- Added support for WeChat and AliPay
- Added a minimum withdraw amount setting
- Added a real name field for AliPay
- Added a third-party login field for AliPay
- Added maxlength of `9` characters for the withdraw amount
- Added a span tag to append '元' to the recharge amount
- Fixed typo
[buyer/src/api/pay.js]
- Add a new function `withdrawalSettingVO` for payment result inquiry
- Change the parameters for `payCallback` function
2023-03-08 21:58:29 +08:00
pikachu1995@126.com
72fb11d3d3 Merge branch 'master' into Bulbasaur 2023-03-08 18:42:17 +08:00
chc
7d0b3c6908 feat: ✨ 商家端增加修改密码,手机号登录 2023-03-08 10:25:23 +08:00
chc
f7a9bff2ba feat: ✨ 集成顺丰平台,发货,查询物流,打印面单 2023-03-06 18:00:11 +08:00
chc
4fd419fcfe Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-03-02 17:55:47 +08:00
chc
f72c28d770 fix: 🐛 关闭物流公司传递参数错误,css /deep/拼写错误 2023-03-02 17:55:36 +08:00
pikachu1995@126.com
7c775f7692 增加提现设置内容:提现方式、最低提现金额、微信提现应用ID 2023-03-02 06:52:15 +08:00
学习很差啦
ac0404adaa 补充提交im ws-socket中发现的问题 2023-03-01 17:51:43 +08:00
学习很差啦
40ccbf3edb fix: 🐛 买家端buyer im传值优化 2023-03-01 15:25:00 +08:00
学习很差啦
2aa7b67b7a Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-03-01 14:59:57 +08:00
学习很差啦
4700bc995a feat: ✨ 优化im 接口403判定,新增从买家端以及卖家端进行跳转im权限判定,新增im掉线重连以及重连成功提醒,新增发送的消息断线将会进行重新发送消息提示,优化最近浏览 订单列表空展示。注释部分im打印的日志信息 2023-03-01 14:59:54 +08:00
Chopper711
7052fa7420 !31 修复添加源时默认切换源类型不正确问题
Merge pull request !31 from Jimi/master
2023-02-28 03:32:00 +00:00
Jimi
08c62e5c9c fix:修复添加源时默认切换源类型不正确问题 2023-02-28 09:21:41 +08:00
学习很差啦
32b29f45e7 修改直播价格展示信息错误 2023-02-21 14:25:32 +08:00
学习很差啦
49d023cef0 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-02-17 11:28:29 +08:00
学习很差啦
674c2352ef feat: ✨ 新增im接口权限失效判定,优化买家显示样式以及卖家样式。 2023-02-17 11:28:26 +08:00
pikachu1995@126.com
96156508b5 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-02-16 18:16:17 +08:00
pikachu1995@126.com
802f13e6e5 存储新增:腾讯云、华为云
短信新增:腾讯云、华为云
物流新增:快递100
2023-02-16 18:15:39 +08:00
学习很差啦
5d24dda4c1 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-02-16 16:28:25 +08:00
学习很差啦
2207d11c7c 修改入驻电话校验 2023-02-16 16:28:24 +08:00
程
495096c779 im跳转问题 2023-02-16 15:57:18 +08:00
程
9375ba9e31 im金额格式化 2023-02-13 09:24:30 +08:00
程
42a24d854b im路径跳转 2023-02-09 16:34:01 +08:00
程
cc31b6232f im聊天发送中文问题 2023-02-09 15:59:08 +08:00
程
092873592d Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-02-09 15:14:05 +08:00
程
70757e8adf IM商家端不显示问题 2023-02-09 15:13:55 +08:00
Chopper711
b1fb019b01 update README.md.
Signed-off-by: Chopper711 <1814994716@qq.com>
2023-02-09 03:21:07 +00:00
15386982806
ed4f78bf6a 用户PC端,我的订单,根据订单号搜索框展示不全问题修改 2023-02-08 18:18:09 +08:00
chc
826ba41866 自提地址最下方显示问题 2023-02-03 17:26:49 +08:00
mahe
4886b53847 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-02-03 10:22:13 +08:00
mahe
56d6401cda 调整im样式,过滤数据 2023-02-03 10:22:06 +08:00
夜良king
36794613cd Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-02-03 10:06:50 +08:00
夜良king
cfd2529caf 修改错别字 2023-02-03 10:06:22 +08:00
chc
f0628c5995 失效商品导致页面不展示 2023-02-02 18:04:49 +08:00
chc
4780ae5b18 核销自提订单 2023-02-02 17:06:32 +08:00
chc
5a93abb946 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-02-01 15:03:51 +08:00
chc
d371fd0146 IM功能 2023-02-01 15:03:40 +08:00
misworga831
c850a27cca fix: 🐛 修复规格值为空后,规格错乱问题 2023-02-01 10:18:38 +08:00
chc
a97ed0c3f6 接口问题修改 2023-01-31 17:42:36 +08:00
15386982806
3c65de9912 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-01-31 17:07:36 +08:00
15386982806
c6e1cc060a 重置用户密码 2023-01-31 17:07:28 +08:00
chc
9df377677b 开启面单按钮问题 2023-01-19 17:26:31 +08:00
chc
69caf86c7e 下载问题 2023-01-19 17:25:07 +08:00
15386982806
c86d863f1d 修改积分商品回显问题 2023-01-18 11:28:46 +08:00
程
c130597e95 im商家接口问题 2023-01-13 18:16:14 +08:00
程
5d16a7a80e 转换表情 2023-01-13 10:53:39 +08:00
程
bad9f9109c im当前浏览发送问题 2023-01-12 17:10:34 +08:00
程
7e33598b8e 宽度,表情 2023-01-12 14:34:38 +08:00
lemon橪
83f145767e refactor: 修改config API_DEV为线上掩饰站点api 2023-01-12 11:07:25 +08:00
程
8ea3843d61 足迹 2023-01-11 18:24:18 +08:00
paulGao
29cc6002cd Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2023-01-11 11:29:34 +08:00
paulGao
db33b34f18 feat: 增加优惠券领取详情和优化pc端跳转使用优惠券页面 2023-01-11 11:28:28 +08:00
程
73acb0bc09 跳转样式问题 2023-01-10 18:44:39 +08:00
夜良king
94ab061cc8 config 修改 2023-01-10 18:32:26 +08:00
夜良king
4f243afb63 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2023-01-10 18:27:52 +08:00
夜良king
efd3ed26df 自动发券模块(管理端加前端展示) 2023-01-10 18:27:37 +08:00
Chopper711
e7d1664673 Merge branch 'lili_self' 2023-01-09 18:47:48 +08:00
夜良king
7b7310ed75 优惠券详情 2023-01-06 10:33:10 +08:00
夜良king
c8649caf1a 商家端 规格修改 2023-01-05 10:43:37 +08:00
程
aaa2deef85 pc发布商品不显示IM 2022-12-30 18:40:50 +08:00
夜良king
b0ed6635e5 修改发布商品模块 商品描述 请求数据删除 2022-12-30 17:24:41 +08:00
程
0dc3124bba 订单列表发送 2022-12-29 18:20:06 +08:00
程
1135c1fbc3 滚动加载样式 2022-12-28 18:32:48 +08:00
程
779f6e4fa1 滚动加载样式 2022-12-28 18:31:26 +08:00
chc
f4bf4dc060 展示问题 2022-12-28 18:23:23 +08:00
程
84d3dd247d 滚动请求 2022-12-28 14:54:57 +08:00
程
61c44af5a0 ds 2022-12-28 11:25:40 +08:00
程
e8b7a85140 聊天 2022-12-28 11:23:46 +08:00
chc
aa4dbc1bbd 商品信息展示修改 2022-12-28 11:22:54 +08:00
程
3881370b6e IM 2022-12-28 10:08:51 +08:00
程
0fa93d545e 删除IM文件夹 2022-12-28 10:08:18 +08:00
chc
a92c213b64 IM功能 2022-12-28 09:22:05 +08:00
lemon橪
fcc9a9f8c5 fix: 🐛 解决秒杀商品中分页错误,以及删除看到的冗余代码 2022-12-26 18:03:09 +08:00
夜良king
0ffd0f0c29 goolist 虚拟/实物展示问题 2022-12-26 11:48:10 +08:00
夜良king
3afad96b8f 楼层 选择链接模板修改 2022-12-23 15:31:59 +08:00
chc
d9e1a4a491 站点图标与logo分开添加与展示 2022-12-22 15:17:13 +08:00
chc
2e4246e63b 手机号搜索消失 2022-12-19 10:19:06 +08:00
Chopper711
235d582ae2 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2022-12-07 17:01:28 +08:00
程
c34e2ad6ad 楼层代码注释 2022-12-07 17:00:37 +08:00
Chopper711
78b8a002e9 楼层装修问题处理 2022-12-07 16:58:51 +08:00
夜良king
29091739d4 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-12-07 10:45:25 +08:00
夜良king
aa05ee1165 去除店铺结算已审核 2022-12-07 10:45:12 +08:00
学习很差啦
2446c28b20 补充提交api地址错误问题 2022-12-07 10:42:47 +08:00
学习很差啦
8378182730 解决合并冲突 2022-12-07 10:37:24 +08:00
学习很差啦
d84250ab88 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-12-07 10:36:17 +08:00
学习很差啦
5218388eff 删除富文本中不用的插件,新增商品上传提示 2022-12-07 10:36:15 +08:00
夜良king
984bc4b635 去除 店铺 申请中状态 2022-12-07 09:58:31 +08:00
paulGao
acc9a0b88a 补全缺失接口 2022-12-06 16:42:32 +08:00
paulGao
a31c7a5ad0 fix: 修复移动端楼层装修外部链接没有地方填写问题 2022-12-06 16:32:29 +08:00
paulGao
f0882793e4 fix: 🐛 优化批发商品,起批量提示 2022-11-29 15:00:45 +08:00
paulGao
053e5ce062 fix: 🐛 优化批发商品购买数量不能低于起批量 2022-11-29 11:40:37 +08:00
mahe
34ef7e555a 修改优惠券的宽度,浏览记录分页与评论超出问题 2022-11-28 09:51:47 +08:00
chc
34165127f0 im 2022-11-23 18:43:53 +08:00
学习很差啦
4d347df505 fix: 🐛 修改 商家端楼层装中 intro 和 mobileIntro 可能存在转义符导致json出错问题 2022-11-23 14:44:46 +08:00
chc
830154371a 自提 2022-11-22 17:17:37 +08:00
学习很差啦
69c2c4c5c2 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-11-22 15:17:14 +08:00
学习很差啦
a5d067943d fix: 🐛 商家端楼层装修选择图片问题修改,以及删除商家端搜索模块 2022-11-22 15:17:09 +08:00
Chopper711
1e190e3a88 update LICENSE.
Signed-off-by: Chopper711 <1814994716@qq.com>
2022-11-21 03:23:34 +00:00
paulGao
b042bd6052 增加可链接外部页面 2022-11-18 10:13:28 +08:00
chc
3861881996 行高问题 2022-10-28 11:27:21 +08:00
chc
405bb4a216 Merge remote-tracking branch 'origin/master' 2022-10-28 09:44:47 +08:00
chc
c382f015f4 移动装修分页无效和pc装修分页样式 2022-10-28 09:44:24 +08:00
夜良king
c083a58f30 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-10-26 16:34:46 +08:00
夜良king
a78d637468 楼层装修 2022-10-26 16:34:34 +08:00
paulGao
0cb32caa3e 优化秒杀页面样式问题 2022-10-26 15:42:08 +08:00
程
8095aa0d8e 登陆页header footer 警告 2022-10-26 11:13:43 +08:00
chc
60117f51b3 商家跳转404 2022-10-26 08:57:31 +08:00
chc
b51a5e6deb 店铺 2022-10-25 19:22:52 +08:00
chc
b9869053c2 wapList 2022-10-25 18:50:54 +08:00
chc
f1753babbe 跳转问题 2022-10-25 18:35:48 +08:00
chc
05f8defe56 配置文件 2022-10-25 17:32:49 +08:00
chc
af115c45cc 配置文件 2022-10-25 17:32:09 +08:00
学习很差啦
532fc8b2dd fix: 🐛 修改演示站点多展示专题问题 2022-10-24 11:10:33 +08:00
chc
fa8aa633bf v4.2.5 2022-10-21 11:22:56 +08:00
chc
dca8ee512f 导入提示 2022-10-20 17:30:31 +08:00
学习很差啦
50c3fd6af8 docs: 📝 更改楼层装修中商品分类模块的表述内容 2022-10-19 14:56:19 +08:00
学习很差啦
bb93be2fb1 feat: ✨ 楼层装修新增绑定分类功能 2022-10-19 11:56:08 +08:00
paulGao
17a4131bf1 fix: 修复新增首个规格项的规格值时。规格列表显示错乱问题 2022-10-14 15:43:39 +08:00
程
eb9c999a16 修改分类树形 2022-10-13 10:36:37 +08:00
学习很差啦
a70c741990 feat: 🎨 新增加专题功能 2022-10-11 17:24:37 +08:00
学习很差啦
6007dc57d5 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-10-09 18:33:32 +08:00
学习很差啦
7dfdb4f685 fix: 🐛 修改发现的代码bug 2022-10-09 18:33:30 +08:00
paulGao
0cc27f4e60 style: 优化秒杀页面显示效果 2022-10-09 16:04:25 +08:00
paulGao
163f9f26c2 fix: 🐛 修复管理端分类绑定规格无数据问题 2022-09-27 10:38:33 +08:00
学习很差啦
68ba97e590 fix: 🐛 修改扫码登录等待时间 2022-09-23 15:24:31 +08:00
学习很差啦
d36c2bdc3d fix: 🐛 解决部门中出现的bug
部门中排序代码导致页面报错不能操作
2022-09-22 09:52:42 +08:00
学习很差啦
72c64f017f Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-09-22 09:14:05 +08:00
学习很差啦
0f28a7f16c 提交微信登录不能登录问题 2022-09-22 09:14:03 +08:00
paulGao
581a1f75e1 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2022-09-21 16:29:36 +08:00
paulGao
a727001daf 适配统一接口返回值 2022-09-21 16:29:28 +08:00
学习很差啦
2f9754b2a5 优化pc二维码刷新 2022-09-21 11:07:21 +08:00
paulGao
a11452a430 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2022-09-20 19:08:16 +08:00
paulGao
7d90846960 修复添加直播商品报错问题 2022-09-20 19:07:59 +08:00
lemon橪
23e456d265 feat: 基于 @xiaochangbai 老哥的代码进行了一点样式优化
看到老哥有引入其他的qr插件,在项目里面本身自带了一个,稍微改了一下部分样式

https://gitee.com/beijing_hongye_huicheng/lilishop-uniapp/pulls/3
2022-09-16 16:37:38 +08:00
paulGao
cddd94b9e5 fix: 🐛 商品编辑时无商品类型问题 2022-09-16 10:01:08 +08:00
paulGao
685ec5f679 fix: 🐛 修复热区弹框优先级问题。优化编辑商品时,可修改分类与商品类型 2022-09-09 19:40:01 +08:00
paulGao
0933f1942e fix: 🐛 修复管理端下架商品传递undefined问题,优化秒杀展示 2022-09-09 14:30:15 +08:00
paulGao
2792df38c0 修复店铺分类可能为undefined问题 2022-09-07 17:58:14 +08:00
paulGao
62d8d121c6 优化热区展示 2022-09-07 16:38:41 +08:00
paulGao
b99db4c673 修复热区移动bug 2022-09-07 15:17:34 +08:00
paulGao
3639804d1b Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2022-09-06 19:45:13 +08:00
paulGao
f6ff0b8a12 管理端楼层装修增加热区功能 2022-09-06 19:45:02 +08:00
Chopper
a345586b25 功能测试与修改 2022-09-05 14:35:01 +08:00
学习很差啦
3d0ba486df Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-09-05 14:22:00 +08:00
学习很差啦
4651d74b7b 优化部分操作流程,修改售后显示问题,优化计量单位 商品规格添加重复问题 2022-09-05 14:21:58 +08:00
paulGao
55aa57d812 优化管理端代码结构 2022-09-02 17:51:33 +08:00
paulGao
36c4584970 修复编辑店铺时,步骤按钮不正确问题 2022-09-02 16:44:55 +08:00
paulGao
96b6565272 优化商品规格编辑 2022-09-02 11:12:02 +08:00
paulGao
8b22b73f3d 优化pc端商品详情页的优惠券展示 2022-09-02 11:00:01 +08:00
fengtianyangyang
ba91d7c26d 合并 2022-09-02 10:46:41 +08:00
paulGao
fd847944b7 还原routes 2022-09-02 10:42:12 +08:00
mahe
4ea142ea08 增加楼层专题 2022-09-02 09:30:57 +08:00
chc
2aceffc112 电子面单页面,导入商品 2022-09-01 18:52:11 +08:00
paulGao
ed59b389a5 improve code 2022-09-01 18:30:51 +08:00
paulGao
2b433cf1e8 merge code 2022-09-01 18:20:22 +08:00
paulGao
41ea3b7a88 重构商品规格编辑部分 2022-09-01 17:36:24 +08:00
paulGao
f5a452c124 重构商品规格编辑部分 2022-09-01 17:34:41 +08:00
chc
9ce3a5e916 电子面单前端页面 2022-08-31 17:27:09 +08:00
学习很差啦
248c4031c0 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-08-30 09:06:29 +08:00
学习很差啦
8715066f7c 修改部分页面展示问题 2022-08-30 09:06:27 +08:00
Chopper
5dc5cce96b 店铺详情多一个空页面问题处理 2022-08-29 16:17:25 +08:00
paulGao
f58500c4e3 优化编辑规格 2022-08-26 19:56:25 +08:00
paulGao
2041eca723 修复删除规格项问题 2022-08-25 14:05:01 +08:00
学习很差啦
db6e47fa04 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-08-18 12:44:54 +08:00
学习很差啦
116c168ed7 修改演示站点发现的问题 2022-08-18 12:44:53 +08:00
paulGao
8ff6c0414a 优化买家端订单详情页,优化卖家端、平台端优惠券显示。优化结算页无效商品提示。 2022-08-12 19:24:41 +08:00
Chopper
aaf1c172de 秒杀销售百分比展示问题 2022-08-12 10:06:45 +08:00
学习很差啦
f7c310b126 修改楼层装修判断的语法 2022-08-12 09:11:07 +08:00
paulGao
ab0db38eb2 修复管理端楼层装修符号错误问题 2022-08-11 22:06:21 +08:00
paulGao
283f4d6afa 修复订单列表查询订单类型查询无效问题 2022-08-11 20:57:30 +08:00
chc
db51df89f7 热词统计增加下方表格 2022-08-11 10:32:26 +08:00
学习很差啦
b77b4c0ef8 解决楼层装修 移动端发现的小问题 2022-08-10 19:06:19 +08:00
学习很差啦
dd67687d3a 发现 并解决了一个 移动端楼层装修拖动促销活动时候出现的bug 2022-08-10 17:54:17 +08:00
学习很差啦
61f5dde015 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-08-04 14:40:55 +08:00
学习很差啦
0355dcddde 新增商家发布商品同步描述按钮 2022-08-04 14:40:50 +08:00
Chopper
1d6a61d5d9 店铺修改密码接口调整 2022-08-04 11:19:22 +08:00
学习很差啦
bf393181b8 补充提交 2022-08-03 18:32:16 +08:00
学习很差啦
79ff1cecb4 修改楼层装修判断失误导致误出现Bug 2022-08-03 18:31:00 +08:00
学习很差啦
0d21c87816 修改发现的bug 2022-08-03 15:18:06 +08:00
学习很差啦
c281b0a867 优化退款消息提示 2022-08-03 11:20:07 +08:00
OceansDeep
bd322709f3 修复多次选择积分商品信息有误 2022-07-28 07:42:06 +00:00
Chopper711
bc4f9527d0 !26 去除router.js中重复的路由
Merge pull request !26 from master
2022-07-20 01:09:27 +00:00
胡程
0b5e7c40b0 去掉fix:router.js中重复路由 2022-07-19 17:51:22 +08:00
学习很差啦
8d5f4db494 修改pc足迹以及nav显示遮罩问题 2022-07-19 16:28:40 +08:00
lemon橪
4ecb41e9a2 merge paulGao commit 2022-07-14 10:38:52 +08:00
lemon橪
dba167738b 优化商家对账时点击切换可能出现的问题 2022-07-14 10:38:07 +08:00
OceansDeep
c1853fd4e0 !25 修复pc端楼层装修外部链接无法填写
Merge pull request !25 from OceansDeep/dev-gl
2022-07-13 13:05:58 +00:00
paulGao
75ef173c64 修复pc端楼层装修外部链接无法填写 2022-07-13 20:00:41 +08:00
Chopper
752c1086a0 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2022-07-13 19:06:42 +08:00
Chopper
6c5994202b 增加minio配置前端访问地址 2022-07-13 19:06:28 +08:00
lemon橪
00e229e7f4 新增退款失败错误提示 2022-07-13 18:12:30 +08:00
lemon橪
4674cfae37 merge 2022-07-13 09:38:58 +08:00
lemon橪
eeadfc1db9 新增移动端公告横纵向设置,我的足迹以及秒杀活动展示优化 2022-07-13 09:37:59 +08:00
Chopper711
34788d800e 足迹未能正常展示问题处理 2022-07-13 01:15:42 +00:00
lemon橪
954cd1cda9 修改分销中展示问题 2022-07-08 18:52:03 +08:00
lemon橪
f3ef286aa7 修改分销订单显示问题 2022-07-08 14:48:23 +08:00
lemon橪
7874931b1f 修改win上商品详情展示优化 2022-07-08 11:48:12 +08:00
lemon橪
c3b3e7bb61 合并master 2022-07-08 11:13:11 +08:00
lemon橪
12839eee8d 解决秒杀活动可能在首页出现的bug 2022-07-08 11:12:13 +08:00
Chopper
601a2e8d33 PC端分销用户绑定关系接口问题处理 2022-07-08 09:34:45 +08:00
mhhhh
a3fe3a3743 修改隐私协议的判断 2022-07-07 18:25:27 +08:00
lemon橪
86fa39d7af 合并master 2022-07-06 17:33:08 +08:00
lemon橪
a785718715 修改回收站不能修改用户信息问题 2022-07-06 17:31:12 +08:00
OceansDeep
d4eb17e573 !24 优化逻辑
Merge pull request !24 from OceansDeep/dev-gl
2022-07-06 08:43:21 +00:00
paulGao
994b700892 优化逻辑 2022-07-06 16:18:09 +08:00
mhhhh
317bf1cd47 增加商家后台打印发货单 2022-07-06 15:18:56 +08:00
lemon橪
8327639c23 优化看到的富文本大小问题 2022-07-05 18:27:01 +08:00
lemon橪
c1830df1a2 修改优化 2022-07-05 18:24:14 +08:00
lemon橪
590ceaf641 合并merge 2022-07-05 18:04:22 +08:00
lemon橪
c7b739e546 更换editor,可支持拖拽式上传 2022-07-05 18:04:04 +08:00
OceansDeep
42db858d61 !23 优化订单投诉显示
Merge pull request !23 from OceansDeep/dev-gl
2022-07-05 01:58:13 +00:00
paulGao
85349a197f 优化订单投诉显示 2022-07-04 18:36:05 +08:00
lemon橪
8ef3510c4b 修改pc显示商品详情图片问题 2022-07-04 18:33:40 +08:00
mhhhh
8d6fa2f19f 去掉隐私协议中的排序,分类 2022-06-30 10:25:38 +08:00
Chopper711
af975b9f46 update README.md. 2022-06-23 01:45:56 +00:00
OceansDeep
3de928ee14 !22 优化管理端促销相关文本,操作条件;优化k8s部署提交
Merge pull request !22 from OceansDeep/dev-gl
2022-06-22 02:56:27 +00:00
paulGao
0a5563e5e2 优化管理端促销相关文本,操作条件 2022-06-22 10:55:17 +08:00
paulGao
f4b7068cd6 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui into dev-gl 2022-06-22 10:20:06 +08:00
lemon橪
2cb6f04465 更改统计图关键字 2022-06-21 16:57:32 +08:00
lemon橪
037a307ed1 pc端分销问题 2022-06-21 16:51:39 +08:00
lemon橪
cd81a6afb1 合并master 2022-06-17 18:50:54 +08:00
lemon橪
f930d73a6a 商品选择器显示零售商品批发商品 2022-06-17 18:50:30 +08:00
paulGao
23bae9efd5 优化k8s部署提交 2022-06-16 14:08:46 +08:00
OceansDeep
2880c21a26 !21 优化代码
Merge pull request !21 from OceansDeep/dev-gl
2022-06-16 01:24:18 +00:00
paulGao
274ac3f155 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui into dev-gl 2022-06-16 09:21:29 +08:00
paulGao
c85d488de4 优化代码 2022-06-16 09:21:14 +08:00
lemon橪
92d58ea7e5 合并paulGao代码 2022-06-15 18:49:34 +08:00
lemon橪
9a3d202524 优化统计图显示 2022-06-15 18:48:43 +08:00
OceansDeep
ba71eaeaaf !20 适配优化的sql,将平台id改为0
Merge pull request !20 from OceansDeep/dev-gl
2022-06-08 08:16:55 +00:00
paulGao
273fdf2e84 适配优化的sql,将平台id改为0 2022-06-08 15:40:23 +08:00
lemon橪
59cfa0efb0 合并master 更改并提交内容 2022-06-07 10:22:42 +08:00
lemon橪
14d720beed 商家端刷新token 路径修改 2022-06-07 10:22:11 +08:00
Chopper
2dcfacd431 适配minio 2022-06-07 09:37:53 +08:00
mhhhh
71690cfd8f 修改title闪现undefined 2022-06-06 16:08:58 +08:00
Chopper
d2c2da25b4 消费积分设置问题 2022-06-02 09:29:19 +08:00
mhhhh
c3c29af8c7 吧配送模版费用为0的限制去掉 2022-06-01 13:56:29 +08:00
mhhhh
e5f9f81ef7 解决冲突 2022-06-01 10:26:41 +08:00
mhhhh
0c0c903529 修改商家logo没有更换的问题 2022-06-01 10:13:53 +08:00
OceansDeep
115fa87ff2 !19 管理端商品详情增加批发商品信息展示
Merge pull request !19 from OceansDeep/dev-gl
2022-06-01 01:15:27 +00:00
paulGao
bb40364aed 管理端商品详情增加批发商品信息展示 2022-06-01 09:04:36 +08:00
lemon橪
0e921de6c3 合并master 2022-05-31 11:17:29 +08:00
lemon橪
58eeed4bbd 解决商品分类控件-添加一个品种后重复添加问题 2022-05-31 11:17:05 +08:00
mhhhh
21289f5a92 修改logo缓存 2022-05-31 11:04:40 +08:00
mhhhh
0aec486291 修改logo接口缓存 2022-05-31 09:51:43 +08:00
OceansDeep
5c34245ba4 !18 修复编辑sku时,单独编辑的sku图片没有保存问题
Merge pull request !18 from OceansDeep/dev-gl
2022-05-30 06:45:42 +00:00
paulGao
3d0a202cbe 修复编辑sku时,单独编辑的sku图片没有保存问题 2022-05-30 14:44:36 +08:00
OceansDeep
66143deb0d !17 增加批发商品的标识
Merge pull request !17 from OceansDeep/dev-gl
2022-05-27 10:28:17 +00:00
paulGao
2111020f62 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui into dev-gl 2022-05-27 18:27:20 +08:00
lemon橪
160658cfb6 批发商品部分 2022-05-27 18:20:42 +08:00
lemon橪
8a7f9b2487 批量商品价格展示 2022-05-27 18:16:12 +08:00
paulGao
85061ed2f8 增加批发商品的标识 2022-05-27 18:12:19 +08:00
paulGao
3405cf68bb 优化生成价格区间 2022-05-27 16:28:26 +08:00
paulGao
ebacb58049 商品搜索优化 2022-05-27 16:07:54 +08:00
paulGao
8873f575db 商品搜索和列表显示增加销售模式 2022-05-27 15:49:27 +08:00
paulGao
994ef217ac add wholesale of sale model 2022-05-27 15:23:10 +08:00
paulGao
1bda042bc9 add wholesale of sale model 2022-05-27 15:22:36 +08:00
lemon橪
e97dbe1c90 批量价格显示的样式 2022-05-27 10:28:37 +08:00
lemon橪
f19071542a 添加vuex cdn 2022-05-24 14:21:10 +08:00
lemon橪
50836e0aa3 删除已发现的冗余内容 2022-05-23 14:17:36 +08:00
lemon橪
1b4c05f70b 修改高德地图key更新此commit 之前请务必确认一下创建的高德key日期。修改部分方法名称 2022-05-20 16:40:09 +08:00
lemon橪
32dffe96ed 修改axios为19.2链接 2022-05-20 15:42:23 +08:00
lemon橪
e2df32d906 补充提交 2022-05-20 15:11:26 +08:00
lemon橪
9eab3b261e 合并seller 2022-05-20 14:42:43 +08:00
lemon橪
1e40e2d557 修改axios版本 2022-05-20 14:42:11 +08:00
OceansDeep
256ada983b !16 优化商品sku编辑,不在清空数据。commit v1
Merge pull request !16 from OceansDeep/dev-gl
2022-05-19 09:32:57 +00:00
paulGao
cd0c90ace8 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui into dev-gl 2022-05-19 17:30:32 +08:00
paulGao
913b96af5a 优化商品sku编辑,不在清空数据。commit v1 2022-05-19 17:22:22 +08:00
lemon橪
a3f5212bbc 删除被墙的cdn 启用pickmall cdn加载资源 2022-05-19 15:51:32 +08:00
lemon橪
9d7a06e867 优化管理端代办事项 2022-05-19 09:13:16 +08:00
mhhhh
48f3c38fbd 修改获取logo接口地址 2022-05-18 21:53:32 +08:00
lemon橪
706bab7eff 修改buyer端发现的问题 2022-05-17 17:27:19 +08:00
mhhhh
b6fa3175c6 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2022-05-17 09:19:58 +08:00
mhhhh
3cd57a6915 隐私协议菜单,店铺详情店铺详情非空判断,自定义logo 2022-05-17 09:19:36 +08:00
lemon橪
d433ff02cb 首页历史统计新增 历史记录对比 2022-05-13 14:17:33 +08:00
lemon橪
68d2c25ff5 合并提交 2022-05-12 15:46:55 +08:00
lemon橪
9ccf51dd5c 优化商品发布规格丢失问题 新增修改删除规格值不丢失 2022-05-12 15:36:59 +08:00
mhhhh
727d240715 git stashMerge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2022-05-12 10:44:17 +08:00
mhhhh
1f4448ba08 增加打印发货单功能,隐藏配送信息,删除腾讯云智能客服 2022-05-12 10:33:02 +08:00
OceansDeep
6064c168bf !15 修复秒杀已售数量不正确问题
Merge pull request !15 from OceansDeep/dev-gl
2022-05-12 01:10:44 +00:00
fengtianyangyang
479470832d 结算单修改 2022-05-11 19:18:04 +08:00
paulGao
71fa00c267 修复秒杀已售数量不正确问题 2022-05-11 16:11:59 +08:00
OceansDeep
c1331e8ccf !14 add build.sh
Merge pull request !14 from OceansDeep/dev-gl
2022-05-10 07:58:11 +00:00
paulGao
8a2ec77c84 add build.sh 2022-05-10 15:57:30 +08:00
lemon橪
b197cda548 合并分支 2022-05-09 18:38:48 +08:00
lemon橪
c83eddd62e 优化订单统计 2022-05-09 18:37:53 +08:00
OceansDeep
46168a037d !13 修复秒杀活动页已售数量问题
Merge pull request !13 from OceansDeep/dev-gl
2022-05-09 07:11:47 +00:00
paulGao
cbb2365ae8 修复秒杀活动页已售数量问题 2022-05-09 14:32:00 +08:00
OceansDeep
ec3093246a !12 修复bug
Merge pull request !12 from OceansDeep/dev-gl
2022-05-05 01:32:18 +00:00
paulGao
670ba74044 修复bug 2022-05-05 09:30:42 +08:00
学习很差啦
84e0803558 !9 修复查看满额活动详细后点击返回键找不到路由返回白屏问题
Merge pull request !9 from Assure/master 感谢Assure发现的返回白屏问题 此处接受并提交
2022-04-28 08:19:02 +00:00
ran
1691f8244f 修改账户昵称过长问题以及viper 在pr上提的Bug 2022-04-28 16:13:36 +08:00
Chopper
24f4a36082 流水信息退款单中展示更多细节 2022-04-26 11:14:57 +08:00
胡程
7cf7123dd2 fix:修复查看满额活动详细后点击返回键找不到路由返回白屏问题 2022-04-26 10:05:11 +08:00
Chopper
37064141c2 Merge branch 'dev-lmr'
# Conflicts:
#	manager/src/views/page/article-manage/hotWords.vue
2022-04-25 19:00:25 +08:00
Chopper
5bd66b9ec6 还原接口api 2022-04-25 18:16:06 +08:00
Chopper
9e34b44165 热词功能补充提交 2022-04-25 18:09:49 +08:00
Chopper
8d9a64d84b 热词功能完善 2022-04-25 18:08:29 +08:00
yeliang-king
92aafe3031 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-04-25 14:50:11 +08:00
yeliang-king
81f4f4a742 接口更改 2022-04-25 14:49:57 +08:00
lemon橪
9b14cd633e 热词部分代码 2022-04-25 09:18:31 +08:00
OceansDeep
118aaaf6fb !8 修复结算页中有无效商品店铺显示问题。优化购物车页。管理端增加搜索热词全删除
Merge pull request !8 from OceansDeep/dev-gl
2022-04-22 08:50:00 +00:00
paulGao
0635dd38a2 修复结算页中有无效商品店铺显示问题。优化购物车页。管理端增加搜索热词全删除 2022-04-22 16:48:43 +08:00
fengtianyangyang
1d648bbad7 结算单页面修改 2022-04-22 09:04:20 +08:00
OceansDeep
5dfcc2482c !7 优化楼层装修,修复结算页显示失效商品问题
Merge pull request !7 from OceansDeep/dev-gl
2022-04-21 08:27:40 +00:00
paulGao
7ff51b5e53 修复结算页显示失效商品问题 2022-04-21 16:11:11 +08:00
paulGao
c4168c9a2b 优惠移动端楼层装修 2022-04-21 14:57:33 +08:00
fengtianyangyang
7312b3ec3f 店铺结算单修改 2022-04-18 19:10:46 +08:00
fengtianyangyang
c09e25974f 结算单修改 2022-04-18 19:10:10 +08:00
paulGao
744567e8de 优化楼层装修 2022-04-18 09:49:09 +08:00
paulGao
4156d51d78 优化楼层装修 2022-04-18 09:38:52 +08:00
yeliang-king
0faae31b2e Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-04-18 09:18:08 +08:00
yeliang-king
79a719e7ff 取消横向滚动条 2022-04-18 09:15:08 +08:00
lemon橪
0d09920314 修复楼层装修选择链接时可能出现的bug 2022-04-18 09:01:09 +08:00
lemon橪
d641123987 新增商家商品模版显示分页显示 2022-04-13 14:34:34 +08:00
lemon橪
ce871a804c 合并提交 2022-04-13 10:42:05 +08:00
lemon橪
36fd58a446 解决短信模版页面分页条件不显示问题 2022-04-13 10:40:45 +08:00
pikachu
9e0a681e01 buyer端的导航条下拉 2022-04-12 18:03:31 +08:00
lemon橪
df408e640a 合并master 2022-04-08 17:31:14 +08:00
lemon橪
f365231ee7 提交高德api中更新安全密钥的提示 2022-04-08 17:29:28 +08:00
paulGao
2e8d124560 修复pc端订单详情不展示发票信息 2022-04-08 15:32:18 +08:00
paulGao
1e8279c849 improve code 2022-03-31 09:26:24 +08:00
paulGao
48668fd2d4 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2022-03-29 17:58:47 +08:00
paulGao
ee5539fb0f 修复pc搜索商品分类参数无效问题 2022-03-29 17:57:42 +08:00
pikachu
97d88abf80 溢出 滚动显示 2022-03-28 18:21:44 +08:00
pikachu
9a33db76e9 楼层装修 问题 2022-03-22 10:14:31 +08:00
Chopper
65aa9d0a9f Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2022-03-18 17:41:33 +08:00
Chopper
baaeef0978 管理端无法修改会员信息问题处理 2022-03-18 17:41:29 +08:00
lemon橪
e27070e089 优化一个上传组件控制台报错bug 以及 buyer端楼层装修显示 2022-03-17 16:35:10 +08:00
pikachu
2ea2723aed 样式 问题 2022-03-16 11:31:05 +08:00
pikachu
5188bba5b1 会员流量报表 名称修改 2022-03-15 11:46:49 +08:00
lemon橪
33bb16a0d3 修改菜单栏重复点击console会显示bug , 以及行政地区不回显问题 2022-03-04 15:12:37 +08:00
夜良king
87f6b81e37 合并 2022-03-04 02:31:56 +08:00
lemon橪
3b4f0b8c9d 修改店铺 2022-03-03 11:33:53 +08:00
lemon橪
3b540b1aac 提交补漏 2022-03-03 11:31:23 +08:00
lemon橪
378ac39315 商家楼层装修 2022-03-03 11:26:50 +08:00
lemon橪
2dac958227 更改买家提交售后显示的价格 2022-03-02 15:21:28 +08:00
lemon橪
c879cb2af0 优化订单详情中显示的价格问题 2022-03-02 15:02:18 +08:00
夜良king
32336decc6 动态导航 2022-02-27 18:24:35 +08:00
夜良king
7cd64553ab chongtu 2022-02-26 15:35:04 +08:00
夜良king
6e737a3fa7 解决冲突 2022-02-26 15:27:10 +08:00
fengtianyangyang
25b403cde9 冲突文件 2022-02-26 15:05:51 +08:00
fengtianyangyang
535a36c378 ‘合并 2022-02-23 21:24:18 +08:00
fengtianyangyang
7b30bc42d7 添加 2022-02-23 20:56:00 +08:00
lemon橪
403ae0a963 修改管理端会员详情缺少前缀问题 2022-02-23 16:16:29 +08:00
lemon橪
800b91d406 修改会员信息少一个前缀问题 2022-02-23 16:15:37 +08:00
Chopper
bf92b0804e 修改会员API路径调整导致无法修改会员信息问题处理 2022-02-23 16:00:37 +08:00
Chopper
7e8ff778f9 商家增加im按钮 2022-02-22 01:32:36 +08:00
Chopper
31f438edfa IM更新 2022-02-21 22:45:39 +08:00
zhenghao
a7ed6454af clerk 2022-02-17 16:37:11 +08:00
夜良king
12ea0c2b84 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-02-17 10:44:14 +08:00
paulGao
44086e8bf4 修改api 2022-02-17 15:32:56 +08:00
paulGao
b740a6f906 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2022-02-17 14:54:30 +08:00
paulGao
7376d4d890 修复api错误 2022-02-17 14:54:18 +08:00
夜良king
f9d09365ea 部分bug 2022-02-17 10:43:46 +08:00
夜良king
81297db7a8 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-02-16 11:37:50 +08:00
夜良king
b5ca94ab98 楼层装修 分页 2022-02-16 11:37:00 +08:00
lemon橪
a220339fd6 合并内容 2022-02-16 11:26:01 +08:00
lemon橪
0994b6659a 合并部分代码 回滚规格 2022-02-16 11:22:35 +08:00
夜良king
c4037a346d 修改样式 和 优化一些 功能 2022-02-16 09:25:01 +08:00
lemon橪
45a6e76d4a 需改pc样式上的bug 2022-02-15 16:54:36 +08:00
paulGao
aee67ec317 修改版本号 2022-02-15 14:08:04 +08:00
夜良king
51610546c4 重新修改config 2022-02-15 10:17:19 +08:00
夜良king
e8e7d27c0d Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-02-15 10:12:53 +08:00
夜良king
166e889b6f commit 2022-02-15 10:12:49 +08:00
paulGao
db95647cd8 修复管理端刷新tokenapi错误问题 2022-02-15 10:03:14 +08:00
lemon橪
db13814156 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2022-02-14 17:10:45 +08:00
lemon橪
5cf3956bc8 取消cdn加载 2022-02-14 17:10:40 +08:00
OceansDeep
329e6df722 !6 适配接口路径修改
Merge pull request !6 from OceansDeep/fengtianyangyang
2022-02-14 07:51:16 +00:00
paulGao
8023852b3c 升级版本号 2022-02-14 15:35:01 +08:00
paulGao
228935034d 适配api 2022-02-14 14:21:37 +08:00
paulGao
acff55dc65 适配修改后的api 2022-02-12 15:20:36 +08:00
paulGao
61a9110c51 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui into fengtianyangyang 2022-02-11 16:44:27 +08:00
paulGao
3a3e14e0a7 适配微服务 2022-02-10 18:57:36 +08:00
lemon橪
6ba767419e 新增文库详情页面,转门为审核使用 2022-02-10 17:13:26 +08:00
lemon橪
925365018b 优化商家发布商品丢失规格问题,修改开启cdn 2022-02-10 14:26:53 +08:00
lemon橪
5960df31bd 合并并提交修改 2022-02-09 20:50:09 +08:00
lemon橪
21f9fd92e2 取消cdn加载 2022-02-09 20:49:49 +08:00
paulGao
9765310136 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui into fengtianyangyang 2022-02-09 10:32:50 +08:00
paulGao
51cde2dd0d fix bugs 2022-01-27 14:58:37 +08:00
fengtianyangyang
3311568e50 修改路径 2022-01-25 19:08:47 +08:00
fengtianyangyang
e5918b041a 路径修改 2022-01-25 12:01:40 +08:00
paulGao
f46330ecf0 Merge branch 'fengtianyangyang' of gitee.com:beijing_hongye_huicheng/lilishop-ui into fengtianyangyang 2022-01-25 09:46:15 +08:00
paulGao
846e80f1fa 适配微服务版本 2022-01-25 09:46:12 +08:00
fengtianyangyang
631519d7c7 路径修改 2022-01-25 09:22:22 +08:00
paulGao
bbeb31e8a3 修复店铺和平台优惠券同时选择时,显示问题 2022-01-21 19:02:09 +08:00
paulGao
52bcf07e25 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2022-01-21 16:53:28 +08:00
paulGao
4d725221a5 优化店铺搜索栏 2022-01-21 16:53:16 +08:00
Chopper
c8a0619141 积分设置优化 2022-01-21 16:20:15 +08:00
fengtianyangyang
e1d7b1801d 接口修改 2022-01-21 09:14:21 +08:00
paulGao
15456ae377 修复删除会员评论,弹出框不关闭问题 2022-01-20 17:40:05 +08:00
fengtianyangyang
1c3d711298 路径修改 2022-01-20 17:21:30 +08:00
paulGao
1bee69cefb 优化管理端和卖家端登录 2022-01-17 18:00:49 +08:00
paulGao
cf740d9605 修复富文本编辑器xss过滤样式问题 2022-01-17 16:49:55 +08:00
paulGao
d2aca24d06 优化申请售后退货 2022-01-04 19:57:40 +08:00
paulGao
6e042c4b78 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2022-01-04 09:21:03 +08:00
paulGao
1afd1704ab 修复pc显示促销价格问题 2022-01-04 09:21:00 +08:00
夜良king
d5f81fe5d8 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2021-12-31 18:23:05 +08:00
夜良king
fada0a735f 修改样式 和查看虚拟实物 2021-12-31 18:22:30 +08:00
夜良king
35de0c031d 样式加 虚拟实物查看 2021-12-31 18:22:06 +08:00
lemon橪
2e5eefc079 提交 buyer和seller退出uuid清空bug 2021-12-30 11:16:08 +08:00
学习很差啦
1fa264b0bf !5 修复登出账号、修改密码等操作会清除uuid的bug 感谢大佬ray 提出的pr
Merge pull request !5 from master
2021-12-30 03:06:29 +00:00
zhanglei829
d2a0940858 修复登出账号、修改密码等操作会清除uuidbug 2021-12-30 10:13:34 +08:00
paulGao
4ff8eb6494 修复优化拼团 2021-12-29 19:50:24 +08:00
paulGao
8ca87cdb2a Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2021-12-28 19:54:58 +08:00
paulGao
f45b115355 修复满额活动赠送积分不显示填写积分。商品规格默认项无法退格删除。权限菜单选择某一子项获取选择全部问题 2021-12-28 19:54:40 +08:00
夜良king
7490211340 修改了小样式 按钮 2021-12-28 18:33:47 +08:00
夜良king
76d028277a buyer一些样式和一个弹框 2021-12-28 17:51:23 +08:00
lemon橪
0a0066fe5c Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2021-12-27 16:16:27 +08:00
lemon橪
4f7e38db3b 修改移动端楼层装修文章地址 2021-12-27 16:16:26 +08:00
paulGao
54dcd2d8be 修复优化促销问题 2021-12-25 18:36:15 +08:00
paulGao
6c1d7cce8d Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2021-12-25 17:05:19 +08:00
lemon橪
06b090cdf6 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2021-12-25 10:59:02 +08:00
lemon橪
3653b4e7cb 优化buyer底部信息,优化购物车显示规格数量可能导致的bug 新增订单物流显示 2021-12-25 10:59:00 +08:00
paulGao
c6c890da63 修复拼团排序问题 2021-12-24 16:55:30 +08:00
paulGao
75e7bc2d9c 优化搜索热词管理 2021-12-24 16:09:57 +08:00
paulGao
649f983990 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2021-12-23 21:20:52 +08:00
paulGao
193628913a 优化店铺详情页 2021-12-23 21:20:37 +08:00
lemon橪
cb304d7d53 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2021-12-23 19:02:30 +08:00
lemon橪
4bb7bd4603 buyer端 部分颜色优化以及部分间距优化 2021-12-23 19:02:29 +08:00
paulGao
1e408eb8ae 修复管理端积分商品问题 2021-12-23 17:11:30 +08:00
Chopper
d762d18c7b 将支付应用id分别配置 2021-12-23 11:58:09 +08:00
Chopper
3622c7bb53 pc订单详情无法跳转商品详情页面问题处理 2021-12-22 18:29:29 +08:00
paulGao
1b9b2d9c95 适配字段变化 2021-12-22 10:50:43 +08:00
paulGao
0d5c60ed8c Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2021-12-21 18:59:57 +08:00
paulGao
ab2bcb515f 优化促销相关代码 2021-12-21 18:59:45 +08:00
lemon橪
b3e6eb72eb 新增npmrc以及yarnrc文件,修改config配置变成可配置的cdn加载以及端口设置 2021-12-21 16:30:54 +08:00
lemon橪
9742aaf0bc udesk 技术储备方案 2021-12-20 17:37:22 +08:00
lemon橪
bc1942c492 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2021-12-20 16:48:10 +08:00
lemon橪
44facf549a 提交udesk方案 2021-12-20 16:48:08 +08:00
eeer
09dd9861fd update seller/vue.config.js. 统一取消cdn加载 目前cdn链接的https请求挂了 2021-12-20 06:31:42 +00:00
eeer
8d3b5cf91d update manager/vue.config.js. 统一取消cdn加载 目前cdn链接的https请求挂了 2021-12-20 06:31:08 +00:00
eeer
5a90567e98 update buyer/vue.config.js. 统一取消cdn加载 目前cdn链接的https请求挂了 2021-12-20 06:30:40 +00:00
lemon橪
246ba9057f 删除最低购买金额 2021-12-16 13:41:57 +08:00
lemon橪
9eecc603db Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2021-12-13 19:27:23 +08:00
lemon橪
1fe4078115 化楼层装修中商品分类判断 2021-12-13 19:27:20 +08:00
paulGao
ef73a6fe94 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2021-12-11 13:51:33 +08:00
paulGao
edef393535 适配重构促销 2021-12-11 13:50:58 +08:00
Chopper
97e6fc79ea Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2021-12-09 20:21:49 +08:00
Chopper
0b82ae7569 商家设置坐席id代码补充 2021-12-09 20:21:46 +08:00
lemon橪
3cb0e52ca0 优化楼层装修中商品分类代码可能会出现的bug . 如果更新此版本建议同步更新uni版本更新 2021-12-09 18:32:11 +08:00
lemon橪
fd1d32d431 管理端优惠券判断优化 2021-12-03 10:00:23 +08:00
lemon橪
8c169489eb 修改统计中发现的bug 2021-11-30 17:15:37 +08:00
lemon橪
6ecb6b8055 修改部分冗余代码,新增商家端npmrc配置 后续还会新增yarnrc 2021-11-22 11:16:32 +08:00
lemon橪
515cd3ebbd 新增部分售后判断 2021-11-18 18:07:58 +08:00
lemon橪
6c6b89f512 优化buyer端配置信息完善性 2021-11-18 17:10:44 +08:00
lemon橪
1ac5dcfe25 Merge branch 'master' of https://gitee.com/beijing_hongye_huicheng/lilishop-ui 2021-11-18 14:51:46 +08:00
lemon橪
ccd5decbf7 优化楼层装修 pc端中控制台因类型转换问题导致的报错信息 2021-11-18 14:51:44 +08:00
paulGao
9a12a29127 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2021-11-17 16:39:38 +08:00
paulGao
8d96a3c106 管理端增加退出登录 2021-11-17 16:39:24 +08:00
lemon橪
41bfd17cd0 pc端物流日志 2021-11-16 11:02:59 +08:00
paulGao
5614414185 add logout 2021-11-11 18:45:53 +08:00
lemon橪
7ac4010910 修改规格样式问题 2021-11-09 15:53:11 +08:00
lemon橪
ffc5af6d39 修改商品中参数可能出现的bug 2021-11-09 15:38:45 +08:00
lemon橪
c64f00fe9e merge master 2021-11-05 16:16:56 +08:00
lemon橪
d3a49f3f3e 修改商品参数中部分bug 2021-11-05 16:16:28 +08:00
paulGao
06c6abe250 修复售后订单loading 2021-11-05 10:49:08 +08:00
chopper711
f54739e337 update README.md. 2021-11-02 08:04:19 +00:00
lemon橪
cdc673da06 删除无用数据 2021-10-28 16:27:59 +08:00
Chopper
0bd99df26a 后台查阅消息,跳转分销提现页面内容问题处理 2021-10-27 10:56:25 +08:00
chopper711
0dcee2f2e2 !4 PC显示发票信息问题处理,结算页面商品宽度调整,后台发票开具条件增加已发货可以开具发票的按钮
Merge pull request !4 from chopper711/lifenlong
2021-10-26 02:40:06 +00:00
Chopper
f7f836f5fd PC显示发票信息问题处理,结算页面商品宽度调整,后台发票开具条件增加已发货可以开具发票的按钮 2021-10-26 10:38:41 +08:00
lemon橪
16d1576c10 秒杀金额显示问题 2021-10-22 15:11:18 +08:00
lemon橪
0d1dbd0350 修改语言插件 2021-10-21 17:50:34 +08:00
lemon橪
18ea8a4366 语言设定小插件 2021-10-21 15:48:03 +08:00
lemon橪
b9aa720bea 修改秒杀添加商品可能出现的bug 2021-10-21 14:09:00 +08:00
lemon橪
28473979ec 合并master 2021-10-19 16:41:03 +08:00
lemon橪
dbe5a21f4d 修改buyer api路径 将buyer manager seller 统一为 public/config下修改api地址,新增buyer底部 公司,备案号等信息展示,修改商家端seller秒杀bug以及部分issue中的优化方案 2021-10-19 16:40:43 +08:00
Chopper
31d9859f10 表单校验几个细节问题 2021-10-19 14:20:20 +08:00
lemon橪
7cbd2b698c 优化劵活动优惠券代码 2021-10-15 18:38:29 +08:00
lemon橪
6fa3fa7822 优化砍价逻辑,以及修改劵活动Bug 2021-10-12 18:06:52 +08:00
lemon橪
e80316d43d 修复管理后台es分词报错问题 2021-10-09 09:29:30 +08:00
paulGao
9979b6fd67 修复管理员添加密码验证 2021-10-08 14:56:25 +08:00
OceansDeep
a36a4cd244 !3 修复设置限时抢购活动无时间显示bug
Merge pull request !3 from OceansDeep/dev-gl
2021-10-08 03:38:51 +00:00
paulGao
f99e2673a6 修复设置限时抢购活动无时间显示bug 2021-10-08 11:37:11 +08:00
lemon橪
47da7d3b16 管理端新增文章时删除全部选项 2021-10-06 17:01:30 +08:00
lemon橪
4f2f6e8d20 优化楼层装修样式问题,以及退单金额显示,删除砍价批量删除商品功能 2021-09-29 16:04:24 +08:00
lemon橪
4da164dcba 优化商品发布规格校验,后续会优化规格详情中添加规格以前数据消失问题 2021-09-26 18:02:26 +08:00
lemon橪
1aab8aa8c8 合并shuai分支 优化正则校验以及商品发布中样式 ,后续会优化商品发布中规格问题 2021-09-26 16:37:53 +08:00
lemon橪
8a2a946bc1 合并shuai分支 优化正则校验以及商品发布中样式 ,后续会优化商品发布中规格问题 2021-09-26 16:36:57 +08:00
Chopper
038de5ed53 商品详情管理端,字段优化问题处理 2021-09-26 16:19:53 +08:00
Chopper
0bac362c95 Merge branch 'liushuai'
大部分为参数校验问题,以及部分商品字段优化
# Conflicts:
#	buyer/src/config/index.js
#	manager/src/config/index.js
#	seller/src/views/goods/goods-seller/draftGoods.vue
2021-09-26 16:12:24 +08:00
Chopper
04599148fc 文章分类,积分设置删除后无法新增问题处理 2021-09-26 16:07:50 +08:00
lemon橪
b61faef093 管理端删除基础配置 2021-09-26 14:49:41 +08:00
Chopper
642536f83e 校验问题处理 2021-09-26 14:49:19 +08:00
Chopper
7ebb5e21d2 各种页面校验功能补充优化 2021-09-24 18:19:09 +08:00
OceansDeep
0c18a0f6db !2 修复楼层装修选择店铺,店铺开启状态不正确
Merge pull request !2 from OceansDeep/dev-gl
2021-09-24 08:40:41 +00:00
paulGao
93768e4014 reset config 2021-09-24 16:39:24 +08:00
paulGao
3674b63db4 reset config 2021-09-24 16:38:27 +08:00
paulGao
9e8f369da4 reset config 2021-09-24 16:37:33 +08:00
paulGao
04cc8b991c reset config seller 2021-09-24 16:34:42 +08:00
paulGao
0342f1d17a fix dialog template shops storeDisable show error 2021-09-24 16:32:23 +08:00
paulGao
82838a5ebb Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui into dev-gl 2021-09-24 15:49:00 +08:00
Chopper
20042786aa 商品模块代码继续完善,表单校验等 2021-09-22 15:32:47 +08:00
lemon橪
2037b57a5d 优化管理端商家端冗余以及配置内容。抽出公共主题颜色、站点标题等内容。分离config中api配置,修改商家发布中拖拽以及控制台出错的bug。 2021-09-22 15:08:34 +08:00
Chopper
2932c7f35d 参数校验相关提交 2021-09-22 12:16:22 +08:00
lemon橪
53cc6f46d1 修改buyer端购物车显示bug 2021-09-17 18:26:24 +08:00
paulGao
a5e2ae9a4d Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui into dev-gl 2021-09-17 17:19:48 +08:00
lemon橪
95beebc5c7 合并master 2021-09-17 17:16:30 +08:00
lemon橪
f7b8713be1 解决商家端 商家列表报错问题 2021-09-17 17:16:15 +08:00
Chopper
c33d10734f im 页面声明 2021-09-17 11:03:09 +08:00
Chopper
edde94af69 IM 设置 2021-09-17 11:01:57 +08:00
Chopper
fbf2b6a6fa Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui 2021-09-16 16:22:36 +08:00
Chopper
b84f1b595e 镜像相关提交 2021-09-16 16:22:13 +08:00
lemon橪
e4bc52a219 修改已发现秒杀的bug 2021-09-15 17:05:43 +08:00
paulGao
ea8c86e2e2 Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui into dev-gl 2021-09-07 09:37:30 +08:00
paulGao
70506767ef Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop-ui into dev-gl 2021-09-03 15:44:06 +08:00
paulGao
48002d6143 conifg 2021-09-03 15:43:46 +08:00
1680 changed files with 504411 additions and 100891 deletions

8
.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
*/.vscode/
/.idea/
*/dist/
.DS_Store
node_modules/
yarn.lock
package-lock.json
!seller/yarn.lock

View File

@@ -1,17 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="OTHER_INDENT_OPTIONS">
<value>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</value>
</option>
<codeStyleSettings language="JavaScript">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="0" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

View File

@@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@@ -1,6 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

12
.idea/lili-shop-ui.iml generated
View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/misc.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/lili-shop-ui.iml" filepath="$PROJECT_DIR$/.idea/lili-shop-ui.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

380
.idea/workspace.xml generated
View File

@@ -1,380 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="BranchesTreeState">
<expand>
<path>
<item name="ROOT" type="e8cecc67:BranchNodeDescriptor" />
<item name="LOCAL_ROOT" type="e8cecc67:BranchNodeDescriptor" />
</path>
<path>
<item name="ROOT" type="e8cecc67:BranchNodeDescriptor" />
<item name="REMOTE_ROOT" type="e8cecc67:BranchNodeDescriptor" />
</path>
<path>
<item name="ROOT" type="e8cecc67:BranchNodeDescriptor" />
<item name="REMOTE_ROOT" type="e8cecc67:BranchNodeDescriptor" />
<item name="GROUP_NODE:origin" type="e8cecc67:BranchNodeDescriptor" />
</path>
</expand>
<select />
</component>
<component name="ChangeListManager">
<list default="true" id="7e964aa0-753b-43f7-854a-2942a3e76fe4" name="默认更改列表" comment="店铺设置">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<<<<<<< HEAD
<change beforePath="$PROJECT_DIR$/buyer/src/pages/home/orderCenter/AddAddress.vue" beforeDir="false" afterPath="$PROJECT_DIR$/buyer/src/pages/home/orderCenter/AddAddress.vue" afterDir="false" />
<change beforePath="$PROJECT_DIR$/manager/src/config/index.js" beforeDir="false" afterPath="$PROJECT_DIR$/manager/src/config/index.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/seller/src/config/index.js" beforeDir="false" afterPath="$PROJECT_DIR$/seller/src/config/index.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/seller/src/views/statistics/goods/goodsStatistics.vue" beforeDir="false" afterPath="$PROJECT_DIR$/seller/src/views/statistics/goods/goodsStatistics.vue" afterDir="false" />
=======
<change beforePath="$PROJECT_DIR$/manager/src/views/goods-unit/index.vue" beforeDir="false" afterPath="$PROJECT_DIR$/manager/src/views/goods-unit/index.vue" afterDir="false" />
<change beforePath="$PROJECT_DIR$/manager/src/views/sensitiveWords/index.vue" beforeDir="false" afterPath="$PROJECT_DIR$/manager/src/views/sensitiveWords/index.vue" afterDir="false" />
>>>>>>> new-lmr
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Vue File" />
<option value="Vue Single File Component" />
<option value="JavaScript File" />
</list>
</option>
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="ProjectId" id="1gGPnr0TWcTGoYhLT7QHFe5MrX4" />
<component name="ProjectLevelVcsManager">
<ConfirmationsSetting value="2" id="Add" />
</component>
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="SHARE_PROJECT_CONFIGURATION_FILES" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" />
<<<<<<< HEAD
<property name="last_opened_file_path" value="$PROJECT_DIR$/manager/src/api" />
=======
<property name="last_opened_file_path" value="$PROJECT_DIR$/manager/src/views/sys/setting-manage" />
>>>>>>> new-lmr
<property name="node.js.detected.package.eslint" value="true" />
<property name="node.js.detected.package.tslint" value="true" />
<property name="node.js.path.for.package.eslint" value="project" />
<property name="node.js.path.for.package.tslint" value="project" />
<property name="node.js.selected.package.eslint" value="(autodetect)" />
<property name="node.js.selected.package.tslint" value="(autodetect)" />
<property name="nodejs_package_manager_path" value="npm" />
<property name="settings.editor.selected.configurable" value="preferences.sourceCode.XML" />
<property name="ts.external.directory.path" value="$APPLICATION_HOME_DIR$/plugins/JavaScriptLanguage/jsLanguageServicesImpl/external" />
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<<<<<<< HEAD
<recent name="$PROJECT_DIR$/manager/src/api" />
<recent name="$PROJECT_DIR$/manager/src/views/my-components" />
=======
<recent name="$PROJECT_DIR$/manager/src/views/sys/setting-manage" />
>>>>>>> new-lmr
<recent name="$PROJECT_DIR$/buyer/src/components/verify" />
<recent name="$PROJECT_DIR$/buyer/src/components/change" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/buyer/src/components/change" />
<recent name="$PROJECT_DIR$/buyer/src/pages/home/memberCenter" />
<recent name="$PROJECT_DIR$/buyer/src/pages/home/orderCenter" />
<recent name="$PROJECT_DIR$/buyer/src/pages/home" />
<recent name="$PROJECT_DIR$/buyer/src/components/home/order" />
</key>
</component>
<component name="RunManager">
<configuration name="Home.vue" type="JavascriptDebugType" temporary="true" nameIsGenerated="true" uri="http://localhost:63342/lili-shop-ui/buyer/src/page/user/Home.vue" useBuiltInWebServerPort="true">
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="JavaScript Debug.Home.vue" />
</list>
</recent_temporary>
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="7e964aa0-753b-43f7-854a-2942a3e76fe4" name="默认更改列表" comment="" />
<created>1597738125477</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1597738125477</updated>
<workItem from="1597738127938" duration="6268000" />
<workItem from="1597825716012" duration="3768000" />
<workItem from="1597830090678" duration="7632000" />
<workItem from="1597972262326" duration="865000" />
<workItem from="1597974893526" duration="112000" />
<workItem from="1597975021121" duration="17000" />
<workItem from="1597975216701" duration="17254000" />
<workItem from="1598184961388" duration="14000" />
<workItem from="1598233017859" duration="10307000" />
<workItem from="1598259954059" duration="2720000" />
<workItem from="1598318520176" duration="726000" />
<workItem from="1598319433942" duration="106000" />
<workItem from="1598319554477" duration="13265000" />
<workItem from="1598406300597" duration="6030000" />
<workItem from="1598422866858" duration="7787000" />
<workItem from="1598491104901" duration="37245000" />
<workItem from="1606876680167" duration="61000" />
<workItem from="1611131536390" duration="5616000" />
<workItem from="1611537245379" duration="828000" />
<workItem from="1611538362285" duration="350000" />
<workItem from="1611560515629" duration="834000" />
<workItem from="1611650051294" duration="3000" />
<workItem from="1611818003333" duration="239000" />
<workItem from="1613989205923" duration="7005000" />
<workItem from="1614076082765" duration="8973000" />
<workItem from="1614142479169" duration="2129000" />
<workItem from="1614162982178" duration="8343000" />
<workItem from="1614228135182" duration="3456000" />
<workItem from="1614248866969" duration="8023000" />
<workItem from="1614313313338" duration="83000" />
<workItem from="1614313447954" duration="211000" />
</task>
<task id="LOCAL-00001" summary="管理端页面优化">
<created>1613996019944</created>
<option name="number" value="00001" />
<option name="presentableId" value="LOCAL-00001" />
<option name="project" value="LOCAL" />
<updated>1613996019944</updated>
</task>
<task id="LOCAL-00002" summary="修复修改商家地址报错问题">
<created>1613996389449</created>
<option name="number" value="00002" />
<option name="presentableId" value="LOCAL-00002" />
<option name="project" value="LOCAL" />
<updated>1613996389449</updated>
</task>
<task id="LOCAL-00003" summary="去掉id">
<created>1614076370139</created>
<option name="number" value="00003" />
<option name="presentableId" value="LOCAL-00003" />
<option name="project" value="LOCAL" />
<updated>1614076370139</updated>
</task>
<task id="LOCAL-00004" summary="选择物流规则不能选择物流模板">
<created>1614080544415</created>
<option name="number" value="00004" />
<option name="presentableId" value="LOCAL-00004" />
<option name="project" value="LOCAL" />
<updated>1614080544415</updated>
</task>
<task id="LOCAL-00005" summary="修改查询条件样式">
<created>1614143298555</created>
<option name="number" value="00005" />
<option name="presentableId" value="LOCAL-00005" />
<option name="project" value="LOCAL" />
<updated>1614143298555</updated>
</task>
<task id="LOCAL-00006" summary="修改样式">
<created>1614143902874</created>
<option name="number" value="00006" />
<option name="presentableId" value="LOCAL-00006" />
<option name="project" value="LOCAL" />
<updated>1614143902874</updated>
</task>
<task id="LOCAL-00007" summary="修改更新时间为NAN">
<created>1614144541858</created>
<option name="number" value="00007" />
<option name="presentableId" value="LOCAL-00007" />
<option name="project" value="LOCAL" />
<updated>1614144541858</updated>
</task>
<task id="LOCAL-00008" summary="修复app版本无法添加和修改">
<created>1614230386509</created>
<option name="number" value="00008" />
<option name="presentableId" value="LOCAL-00008" />
<option name="project" value="LOCAL" />
<updated>1614230386509</updated>
</task>
<task id="LOCAL-00009" summary="去掉打印">
<created>1614230407722</created>
<option name="number" value="00009" />
<option name="presentableId" value="LOCAL-00009" />
<option name="project" value="LOCAL" />
<updated>1614230407722</updated>
</task>
<task id="LOCAL-00010" summary="去掉多选">
<created>1614230544808</created>
<option name="number" value="00010" />
<option name="presentableId" value="LOCAL-00010" />
<option name="project" value="LOCAL" />
<updated>1614230544808</updated>
</task>
<task id="LOCAL-00011" summary="修改消息标题宽度">
<created>1614230627881</created>
<option name="number" value="00011" />
<option name="presentableId" value="LOCAL-00011" />
<option name="project" value="LOCAL" />
<updated>1614230627881</updated>
</task>
<task id="LOCAL-00012" summary="店铺相关js提交">
<created>1614231645143</created>
<option name="number" value="00012" />
<option name="presentableId" value="LOCAL-00012" />
<option name="project" value="LOCAL" />
<updated>1614231645143</updated>
</task>
<task id="LOCAL-00013" summary="店铺修改">
<created>1614231785359</created>
<option name="number" value="00013" />
<option name="presentableId" value="LOCAL-00013" />
<option name="project" value="LOCAL" />
<updated>1614231785359</updated>
</task>
<task id="LOCAL-00014" summary="优化页面">
<created>1614249105672</created>
<option name="number" value="00014" />
<option name="presentableId" value="LOCAL-00014" />
<option name="project" value="LOCAL" />
<updated>1614249105672</updated>
</task>
<task id="LOCAL-00015" summary="页面优化">
<created>1614258980903</created>
<option name="number" value="00015" />
<option name="presentableId" value="LOCAL-00015" />
<option name="project" value="LOCAL" />
<updated>1614258980903</updated>
</task>
<task id="LOCAL-00016" summary="页面优化">
<created>1614259068248</created>
<option name="number" value="00016" />
<option name="presentableId" value="LOCAL-00016" />
<option name="project" value="LOCAL" />
<updated>1614259068248</updated>
</task>
<task id="LOCAL-00017" summary="页面优化">
<created>1614313690732</created>
<option name="number" value="00017" />
<option name="presentableId" value="LOCAL-00017" />
<option name="project" value="LOCAL" />
<updated>1614313690732</updated>
</task>
<option name="localTasksCounter" value="18" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="1" />
</component>
<component name="Vcs.Log.History.Properties">
<option name="COLUMN_ID_ORDER">
<list>
<option value="Default.Root" />
<option value="Default.Author" />
<option value="Default.Date" />
<option value="Default.Subject" />
</list>
</option>
</component>
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="1">
<value>
<State>
<option name="SHOW_ONLY_AFFECTED_CHANGES" value="true" />
<option name="FILTERS">
<map>
<entry key="branch">
<value>
<list>
<option value="HEAD" />
</list>
</value>
</entry>
<entry key="structure">
<value>
<list>
<option value="dir:/Users/liushuai/Documents/workspace/lili-shop-ui/seller/src/router" />
</list>
</value>
</entry>
</map>
</option>
</State>
</value>
</entry>
<entry key="MAIN">
<value>
<State>
<option name="COLUMN_ORDER" />
</State>
</value>
</entry>
</map>
</option>
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="店铺设置" />
<MESSAGE value="文件排序问题处理" />
<MESSAGE value="管理端页面优化" />
<MESSAGE value="修复修改商家地址报错问题" />
<MESSAGE value="去掉id" />
<MESSAGE value="选择物流规则不能选择物流模板" />
<MESSAGE value="修改查询条件样式" />
<MESSAGE value="修改样式" />
<MESSAGE value="修改更新时间为NAN" />
<MESSAGE value="修复app版本无法添加和修改" />
<MESSAGE value="去掉打印" />
<MESSAGE value="去掉多选" />
<MESSAGE value="修改消息标题宽度" />
<MESSAGE value="店铺相关js提交" />
<MESSAGE value="店铺修改" />
<MESSAGE value="优化页面" />
<MESSAGE value="页面优化" />
<option name="LAST_COMMIT_MESSAGE" value="页面优化" />
</component>
<component name="WindowStateProjectService">
<state x="2074" y="292" key="CommitChangelistDialog2" timestamp="1614313690605">
<screen x="0" y="23" width="3440" height="1333" />
</state>
<state x="2074" y="292" key="CommitChangelistDialog2/0.23.3440.1333@0.23.3440.1333" timestamp="1614313690605" />
<state x="1660" y="123" width="1572" height="1133" key="DiffContextDialog" timestamp="1614231764977">
<screen x="0" y="23" width="3440" height="1333" />
</state>
<state x="1660" y="123" width="1572" height="1133" key="DiffContextDialog/0.23.3440.1333@0.23.3440.1333" timestamp="1614231764977" />
<state x="2046" y="418" key="Vcs.Push.Dialog.v2" timestamp="1614313692405">
<screen x="0" y="23" width="3440" height="1333" />
</state>
<state x="2046" y="418" key="Vcs.Push.Dialog.v2/0.23.3440.1333@0.23.3440.1333" timestamp="1614313692405" />
<state x="2055" y="414" width="782" height="550" key="find.popup" timestamp="1614256597933">
<screen x="0" y="23" width="3440" height="1333" />
</state>
<state x="2055" y="414" width="782" height="550" key="find.popup/0.23.3440.1333@0.23.3440.1333" timestamp="1614256597933" />
<state x="2111" y="325" key="run.anything.popup" timestamp="1613991372498">
<screen x="0" y="23" width="3440" height="1333" />
</state>
<state x="2111" y="325" key="run.anything.popup/0.23.3440.1333@0.23.3440.1333" timestamp="1613991372498" />
<state x="2111" y="327" width="670" height="676" key="search.everywhere.popup" timestamp="1614254687317">
<screen x="0" y="23" width="3440" height="1333" />
</state>
<state x="2111" y="327" width="670" height="676" key="search.everywhere.popup/0.23.3440.1333@0.23.3440.1333" timestamp="1614254687317" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" type="javascript">
<url>file://$PROJECT_DIR$/manager/src/views/sys/monitor/monitor.vue</url>
<line>5</line>
<option name="timeStamp" value="2" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>
</component>
</project>

695
LICENSE
View File

@@ -1,674 +1,21 @@
GNU GENERAL PUBLIC LICENSE MIT License
Version 3, 29 June 2007
Copyright (c) 2020-2026 Beijing Hongye Huicheng Technology Co., Ltd. (北京宏业汇成科技有限公司)
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies Permission is hereby granted, free of charge, to any person obtaining a copy
of this license document, but changing it is not allowed. of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
Preamble to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
The GNU General Public License is a free, copyleft license for furnished to do so, subject to the following conditions:
software and other kinds of works.
The above copyright notice and this permission notice shall be included in all
The licenses for most software and other practical works are designed copies or substantial portions of the Software.
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
share and change all versions of a program--to make sure it remains free IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
software for all its users. We, the Free Software Foundation, use the FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
GNU General Public License for most of our software; it applies also to AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
any other work released this way by its authors. You can apply it to LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
your programs, too. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

201
MIGRATION-VUE3.md Normal file
View File

@@ -0,0 +1,201 @@
# Lilishop UI — Vue 3 迁移与上线前检查清单
四个子项目(buyer / seller / manager / im)已完成 **Vue 3 + Element Plus** 迁移,并完成依赖小版本对齐。本文档供上线前统一回归使用。
## 技术栈(四端一致)
| 类别 | 包 | 版本(package.json) |
|------|-----|---------------------|
| 框架 | vue | ^3.5.35 |
| 编译 | @vue/compiler-sfc | ^3.5.35 |
| 路由 | vue-router | ^4.6.4 |
| 状态 | pinia | ^4.0.3(四端已全部从 vuex 迁移完成) |
| 组件写法 | `<script setup>` | 四端 597 个组件已全部完成 Options API → 组合式 API 迁移;各端 eslint 已启用 `vue/component-api-style: ['warn', ['script-setup']]` 防止回退 |
| UI | element-plus | ^2.14.1 |
| 图标 | @element-plus/icons-vue | ^2.3.2 |
| 请求 | axios | ^1.7.9 |
| 兼容 | core-js | ^3.49.0 |
| 构建 | @vue/cli-service | ^5.0.9 |
> 使用 `^` 范围,实际安装版本以各目录 `yarn.lock` 为准。
> 要求 **Node >= 16**,包管理统一 **yarn**。
## 本地启动
```bash
# 买家端
cd buyer && yarn install && yarn dev # 端口 10000
# 商家端
cd seller && yarn install && yarn dev # 端口 10002
# 管理端
cd manager && yarn install && yarn dev # 端口 10003
# IM 客服
cd im && yarn install && yarn dev # 端口 8000
```
生产构建(上线前必跑):
```bash
cd buyer && yarn build
cd seller && yarn build
cd manager && yarn build
cd im && yarn build
```
---
## 一、通用检查(四端都要过)
### 1. 认证与请求(axios 1.x 重点)
各端请求封装位置:
| 端 | 文件 |
|----|------|
| buyer | `buyer/src/plugins/request.js` |
| seller | `seller/src/libs/axios.js` |
| manager | `manager/src/libs/axios.js` |
| im | `im/src/utils/request.js` |
- [ ] **登录**:账号密码登录成功,token 写入正常
- [ ] **登出**:清除 token,跳转登录页
- [ ] **401**:token 过期后跳转登录 / 刷新 token(buyer/manager/seller 有刷新逻辑)
- [ ] **403**:无权限时提示文案正确、不白屏
- [ ] **400 / 5xx**:接口报错能弹出 `Message` / `ElMessage` / `Notification`
- [ ] **网络超时**:断网或超时后有错误提示,页面不卡死
- [ ] **GET 带参**:列表筛选、分页参数序列化正常
- [ ] **POST JSON**:`Content-Type: application/json` 请求体正确
- [ ] **POST 表单**:`application/x-www-form-urlencoded` 提交正常(im 等)
### 2. Element Plus UI(2.6 → 2.14 重点)
- [ ] **表格** `el-table`:列展示、排序、空数据、加载态
- [ ] **分页** `el-pagination`:翻页、每页条数切换
- [ ] **表单** `el-form`:必填校验、错误提示位置
- [ ] **弹窗** `el-dialog` / `ElMessageBox`:打开、确认、取消、关闭
- [ ] **下拉** `el-select` / `el-dropdown`:选项、点击外部关闭
- [ ] **消息** `ElMessage` / `$Message` 兼容层:success / error / warning
- [ ] **加载** `ElLoading` / `v-loading`:请求期间遮罩正常消失
- [ ] **日期** `el-date-picker`:选择、清空、范围选择
- [ ] **上传** `el-upload`:选文件、进度、成功 / 失败回调
### 3. 路由与页面
- [ ] 浏览器 **刷新** 当前路由不 404(history 模式 + 服务端配置)
- [ ] **动态路由** 加载正常(seller / manager 菜单权限路由)
- [ ] 浏览器 **前进 / 后退** 正常
- [ ] 各端 **404 页** 可回到首页
### 4. 构建与部署
- [ ] 四端 `yarn build` 无 error(warning 可记录,不阻断)
- [ ] 生产环境 API 地址配置正确(`config` / 环境变量)
- [ ] 静态资源 `publicPath` 与 Nginx / CDN 路径一致
- [ ] gzip 压缩包(如有)可正常访问
---
## 二、分端专项检查
### Buyer 买家端(10000)
详见 [buyer/MIGRATION-VUE3.md](./buyer/MIGRATION-VUE3.md)
- [ ] 首页装修模块渲染(轮播、商品列表、秒杀区等)
- [ ] 商品详情:规格选择、加购、收藏、`el-image` 预览
- [ ] 购物车 → 结算 → 支付流程
- [ ] 用户中心:订单列表、地址、优惠券、售后
- [ ] 登录 / 注册 / 忘记密码
- [ ] 店铺入驻、商户页
- [ ] 地图(高德 `@amap/amap-jsapi-loader`)定位与选点
- [ ] 侧边栏 `el-menu`、头部 `el-dropdown`、动态图标 `iconMap.js`
### Seller 商家端(10002)
详见 [seller/MIGRATION-VUE3.md](./seller/MIGRATION-VUE3.md)
- [ ] 商家登录、店铺信息
- [ ] 商品发布三步流程(`goodsOperation` 步骤条)
- [ ] 订单管理:发货、退款、详情
- [ ] 促销 / 分销 / 统计图表(`@antv/g2`)
- [ ] 页面装修(wap / modelList,从 manager 同步部分)
- [ ] 图片懒加载 `vue-lazyload`
- [ ] Excel 导出 `vue-json-excel`
### Manager 管理端(10003)
详见 [manager/MIGRATION-VUE3.md](./manager/MIGRATION-VUE3.md)
- [ ] 管理员登录、权限菜单、动态路由
- [ ] 系统设置(`sys/setting-manage` 各 Tab)
- [ ] 菜单 / 部门管理
- [ ] 页面装修(PC + H5)
- [ ] 文章管理
- [ ] 商品 / 订单 / 会员 / 促销等核心列表 CRUD
- [ ] 富文本 TinyMCE 编辑、图片上传
- [ ] 多语言 `vue-i18n` 切换(如有启用)
### IM 客服端(8000)
详见 [im/MIGRATION-VUE3.md](./im/MIGRATION-VUE3.md)
- [ ] 带 token 参数进入会话页
- [ ] 对话列表加载、切换会话、未读数
- [ ] 发送文字、表情、图片消息
- [ ] 商品 / 订单卡片链接跳转(`linkToGoods` / `linkToOrders`)
- [ ] 右键菜单(复制、撤回、删除等)
- [ ] WebSocket 连接 / 断线重连 / 新消息通知
- [ ] 最近浏览、订单列表侧栏(商家场景)
- [ ] 用户名片弹层 `$user()`
---
## 三、已知可忽略项
| 项 | 说明 |
|----|------|
| `vue-awesome-swiper` peer warning | 历史依赖,Vue 3 下仍有 peer 告警,功能正常可暂忽略 |
| im 内 `<i class="el-icon-*">` | Element Plus 无字体图标,部分旧图标可能不显示,不影响核心功能 |
| `vue-prism-editor@2.0.0-alpha.2` | im 代码块编辑器刻意锁定 alpha 版 |
| 打包体积 warning | chunk-vendors 偏大,属 Element Plus 全量引入,可后续做按需优化 |
---
## 四、问题记录模板
上线测试时建议按端记录:
```markdown
### [端名] 问题标题
- 页面/路由:
- 操作步骤:
- 预期:
- 实际:
- 控制台报错:
- 优先级:P0 / P1 / P2
```
---
## 五、子项目文档索引
| 端 | 迁移说明 |
|----|----------|
| buyer | [buyer/MIGRATION-VUE3.md](./buyer/MIGRATION-VUE3.md) |
| seller | [seller/MIGRATION-VUE3.md](./seller/MIGRATION-VUE3.md) |
| manager | [manager/MIGRATION-VUE3.md](./manager/MIGRATION-VUE3.md) |
| im | [im/MIGRATION-VUE3.md](./im/MIGRATION-VUE3.md) |
---
## 六、建议上线顺序
1. **manager**(后台配置源头)
2. **seller**(商家经营)
3. **buyer**(C 端流量最大)
4. **im**(客服,依赖前后端 WebSocket)
每上一端,至少完成本文 **第一节通用检查** + 对应 **第二节分端检查** 后再切下一端。

144
README.en.md Normal file
View File

@@ -0,0 +1,144 @@
<div align="center">
<img src="./manager/src/assets/logo.png" width="180" alt="Lilishop Logo" />
<h1>Lilishop(PickMall) - Web Frontend (Vue 3)</h1>
<p>
<a href="https://github.com/lilishop/lilishop"><img src="https://img.shields.io/github/stars/lilishop/lilishop.svg?style=social&logo=github" alt="GitHub Stars" /></a>
<a href="https://gitee.com/beijing_hongye_huicheng/lilishop"><img src="https://gitee.com/beijing_hongye_huicheng/lilishop/badge/star.svg?theme=dark" alt="Gitee Stars" /></a>
<a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License" /></a>
<a href="https://vuejs.org/"><img src="https://img.shields.io/badge/Vue-3.5-brightgreen.svg" alt="Vue 3" /></a>
<a href="https://element-plus.org/"><img src="https://img.shields.io/badge/Element%20Plus-2.x-409EFF.svg" alt="Element Plus" /></a>
<a href="https://pinia.vuejs.org/"><img src="https://img.shields.io/badge/Pinia-4.x-yellow.svg" alt="Pinia" /></a>
</p>
<p>
<a href="https://pickmall.cn">🏠 Official Website</a> ·
<a href="https://bdwx2tfwwt.feishu.cn/wiki/space/7675179368632617952?ccm_open_type=lark_wiki_spaceLink&open_tab_from=wiki_home">📖 Product Documentation</a> ·
<a href="#2-online-demo">💻 Online Demo</a> ·
<a href="https://github.com/lilishop/lilishop">💻 GitHub</a>
</p>
<p>
<a href="./README.md">简体中文</a> | <b>English</b>
</p>
</div>
> ⭐ **If you like this project, please click `Star` in the top-right corner to support us! Your Star is our greatest motivation for continuous open-source iteration!**
**LILISHOP** is an open-source e-commerce system built with Spring Boot, Vue 3, and uni-app. It supports B2B2C multi-vendor marketplaces, WeChat Mini Programs, H5, Android/iOS Apps, live-streaming e-commerce, affiliate distribution, and flash sales.
### ✨ Why Choose Lilishop
- 🟢 **True MIT License**: Free for commercial use and private secondary development without licensing concerns.
- 🚀 **Modern Vue 3 Stack**: Built on `Vue 3.5 + Pinia 4 + Vue Router 4 + Element Plus`, leaving legacy Vue 2 templates behind.
- 🧩 **4-in-1 Production Suite**: Covers **PC Buyer Mall (`buyer`)**, **Seller Portal (`seller`)**, **Platform Admin Panel (`manager`)**, and **IM Customer Service Web (`im`)**, complete with drag-and-drop visual storefront decoration and rich analytics.
---
## 1. Overview
This repository (`lilishop-ui`) is the **Web Frontend Suite** of Lilishop, containing four standalone **Vue 3** web applications: **PC Buyer Mall, Seller Panel, Platform Admin Panel, and IM Customer Service Web**.
- **Official Website**: <https://pickmall.cn>
- **Documentation**: [Product Documentation](https://bdwx2tfwwt.feishu.cn/wiki/space/7675179368632617952?ccm_open_type=lark_wiki_spaceLink&open_tab_from=wiki_home)
- **Gitee Repository**: <https://gitee.com/beijing_hongye_huicheng>
- **GitHub Main Repository**: <https://github.com/lilishop/lilishop>
---
## 2. Online Demo
> **Note**: The verification code for the demo environment is `111111`.
| Portal | URL | Demo Credentials |
| :--- | :--- | :--- |
| **Platform Admin Panel (`manager`)** | <https://admin-b2b2c.pickmall.cn> | `admin` / `123456` |
| **Seller / Store Panel (`seller`)** | <https://store-b2b2c.pickmall.cn> | `13011111111` / `111111` |
| **PC Buyer Mall (`buyer`)** | <https://pc-b2b2c.pickmall.cn> | SMS code: `111111` |
| **Mobile H5 (`uni-app`)** | <https://m-b2b2c.pickmall.cn> | SMS code: `111111` |
| WeChat Mini Program | Mobile H5 ([Visit Directly](https://m-b2b2c.pickmall.cn)) |
| :---: | :---: |
| <img src="https://static.pickmall.cn/images/h5-qrcode.png" width="180" alt="WeChat Mini Program QR Code" /> | <img src="https://lilishop-wechat.oss-cn-beijing.aliyuncs.com/h5-qrcode.png" width="180" alt="Mobile H5 QR Code" /> |
| Scan with WeChat | Scan or visit <https://m-b2b2c.pickmall.cn> |
---
## 3. Core Features & Tech Stack
### Core Features
- **Four-Portal Synergy**: Includes Platform Admin, Seller Panel, PC Buyer Mall, and IM Web Workbench with clear role boundaries.
- **Drag-and-Drop Visual Decoration**: Built-in visual floor editor (`vuedraggable`) for customizing both PC and mobile storefronts.
- **Multi-Vendor B2B2C Operations**: Merchant onboarding, product auditing, split-order fulfillment, promotions, and financial settlement ledgers.
- **Rich Business Analytics**: Powered by `@antv/g2` for sales overview, YoY/MoM product reports, member analytics, and distribution metrics.
- **IM Customer Service**: Integrated with Tencent Cloud IM / WebSocket customer service for real-time communication.
### Web Tech Stack
| Category | Technology | Description |
| :--- | :--- | :--- |
| Core Framework | `Vue 3.5` + `Vue Router 4` | Modern reactive frontend framework |
| State Management | `Pinia 4` | Official Vue 3 state management library |
| UI Library | `Element Plus 2.x` | Enterprise desktop UI component library |
| HTTP Client | `Axios 1.x` | Unified request/response interceptors & auth handling |
| Data Visualization | `@antv/g2` | Interactive charts and business analytics |
| Visual Decoration | `vuedraggable 4` | Drag-and-drop page floor builder |
| Messaging & IM | `@tencentcloud/chat` / `sockjs-client` | Real-time customer service messaging |
| Video Player | `dplayer` + `hls.js` | Product video and live streaming playback |
| Build & Styling | `Vue CLI 5` + `Webpack 5` + `Sass / Less` | Modular build pipeline and theme customization |
---
## 4. Directory Structure
```text
lilishop-ui
├── buyer/ # [PC Buyer Mall]
│ ├── public/ # Static assets & global config (config.js)
│ └── src/
│ ├── api/ # Buyer API modules (goods, cart, order, member, promotion)
│ ├── components/ # Shared components (floor renderer, navbar, goods card)
│ ├── pages/ # PC Mall pages (Home, Product Detail, Checkout, User Center)
│ ├── router/ # Route definitions & guards
│ ├── stores/ # Pinia stores
│ └── utils/ # Request interceptors & helpers
├── seller/ # [Seller / Store Management Portal]
│ ├── public/ # Static assets & global config
│ └── src/
│ ├── api/ # Seller API modules
│ ├── components/ # Seller shared & decoration components
│ ├── views/ # Seller views (goods, orders, after-sales, promotions, store settings)
│ ├── router/ # Dynamic permission routes
│ └── stores/ # Pinia stores
├── manager/ # [Platform Admin Portal]
│ ├── public/ # Static assets & global config
│ └── src/
│ ├── api/ # Admin API modules
│ ├── components/ # Admin components, rich-text editor, visual floor builder
│ ├── views/ # Admin views (member, goods, order, seller, marketing, finance, stats, system)
│ ├── router/ # Menu & permission routes
│ └── stores/ # Pinia stores
├── im/ # [IM Customer Service Web Client]
│ └── src/
│ ├── api/ # Chat session & message APIs
│ ├── components/ # Chat window, message list, product/order cards
│ ├── im-server/ # WebSocket / IM connection manager
│ └── views/ # Customer service workbench
├── build.sh # Unified build script
└── docker-build.sh # Docker image build script
```
---
## 5. Related Repositories
| Repository | Description | Links |
| :--- | :--- | :--- |
| **`lilishop`** | Backend Services (Spring Boot 4 / Java 21) | [Gitee](https://gitee.com/beijing_hongye_huicheng/lilishop) · [GitHub](https://github.com/lilishop/lilishop) |
| **`lilishop-ui`** | PC Mall / Seller / Admin / IM Web Frontend | [Gitee](https://gitee.com/beijing_hongye_huicheng/lilishop-ui) |
| **`lilishop-uniapp`** | Mobile Buyer Client (H5 / Mini Program / App) | [Gitee](https://gitee.com/beijing_hongye_huicheng/lilishop-uniapp) |
| **`docker`** | Docker Compose, Images & SQL Init Scripts | [Gitee](https://gitee.com/beijing_hongye_huicheng/docker) · [MySQL Scripts](https://gitee.com/beijing_hongye_huicheng/docker/tree/master/init/mysql) |
---
## 6. License
Lilishop is licensed under the [MIT](./LICENSE) License. Copyright © 2020-2026 **Beijing Hongye Huicheng Technology Co., Ltd.**

426
README.md
View File

@@ -1,277 +1,181 @@
## Lilishop B2B2C商城系统 <div align="center">
<img src="./manager/src/assets/logo.png" width="180" alt="Lilishop Logo" />
##### 官方公众号 & 开源不易,如有帮助请点Star <h1>Lilishop(PickMall) 开源商城系统 - Web 前端 (Vue 3)</h1>
![image-20210511171611793](https://pickmall.cn/assets/imgs/h5-qrcode.png)
<p>
[![star](https://gitee.com/beijing_hongye_huicheng/lilishop/badge/star.svg?theme=dark)](https://gitee.com/beijing_hongye_huicheng/lilishop/stargazers) <a href="https://github.com/lilishop/lilishop"><img src="https://img.shields.io/github/stars/lilishop/lilishop.svg?style=social&logo=github" alt="GitHub Stars" /></a>
<a href="https://gitee.com/beijing_hongye_huicheng/lilishop"><img src="https://gitee.com/beijing_hongye_huicheng/lilishop/badge/star.svg?theme=dark" alt="Gitee Stars" /></a>
<a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License" /></a>
### 介绍 <a href="https://vuejs.org/"><img src="https://img.shields.io/badge/Vue-3.5-brightgreen.svg" alt="Vue 3" /></a>
**官网**:https://pickmall.cn <a href="https://element-plus.org/"><img src="https://img.shields.io/badge/Element%20Plus-2.x-409EFF.svg" alt="Element Plus" /></a>
<a href="https://pinia.vuejs.org/"><img src="https://img.shields.io/badge/Pinia-4.x-yellow.svg" alt="Pinia" /></a>
Lilishop 是一款Java开发,基于SpringBoot研发的B2B2C多用户商城,前端使用 Vue、uniapp开发 **系统全端全部代码开源** </p>
产品前后端分离、支持分布式部署。 <p>
<a href="https://pickmall.cn">🏠 官方网站</a> ·
商城展示端包含 PC、H5、微信小程序、APP。 <a href="https://bdwx2tfwwt.feishu.cn/wiki/space/7675179368632617952?ccm_open_type=lark_wiki_spaceLink&open_tab_from=wiki_home">📖 产品文档</a> ·
<a href="#2-在线演示">💻 在线演示</a> ·
商城包含 会员模块、**第三方登录模块**、**第三方支付模块**、**楼层装修模块**、订单模块、分销模块、文章模块、系统设置模块、流量分析模块 <a href="#7-社区与支持">💬 微信交流群</a>
</p>
系统包含各种中间件、搜索引擎、多级缓存、分布式事务、分布式任务调度等,支持Docker,支持k8s。是一款高性能,支持高并发等商城系统。
<p>
开箱即用,简单配置即可部署一套属于您的系统。 <b>简体中文</b> | <a href="./README.en.md">English</a>
</p>
### 文档 </div>
**产品文档**(需求、架构、使用、部署、开发):https://docs.pickmall.cn > ⭐ **如果觉得项目不错,请点击右上角 `Star` 收藏支持!您的 Star 是我们持续开源迭代的最大动力!**
**LILISHOP** 是基于 Spring Boot / Vue 3 / uni-app 开发的开源商城系统,支持 B2B2C 多商户商城、微信小程序商城、H5 商城、APP 商城、直播电商、分销返佣、秒杀活动。
### 项目链接(gitee)
### ✨ 为什么选择 Lilishop
**Java后台**:https://gitee.com/beijing_hongye_huicheng/lilishop.git - 🟢 **真 MIT 协议**:支持免费商用与私有化闭源二开,无版权后顾之忧。
- 🚀 **Vue 3 全新栈**:全面基于 `Vue 3.5 + Pinia 4 + Vue Router 4 + Element Plus` 构建,告别老旧 Vue 2 架构。
**Vue后台前端**: https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git - 🧩 **四端合一生产级闭环**:完整覆盖 **PC 买家端 (`buyer`)**、**商家端 (`seller`)**、**平台运营管理端 (`manager`)** 与 **在线客服端 (`im`)**,支持拖拽式可视化楼层装修与多维数据统计报表。
**Uni-app**:https://gitee.com/beijing_hongye_huicheng/lilishop-uniapp.git ---
**docker一键部署**:https://gitee.com/beijing_hongye_huicheng/docker.git ## 1. 项目简介
### 项目链接(github) **Lilishop** 是一款功能完善的 B2B2C 多商户商城系统,采用前后端分离架构,全端代码开源。
后端基于 **Spring Boot 4**(Java 21)构建,具备高内聚、低耦合的特性,支持分布式部署;前端覆盖 PC、管理后台、H5、小程序和 APP,基于 **Vue 3** 和 **uni-app** 开发。
**Java后台**:https://github.com/hongyehuicheng/lilishop.git
本仓库(`lilishop-ui`)为 **Web 前端源码仓库**,包含 **PC 商城端、商家后台、平台管理后台、IM 在线客服** 四个独立子工程。
**Vue后台前端**: https://github.com/hongyehuicheng/lilishop-ui.git
- **官方网站**: <https://pickmall.cn>
**Uni-app**:https://github.com/hongyehuicheng/lilishop-uniapp.git - **官方文档**: [产品文档](https://bdwx2tfwwt.feishu.cn/wiki/space/7675179368632617952?ccm_open_type=lark_wiki_spaceLink&open_tab_from=wiki_home)
- **Gitee 仓库**: <https://gitee.com/beijing_hongye_huicheng>
**docker一键部署**:https://github.com/hongyehuicheng/docker.git - **GitHub 主仓库**: <https://github.com/lilishop/lilishop>
### 演示地址 ---
**运营后台**:https://admin-b2b2c.pickmall.cn 账号:admin/123456 ## 2. 在线演示
**店铺后台**:https://store-b2b2c.pickmall.cn 账号:13011111111/111111 > **注意**: 演示站手机验证码统一为 `111111`。演示环境部署于 `master` 分支。
**用户前台**:https://pc-b2b2c.pickmall.cn | 演示站点 | 访问地址 | 演示账号 |
| :--- | :--- | :--- |
**移动端**:https://m-b2b2c.pickmall.cn | **平台运营管理端 (`manager`)** | <https://admin-b2b2c.pickmall.cn> | 账号:`admin` / 密码:`123456` |
| **商家店铺管理端 (`seller`)** | <https://store-b2b2c.pickmall.cn> | 账号:`13011111111` / 密码:`111111` |
![image-20210511171611793](https://pickmall.cn/assets/imgs/h5-qrcode.png) | **商城 PC 买家端 (`buyer`)** | <https://pc-b2b2c.pickmall.cn> | 可使用手机号验证码 `111111` 登录 |
| **移动端 H5 (`uni-app`)** | <https://m-b2b2c.pickmall.cn> | 可使用手机号验证码 `111111` 登录 |
### 3行命令搭建本地环境
| 微信小程序 | 移动端 H5([点击直接访问](https://m-b2b2c.pickmall.cn)) |
温馨提示:由于服务较多,如果笔记本环境启动内存没有32g可能无法启动成功(macbookpro 2020 16g内存启动无法成功),台式机在16g内存、AMD 3700x 的ubuntu系统成功运行。 | :---: | :---: |
| <img src="https://static.pickmall.cn/images/h5-qrcode.png" width="180" alt="微信小程序体验码" /> | <img src="https://lilishop-wechat.oss-cn-beijing.aliyuncs.com/h5-qrcode.png" width="180" alt="移动端 H5 体验二维码" /> |
##### 下载docker脚本 | 微信扫码体验小程序 | 手机扫码或访问 <https://m-b2b2c.pickmall.cn> |
`git clone https://gitee.com/beijing_hongye_huicheng/docker.git `
##### 部署基础环境 ---
`docker-compose up -d`
## 3. 核心特性与技术栈
##### 部署应用
`docker-compose -f docker-compose-application.yml up -d` ### 核心特性
- **四端协同**: 涵盖平台管理端、商家管理端、PC 买家商城端、IM 客服端,角色边界清晰,开箱即用。
- **可视化拖拽装修**: 管理端与商家端内置可视化楼层编辑器(基于 `vuedraggable`),可同步配置 PC 端与移动端首页/专题页。
- **多商户入驻与结算**: 完整的商家入驻审核、商品审核、拆单发货、促销报名、财务对账与结算台账体系。
PS:单独部署的话,数据库文件访问这里:https://gitee.com/beijing_hongye_huicheng/docker/tree/master/init/mysql - **多维经营分析**: 集成 `@antv/g2` 图表引擎,提供营业概况、商品同比环比、会员分析、营销与分销数据统计。
- **即时通讯客服**: 集成腾讯云 IM / WebSocket 在线客服系统,支持买家、商家与平台实时沟通。
##### 各个地址
### Web 前端技术栈
| API | 地址 | | 类别 | 技术选型 | 说明 |
| -------------- | --------------- | | :--- | :--- | :--- |
| 买家API | http://127.0.0.1:8888 | | 核心框架 | `Vue 3.5` + `Vue Router 4` | 基于 Composition API 的现代响应式前端框架 |
| 商家API | http://127.0.0.1:8889 | | 状态管理 | `Pinia 4` | 轻量、类型友好的 Vue 3 官方状态管理库 |
| 管理端API | http://127.0.0.1:8887 | | UI 组件库 | `Element Plus 2.x` | 企业级中后台与桌面端 UI 组件库 |
| 通用API | http://127.0.0.1:8890 | | 网络请求 | `Axios 1.x` | 统一请求/响应拦截、Token 刷新与异常提示 |
| 数据可视化 | `@antv/g2` | 运营端与商家端数据统计图表渲染 |
| 前端演示 | 地址 | | 可视化拖拽 | `vuedraggable 4` | 商城首页及专题楼层可视化拖拽装修 |
| -------------- | --------------- | | 即时通讯 | `@tencentcloud/chat` / `sockjs-client` | 在线客服消息收发与实时通知 |
| PC | http://127.0.0.1:10000 | | 音视频播放 | `dplayer` + `hls.js` | 商品视频与直播流播放支持 |
| WAP | http://127.0.0.1:10001 | | 构建与样式 | `Vue CLI 5` + `Webpack 5` + `Sass / Less` | 模块化工程构建与全局主题样式定制 |
| 商家 | http://127.0.0.1:10002 |
| 管理端 | http://127.0.0.1:10003 | ---
## 4. 目录结构
```text
lilishop-ui
### 功能列表 ├── buyer/ # 【PC 买家商城端】源码工程
│ ├── public/ # 静态资源与全局配置文件 (config.js)
│ └── src/
│ ├── api/ # 买家端接口定义(商品、购物车、订单、会员、促销等)
#### 平台功能 │ ├── components/ # 公共业务组件(楼层渲染、导航栏、商品卡片等)
│ ├── pages/ # PC 商城各业务页面(首页、商品详情、结算、个人中心等)
![平台功能](https://pickmall.cn/assets/imgs/other/managerList.jpg) │ ├── router/ # 路由配置与守卫
│ ├── stores/ # Pinia 状态管理
│ └── utils/ # 请求封装与通用工具函数
├── seller/ # 【商家店铺管理端】源码工程
#### 商家端功能 │ ├── public/ # 静态资源与全局配置
│ └── src/
![商家端功能](https://pickmall.cn/assets/imgs/other/storeList.jpg) │ ├── api/ # 商家端接口定义
│ ├── components/ # 商家端公共组件与装修组件
│ ├── views/ # 商家端业务视图(商品管理、订单发货、售后、促销、店铺设置、统计等)
│ ├── router/ # 动态权限路由
│ └── stores/ # Pinia 状态管理
├── manager/ # 【平台运营管理端】源码工程
### 功能展示 │ ├── public/ # 静态资源与全局配置
│ └── src/
│ ├── api/ # 运营端接口定义
│ ├── components/ # 平台公共组件、富文本、可视化楼层装修编辑器
#### 移动端 │ ├── views/ # 运营端业务视图(会员、商品、订单、商家、营销、分销、财务、统计、系统设置)
│ ├── router/ # 菜单与权限路由
<img src="https://pickmall.cn/assets/imgs/other/app.gif" alt="管理端功能展示" style="zoom:50%;" /> │ └── stores/ # Pinia 状态管理
├── im/ # 【IM 在线客服 Web 端】源码工程
<img src="https://pickmall.cn/assets/imgs/other/app.gif" alt="移动端功能展示" style="zoom:50%;" /> │ └── src/
│ ├── api/ # 客服会话与消息接口
│ ├── components/ # 聊天窗口、消息列表、商品/订单卡片组件
│ ├── im-server/ # WebSocket / IM 连接服务管理
#### 管理端 │ └── views/ # 客服工作台页面
├── build.sh # 多端统一构建脚本
![管理端功能展示](https://pickmall.cn/assets/imgs/other/manager.gif) └── docker-build.sh # Docker 镜像构建脚本
### 技术选型
#### 架构图
![架构](https://lili-system.oss-cn-beijing.aliyuncs.com/docs/%E6%9E%B6%E6%9E%84.png)
##### Java后台
| 说明 | 框架 | 说明 | |
| -------------- | --------------- | -------------- | ------------- |
| 基础框架 | Spring Boot | MVC框架 | Spring MVC |
| 持久框架 | Mybatis-Plus | 程序构建 | Maven |
| 关系型数据库 | MySQL | 消息中间件AMQP | RocketMQ |
| 缓存 | Redis +MongoDB | 搜索引擎 | Elasticsearch |
| 安全框架 | Spring Security | 数据库连接池 | Druid |
| 数据库分库分表 | sharding | 定时任务 | xxl-job |
| 负载均衡 | Nginx | 静态资源 | 阿里云OSS |
| 短信 | 阿里云短信 | 认证 | JWT |
| 日志处理 | Log4j | 接口规范 | RESTful |
##### 前端-运营后台、店铺后台
| 说明 | 框架 | 说明 | 框架 |
| ---------- | ---------- | ---------- | ------- |
| 构建工具 | webpack | JS版本 | ES6 |
| 基础JS框架 | Vue.js | 视频播放器 | Dplayer |
| 路由管理 | Vue Router | 状态管理 | Vuex |
| 基础UI库 | iView | UI界面基于 | iView |
| 网络请求 | axios | | |
##### 前端-移动端
| 说明 | 架构 | 说明 | 架构 |
| --------- | ------- | -------- | ------- |
| 基础UI库 | uViewui | 基础框架 | uni-app |
| CSS预处理 | scss | 地图引擎 | amap |
### 升级计划
#### 计划每个月发布一个版本,具体时间可能有出入
时间:2021年6月15日
```
新增功能:
1.微信小程序直播
2.优惠券活动
3.新人赠券
4.准确发券
5.用户等级
6.数据导出
7.订单批量
8.APP版本升级检测
9.积分商城
功能优化:
1.优惠券有效期增加类型:设置领取后*内有效。
2.秒杀活动设置为每天开启,需设置秒杀活动开启时间。
3.店铺配送模板,配送地区如果选择省份则下方的市级地址不展示。
4.店铺配送模板支持,店铺包邮。
5.普通商品设置去除卖家承担运费。
``` ```
时间:2021年7月15日 ---
``` ## 5. 配套源码仓库
新增功能:
1.会员权益
2.支持用户升级会员
3.供求单
4.IM:腾讯云智服
5.服务商品
6.店铺支持订单核销
7.店铺自提点
功能优化:
1.用户分享商城、关注店铺、邀请新用户可获取积分、经验值。
```
时间:2021年8月16日 本仓库专注于 **PC / 商家端 / 运营端 / IM Web**(`lilishop-ui`)。完整系统由以下四个核心仓库组成:
``` | 仓库名称 | 职责说明 | 仓库地址 |
新增功能: | :--- | :--- | :--- |
1.微淘功能 | **`lilishop`** | 后端服务源码(Spring Boot 4 / Java 21) | [Gitee](https://gitee.com/beijing_hongye_huicheng/lilishop) · [GitHub](https://github.com/lilishop/lilishop) |
2.店铺移动端 | **`lilishop-ui`** | PC 商城 / 商家端 / 运营管理端 / IM Web 前端 | [Gitee](https://gitee.com/beijing_hongye_huicheng/lilishop-ui) |
3.店铺发货单 | **`lilishop-uniapp`** | 买家端 H5 / 微信小程序 / Android & iOS APP | [Gitee](https://gitee.com/beijing_hongye_huicheng/lilishop-uniapp) |
``` | **`docker`** | 容器化部署编排、镜像与数据库脚本 | [Gitee](https://gitee.com/beijing_hongye_huicheng/docker) · [MySQL 脚本](https://gitee.com/beijing_hongye_huicheng/docker/tree/master/init/mysql) |
时间:2021年9月15日 ---
``` ## 6. 开源与授权
新增功能:
增加供应商功能
```
### 版本升级 本项目遵循 [MIT](./LICENSE) 开源协议,版权归 **北京宏业汇成科技有限公司** 所有。允许个人及企业免费用于学习、研究、修改和商业用途(需保留原始版权和许可声明)。
``` ---
后续会持续版本升级,修复bug,完善功能,覆盖更多业务场景 o2o/b2b/s2b2b2c/跨境电商
后续会考虑推出微服务/中台等 企业级版本 ## 7. 社区与支持
```
### 技术亮点 我们欢迎任何形式的交流与贡献。在提问前,请先查阅 [产品文档](https://bdwx2tfwwt.feishu.cn/wiki/space/7675179368632617952?ccm_open_type=lark_wiki_spaceLink&open_tab_from=wiki_home),并参考 [《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md) 以便高效沟通。
- **[在线客服](https://work.weixin.qq.com/kfid/kfc4d8dc24a73c15f44)**
- **微信交流群**:
<img src="https://lilishop-wechat.oss-cn-beijing.aliyuncs.com/wechat.jpg" width="200" alt="微信群" />
1.后端框架基于Springboot,构建基于maven,持久层使用MyBatisPlus。使用elasticsearch、redis、mongodb、rocketmq 等各种中间健。都是主流架构,轻松应对各种环境。 ---
2.支持集群、分布式,支持docker 轻松部署,解决各种复杂场景! ## 8. 升级计划
3.代码模块清晰,主要分为三端api(买家、卖家、管理),各端API互相隔离,自己鉴权,自己操作业务。 ### ✅ 已完成特性
| 功能模块 | 功能模块 |
4.使用阿里开源的RocketMQ,基于mq解决各种并发场景,解决事务一致性,解决搞并发延迟场景问题。 | :--- | :--- |
| ✅ 商品定时上下架 | ✅ 商品分组 / 会员分组 |
5.项目使用多级缓存,应用不同场景,redis缓存业务数据、mongodb缓存关系型多对多关系问题、nginx缓存高频访问低频修改的页面。 | ✅ 商品虚拟销量 | ✅ 专用发票(发票上传) |
| ✅ 置顶评论 | ✅ 客户等级体系 |
6.支持各种联合登陆,支持各种客户端的支付问题,灵活配置灵活开启。 | ✅ 购物卡 | ✅ 腾讯云-云直播 |
| ✅ 卡密商品 | ✅ 二级分销 |
7.内置完善的楼层装修机制,各种拖拉拽,维护跳转页面或外网,即便是一个什么都不懂的运营也可以轻松掌握。 | ✅ 定时任务管理 | ✅ 预约服务商品 |
| ✅ 主题色管理 | ✅ 商家发货改造(整单/拆单/无需配送) |
8.内置阿里短信接口,可以在线申请短信模版。内置阿里oss系统,可以对文件执行各种操作。oss商家端资源相互隔离。 | ✅ 多维统计(营业/商品/会员/积分/储值/营销/分销) | ✅ 经营报表(店铺业绩/商品同比环比/订单明细/销售汇总) |
10.强大的统计报表,统计效果,可以实现各个场景,包含在线人数,历史在线人数,活跃人数等信息。
11.标准Api接口、提供swagger文档,快速二开。
12.分布式调度任务中心,解决分布式定时任务多次执行问题。
13.代码注释完善,快速上手。
14.非移动端采用IView框架,各种自定义插件、选择器实现。移动端采用uniapp,一次编写,全端使用
15.已经对接好各种第三方插件,支持各种复杂等联合登陆,联合支付等场景。
### 开源须知
1.仅允许用于个人学习研究使用.
2.禁止将本开源的代码和资源进行任何形式任何名义的出售.
3.限制商用,如果需要商业使用请联系我们。QQ3409056806.
### 交流群
**QQ群**:961316482
### 🔜 近期规划中
- 🔜 店铺结算汇总 & 结算台账
- 🔜 支付方式汇总 & 钱包流水 & 财务汇总
- 🔜 微信小店对接
- 🔜 抖店对接

19
build.sh Normal file
View File

@@ -0,0 +1,19 @@
#代码目录
code_path=$PWD
git pull
cd ${code_path}/manager
rm -rf ./dist
yarn install
yarn build
cd ${code_path}/seller
rm -rf ./dist
yarn install
yarn build
cd ${code_path}/buyer
rm -rf ./dist
yarn install
yarn build

View File

@@ -1,12 +0,0 @@
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-vue-jsx", "transform-runtime"]
}

View File

@@ -1,4 +0,0 @@
/build/
/config/
/dist/
/*.js

View File

@@ -1,33 +0,0 @@
// https://eslint.org/docs/user-guide/configuring
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint'
},
env: {
browser: true,
},
extends: [
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
// consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
'plugin:vue/essential',
// https://github.com/standard/standard/blob/master/docs/RULES-en.md
'standard'
],
// required to lint *.vue files
plugins: [
'vue'
],
// add your custom rules here
rules: {
"semi": [0, "never"],
// allow async-await
'generator-star-spacing': 'off',
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
"vue/no-parsing-error": [2, {
"x-invalid-end-tag": false
}]
}
}

1
buyer/.npmrc Normal file
View File

@@ -0,0 +1 @@
engine-strict=false

1
buyer/.yarnrc Normal file
View File

@@ -0,0 +1 @@
--ignore-engines true

View File

@@ -1,8 +1,13 @@
FROM nginx:alpine FROM node:10.19.0 as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
RUN mkdir -p /app/ # production stage
COPY ./dist /app/ FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/nginx.conf COPY ./nginx.conf /etc/nginx/nginx.conf
EXPOSE 80 EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]k

55
buyer/MIGRATION-VUE3.md Normal file
View File

@@ -0,0 +1,55 @@
# Buyer 买家端 Vue 3 迁移说明
## 技术栈
- Vue 3 + Vue Router 4 + Pinia(vuex 已移除,见下文"组合式 API 迁移")
- Element Plus(替代 view-design / iView)
- 保留 `$Message` / `$Modal` / `$Notice` 兼容层(`src/utils/message.js`)
## 启动
```bash
cd buyer
yarn install
yarn dev # 默认端口 10000
yarn build
```
## 迁移要点
1. **入口** `src/main.js` 使用 `createApp`,全局过滤器改为 `$filters`
2. **路由** `src/router/index.js` 使用 `createRouter` + 动态 `import()`
3. **请求** `src/plugins/request.js` 使用 Element Plus `ElLoading`
4. **iView 组件已全部替换**:轮播 `el-carousel`、下拉 `el-dropdown`、侧栏 `el-menu`、头像 `el-avatar` 等
5. **图标映射** `src/utils/iconMap.js` — 动态图标(如侧边栏菜单)通过 `resolveIcon()` 使用
6. **自定义字体图标** `icomoon` 保留为 `<i class="icomoon icon-*">`(购物车步骤条、钱包等)
7. **首页装修** `indexDecorate/modelList` 保留买家端展示逻辑(非 manager 编辑版)
8. **特殊替换**
- `vue-piczoom` → `el-image` 预览
- `mv-count-down` → 内置倒计时
- 秒杀轮播 → 横向滚动列表
## 组合式 API 迁移(2026-10 完成)
全部 95 个 `.vue` 组件已从 Options API 转换为 `<script setup>`,同时完成 vuex → pinia:
- **状态管理**:`src/stores/app.js`(`useAppStore`:navList / cartNum / unreadMsg / logoImg / siteName / hotWordsList / category + 对应 setXxx actions)。原 `src/vuex/` 已删除,package.json 不再依赖 vuex。
- **路由守卫**:`beforeRouteEnter` 无组合式等价物,5 个页面(`GoodsList` / `GoodsDetail` / `PointGoodsDetail` / `Cart` / `ShoppingCart`)保留普通 `<script>` 块存放 `export default { name, beforeRouteEnter }`——这是官方支持的合并写法,统计 Options API 残留时需排除。
- **defineExpose**:以下组件的方法/状态被父组件通过模板 ref 调用,已显式暴露:`verify`(init / close)、`multiple-map`(open)、`addressManage`(show / hide)、`invoiceModal`(invoiceAvailable)。新增此类父子调用时必须加 `defineExpose`。
- **模板 ref 与响应式变量同名会互相覆盖**:同名时模板 ref 统一改名 `xxxRef`(如 `formRef` / `verifyRef`)。
- **mixin 已消除**:原 `components/mixes/talkIm.vue` 的 IM 客服逻辑已内联进 `Merchant.vue` 和 `goodsDetail/StoreSide.vue`,文件已删除。
- **全局属性照旧**:模板中的 `$filters.*` / `linkTo` / `connectCs` / `$inputMaxLength` 是 `main.js` 注册的全局属性,`<script setup>` 下模板可直接使用;script 内使用 `$filters` 函数需从 `@/plugins/filters.js` 具名导入,`this.Cookies` 等同 `storage`(`@/plugins/storage`)。
- **其余三端(seller / manager / im)仍为 Options API + vuex**,迁移时参照本端模式。
## 批量脚本
- `scripts/migrate-iview-to-element.js` — iView → Element 模板替换
- `scripts/fix-filters.js` — Vue 2 过滤器语法修复
- `scripts/replace-page.js` — `<Page>` → `el-pagination`
- `scripts/replace-icon.js` — 静态 `<Icon type>` → `el-icon`
- `scripts/fix-el-icon-click.js` — 修复 `@click` 绑定
- `scripts/fix-broken-tags.js` — 闭合标签修复
## 上线前检查
四端统一清单(认证、axios、Element Plus、分端专项):[../MIGRATION-VUE3.md](../MIGRATION-VUE3.md)

View File

@@ -1,19 +0,0 @@
# new
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

View File

@@ -1 +1 @@
docker build -t registry.cn-beijing.aliyuncs.com/lili-images/buyer-ui-4.2.0:0.0.2 . docker build -t registry.cn-beijing.aliyuncs.com/lili-images/buyer-ui:4.2.4.1 .

36
buyer/eslint.config.js Normal file
View File

@@ -0,0 +1,36 @@
const globals = require('globals')
const pluginVue = require('eslint-plugin-vue')
module.exports = [
{
ignores: [
'dist/**',
'node_modules/**',
'build/**',
'config/**',
'src/scripts/**', // 一次性迁移脚本,不参与 lint
],
},
...pluginVue.configs['flat/essential'],
{
files: ['src/**/*.{js,vue}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
...globals.browser,
},
},
rules: {
'no-console': ['warn', { allow: ['warn', 'error'] }],
'no-empty': ['error', { allowEmptyCatch: false }],
'vue/no-parsing-error': ['error', { 'x-invalid-end-tag': false }],
// 页面组件通过路由按文件路径引用,组件名不参与解析,存量单词组件名不再强制多词
'vue/multi-word-component-names': 'off',
// 存量代码大量使用与 HTML 保留名同名的组件(element-plus 图标 Search/View/Camera/Link 及全局注册的 empty/drawer 等),重命名成本高,暂不启用
'vue/no-reserved-component-names': 'off',
// 全端已完成 Options API → <script setup> 迁移,防止新代码回退(路由守卫的普通 script 块等有意保留的除外,故用 warn)
'vue/component-api-style': ['warn', ['script-setup']],
},
},
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,51 +1,46 @@
#这个文件给docker用的 #这个文件给docker用的
#user nobody; #user nobody;
worker_processes 1; worker_processes 1;
#error_log logs/error.log; #error_log logs/error.log;
#error_log logs/error.log notice; #error_log logs/error.log notice;
#error_log logs/error.log info; #error_log logs/error.log info;
#pid logs/nginx.pid; #pid logs/nginx.pid;
events { events {
worker_connections 1024; worker_connections 1024;
} }
http { http {
include mime.types; include mime.types;
default_type application/octet-stream; default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" ' #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" ' # '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"'; # '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main; #access_log logs/access.log main;
sendfile on;
sendfile on;
#tcp_nopush on; #tcp_nopush on;
#keepalive_timeout 0; #keepalive_timeout 0;
keepalive_timeout 65; keepalive_timeout 65;
client_max_body_size 10m; client_max_body_size 10m;
gzip on; gzip on;
gzip_min_length 5k; gzip_min_length 5k;
gzip_buffers 4 16k; gzip_buffers 4 16k;
gzip_http_version 1.0; gzip_http_version 1.0;
gzip_comp_level 4; gzip_comp_level 4;
gzip_types text/plain application/x-javascript application/javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png; gzip_types text/plain application/x-javascript application/javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary on; gzip_vary on;
server { server {
listen 10000; listen 10000;
server_name localhost;
location / { location / {
root /app; root /app;
try_files $uri $uri/ /index.html $uri/ =404; try_files $uri $uri/ /index.html $uri/ =404;
index index.html index.htm; index index.html index.htm;
} }
} }
} }

9902
buyer/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,40 +3,54 @@
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vue-cli-service serve",
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
"build": "vue-cli-service build" "build": "vue-cli-service build",
"dev": "vue-cli-service serve",
"lint": "eslint src",
"lint:fix": "eslint src --fix"
},
"engines": {
"node": ">=16"
}, },
"dependencies": { "dependencies": {
"@amap/amap-jsapi-loader": "0.0.7", "@amap/amap-jsapi-loader": "0.0.7",
"axios": "^0.19.2", "@element-plus/icons-vue": "^2.3.2",
"axios": "^1.7.9",
"core-js": "^3.49.0",
"dplayer": "^1.27.1",
"element-plus": "^2.14.1",
"js-cookie": "^2.2.1", "js-cookie": "^2.2.1",
"less": "^2.7.0", "nprogress": "^0.2.0",
"less-loader": "^5.0.0", "pinia": "^4.0.3",
"mv-count-down": "^0.1.15",
"node-sass": "^4.14.1",
"psl": "^1.8.0", "psl": "^1.8.0",
"qs": "^6.9.4", "qs": "^6.9.4",
"sass-loader": "^7.3.1", "sass": "^1.63.6",
"sass-loader": "^10.4.1",
"uuid": "^8.3.2", "uuid": "^8.3.2",
"view-design": "^4.3.2", "vue": "^3.5.35",
"vue": "^2.6.11", "vue-qr": "^5.0.3",
"vue-awesome-swiper": "^3.1.3", "vue-router": "^4.6.4"
"vue-piczoom": "^1.0.6",
"vue-qr": "^2.3.0",
"vue-router": "^3.0.1",
"vuex": "^3.0.1"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-service": "~4.5.0", "@vue/cli-plugin-babel": "^5.0.9",
"compression-webpack-plugin": "^5.0.0", "@vue/cli-service": "^5.0.9",
"sass-loader": "^7.3.1", "@vue/compiler-sfc": "^3.5.35",
"uglifyjs-webpack-plugin": "^2.2.0", "compression-webpack-plugin": "^10.0.0",
"vue-template-compiler": "^2.6.11" "eslint": "^9.39.4",
"eslint-plugin-vue": "^10.11.1",
"globals": "^17.13.0",
"less": "^4.2.0",
"less-loader": "^11.1.4",
"vue-eslint-parser": "^10.4.1",
"webpack": "^5.95.0"
}, },
"browserslist": [ "browserslist": [
"> 1%", "> 1%",
"last 2 versions", "last 2 versions",
"not dead" "not dead"
] ],
"resolutions": {
"minimatch": "^3.1.2",
"@achrinza/node-ipc": "9.2.2"
}
} }

8672
buyer/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

11
buyer/public/config.js Normal file
View File

@@ -0,0 +1,11 @@
var BASE = {
/**
* @description api请求基础路径
*/
API_DEV: {
buyer: "https://buyer-api.pickmall.cn",
},
API_PROD: {
buyer: "https://buyer-api.pickmall.cn",
},
};

View File

@@ -3,21 +3,16 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name='description' content='在线购物平台'>
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>logo.ico"> <link rel="icon" href="<%= BASE_URL %>logo.ico">
<title><%= htmlWebpackPlugin.options.title %></title> <title><%= htmlWebpackPlugin.options.title %></title>
<% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
<link rel="stylesheet" href="<%=css%>" />
<% } %>
</head> </head>
<body> <body>
<% for(var js of htmlWebpackPlugin.options.cdn.js) { %> <script src="<%= BASE_URL %>config.js"></script>
<script src="<%=js%>"></script>
<% } %>
<noscript> <noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript> </noscript>
<div id="app"></div> <div id="app"></div>
<!-- built files will be auto injected -->
</body> </body>
</html> </html>

View File

@@ -0,0 +1,54 @@
#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const ROOT = path.join(__dirname, "..");
function walkDir(dir, files = []) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) walkDir(full, files);
else if (entry.name.endsWith(".vue")) files.push(full);
}
return files;
}
function fix(content) {
let c = content;
c = c.replace(/<\/Button>/g, "</el-button>");
c = c.replace(/<\/Button\b/g, "</el-button");
c = c.replace(/<\/Input>/g, "</el-input>");
c = c.replace(/<\/Input\b/g, "</el-input");
c = c.replace(/<\/Option>/g, "</el-option>");
c = c.replace(/<\/Option\b/g, "</el-option");
c = c.replace(/<\/Checkbox>/g, "</el-checkbox>");
c = c.replace(/<\/Checkbox\b/g, "</el-checkbox");
c = c.replace(/<\/Select>/g, "</el-select>");
c = c.replace(/<\/Select\b/g, "</el-select");
c = c.replace(/<\/Form>/g, "</el-form>");
c = c.replace(/<\/Modal>/g, "</el-dialog>");
c = c.replace(/@click\.native/g, "@click");
c = c.replace(/@on-search/g, "@keyup.enter");
c = c.replace(/\bsearch\b(?=\s+enter-button)/g, "");
c = c.replace(/\benter-button\b/g, "");
c = c.replace(/<BreadcrumbItem/g, "<el-breadcrumb-item");
c = c.replace(/<\/BreadcrumbItem>/g, "</el-breadcrumb-item>");
c = c.replace(/<Breadcrumb/g, "<el-breadcrumb");
c = c.replace(/<\/Breadcrumb>/g, "</el-breadcrumb>");
c = c.replace(/type="error"/g, 'type="danger"');
c = c.replace(/<i-col/g, "<div");
c = c.replace(/<\/i-col>/g, "</div>");
c = c.replace(/\{\{([^}|]+)\s*\|\s*secrecyMobile\s*\}\}/g, "{{ $filters.secrecyMobile($1) }}");
return c;
}
let count = 0;
for (const file of walkDir(path.join(ROOT, "src"))) {
const original = fs.readFileSync(file, "utf8");
const fixed = fix(original);
if (fixed !== original) {
fs.writeFileSync(file, fixed);
count++;
}
}
console.log(`Fixed tags in ${count} files`);

View File

@@ -0,0 +1,52 @@
#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const ROOT = path.join(__dirname, "..");
function walkDir(dir, files = []) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) walkDir(full, files);
else if (entry.name.endsWith(".vue")) files.push(full);
}
return files;
}
function fix(content) {
let c = content;
c = c.replace(/<p #header>/g, "<template #header><p>");
c = c.replace(
/(<template #header><p>[\s\S]*?<\/p>)(\s*<div)/g,
"$1</template>$2"
);
c = c.replace(
/<template #footer><div([^>]*)>([\s\S]*?)<\/div><\/template><\/el-dialog>/g,
"<template #footer><div$1>$2</div></template>\n </el-dialog>"
);
c = c.replace(
/<template #default\s*>([\s\S]*?)<\/template\s*>/g,
(match, inner) => {
if (match.includes("el-alert")) {
return `<template #title>${inner}</template>`;
}
return match;
}
);
return c;
}
let count = 0;
for (const file of walkDir(path.join(ROOT, "src"))) {
const original = fs.readFileSync(file, "utf8");
const fixed = fix(original);
if (fixed !== original) {
fs.writeFileSync(file, fixed);
count++;
}
}
console.log(`Fixed dialog slots in ${count} files`);

View File

@@ -0,0 +1,26 @@
#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const ROOT = path.join(__dirname, "..", "src");
function walk(dir, files = []) {
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
const f = path.join(dir, e.name);
if (e.isDirectory()) walk(f, files);
else if (e.name.endsWith(".vue")) files.push(f);
}
return files;
}
let n = 0;
for (const file of walk(ROOT)) {
let c = fs.readFileSync(file, "utf8");
const next = c.replace(/:size="(\d+)"\s+:size="\1"/g, ':size="$1"');
if (next !== c) {
fs.writeFileSync(file, next);
n++;
console.log(path.relative(ROOT, file));
}
}
console.log(`Fixed duplicate :size in ${n} files`);

View File

@@ -0,0 +1,28 @@
#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const ROOT = path.join(__dirname, "..", "src");
function walk(dir, files = []) {
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
const f = path.join(dir, e.name);
if (e.isDirectory()) walk(f, files);
else if (e.name.endsWith(".vue")) files.push(f);
}
return files;
}
let n = 0;
for (const file of walk(ROOT)) {
let c = fs.readFileSync(file, "utf8");
const next = c
.replace(/<el-icon([^>]*?):click=/g, "<el-icon$1@click=")
.replace(/:class="refresh"/g, 'class="refresh"')
.replace(/:size="20" @click="show = false" :size="20"/g, ':size="20" @click="show = false"');
if (next !== c) {
fs.writeFileSync(file, next);
n++;
}
}
console.log(`Fixed el-icon click in ${n} files`);

View File

@@ -0,0 +1,77 @@
#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const ROOT = path.join(__dirname, "..");
function walkDir(dir, files = []) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) walkDir(full, files);
else if (entry.name.endsWith(".vue")) files.push(full);
}
return files;
}
function fixFilters(content) {
let c = content;
// Fix broken: {{ expr {{ $filters.unitPrice(args) }}
c = c.replace(
/\{\{\s*([^}{]+?)\s*\{\{\s*\$filters\.unitPrice\(([^)]*)\)\s*\}\}/g,
"{{ $filters.unitPrice($1, $2) }}"
);
// Fix: {{ expr | unitPrice }} or {{ expr | unitPrice('¥') }}
c = c.replace(
/\{\{\s*([^}|]+?)\s*\|\s*unitPrice(?:\(([^)]*)\))?\s*\}\}/g,
(_, expr, args) => {
const e = expr.trim();
return args !== undefined
? `{{ $filters.unitPrice(${e}, ${args}) }}`
: `{{ $filters.unitPrice(${e}) }}`;
}
);
// Fix inline without braces: expr | unitPrice("¥")
c = c.replace(
/(?<!\{\{)\s*([a-zA-Z0-9_.?()[\]'"\s]+?)\s*\|\s*unitPrice\(([^)]*)\)/g,
(match, expr, args) => {
if (match.includes("{{")) return match;
return `{{ $filters.unitPrice(${expr.trim()}, ${args}) }}`;
}
);
// Fix inline without args: expr | unitPrice
c = c.replace(
/(?<!\{\{)\s*([a-zA-Z0-9_.?()[\]'"\s]+?)\s*\|\s*unitPrice(?!\()/g,
(match, expr) => {
if (match.includes("{{") || match.includes("$filters")) return match;
return `{{ $filters.unitPrice(${expr.trim()}) }}`;
}
);
// Fix unixToDate filter
c = c.replace(
/\{\{\s*([^}|]+?)\s*\|\s*unixToDate(?:\(([^)]*)\))?\s*\}\}/g,
(_, expr, args) => {
const e = expr.trim();
return args !== undefined
? `{{ $filters.unixToDate(${e}, ${args}) }}`
: `{{ $filters.unixToDate(${e}) }}`;
}
);
return c;
}
let count = 0;
for (const file of walkDir(path.join(ROOT, "src"))) {
const original = fs.readFileSync(file, "utf8");
const fixed = fixFilters(original);
if (fixed !== original) {
fs.writeFileSync(file, fixed);
count++;
}
}
console.log(`Fixed filters in ${count} files`);

View File

@@ -0,0 +1,55 @@
#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const ROOT = path.join(__dirname, "..");
function walkDir(dir, files = []) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) walkDir(full, files);
else if (entry.name.endsWith(".vue")) files.push(full);
}
return files;
}
function fix(content) {
let c = content;
c = c.replace(/<el-pagination\b/g, "<Page");
c = c.replace(/<\/el-pagination>/g, "</Page>");
c = c.replace(
/<Icon([^>]*)\s+#prepend\s*>\s*<\/Icon>/g,
"<template #prepend><Icon$1></Icon></template>"
);
c = c.replace(
/<Icon([^>]*)\s+#prepend\s*>\s*<\/Icon>/g,
"<template #prepend><Icon$1></Icon></template>"
);
c = c.replace(
/<template #prepend><Icon([^>]*)\s*\/>/g,
"<template #prepend><Icon$1></Icon></template>"
);
c = c.replace(/@keyup\.enter\.native/g, "@keyup.enter");
c = c.replace(/slot="append"/g, "#append");
c = c.replace(/(<div[^>]*)\s+#append/g, "<template #append>$1");
c = c.replace(/(<el-button[^>]*)\slong/g, '$1 style="width:100%"');
c = c.replace(/@on-select/g, "@select");
c = c.replace(/@on-click/g, "@click");
return c;
}
let count = 0;
for (const file of walkDir(path.join(ROOT, "src"))) {
const original = fs.readFileSync(file, "utf8");
const fixed = fix(original);
if (fixed !== original) {
fs.writeFileSync(file, fixed);
count++;
}
}
console.log(`Runtime compat fixes in ${count} files`);

View File

@@ -0,0 +1,54 @@
#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const ROOT = path.join(__dirname, "..");
function walkDir(dir, files = []) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) walkDir(full, files);
else if (entry.name.endsWith(".vue")) files.push(full);
}
return files;
}
function fix(content) {
let c = content;
c = c.replace(
/<template #default="(\{[^"]+\})" #([a-zA-Z0-9_-]+)>/g,
'<template #$2="$1">'
);
c = c.replace(
/<div([^>]*) #footer([^>]*)>/g,
'<template #footer><div$1$2>'
);
c = c.replace(/<\/div>\s*(?=<\/el-dialog>)/g, "</div></template>");
c = c.replace(/<span #append>/g, "<template #append><span>");
c = c.replace(/<\/span><\/el-input/g, "</span></template></el-input");
c = c.replace(/><span #append>/g, "><template #append><span>");
c = c.replace(/<el-button #append/g, "<template #append><el-button");
c = c.replace(
/<\/el-button>(\s*<\/el-input>)/g,
"</el-button></template>$1"
);
c = c.replace(/<template #desc\b/g, "<template #default");
return c;
}
let count = 0;
for (const file of walkDir(path.join(ROOT, "src"))) {
const original = fs.readFileSync(file, "utf8");
const fixed = fix(original);
if (fixed !== original) {
fs.writeFileSync(file, fixed);
count++;
}
}
console.log(`Fixed slots in ${count} files`);

View File

@@ -0,0 +1,46 @@
#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const ROOT = path.join(__dirname, "..");
function walkDir(dir, files = []) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) walkDir(full, files);
else if (entry.name.endsWith(".vue")) files.push(full);
}
return files;
}
function fix(content) {
let c = content;
c = c.replace(/<\/span\s*\n\s*>/g, "</span>");
c = c.replace(/<\/span\s+>/g, "</span>");
c = c.replace(/<i-input/g, "<el-input");
c = c.replace(/<\/i-input>/g, "</el-input>");
c = c.replace(
/<Icon([^>]*)\s+#prepend\s*\/>/g,
"<template #prepend><Icon$1 /></template>"
);
c = c.replace(
/<template #append><el-button([^>]*)>([\s\S]*?)<\/el-button>\s*<\/i-input>/g,
"<template #append><el-button$1>$2</el-button></template></el-input>"
);
c = c.replace(
/<template #append><el-button([^>]*)>([\s\S]*?)<\/el-button>\s*<\/el-input>/g,
"<template #append><el-button$1>$2</el-button></template></el-input>"
);
return c;
}
let count = 0;
for (const file of walkDir(path.join(ROOT, "src"))) {
const original = fs.readFileSync(file, "utf8");
const fixed = fix(original);
if (fixed !== original) {
fs.writeFileSync(file, fixed);
count++;
}
}
console.log(`Fixed span/input tags in ${count} files`);

View File

@@ -0,0 +1,55 @@
#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const ROOT = path.join(__dirname, "..");
function walkDir(dir, files = []) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) walkDir(full, files);
else if (entry.name.endsWith(".vue")) files.push(full);
}
return files;
}
function fix(content) {
let c = content;
c = c.replace(
/(<div[^>]*)\s+#content>/g,
"<template #content><div$1>"
);
c = c.replace(
/(<\/el-tooltip>)/g,
(match, _m, offset, str) => {
return match;
}
);
c = c.replace(
/(<div style="white-space:[^"]*"[^>]*>[\s\S]*?<\/div>)(\s*<\/el-tooltip>)/g,
"$1</template>$2"
);
c = c.replace(/<\/div><\/template><\/el-dialog>/g, (m, offset, str) => {
const before = str.slice(Math.max(0, offset - 200), offset);
if (before.includes("#footer")) return m;
return "</div></el-dialog>";
});
c = c.replace(/<i(\s[^>]*)\/>/g, "<i$1></i>");
return c;
}
let count = 0;
for (const file of walkDir(path.join(ROOT, "src"))) {
const original = fs.readFileSync(file, "utf8");
const fixed = fix(original);
if (fixed !== original) {
fs.writeFileSync(file, fixed);
count++;
}
}
console.log(`Fixed stray templates in ${count} files`);

View File

@@ -0,0 +1,227 @@
#!/usr/bin/env node
/**
* Migrate buyer Vue files from iView to Element Plus.
* Usage: node scripts/migrate-iview-to-element.js
*/
const fs = require("fs");
const path = require("path");
const BUYER_ROOT = path.join(__dirname, "..");
const MANAGER_ROOT = path.join(__dirname, "../../manager");
const MODEL_LIST = [
["Carousel.vue", "carousel.vue"],
["Carousel1.vue", "carousel1.vue"],
["Carousel2.vue", "carousel2.vue"],
["FirstPageAdvert.vue", "firstPageAdvert.vue"],
["NewGoodsSort.vue", "newGoodsSort.vue"],
["NotEnough.vue", "notEnough.vue"],
["Recommend.vue", "recommend.vue"],
["Seckill.vue", "seckill.vue"],
["forYour.vue", "forYour.vue"],
["goodsAndType.vue", "goodsAndType.vue"],
["mixModel.vue", "mixModel.vue"],
["oneRowThreeColumns.vue", "oneRowThreeColumns.vue"],
["onlyGoodsModel.vue", "onlyGoodsModel.vue"],
["mixs/mix-brand.vue", "mixs/mix-brand.vue"],
["mixs/mix-goods.vue", "mixs/mix-goods.vue"],
];
const DECORATE_COPY_MAP = [
[
"src/components/indexDecorate/ModelForm.vue",
"src/views/page-decoration/modelForm.vue",
],
[
"src/components/indexDecorate/ModelFormItem.vue",
"src/views/page-decoration/modelFormItem.vue",
],
];
MODEL_LIST.forEach(([buyerName, managerName]) => {
DECORATE_COPY_MAP.push([
`src/components/indexDecorate/modelList/${buyerName}`,
`src/views/page-decoration/modelList/${managerName}`,
]);
});
const TARGET_DIRS = ["src/pages", "src/components"];
function adaptBuyerContent(content) {
return content
.replace(/@\/views\/page-decoration\//g, "@/components/indexDecorate/")
.replace(/admin-setting/g, "buyer-setting")
.replace(/adminPCPageCache/g, "buyerPCPageCache")
.replace(/getStore\('adminPCPageCache'\)/g, "getStore('buyerPCPageCache')")
.replace(/setStore\('adminPCPageCache'/g, "setStore('buyerPCPageCache'");
}
function applyScriptTransforms(content) {
let c = content;
c = c.replace(/\$options\.filters\./g, "$filters.");
c = c.replace(/\|\s*unitPrice\(/g, "{{ $filters.unitPrice(");
c = c.replace(/\|\s*unixToDate\(/g, "{{ $filters.unixToDate(");
c = c.replace(/\bbeforeDestroy\b/g, "beforeUnmount");
c = c.replace(/this\.\$set\(([^,]+),\s*([^,]+),\s*([^)]+)\)/g, "$1[$2] = $3");
c = c.replace(/::v-deep/g, ":deep");
c = c.replace(/\/deep\//g, ":deep");
c = c.replace(/@on-change/g, "@change");
c = c.replace(/@on-click/g, "@click");
c = c.replace(/@on-ok/g, "@ok");
c = c.replace(/@on-cancel/g, "@cancel");
c = c.replace(/@on-clear/g, "@clear");
c = c.replace(/@on-open-change/g, "@visible-change");
c = c.replace(/@on-page-size-change/g, "@size-change");
c = c.replace(/@on-select/g, "@select");
c = c.replace(/@keydown\.enter\.native/g, "@keyup.enter");
c = c.replace(/slot-scope="([^"]+)"/g, '#default="$1"');
c = c.replace(/slot="([^"]+)"/g, '#$1');
c = c.replace(/from ['"]view-design['"]/g, 'from "@/utils/message"');
c = c.replace(/import\s*\{([^}]*)\}\s*from\s*['"]view-design['"]/g, 'import {$1} from "@/utils/message"');
return c;
}
function applyTemplateTransforms(content) {
let c = content;
const replacements = [
[/<\/?Card>/g, (m) => m.replace("Card", "el-card")],
[/<Form-item/g, "<el-form-item"],
[/<\/Form-item>/g, "</el-form-item>"],
[/<FormItem/g, "<el-form-item"],
[/<\/FormItem>/g, "</el-form-item>"],
[/<Form(\s|>)/g, "<el-form$1"],
[/<\/Form>/g, "</el-form>"],
[/<InputNumber/g, "<el-input-number"],
[/<\/InputNumber>/g, "</el-input-number>"],
[/<Input(\s|>)/g, "<el-input$1"],
[/<\/Input>/g, "</el-input>"],
[/<Button(\s|>)/g, "<el-button$1"],
[/<\/Button>/g, "</el-button>"],
[/<Select(\s|>)/g, "<el-select$1"],
[/<\/Select>/g, "</el-select>"],
[/<Option(\s)/g, "<el-option "],
[/<\/Option>/g, "</el-option>"],
[/<DatePicker/g, "<el-date-picker"],
[/<\/DatePicker>/g, "</el-date-picker>"],
[/<TimePicker/g, "<el-time-picker"],
[/<\/TimePicker>/g, "</el-time-picker>"],
[/<Modal/g, "<el-dialog"],
[/<\/Modal>/g, "</el-dialog>"],
[/<Page(\s)/g, "<el-pagination "],
[/<\/Page>/g, "</el-pagination>"],
[/<Tabs(\s|>)/g, "<el-tabs$1"],
[/<\/Tabs>/g, "</el-tabs>"],
[/<TabPane/g, "<el-tab-pane"],
[/<\/TabPane>/g, "</el-tab-pane>"],
[/<Row(\s|>)/g, "<div$1"],
[/<\/Row>/g, "</div>"],
[/<Col(\s|>)/g, "<div$1"],
[/<\/Col>/g, "</div>"],
[/<Tag(\s|>)/g, "<el-tag$1"],
[/<\/Tag>/g, "</el-tag>"],
[/<Switch(\s|>)/g, "<el-switch$1"],
[/<\/Switch>/g, "</el-switch>"],
[/<RadioGroup/g, "<el-radio-group"],
[/<\/RadioGroup>/g, "</el-radio-group>"],
[/<Radio(\s)/g, "<el-radio "],
[/<\/Radio>/g, "</el-radio>"],
[/<CheckboxGroup/g, "<el-checkbox-group"],
[/<\/CheckboxGroup>/g, "</el-checkbox-group>"],
[/<Checkbox/g, "<el-checkbox"],
[/<\/Checkbox>/g, "</el-checkbox>"],
[/<Poptip/g, "<el-popover"],
[/<\/Poptip>/g, "</el-popover>"],
[/<Tooltip/g, "<el-tooltip"],
[/<\/Tooltip>/g, "</el-tooltip>"],
[/<Drawer/g, "<el-drawer"],
[/<\/Drawer>/g, "</el-drawer>"],
[/<Alert/g, "<el-alert"],
[/<\/Alert>/g, "</el-alert>"],
[/<Badge/g, "<el-badge"],
[/<\/Badge>/g, "</el-badge>"],
[/<Divider/g, "<el-divider"],
[/<\/Divider>/g, "</el-divider>"],
[/<Rate/g, "<el-rate"],
[/<\/Rate>/g, "</el-rate>"],
[/<Steps/g, "<el-steps"],
[/<\/Steps>/g, "</el-steps>"],
[/<Step(\s)/g, "<el-step "],
[/<\/Step>/g, "</el-step>"],
[/<Upload/g, "<el-upload"],
[/<\/Upload>/g, "</el-upload>"],
[/<Cascader/g, "<el-cascader"],
[/<\/Cascader>/g, "</el-cascader>"],
[/<Affix/g, "<el-affix"],
[/<\/Affix>/g, "</el-affix>"],
[/<Spin/g, "<el-skeleton"],
[/<\/Spin>/g, "</el-skeleton>"],
[/:label-width="(\d+)"/g, 'label-width="$1px"'],
[/:mask-closable="false"/g, ':close-on-click-modal="false"'],
[/:width="(\d+)"/g, 'width="$1"'],
[/type="primary"/g, 'type="primary"'],
];
for (const [pattern, replacement] of replacements) {
c = c.replace(pattern, replacement);
}
return c;
}
function walkDir(dir, files = []) {
if (!fs.existsSync(dir)) return files;
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) {
walkDir(full, files);
} else if (entry.name.endsWith(".vue")) {
files.push(full);
}
}
return files;
}
const copied = [];
const transformed = [];
const skipped = [];
for (const [buyerRel, managerRel] of DECORATE_COPY_MAP) {
const managerPath = path.join(MANAGER_ROOT, managerRel);
const buyerPath = path.join(BUYER_ROOT, buyerRel);
if (!fs.existsSync(managerPath)) {
skipped.push({ file: buyerRel, reason: "manager counterpart missing" });
continue;
}
let content = fs.readFileSync(managerPath, "utf8");
content = adaptBuyerContent(content);
fs.mkdirSync(path.dirname(buyerPath), { recursive: true });
fs.writeFileSync(buyerPath, content);
copied.push(buyerRel);
}
const copiedSet = new Set(copied);
for (const dir of TARGET_DIRS) {
const absDir = path.join(BUYER_ROOT, dir);
for (const filePath of walkDir(absDir)) {
const rel = path.relative(BUYER_ROOT, filePath).replace(/\\/g, "/");
if (copiedSet.has(rel)) continue;
let content = fs.readFileSync(filePath, "utf8");
const hasIView =
/<(Card|Form|Form-item|FormItem|Table|Button|Modal|Page|Tabs|TabPane|Input|Select|Option|DatePicker|Row|Poptip|Drawer|Upload|Checkbox|Radio|Switch|Tag|Alert|Rate|Steps|Step|Spin|Affix|TimePicker|Cascader|Divider|Badge|InputNumber)\b/.test(
content
);
if (!hasIView) {
skipped.push({ file: rel, reason: "no iView components" });
continue;
}
content = applyTemplateTransforms(content);
content = applyScriptTransforms(content);
fs.writeFileSync(filePath, content);
transformed.push(rel);
}
}
console.log("=== Buyer Migration Summary ===");
console.log(`Copied from manager: ${copied.length}`);
console.log(`Script-transformed: ${transformed.length}`);
console.log(`Skipped: ${skipped.length}`);

View File

@@ -0,0 +1,149 @@
#!/usr/bin/env node
/**
* 将静态 <Icon type="..." /> 替换为 <el-icon><Xxx /></el-icon>
* 动态 :type / custom 属性保留,由人工或 resolveIcon 处理。
*/
const fs = require("fs");
const path = require("path");
const ROOT = path.join(__dirname, "..", "src");
const TYPE_TO_COMPONENT = {
"md-checkmark": "Check",
"md-close": "Close",
"md-trash": "Delete",
"md-add": "Plus",
"md-arrow-dropdown": "ArrowDown",
"md-arrow-dropup": "ArrowUp",
"md-person": "User",
"md-lock": "Lock",
"md-phone-portrait": "Iphone",
"md-key": "Key",
"md-link": "Link",
"md-refresh": "Refresh",
"md-qr-scanner": "Iphone",
"ios-arrow-down": "ArrowDown",
"ios-arrow-up": "ArrowUp",
"ios-arrow-forward": "ArrowRight",
"ios-arrow-back": "ArrowLeft",
"ios-arrow-round-down": "ArrowDown",
"ios-arrow-round-forward": "ArrowRight",
"ios-cart-outline": "ShoppingCart",
"ios-camera": "Camera",
"ios-eye-outline": "View",
"ios-trash-outline": "Delete",
"ios-alert-outline": "Warning",
"ios-help-circle-outline": "Help",
"ios-add-circle-outline": "Plus",
"ios-information-circle": "InfoFilled",
"ios-search": "Search",
"ios-text-outline": "Document",
"ios-alarm-outline": "AlarmClock",
"ios-heart": "StarFilled",
"md-close-circle": "CircleClose",
edit: "Edit",
"trash-a": "Delete",
location: "Location",
};
function walkDir(dir, files = []) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory() && entry.name !== "compat") walkDir(full, files);
else if (entry.name.endsWith(".vue")) files.push(full);
}
return files;
}
function parseAttrs(attrStr) {
const attrs = {};
const re = /(?::([\w-]+)|@([\w-]+)|([\w-]+))=(?:"([^"]*)"|'([^']*)')|(?::([\w-]+)|@([\w-]+)|([\w-]+))(?=\s|\/|>)/g;
let m;
while ((m = re.exec(attrStr)) !== null) {
const name = m[1] || m[2] || m[3] || m[6] || m[7] || m[8];
const value = m[4] ?? m[5] ?? true;
attrs[name] = value;
}
return attrs;
}
function attrsToString(attrs, exclude = []) {
return Object.entries(attrs)
.filter(([k]) => !exclude.includes(k))
.map(([k, v]) => {
if (v === true) return k;
if (k.startsWith("@")) return `${k}="${v}"`;
return `:${k}="${v}"`;
})
.join(" ");
}
function transform(content, filePath) {
if (filePath.includes("/compat/")) return content;
let c = content;
const used = new Set();
c = c.replace(/<Icon\b([^>]*?)\/>/g, (match, attrStr) => {
if (/\bcustom=/.test(attrStr) || /:type=/.test(attrStr)) return match;
const attrs = parseAttrs(attrStr);
const type = attrs.type;
if (!type || !TYPE_TO_COMPONENT[type]) return match;
const comp = TYPE_TO_COMPONENT[type];
used.add(comp);
const rest = attrsToString(attrs, ["type"]);
const size = attrs.size ? ` :size="${attrs.size}"` : "";
const open = rest ? `<el-icon ${rest}${size}>` : `<el-icon${size}>`;
return `${open}<${comp} /></el-icon>`;
});
c = c.replace(/<Icon\b([^>]*?)><\/Icon>/g, (match, attrStr) => {
if (/\bcustom=/.test(attrStr) || /:type=/.test(attrStr)) return match;
const attrs = parseAttrs(attrStr);
const type = attrs.type;
if (!type || !TYPE_TO_COMPONENT[type]) return match;
const comp = TYPE_TO_COMPONENT[type];
used.add(comp);
const rest = attrsToString(attrs, ["type"]);
const size = attrs.size ? ` :size="${attrs.size}"` : "";
const open = rest ? `<el-icon ${rest}${size}>` : `<el-icon${size}>`;
return `${open}<${comp} /></el-icon>`;
});
if (used.size && !c.includes("@element-plus/icons-vue")) {
const imports = [...used].sort().join(", ");
c = c.replace(
/(<script[^>]*>\s*\n)/,
`$1import { ${imports} } from '@element-plus/icons-vue';\n`
);
c = c.replace(/export default \{/, (m) => {
if (/components:\s*\{/.test(c)) {
return m;
}
return `${m}\n components: { ${imports} },`;
});
if (/components:\s*\{/.test(c) && !c.includes(`${[...used][0]},`)) {
c = c.replace(/components:\s*\{([^}]*)\}/, (m, inner) => {
const existing = inner.trim();
const add = [...used].filter((n) => !inner.includes(n)).join(", ");
if (!add) return m;
const merged = existing ? `${existing}, ${add}` : add;
return `components: { ${merged} }`;
});
}
}
return c;
}
let count = 0;
for (const file of walkDir(ROOT)) {
const original = fs.readFileSync(file, "utf8");
if (!/<Icon\b/.test(original)) continue;
const fixed = transform(original, file);
if (fixed !== original) {
fs.writeFileSync(file, fixed);
count++;
console.log(path.relative(ROOT, file));
}
}
console.log(`Icon replacements in ${count} files`);

View File

@@ -0,0 +1,63 @@
#!/usr/bin/env node
/**
* 将全局 <Page> 封装替换为原生 el-pagination
*/
const fs = require("fs");
const path = require("path");
const ROOT = path.join(__dirname, "..", "src");
function walkDir(dir, files = []) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) walkDir(full, files);
else if (entry.name.endsWith(".vue")) files.push(full);
}
return files;
}
function transformPage(content) {
return content.replace(
/<Page\b([^>]*?)(\/>|>(\s*)<\/Page>)/gs,
(match, attrs, close) => {
let a = attrs;
const hasTotal = /\bshow-total\b/.test(a);
const hasSizer = /\bshow-sizer\b/.test(a);
const hasElevator = /\bshow-elevator\b/.test(a);
a = a.replace(/\s+show-total\b/g, "");
a = a.replace(/\s+show-sizer\b/g, "");
a = a.replace(/\s+show-elevator\b/g, "");
a = a.replace(/:current=/g, ":current-page=");
a = a.replace(/:page-size-opts=/g, ":page-sizes=");
a = a.replace(/@change=/g, "@current-change=");
a = a.replace(/\ssize="small"/g, " small");
const layoutParts = [];
if (hasTotal) layoutParts.push("total");
if (hasSizer) layoutParts.push("sizes");
layoutParts.push("prev", "pager", "next");
if (hasElevator) layoutParts.push("jumper");
const layoutAttr = ` layout="${layoutParts.join(", ")}"`;
if (close.startsWith("/>")) {
return `<el-pagination${a}${layoutAttr} />`;
}
return `<el-pagination${a}${layoutAttr}></el-pagination>`;
}
);
}
let count = 0;
for (const file of walkDir(ROOT)) {
const original = fs.readFileSync(file, "utf8");
if (!/<Page\b/.test(original)) continue;
const fixed = transformPage(original);
if (fixed !== original) {
fs.writeFileSync(file, fixed);
count++;
console.log(path.relative(ROOT, file));
}
}
console.log(`Page → el-pagination in ${count} files`);

View File

@@ -1,25 +1,84 @@
<template> <template>
<div id="app"> <div id="app">
<router-view/> <router-view />
</div> </div>
</template> </template>
<script> <script setup>
import {v4 as uuidv4} from 'uuid'; import { onMounted } from "vue";
import storage from '@/plugins/storage'; import { useRoute } from "vue-router";
export default { import storage from "@/plugins/storage";
name: 'App', import { getBaseSite, getThemeSetting } from "@/api/common.js";
mounted () { import { fetchAndApplyTheme } from "@/utils/theme";
let uuid = storage.getItem('uuid'); import { useAppStore } from "@/stores/app";
if (!uuid) {
uuid = uuidv4(); defineOptions({ name: "App" });
storage.setItem('uuid', uuid);
} const route = useRoute();
const appStore = useAppStore();
function applySiteInfo(data) {
const expirationTime = new Date().setHours(new Date().getHours() + 1);
storage.setItem("sitelogo_expiration_time", expirationTime);
storage.setItem("siteName", data.siteName);
storage.setItem("logoImg", data.buyerSideLogo);
storage.setItem("siteIcon", data.buyerSideIcon);
appStore.setSiteName(data.siteName);
appStore.setLogoImg(data.buyerSideLogo);
if (route.meta.title === undefined) {
window.document.title = data.siteName;
} }
}; let link =
document.querySelector("link[rel*='icon']") ||
document.createElement("link");
link.type = "image/x-icon";
link.href = data.buyerSideIcon;
link.rel = "shortcut icon";
document.getElementsByTagName("head")[0].appendChild(link);
}
function init() {
const expirationTime = storage.getItem("sitelogo_expiration_time");
const cacheValid =
expirationTime && new Date() <= new Date(Number(expirationTime));
if (cacheValid) {
applySiteInfo({
siteName: storage.getItem("siteName"),
buyerSideLogo: storage.getItem("logoImg"),
buyerSideIcon: storage.getItem("siteIcon"),
});
}
getSite();
getTheme();
}
function getSite() {
getBaseSite().then((res) => {
if (res.success && res.result.settingValue) {
try {
const data = JSON.parse(res.result.settingValue);
applySiteInfo(data);
} catch {
// 站点配置解析失败时使用缓存
}
}
}).catch((err) => {
console.warn('获取站点配置失败', err);
});
}
function getTheme() {
fetchAndApplyTheme(getThemeSetting).catch((err) => {
console.warn('获取主题配置失败', err);
});
}
onMounted(() => {
init();
});
</script> </script>
<style lang="scss"> <style lang="scss">
#app{ #app {
@include background_color($light_background_color); @include background_color($light_background_color);
} }
</style> </style>

View File

@@ -11,7 +11,7 @@ import request, {Method} from '@/plugins/request.js'
// 获取密码状态 // 获取密码状态
export function getPwdStatus (params) { export function getPwdStatus (params) {
return request({ return request({
url: '/buyer/members/wallet/check', url: '/buyer/passport/member/wallet/check',
method: Method.GET, method: Method.GET,
needToken: true, needToken: true,
params params
@@ -21,7 +21,7 @@ export function getPwdStatus (params) {
// 设置密码 // 设置密码
export function setPwd (params) { export function setPwd (params) {
return request({ return request({
url: '/buyer/members/wallet/set-password', url: '/buyer/passport/member/wallet/set-password',
method: Method.POST, method: Method.POST,
needToken: true, needToken: true,
data: params data: params
@@ -31,7 +31,7 @@ export function setPwd (params) {
// 设置支付密码 // 设置支付密码
export function setUpdatePwdOrdinary (params) { export function setUpdatePwdOrdinary (params) {
return request({ return request({
url: '/buyer/members/wallet/update-password/ordinary', url: '/buyer/passport/member/wallet/update-password/ordinary',
method: Method.GET, method: Method.GET,
needToken: true, needToken: true,
data: params data: params
@@ -41,19 +41,31 @@ export function setUpdatePwdOrdinary (params) {
// 修改会员资料 // 修改会员资料
export function editMemberInfo (params) { export function editMemberInfo (params) {
return request({ return request({
url: '/buyer/members/editOwn', url: '/buyer/passport/member/editOwn',
method: Method.PUT, method: Method.PUT,
needToken: true, needToken: true,
data: params data: params,
loading: false
}) })
} }
// 修改密码 // 修改密码
export function editPwd (params) { export function editPwd (params) {
return request({ return request({
url: `/buyer/members/modifyPass`, url: `/buyer/passport/member/modifyPass`,
method: Method.PUT, method: Method.PUT,
needToken: true, needToken: true,
data: params data: params,
loading: false,
skipMessage: true
})
}
// 获取密码状态
export function logout () {
return request({
url: '/buyer/passport/member/logout',
method: Method.POST,
needToken: true
}) })
} }

View File

@@ -1,11 +1,11 @@
import request, { import request, {
Method, commonUrl Method, buyerUrl
} from '@/plugins/request.js'; } from '@/plugins/request.js';
// 会员收货地址列表 // 会员收货地址列表
export function memberAddress () { export function memberAddress () {
return request({ return request({
url: '/buyer/memberAddress', url: '/buyer/member/address',
needToken: true, needToken: true,
method: Method.GET method: Method.GET
}); });
@@ -14,36 +14,39 @@ export function memberAddress () {
// 添加收货地址 // 添加收货地址
export function newMemberAddress (params) { export function newMemberAddress (params) {
return request({ return request({
url: '/buyer/memberAddress', url: '/buyer/member/address',
needToken: true, needToken: true,
method: Method.POST, method: Method.POST,
data: params data: params,
loading: false
}); });
} }
// 编辑收货地址 // 编辑收货地址
export function editMemberAddress (params) { export function editMemberAddress (params) {
return request({ return request({
url: '/buyer/memberAddress', url: '/buyer/member/address',
needToken: true, needToken: true,
method: Method.PUT, method: Method.PUT,
params params,
loading: false
}); });
} }
// 删除收货地址 // 删除收货地址
export function delMemberAddress (id) { export function delMemberAddress (id) {
return request({ return request({
url: `/buyer/memberAddress/delById/${id}`, url: `/buyer/member/address/delById/${id}`,
needToken: true, needToken: true,
method: Method.DELETE method: Method.DELETE,
loading: false
}); });
} }
// 根据id获取会员地址详情 // 根据id获取会员地址详情
export function getAddrDetail (id) { export function getAddrDetail (id) {
return request({ return request({
url: `/buyer/memberAddress/get/${id}`, url: `/buyer/member/address/get/${id}`,
needToken: true, needToken: true,
method: Method.GET method: Method.GET
}); });
@@ -52,7 +55,7 @@ export function getAddrDetail (id) {
// 传给后台citycode 获取城市街道等id // 传给后台citycode 获取城市街道等id
export function handleRegion (params) { export function handleRegion (params) {
return request({ return request({
url: `${commonUrl}/common/region/region`, url: `${buyerUrl}/buyer/common/region/region`,
needToken: true, needToken: true,
method: Method.GET, method: Method.GET,
params params

View File

@@ -20,7 +20,8 @@ export function cartGoodsAll () {
return request({ return request({
url: '/buyer/trade/carts/all', url: '/buyer/trade/carts/all',
method: Method.GET, method: Method.GET,
needToken: true needToken: true,
loading: false
}); });
} }
@@ -64,7 +65,7 @@ export function addCartGoods (params) {
/** /**
* 创建交易 * 创建交易
* @param client 客户端:H5/移动端 PC/PC端,WECHAT_MP/小程序端,APP/移动应用端 * @param client 客户端:H5/移动端 PC/PC端,WECHAT_MP/小程序端,APP/移动应用端
* @param way 购物车购买:CART/立即购买:BUY_NOW / 积分购买:POINT * @param way 购物车:CART / 立即购买:BUY_NOW / 积分:POINTS / 拼团:PINTUAN / 砍价:KANJIA
* @param remark 备注 非必填 * @param remark 备注 非必填
*/ */
export function createTrade (data) { export function createTrade (data) {
@@ -80,7 +81,7 @@ export function createTrade (data) {
/** /**
* 选择优惠券 * 选择优惠券
* @param memberCouponId 优惠券id * @param memberCouponId 优惠券id
* @param way 购物车购买:CART/立即购买:BUY_NOW/ 积分购买:POINT * @param way 购物车:CART / 立即购买:BUY_NOW / 积分:POINTS
* @param used 使用true 弃用 false * @param used 使用true 弃用 false
*/ */
export function selectCoupon (params) { export function selectCoupon (params) {
@@ -92,6 +93,21 @@ export function selectCoupon (params) {
}); });
} }
/**
* 选择礼品卡
* @param way 购物车:CART / 立即购买:BUY_NOW / 拼团:PINTUAN / 积分:POINTS / 砍价:KANJIA
* @param credentialId 礼品卡凭证 id;used=false 且不传则清空全部
* @param used 使用 true / 弃用 false
*/
export function selectGiftCard (params) {
return request({
url: '/buyer/trade/carts/select/giftCard',
method: Method.GET,
needToken: true,
params
});
}
/** /**
* 可用优惠券数量 * 可用优惠券数量
*/ */
@@ -212,3 +228,52 @@ export function receiptSelect (params) {
params params
}); });
} }
/**
* 获取全部配送方式
*/
export function shippingMethodList(params) {
return request({
url: `/buyer/trade/carts/shippingMethodList`,
method: Method.GET,
needToken: true,
params: params,
});
}
/**
* 获取全部配送方式
*/
export function storeAddressList(params) {
return request({
url: `/buyer/store/address/shippingMethodList`,
method: Method.GET,
needToken: true,
params: params,
});
}
/**
* 设置自提地址ID
* @param addressId
*/
export function setStoreAddressId(storeAddressId,way) {
return request({
url: `/buyer/trade/carts/storeAddress?storeAddressId=${storeAddressId}&way=${way}`,
method: Method.GET,
needToken: true,
});
}
/**
* 提交配送方式
* @param params
*/
export function setShipMethod(params) {
return request({
url: "/buyer/trade/carts/shippingMethod",
method: Method.PUT,
needToken: true,
params,
});
}

View File

@@ -1,11 +1,11 @@
import request, {Method, commonUrl} from '@/plugins/request.js'; import request, {Method, buyerUrl} from '@/plugins/request.js';
/** /**
* 获取拼图验证 * 获取拼图验证
*/ */
export function getVerifyImg (verificationEnums) { export function getVerifyImg (verificationEnums) {
return request({ return request({
url: `${commonUrl}/common/slider/${verificationEnums}`, url: `${buyerUrl}/buyer/common/slider/${verificationEnums}`,
method: Method.GET, method: Method.GET,
needToken: false needToken: false
}); });
@@ -15,7 +15,7 @@ export function getVerifyImg (verificationEnums) {
*/ */
export function postVerifyImg (params) { export function postVerifyImg (params) {
return request({ return request({
url: `${commonUrl}/common/slider/${params.verificationEnums}`, url: `${buyerUrl}/buyer/common/slider/${params.verificationEnums}`,
method: Method.POST, method: Method.POST,
needToken: false, needToken: false,
params params
@@ -26,28 +26,20 @@ export function postVerifyImg (params) {
*/ */
export function sendSms (params) { export function sendSms (params) {
return request({ return request({
url: `${commonUrl}/common/sms/${params.verificationEnums}/${params.mobile}`, url: `${buyerUrl}/buyer/common/sms/${params.verificationEnums}/${params.mobile}`,
method: Method.GET, method: Method.GET,
needToken: false, needToken: false,
params params
}); });
} }
/**
* 获取logo图标
*/
export function getLogo () {
return request({
url: `${commonUrl}/common/logo`,
method: Method.GET,
needToken: false
});
}
// 地区数据,用于三级联动 // 地区数据,用于三级联动
export function getRegion (id) { export function getRegion (id) {
return request({ return request({
url: `${commonUrl}/common/region/item/${id}`, url: `${buyerUrl}/buyer/common/region/item/${id}`,
needToken: true, needToken: true,
method: Method.GET method: Method.GET,
loading: false
}); });
} }
@@ -57,7 +49,7 @@ export function getRegion (id) {
*/ */
export function articleList (params) { export function articleList (params) {
return request({ return request({
url: `/buyer/article`, url: `/buyer/other/article`,
method: Method.GET, method: Method.GET,
params params
}); });
@@ -69,7 +61,7 @@ export function articleList (params) {
*/ */
export function articleCateList () { export function articleCateList () {
return request({ return request({
url: `/buyer/article/articleCategory/list`, url: `/buyer/other/article/articleCategory/list`,
method: Method.GET method: Method.GET
}); });
} }
@@ -77,7 +69,37 @@ export function articleCateList () {
// 通过id获取文章 // 通过id获取文章
export function articleDetail (id) { export function articleDetail (id) {
return request({ return request({
url: `/buyer/article/get/${id}`, url: `/buyer/other/article/get/${id}`,
method: Method.GET method: Method.GET
}); });
} }
// 获取IM接口前缀
export function getIMDetail () {
return request({
url: `${buyerUrl}/buyer/common/IM`,
method: Method.GET
});
}
//获取图片logo
export function getBaseSite(){
return request ({
url:`${buyerUrl}/buyer/common/site`,
method: Method.GET,
needToken: false
})
}
// 获取主题色配置
export function getThemeSetting() {
return request({
url: `${buyerUrl}/buyer/common/site/theme`,
method: Method.GET,
needToken: false,
});
}

View File

@@ -5,9 +5,10 @@ import request, {
// 商品列表 // 商品列表
export function goodsList (params) { export function goodsList (params) {
return request({ return request({
url: '/buyer/goods/es', url: '/buyer/goods/goods/search',
method: Method.GET, method: Method.GET,
needToken: false, needToken: false,
optionalToken: true,
params params
}); });
} }
@@ -15,9 +16,10 @@ export function goodsList (params) {
// 商品分类 筛选条件 品牌, 尺寸等 // 商品分类 筛选条件 品牌, 尺寸等
export function filterList (params) { export function filterList (params) {
return request({ return request({
url: '/buyer/goods/es/related', url: '/buyer/goods/goods/search/related',
method: Method.GET, method: Method.GET,
needToken: false, needToken: false,
optionalToken: true,
params params
}); });
} }
@@ -25,18 +27,19 @@ export function filterList (params) {
// id获取商品详情 // id获取商品详情
export function goodsDetail (goodsId) { export function goodsDetail (goodsId) {
return request({ return request({
url: `/buyer/goods/get/${goodsId}`, url: `/buyer/goods/goods/get/${goodsId}`,
method: Method.GET, method: Method.GET,
needToken: false needToken: false
}); });
} }
// id获取商品Sku详情 // id获取商品Sku详情(支持未登录浏览,登录后可选携带 token)
export function goodsSkuDetail (params) { export function goodsSkuDetail (params) {
return request({ return request({
url: `/buyer/goods/sku/${params.goodsId}/${params.skuId}`, url: `/buyer/goods/goods/sku/${params.goodsId}/${params.skuId}`,
method: Method.GET, method: Method.GET,
needToken: true, needToken: false,
optionalToken: true,
params params
}); });
} }
@@ -44,7 +47,7 @@ export function goodsSkuDetail (params) {
// 获取所有商品分类 // 获取所有商品分类
export function getCategory (parentId) { export function getCategory (parentId) {
return request({ return request({
url: `/buyer/category/get/${parentId}`, url: `/buyer/goods/category/get/${parentId}`,
method: Method.GET, method: Method.GET,
needToken: false needToken: false
}); });
@@ -65,7 +68,7 @@ export function pintuanMembers (pintuanId) {
*/ */
export function hotWords (params) { export function hotWords (params) {
return request({ return request({
url: `/buyer/goods/hot-words`, url: `/buyer/goods/goods/hot-words`,
method: Method.GET, method: Method.GET,
needToken: false, needToken: false,
params params

View File

@@ -1,13 +1,44 @@
import request, {Method} from '@/plugins/request.js' import request, { Method } from "@/plugins/request.js";
/**
* 获取首页专题数据
*/
export function getTopicData(id) {
return request({
url: `/buyer/other/pageData/get/${id}`,
method: Method.GET,
});
}
// 获取首页楼层装修数据 // 获取首页楼层装修数据
export function indexData (params) { export function indexData(params) {
return request({ return request({
url: '/buyer/pageData/getIndex', url: "/buyer/other/pageData/getIndex",
method: Method.GET, method: Method.GET,
needToken: false, needToken: false,
params params,
}) });
}
// 获取自动发券
export function getAutoCoup(){
return request({
url: "/buyer/promotion/coupon/activity",
method: Method.GET,
needToken: true,
});
}
/**
* 获取店铺楼层数据
*/
export function getFloorStoreData(params) {
return request({
url: `/buyer/other/pageData?pageClientType=PC`,
method: "get",
params,
});
} }
/** /**
@@ -15,21 +46,36 @@ export function indexData (params) {
* @param pageClientType 客户端类型,可用值:PC,H5,WECHAT_MP,APP * @param pageClientType 客户端类型,可用值:PC,H5,WECHAT_MP,APP
* @param pageType 页面类型,可用值:INDEX,STORE,SPECIAL * @param pageType 页面类型,可用值:INDEX,STORE,SPECIAL
*/ */
export function pageData (params) { export function pageData(params) {
return request({ return request({
url: `/buyer/pageData`, url: `/buyer/other/pageData`,
method: Method.GET, method: Method.GET,
needToken: false, needToken: false,
params params,
}) });
} }
/** /**
* 刷新token * 刷新token
*/ */
export function handleRefreshToken (token) { export function handleRefreshToken(token) {
return request({ return request({
url: `/buyer/members/refresh/${token}`, url: `/buyer/passport/member/refresh/${token}`,
method: Method.GET, method: Method.GET,
needToken: false needToken: false,
}) // 刷新令牌请求自身不再进入 401/403 刷新分支,避免拦截器递归死锁;失败也不弹全局错误提示
skipAuthHandler: true,
skipMessage: true,
});
} }
// /**
// * 获取店铺楼层数据
// */
// export function getFloorStoreData(params) {
// return request({
// url: `/buyer/other/pageData?pageClientType=PC`,
// method: "get",
// params,
// });
// }

View File

@@ -6,7 +6,7 @@ import request, {Method, buyerUrl} from '@/plugins/request.js';
*/ */
export function regist (params) { export function regist (params) {
return request({ return request({
url: '/buyer/members/register', url: '/buyer/passport/member/register',
method: Method.POST, method: Method.POST,
needToken: false, needToken: false,
data: params data: params
@@ -18,7 +18,7 @@ export function regist (params) {
*/ */
export function login (params) { export function login (params) {
return request({ return request({
url: '/buyer/members/userLogin', url: '/buyer/passport/member/userLogin',
method: Method.POST, method: Method.POST,
needToken: false, needToken: false,
data: params, data: params,
@@ -31,7 +31,7 @@ export function login (params) {
*/ */
export function smsLogin (params) { export function smsLogin (params) {
return request({ return request({
url: '/buyer/members/smsLogin', url: '/buyer/passport/member/smsLogin',
method: Method.POST, method: Method.POST,
needToken: false, needToken: false,
data: params, data: params,
@@ -44,7 +44,7 @@ export function smsLogin (params) {
*/ */
export function getMemberMsg (params) { export function getMemberMsg (params) {
return request({ return request({
url: '/buyer/members', url: '/buyer/passport/member',
method: Method.GET, method: Method.GET,
needToken: true, needToken: true,
params params
@@ -55,7 +55,7 @@ export function getMemberMsg (params) {
* 第三方登录 支付宝,微博,qq,微信 * 第三方登录 支付宝,微博,qq,微信
*/ */
export function webLogin (type) { export function webLogin (type) {
window.open(`${buyerUrl}/buyer/connect/login/web/${type}`, 'blank'); window.open(`${buyerUrl}/buyer/passport/connect/connect/login/web/${type}`, 'blank');
} }
/** /**
@@ -63,18 +63,44 @@ export function webLogin (type) {
*/ */
export function loginCallback (uuid) { export function loginCallback (uuid) {
return request({ return request({
url: `/buyer/connect/result?state=${uuid}`, url: `/buyer/passport/connect/connect/result?state=${uuid}`,
method: Method.GET, method: Method.GET,
needToken: false needToken: false
}); });
} }
export function getThirdAccountBindList () {
return request({
url: '/buyer/passport/connect/bind/list',
method: Method.GET,
needToken: true
});
}
export function bindThirdAccount (data) {
return request({
url: '/buyer/passport/connect/bind',
method: Method.POST,
needToken: true,
data
});
}
export function unbindThirdAccount (data) {
return request({
url: '/buyer/passport/connect/bind/unbind',
method: Method.POST,
needToken: true,
data
});
}
/** /**
* 忘记密码 验证手机验证码 * 忘记密码 验证手机验证码
*/ */
export function validateCode (params) { export function validateCode (params) {
return request({ return request({
url: `/buyer/members/resetByMobile`, url: `/buyer/passport/member/resetByMobile`,
method: Method.POST, method: Method.POST,
needToken: false, needToken: false,
params params
@@ -86,9 +112,40 @@ export function validateCode (params) {
*/ */
export function resetPassword (params) { export function resetPassword (params) {
return request({ return request({
url: `/buyer/members/resetPassword`, url: `/buyer/passport/member/resetPassword`,
method: Method.POST, method: Method.POST,
needToken: false, needToken: false,
params params
}); });
} }
export function getSCLoginCode(params) {
return request({
url: `/buyer/passport/member/pc_session`,
method: Method.POST,
needToken: false,
loading: false,
params
});
}
export function sCLogin(token,params) {
return request({
url: `/buyer/passport/member/session_login/`+token,
method: Method.POST,
needToken: false,
loading: false,
skipMessage: true,
// 长轮询后端最长挂起 20s,需大于该值,避免 axios 10s 默认超时把二维码请求掐断
timeout: 25000,
params
});
}
export function getWechatH5QrCode (params) {
return request({
url: '/buyer/other/wechat/h5/qrcode',
method: Method.GET,
needToken: true,
params
})
}

View File

@@ -3,7 +3,7 @@ import request, {Method} from '@/plugins/request.js';
// 查询账户余额 // 查询账户余额
export function getMembersWallet () { export function getMembersWallet () {
return request({ return request({
url: '/buyer/members/wallet', url: '/buyer/wallet/wallet',
method: Method.GET, method: Method.GET,
needToken: true needToken: true
}); });
@@ -22,7 +22,7 @@ export function getDepositLog (params) {
// 查询充值记录 // 查询充值记录
export function getRecharge (params) { export function getRecharge (params) {
return request({ return request({
url: '/buyer/member/recharge', url: '/buyer/wallet/recharge',
method: Method.GET, method: Method.GET,
needToken: true, needToken: true,
params params
@@ -52,14 +52,14 @@ export function recharge (params) {
// 提现 // 提现
export function withdrawalApply (params) { export function withdrawalApply (params) {
return request({ return request({
url: '/buyer/members/wallet/withdrawal', url: '/buyer/wallet/wallet/withdrawal',
method: Method.POST, method: Method.POST,
needToken: true, needToken: true,
data: params data: params
}); });
} }
// 收藏商品、店铺 // 收藏商品
export function collectGoods (type, id) { export function collectGoods (type, id) {
return request({ return request({
url: `/buyer/member/collection/add/${type}/${id}`, url: `/buyer/member/collection/add/${type}/${id}`,
@@ -68,7 +68,16 @@ export function collectGoods (type, id) {
}); });
} }
// 取消 收藏商品、店铺 // 收藏店铺
export function collectStore (type, id) {
return request({
url: `/buyer/member/storeCollection/add/${type}/${id}`,
method: Method.POST,
needToken: true
});
}
// 取消 收藏商品
export function cancelCollect (type, id) { export function cancelCollect (type, id) {
return request({ return request({
url: `/buyer/member/collection/delete/${type}/${id}`, url: `/buyer/member/collection/delete/${type}/${id}`,
@@ -77,16 +86,38 @@ export function cancelCollect (type, id) {
}); });
} }
// 查看是否收藏 // 取消 收藏店铺
export function isCollection (type, goodsId) { export function cancelStoreCollect (type, id) {
return request({ return request({
url: `/buyer/member/collection/isCollection/${type}/${goodsId}`, url: `/buyer/member/storeCollection/delete/${type}/${id}`,
method: Method.GET, method: Method.DELETE,
needToken: true needToken: true
}); });
} }
// 会员收藏列表 // 查看是否收藏商品(后台查询,token 失效时静默失败,不弹全局登录框)
export function isCollection (type, goodsId) {
return request({
url: `/buyer/member/collection/isCollection/${type}/${goodsId}`,
method: Method.GET,
needToken: true,
skipAuthHandler: true,
skipMessage: true
});
}
// 查看是否收藏店铺(后台查询,token 失效时静默失败,不弹全局登录框)
export function isStoreCollection (type, goodsId) {
return request({
url: `/buyer/member/storeCollection/isCollection/${type}/${goodsId}`,
method: Method.GET,
needToken: true,
skipAuthHandler: true,
skipMessage: true
});
}
// 会员收藏商品列表
export function collectList (params) { export function collectList (params) {
return request({ return request({
url: `/buyer/member/collection/${params.type}`, url: `/buyer/member/collection/${params.type}`,
@@ -96,39 +127,53 @@ export function collectList (params) {
}); });
} }
// 单个商品评价 // 会员收藏店铺列表
export function goodsComment (params) { export function storeCollectList (params) {
return request({ return request({
url: `/buyer/memberEvaluation/${params.goodsId}/goodsEvaluation`, url: `/buyer/member/storeCollection/${params.type}`,
method: Method.GET, method: Method.GET,
needToken: false, needToken: true,
params params
}); });
} }
// 商品各评价类别数量 // 单个商品评价(需登录;token 失效时静默失败,不弹全局登录框)
export function goodsComment (params) {
return request({
url: `/buyer/member/evaluation/${params.goodsId}/goodsEvaluation`,
method: Method.GET,
needToken: true,
skipAuthHandler: true,
skipMessage: true,
params
});
}
// 商品各评价类别数量(需登录;token 失效时静默失败,不弹全局登录框)
export function goodsCommentNum (goodsId) { export function goodsCommentNum (goodsId) {
return request({ return request({
url: `/buyer/memberEvaluation/${goodsId}/evaluationNumber`, url: `/buyer/member/evaluation/${goodsId}/evaluationNumber`,
method: Method.GET, method: Method.GET,
needToken: false needToken: true,
skipAuthHandler: true,
skipMessage: true
}); });
} }
// 添加会员评价 // 添加会员评价
export function addEvaluation (params) { export function addEvaluation (params) {
return request({ return request({
url: `/buyer/memberEvaluation`, url: `/buyer/member/evaluation`,
method: Method.POST, method: Method.POST,
needToken: true, needToken: true,
params data: params
}); });
} }
// 会员评价详情 // 会员评价详情
export function evaluationDetail (id) { export function evaluationDetail (id) {
return request({ return request({
url: `/buyer/memberEvaluation/get/${id}`, url: `/buyer/member/evaluation/get/${id}`,
method: Method.GET, method: Method.GET,
needToken: true needToken: true
}); });
@@ -143,6 +188,15 @@ export function receiptList () {
}); });
} }
// 发票详情
export function receiptDetail (id) {
return request({
url: `/buyer/trade/receipt/${id}`,
method: Method.GET,
needToken: true
});
}
// 保存发票信息 // 保存发票信息
export function saveReceipt (params) { export function saveReceipt (params) {
return request({ return request({
@@ -159,6 +213,7 @@ export function couponList (params) {
url: `/buyer/promotion/coupon`, url: `/buyer/promotion/coupon`,
method: Method.GET, method: Method.GET,
needToken: true, needToken: true,
loading: false,
params params
}); });
} }
@@ -195,7 +250,7 @@ export function receiveCoupon (couponId) {
// 获取申请售后列表 // 获取申请售后列表
export function afterSaleList (params) { export function afterSaleList (params) {
return request({ return request({
url: `/buyer/afterSale/page`, url: `/buyer/order/afterSale/page`,
method: Method.GET, method: Method.GET,
needToken: true, needToken: true,
params params
@@ -205,7 +260,7 @@ export function afterSaleList (params) {
// 获取申请售后页面信息 // 获取申请售后页面信息
export function afterSaleInfo (sn) { export function afterSaleInfo (sn) {
return request({ return request({
url: `/buyer/afterSale/applyAfterSaleInfo/${sn}`, url: `/buyer/order/afterSale/applyAfterSaleInfo/${sn}`,
method: Method.GET, method: Method.GET,
needToken: true needToken: true
}); });
@@ -214,7 +269,7 @@ export function afterSaleInfo (sn) {
// 获取申请售后、投诉原因 // 获取申请售后、投诉原因
export function afterSaleReason (serviceType) { export function afterSaleReason (serviceType) {
return request({ return request({
url: `/buyer/afterSale/get/afterSaleReason/${serviceType}`, url: `/buyer/order/afterSale/get/afterSaleReason/${serviceType}`,
method: Method.GET, method: Method.GET,
needToken: true needToken: true
}); });
@@ -222,7 +277,7 @@ export function afterSaleReason (serviceType) {
// 获取申请售后详情 // 获取申请售后详情
export function afterSaleDetail (sn) { export function afterSaleDetail (sn) {
return request({ return request({
url: `/buyer/afterSale/get/${sn}`, url: `/buyer/order/afterSale/get/${sn}`,
method: Method.GET, method: Method.GET,
needToken: true needToken: true
}); });
@@ -230,7 +285,7 @@ export function afterSaleDetail (sn) {
// 售后日志 // 售后日志
export function afterSaleLog (sn) { export function afterSaleLog (sn) {
return request({ return request({
url: `/buyer/afterSale/get/getAfterSaleLog/${sn}`, url: `/buyer/order/afterSale/get/getAfterSaleLog/${sn}`,
method: Method.GET, method: Method.GET,
needToken: true needToken: true
}); });
@@ -239,7 +294,7 @@ export function afterSaleLog (sn) {
// 申请售后 // 申请售后
export function applyAfterSale (params) { export function applyAfterSale (params) {
return request({ return request({
url: `/buyer/afterSale/save/${params.orderItemSn}`, url: `/buyer/order/afterSale/save/${params.orderItemSn}`,
method: Method.POST, method: Method.POST,
needToken: true, needToken: true,
params params
@@ -249,16 +304,17 @@ export function applyAfterSale (params) {
// 取消售后申请 // 取消售后申请
export function cancelAfterSale (afterSaleSn) { export function cancelAfterSale (afterSaleSn) {
return request({ return request({
url: `/buyer/afterSale/cancel/${afterSaleSn}`, url: `/buyer/order/afterSale/cancel/${afterSaleSn}`,
method: Method.POST, method: Method.POST,
needToken: true needToken: true,
loading: false
}); });
} }
// 投诉商品 // 投诉商品
export function handleComplain (data) { export function handleComplain (data) {
return request({ return request({
url: `/buyer/complain`, url: `/buyer/order/complain`,
method: Method.POST, method: Method.POST,
needToken: true, needToken: true,
data data
@@ -267,7 +323,7 @@ export function handleComplain (data) {
// 分页获取我的投诉列表 // 分页获取我的投诉列表
export function complainList (params) { export function complainList (params) {
return request({ return request({
url: `/buyer/complain`, url: `/buyer/order/complain`,
method: Method.GET, method: Method.GET,
needToken: true, needToken: true,
params params
@@ -279,7 +335,7 @@ export function complainList (params) {
*/ */
export function getComplainDetail (id) { export function getComplainDetail (id) {
return request({ return request({
url: `/buyer/complain/${id}`, url: `/buyer/order/complain/${id}`,
method: Method.GET, method: Method.GET,
needToken: true needToken: true
}); });
@@ -290,99 +346,12 @@ export function getComplainDetail (id) {
*/ */
export function clearComplain (id) { export function clearComplain (id) {
return request({ return request({
url: `/buyer/complain/status/${id}`, url: `/buyer/order/complain/status/${id}`,
method: Method.PUT, method: Method.PUT,
needToken: true needToken: true
}); });
} }
/**
* 获取当前会员分销信息
*/
export function distribution () {
return request({
url: `/buyer/distribution`,
method: Method.GET,
needToken: true
});
}
/**
* 申请成为分销商
* @param idNumber 身份证号
* @param name 名字
*/
export function applyDistribution (params) {
return request({
url: `/buyer/distribution`,
method: Method.POST,
needToken: true,
params
});
}
/**
* 获取分销商订单列表
*/
export function getDistOrderList (params) {
return request({
url: `/buyer/distribution/distributionOrder`,
method: Method.GET,
needToken: true,
params
});
}
/**
* 获取分销商商品列表
*/
export function getDistGoodsList (params) {
return request({
url: `/buyer/distributionGoods`,
method: Method.GET,
needToken: true,
params
});
}
/**
* 绑定、解绑分销商品
* @param distributionGoodsId 分销商品id
* @param checked 分销商品id,true为绑定,false为解绑
*/
export function selectDistGoods (params) {
return request({
url: `/buyer/distributionGoods/checked/${params.distributionGoodsId}`,
method: Method.GET,
needToken: true,
params
});
}
/**
* 分销商提现历史
*/
export function distCashHistory (params) {
return request({
url: `/buyer/distribution/cash`,
method: Method.GET,
needToken: true,
params
});
}
/**
* 分销商提现
*/
export function distCash (params) {
return request({
url: `/buyer/distribution/cash`,
method: Method.POST,
needToken: true,
params
});
}
/** /**
* 我的足迹 * 我的足迹
* @param {Number} pageNumber 页码 * @param {Number} pageNumber 页码
@@ -390,7 +359,7 @@ export function distCash (params) {
*/ */
export function tracksList (params) { export function tracksList (params) {
return request({ return request({
url: `/buyer/footprint`, url: `/buyer/member/footprint`,
method: Method.GET, method: Method.GET,
needToken: true, needToken: true,
params params
@@ -402,7 +371,7 @@ export function tracksList (params) {
*/ */
export function clearTracks () { export function clearTracks () {
return request({ return request({
url: `/buyer/footprint`, url: `/buyer/member/footprint`,
method: Method.DELETE, method: Method.DELETE,
needToken: true needToken: true
}); });
@@ -414,7 +383,7 @@ export function clearTracks () {
*/ */
export function clearTracksById (ids) { export function clearTracksById (ids) {
return request({ return request({
url: `/buyer/footprint/delByIds/${ids}`, url: `/buyer/member/footprint/delByIds/${ids}`,
method: Method.DELETE, method: Method.DELETE,
needToken: true needToken: true
}); });
@@ -443,13 +412,38 @@ export function memberPointHistory (params) {
params params
}); });
} }
export function memberGradeCurrent (params) {
return request({
url: `/buyer/member/memberGrade/current`,
method: Method.GET,
needToken: true,
params
})
}
export function memberGradeRules () {
return request({
url: `/buyer/member/memberGrade/rules`,
method: Method.GET,
needToken: true
})
}
export function memberGradeList () {
return request({
url: `/buyer/member/memberGrade/list`,
method: Method.GET,
needToken: true
})
}
/** /**
* 分页获取会员站内信 * 分页获取会员站内信
* @param {Object} params 请求参数,包括pageNumber、pageSize、status * @param {Object} params 请求参数,包括pageNumber、pageSize、status
*/ */
export function memberMsgList (params) { export function memberMsgList (params) {
return request({ return request({
url: `/buyer/member/message`, url: `/buyer/message/member`,
method: Method.GET, method: Method.GET,
needToken: true, needToken: true,
params params
@@ -460,9 +454,18 @@ export function memberMsgList (params) {
* @param {String} messageId 消息id * @param {String} messageId 消息id
*/ */
export function getMemberMessage (id) {
return request({
url: `/buyer/message/member/${id}`,
method: Method.GET,
needToken: true,
skipMessage: true
});
}
export function readMemberMsg (id) { export function readMemberMsg (id) {
return request({ return request({
url: `/buyer/member/message/${id}`, url: `/buyer/message/member/${id}`,
method: Method.PUT, method: Method.PUT,
needToken: true needToken: true
}); });
@@ -473,7 +476,7 @@ export function readMemberMsg (id) {
*/ */
export function delMemberMsg (id) { export function delMemberMsg (id) {
return request({ return request({
url: `/buyer/member/message/${id}`, url: `/buyer/message/member/${id}`,
method: Method.DELETE, method: Method.DELETE,
needToken: true needToken: true
}); });
@@ -485,7 +488,7 @@ export function delMemberMsg (id) {
*/ */
export function getGoodsDistribution (distributionId) { export function getGoodsDistribution (distributionId) {
return request({ return request({
url: `/buyer/distribution/bindingDistribution/${distributionId}`, url: `/buyer/distribution/distribution/bindingDistribution/${distributionId}`,
method: Method.GET, method: Method.GET,
needToken: true needToken: true
}); });

View File

@@ -5,7 +5,7 @@ import request, {
// 查询会员订单列表 // 查询会员订单列表
export function getOrderList (params) { export function getOrderList (params) {
return request({ return request({
url: `/buyer/orders`, url: `/buyer/order/order`,
method: Method.GET, method: Method.GET,
needToken: true, needToken: true,
params params
@@ -18,7 +18,7 @@ export function getOrderList (params) {
*/ */
export function orderDetail (orderSn) { export function orderDetail (orderSn) {
return request({ return request({
url: `/buyer/orders/${orderSn}`, url: `/buyer/order/order/${orderSn}`,
method: Method.GET, method: Method.GET,
needToken: true needToken: true
}); });
@@ -31,7 +31,7 @@ export function orderDetail (orderSn) {
*/ */
export function cancelOrder (params) { export function cancelOrder (params) {
return request({ return request({
url: `/buyer/orders/${params.orderSn}/cancel`, url: `/buyer/order/order/${params.orderSn}/cancel`,
method: Method.POST, method: Method.POST,
needToken: true, needToken: true,
params params
@@ -44,7 +44,7 @@ export function cancelOrder (params) {
*/ */
export function delOrder (orderSn) { export function delOrder (orderSn) {
return request({ return request({
url: `/buyer/orders/${orderSn}`, url: `/buyer/order/order/${orderSn}`,
method: Method.DELETE, method: Method.DELETE,
needToken: true needToken: true
}); });
@@ -56,7 +56,7 @@ export function delOrder (orderSn) {
*/ */
export function sureReceived (orderSn) { export function sureReceived (orderSn) {
return request({ return request({
url: `/buyer/orders/${orderSn}/receiving`, url: `/buyer/order/order/${orderSn}/receiving`,
method: Method.POST, method: Method.POST,
needToken: true needToken: true
}); });
@@ -68,7 +68,7 @@ export function sureReceived (orderSn) {
*/ */
export function getTraces (orderSn) { export function getTraces (orderSn) {
return request({ return request({
url: `/buyer/orders/getTraces/${orderSn}`, url: `/buyer/order/order/getTraces/${orderSn}`,
method: Method.POST, method: Method.POST,
needToken: true needToken: true
}); });
@@ -80,7 +80,7 @@ export function getTraces (orderSn) {
*/ */
export function evolutionList (params) { export function evolutionList (params) {
return request({ return request({
url: `/buyer/memberEvaluation`, url: `/buyer/member/evaluation`,
method: Method.GET, method: Method.GET,
needToken: true, needToken: true,
params params
@@ -90,7 +90,7 @@ export function evolutionList (params) {
// 添加交易投诉对话 // 添加交易投诉对话
export function communication (params) { export function communication (params) {
return request({ return request({
url: `/buyer/complain/communication`, url: `/buyer/order/complain/communication`,
method: Method.POST, method: Method.POST,
needToken: true, needToken: true,
params params
@@ -100,7 +100,7 @@ export function communication (params) {
// 退换货服务 提交物流 // 退换货服务 提交物流
export function afterSaleDelivery (params) { export function afterSaleDelivery (params) {
return request({ return request({
url: `/buyer/afterSale/delivery/${params.afterSaleSn}`, url: `/buyer/order/afterSale/delivery/${params.afterSaleSn}`,
method: Method.POST, method: Method.POST,
needToken: true, needToken: true,
params params
@@ -109,9 +109,27 @@ export function afterSaleDelivery (params) {
// 获取退货可选物流公司 // 获取退货可选物流公司
export function getLogisticsCompany () { export function getLogisticsCompany () {
return request({ return request({
url: `/buyer/logistics`, url: `/buyer/other/logistics`,
method: Method.GET, method: Method.GET,
needToken: true, needToken: true,
params: { pageNumber: 1, pageSize: 200, disabled: 'OPEN' } params: { pageNumber: 1, pageSize: 200, disabled: 'OPEN' }
}); });
} }
//查询包裹列表
export const getPackage = (sn) => {
return request({
url: `/buyer/order/order/getPackage/${sn}`,
method: Method.GET,
needToken: true,
})
}
//查询物流
export const getTracesList = (sn, params) => {
return request({
url: `/buyer/order/order/getTracesList/${sn}`,
method: Method.GET,
needToken: true,
})
};

View File

@@ -10,7 +10,7 @@ import request, {
*/ */
export function tradeDetail (params) { export function tradeDetail (params) {
return request({ return request({
url: '/buyer/cashier/tradeDetail', url: '/buyer/payment/cashier/tradeDetail',
needToken: true, needToken: true,
method: Method.GET, method: Method.GET,
params params
@@ -24,9 +24,24 @@ export function tradeDetail (params) {
* @param payClient 调起方式 可用值:APP,NATIVE,JSAPI,H5 * @param payClient 调起方式 可用值:APP,NATIVE,JSAPI,H5
* @param sn 订单编号 * @param sn 订单编号
*/ */
export function pay (params) { export function pay (params, config = {}) {
return request({ return request({
url: `/buyer/cashier/pay/${params.paymentMethod}/${params.paymentClient}`, url: `/buyer/payment/cashier/pay/${params.paymentMethod}/${params.paymentClient}`,
needToken: true,
method: Method.GET,
params,
skipMessage: !!config.skipMessage,
});
}
/**
* 支付结果查询
* @param orderType 交易类型,可用值:TRADE,ORDER,RECHARGE
* @param sn 订单编号
*/
export function payCallback (params) {
return request({
url: `/buyer/payment/cashier/result`,
needToken: true, needToken: true,
method: Method.GET, method: Method.GET,
params params
@@ -38,9 +53,9 @@ export function pay (params) {
* @param orderType 交易类型,可用值:TRADE,ORDER,RECHARGE * @param orderType 交易类型,可用值:TRADE,ORDER,RECHARGE
* @param sn 订单编号 * @param sn 订单编号
*/ */
export function payCallback (params) { export function withdrawalSettingVO (params) {
return request({ return request({
url: `/buyer/cashier/result`, url: `/buyer/wallet/wallet/withdrawalSettingVO`,
needToken: true, needToken: true,
method: Method.GET, method: Method.GET,
params params

View File

@@ -57,3 +57,50 @@ export function pointGoodsDetail (id) {
id id
}); });
} }
/**
* 分页查询当前客户礼品卡
*/
export function getGiftCardCashMemberCardPage (params) {
return request({
url: '/buyer/promotion/giftCardCash/memberCard',
method: Method.GET,
needToken: true,
params
});
}
/**
* 绑定礼品卡(卡号 + 兑换码/卡密)
*/
export function bindGiftCardCashMemberCard (data) {
return request({
url: '/buyer/promotion/giftCardCash/memberCard/bind',
method: Method.POST,
needToken: true,
headers: { 'Content-Type': 'application/json' },
data
});
}
/**
* 激活礼品卡
*/
export function activateGiftCardCashMemberCard (memberCardId) {
return request({
url: `/buyer/promotion/giftCardCash/memberCard/${memberCardId}/activate`,
method: Method.POST,
needToken: true
});
}
/**
* 下单页可用礼品卡列表
*/
export function getAvailableGiftCardCashMemberCards () {
return request({
url: '/buyer/promotion/giftCardCash/memberCard/available',
method: Method.GET,
needToken: true
});
}

View File

@@ -5,8 +5,9 @@ import request, {
// 店铺分页列表 // 店铺分页列表
export function shopList (params) { export function shopList (params) {
return request({ return request({
url: '/buyer/store', url: '/buyer/store/store',
needToken: true, needToken: false,
optionalToken: true,
method: Method.GET, method: Method.GET,
params params
}) })
@@ -15,7 +16,7 @@ export function shopList (params) {
// 申请店铺第一步-填写企业信息 // 申请店铺第一步-填写企业信息
export function applyFirst (params) { export function applyFirst (params) {
return request({ return request({
url: '/buyer/store/apply/first', url: '/buyer/store/store/apply/first',
needToken: true, needToken: true,
method: Method.PUT, method: Method.PUT,
params params
@@ -25,7 +26,7 @@ export function applyFirst (params) {
// 申请店铺第一步-填写企业信息 // 申请店铺第一步-填写企业信息
export function applySecond (params) { export function applySecond (params) {
return request({ return request({
url: '/buyer/store/apply/second', url: '/buyer/store/store/apply/second',
needToken: true, needToken: true,
method: Method.PUT, method: Method.PUT,
params params
@@ -35,25 +36,45 @@ export function applySecond (params) {
// 申请店铺第一步-填写企业信息 // 申请店铺第一步-填写企业信息
export function applyThird (params) { export function applyThird (params) {
return request({ return request({
url: '/buyer/store/apply/third', url: '/buyer/store/store/apply/third',
needToken: true, needToken: true,
method: Method.PUT, method: Method.PUT,
params params
}) })
} }
// 店铺信息(含评分)
export function getStoreById (id) {
return request({
url: `/buyer/store/store/store/${id}`,
needToken: false,
method: Method.GET
})
}
// 店铺详情 // 店铺详情
// 获取店铺工商/营业执照信息
export function getLicencePhoto (id) {
return request({
url: `/buyer/store/store/get/licencePhoto/${id}`,
needToken: false,
optionalToken: true,
method: Method.GET
})
}
export function getDetailById (id) { export function getDetailById (id) {
return request({ return request({
url: `/buyer/store/get/detail/${id}`, url: `/buyer/store/store/get/detail/${id}`,
needToken: true, needToken: false,
optionalToken: true,
method: Method.GET method: Method.GET
}) })
} }
// 店铺分类 // 店铺分类
export function getCateById (id) { export function getCateById (id) {
return request({ return request({
url: `/buyer/store/label/get/${id}`, url: `/buyer/store/store/label/get/${id}`,
needToken: true, needToken: true,
method: Method.GET method: Method.GET
}) })
@@ -61,7 +82,7 @@ export function getCateById (id) {
// 店铺入驻协议 // 店铺入驻协议
export function agreement () { export function agreement () {
return request({ return request({
url: `/buyer/article/type/STORE_REGISTER`, url: `/buyer/other/article/type/STORE_REGISTER`,
needToken: true, needToken: true,
method: Method.GET method: Method.GET
}) })
@@ -70,8 +91,21 @@ export function agreement () {
// 获取当前登录会员的店铺信息 // 获取当前登录会员的店铺信息
export function applyStatus () { export function applyStatus () {
return request({ return request({
url: `/buyer/store/apply`, url: `/buyer/store/store/apply`,
needToken: true, needToken: true,
method: Method.GET method: Method.GET,
loading: false
}) })
} }
/**
* 获取自提点信息
* @param storeId
*/
export function getStoreAddress(storeId,params) {
return request({
url: `/buyer/store/address/page/${storeId}`,
method: Method.GET,
params
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,29 @@
import back from "./back.png";
import carts from "./carts.png";
import collage from "./collage.png";
import feedback from "./feedback.png";
import notice from "./notice.png";
import notification from "./notification.png";
import shop from "./shop.png";
import story from "./story.png";
import support from "./support.png";
import user from "./user.png";
const iconMap = {
back,
carts,
collage,
feedback,
notice,
notification,
shop,
story,
support,
user,
};
export function getIconUrl(name) {
return iconMap[name] || "";
}
export default iconMap;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg width="24" height="24" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M24 44C35.0457 44 44 35.0457 44 24C44 12.9543 35.0457 4 24 4C12.9543 4 4 12.9543 4 24C4 35.0457 12.9543 44 24 44Z" fill="none" stroke="#333" stroke-width="4" stroke-linejoin="round"/><path d="M20 24V17.0718L26 20.5359L32 24L26 27.4641L20 30.9282V24Z" fill="none" stroke="#333" stroke-width="4" stroke-linejoin="round"/></svg>

After

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

View File

@@ -0,0 +1,40 @@
:root {
--el-color-primary: var(--theme-color, #ff3c2a);
--el-color-danger: var(--theme-color, #ff3c2a);
--el-font-size-base: 14px;
}
.el-table--border {
.el-table__cell {
border-right: none !important;
}
}
.link-text {
color: var(--theme-color, #ff3c2a);
cursor: pointer;
text-decoration: none;
&:hover {
opacity: 0.85;
}
}
.op-split {
margin: 0 8px;
color: #dcdfe6;
}
/* 次要强调按钮,使用高亮主题色(如「立即购买」) */
.confirm-receipt-btn {
background-color: var(--theme-light, #ff6b35) !important;
border-color: var(--theme-light, #ff6b35) !important;
color: #fff !important;
&:hover,
&:focus {
background-color: color-mix(in srgb, var(--theme-light, #ff6b35) 88%, black) !important;
border-color: color-mix(in srgb, var(--theme-light, #ff6b35) 88%, black) !important;
color: #fff !important;
}
}

View File

@@ -0,0 +1,25 @@
// 全局布局工具类(非 scoped,避免子组件继承 class 时宽度失效)
.width_1200_auto {
width: 1200px;
max-width: 1200px;
margin-left: auto;
margin-right: auto;
box-sizing: border-box;
}
// 首页主体:分类导航 + 楼层装修共用同一 1200px 容器,保证列对齐
.index-main {
width: 1200px;
max-width: 1200px;
margin-left: auto;
margin-right: auto;
box-sizing: border-box;
position: relative;
}
// 与 CateNav 商品分类栏、Carousel 左占位一致的列宽
$index-main-width: 1200px;
$index-side-col-width: 263.2px;
$index-col-gap: 10px;
// 1200 - 263.2*2 - 10*2 = 653.6px
$index-center-col-width: $index-main-width - ($index-side-col-width * 2) - ($index-col-gap * 2);

View File

@@ -10,20 +10,29 @@ $warning_color: #ff9900;
$error_color: #ed3f14; $error_color: #ed3f14;
$handle-btn-color: #438cde; $handle-btn-color: #438cde;
$theme_color: #ed3f14; $theme_color: var(--theme-color, #ff3c2a);
$border_color: #dddee1; $border_color: #dddee1;
$title_color: #8c8c8c; $title_color: #8c8c8c;
$light_title_color: #1c2438; $light_title_color: #1c2438;
$light_content_color: #495060; $light_content_color: #495060;
$light_sub_color: #80848f; $light_sub_color: #80848f;
$light_background_color: #f8f8f9; $light_background_color: #F5F5F7;
$light_white_background_color: #fff; $light_white_background_color: #fff;
// 暗黑主题颜色 // 暗黑主题颜色
$dark_background_color: #141414; $dark_background_color: #141414;
$dark_sub_background_color: #1d1d1d; //稍微浅一点的 $dark_sub_background_color: #1d1d1d; //稍微浅一点的
$dark_content_color: #d5d5d5; $dark_content_color: #d5d5d5;
.wes-2 {
/* 适用于webkit内核和移动端 */
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
overflow: hidden;
}
/***** 封装一些方法可用于 黑暗主题 ,明亮主题 *****/ /***** 封装一些方法可用于 黑暗主题 ,明亮主题 *****/
// 背景颜色 // 背景颜色
@@ -170,6 +179,19 @@ $dark_content_color: #d5d5d5;
margin-right: 20px; margin-right: 20px;
} }
.mb_24 {
margin-bottom: 24px;
}
.mt_24 {
margin-top: 24px;
}
.ml_24 {
margin-left: 24px;
}
.mr_24 {
margin-right: 24px;
}
.mb_10 { .mb_10 {
margin-bottom: 10px; margin-bottom: 10px;
} }
@@ -270,10 +292,26 @@ li {
left: auto; left: auto;
} }
} }
.flex{
display: flex;
}
.flex-a-c{
align-items: center;
}
.flex-j-sb{
justify-content: space-between;
}
.flex-j-c{
justify-content: center;
}
.width_1200_auto {
width: 1200px;
max-width: 1200px;
margin: 0 auto;
box-sizing: border-box;
}
@@ -290,18 +328,24 @@ li {
.goods-list { .goods-list {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
width: 1200px; width: 100%;
margin: 0 auto; margin: 0 auto;
column-gap: 10px;
} }
.goods-show-info { .goods-show-info {
width: 235px; width: calc(20% - 8px);
padding: 6px; padding: 6px;
margin: 10px 0px; margin: 10px 0;
margin-left: 5px;
position: relative; position: relative;
border: 1px solid #fff; border: 1px solid #fff;
cursor: pointer; cursor: pointer;
background-color: #fff; background-color: #fff;
box-sizing: border-box;
}
.goods-show-img img {
width: 100%;
aspect-ratio: 1;
object-fit: cover;
} }
.goods-show-info:hover { .goods-show-info:hover {
border: 1px solid #ccc; border: 1px solid #ccc;
@@ -311,16 +355,17 @@ li {
margin-top: 6px; margin-top: 6px;
} }
.goods-show-detail { .goods-show-detail {
font-size: 12px; font-size: 14px;
line-height: 21px;
margin: 6px 0px; margin: 6px 0px;
} }
.goods-show-num { .goods-show-num {
font-size: 12px; font-size: 14px;
margin-bottom: 6px; margin-bottom: 6px;
color: #666; color: #666;
} }
.goods-show-num { .goods-show-num {
font-size: 12px; font-size: 14px;
margin-bottom: 6px; margin-bottom: 6px;
color: #009688; color: #009688;
} }
@@ -329,11 +374,16 @@ li {
font-weight: bold; font-weight: bold;
} }
.goods-show-seller { .goods-show-seller {
font-size: 12px; font-size: 14px;
color: $theme_color; color: $theme_color;
} }
.goods-page { .goods-page {
margin:10px auto ; margin: 10px 0;
text-align: right; width: 100%;
width: 1200px; display: flex;
justify-content: flex-end;
:deep(.el-pagination) {
justify-content: flex-end;
}
} }

View File

@@ -9,18 +9,24 @@
.goods-list { .goods-list {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
width: 1200px; width: 100%;
margin: 0 auto; margin: 0 auto;
column-gap: 10px;
} }
.goods-show-info { .goods-show-info {
width: 235px; width: calc(20% - 8px);
padding: 6px; padding: 6px;
margin: 10px 0px; margin: 10px 0;
margin-left: 5px;
position: relative; position: relative;
border: 1px solid #fff; border: 1px solid #fff;
cursor: pointer; cursor: pointer;
background-color: #fff; background-color: #fff;
box-sizing: border-box;
}
.goods-show-img img {
width: 100%;
aspect-ratio: 1;
object-fit: cover;
} }
.goods-show-info:hover { .goods-show-info:hover {
border: 1px solid #ccc; border: 1px solid #ccc;
@@ -30,16 +36,28 @@
margin-top: 6px; margin-top: 6px;
} }
.goods-show-detail { .goods-show-detail {
font-size: 12px; height: 42px;
font-size: 14px;
line-height: 21px;
margin: 6px 0px; margin: 6px 0px;
overflow:hidden;
text-overflow: ellipsis;
display:-webkit-box;
-webkit-line-clamp:2;
line-clamp: 2;
-webkit-box-orient:vertical;
color:#808080;
}
.goods-show-detail :hover{
color:#E23A3A;
} }
.goods-show-num { .goods-show-num {
font-size: 12px; font-size: 14px;
margin-bottom: 6px; margin-bottom: 6px;
color: #666; color: #666;
} }
.goods-show-num { .goods-show-num {
font-size: 12px; font-size: 14px;
margin-bottom: 6px; margin-bottom: 6px;
color: #009688; color: #009688;
} }
@@ -48,11 +66,16 @@
font-weight: bold; font-weight: bold;
} }
.goods-show-seller { .goods-show-seller {
font-size: 12px; font-size: 14px;
color: $theme_color; color: $theme_color;
} }
.goods-page { .goods-page {
margin:10px auto ; margin: 10px 0;
text-align: right; width: 100%;
width: 1200px; display: flex;
justify-content: flex-end;
:deep(.el-pagination) {
justify-content: flex-end;
}
} }

View File

@@ -1,9 +1,15 @@
@import '~view-design/src/styles/index.less'; // Element Plus 主题变量(原 view-design less 已移除)
@primary-color: #ff5c58;
@info-color: #fa6419;
@success-color: #68cabe;
@error-color: #ff3c2a;
@table-thead-bg: #f8f8f9;
@table-td-stripe-bg: #f8f8f9;
@table-td-hover-bg: #ededed;
@table-td-highlight-bg: #ededed;
@font-size-base: 12px;
@primary-color: #ed3f14; .el-drawer,
.drawer {
z-index: 2600 !important;
@table-thead-bg : #f8f8f9; }
@table-td-stripe-bg : #f8f8f9;
@table-td-hover-bg : #ededed;
@table-td-highlight-bg : #ededed;

View File

@@ -1,162 +1,496 @@
<template> <template>
<div> <div class="navbar" ref="rootRef" :class="{'small-search-box': useClass == 'fixed-show'}">
<div class="container"> <template v-if="useClass == 'fixed-show'">
<img <div class="search search-embedded">
:src="$store.state.logoImg" <el-input
v-if="showLogo" v-model="searchData"
class="logo-img" size="large"
alt="" class="search-input"
@click="$router.push('/')" :placeholder="placeholderText"
/> @focus="openPanel"
<i-input @input="queueSuggest"
v-model="searchData" @keyup.enter="search"
size="large" />
class="search" <div class="search-btn" @click="search">
placeholder="输入你想查找的商品" <el-icon :size="21"><SearchIcon /></el-icon>
@keyup.enter.native="search"
>
<Button v-if="!store" slot="append" @click="search">搜索</Button>
</i-input>
<div v-if="store" class="btn-div">
<Button class="store-search" type="warning" @click="searchStore">搜本店</Button>
<Button class="store-search" type="primary" @click="search">搜全站</Button>
</div>
<template v-if="showTag">
<div style="height:12px" v-if="promotionTags.length === 0"></div>
<div v-else>
<Tag
v-for="(item, index) in promotionTags"
:key="index"
class="mr_10"
>
<span class="hover-color" @click="selectTags(item)">{{ item }}</span>
</Tag>
</div> </div>
</template> <div v-if="showPanel" class="suggest-panel" @mousedown.prevent>
</div> <SearchSuggest
:keyword="trimmedKeyword"
:history="history"
:hot-words="promotionTags"
:suggestions="suggestions"
:suggesting="suggesting"
@pick="selectTags"
@clear="clearHistory"
/>
</div>
</div>
</template>
<template v-else>
<div class="container width_1200_auto flex flex-a-c">
<img
:src="logoImg"
v-if="showLogo"
class="logo-img"
alt=""
@click="$router.push('/')"
/>
<div class="search-box">
<!-- 搜索类型切换:商品 / 店铺(店铺内搜索时不展示) -->
<div v-if="showTypeSwitch" class="search-type">
<span
v-for="item in searchTypes"
:key="item.value"
class="search-type-item"
:class="{ active: searchType === item.value }"
@click="switchType(item.value)"
>{{ item.label }}</span>
</div>
<div class="search">
<el-input
v-model="searchData"
size="large"
class="search-input"
:placeholder="placeholderText"
@focus="openPanel"
@input="queueSuggest"
@keyup.enter="search"
/>
<div class="search-btn" @click="search">
<el-icon :size="21"><SearchIcon /></el-icon>
</div>
<div v-if="showPanel" class="suggest-panel" @mousedown.prevent>
<SearchSuggest
:keyword="trimmedKeyword"
:history="history"
:hot-words="promotionTags"
:suggestions="suggestions"
:suggesting="suggesting"
@pick="selectTags"
@clear="clearHistory"
/>
</div>
</div>
<template v-if="showTag">
<div v-if="promotionTags.length === 0"></div>
<div v-else class="history-list flex">
<div
v-for="(item, index) in promotionTags"
:key="index"
class="mr_10"
>
<span class="history-item" @click="selectTags(item)">{{ item }}</span>
</div>
</div>
</template>
</div>
</div>
</template>
</div> </div>
</template> </template>
<script> <script setup>
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import storage from '@/plugins/storage.js' import storage from '@/plugins/storage.js'
import {hotWords} from '@/api/goods.js' import { goodsList, hotWords } from '@/api/goods.js'
export default { import { Search as SearchIcon } from '@element-plus/icons-vue'
name: 'search', import SearchSuggest from '@/components/SearchSuggest.vue'
props: { import { useAppStore } from '@/stores/app'
showTag: { // 是否展示搜索栏下方热门搜索
type: Boolean, defineOptions({ name: 'search' })
default: true
}, const props = defineProps({
showLogo: { // 是否展示左侧logo showTag: {
type: Boolean, type: Boolean,
default: true default: true
},
store: { // 是否为店铺页面
type: Boolean,
default: false
},
hover: {
type: Boolean,
default: false
}
}, },
data () { showLogo: {
return { type: Boolean,
searchData: '' // 搜索内容 default: true
};
}, },
methods: { storeId: {
selectTags (item) { // 选择热门标签 type: String,
this.searchData = item; default: ""
this.search();
},
search () { // 全平台搜索商品
this.$router.push({
path: '/goodsList',
query: { keyword: this.searchData }
});
},
searchStore () { // 店铺搜索商品
this.$emit('search', this.searchData)
}
}, },
computed: { hover: {
promotionTags () { type: Boolean,
if (this.$store.state.hotWordsList) { default: false
return JSON.parse(this.$store.state.hotWordsList)
} else {
return []
}
}
}, },
created () { useClass: {
this.searchData = this.$route.query.keyword type: null,
if (!this.hover) { // 首页顶部固定搜索栏不调用热词接口 default: ''
// 搜索热词每5分钟请求一次
const reloadTime = storage.getItem('hotWordsReloadTime')
const time = new Date().getTime() - 5 * 60 * 1000
if (!reloadTime) {
hotWords({count: 5}).then(res => {
if (res.success && res.result) storage.setItem('hotWordsList', res.result)
})
storage.setItem('hotWordsReloadTime', new Date().getTime())
} else if (reloadTime && time > reloadTime) {
hotWords({count: 5}).then(res => {
if (res.success && res.result) storage.setItem('hotWordsList', res.result)
})
storage.setItem('hotWordsReloadTime', new Date().getTime())
}
}
} }
}; })
const emit = defineEmits(['search'])
const route = useRoute()
const router = useRouter()
const appStore = useAppStore()
const HISTORY_KEY = 'buyerSearchHistory'
const HISTORY_LIMIT = 10
function readHistory() {
try {
const raw = localStorage.getItem(HISTORY_KEY)
const list = raw ? JSON.parse(raw) : []
return Array.isArray(list) ? list.filter((item) => typeof item === 'string' && item.trim()) : []
} catch {
return []
}
}
function parseHotWords(raw) {
if (!raw) return []
if (Array.isArray(raw)) return raw.filter(Boolean)
if (typeof raw !== 'string') return []
try {
const parsed = JSON.parse(raw)
if (Array.isArray(parsed)) return parsed.filter(Boolean)
} catch {
// 旧数据可能是逗号拼接
}
return raw.split(',').map((item) => item.trim()).filter(Boolean)
}
const rootRef = ref(null)
const searchData = ref('')
const history = ref([])
const panelVisible = ref(false)
const suggestions = ref([])
const suggesting = ref(false)
let suggestTimer = null
let suggestSeq = 0
const logoImg = computed(() => appStore.logoImg)
const trimmedKeyword = computed(() => {
return (searchData.value || '').trim()
})
const promotionTags = computed(() => {
return parseHotWords(appStore.hotWordsList)
})
// 搜索类型:goods 商品 / store 店铺
const searchTypes = [
{ label: '商品', value: 'goods' },
{ label: '店铺', value: 'store' },
]
const searchType = ref(route.path === '/storeList' ? 'store' : 'goods')
// 店铺内搜索(传了 storeId)只能搜本店商品,不展示切换
const showTypeSwitch = computed(() => !props.storeId && props.useClass !== 'fixed-show')
const isStoreMode = computed(() => searchType.value === 'store' && !props.storeId)
const placeholderText = computed(() => (isStoreMode.value ? '输入你想查找的店铺' : '输入你想查找的商品'))
function switchType(type) {
if (searchType.value === type) return
searchType.value = type
suggestions.value = []
suggesting.value = false
}
const showPanel = computed(() => {
// 店铺搜索暂无联想/历史,不展示下拉面板
if (isStoreMode.value) return false
if (!panelVisible.value) return false
if (trimmedKeyword.value) return true
return history.value.length > 0 || promotionTags.value.length > 0
})
watch(
() => route.query.keyword,
(value) => {
searchData.value = value || ''
}
)
function selectTags(item) {
// 热词/历史均为商品关键词,点击时按商品搜索
searchType.value = 'goods'
searchData.value = item
search()
}
function remember(keyword) {
const next = [keyword, ...history.value.filter((item) => item !== keyword)].slice(0, HISTORY_LIMIT)
history.value = next
localStorage.setItem(HISTORY_KEY, JSON.stringify(next))
}
function clearHistory() {
history.value = []
localStorage.removeItem(HISTORY_KEY)
}
function openPanel() {
panelVisible.value = true
if (trimmedKeyword.value) queueSuggest()
}
function closePanel() {
panelVisible.value = false
}
function onDocumentClick(event) {
if (rootRef.value && !rootRef.value.contains(event.target)) closePanel()
}
function queueSuggest() {
if (isStoreMode.value) return
panelVisible.value = true
clearTimeout(suggestTimer)
const keyword = trimmedKeyword.value
if (!keyword) {
suggestions.value = []
suggesting.value = false
return
}
suggesting.value = true
suggestTimer = setTimeout(() => fetchSuggest(keyword), 300)
}
function fetchSuggest(keyword) {
const seq = ++suggestSeq
const params = { keyword, pageNumber: 1, pageSize: 8 }
if (props.storeId) params.storeId = props.storeId
goodsList(params).then((res) => {
if (seq !== suggestSeq || keyword !== trimmedKeyword.value) return
const records = res && res.success ? (res.result.records || []) : []
const seen = new Set()
const names = []
promotionTags.value.forEach((word) => {
if (word && String(word).toLowerCase().includes(keyword.toLowerCase()) && !seen.has(word)) {
seen.add(word)
names.push(word)
}
})
records.forEach((item) => {
const name = item && item.goodsName
if (name && !seen.has(name)) {
seen.add(name)
names.push(name)
}
})
suggestions.value = names.slice(0, 8)
}).catch(() => {
if (seq === suggestSeq) suggestions.value = []
}).finally(() => {
if (seq === suggestSeq) suggesting.value = false
})
}
function search() {
const keyword = trimmedKeyword.value
searchData.value = keyword
closePanel()
if (isStoreMode.value) {
if (route.path === '/storeList') {
emit('search', keyword)
} else {
router.push({ path: '/storeList', query: keyword ? { keyword } : {} })
}
return
}
if (keyword) remember(keyword)
const url = route.path
if (url == '/goodsList') {
emit('search', keyword)
} else {
const pushData = {
path: '/goodsList',
query: keyword ? { keyword } : {},
}
if (props.storeId) pushData.query.storeId = props.storeId
router.push(pushData)
}
}
function searchStore() {
emit('search', trimmedKeyword.value)
}
function applyHotWords(result) {
const list = parseHotWords(result)
appStore.setHotWords(list)
storage.setItem('hotWordsList', JSON.stringify(list))
}
function loadHotWords() {
hotWords({ count: 5 }).then((res) => {
if (res.success && res.result) applyHotWords(res.result)
}).catch(() => {
// 热词为可选数据,失败时沿用缓存或默认热词
})
storage.setItem('hotWordsReloadTime', new Date().getTime())
}
// 初始化(原 created 钩子逻辑)
searchData.value = route.query.keyword || ''
history.value = readHistory()
if (!props.hover) {
const reloadTime = storage.getItem('hotWordsReloadTime')
const time = new Date().getTime() - 5 * 60 * 1000
if (!reloadTime || time > reloadTime) loadHotWords()
}
onMounted(() => {
document.addEventListener('click', onDocumentClick)
})
onUnmounted(() => {
clearTimeout(suggestTimer)
document.removeEventListener('click', onDocumentClick)
})
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.container { .navbar {
margin: 30px auto; height: 113px;
width: 460px; background: #fff;
position: relative;
} }
.navbar.small-search-box {
height: 60px;
width: 100%;
margin: 0;
display: flex;
align-items: center;
background: transparent;
}
.search-embedded {
width: 100%;
margin: 0;
}
.container {
position: relative;
height: 100%;
}
.search { .search {
$btn-gap: 4px;
$btn-width: 60px;
$input-height: 37.8px;
position: relative;
width: 778.4px;
height: $input-height;
margin: 10px 0px 5px 0; margin: 10px 0px 5px 0;
/deep/ .ivu-input.ivu-input-large {
border: 2px solid $theme_color; .search-input {
font-size: 12px; width: 100%;
height: 34px;
&:focus { :deep(.el-input__wrapper) {
border: 2px solid #409EFF;
border-radius: 4px;
padding-left: 26px;
padding-right: calc(#{$btn-gap * 2} + #{$btn-width});
font-size: 14px;
font-weight: normal;
height: $input-height;
color: #999;
box-shadow: none; box-shadow: none;
} }
} }
/deep/ .ivu-input-group-append {
border: 1px solid $theme_color; .search-btn {
border-left: none; position: absolute;
height: 30px; right: $btn-gap;
background-color: $theme_color; top: $btn-gap;
bottom: $btn-gap;
width: $btn-width;
border-radius: 0 3px 3px 0;
cursor: pointer;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
background-color: #409EFF;
color: #ffffff; color: #ffffff;
button { transition: background 0.2s;
font-size: 14px;
font-weight: 600; &:hover {
line-height: 1; background-color: #66b1ff;
} }
} }
} }
.logo-img {
position: absolute; .search-embedded.search {
left: -360px; width: 100%;
top: -9px;
width: 150px;
cursor: pointer;
} }
.store-search{
padding: 0 9px; .search-box{
border-radius: 0; margin-left: 28px;
&:nth-child(2){ }
margin-left: -5px;
.search-type {
display: flex;
align-items: flex-end;
gap: 4px;
height: 22px;
padding-left: 18px;
margin-top: 4px;
}
.search-type-item {
padding: 2px 10px;
border-radius: 4px 4px 0 0;
color: #666;
font-size: 13px;
line-height: 18px;
cursor: pointer;
user-select: none;
&:hover {
color: $theme_color;
}
&.active {
color: #fff;
background: $theme_color;
} }
} }
.btn-div{
position: relative; .search-type + .search {
height: 0px; margin-top: 0;
top: -38px;
left: 339px;
} }
.logo-img {
max-width: 150px;
cursor: pointer;
}
.history-list {
margin-left: 28px;
}
.history-item {
font-size: 13px;
font-weight: normal;
line-height: 16px;
letter-spacing: 0px;
margin-right: 17px;
color: #666666;
cursor: pointer;
}
.suggest-panel {
position: absolute;
left: 0;
right: 0;
top: calc(100% + 8px);
z-index: 30;
padding: 8px 0;
background: #fff;
border: 1px solid #eee;
border-radius: 8px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
}
</style> </style>

View File

@@ -0,0 +1,150 @@
<template>
<div>
<div v-if="keyword" class="suggest-section">
<div v-if="suggesting && !suggestions.length" class="suggest-empty">正在查找...</div>
<button
v-for="item in suggestions"
:key="item"
type="button"
class="suggest-item"
@click="$emit('pick', item)"
>
<span v-for="(part, index) in parts(item)" :key="index" :class="{ hit: part.hit }">{{ part.text }}</span>
</button>
<div v-if="!suggesting && !suggestions.length" class="suggest-empty">没有匹配的商品,回车查看全部结果</div>
</div>
<template v-else>
<div v-if="history.length" class="suggest-section">
<div class="suggest-head">
<span>搜索历史</span>
<button type="button" class="suggest-clear" @click="$emit('clear')">清空</button>
</div>
<div class="suggest-tags">
<button
v-for="item in history"
:key="item"
type="button"
class="suggest-tag"
@click="$emit('pick', item)"
>{{ item }}</button>
</div>
</div>
<div v-if="hotWords.length" class="suggest-section">
<div class="suggest-head"><span>热门搜索</span></div>
<div class="suggest-tags">
<button
v-for="item in hotWords"
:key="item"
type="button"
class="suggest-tag"
@click="$emit('pick', item)"
>{{ item }}</button>
</div>
</div>
</template>
</div>
</template>
<script setup>
defineOptions({ name: "SearchSuggest" });
const props = defineProps({
keyword: { type: String, default: "" },
history: { type: Array, default: () => [] },
hotWords: { type: Array, default: () => [] },
suggestions: { type: Array, default: () => [] },
suggesting: { type: Boolean, default: false },
});
defineEmits(["pick", "clear"]);
function parts(text) {
const value = String(text || "");
const key = props.keyword;
if (!key) return [{ text: value, hit: false }];
const index = value.toLowerCase().indexOf(key.toLowerCase());
if (index < 0) return [{ text: value, hit: false }];
return [
{ text: value.slice(0, index), hit: false },
{ text: value.slice(index, index + key.length), hit: true },
{ text: value.slice(index + key.length), hit: false },
].filter((part) => part.text);
}
</script>
<style scoped lang="scss">
.suggest-section + .suggest-section {
margin-top: 4px;
padding-top: 4px;
border-top: 1px solid #f5f5f5;
}
.suggest-head {
display: flex;
align-items: center;
justify-content: space-between;
padding: 6px 16px;
color: #999;
font-size: 13px;
}
.suggest-clear {
border: none;
background: transparent;
color: #999;
font-size: 13px;
cursor: pointer;
}
.suggest-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
padding: 0 16px 8px;
}
.suggest-tag {
max-width: 180px;
padding: 4px 10px;
border: none;
border-radius: 14px;
background: #f5f5f5;
color: #333;
font-size: 13px;
line-height: 20px;
cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.suggest-item {
display: block;
width: 100%;
padding: 8px 16px;
border: none;
background: transparent;
color: #333;
font-size: 14px;
line-height: 22px;
text-align: left;
cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&:hover {
background: #fafafa;
}
.hit {
color: $theme_color;
}
}
.suggest-empty {
padding: 10px 16px;
color: #999;
font-size: 13px;
}
</style>

View File

@@ -1,166 +1,177 @@
<template> <template>
<div> <div>
<Modal v-model="showAddr" width="800" title="收件人地址"> <el-dialog v-model="showAddr" width="800" title="收件人地址">
<Form <el-form
:model="formData" :model="formData"
ref="form" ref="formRef"
label-position="left" label-position="left"
:label-width="100" label-width="100px"
:rules="ruleInline" :rules="ruleInline"
> >
<FormItem label="收件人" prop="name"> <el-form-item label="收件人" prop="name">
<i-input v-model="formData.name" style="width: 600px"></i-input> <el-input v-model="formData.name" style="width: 600px"></el-input>
</FormItem> </el-form-item>
<FormItem label="收件地区" prop="address"> <el-form-item label="收件地区" prop="address">
<i-input {{ formData.address || '暂无地址' }}
v-model="formData.address" <el-button type="primary" style="margin-left: 10px;" size="small" @click="mapRef.open()">选择</el-button>
disabled </el-form-item>
style="width: 600px" <el-form-item label="详细地址" prop="detail">
></i-input> <el-input v-model="formData.detail" style="width: 600px"></el-input>
<Button type="primary" size="small" @click="$refs.map.showMap = true">选择</Button> </el-form-item>
</FormItem> <el-form-item label="手机号码" prop="mobile">
<FormItem label="详细地址" prop="detail"> <el-input v-model="formData.mobile" style="width: 600px"></el-input>
<i-input v-model="formData.detail" style="width: 600px"></i-input> </el-form-item>
</FormItem> <el-form-item label="地址别名">
<FormItem label="手机号码" prop="mobile"> <el-input
<i-input v-model="formData.mobile" style="width: 600px"></i-input>
</FormItem>
<FormItem label="地址别名">
<i-input
v-model="formData.alias" v-model="formData.alias"
length :maxlength="5"
:maxlength="4" show-word-limit
placeholder="请输入地址别名,例如公司" placeholder="请输入地址别名,例如公司"
style="width: 600px" style="width: 600px"
></i-input> ></el-input>
</FormItem> </el-form-item>
<FormItem label="默认地址"> <el-form-item label="默认地址">
<i-switch v-model="formData.isDefault" /> <el-switch v-model="formData.isDefault" />
</FormItem> </el-form-item>
</Form> </el-form>
<div class="mt_20" slot="footer"> <template #footer><div class="mt_20">
<Button @click="hide">取消</Button> <el-button @click="hide">取消</el-button>
<Button type="primary" class="mr_10" :loading="loading" @click="save">保存收货地址</Button> <el-button type="primary" class="mr_10" :loading="loading" @click="save">保存收货地址</el-button>
</div> </div></template>
</Modal> </el-dialog>
<lili-map ref="map" @getAddress="getAddress"></lili-map> <multipleMap ref="mapRef" @callback="getAddress"></multipleMap>
</div> </div>
</template> </template>
<script> <script setup>
import liliMap from '@/components/map'; import { ref, watch } from "vue";
import { Message } from "@/utils/message";
import multipleMap from "@/components/map/multiple-map";
import { import {
newMemberAddress, newMemberAddress,
editMemberAddress, editMemberAddress,
getAddrDetail getAddrDetail
} from '@/api/address'; } from '@/api/address';
export default {
name: 'addressManage', defineOptions({ name: 'addressManage' });
props: {
id: { // 传入的地址id const props = defineProps({
defalut: '', id: { // 传入的地址id
type: String defalut: '',
type: String
}
});
const emit = defineEmits(['change']);
const showAddr = ref(false); // 控制模态框显隐
const formData = ref({ // 表单数据
isDefault: false
});
const ruleInline = { // 验证规则
name: [{ required: true, message: '请输入收件人姓名', trigger: 'blur' }],
address: [{ required: true, message: '请输入地址', trigger: 'change' }],
detail: [
{ required: true, message: '请输入详细地址', trigger: 'blur' }
],
mobile: [
{ required: true, message: '手机号不能为空', trigger: 'blur' },
{
type: 'string',
pattern: /^1[3|4|5|6|7|8][0-9]{9}$/,
message: '手机号格式出错',
trigger: 'blur'
} }
}, ]
data () { };
return { const loading = ref(false); // 提交的加载状态
showAddr: false, // 控制模态框显隐 const mapMsg = ref({}); // 地图信息
formData: { // 表单数据
isDefault: false const formRef = ref(null);
}, const mapRef = ref(null);
ruleInline: { // 验证规则
name: [{ required: true, message: '请输入收件人姓名', trigger: 'blur' }], function save () { // 保存地址
address: [{ required: true, message: '请输入地址', trigger: 'change' }], formRef.value.validate((valid) => {
detail: [ if (valid) {
{ required: true, message: '请输入详细地址', trigger: 'blur' } const params = JSON.parse(JSON.stringify(formData.value));
], params.consigneeAddressPath = params.address.replace(/\s/g, ',');
mobile: [ delete params.address;
{ required: true, message: '手机号不能为空', trigger: 'blur' }, loading.value = true;
{ if (props.id) {
type: 'string', editMemberAddress(params).then((res) => {
pattern: /^1[3|4|5|6|7|8][0-9]{9}$/, loading.value = false;
message: '手机号格式出错', if (res.success) {
trigger: 'blur' Message.success('编辑地址成功');
emit('change', true);
hide();
} }
] }).catch(() => { loading.value = false; });
}, } else {
loading: false, // 提交的加载状态 newMemberAddress(params).then((res) => {
mapMsg: {} // 地图信息 loading.value = false;
}; if (res.success) {
}, Message.success('新增地址成功');
methods: { emit('change', true);
save () { // 保存地址 hide();
this.$refs.form.validate((valid) => {
if (valid) {
const params = JSON.parse(JSON.stringify(this.formData));
params.consigneeAddressPath = params.address.replace(/\s/g, ',');
delete params.address;
this.loading = true;
if (this.id) {
editMemberAddress(params).then((res) => {
this.loading = false;
if (res.success) {
this.$Message.success('编辑地址成功');
this.$emit('change', true);
this.hide();
}
}).catch(() => { this.loading = false; });
} else {
newMemberAddress(params).then((res) => {
this.loading = false;
if (res.success) {
this.$Message.success('新增地址成功');
this.$emit('change', true);
this.hide();
}
}).catch(() => { this.loading = false; });
} }
} }).catch(() => { loading.value = false; });
});
},
getAddrById (id) {
// 获取地址详情
getAddrDetail(id).then((res) => {
if (res.success) {
console.log(res);
const data = res.result;
data.address = res.result.consigneeAddressPath.replace(/,/g, ' ');
this.formData = data;
}
});
},
getAddress (item) {
// 获取地图选择信息
this.mapMsg = item;
this.$set(this.formData, 'address', item.addr);
this.$set(this.formData, 'consigneeAddressIdPath', item.addrId);
this.$set(this.formData, 'detail', item.detail);
this.formData.lat = item.position.lat;
this.formData.lon = item.position.lng;
},
show () { // 地址模态框显示
this.showAddr = true;
},
hide () { // 地址模态框隐藏
this.showAddr = false;
}
},
watch: {
id: { // 传入的地址id
handler: function (v) {
if (v) {
this.getAddrById(v);
} else {
this.formData = {isDefault: false}
this.$refs.form.resetFields();
}
} }
} }
}, });
components: { }
liliMap
function getAddrById (id) {
// 获取地址详情
getAddrDetail(id).then((res) => {
if (res.success) {
const data = res.result;
data.address = res.result.consigneeAddressPath.replace(/,/g, ' ');
formData.value = data;
}
});
}
function getAddress (val) {
// 获取地图选择信息
if(val.type === 'select'){
const paths = val.data.map(item => item.name).join(',')
const ids = val.data.map(item => item.id).join(',')
formData.value['address'] = paths
formData.value['consigneeAddressIdPath'] = ids
const coord = val.data[val.data.length - 1].center.split(',')
formData.value.lat = coord[1]
formData.value.lon = coord[0]
}else{
formData.value["address"] = val.data.addr;
formData.value["consigneeAddressIdPath"] = val.data.addrId;
formData.value["detail"] = val.data.address;
formData.value.lat = val.data.position.lat;
formData.value.lon = val.data.position.lng;
} }
};
}
function show () { // 地址模态框显示
showAddr.value = true;
}
function hide () { // 地址模态框隐藏
showAddr.value = false;
}
defineExpose({ show, hide });
watch(
() => props.id, // 传入的地址id
(v) => {
if (v) {
getAddrById(v);
} else {
formData.value = {isDefault: false}
formRef.value.resetFields();
}
}
);
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -1,30 +1,28 @@
<template> <template>
<!-- 头部广告 --> <!-- 头部广告 -->
<div class="advertising" v-if="show" :style="{'background-color': data.bgColor}"> <div class="advertising" v-if="show && data" :style="{'background-color': data.bgColor}">
<img :src="data.img" class="hover-pointer" @click="linkTo(data.url)"/> <img :src="data.img" class="hover-pointer" @click="linkTo(data.url)"/>
<Icon type="md-close-circle" size="20" @click="show = false" /> <el-icon :size="20" @click="show = false"><CircleClose /></el-icon>
</div> </div>
</template> </template>
<script> <script setup>
export default { import { ref } from 'vue';
props: { import { CircleClose } from '@element-plus/icons-vue';
data: { // 传入的广告信息
type: Object, defineProps({
default: null data: { // 传入的广告信息
} type: Object,
}, default: null
data () {
return {
show: true // 是否显示头部广告
}
} }
}; });
const show = ref(true); // 是否显示头部广告
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.advertising { .advertising {
height: 80px; height: 80px;
width: 100%; width: 100%;
background-color: $theme_color;
text-align: center; text-align: center;
overflow: hidden; overflow: hidden;
position: relative; position: relative;

View File

@@ -1,148 +1,159 @@
<template> <template>
<Card class="_Card" :bordered="false" :dis-hover="true"> <el-card class="_Card" shadow="never">
<div slot="title" class="cardTitle"> <template #header>
<span :style="{fontSize:`${_Size}px`}">{{_Title}}</span> <div class="card-header">
<div class="cardTitle">
<div v-if="_Tabs" class="cardTabs"> <span :style="{ fontSize: `${_Size}px` }">{{ _Title }}</span>
<div @click="tabsChange(index)" :class="{active:(isActive==index)}" class="cardTabsItem" :style="{fontSize:`${_Size-2}px`}" v-for="(item,index) in _Tabs" <div v-if="_Tabs" class="cardTabs">
:key="index"> <div
{{item}} @click="tabsChange(index)"
:class="{ active: isActive == index }"
class="cardTabsItem"
:style="{ fontSize: `${_Size - 2}px` }"
v-for="(item, index) in _Tabs"
:key="index"
>
{{ item }}
</div>
</div>
</div>
<div class="cardExtra" v-if="_More" @click="callBack()">
{{ _More }}
</div> </div>
</div> </div>
</div> </template>
<div slot="extra" class="cardExtra" v-if="_More" @click="callBack()"> <slot />
{{_More}} </el-card>
</div>
<div>
</div>
</Card>
</template> </template>
<script> <script setup>
export default { import { ref, watch } from "vue";
name: 'index', import { useRouter } from "vue-router";
props:
{ defineOptions({ name: "index" });
_Tabs: { // 可点击的tab栏
type: null, const props = defineProps({
default: '' _Tabs: {
}, type: null,
// 头部 default: "",
_Title: { // 标题
type: null,
default: '卡片头部'
},
// 右侧更多
_More: {
type: null,
default: false
},
_Size: { // 文字大小
type: Number,
default: 16
},
// 点击更多触发跳转
_Src: {
type: null,
default: function (val) {
if (this._More) {
return val;
} else {
return false;
}
}
}
},
data () {
return {
isActive: 0 // 已激活tab栏下标
};
}, },
methods: { _Title: {
// 点击右侧的回调 type: null,
callBack () { default: "卡片头部",
let _this = this; },
if (this._Src !== '' || this._Src != null) { _More: {
this.$router.push({ type: null,
path: _this._Src default: false,
}); },
} _Size: {
}, type: Number,
// 点击tab的回调 default: 16,
tabsChange (index) { },
// 处理并返回index _Src: {
this.isActive = index; type: null,
this.$emit('_Change', index); default: null,
} },
_ActiveTab: {
type: Number,
default: 0,
},
});
const emit = defineEmits(["_Change"]);
const router = useRouter();
const isActive = ref(props._ActiveTab);
watch(
() => props._ActiveTab,
(val) => {
isActive.value = val;
} }
}; );
function callBack() {
if (props._Src) {
router.push({ path: props._Src });
}
}
function tabsChange(index) {
isActive.value = index;
emit("_Change", index);
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.cardTitle { .card-header {
display: flex; display: flex;
cursor: pointer; align-items: center;
} justify-content: space-between;
.active{ }
color: $theme_color; .cardTitle {
position: relative; display: flex;
&::before{ cursor: pointer;
content: ''; }
position: absolute; .active {
width: 100%; color: $theme_color;
height: 3px; position: relative;
bottom: 0; &::before {
left: 0; content: "";
background: $theme_color; position: absolute;
} width: 100%;
height: 3px;
bottom: 0;
left: 0;
background: $theme_color;
} }
}
.cardTabs { .cardTabs {
display: flex; display: flex;
padding: 0 12px;
> .cardTabsItem {
padding: 0 12px; padding: 0 12px;
> .cardTabsItem {
padding: 0 12px;
}
> .cardTabsItem:hover {
color: $theme_color;
}
} }
/deep/ .ivu-card, .ivu-card-head, ._Card { > .cardTabsItem:hover {
margin-bottom: 20px;
@include white_background_color();
}
/deep/ .ivu-card-head {
position: relative;
padding: 0 14px;
height: 50px;
line-height: 50px;
&::before {
content: '';
width: 3px;
height: 50%;
top: 25%;
background: $theme_color;
position: absolute;
left: 0;
}
}
.cardExtra {
color: $theme_color; color: $theme_color;
cursor: pointer;
} }
}
/deep/ .ivu-card-body { :deep(._Card) {
padding: 0 !important; margin-bottom: 20px;
display: none; @include white_background_color();
}
:deep(._Card .el-card__header) {
position: relative;
padding: 0 14px;
height: 50px;
line-height: 50px;
&::before {
content: "";
width: 3px;
height: 50%;
top: 25%;
background: $theme_color;
position: absolute;
left: 0;
} }
}
.cardExtra {
color: $theme_color;
cursor: pointer;
}
:deep(._Card .el-card__body) {
padding: 0 !important;
min-height: 0;
}
:deep(._Card .el-card__body:empty) {
display: none;
}
</style> </style>

View File

@@ -4,16 +4,16 @@
<ul> <ul>
<li v-for="(goods,goodsIndex) in cartList" :key="goodsIndex"> <li v-for="(goods,goodsIndex) in cartList" :key="goodsIndex">
<div> <div>
<img :src="goods.goodsSku.thumbnail" width="90" height="90" alt=""> <img :src="goods.goodsSku.thumbnail" loading="lazy" decoding="async" width="90" height="90" alt="">
</div> </div>
<div> <div>
<p class="hover-color" @click="linkTo(`/goodsDetail?skuId=${goods.goodsSku.id}&goodsId=${goods.goodsSku.goodsId}`)">{{goods.goodsSku.goodsName}}</p> <p class="hover-color" @click="linkTo(`/goodsDetail?skuId=${goods.goodsSku.id}&goodsId=${goods.goodsSku.goodsId}`)">{{goods.goodsSku.goodsName}}</p>
<p class="price">{{goods.goodsSku.price | unitPrice('¥')}}<span>&nbsp; x{{goods.num}}</span></p> <p class="price">{{ $filters.unitPrice(goods.goodsSku.price, '¥') }}<span>&nbsp; x{{goods.num}}</span></p>
</div> </div>
<span class="del hover-color" @click="delGoods(goods.goodsSku.id)">删除</span> <span class="del hover-color" @click="delGoods(goods.goodsSku.id)">删除</span>
</li> </li>
</ul> </ul>
<Button size="large" class="mt_10" type="primary" @click="linkTo('/cart')" long>去购物车结算</Button> <el-button size="large" class="mt_10" type="primary" @click="linkTo('/cart')" style="width:100%">去购物车结算</el-button>
</div> </div>
<div v-else-if="title === '我的订单'" class="order-con"> <div v-else-if="title === '我的订单'" class="order-con">
@@ -21,15 +21,15 @@
<li v-for="(order,orderIndex) in orderList" :key="orderIndex"> <li v-for="(order,orderIndex) in orderList" :key="orderIndex">
<div class="order-status"><span>{{filterOrderStatus(order.orderStatus)}}</span><span>{{order.createTime}}</span></div> <div class="order-status"><span>{{filterOrderStatus(order.orderStatus)}}</span><span>{{order.createTime}}</span></div>
<div class="goods-img"> <div class="goods-img">
<img :src="img.image" <img :src="img.image" loading="lazy" decoding="async"
@click="linkTo(`/goodsDetail?skuId=${img.skuId}&goodsId=${img.goodsId}`)" @click="linkTo(`/goodsDetail?skuId=${img.skuId}&goodsId=${img.goodsId}`)"
v-for="(img,imgIndex) in order.orderItems" v-for="(img,imgIndex) in order.orderItems"
:key="imgIndex" width="40" height="40" alt=""> :key="imgIndex" width="40" height="40" alt="">
</div> </div>
<div class="order-handle"><span>{{ order.flowPrice | unitPrice("¥") }}</span><span class="hover-color" @click="linkTo(`home/OrderDetail?sn=${order.sn}`)">查看订单</span></div> <div class="order-handle"><span>{{ $filters.unitPrice(order.flowPrice, "¥") }}</span><span class="hover-color" @click="linkTo(`/home/OrderDetail?sn=${order.sn}`)">查看订单</span></div>
</li> </li>
</ul> </ul>
<Button type="primary" @click="linkTo('/home/MyOrder')" long>查看全部订单</Button> <el-button type="primary" @click="linkTo('/home/MyOrder')" style="width:100%">查看全部订单</el-button>
</div> </div>
<div v-else-if="title === '优惠券'" class="coupon-con"> <div v-else-if="title === '优惠券'" class="coupon-con">
@@ -37,7 +37,7 @@
<li v-for="(coupon, index) in couponList" class="coupon-item" :key="index"> <li v-for="(coupon, index) in couponList" class="coupon-item" :key="index">
<div class="c-left"> <div class="c-left">
<div> <div>
<span v-if="coupon.couponType === 'PRICE'" class="fontsize_12 global_color">¥<span class="price">{{coupon.price | unitPrice}}</span></span> <span v-if="coupon.couponType === 'PRICE'" class="fontsize_12 global_color">¥<span class="price">{{ $filters.unitPrice(coupon.price) }}</span></span>
<span v-if="coupon.couponType === 'DISCOUNT'" class="fontsize_12 global_color"><span class="price">{{coupon.couponDiscount}}</span>折</span> <span v-if="coupon.couponType === 'DISCOUNT'" class="fontsize_12 global_color"><span class="price">{{coupon.couponDiscount}}</span>折</span>
<span class="describe">满{{coupon.consumeThreshold}}元可用</span> <span class="describe">满{{coupon.consumeThreshold}}元可用</span>
</div> </div>
@@ -54,9 +54,9 @@
<div v-else-if="title === '我的足迹'" class="tracks-con"> <div v-else-if="title === '我的足迹'" class="tracks-con">
<ul> <ul>
<li v-for="(track,trackIndex) in tracksList" :key="trackIndex"> <li v-for="(track,trackIndex) in tracksList" :key="trackIndex">
<img :src="track.thumbnail" :alt="track.thumbnail" @click="linkTo(`/goodsDetail?skuId=${track.id}&goodsId=${track.goodsId}`)" width="100" height="100"> <img :src="track.thumbnail" loading="lazy" decoding="async" :alt="track.thumbnail" @click="linkTo(`/goodsDetail?skuId=${track.id}&goodsId=${track.goodsId}`)" width="100" height="100">
<div @click="addToCart(track.id)">加入购物车</div> <div @click="addToCart(track.id)">加入购物车</div>
<p class="global_color">{{track.price | unitPrice('¥')}}</p> <p class="global_color">{{ $filters.unitPrice(track.price, '¥') }}</p>
</li> </li>
</ul> </ul>
<div class="hover-color" style="text-align:center;" @click="linkTo('/home/MyTracks')">查看更多>></div> <div class="hover-color" style="text-align:center;" @click="linkTo('/home/MyTracks')">查看更多>></div>
@@ -64,238 +64,242 @@
<div v-else-if="title === '我的收藏'" class="collect-con"> <div v-else-if="title === '我的收藏'" class="collect-con">
<ul> <ul>
<li v-for="(collect,collectIndex) in collectList" :key="collectIndex"> <li v-for="(collect,collectIndex) in collectList" :key="collectIndex">
<img :src="collect.image" :alt="collect.image" @click="linkTo(`/goodsDetail?skuId=${collect.skuId}&goodsId=${collect.goodsId}`)" width="100" height="100"> <img :src="collect.image" loading="lazy" decoding="async" :alt="collect.image" @click="linkTo(`/goodsDetail?skuId=${collect.skuId}&goodsId=${collect.goodsId}`)" width="100" height="100">
<div @click="addToCart(collect.skuId)">加入购物车</div> <div @click="addToCart(collect.skuId)">加入购物车</div>
<span class="del-icon" @click.stop="cancelCollect(collect.skuId)"> <span class="del-icon" @click.stop="cancelCollect(collect.skuId)">
<Icon type="md-trash" /> <el-icon><Delete /></el-icon>
</span> </span>
<p class="global_color">{{collect.price | unitPrice('¥')}}</p> <p class="global_color">{{ $filters.unitPrice(collect.price, '¥') }}</p>
</li> </li>
</ul> </ul>
<div class="hover-color" style="text-align:center;" @click="linkTo('/home/Favorites')">查看更多>></div> <div class="hover-color" style="text-align:center;" @click="linkTo('/home/Favorites')">查看更多>></div>
</div> </div>
<Spin v-if="loading" fix></Spin> <el-skeleton v-if="loading" fix></el-skeleton>
</div> </div>
</template> </template>
<script> <script setup>
import { ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { Message, Modal } from "@/utils/message";
import { Delete } from '@element-plus/icons-vue';
import {cartGoodsAll, delCartGoods, addCartGoods, cartCount} from '@/api/cart.js' import {cartGoodsAll, delCartGoods, addCartGoods, cartCount} from '@/api/cart.js'
import { getOrderList } from '@/api/order'; import { getOrderList as fetchOrderList } from '@/api/order';
import {couponList, receiveCoupon, tracksList, collectList, cancelCollect} from '@/api/member.js' import {couponList as fetchCouponList, receiveCoupon, tracksList as fetchTracksList, collectList as fetchCollectList, cancelCollect as apiCancelCollect} from '@/api/member.js'
export default { import storage from '@/plugins/storage.js'
name: 'Drawer', import { useAppStore } from '@/stores/app'
props: {
title: { defineOptions({ name: 'Drawer' })
default: '',
type: String const props = defineProps({
} title: {
}, default: '',
watch: { type: String
title (val) {
switch (val) {
case '购物车':
this.getCartList()
break;
case '我的订单':
this.getOrderList()
break;
case '我的足迹':
this.getTracksList()
break;
case '优惠券':
this.getCouponList()
break;
case '我的收藏':
this.getCollectList()
break;
}
}
},
data () {
return {
loading: false, // 控制spin显隐
cartList: [], // 购物车列表
couponList: [], // 优惠券列表
orderList: [], // 订单列表
collectList: [], // 收藏列表
tracksList: [], // 足迹列表
orderStatusList: [ // 订单状态
{
name: '未付款',
status: 'UNPAID'
},
{
name: '已付款',
status: 'PAID'
},
{
name: '待发货',
status: 'UNDELIVERED'
},
{
name: '已发货',
status: 'DELIVERED'
},
{
name: '已完成',
status: 'COMPLETED'
},
{
name: '待核验',
status: 'TAKE'
},
{
name: '已取消',
status: 'CANCELLED'
}
]
};
},
methods: {
getCartList () { // 获取购物车列表
this.loading = true
cartGoodsAll().then(res => {
this.loading = false
this.cartList = res.result.skuList
})
},
// 删除商品
delGoods (id) {
delCartGoods({ skuIds: id }).then((res) => {
if (res.success) {
this.$Message.success('删除成功');
this.getCartList();
cartCount().then(res => {
this.$store.commit('SET_CARTNUM', res.result)
this.Cookies.setItem('cartNum', res.result)
})
} else {
this.$Message.error(res.message);
}
});
},
filterOrderStatus (status) { // 获取订单状态中文
const ob = this.orderStatusList.filter(e => { return e.status === status });
return ob[0].name
},
receive (item) { // 领取优惠券
receiveCoupon(item.id).then(res => {
if (res.success) {
this.$Modal.confirm({
title: '领取优惠券',
content: '<p>优惠券领取成功,可到我的优惠券页面查看</p>',
okText: '我的优惠券',
cancelText: '立即使用',
onOk: () => {
this.$router.push('/home/Coupons')
},
onCancel: () => {
if (item.storeId !== 'platform') {
this.$router.push({path: '/merchant', query: {id: item.storeId}})
} else {
if (item.scopeType === 'PORTION_GOODS_CATEGORY') {
this.$router.push({path: '/goodsList', query: {categoryId: item.scopeId}})
} else {
this.$router.push({path: '/goodsList'})
}
}
}
});
}
})
},
useScope (type, storeName) { // 判断优惠券使用范围
let shop = '平台';
let goods = '全部商品'
if (storeName !== 'platform') shop = storeName
switch (type) {
case 'ALL':
goods = '全部商品'
break;
case 'PORTION_GOODS':
goods = '部分商品'
break;
case 'PORTION_GOODS_CATEGORY':
goods = '部分分类商品'
break;
}
return `${shop}${goods}可用`
},
addToCart (id) { // 添加商品到购物车
const params = {
num: 1,
skuId: id
}
this.loading = true;
addCartGoods(params).then(res => {
this.loading = false;
if (res.success) {
this.$Message.success('商品已成功添加到购物车')
} else {
this.$Message.warning(res.message);
}
}).catch(() => { this.loading = false });
},
getCouponList () { // 获取优惠券列表
// this.loading = true;
const params = {
pageNumber: 1,
pageSize: 10
}
couponList(params).then(res => {
this.loading = false
if (res.success) {
this.couponList = res.result.records
}
}).catch(() => { this.loading = false })
},
getOrderList () { // 获取订单列表
this.loading = true
const params = {
pageNumber: 1,
pageSize: 10,
tag: 'ALL'
}
getOrderList(params).then(res => {
this.loading = false
if (res.success) {
this.orderList = res.result.records;
}
});
},
getCollectList () { // 获取收藏列表
const params = {
pageNumber: 1,
pageSize: 10,
type: 'GOODS'
}
this.loading = true
collectList(params).then(res => {
this.loading = false
this.collectList = res.result.records
})
},
cancelCollect (id) { // 取消商品收藏
cancelCollect('GOODS', id).then(res => {
if (res.success) {
this.$Message.success('取消收藏成功')
this.getCollectList();
}
})
},
getTracksList () { // 获取足迹列表
const params = {
pageNumber: 1,
pageSize: 20
}
this.loading = true
tracksList(params).then(res => {
this.tracksList = res.result
this.loading = false
}).catch(() => { this.loading = false })
}
} }
}; })
const router = useRouter()
const appStore = useAppStore()
const loading = ref(false) // 控制spin显隐
const cartList = ref([]) // 购物车列表
const couponList = ref([]) // 优惠券列表
const orderList = ref([]) // 订单列表
const collectList = ref([]) // 收藏列表
const tracksList = ref([]) // 足迹列表
const orderStatusList = ref([ // 订单状态
{
name: '未付款',
status: 'UNPAID'
},
{
name: '已付款',
status: 'PAID'
},
{
name: '待发货',
status: 'UNDELIVERED'
},
{
name: '已发货',
status: 'DELIVERED'
},
{
name: '已完成',
status: 'COMPLETED'
},
{
name: '待核验',
status: 'TAKE'
},
{
name: '已取消',
status: 'CANCELLED'
}
])
watch(() => props.title, (val) => {
switch (val) {
case '购物车':
getCartList()
break;
case '我的订单':
getOrderList()
break;
case '我的足迹':
getTracksList()
break;
case '优惠券':
getCouponList()
break;
case '我的收藏':
getCollectList()
break;
}
})
function getCartList () { // 获取购物车列表
loading.value = true
cartGoodsAll().then(res => {
loading.value = false
cartList.value = res.result.skuList
})
}
// 删除商品
function delGoods (id) {
delCartGoods({ skuIds: id }).then((res) => {
if (res.success) {
Message.success('删除成功');
getCartList();
cartCount().then(res => {
appStore.setCartNum(res.result)
storage.setItem('cartNum', res.result)
})
} else {
Message.error(res.message);
}
});
}
function filterOrderStatus (status) { // 获取订单状态中文
const ob = orderStatusList.value.filter(e => { return e.status === status });
return ob[0].name
}
function receive (item) { // 领取优惠券
receiveCoupon(item.id).then(res => {
if (res.success) {
Modal.confirm({
title: '领取优惠券',
content: '<p>优惠券领取成功,可到我的优惠券页面查看</p>',
okText: '我的优惠券',
cancelText: '立即使用',
onOk: () => {
router.push('/home/Coupons')
},
onCancel: () => {
if (item.storeId !== '0') {
router.push({path: '/merchant', query: {id: item.storeId}})
} else {
if (item.scopeType === 'PORTION_GOODS_CATEGORY') {
router.push({path: '/goodsList', query: {categoryId: item.scopeId}})
} else {
router.push({path: '/goodsList'})
}
}
}
});
}
})
}
function useScope (type, storeName) { // 判断优惠券使用范围
let shop = '平台';
let goods = '全部商品'
if (storeName !== 'platform') shop = storeName
switch (type) {
case 'ALL':
goods = '全部商品'
break;
case 'PORTION_GOODS':
goods = '部分商品'
break;
case 'PORTION_GOODS_CATEGORY':
goods = '部分分类商品'
break;
}
return `${shop}${goods}可用`
}
function addToCart (id) { // 添加商品到购物车
const params = {
num: 1,
skuId: id
}
loading.value = true;
addCartGoods(params).then(res => {
loading.value = false;
if (res.success) {
Message.success('商品已成功添加到购物车')
} else {
Message.warning(res.message);
}
}).catch(() => { loading.value = false });
}
function getCouponList () { // 获取优惠券列表
// loading.value = true;
const params = {
pageNumber: 1,
pageSize: 10
}
fetchCouponList(params).then(res => {
loading.value = false
if (res.success) {
couponList.value = res.result.records
}
}).catch(() => { loading.value = false })
}
function getOrderList () { // 获取订单列表
loading.value = true
const params = {
pageNumber: 1,
pageSize: 10,
tag: 'ALL'
}
fetchOrderList(params).then(res => {
loading.value = false
if (res.success) {
orderList.value = res.result.records;
}
});
}
function getCollectList () { // 获取收藏列表
const params = {
pageNumber: 1,
pageSize: 10,
type: 'GOODS'
}
loading.value = true
fetchCollectList(params).then(res => {
loading.value = false
collectList.value = res.result.records
})
}
function cancelCollect (id) { // 取消商品收藏
apiCancelCollect('GOODS', id).then(res => {
if (res.success) {
Message.success('取消收藏成功')
getCollectList();
}
})
}
function getTracksList () { // 获取足迹列表
const params = {
pageNumber: 1,
pageSize: 20
}
loading.value = true
fetchTracksList(params).then(res => {
tracksList.value = res.result.records
loading.value = false
}).catch(() => { loading.value = false })
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -3,102 +3,99 @@
<div class="wrapper" :style="{right:handleDrawer ? '300px' : '0px'}"> <div class="wrapper" :style="{right:handleDrawer ? '300px' : '0px'}">
<div class="barItem" @mouseenter="showCartNum(item)" @click="clickBar(item)" v-for="(item,index) in resetConfig.menuList" :key="index"> <div class="barItem" @mouseenter="showCartNum(item)" @click="clickBar(item)" v-for="(item,index) in resetConfig.menuList" :key="index">
<Tooltip placement="left" :content="item.title"> <el-tooltip placement="left" :content="item.title">
<Icon size="20" :type="item.icon"/> <el-icon :size="20"><component :is="resolveIcon(item.icon)" /></el-icon>
<p class="barTitle" v-if="item.titleShow"> {{item.title}}</p> <p class="barTitle" v-if="item.titleShow"> {{item.title}}</p>
<div class="circle" v-if="item.title === '购物车'"> <div class="circle" v-if="item.title === '购物车'">
{{cartNum < 100 ? cartNum : 99}} {{ Number(cartNum) > 99 ? '99+' : cartNum }}
</div> </div>
</Tooltip> </el-tooltip>
</div> </div>
</div> </div>
<Drawer width="300" class="popup" :title="drawerData.title" :mask="resetConfig.mask" :closable="resetConfig.closable" <el-drawer width="300" class="popup" :title="drawerData.title" :modal="resetConfig.mask" :show-close="resetConfig.closable"
v-model="handleDrawer"> v-model="handleDrawer">
<drawerPage :title="drawerData.title" /> <drawerPage :title="drawerData.title" />
</Drawer> </el-drawer>
</div> </div>
</template> </template>
<script> <script setup>
import Storage from '@/plugins/storage.js'; import { computed, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { Modal } from "@/utils/message";
import storage from '@/plugins/storage.js';
import Configuration from './config'; import Configuration from './config';
import drawerPage from './Drawer' import drawerPage from './Drawer'
import {cartCount} from '@/api/cart.js' import {cartCount} from '@/api/cart.js'
export default { import { resolveIcon } from '@/utils/iconMap'
name: 'Main', import { useAppStore } from '@/stores/app'
data () {
return { defineOptions({ name: 'Main' })
resetConfig: Configuration, // 菜单项
handleDrawer: false, // 是否可展开 const route = useRoute()
drawerData: '' // 菜单基础数据 const router = useRouter()
} const appStore = useAppStore()
},
components: {drawerPage}, const resetConfig = ref(Configuration) // 菜单项
computed: { const handleDrawer = ref(false) // 是否可展开
// 用户信息 const drawerData = ref('') // 菜单基础数据
userInfo () {
return Storage.getItem('userInfo'); // 用户信息
}, const userInfo = computed(() => {
// 购物车商品数量 return storage.getItem('userInfo');
cartNum () { })
return this.$store.state.cartNum
} // 购物车商品数量
}, const cartNum = computed(() => appStore.cartNum)
methods: {
showCartNum (item) { // 获取购物车数量 function showCartNum (item) { // 获取购物车数量
if (this.userInfo && item.title === '购物车') { if (userInfo.value && item.title === '购物车') {
this.getCartList() getCartList()
} }
}, }
clickBar (val) { // tabbar点击操作
if (!this.userInfo) { function clickBar (val) { // tabbar点击操作
this.$Modal.confirm({ if (!userInfo.value) {
title: '请登录', Modal.confirm({
content: '<p>请登录后执行此操作</p>', title: '请登录',
okText: '立即登录', content: '请登录后执行此操作',
cancelText: '继续浏览', okText: '立即登录',
onOk: () => { cancelText: '继续浏览',
this.$router.push({ onOk: () => {
path: '/login', router.push({
query: { path: '/login',
rePath: this.$router.history.current.path, query: {
query: JSON.stringify(this.$router.history.current.query) rePath: route.path,
} query: JSON.stringify(route.query || {}),
}); },
}
}); });
} else {
if (val.display) {
this.handleDrawer = true
this.drawerData = val
} else {
this.handleDrawer = false
switch (val.title) {
case '会员中心':
this.openBlank('/home')
break;
case '我的资产':
this.openBlank('/home/MoneyManagement')
break;
}
}
} }
}, });
openBlank (path) { // 新页面打开地址 } else {
let routerUrl = this.$router.resolve({ if (val.display) {
path: path handleDrawer.value = true
}) drawerData.value = val
window.open(routerUrl.href, '_blank') } else {
}, handleDrawer.value = false
getCartList () { // 获取购物车列表 switch (val.title) {
cartCount().then(res => { case '会员中心':
this.$store.commit('SET_CARTNUM', res.result) router.push('/home')
this.Cookies.setItem('cartNum', res.result) break;
}) case '我的资产':
router.push('/home/MoneyManagement')
break;
}
} }
} }
} }
function getCartList () { // 获取购物车列表
cartCount().then(res => {
appStore.setCartNum(res.result)
storage.setItem('cartNum', res.result)
})
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@@ -128,11 +125,15 @@ export default {
} }
.circle { .circle {
width: 20px; min-width: 20px;
height: 20px; height: 20px;
border-radius: 50%; padding: 0 4px;
border-radius: 10px;
color: #fff; color: #fff;
background: $theme_color; background: $theme_color;
font-size: 12px;
line-height: 20px;
box-sizing: border-box;
} }
.wrapper { .wrapper {
@@ -147,11 +148,11 @@ export default {
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
} }
/deep/.popup .ivu-drawer-body{ :deep(.popup .el-drawer__body) {
padding: 0!important; padding: 0 !important;
background-color: #eee; background-color: #eee;
} }
/deep/.popup .ivu-drawer-wrap{ :deep(.popup) {
z-index: 3001; z-index: 3001;
} }
</style> </style>

View File

@@ -1,42 +1,30 @@
# 右侧侧边栏组件 # 右侧侧边栏组件
> 本组件依赖于iview的组件基础上进行封装
>项目结构
>* Main -- 组件用于挂在右侧的横栏
>* drawer -- 右侧横栏的内容
>* config -- 用于设置大小
基于 Element Plus `el-drawer` 封装的右侧悬浮栏。
#### config设置 ## 项目结构
```
- `Main.vue` — 挂载右侧横栏的容器
- `Drawer.vue` — 横栏展开后的内容面板
- `config.js` — 尺寸与菜单配置
## config 设置
```js
/** /**
menuList // 组件的menu * menuList 菜单项列表
display //是否显示此menu * display 是否显示该项
badge //显示徽标数 * badge 徽标数字
titleShow //是否显示title * titleShow 是否显示标题
*/ */
width: 50,
//实例代码 menuList: [{ icon: '...' }]
width : 50, //bar的大小
menuList:[
{
icon
}
]
``` ```
## 功能模块
账户信息、购物车、我的订单、优惠券、我的资产、我的足迹、我的收藏、邮箱订阅
> 账户信息 ## 使用
> 购物车
> 我的订单
> 优惠券
> 我的资产
> 我的足迹
> 我的收藏
> 邮箱订阅
在页面中注册全局组件 `<drawer />` 即可(已在 `global.js` 中注册)。
## 如何使用
1.

View File

@@ -7,23 +7,23 @@
alt="" alt=""
/> />
<p v-if="_Title">{{ _Title }}</p> <p v-if="_Title">{{ _Title }}</p>
<slot></slot>
</div> </div>
</template> </template>
<script> <script setup>
export default { defineOptions({ name: 'Main' })
name: 'Main',
props: { defineProps({
_Title: { // 描述内容 _Title: { // 描述内容
type: null, type: null,
default: '暂无更多' default: '暂无更多'
}, },
_Size: { // 图片大小 _Size: { // 图片大小
type: Number, type: Number,
default: 150 default: 150
}
} }
}; })
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -0,0 +1,149 @@
<template>
<div class="shadow-box">
<div class="shadow-item flex flex-a-c flex-j-c" v-for="(item,index) in iconList" @click="handleClickIcon(item)" :key="index">
<img class="icon" :src="getIconUrl(item.icon)">
<div class="shadow-label">{{item.label}}</div>
<div class="line" v-if="iconList.length-1 !=index"></div>
</div>
</div>
</template>
<script setup>
import { onMounted, ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import { getIconUrl } from "@/assets/iconfont/iconMap";
import storage from "@/plugins/storage.js";
defineOptions({ name: "fixed-index" });
const route = useRoute();
const router = useRouter();
const iconList = ref([
{
icon:"user",
label:"会员中心",
path:"/home",
requireLogin: true,
},
{
icon:"carts",
label:"购物车",
path:"/cart",
requireLogin: true,
},
{
icon:"notification",
label:"消息",
path:"/home/MsgList",
requireLogin: true,
},
{
icon:"collage",
label:"收藏",
path:"/home/Favorites",
requireLogin: true,
},
{
icon:"back",
label:"顶部",
path:"back"
},
]);
let isScrolling = false;
let timeoutId = "";
onMounted(() => {
// 添加滚轮事件监听器
window.addEventListener('wheel', function() {
if (isScrolling) {
// 如果页面正在滚动,则取消定时器并设置 isScrolling 为 false
window.cancelAnimationFrame(timeoutId);
isScrolling = false;
}
});
});
function scrollToTop() {
const c = document.documentElement.scrollTop || document.body.scrollTop;
if (c > 0) {
timeoutId = window.requestAnimationFrame(scrollToTop);
window.scrollTo(0, c - c / 4);
isScrolling = true;
}else {
isScrolling = false;
}
}
function isLoggedIn () {
const rawUserInfo = storage.getItem('userInfo');
if (rawUserInfo) {
try {
return !!JSON.parse(rawUserInfo).username;
} catch {
return false;
}
}
return !!storage.getItem('accessToken');
}
function goLogin (rePath) {
router.push({
path: '/login',
query: {
rePath,
query: JSON.stringify(route.query || {}),
},
});
}
function handleClickIcon (val) {
if (val.path === 'back') {
scrollToTop();
return;
}
if (val.requireLogin && !isLoggedIn()) {
goLogin(val.path);
return;
}
router.push(val.path);
}
</script>
<style scoped lang="scss">
.shadow-box{
width: 64px;
height: 354px;
border-radius: 10px;
opacity: 1;
background: #FFFFFF;
box-shadow: 0px 1px 10px 0px rgba(154, 154, 154, 0.5);
}
.shadow-label{
font-size: 13px;
font-weight: normal;
line-height: 16px;
text-align: center;
letter-spacing: 0px;
color: #666666;
}
.icon{
margin-top: 15px;
width: 20px;
height: 20px;
margin-bottom: 5px;
}
.shadow-item{
cursor: pointer;
flex-direction: column;
height: 70px;
>.line{
width: 34px;
height: 1px;
opacity: 1;
margin-top: 17px;
border: 0.7px solid #EAEAEA;
}
}
</style>

View File

@@ -3,20 +3,20 @@
<footer class="footer"> <footer class="footer">
<div class="clearfix"></div> <div class="clearfix"></div>
<div class="icon-row"> <div class="icon-row">
<div class="footer-icon"> <div class="footer-icon flex flex-a-c">
<h5 class="footer-icon-child"></h5> <h5 class="footer-icon-child">多</h5>
<span class="footer-icon-text">品类齐全,轻松购物</span> <span class="footer-icon-text">品类齐全,轻松购物</span>
</div> </div>
<div class="footer-icon"> <div class="footer-icon flex flex-a-c">
<h5 class="footer-icon-child footer-icon-child-2"></h5> <h5 class="footer-icon-child footer-icon-child-2">快</h5>
<span class="footer-icon-text">多仓直发,极速配送</span> <span class="footer-icon-text">多仓直发,极速配送</span>
</div> </div>
<div class="footer-icon"> <div class="footer-icon flex flex-a-c">
<h5 class="footer-icon-child footer-icon-child-3"></h5> <h5 class="footer-icon-child footer-icon-child-3">好</h5>
<span class="footer-icon-text">正品行货,精致服务</span> <span class="footer-icon-text">正品行货,精致服务</span>
</div> </div>
<div class="footer-icon"> <div class="footer-icon flex flex-a-c">
<h5 class="footer-icon-child footer-icon-child-4"></h5> <h5 class="footer-icon-child footer-icon-child-4">省</h5>
<span class="footer-icon-text">天天低价,畅选无忧</span> <span class="footer-icon-text">天天低价,畅选无忧</span>
</div> </div>
</div> </div>
@@ -29,131 +29,185 @@
</div> </div>
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
<div class="friend-link"> <div class="friend-link flex">
<div class="friend-link-item"> <div class="friend-link-item">
<ul> <ul>
<li v-for="(link, index) in moreLink" :key="index" @click="goArticle"> <li v-for="(link, index) in moreLink" :key="index" @click="goArticle">
<span class="link-item" :class="{'link-last-item': index === 4}">{{link}}</span> <span class="link-item" :class="{'link-last-item': index === 4}">{{link}}</span>
</li> </li>
</ul> </ul>
</div> </div>
</div>
<div class="information footer-bottmom">
<div class="icp">
<li v-if="config.icpCard">
<a :href='"https://tsm.miit.gov.cn/dxxzsp/xkz/xkzgl/resource/qiyesearch.jsp?num="+config.icpCard+"&type=xuke"' target="_blank">
{{config.icpCard}}
</a>
</li>
<li v-if="config.icpMessage" class="footer-bottmom">
<a href="https://beian.miit.gov.cn/" target="_blank">
{{config.icpMessage}}
</a>
</li>
</div>
<a class="flex " :href="config.company.href">
<img class="zhizhao" src="@/assets/images/zhizhao.jpg" mode="" />{{config.company.name}}
</a>
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
<div class="copyright"> <div class="copyright">
<p>Copyright © {{year}} LILI</p> <p>Copyright © {{year}} {{config.title}}</p>
</div> </div>
</div> </div>
</footer> </footer>
</div> </div>
</template> </template>
<script> <script setup>
export default { import { ref } from 'vue'
name: 'Footer', import { useRouter } from 'vue-router'
data () { import config from '@/config'
return {
guideArr: [ // 导航链接 defineOptions({ name: 'Footer' })
[ '购物指南', '购物流程', '会员介绍', '生活旅行', '常见问题' ],
[ '配送方式', '上门自提', '配送服务查询', '收取标准', '物流规则' ], const router = useRouter()
[ '支付方式', '在线支付', '公司转账', '余额支付', '积分支付' ],
[ '售后服务', '售后政策', '退款说明', '返修/退货', '取消订单' ] const guideArr = ref([
], // 导航链接
moreLink: ['关于我们', '联系我们', '联系客服', '商家帮助', '隐私政策'], // 更多链接 ["购物指南", "购物流程", "会员介绍", "生活旅行", "常见问题"],
year: new Date().getFullYear() // 当前年份 ["配送方式", "上门自提", "配送查询", "收取标准", "物流规则"],
}; ["支付方式", "在线支付", "公司转账", "余额支付", "积分支付"],
}, ["售后服务", "售后政策", "退款说明", "返修/退货", "取消订单"],
methods: { ])
goArticle () { // 跳转文章页 const moreLink = ref(["关于我们", "联系我们", "联系客服", "商家帮助", "隐私政策"]) // 更多链接
let routeUrl = this.$router.resolve({ const year = ref(new Date().getFullYear()) // 当前年份
path: '/article'
}) function goArticle() {
window.open(routeUrl.href, '_blank') // 跳转文章页
} router.push("/article")
} }
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
/*****************************底 部 开 始*****************************/ /*****************************底 部 开 始*****************************/
.footer { .footer {
width: 100%; width: 100%;
height: 380px; height: 370px;
padding-top: 30px; background: #FFFFFF;
@include background_color($light_background_color);
} }
.icon-row { .icon-row {
margin: 15px auto; display: flex;
padding-top: 8px; align-items: center;
width: 1000px; justify-content: space-between;
height: 64px; width: 1056px;
height: 71px;
margin: 0 auto;
} }
.footer-icon { .footer-icon {
margin-left: 17px;
margin-right: 17px;
float: left; float: left;
} }
.footer-icon-child { .footer-icon-child {
margin-top: 10px;
overflow: hidden; overflow: hidden;
position: absolute; width: 36.4px;
width: 36px; display: flex;
height: 42px; align-items: center;
background-image: url("../../assets/images/footer/ico_service.png"); justify-content: center;
text-indent: -999px; font-size: 18.2px;
font-weight: normal;
color: #333;
height: 36.4px;
border: 1.4px solid #CECECE;
border-radius: 50%;
} }
.footer-icon-child-2 {
background-position: 0 -43px; .icp {
margin-right: 30px !important;
>*{
margin: 0 4px;
}
flex-direction: column;
} }
.footer-icon-child-3 { .flex{
background-position: 0 -86px; display: flex;
align-items: center;
>img{
margin-right: 4px;
}
} }
.footer-icon-child-4 { .footer-icon-text {
background-position: 0 -129px; margin-left: 11px;
} font-size: 16px;
.footer-icon-text{
margin-left: 45px; font-weight: normal;
font-size: 18px;
font-weight: bold; text-align: center;
line-height: 64px;
} }
.service-intro { .service-intro {
width: 100%; width: 100%;
border-top: 1px solid $border_color; border-top: 1px solid $border_color;
} }
.servece-type { .servece-type {
margin: 15px auto; width: 952px;
width: 800px; margin: 22px auto 10px auto;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
}
}
.servece-type-info{
}
.servece-type-info ul { .servece-type-info ul {
list-style: none; list-style: none;
} }
.servece-type-info li { .servece-type-info li {
font-size: 14px; font-size: 12px;
cursor: pointer; cursor: pointer;
line-height: 26px; font-weight: normal;
line-height: 15px;
text-align: center;
margin-bottom: 13px;
color: #333;
} }
.servece-type-info li:first-child { .servece-type-info li:first-child {
font-size: 16px; font-size: 14.82px;
line-height: 28px; font-weight: normal;
font-weight: bold; line-height: 18px;
letter-spacing: 0px;
margin-bottom: 17px;
color: #333333;
} }
.friend-link { .friend-link {
display: flex; display: flex;
align-items: center; align-items: flex-start;
justify-content: center;
width: 908px; width: 908px;
height: 30px; padding: 10px 0;
margin: 0px auto; margin: 0px auto;
border-top: 1px solid $border_color; border-top: 1px solid $border_color;
} }
.friend-link-item { .information {
margin: 0px auto; margin-top: 23px;
margin-bottom: 21px;
display: flex;
justify-content: center;
}
a{
color: #3457FF;
}
.zhizhao {
width: 20px;
height: 20px;
border-radius: 50%;
} }
.friend-link-item ul { .friend-link-item ul {
list-style: none; list-style: none;
@@ -161,29 +215,45 @@ export default {
.friend-link-item li { .friend-link-item li {
padding: 5px 0px; padding: 5px 0px;
float: left; float: left;
margin-right: 59px;
font-weight: normal;
line-height: 13px;
color: #333333;
} }
.link-item { .link-item {
padding: 0px 8px; padding: 0px 8px;
cursor: pointer; cursor: pointer;
border-right: 1px solid $border_color;
} }
.link-last-item { .link-last-item {
border: none; border: none;
} }
.copyright { .copyright {
width: 100%; width: 100%;
line-height: 30px; cursor: pointer;
text-align: center; text-align: center;
height:25px;
opacity: 1;
margin-bottom: 12px;
font-size: 12px;
font-weight: normal;
line-height: 13px;
letter-spacing: 0px;
color: #959595;
} }
.copyright a{
color: #232323; .footer-icon-text {
font-size: 20px; @include title_color($light_title_color);
} }
.footer-icon-text{ .copyright,
@include title_color($light_title_color) .friend-link,
} .servece-type-info {
.copyright,.friend-link,.servece-type-info { @include sub_color($light_sub_color);
@include sub_color($light_sub_color)
} }
/*****************************底 部 结 束*****************************/ /*****************************底 部 结 束*****************************/
</style> </style>

View File

@@ -1,54 +1,21 @@
// 全局组件配置 import empty from "./empty/Main.vue";
import drawer from "./drawer/Main.vue";
import Header from "@/components/header/Header.vue";
import FixedTopPage from "@/components/advertising/FixedTop.vue";
import Footer from "@/components/footer/Footer.vue";
import Search from "@/components/Search.vue";
import card from "@/components/card/index.vue";
import cateNav from "@/components/nav/CateNav.vue";
import UserCenterLayout from "@/components/userCenter/Layout.vue";
import empty from './empty/Main' // 空状态组件 export function registerGlobalComponents(app) {
import drawer from './drawer/Main' // 右侧bar app.component("empty", empty);
import Header from '@/components/header/Header'; // 头部组件 app.component("drawer", drawer);
import FixedTopPage from '@/components/advertising/FixedTop'; // 顶部广告 app.component("BaseHeader", Header);
import Footer from '@/components/footer/Footer'; // 底部栏 app.component("FixedTopPage", FixedTopPage);
import Search from '@/components/Search' // 搜索框 app.component("BaseFooter", Footer);
import card from '@/components/card' // 个人中心 卡片 app.component("Search", Search);
import cateNav from '@/components/nav/CateNav' // 个人中心 卡片 app.component("card", card);
app.component("UserCenterLayout", UserCenterLayout);
empty.install = function (Vue) { app.component("cateNav", cateNav);
Vue.component('empty', empty);
};
drawer.install = function (Vue) {
Vue.component('drawer', drawer);
};
Header.install = function (Vue) {
Vue.component('BaseHeader', Header);
};
FixedTopPage.install = function (Vue) {
Vue.component('FixedTopPage', FixedTopPage);
};
Footer.install = function (Vue) {
Vue.component('BaseFooter', Footer);
};
Search.install = function (Vue) {
Vue.component('Search', Search);
};
card.install = function (Vue) {
Vue.component('card', card)
}
cateNav.install = function (Vue) {
Vue.component('cateNav', cateNav)
}
// 引用本js中所有的组件
export function InstallAll (Vue) {
Vue.use(empty)
Vue.use(drawer)
Vue.use(Header)
Vue.use(FixedTopPage)
Vue.use(Footer)
Vue.use(Search)
Vue.use(card)
Vue.use(cateNav)
} }

View File

@@ -0,0 +1,146 @@
<template>
<div class="goods-thumb" ref="rootEl" :class="{ 'is-loaded': loaded, 'is-error': error }">
<img v-if="currentSrc" :src="currentSrc" :alt="alt" @load="loaded = true" @error="onError" />
<img v-else-if="error" :src="defaultImg" :alt="alt || '默认商品图片'" class="default-img" />
</div>
</template>
<script setup>
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
import defaultImg from "@/assets/images/default.png";
defineOptions({ name: "GoodsThumb" });
const props = defineProps({
src: {
type: String,
default: "",
},
alt: {
type: String,
default: "",
},
});
const rootEl = ref(null);
const currentSrc = ref("");
const loaded = ref(false);
const error = ref(false);
let observer = null;
function isValidUrl(url) {
if (!url || typeof url !== "string") return false;
const s = url.trim().toLowerCase();
if (
!s ||
s === "null" ||
s === "undefined" ||
s.startsWith("null?") ||
s.startsWith("undefined?")
) {
return false;
}
return true;
}
watch(
() => props.src,
() => {
observe();
}
);
function disconnect() {
if (observer) {
observer.disconnect();
observer = null;
}
}
function observe() {
disconnect();
currentSrc.value = "";
loaded.value = false;
error.value = false;
if (!isValidUrl(props.src)) {
error.value = true;
return;
}
if (typeof IntersectionObserver === "undefined") {
currentSrc.value = props.src;
return;
}
observer = new IntersectionObserver(
(entries) => {
if (!entries.some((entry) => entry.isIntersecting)) return;
currentSrc.value = props.src;
disconnect();
},
{ rootMargin: "160px 0px" }
);
observer.observe(rootEl.value);
}
function onError() {
error.value = true;
loaded.value = false;
currentSrc.value = "";
}
onMounted(() => {
observe();
});
onBeforeUnmount(() => {
disconnect();
});
</script>
<style scoped lang="scss">
.goods-thumb {
position: relative;
width: 100%;
aspect-ratio: 1;
overflow: hidden;
background: #f3f3f3;
}
.goods-thumb::before {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(90deg, #f3f3f3 25%, #e8e8e8 37%, #f3f3f3 63%);
background-size: 400% 100%;
animation: goods-thumb-loading 1.2s ease infinite;
}
.goods-thumb.is-loaded::before,
.goods-thumb.is-error::before {
display: none;
}
.goods-thumb img {
position: relative;
z-index: 1;
width: 100%;
height: 100%;
object-fit: cover;
display: block;
&.default-img {
object-fit: contain;
padding: 14px;
box-sizing: border-box;
opacity: 0.55;
}
}
@keyframes goods-thumb-loading {
0% {
background-position: 100% 0;
}
100% {
background-position: 0 0;
}
}
</style>

View File

@@ -1,9 +1,14 @@
<template> <template>
<div> <div>
<div class="wrapper" v-if="type === 'goodsDetail'"> <div class="wrapper" v-if="type === 'goodsDetail'">
<div class="wr-l"><Icon size="23" type="ios-alarm-outline" /> 秒杀活动</div> <div class="wr-l"><el-icon :size="23"><AlarmClock /></el-icon> 秒杀活动</div>
<div class="count-down" v-if="end === ''"> <div class="count-down" v-if="end === ''">
<p>倒计时:</p><span>{{ hours }}</span><span>{{ minutes }}</span><span>{{ seconds }}</span> <span class="count-down-label">倒计时:</span>
<span class="count-down-num">{{ hours }}</span>
<span class="count-down-colon">:</span>
<span class="count-down-num">{{ minutes }}</span>
<span class="count-down-colon">:</span>
<span class="count-down-num">{{ seconds }}</span>
</div> </div>
<div v-else>{{end}}</div> <div v-else>{{end}}</div>
</div> </div>
@@ -13,58 +18,57 @@
</span> </span>
</div> </div>
</template> </template>
<script> <script setup>
export default { import { onMounted, ref } from 'vue';
props: { import { AlarmClock } from '@element-plus/icons-vue';
time: { // 传入的初始时间
default: 1718977559428 const props = defineProps({
}, time: { // 传入的初始时间
type: { // 区分是在详情还是购物车调用 default: 1718977559428
default: 'goodsDetail', // 设置两个值,goodsDetail和cart,样式不同
type: String
}
}, },
data () { type: { // 区分是在详情还是购物车调用
return { default: 'goodsDetail', // 设置两个值,goodsDetail和cart,样式不同
end: '', // 结束状态 type: String
hours: '', // 小时
minutes: '', // 分钟
seconds: '', // 秒
interval: '' // 定时器
};
},
mounted () {
this.init()
},
methods: {
countDown (val) { // 倒计时方法
function addZero (i) {
return i < 10 ? '0' + i : i + '';
}
var nowtime = new Date();
var endtime = new Date(val);
var lefttime = parseInt((endtime.getTime() - nowtime.getTime()) / 1000);
var h = parseInt((lefttime / (60 * 60)) % 24);
var m = parseInt((lefttime / 60) % 60);
var s = parseInt(lefttime % 60);
h = addZero(h);
m = addZero(m);
s = addZero(s);
this.hours = h;
this.minutes = m
this.seconds = s;
if (lefttime <= 0) {
this.end = `活动已结束`;
clearInterval(this.interval)
}
},
init () { // 初始化
this.interval = setInterval(() => {
this.countDown(this.time);
}, 1000);
}
} }
}; });
const end = ref(''); // 结束状态
const hours = ref(''); // 小时
const minutes = ref(''); // 分钟
const seconds = ref(''); // 秒
let interval = null; // 定时器
function countDown (val) { // 倒计时方法
function addZero (i) {
return i < 10 ? '0' + i : i + '';
}
var nowtime = new Date();
var endtime = new Date(val);
var lefttime = parseInt((endtime.getTime() - nowtime.getTime()) / 1000);
var h = parseInt((lefttime / (60 * 60)) % 24);
var m = parseInt((lefttime / 60) % 60);
var s = parseInt(lefttime % 60);
h = addZero(h);
m = addZero(m);
s = addZero(s);
hours.value = h;
minutes.value = m
seconds.value = s;
if (lefttime <= 0) {
end.value = `活动已结束`;
clearInterval(interval)
}
}
function init () { // 初始化
interval = setInterval(() => {
countDown(props.time);
}, 1000);
}
onMounted(() => {
init()
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.cart-promotion{ .cart-promotion{
@@ -87,36 +91,35 @@ export default {
font-size: 13px; font-size: 13px;
} }
.count-down { .count-down {
margin-right: -20px; display: flex;
p{ align-items: center;
float: left; gap: 4px;
line-height: 20px; font-size: 13px;
line-height: 1;
.count-down-label {
flex-shrink: 0;
white-space: nowrap;
} }
> span {
position: relative; .count-down-num {
float: left; display: inline-flex;
width: 20px; align-items: center;
justify-content: center;
min-width: 20px;
height: 20px; height: 20px;
text-align: center; padding: 0 2px;
background-color: #2f3430; background-color: #2f3430;
margin-right: 20px; color: #fff;
color: white;
font-size: 14px; font-size: 14px;
line-height: 20px; line-height: 1;
&::after { border-radius: 2px;
content: ":";
display: block;
position: absolute;
right: -20px;
font-weight: bolder;
font-size: 14px;
width: 20px;
height: 100%;
top: 0;
}
} }
> span:last-child::after {
content: ""; .count-down-colon {
font-weight: bold;
font-size: 14px;
line-height: 1;
} }
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,495 @@
<template>
<aside class="store-side" v-if="storeId">
<div class="store-card">
<div class="store-head" @click="goStore">
<img
v-if="store.storeLogo && !logoError"
class="store-logo"
:src="store.storeLogo"
loading="lazy"
decoding="async"
:alt="storeName"
@error="logoError = true"
/>
<span v-else class="store-logo store-logo-fallback">{{ storeInitial }}</span>
<div class="store-head-text">
<p class="store-name">
<span v-if="isSelfOperated" class="store-self">自营</span>
<span class="store-name-text">{{ storeName }}</span>
</p>
</div>
</div>
<div class="store-scores">
<div class="score-item">
<span class="score-label">描述</span>
<span class="score-value">{{ formatScore(store.descriptionScore) }}</span>
</div>
<div class="score-item">
<span class="score-label">服务</span>
<span class="score-value">{{ formatScore(store.serviceScore) }}</span>
</div>
<div class="score-item">
<span class="score-label">物流</span>
<span class="score-value">{{ formatScore(store.deliveryScore) }}</span>
</div>
</div>
<div class="store-actions">
<button type="button" class="store-btn" @click="contact">联系客服</button>
<button type="button" class="store-btn" :class="{ 'is-on': collected }" @click="toggleCollect">
{{ collected ? "已收藏" : "收藏店铺" }}
</button>
</div>
<button type="button" class="enter-store" @click="goStore">进店逛逛</button>
</div>
<div class="recommend-card" v-if="recommends.length">
<p class="recommend-title">店铺推荐</p>
<div
class="recommend-item"
v-for="item in recommends"
:key="item.id"
@click="goGoods(item)"
>
<img class="recommend-img" :src="item.thumbnail || item.small" loading="lazy" decoding="async" :alt="item.goodsName" />
<div class="recommend-info">
<p class="recommend-name">{{ item.goodsName }}</p>
<div class="recommend-meta">
<p class="recommend-price">{{ $filters.unitPrice(item.price, "¥") }}</p>
<span class="recommend-sales">销量 {{ item.buyCount || 0 }}</span>
</div>
</div>
</div>
</div>
</aside>
</template>
<script setup>
import { computed, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { Message, Modal } from "@/utils/message";
import { goodsList } from "@/api/goods";
import { getStoreById } from "@/api/shopentry";
import { cancelStoreCollect, collectStore, isStoreCollection } from "@/api/member";
import { getIMDetail } from "@/api/common";
import { getMemberMsg } from "@/api/login";
import storage from "@/plugins/storage.js";
defineOptions({ name: "StoreSide" });
const props = defineProps({
storeId: {
type: [String, Number],
default: "",
},
goodsId: {
type: [String, Number],
default: "",
},
skuId: {
type: [String, Number],
default: "",
},
storeNameFallback: {
type: String,
default: "",
},
});
const route = useRoute();
const router = useRouter();
const store = ref({});
const logoError = ref(false);
const collected = ref(false);
const recommends = ref([]);
// 原 talkIm mixin 的 IM 链接
const IMLink = ref("");
const storeName = computed(() => {
return store.value.storeName || props.storeNameFallback || "店铺";
});
const storeInitial = computed(() => {
return storeName.value.slice(0, 1);
});
// 自营标记后端可能是 true、1 或 "1"
const isSelfOperated = computed(() => {
const flag = store.value.selfOperated;
return flag === true || flag === 1 || flag === "1";
});
watch(
() => props.storeId,
(id) => {
if (!id) return;
logoError.value = false;
loadStore(id);
loadRecommend(id);
loadCollected(id);
},
{ immediate: true }
);
// 没有评分或小于等于 0 时按满分展示
function formatScore(value) {
const score = Number(value);
if (!Number.isFinite(score) || score <= 0) return "5.00";
return score.toFixed(2);
}
function loadStore(id) {
getStoreById(id).then((res) => {
if (res.success && res.result) store.value = res.result;
}).catch((err) => {
console.warn('获取店铺信息失败', err);
});
}
// 按销量取店内商品,去掉当前商品,最多 4 个
function loadRecommend(id) {
goodsList({
storeId: id,
pageNumber: 1,
pageSize: 8,
sort: "buyCount",
order: "desc",
}).then((res) => {
const records = (res.success && res.result && res.result.records) || [];
recommends.value = records
.filter((item) => String(item.goodsId) !== String(props.goodsId))
.slice(0, 4);
}).catch(() => {
// 推荐商品为可选数据,加载失败时静默
});
}
// 同时有 token 和用户信息才查收藏,避免残留 userInfo 触发登录跳转
function loadCollected(id) {
if (!storage.getItem("accessToken") || !storage.getItem("userInfo")) return;
isStoreCollection("STORE", id).then((res) => {
if (res.success && res.result) collected.value = true;
}).catch(() => {
// 收藏状态为可选数据,失败时静默
});
}
function goStore() {
router.push({ path: "/merchant", query: { id: props.storeId } });
}
// 推荐商品新开详情页,店铺页仍在当前页打开
function goGoods(item) {
const href = router.resolve({
path: "/goodsDetail",
query: { skuId: item.id, goodsId: item.goodsId },
}).href;
window.open(href, "_blank");
}
// 原 talkIm mixin 的登录提示
function promptLogin() {
Modal.confirm({
title: "温馨提示",
content: "请登录后执行此操作",
okText: "立即登录",
cancelText: "取消",
onOk: () => {
router.push({
path: "/login",
query: {
rePath: route.path,
query: JSON.stringify(route.query || {}),
},
});
},
});
}
// 获取im信息(原 talkIm mixin)
async function getIMDetailMethods() {
let res = await getIMDetail();
if (res.success) {
IMLink.value = res.result;
}
}
// 跳转im客服(原 talkIm mixin;本组件无 storeMsg,mixin 的 storeMsg?.storeId 兜底恒为 undefined,等价于直接用传入的 id)
async function IMService(id, goodsId, skuId) {
if (!storage.getItem("accessToken")) {
promptLogin();
return;
}
try {
await getIMDetailMethods();
const userInfo = await getMemberMsg();
if (!userInfo.success) {
promptLogin();
return;
}
const accessToken = storage.getItem("accessToken");
const storeId = id;
const baseUrl = `${IMLink.value}?token=${accessToken}&id=${storeId}`;
if (goodsId && skuId) {
window.open(`${baseUrl}&goodsId=${goodsId}&skuId=${skuId}`);
} else {
window.open(baseUrl);
}
} catch {
// token 过期等场景由 request 拦截器处理;未登录时避免未捕获异常
if (!storage.getItem("accessToken")) {
promptLogin();
}
}
}
function contact() {
IMService(props.storeId, props.goodsId, props.skuId);
}
// 未登录先去登录,并带回当前商品页
async function toggleCollect() {
if (!storage.getItem("accessToken") || !storage.getItem("userInfo")) {
router.push({
path: "/login",
query: {
rePath: route.path,
query: JSON.stringify(route.query || {}),
},
});
return;
}
if (collected.value) {
const cancel = await cancelStoreCollect("STORE", props.storeId);
if (cancel.success) {
collected.value = false;
Message.success("已取消收藏");
}
return;
}
const collect = await collectStore("STORE", props.storeId);
if (collect.code === 200) {
collected.value = true;
Message.success("收藏店铺成功,可以前往个人中心我的收藏查看");
}
}
</script>
<style scoped lang="scss">
.store-side {
width: 260px;
flex-shrink: 0;
position: sticky;
top: 16px;
}
.store-card,
.recommend-card {
background: #fff;
border: 1px solid #f0f0f0;
border-radius: 4px;
}
.store-card {
padding: 16px;
}
.store-head {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
cursor: pointer;
}
.store-logo {
width: 64px;
height: 64px;
border-radius: 4px;
object-fit: cover;
border: 1px solid #f0f0f0;
flex-shrink: 0;
background: #fafafa;
}
.store-logo-fallback {
display: flex;
align-items: center;
justify-content: center;
color: #fff;
background: $theme_color;
font-size: 18px;
font-weight: 600;
}
.store-head-text {
width: 100%;
text-align: center;
}
.store-name {
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
margin: 0;
color: #171A26;
font-size: 15px;
font-weight: 600;
line-height: 22px;
}
.store-name-text {
min-width: 0;
}
.store-self {
flex-shrink: 0;
padding: 0 6px;
border-radius: 2px;
background: $theme_color;
color: #fff;
font-size: 12px;
font-weight: 400;
line-height: 18px;
}
.store-scores {
display: flex;
margin-top: 14px;
padding: 10px 0;
border-top: 1px solid #f5f5f5;
border-bottom: 1px solid #f5f5f5;
}
.score-item {
flex: 1;
text-align: center;
}
.score-label {
display: block;
color: #999;
font-size: 12px;
line-height: 18px;
}
.score-value {
display: block;
margin-top: 2px;
color: $theme_color;
font-size: 14px;
font-weight: 600;
line-height: 20px;
}
.store-actions {
display: flex;
gap: 8px;
margin-top: 14px;
}
.store-btn,
.enter-store {
border: 1px solid #eee;
background: #fff;
color: #171A26;
font-size: 13px;
line-height: 32px;
border-radius: 4px;
cursor: pointer;
&:hover {
color: $theme_color;
border-color: $theme_color;
}
}
.store-btn {
flex: 1;
}
.store-btn.is-on {
color: $theme_color;
border-color: $theme_color;
background: #fff5f4;
}
.enter-store {
width: 100%;
margin-top: 8px;
}
.recommend-card {
margin-top: 12px;
padding: 12px 12px 4px;
}
.recommend-title {
margin: 0 0 8px;
color: #171A26;
font-size: 18px;
font-weight: 600;
line-height: 26px;
}
.recommend-item {
display: flex;
flex-direction: column;
gap: 8px;
padding: 8px 0 12px;
cursor: pointer;
& + & {
border-top: 1px solid #f5f5f5;
}
}
.recommend-img {
width: 100%;
aspect-ratio: 1;
object-fit: cover;
border-radius: 4px;
background: #fafafa;
}
.recommend-info {
min-width: 0;
}
.recommend-name {
margin: 0;
color: #333;
font-size: 16px;
line-height: 24px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.recommend-meta {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
margin-top: 4px;
}
.recommend-price {
margin: 0;
color: $theme_color;
font-size: 18px;
font-weight: 600;
line-height: 26px;
}
.recommend-sales {
flex-shrink: 0;
color: #999;
font-size: 15px;
line-height: 22px;
}
</style>

View File

@@ -1,27 +1,35 @@
<template> <template>
<div class="box"> <div class="box">
<div class="nav"> <div class="nav width_1200_auto">
<ul class="location"> <ul class="location flex">
<li v-if="$route.path.includes('home')" style="margin-left:10px"><router-link to="/">首页</router-link></li> <li v-if="$route.path.includes('home')" style="margin-left:10px">
<router-link to="/">首页</router-link>
</li>
<ul class="flex">
<li>Hi,欢迎来到{{ config.title }}</li>
<li class="first" v-show="!userInfo.username">
<router-link :to="`/signUp`" class="nav-item">
<span>立即注册</span>
</router-link>
</li>
<li v-show="!userInfo.username">
<router-link class="nav-item" :to="`/login?rePath=${$route.path}&query=${JSON.stringify($route.query)}`">
<span>请登录</span>
</router-link>
</li>
</ul>
</ul> </ul>
<ul class="detail"> <ul class="detail flex">
<li class="first" v-show="!userInfo.username">
<router-link :to="`/signUp`">
<span style="border:none">立即注册</span>
</router-link>
</li>
<li v-show="!userInfo.username">
<router-link :to="`/login?rePath=${$route.path}&query=${JSON.stringify($route.query)}`">
<span style="border:none">请登录</span>
</router-link>
</li>
<li v-show="!!userInfo.username"> <li v-show="!!userInfo.username">
<div class="username-p"> <div class="username-p">
<div> <div>
<Avatar class="person-icon" :src="userInfo.face" icon="person" size="small" /> <el-avatar class="person-icon" :src="userInfo.face" :size="24" />
<span class="username">{{ userInfo.nickName? userInfo.nickName : userInfo.username | secrecyMobile }}</span> <span class="username">{{ $filters.secrecyMobile(
userInfo.nickName ? userInfo.nickName : userInfo.username ) }}</span>
</div> </div>
<transition name='fade'> <transition name='fade'>
<!-- 下拉菜单通过父级 hover 的 CSS 控制显隐,transition 内无需 v-if/v-show -->
<!-- eslint-disable-next-line vue/require-toggle-inside-transition -->
<ul class="drop-items"> <ul class="drop-items">
<li @click="goUserCenter('/home')">我的主页</li> <li @click="goUserCenter('/home')">我的主页</li>
<li @click="goUserCenter('/home/Coupons')">优惠券</li> <li @click="goUserCenter('/home/Coupons')">优惠券</li>
@@ -31,342 +39,513 @@
</transition> </transition>
</div> </div>
</li> </li>
<li @click="goUserCenter('/home/MyOrder')"><span class="nav-item hover-color">我的订单</span></li> <li @click="goUserCenter('/home/MyOrder')"><span class="nav-item">我的订单</span></li>
<li @click="goUserCenter('/home/MyTracks')"><span class="nav-item hover-color">我的足迹</span></li> <li @click="goUserCenter('/home/MyTracks')"><span class="nav-item">我的足迹</span></li>
<li @click="goUserCenter('/home/MsgList')"><span class="nav-item hover-color">我的消息</span></li> <li @click="goUserCenter('/home/MsgList')">
<li v-if="$route.name !== 'Cart'" style="position:relative;"> <span class="nav-item">
<i class="cart-badge" v-show="Number(cartNum)">{{cartNum < 100 ? cartNum : '99'}}</i> 我的消息
<Dropdown placement="bottom-start"> <i v-if="unreadMsg > 0" class="msg-badge">{{ unreadLabel }}</i>
<router-link to="/cart" target="_blank"> </span>
<span @mouseenter="getCartList"> </li>
<Icon size="18" type="ios-cart-outline"></Icon> <li v-if="$route.name !== 'Cart'" class="cart-nav-item">
购物车 <el-dropdown
</span> class="cart-nav-dropdown"
</router-link> placement="bottom-start"
<DropdownMenu slot="list"> trigger="hover"
<div class="shopping-cart-null" style="width:200px" v-show="shoppingCart.length <= 0"> @visible-change="handleCartDropdownVisible"
<Icon type="ios-cart-outline" class="cart-null-icon"></Icon> >
<span class="nav-item" @click="goToPay">
<el-icon :size="18"><ShoppingCart /></el-icon>
购物车({{ Number(cartNum) > 99 ? '99+' : cartNum }})
</span>
<template #dropdown>
<div class="shopping-cart-null" v-show="shoppingCart.length <= 0">
<el-icon class="cart-null-icon"><ShoppingCart /></el-icon>
<span>你的购物车没有宝贝哦</span> <span>你的购物车没有宝贝哦</span>
<span>赶快去添加商品吧~</span> <span>赶快去添加商品吧~</span>
</div> </div>
<div class="shopping-cart-list" v-show="shoppingCart.length > 0"> <div class="shopping-cart-list" v-show="shoppingCart.length > 0">
<div class="shopping-cart-box" v-for="(item, index) in shoppingCart" @click="goToPay" :key="index"> <div class="shopping-cart-box" v-for="(item, index) in shoppingCart" @click="goToPay" :key="index">
<div class="shopping-cart-img"> <div class="shopping-cart-img">
<img :src="item.goodsSku.thumbnail" class="hover-pointer" /> <img :src="item.goodsSku.thumbnail" alt="" />
</div> </div>
<div class="shopping-cart-info"> <div class="shopping-cart-info">
<div class="shopping-cart-title "> <p class="goods-title">{{ item.goodsSku.goodsName }}</p>
<p class="hover-pointer goods-title ellipsis">{{ item.goodsSku.goodsName }}</p>
</div>
<div class="shopping-cart-detail"> <div class="shopping-cart-detail">
<p> <span>数量 {{ item.num }}</span>
数量: <span class="shopping-price">{{ $filters.unitPrice(item.purchasePrice, '¥') }}</span>
<span class="shopping-cart-text">{{ item.num }}</span>
价钱:
<span class="shopping-cart-text">{{ item.purchasePrice | unitPrice('¥') }}</span>
</p>
</div> </div>
</div> </div>
</div> </div>
<div class="go-to-buy">
<Button type="error" size="small" @click="goToPay">去结账</Button>
</div>
</div> </div>
</DropdownMenu> </template>
</Dropdown> </el-dropdown>
</li> </li>
<li> <li>
<span class="nav-item" @click="shopEntry">店铺入驻</span> <span class="nav-item" @click="shopEntry">店铺入驻</span>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
</template> </template>
<script> <script setup>
import { ref, computed } from "vue";
import { useRoute, useRouter } from "vue-router";
import { Modal } from "@/utils/message";
import { ShoppingCart } from '@element-plus/icons-vue';
import storage from '@/plugins/storage.js'; import storage from '@/plugins/storage.js';
import { cartGoodsAll } from '@/api/cart.js'; import {cartGoodsAll} from '@/api/cart.js';
export default { import {logout} from '@/api/account.js';
name: 'M-Header', import config from '@/config';
created () { import { refreshUnreadMessage } from '@/utils/unreadMessage';
if (storage.getItem('userInfo')) { import { useAppStore } from '@/stores/app';
this.userInfo = JSON.parse(storage.getItem('userInfo'));
}
},
data () { defineOptions({ name: 'M-Header' });
return {
userInfo: {}, // 用户信息 const route = useRoute();
shoppingCart: [] // 购物车 const router = useRouter();
}; const appStore = useAppStore();
},
computed: { const userInfo = ref({}); // 用户信息
// 购物车商品数量 const shoppingCart = ref([]); // 购物车
cartNum () { const cartLoading = ref(false);
return this.$store.state.cartNum; const cartLoadedAt = ref(0);
} const cartCacheTime = ref(5000);
},
methods: { // 购物车商品数量
goToPay () { // 跳转购物车 const cartNum = computed(() => appStore.cartNum);
let url = this.$router.resolve({ const unreadMsg = computed(() => appStore.unreadMsg);
path: '/cart' const unreadLabel = computed(() => {
}); return unreadMsg.value > 99 ? '99+' : String(unreadMsg.value);
window.open(url.href, '_blank'); });
},
myInfo () { // 跳转会员中心 if (storage.getItem('userInfo')) {
let url = this.$router.resolve({ userInfo.value = JSON.parse(storage.getItem('userInfo'));
path: '/home' refreshUnreadMessage();
}); }
window.open(url.href, '_blank');
}, function goToPay() {
signOutFun () { // 退出登录 if (!userInfo.value.username) {
storage.removeItem('accessToken'); Modal.confirm({
storage.removeItem('refreshToken'); title: '温馨提示',
storage.removeItem('userInfo'); content: '请登录后执行此操作',
storage.removeItem('cartNum'); okText: '立即登录',
this.$store.commit('SET_CARTNUM', 0) cancelText: '取消',
this.$router.push('/login'); onOk: () => {
}, router.push({
goUserCenter (path) { path: '/login',
// 跳转我的订单,我的足迹、收藏等 query: {
if (this.userInfo.username) { rePath: '/cart',
this.$router.push({ path: path }); query: JSON.stringify(route.query || {}),
} else { },
this.$Modal.confirm({
title: '请登录',
content: '<p>请登录后执行此操作</p>',
okText: '立即登录',
cancelText: '继续浏览',
onOk: () => {
this.$router.push({
path: '/login',
query: {
rePath: this.$router.history.current.path,
query: JSON.stringify(this.$router.history.current.query)
}
});
}
}); });
} },
}, });
shopEntry () { return;
// 店铺入驻
if (storage.getItem('accessToken')) {
let routeUrl = this.$router.resolve({
path: '/shopEntry',
query: { id: 1 }
});
window.open(routeUrl.href, '_blank');
} else {
this.$router.push('login');
}
},
getCartList () {
// 获取购物车列表
if (this.userInfo.username) {
cartGoodsAll().then((res) => {
this.shoppingCart = res.result.skuList;
this.$store.commit('SET_CARTNUM', this.shoppingCart.length);
this.Cookies.setItem('cartNum', this.shoppingCart.length);
});
}
}
} }
}; router.push('/cart');
}
function myInfo() { // 跳转会员中心
router.push('/home');
}
function signOutFun() { // 退出登录
logout().then(res => {
storage.removeItem('accessToken');
storage.removeItem('refreshToken');
storage.removeItem('userInfo');
storage.removeItem('cartNum');
appStore.setCartNum(0)
appStore.setUnreadMsg(0)
router.push('/login');
});
}
function goUserCenter(path) {
// 跳转我的订单,我的足迹、收藏等
if (userInfo.value.username) {
router.push({path: path});
} else {
Modal.confirm({
title: '请登录',
content: '请登录后执行此操作',
okText: '立即登录',
cancelText: '继续浏览',
onOk: () => {
router.push({
path: '/login',
query: {
rePath: route.path,
query: JSON.stringify(route.query || {}),
},
});
}
});
}
}
function shopEntry() {
if (storage.getItem('accessToken')) {
router.push({
path: '/shopEntry',
query: { id: 1 },
});
return;
}
Modal.confirm({
title: '温馨提示',
content: '请登录后执行此操作',
okText: '立即登录',
cancelText: '取消',
onOk: () => {
router.push({
path: '/login',
query: {
rePath: '/shopEntry',
query: JSON.stringify({ id: 1 }),
},
});
},
});
}
function handleCartDropdownVisible(visible) {
if (visible) {
getCartList();
}
}
function getCartList() {
// 获取购物车列表
if (!userInfo.value.username || cartLoading.value) {
return;
}
const now = Date.now();
if (cartLoadedAt.value && now - cartLoadedAt.value < cartCacheTime.value) {
return;
}
cartLoadedAt.value = now;
cartLoading.value = true;
cartGoodsAll().then((res) => {
if (res.success) {
shoppingCart.value = (res.result && res.result.skuList) || [];
appStore.setCartNum(shoppingCart.value.length);
storage.setItem('cartNum', shoppingCart.value.length);
}
}).finally(() => {
cartLoading.value = false;
});
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.shopping-cart-detail,
.shopping-cart-text,
.shopping-cart-info,
.nav a,
.location,
.first,
.username,
.shopping-cart-null span {
}
.box { .box {
width: 100%; width: 100%;
font-size: 12px!important; font-size: 12px;
// height: 35px; height: 40px;
@include background_color($light_white_background_color); background: #f8fafc;
border-bottom: 1px solid #e2e8f0;
color: #64748b;
display: flex;
align-items: center;
} }
.nav { .nav {
margin: 0 auto;
width: 1200px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center;
justify-content: space-between; justify-content: space-between;
height: 100%;
} }
.nav ul {
.nav > ul {
list-style: none; list-style: none;
margin: 0;
padding: 0;
display: flex;
align-items: center;
} }
.nav li {
float: left; .nav > ul > li,
font-size: 12px; .location > ul.flex > li {
line-height: 35px; cursor: pointer;
margin-right: 10px; float: none;
font-weight: bold; line-height: 40px;
margin-right: 15px;
display: flex;
align-items: center;
} }
.nav a, .nav a,
.nav-item { .nav-item {
font-size: 12px;
font-weight: normal;
text-decoration: none; text-decoration: none;
padding-left: 14px;
border-left: 1px solid #ccc;
color: #999;
cursor: pointer; cursor: pointer;
color: #64748b;
display: inline-flex;
align-items: center;
line-height: 1;
transition: color 0.15s ease;
&:hover {
color: #409EFF;
}
} }
.nav-item {
padding-left: 20px;
gap: 4px;
}
.msg-badge {
min-width: 16px;
height: 16px;
padding: 0 4px;
border-radius: 8px;
background: $theme_color;
color: #fff;
font-size: 12px;
font-style: normal;
line-height: 16px;
text-align: center;
}
.cart-nav-item {
:deep(.cart-nav-dropdown),
:deep(.el-dropdown) {
display: inline-flex;
align-items: center;
margin: 0;
padding: 0;
vertical-align: middle;
line-height: 40px;
}
:deep(.el-tooltip__trigger),
:deep(.el-dropdown-selfdefine),
:deep([aria-expanded="true"]) {
outline: none !important;
border: none !important;
box-shadow: none !important;
}
}
.location a { .location a {
border-left: none; border-left: none;
} }
.nav a:hover {
color: $theme_color;
}
.icon { .icon {
color: gray; color: gray;
vertical-align: middle; vertical-align: middle;
} }
.first a:first-child {
padding-left: 3px;
border-left: none;
}
.city { .city {
padding: 10px 15px; padding: 10px 15px;
} }
.city-item { .city-item {
font-weight: bold; font-weight: bold;
cursor: pointer; cursor: pointer;
padding: 5px; padding: 5px;
} }
.city-item:hover { .city-item:hover {
color: $theme_color; color: $theme_color;
} }
.person-icon { .person-icon {
color: $theme_color; color: $theme_color;
background-color: #f0cdb2; background-color: #f0cdb2;
} }
.shopping-cart-list {
padding: 10px 15px;
box-sizing: border-box;
max-height: 300px;
overflow: scroll;
}
.shopping-cart-box {
margin: 8px 0px;
margin-top: 15px;
padding-bottom: 15px;
height: 40px;
display: flex;
align-items: center;
border-bottom: 1px #ccc dotted;
}
.shopping-cart-box:first-child {
margin-top: 8px;
}
.shopping-cart-img {
margin-right: 15px;
width: 40px;
height: 40px;
}
.shopping-cart-img img {
width: 100%;
}
.shopping-cart-info {
display: flex;
flex-direction: column;
justify-content: space-between;
align-content: space-between;
width: 200px;
overflow: hidden;
font-size: 12px;
line-height: 20px;
}
.go-to-buy {
display: flex;
justify-content: flex-end;
}
.shopping-cart-null { .shopping-cart-null {
padding: 15px; width: 320px;
padding: 28px 16px;
box-sizing: border-box;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.cart-null-icon { .cart-null-icon {
font-size: 38px; font-size: 36px;
margin-bottom: 15px; margin-bottom: 12px;
color: #ccc;
} }
.shopping-cart-null span { .shopping-cart-null span {
font-size: 12px; font-size: 13px;
line-height: 16px; line-height: 1.6;
color: #999;
} }
.shopping-cart-list {
width: 320px;
max-height: 320px;
overflow-y: auto;
padding: 4px 0;
box-sizing: border-box;
color: #333;
}
.shopping-cart-box {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 12px 16px;
cursor: pointer;
&:hover {
background: #fafafa;
}
& + .shopping-cart-box {
border-top: 1px solid #f2f2f2;
}
}
.shopping-cart-img {
width: 64px;
height: 64px;
flex-shrink: 0;
border-radius: 6px;
overflow: hidden;
background: #f5f5f5;
img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
}
.shopping-cart-info {
flex: 1;
min-width: 0;
min-height: 64px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.shopping-cart-info .goods-title {
margin: 0;
font-size: 13px;
line-height: 1.4;
color: #333;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
white-space: normal;
}
.shopping-cart-detail {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 8px;
color: #999;
font-size: 14px;
}
.shopping-price {
color: $theme_color;
font-size: 14px;
font-weight: 600;
}
.username-p { .username-p {
position: relative; position: relative;
div{ z-index: 100;
div {
cursor: pointer; cursor: pointer;
>span{ display: flex;
align-items: center;
> span {
margin-left: 5px; margin-left: 5px;
} }
} }
.drop-items { .drop-items {
position: absolute; position: absolute;
display: none; display: none;
top: 45px; flex-direction: column;
left: 0; top: calc(100% + 10px);
right: 0; left: 50%;
margin: 0 auto; transform: translateX(-50%);
padding: 5px 10px; margin: 0;
z-index: 20; padding: 4px 0;
height: 150px; z-index: 1000;
min-width: 100px;
width: max-content;
background-color: #fff; background-color: #fff;
width: 80px;
border: 1px solid #eee; border: 1px solid #eee;
box-shadow: 2px 2px 7px #999; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
list-style: none;
li { li {
color: rgb(107, 106, 106); display: block;
float: none;
width: 100%; width: 100%;
border-bottom:1px solid rgb(207, 206, 206); margin: 0;
padding: 8px 16px;
line-height: 1.4;
color: #666;
font-size: 14px;
font-weight: normal; font-weight: normal;
text-align: center; text-align: center;
&:last-child{ white-space: nowrap;
border: none; border-bottom: 1px solid #f0f0f0;
box-sizing: border-box;
&:last-child {
border-bottom: none;
} }
&:hover{
&:hover {
cursor: pointer; cursor: pointer;
color: $theme_color; color: $theme_color;
background-color: #fff7f7;
} }
} }
&::before{ &::before {
position: absolute; position: absolute;
top: -20px; top: -6px;
left: 30px; left: 50%;
transform: translateX(-50%);
content: ''; content: '';
width: 0; width: 0;
height: 0; height: 0;
border: 10px solid #999; border: 6px solid transparent;
border-color: transparent transparent #fff transparent ; border-bottom-color: #fff;
} }
&::after{ &::after {
content: ''; content: '';
position: absolute; position: absolute;
width: 80px; width: 100%;
height: 20px; height: 10px;
top: -20px; top: -10px;
left: 0; left: 0;
} }
} }
&:hover{
.drop-items{ &:hover {
display: block; .drop-items {
display: flex;
} }
} }
} }
@@ -379,11 +558,13 @@ export default {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.my-page a { .my-page a {
margin: 0px; margin: 0px;
padding: 0px; padding: 0px;
border: none; border: none;
} }
.my-info { .my-info {
padding: 5px; padding: 5px;
width: 50%; width: 50%;
@@ -391,15 +572,19 @@ export default {
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
} }
.my-info:hover { .my-info:hover {
box-shadow: 0px 0px 5px #ccc; box-shadow: 0px 0px 5px #ccc;
} }
.my-info i { .my-info i {
font-size: 28px; font-size: 28px;
} }
.my-info p { .my-info p {
font-size: 12px; font-size: 14px;
} }
.sign-out { .sign-out {
padding: 5px; padding: 5px;
width: 50%; width: 50%;
@@ -407,18 +592,23 @@ export default {
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
} }
.sign-out:hover { .sign-out:hover {
box-shadow: 0px 0px 5px $border_color; box-shadow: 0px 0px 5px $border_color;
} }
.sign-out i { .sign-out i {
font-size: 28px; font-size: 28px;
} }
.sign-out p { .sign-out p {
font-size: 12px; font-size: 14px;
} }
.goods-title:hover { .goods-title:hover {
color: $theme_color; color: $theme_color;
} }
.cart-badge { .cart-badge {
position: absolute; position: absolute;
right: -8px; right: -8px;

View File

@@ -1,62 +0,0 @@
<template>
<div class="shop-box">
<div class="shop-container">
<div class="shop-title-content">
<img class="hover-pointer" @click="linkTo(`/merchant?id=${storeDetail.storeId}`)" :src="storeDetail.storeLogo" height="40" alt="">
<p><router-link :to="`/merchant?id=${storeDetail.storeId}`">{{ storeDetail.storeName }}</router-link></p>
<div class="ml_20" v-html="storeDetail.storeDesc"></div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'ShopHeader',
props: {
detail: {
type: Object,
default: null
}
},
computed: {
storeDetail () { // 店铺详情
return this.detail;
}
}
};
</script>
<style scoped>
/* 店铺介绍 */
.shop-box {
width: 100%;
height: 50px;
background-color: #484848;
}
.shop-container {
width: 1200px;
height: 100%;
margin: 0px auto;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
color: #fff;
}
.shop-title-content {
display: flex;
align-items: center;
}
.shop-title-content p {
font-size: 20px;
margin-left: 20px;
}
.shop-title-content a {
color: #fff;
}
</style>

View File

@@ -1,93 +1,251 @@
<template> <template>
<div class="scroll-show"> <div class="scroll-show">
<div class="content clearfix"> <div class="content">
<cateNav class="cate" :hover="true" :showNavBar="false"></cateNav> <!-- 1. 左侧区域:商城 Logo -->
<Search class="search-con" :hover="true" :showLogo="false" :showTag="false"></Search> <div class="left-section">
<Icon type="ios-cart-outline" @click="goCartList" class="cart-icon" @mouseenter.native="getCartList" /> <router-link to="/" class="logo-link">
<i class="cart-badge">{{cartNum < 100 ? cartNum : '99'}}</i> <img v-if="logoSrc" :src="logoSrc" alt="Logo" class="site-logo" />
<span v-else class="text-logo">LiliShop</span>
</router-link>
</div>
<!-- 2. 中间搜索区域:与 SearchHeader 样式完全一致(蓝底色、圆角4px、搜索按钮) -->
<div class="search-main">
<div class="search-box">
<input
v-model="keyword"
type="text"
class="search-input"
:placeholder="placeholderText"
@keyup.enter="handleSearch"
/>
<button type="button" class="search-btn" @click="handleSearch">
<el-icon><Search /></el-icon>
<span>搜索</span>
</button>
</div>
</div>
<!-- 3. 右侧“我的购物车”胶囊入口:与 SearchHeader 样式完全一致 -->
<div class="cart-entry">
<router-link to="/cart" class="cart-btn" @mouseenter="getCartList">
<el-icon class="cart-icon"><ShoppingCart /></el-icon>
<span class="cart-text">{{ options.cartText || '我的购物车' }}</span>
<span class="cart-count">{{ Number(cartNum) > 99 ? '99+' : cartNum }}</span>
</router-link>
</div>
</div> </div>
</div> </div>
</template> </template>
<script>
import {cartCount} from '@/api/cart.js' <script setup>
import { computed, onMounted, ref, watch } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { cartCount } from '@/api/cart.js';
import storage from '@/plugins/storage.js'; import storage from '@/plugins/storage.js';
export default { import { ShoppingCart, Search } from '@element-plus/icons-vue';
data () { import { useAppStore } from '@/stores/app';
return {
userInfo: {} // 用户信息 const props = defineProps({
options: {
type: Object,
default: () => ({})
}
});
const router = useRouter();
const route = useRoute();
const appStore = useAppStore();
const keyword = ref(route.query.keyword || '');
const cartNum = computed(() => appStore.cartNum || 0);
watch(() => route.query.keyword, (v) => {
keyword.value = v || '';
});
const logoSrc = computed(() => {
return props.options?.logoUrl || appStore.logoImg || '';
});
const placeholderText = computed(() => {
const ph = props.options?.placeholder;
if (!ph || ph === '搜索品牌或商品' || ph === '请输入商品名称、品牌或型号') {
return '请输入商品名称';
}
return ph;
});
function handleSearch() {
const kw = (keyword.value || '').trim();
if (route.path === '/goodsList') {
const nextQuery = { ...route.query };
if (kw) {
nextQuery.keyword = kw;
} else {
delete nextQuery.keyword;
} }
}, router.push({ path: '/goodsList', query: nextQuery });
computed: { } else {
cartNum () { // 购物车商品数量 router.push({ path: '/goodsList', query: kw ? { keyword: kw } : {} });
return this.$store.state.cartNum }
}
function getCartList() {
if (storage.getItem('userInfo')) {
cartCount().then((res) => {
appStore.setCartNum(res.result);
storage.setItem('cartNum', res.result);
});
}
}
onMounted(() => {
getCartList();
});
</script>
<style lang="scss" scoped>
.scroll-show {
height: 60px;
width: 100%;
background: #ffffff;
}
.content {
width: 1200px;
max-width: 100%;
height: 60px;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
padding: 0 10px;
}
.left-section {
display: flex;
align-items: center;
flex-shrink: 0;
.logo-link {
display: flex;
align-items: center;
text-decoration: none;
height: 40px;
.site-logo {
max-height: 36px;
max-width: 160px;
object-fit: contain;
display: block;
} }
},
methods: { .text-logo {
goCartList () { // 跳转购物车页面 font-size: 22px;
let routerUrl = this.$router.resolve({ font-weight: 800;
path: '/cart' color: #409EFF;
}) letter-spacing: -0.5px;
window.open(routerUrl.href, '_blank') line-height: 1;
},
getCartList () { // 获取购物车列表
if (storage.getItem('userInfo')) {
cartCount().then(res => {
this.$store.commit('SET_CARTNUM', res.result)
this.Cookies.setItem('cartNum', res.result)
})
}
}
},
mounted () {
if (storage.getItem('userInfo')) {
this.userInfo = JSON.parse(storage.getItem('userInfo'));
} }
} }
} }
</script>
<style lang="scss" scoped> .search-main {
.content{ width: 560px;
width: 1200px; flex-shrink: 0;
height: 40px;
margin: 10px auto; .search-box {
position: relative; display: flex;
} border: 2px solid #409EFF;
.cate { border-radius: 4px;
float: left;
width: 200px!important;
}
.search-con{
float: left;
width: 800px;
overflow: hidden; overflow: hidden;
margin-top: -27px; height: 38px;
} box-sizing: border-box;
.cart-icon { background: #ffffff;
width: 30px;
float: left; .search-input {
font-size: 25px; flex: 1;
margin-top: 8px; min-width: 0;
color: $theme_color; border: none;
z-index: 1; padding: 0 14px;
position: relative; font-size: 13px;
&:hover{ color: #334155;
outline: none;
background: #ffffff;
&::placeholder {
color: #94a3b8;
}
}
.search-btn {
background: #409EFF;
color: #ffffff;
border: none;
padding: 0 22px;
display: flex;
align-items: center;
gap: 4px;
font-size: 14px;
font-weight: 600;
cursor: pointer; cursor: pointer;
transition: background 0.15s;
flex-shrink: 0;
&:hover {
background: #66b1ff;
}
} }
} }
.cart-badge { }
position: absolute;
font-style: normal; .cart-entry {
right: 165px; flex-shrink: 0;
display: block;
background-color: $theme_color; .cart-btn {
color: #fff; height: 38px;
font-size: 12px; display: flex;
width: 17px; align-items: center;
height: 17px; gap: 8px;
border-radius: 10px; padding: 0 16px;
line-height: 17px; border: 1px solid #e2e8f0;
text-align: center; border-radius: 4px;
z-index: 5; font-size: 13px;
top: 3px; color: #334155;
background: #ffffff;
text-decoration: none;
cursor: pointer;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.02);
transition: all 0.15s ease;
box-sizing: border-box;
.cart-icon {
font-size: 16px;
color: #409EFF;
}
.cart-text {
font-weight: 500;
white-space: nowrap;
}
.cart-count {
background: #409EFF;
color: #ffffff;
font-size: 11px;
font-weight: 700;
padding: 0 6px;
height: 18px;
line-height: 18px;
border-radius: 9px;
}
&:hover {
border-color: #409EFF;
color: #409EFF;
}
} }
}
</style> </style>

View File

@@ -1,31 +1,82 @@
<template> <template>
<div class="model-form"> <div class="model-form" :style="pageContainerStyle">
<div class="model-content"> <!-- Version 2: 新万米行模型渲染 -->
<template v-for="(element, index) in data.list"> <div v-if="isVersion2" class="v2-rows-container">
<model-form-item <row-wrapper
v-if="element && element.key" v-for="row in v2Rows"
:key="element.key" :key="row.id"
:element="element" :row="row"
:index="index" />
:data="data" </div>
></model-form-item>
</template> <!-- 旧版降级渲染 -->
<div v-else class="model-content">
<model-form-item
v-for="(element, index) in renderList"
:key="element.key"
:element="element"
:index="index"
:data="data"
></model-form-item>
</div> </div>
</div> </div>
</template> </template>
<script>
<script setup>
import { computed } from 'vue';
import ModelFormItem from './ModelFormItem.vue'; import ModelFormItem from './ModelFormItem.vue';
export default { import RowWrapper from './RowWrapper.vue';
name: 'modelForm',
components: { defineOptions({ name: 'modelForm' });
ModelFormItem
}, const props = defineProps(['data']);
props: ['data']
}; // 是否为 v2 行模型数据
const isVersion2 = computed(() => {
return (props.data?.version === 2 || props.data?.version === '2.0') && Array.isArray(props.data?.list);
});
const v2Rows = computed(() => {
return props.data?.list || [];
});
const pageContainerStyle = computed(() => {
if (isVersion2.value && props.data?.pageStyle?.backgroundColor) {
return {
backgroundColor: props.data.pageStyle.backgroundColor
};
}
return {};
});
const renderList = computed(() => {
const list = props.data?.list || [];
return list.filter(
(el) => el && el.key && !isBuiltinModule(el.type)
);
});
function isBuiltinModule(type) {
return type === 'topAdvert' || type === 'navBar';
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.model-form {
position: relative;
z-index: 0;
width: 100%;
}
.v2-rows-container {
width: 100%;
min-height: 400px;
}
.model-content { .model-content {
width: 100%; width: 100%;
min-height: 1200px; min-height: 1200px;
box-sizing: border-box;
overflow-x: visible;
} }
</style> </style>

View File

@@ -2,69 +2,81 @@
<div class="model-item" v-if="element && element.key"> <div class="model-item" v-if="element && element.key">
<!-- 轮播图模块,包括个人信息,快捷导航模块 --> <!-- 轮播图模块,包括个人信息,快捷导航模块 -->
<template v-if="element.type == 'carousel'"> <template v-if="element.type == 'carousel'">
<model-carousel :data="element" class="mb_20 width_1200_auto"></model-carousel> <div class="carousel-wrap mb_20">
<model-carousel :key="element.key" :data="element"></model-carousel>
</div>
</template> </template>
<template v-if="element.type == 'carousel1'"> <template v-if="element.type == 'carousel1'">
<model-carousel1 :data="element" class="mb_20"></model-carousel1> <model-carousel1 :data="element" class="mb_20"></model-carousel1>
</template> </template>
<template v-if="element.type == 'carousel2'"> <template v-if="element.type == 'carousel2'">
<model-carousel2 :data="element" class="mb_20 width_1200_auto"></model-carousel2> <model-carousel2
:data="element"
class="mb_20 width_1200_auto"
></model-carousel2>
</template> </template>
<!-- 热门广告 --> <!-- 热门广告 -->
<template v-if="element.type == 'hotAdvert'"> <template v-if="element.type == 'hotAdvert'">
<div class="mb_20 width_1200_auto"> <div class="hot-advert mb_20 width_1200_auto">
<img <div class="hot-advert-banner">
style="display: block" <img
class="hover-pointer"
:src="element.options.list[0].img"
@click="linkTo(element.options.list[0].url)"
width="1200"
alt=""
/>
</div>
<ul class="advert-list width_1200_auto">
<template v-for="(item, index) in element.options.list">
<li
v-if="index !== 0"
@click="linkTo(item.url)"
class="hover-pointer" class="hover-pointer"
:key="index" :src="element.options.list[0].img"
> @click="linkTo(element.options.list[0].url)"
<img :src="item.img" width="230" height="190" alt="" /> alt=""
</li> />
</template> </div>
</ul> <ul class="advert-list">
<template v-for="(item, index) in element.options.list" :key="index">
<li
v-if="index !== 0"
@click="linkTo(item.url)"
class="hover-pointer"
>
<img :src="item.img" alt="" />
</li>
</template>
</ul>
</div>
</template> </template>
<!-- 限时秒杀 待完善 --> <!-- 限时秒杀 待完善 -->
<template v-if="element.type == 'seckill' && element.options.list.length"> <template v-if="element.type == 'seckill' && element.options?.list?.length">
<seckill :data="element" class="mb_20 width_1200_auto"></seckill> <seckill :data="element" class="mb_20 width_1200_auto"></seckill>
</template> </template>
<!-- 折扣广告 --> <!-- 折扣广告 -->
<template v-if="element.type == 'discountAdvert'"> <template v-if="element.type == 'discountAdvert'">
<div <div class="discountAdvert-wrap width_1200_auto mb_20">
class="discountAdvert" <div
:style="{'backgroundImage' :'url(' + require('@/assets/images/decorate.png') + ')'}" class="discountAdvert"
> :style="{
<img backgroundImage: 'url(' + decorateImg + ')',
@click="linkTo(item.url)" }"
class="hover-pointer" >
v-for="(item, index) in element.options.classification" <div>
:key="index" <img
:src="item.img" @click="linkTo(item.url)"
width="190" class="hover-pointer"
height="210" v-for="(item, index) in element.options.classification"
alt="" :key="index"
/> :src="item.img"
<img width="190"
@click="linkTo(item.url)" height="210"
class="hover-pointer" alt=""
v-for="(item, index) in element.options.brandList" />
:key="'discount' + index" </div>
:src="item.img" <div>
width="240" <img
height="105" @click="linkTo(item.url)"
alt="" class="hover-pointer"
/> v-for="(item, index) in element.options.brandList"
:key="'discount' + index"
:src="item.img"
width="240"
height="105"
alt=""
/>
</div>
</div>
</div> </div>
</template> </template>
@@ -72,76 +84,148 @@
<template v-if="element.type == 'recommend'"> <template v-if="element.type == 'recommend'">
<recommend :data="element" class="mb_20 width_1200_auto"></recommend> <recommend :data="element" class="mb_20 width_1200_auto"></recommend>
</template> </template>
<!-- 一行三列 -->
<template v-if="element.type == 'oneRowThreeColumns'">
<oneRowThreeColumns :data="element" class="mb_20 width_1200_auto"></oneRowThreeColumns>
</template>
<!-- 商品模块 -->
<template v-if="element.type == 'goodsType'">
<goodsAndType :paramData="element" class="mb_20 width_1200_auto"></goodsAndType>
</template>
<!-- 商品模块 -->
<template v-if="element.type == 'onlyGoodsModel'">
<onlyGoodsModel :data="element" class="mb_20 width_1200_auto"></onlyGoodsModel>
</template>
<!-- 混合模块 -->
<template v-if="element.type == 'mixModel'">
<mixModel :data="element" class="mb_20 width_1200_auto"></mixModel>
</template>
<!-- 混合模块 -->
<template v-if="element.type == 'forYour'">
<forYour :data="element" class="mb_20 width_1200_auto"></forYour>
</template>
<!-- 新品排行 --> <!-- 新品排行 -->
<template v-if="element.type == 'newGoodsSort'"> <template v-if="element.type == 'newGoodsSort'">
<new-goods-sort :data="element" class="mb_20 width_1200_auto"></new-goods-sort> <new-goods-sort
:data="element"
class="mb_20 width_1200_auto"
></new-goods-sort>
</template> </template>
<!-- 首页广告 --> <!-- 首页广告 -->
<template v-if="element.type == 'firstAdvert'"> <template v-if="element.type == 'firstAdvert'">
<first-page-advert :data="element" class="mb_20 width_1200_auto"></first-page-advert> <first-page-advert
:data="element"
class="mb_20 width_1200_auto"
></first-page-advert>
</template> </template>
<!-- 横幅广告 --> <!-- 横幅广告 -->
<template v-if="element.type == 'bannerAdvert'"> <template v-if="element.type == 'bannerAdvert' && element.options.img">
<img <div
width="1200" class="horizontal-advert width_1200_auto mb_20 hover-pointer"
class="hover-pointer mb_20"
@click="linkTo(element.options.url)" @click="linkTo(element.options.url)"
:src="element.options.img" >
alt="" <img class="bannerAd" :src="element.options.img" alt="" />
/> </div>
</template> </template>
<template v-if="element.type == 'notEnough'"> <template v-if="element.type == 'notEnough'"
<not-enough :data="element" class="mb_20 width_1200_auto"></not-enough> >
<not-enough
:data="element"
class="mb_20 width_1200_auto"
></not-enough>
</template> </template>
</div> </div>
</template> </template>
<script> <script setup>
import ModelCarousel from './modelList/Carousel.vue'; import { ref } from "vue";
import ModelCarousel1 from './modelList/Carousel1.vue'; import ModelCarousel from "./modelList/Carousel.vue";
import ModelCarousel2 from './modelList/Carousel2.vue'; import ModelCarousel1 from "./modelList/Carousel1.vue";
import FirstPageAdvert from './modelList/FirstPageAdvert.vue'; import ModelCarousel2 from "./modelList/Carousel2.vue";
import NewGoodsSort from './modelList/NewGoodsSort.vue'; import FirstPageAdvert from "./modelList/FirstPageAdvert.vue";
import Recommend from './modelList/Recommend.vue'; import NewGoodsSort from "./modelList/NewGoodsSort.vue";
import NotEnough from './modelList/NotEnough.vue'; import Recommend from "./modelList/Recommend.vue";
import Seckill from './modelList/Seckill.vue'; import NotEnough from "./modelList/NotEnough.vue";
import Seckill from "./modelList/Seckill.vue";
import oneRowThreeColumns from "./modelList/oneRowThreeColumns.vue";
import goodsAndType from "./modelList/goodsAndType.vue";
import onlyGoodsModel from "./modelList/onlyGoodsModel.vue";
import mixModel from "./modelList/mixModel.vue";
import forYour from "./modelList/forYour.vue";
import decorateImgUrl from "@/assets/images/decorate.png";
export default { defineOptions({ name: "modelFormItem" });
name: 'modelFormItem',
props: ['element', 'select', 'index', 'data'], defineProps(["element", "select", "index", "data"]);
components: {
ModelCarousel, const decorateImg = ref(decorateImgUrl);
ModelCarousel1, const showModal = ref(false); // 控制模态框显隐
ModelCarousel2, const selected = ref({}); // 已选数据
Recommend,
NewGoodsSort,
FirstPageAdvert,
NotEnough,
Seckill
},
data () {
return {
showModal: false, // 控制模态框显隐
selected: {} // 已选数据
};
}
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.model-item { .model-item {
position: relative; position: relative;
margin-bottom: 10px;
width: 100%;
box-sizing: border-box;
}
.carousel-wrap {
width: 100%;
max-width: 1200px;
margin: 0 auto;
box-sizing: border-box;
overflow: hidden;
}
/** 横幅广告 */
.horizontal-advert {
width: 100%;
max-width: 1200px;
overflow: hidden;
border-radius: 10px;
line-height: 0;
}
.bannerAd {
display: block;
width: 100%;
height: auto;
max-height: 166px;
object-fit: cover;
} }
/** 热门广告 */ /** 热门广告 */
.advert-list { .hot-advert {
background: $theme_color; width: 1200px;
height: 200px; max-width: 100%;
display: flex; overflow: hidden;
justify-content: space-around;
padding: 3px 10px; .hot-advert-banner {
> li { line-height: 0;
img { img {
display: block;
width: 100%;
height: auto;
}
}
}
.advert-list {
width: 100%;
margin: 0;
padding: 10px;
list-style: none;
box-sizing: border-box;
background: $theme_color;
height: 210px;
display: flex;
gap: 10px;
align-items: center;
> li {
flex: 1 1 0;
min-width: 0;
img {
display: block;
width: 100%;
height: 190px;
cursor: pointer; cursor: pointer;
border-radius: 10px; border-radius: 10px;
transition: all 150ms ease-in-out; transition: all 150ms ease-in-out;
@@ -154,32 +238,45 @@ export default {
} }
/** 折扣广告 */ /** 折扣广告 */
.discountAdvert-wrap {
width: 1200px;
position: relative;
overflow: visible;
}
.discountAdvert { .discountAdvert {
width: 1300px; width: 1300px;
height: 566px; height: 585px;
margin: 0 auto; margin-left: -100px;
margin-bottom: 20px; box-sizing: border-box;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 1300px 585px;
background-position: left top;
position: relative; position: relative;
left: -47px; > div {
padding-left: 295px; padding-left: 295px;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: flex-start; box-sizing: border-box;
img { &:nth-child(1) img {
margin-top: 10px; margin: 10px 10px 0 0;
margin-right: 10px; transition: all 150ms ease-in-out;
transition: all 150ms ease-in-out; &:hover {
&:hover { box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.4);
box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.4); transform: translateY(-2px);
transform: translateY(-2px); }
}
&:nth-child(2) {
margin-top: 10px;
img {
margin: 0 10px 0 0;
transition: all 150ms ease-in-out;
&:hover {
box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.4);
transform: translateY(-2px);
}
}
} }
} }
} }
.width_1200_auto{
width: 1200px;
margin: 0 auto;
background-color: #fff;
}
</style> </style>

View File

@@ -0,0 +1,368 @@
<template>
<div class="row-wrapper" :style="rowWrapperStyle">
<div class="row-inner-flex" :style="rowInnerFlexStyle">
<div
v-for="comp in row.components"
:key="comp.id"
class="component-cell"
:style="getComponentCellStyle(comp.componentStyle, row.rowStyle, row.components ? row.components.length : 1)"
>
<component
:is="resolveComponent(comp.type)"
v-if="resolveComponent(comp.type)"
:component="comp"
:options="comp.options || {}"
:component-style="comp.componentStyle || {}"
:row-style="row.rowStyle || {}"
/>
<div v-else class="unknown-component-placeholder">
未知组件: {{ comp.type }}
</div>
</div>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue';
import { resolveComponent } from './registry.js';
const props = defineProps({
row: {
type: Object,
required: true
}
});
const rowWrapperStyle = computed(() => {
const s = props.row.rowStyle || {};
const style = {};
// 宽度 (width)
if (s.width !== undefined && s.width !== '') {
const w = String(s.width).trim();
if (w && w !== '100%') {
const num = parseInt(w, 10);
if (!isNaN(num) && num >= 1920 && !w.endsWith('%')) {
style.width = '100%';
} else {
style.width = /^\d+$/.test(w) ? `${w}px` : w;
style.maxWidth = '100%';
}
} else {
style.width = '100%';
}
} else {
style.width = '100%';
}
// 高度 (height)
if (s.height !== undefined && s.height !== '') {
const h = String(s.height).trim();
if (h && Number(h) > 0) {
const hVal = /^\d+$/.test(h) ? `${h}px` : h;
style.height = hVal;
style.minHeight = hVal;
}
}
// 外边距 (margin)
const isNarrow = style.width !== '100%';
if (Array.isArray(s.margin)) {
style.marginTop = `${s.margin[0] || 0}px`;
style.marginRight = s.margin[1] ? `${s.margin[1]}px` : (isNarrow ? 'auto' : '0px');
style.marginBottom = `${s.margin[2] || 0}px`;
style.marginLeft = s.margin[3] ? `${s.margin[3]}px` : (isNarrow ? 'auto' : '0px');
} else if (isNarrow) {
style.marginLeft = 'auto';
style.marginRight = 'auto';
}
// 内边距 (padding)
if (Array.isArray(s.padding)) {
style.paddingTop = `${s.padding[0] || 0}px`;
style.paddingRight = `${s.padding[1] || 0}px`;
style.paddingBottom = `${s.padding[2] || 0}px`;
style.paddingLeft = `${s.padding[3] || 0}px`;
}
// 圆角 (radius)
if (Array.isArray(s.radius)) {
style.borderTopLeftRadius = `${s.radius[0] || 0}px`;
style.borderTopRightRadius = `${s.radius[1] || 0}px`;
style.borderBottomRightRadius = `${s.radius[2] || 0}px`;
style.borderBottomLeftRadius = `${s.radius[3] || 0}px`;
}
// 行背景由各组件配置统一管理
return style;
});
const rowInnerFlexStyle = computed(() => {
const s = props.row.rowStyle || {};
const styleObj = {
display: 'flex',
flexDirection: 'row',
flexWrap: 'nowrap',
alignItems: s.alignItems || 'stretch',
justifyContent: s.justifyContent || 'flex-start',
width: '100%',
height: '100%',
gap: `${s.gap || 0}px`
};
if (s.height !== undefined && s.height !== '') {
const h = String(s.height).trim();
if (h && Number(h) > 0) {
const hVal = /^\d+$/.test(h) ? `${h}px` : h;
styleObj.height = hVal;
styleObj.minHeight = hVal;
}
}
return styleObj;
});
function getComponentCellStyle(style, rowStyle = {}, totalComps = 1) {
if (!style) return { flex: '1 1 0%' };
const s = {};
if (rowStyle?.height !== undefined && rowStyle?.height !== '') {
const rh = String(rowStyle.height).trim();
if (rh && Number(rh) > 0) {
const rhVal = /^\d+$/.test(rh) ? `${rh}px` : rh;
s.height = rhVal;
s.minHeight = rhVal;
}
}
const gap = Number(rowStyle?.gap) || 0;
const totalGap = (totalComps > 1 && gap > 0) ? gap * (totalComps - 1) : 0;
if (style.widthRatio && style.widthRatio !== 'auto') {
let w = style.widthRatio;
if (w === '16.67%' || w === '16.6%' || w === '16.7%') {
w = totalGap > 0 ? `calc((100% - ${totalGap}px) / 6)` : 'calc(100% / 6)';
} else if (w === '66.67%' || w === '66.6%' || w === '66.7%') {
w = totalGap > 0 ? `calc((100% - ${totalGap}px) * 2 / 3)` : 'calc(100% * 2 / 3)';
} else if (w === '33.33%' || w === '33.3%') {
w = totalGap > 0 ? `calc((100% - ${totalGap}px) / 3)` : 'calc(100% / 3)';
} else if (w === '50%') {
w = totalGap > 0 ? `calc((100% - ${totalGap}px) / 2)` : '50%';
}
s.flex = `0 0 ${w}`;
s.width = w;
s.maxWidth = w;
s.minWidth = '0';
} else {
s.flex = '1 1 0%';
s.minWidth = '0';
}
if (Array.isArray(style.padding)) {
s.paddingTop = `${style.padding[0] || 0}px`;
s.paddingRight = `${style.padding[1] || 0}px`;
s.paddingBottom = `${style.padding[2] || 0}px`;
s.paddingLeft = `${style.padding[3] || 0}px`;
}
if (Array.isArray(style.radius)) {
s.borderTopLeftRadius = `${style.radius[0] || 0}px`;
s.borderTopRightRadius = `${style.radius[1] || 0}px`;
s.borderBottomRightRadius = `${style.radius[2] || 0}px`;
s.borderBottomLeftRadius = `${style.radius[3] || 0}px`;
}
if (Array.isArray(style.margin)) {
s.marginTop = `${style.margin[0] || 0}px`;
s.marginRight = `${style.margin[1] || 0}px`;
s.marginBottom = `${style.margin[2] || 0}px`;
s.marginLeft = `${style.margin[3] || 0}px`;
}
if (style.backgroundColor && style.backgroundColor !== 'transparent') {
let bg = style.backgroundColor;
if (/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*0\s*\)$/.test(bg.trim())) {
bg = bg.trim().replace(/,\s*0\s*\)$/, ', 1)');
}
s.backgroundColor = bg;
}
if (style.backgroundImage) {
s.backgroundImage = `url(${style.backgroundImage})`;
s.backgroundSize = 'cover';
s.backgroundRepeat = 'no-repeat';
s.backgroundPosition = 'center';
}
return s;
}
</script>
<style lang="scss" scoped>
.row-wrapper {
box-sizing: border-box;
display: flex;
flex-direction: column;
.row-inner-flex {
box-sizing: border-box;
flex: 1;
height: 100%;
min-height: 0;
.component-cell {
box-sizing: border-box;
min-width: 0;
display: flex;
flex-direction: column;
height: 100%;
> * {
flex: 1;
height: 100%;
width: 100%;
box-sizing: border-box;
}
}
}
}
.unknown-component-placeholder {
padding: 20px;
background: #fef2f2;
border: 1px dashed #f87171;
color: #dc2626;
text-align: center;
font-size: 13px;
border-radius: 6px;
}
</style>

Some files were not shown because too many files have changed in this diff Show More