Files
guilixu-admin/.workbuddy/memory/2026-07-24.md
赵忠林 f9bf3c6df3 feat(passport): 优化忘记密码页发送验证码体验
- 引入图形验证码弹窗,风格与注册页面保持一致
- 使用 localStorage 记录每个账号发送验证码次数,前三次免图形验证码
- 第四次及以后发送验证码需输入正确图形验证码才能发送
- 失败时自动刷新验证码,关闭弹窗时重置加载状态
- 新增相关国际化文案支持中英文
- 调整登录页邮箱登录相关占位符文案提升用户体验
2026-07-24 22:14:29 +08:00

6.2 KiB
Raw Blame History

2026-07-24 工作日志

shopGoods 商品列表排序机制分析

  • 现状:列表「排序号」列(src/views/shop/shopGoods/index.vue 约 273-279 行)只做展示,未启用 sorter,列表默认也不按 sortNumber 排序(默认排序由后端决定,前端 orders 仅来自「创建时间」列的排序)。
  • 编辑表单里「排序号」是 a-input-number0-9999默认 100且在 rules 里是 必填
  • 已存在类似的布尔开关 recommend列表内联切换index.vue 约 47-58 行),「置顶」可复用同一 UI 模式。
  • 结论倾向:纯排序号在商品多时难用,建议「置顶开关 + 少量置顶项内排序 + 其余按默认(创建时间/销量)」的混合方案,而非完全替换。

已实现:方案 B商品置顶功能

  • 数据模型 src/api/shop/shopGoods/model/index.ts:新增 isTop?: number(置顶 1/不置顶 0
  • 列表 src/views/shop/shopGoods/index.vue
    • 新增「置顶」列,列表内联一键切换(复用 recommend 的 CheckOutlined/CloseOutlined 模式),新增 onTop 处理函数。
    • 「排序号」列开启 sorter: true(之前只展示、不可排序)。
  • 后端迁移脚本 add-is-top-shop-goods.sql:新增 is_top TINYINT 字段;分页默认排序需改为 ORDER BY is_top DESC, sort_number ASC, create_time DESC(后端不在本仓库,需手动改 page 接口 ORDER BY / 放开 orders 白名单)。
  • 注意:置顶真正"排到最前"依赖后端默认排序改动;点击列排序也需后端放开 is_top / sort_number。

后端改动(/Users/gxwebsoft/JAVA/guilixu-javaSpring Boot + MyBatis-Plus

  • entity/ShopGoods.java:新增 private Integer isTop;(映射列 is_top沿用 camelCase→下划线策略mapper 用 SELECT a.*,无需改 XML
  • service/impl/ShopGoodsServiceImpl.java
    • pageRellistRel 默认排序由 sort_number asc, create_time desc 改为 is_top desc, sort_number asc, create_time desc(置顶优先,置顶内按排序号,其余按创建时间倒序)。
    • collectFromUrl 采集默认值补 goods.setIsTop(0)(与 recommend 一致)。
  • 排序字段无白名单:PageParam 直接按列名拼 ORDER BY前端点「置顶」「排序号」列排序无需额外放开。
  • DB 仍需执行 add-is-top-shop-goods.sql(在 admin 仓库根目录):ALTER TABLE shop_goods ADD COLUMN is_top TINYINT(1) NOT NULL DEFAULT 0
  • 副作用提醒:默认排序改为置顶优先会影响所有调用 pageRel/listRel 的端(含小程序商品列表),置顶商品会浮到最前——通常正是期望行为。

shopGoods 列表:商品编号移到名称下方

  • src/views/shop/shopGoods/index.vue:删除独立的「编号」列(原 code 列),改为在「商品」列的名称下方显示「编号:{{ record.code }}」(灰色小字),节省一列横向空间。无 code 时不渲染该行。

shopGoods 列表:三个价格合并为一列 + 与编辑弹窗对齐

  • 原「市场价/价格/会员价」三列(字段 salePrice/price/dealerPrice合并为单个「价格」列key: 'priceGroup'width 150
  • 单元格内堆叠显示,顺序与命名对齐编辑弹窗(shopGoodsEdit.vue 基本信息 Tab价格price加粗头条→ 市场价salePrice→ 会员价dealerPrice空值显示 -
  • 列表展示用 priceGroup 自定义 #bodyCell 渲染;导出 ExcelhandleExport)仍保留三列独立价格,未改动。

商品分类(ShopGoodsCategory)多级分类调研

  • 分类管理页 /shop/shopGoodsCategory 本身支持多级:模型有 parentId/children编辑弹窗用 a-tree-select(toTreeData) 不限层级,列表 computeDepth 递归缩进。
  • 但商品端选分类的级联组件 src/components/SelectGoodsCategory/index.vue 的 formatData/filterData 只映射 2~3 级shopGoodsEdit 的 chooseGoodsCategory 写死 value[1].value/value[0].label(仅 2 级3 级及以上会选错/选不中。
  • 后端 /shop/shop-goods-category 是否限层级需查后端仓库确认(本仓库看不到)。

新增:忘记密码(找回密码)功能

  • 参考项目:/Users/gxwebsoft/VUE/website-admin/app/pages/login.vue(已验证可用)。
  • 新增页面 src/views/passport/forget/index.vue:复用登录页视觉风格,支持「邮箱找回 / 手机找回」两种 Tab含验证码 60s 倒计时、密码强度校验≥8 位且含字母+数字)、两次密码一致性校验。
  • 路由:在 src/router/routes.ts 启用 /forget(登录页「忘记密码」链接 push('/forget') 原本就指向它,路由此前被注释)。
  • 新增 API
    • src/api/passport/login/index.tssendEmailCaptcha(data,{skipTenant}) → POST /sendEmailCaptchasendSmsCaptchaByAdmin(data,{skipTenant}) → POST /sendSmsCaptchaByAdmin。
    • src/api/layout/index.tsresetPassword(data) → POST /resetPassword带 X-Tenant-Skip:1src/api/layout/model/index.ts 新增 ResetPasswordParam
  • 关键改动:src/utils/request.ts 请求拦截器在请求头含 X-Tenant-Skip 时跳过注入 TenantId/CompanyId/MerchantId/Domain登录前找回密码场景避免串租户vite build --outDir dist-verify 验证通过(真实 vite build 因沙箱 safe-delete 守卫删 dist 拦截,非代码问题)。
  • 后端同址 server.websoft.top/api与 website-admin 共用一套找回密码接口。

优化:忘记密码页发送验证码前 3 次免图形验证

  • 修改 src/views/passport/forget/index.vue:引入 getCaptcha,新增图形验证码弹窗(与 register2/index.vue 风格一致)。
  • localStorageforget_send_count_${activeTab}_${account} 记录每个邮箱/手机号的发送次数。
  • 同一个账号前 3 次点击「获取验证码」直接调用 sendEmailCaptcha/sendSmsCaptchaByAdmin;第 4 次起弹出图形验证码弹窗,输入正确并点击「立即发送」后才真正发送。
  • 失败时自动刷新图形验证码;弹窗关闭时重置 codeLoading
  • 新增 i18n 键 login.forgetPage.captchaTitlecaptchaPlaceholdersendNowzh_CN/en
  • vue-tsc 本次新增代码无类型错误;vite build --outDir dist-verify-captcha 编译通过。