mirror of
https://gitee.com/ShopeX/ECShopX_mobile-frontend
synced 2026-08-06 04:36:24 +08:00
[TBID:ECX-8807] fix: home overlays, purchase PDP, and after-sale UI
Move screen ad and coupon package outside ScrollView; fix float layout pointer-events, SpImage H5 sizing, and footer z-index; purchase PDP dynamic swiper height and enterprise logo; after-sale default return type and layout. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
---
|
||||
description: Karpathy 行为准则——先想清楚、极简、手术式改动、可验证目标
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Karpathy-inspired coding guidelines
|
||||
# Karpathy behavioral guidelines
|
||||
|
||||
Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.
|
||||
|
||||
@@ -13,6 +14,7 @@ Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-s
|
||||
**Don't assume. Don't hide confusion. Surface tradeoffs.**
|
||||
|
||||
Before implementing:
|
||||
|
||||
- State your assumptions explicitly. If uncertain, ask.
|
||||
- If multiple interpretations exist, present them - don't pick silently.
|
||||
- If a simpler approach exists, say so. Push back when warranted.
|
||||
@@ -35,12 +37,14 @@ Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, sim
|
||||
**Touch only what you must. Clean up only your own mess.**
|
||||
|
||||
When editing existing code:
|
||||
|
||||
- Don't "improve" adjacent code, comments, or formatting.
|
||||
- Don't refactor things that aren't broken.
|
||||
- Match existing style, even if you'd do it differently.
|
||||
- If you notice unrelated dead code, mention it - don't delete it.
|
||||
|
||||
When your changes create orphans:
|
||||
|
||||
- Remove imports/variables/functions that YOUR changes made unused.
|
||||
- Don't remove pre-existing dead code unless asked.
|
||||
|
||||
@@ -51,11 +55,13 @@ The test: Every changed line should trace directly to the user's request.
|
||||
**Define success criteria. Loop until verified.**
|
||||
|
||||
Transform tasks into verifiable goals:
|
||||
|
||||
- "Add validation" → "Write tests for invalid inputs, then make them pass"
|
||||
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
|
||||
- "Refactor X" → "Ensure tests pass before and after"
|
||||
|
||||
For multi-step tasks, state a brief plan:
|
||||
|
||||
```
|
||||
1. [Step] → verify: [check]
|
||||
2. [Step] → verify: [check]
|
||||
170
.cursor/skills/git-commit/SKILL.md
Normal file
170
.cursor/skills/git-commit/SKILL.md
Normal file
@@ -0,0 +1,170 @@
|
||||
---
|
||||
name: git-commit
|
||||
description: 按 GitLab TBID 强制校验规范提交 Git 变更并在对话中总结。提交信息必须以 [TBID:项目ID-任务编号] 开头。用户说「提交」「提交并总结」「帮我 commit」时使用;不写 .cursor/commit-summary 文件。
|
||||
---
|
||||
|
||||
# Git 提交(TBID 规范)
|
||||
|
||||
**2026 年 6 月 12 日起**,GitLab 仓库开启 Commit Message 强制校验:**所有提交必须包含 `[TBID:项目ID-任务编号]`,否则推送将被拒绝。**
|
||||
|
||||
## 何时触发
|
||||
|
||||
- 「提交并总结」「帮我 commit」「直接提交」「记录并提交」
|
||||
- 「总结这次改了什么并提交」(只对话总结 + commit,不写 md 文件)
|
||||
- 「修正提交信息」「改 commit message」(按下方「错误提交修正」处理)
|
||||
|
||||
## Commit Message 格式(强制)
|
||||
|
||||
```
|
||||
[TBID:项目ID-任务编号] <提交类型> <问题/功能简述>
|
||||
```
|
||||
|
||||
类型后可加冒号(如 `feat:`),与不加冒号(如 `fix `)均可;推荐统一为 `type:` 后接简述。
|
||||
|
||||
**正确示例:**
|
||||
|
||||
```
|
||||
[TBID:PROJ-1001] fix 解决用户登录超时问题
|
||||
[TBID:PROJ-1002] feat: 新增用户注册验证码功能
|
||||
[TBID:WA-641] style: 赠品缩进改为固定 20px
|
||||
```
|
||||
|
||||
### [TBID:项目ID-任务编号](必填,放开头)
|
||||
|
||||
- 格式固定:`[TBID:项目ID-任务编号]`,关联 Teambition 任务
|
||||
- 示例:`[TBID:ECX-8754]`、`[TBID:WA-641]`、`[TBID:LAXZE-7377]`
|
||||
- **用户未提供完整 TBID 时必须先询问**,禁止猜测或使用占位符
|
||||
|
||||
### 提交类型(必填)
|
||||
|
||||
| type | 说明 |
|
||||
|------|------|
|
||||
| `feat` | 新功能、新特性 |
|
||||
| `fix` | 修改 bug |
|
||||
| `perf` | 性能优化(不改变代码行为) |
|
||||
| `refactor` | 代码重构(不改变行为与功能) |
|
||||
| `docs` | 文档修改 |
|
||||
| `style` | 代码格式修改(**非 CSS**;删多余行、缩进等) |
|
||||
| `test` | 测试用例新增、修改 |
|
||||
| `build` | 影响构建或依赖(如 pom 依赖) |
|
||||
| `revert` | 恢复上一次提交 |
|
||||
| `ci` | CI 相关(Dockerfile 等) |
|
||||
| `chore` | 其他(不在上述类型中) |
|
||||
| `release` | 发布新版本 |
|
||||
| `workflow` | 工作流相关文件修改 |
|
||||
|
||||
用户指定 type 时以用户为准。
|
||||
|
||||
### 问题/功能简述(必填)
|
||||
|
||||
- 一句话描述本次提交,**不超过 50 字**
|
||||
- 写「做了什么」,不要堆文件路径列表
|
||||
|
||||
## 流程
|
||||
|
||||
### 1. 获取变更
|
||||
|
||||
```bash
|
||||
git status -sb
|
||||
git diff --stat
|
||||
git diff
|
||||
```
|
||||
|
||||
若有 staged 变更,再执行 `git diff --cached`。
|
||||
|
||||
### 2. 对话总结(不写文件)
|
||||
|
||||
用中文简要说明:
|
||||
|
||||
- 涉及哪些文件/模块
|
||||
- 主要改了什么
|
||||
- 拟用的完整 commit message(含 TBID、type、简述)
|
||||
|
||||
**禁止**创建或更新 `.cursor/commit-summary/` 下任何 md 文件。
|
||||
|
||||
**发现不合理代码时**:只指出问题与建议,**不得擅自修改**;先询问用户是否需要一并处理,待确认后再动代码。
|
||||
|
||||
### 3. 是否提交
|
||||
|
||||
| 用户意图 | 动作 |
|
||||
|----------|------|
|
||||
| 仅「总结」「看看改了啥」 | 只输出总结,不 `git add` / `git commit` |
|
||||
| 「并提交」「直接 commit」 | 继续步骤 4 |
|
||||
|
||||
### 4. 执行提交
|
||||
|
||||
1. **只提交已有 diff**:不得顺带改代码;有问题在提交前说明
|
||||
2. **不改无关代码**:先向用户说明并询问,**禁止擅自改动**
|
||||
3. **暂存**:未指定文件时 add 相关变更;用户指定路径则只 add 指定项
|
||||
4. **排除敏感文件**:`.env`、密钥等勿加入暂存,并提醒用户
|
||||
5. **提交**(message 必须含 TBID):
|
||||
|
||||
```bash
|
||||
git commit -m "$(cat <<'EOF'
|
||||
[TBID:项目ID-任务编号] type: 问题/功能简述
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
6. **确认**:回复「已提交」+ commit hash + 一句话总结
|
||||
7. **不 push**:除非用户明确要求
|
||||
|
||||
## 错误提交修正(未推送前)
|
||||
|
||||
推送被拦截或发现 message 不符合规范时:
|
||||
|
||||
### 仅最近 1 次提交写错
|
||||
|
||||
```bash
|
||||
git commit --amend -m "[TBID:XXXX-123] fix: 正确描述"
|
||||
```
|
||||
|
||||
### 最近 N 次提交都写错
|
||||
|
||||
```bash
|
||||
git rebase -i HEAD~N
|
||||
```
|
||||
|
||||
将需修改的提交前的 `pick` 改为 `reword`,保存后依次修改每条 message。
|
||||
|
||||
> 交互式 rebase 需用户确认;Agent 仅在用户明确要求修正历史提交信息时执行,且不使用 `-i` 以外的 destructive 操作。
|
||||
|
||||
### 查看未推送的提交
|
||||
|
||||
```bash
|
||||
git log --oneline origin/<分支名>..HEAD
|
||||
```
|
||||
|
||||
## 代码改动边界
|
||||
|
||||
- 提交、总结、review 过程中发现不合理代码:**先问用户,再改**
|
||||
- 用户未确认前,不得把「顺手修复」混进本次 commit
|
||||
|
||||
## 安全约束
|
||||
|
||||
- 不修改 git config
|
||||
- 不执行 destructive 命令(force push、hard reset 等),除非用户明确要求
|
||||
- 不 skip hooks(`--no-verify` 等),除非用户明确要求
|
||||
- **`--amend` / `rebase -i reword`**:仅用于修正 commit message(TBID 规范),且符合用户 amend 规则(HEAD 为自己创建、未 push 等)
|
||||
|
||||
## 示例对话
|
||||
|
||||
**用户**:`提交 WA-641,赠品缩进改 20px`
|
||||
|
||||
**Agent**:
|
||||
|
||||
1. 查看 diff → 3 个 trade scss 文件
|
||||
2. 总结:订单列表/结算/详情赠品 margin-left 改为 20px
|
||||
3. `git commit -m "[TBID:WA-641] style: 赠品缩进改为固定 20px"`
|
||||
4. 回复:已提交 `515c73472`
|
||||
|
||||
**用户**:`推送被拒,上次 commit 没写 TBID`
|
||||
|
||||
**Agent**:
|
||||
|
||||
1. 确认未 push → `git commit --amend -m "[TBID:WA-641] style: 赠品缩进改为固定 20px"`
|
||||
2. 提醒用户再次 push
|
||||
|
||||
**用户**:`先总结我改了啥`
|
||||
|
||||
**Agent**:只输出 diff 总结,不 commit,并问是否需要提交及 TBID。
|
||||
@@ -27,7 +27,7 @@ function SpFloatLayout(props) {
|
||||
className={classNames('sp-float-layout', className, {
|
||||
active: open
|
||||
})}
|
||||
catchMove
|
||||
catchMove={open}
|
||||
>
|
||||
<View className='sp-float-layout__overlay' onClick={onClose}></View>
|
||||
<View className='sp-float-layout__body'>
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
z-index: 1000;
|
||||
// display: none;
|
||||
transform: translate3D(0, 110%, 0);
|
||||
pointer-events: none;
|
||||
|
||||
&__overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -34,6 +36,7 @@
|
||||
// transition: all .3s linear;
|
||||
}
|
||||
&.active {
|
||||
pointer-events: auto;
|
||||
transform: translate3D(0, 0, 0);
|
||||
// display: block;
|
||||
#{$self}__overlay {
|
||||
|
||||
@@ -60,6 +60,10 @@
|
||||
&.sp-image--loaded {
|
||||
opacity: 1;
|
||||
}
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: $z-index-level-3;
|
||||
z-index: $z-index-level-5;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@ function SpGoodsCompactCard(props) {
|
||||
return (
|
||||
<View
|
||||
id={`sp-goods-compact-card-${info.itemId}`}
|
||||
key={props.key}
|
||||
className={classNames('sp-goods-compact-card', props.className)}
|
||||
onClick={handleClick}
|
||||
>
|
||||
@@ -178,7 +177,6 @@ SpGoodsCompactCard.defaultProps = {
|
||||
className: '',
|
||||
id: '',
|
||||
info: null,
|
||||
key: '',
|
||||
onClick: null,
|
||||
mode: 'aspectFill',
|
||||
width: 218,
|
||||
|
||||
@@ -42,7 +42,6 @@ function SpGoodsGridCard(props) {
|
||||
return (
|
||||
<View
|
||||
id={`sp-goods-grid-card-${info.itemId}`}
|
||||
key={props.key}
|
||||
className={classNames('sp-goods-grid-card', props.className)}
|
||||
onClick={handleClick}
|
||||
>
|
||||
@@ -131,7 +130,6 @@ SpGoodsGridCard.defaultProps = {
|
||||
className: '',
|
||||
id: '',
|
||||
info: null,
|
||||
key: '',
|
||||
onClick: null,
|
||||
mode: 'aspectFill',
|
||||
width: 200,
|
||||
|
||||
@@ -35,7 +35,6 @@ function SpGoodsHeroCard(props) {
|
||||
return (
|
||||
<View
|
||||
id={`sp-goods-hero-card-${info.itemId}`}
|
||||
key={props.key}
|
||||
className={classNames('sp-goods-hero-card', props.className)}
|
||||
onClick={handleClick}
|
||||
>
|
||||
@@ -154,7 +153,6 @@ SpGoodsHeroCard.defaultProps = {
|
||||
className: '',
|
||||
id: '',
|
||||
info: null,
|
||||
key: '',
|
||||
onClick: null,
|
||||
mode: 'aspectFill',
|
||||
width: 200,
|
||||
|
||||
@@ -55,6 +55,12 @@ export default class ScreenAd extends Component {
|
||||
}
|
||||
const isHave = res.is_enable === 1 && (res.app === 'all' || res.app.indexOf(client[env]) !== -1)
|
||||
const { showAdv } = this.props
|
||||
if (!isHave) {
|
||||
if (!showAdv) {
|
||||
this.props.onUpdateShowAdv(true)
|
||||
}
|
||||
return
|
||||
}
|
||||
if (isHave && res.show_time === 'once' && showAdv) {
|
||||
this.props.onUpdateShowAdv(true)
|
||||
return
|
||||
|
||||
@@ -177,10 +177,11 @@ function withPageWrapper(Component) {
|
||||
|
||||
if (dtid) {
|
||||
params['distributor_id'] = dtid
|
||||
} else if (shopInfo?.distributor_id) {
|
||||
// 用户已在店铺列表手动切店时,优先保留当前店铺,避免 LBS 再次按定位覆盖
|
||||
params['distributor_id'] = shopInfo.distributor_id
|
||||
} else if (forceLocation && entryLaunch.isEntryStoreLbsEnabled() && isLocation) {
|
||||
await appendLocationParams()
|
||||
} else if (shopInfo?.distributor_id) {
|
||||
params['distributor_id'] = shopInfo?.distributor_id
|
||||
} else if (entryLaunch.isEntryStoreLbsEnabled() && isLocation) {
|
||||
await appendLocationParams()
|
||||
}
|
||||
|
||||
@@ -82,6 +82,13 @@ function WgtFullSlider(props) {
|
||||
})
|
||||
}, [immersive, isShowHomeHeader, isTab, footerHeight])
|
||||
|
||||
// footerHeight 由 SpPage onReady 异步注入,需在变化后重新计算高度
|
||||
useEffect(() => {
|
||||
if (show) {
|
||||
setHeight()
|
||||
}
|
||||
}, [show, setHeight])
|
||||
|
||||
// 切换视频播放
|
||||
const togglePlay = (itemIndex) => {
|
||||
const item = localData[itemIndex]
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
bottom: 0px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 999;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&.left {
|
||||
|
||||
@@ -345,6 +345,7 @@ function Home() {
|
||||
pageData?.base?.isImmersive ? 0 : gNavbarH
|
||||
}px - ${footerHeight})`
|
||||
draft.navbarHeight = gNavbarH
|
||||
draft.footerHeight = footerHeight
|
||||
})
|
||||
}}
|
||||
>
|
||||
@@ -391,12 +392,6 @@ function Home() {
|
||||
{/* 小程序收藏提示 */}
|
||||
{isWeixin && <MCompAddTip />}
|
||||
|
||||
{/* 开屏广告 */}
|
||||
{isWeixin && !showAdv && <SpScreenAd />}
|
||||
|
||||
{/* 优惠券包 */}
|
||||
{VERSION_STANDARD && <SpCouponPackage />}
|
||||
|
||||
{/* Sku选择器 */}
|
||||
<MSpSkuSelect
|
||||
open={skuPanelOpen}
|
||||
@@ -416,6 +411,12 @@ function Home() {
|
||||
/>
|
||||
</>
|
||||
</ScrollView>
|
||||
|
||||
{/* 全屏弹层需放在 ScrollView 外,真机上 scroll-view 内 fixed 层叠会异常 */}
|
||||
{/* 开屏广告 */}
|
||||
{isWeixin && !showAdv && <SpScreenAd />}
|
||||
{/* 优惠券包 微信端等开屏广告关闭(showAdv=true)后再弹券包,避免与开屏叠层 */}
|
||||
{VERSION_STANDARD && (!isWeixin || showAdv) && <SpCouponPackage />}
|
||||
</SpPage>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
import React, { useEffect, useRef, useMemo, useState } from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import Taro from '@tarojs/taro'
|
||||
import { View, Text, Swiper, SwiperItem, Video } from '@tarojs/components'
|
||||
import { View, Text, Swiper, SwiperItem, Video, Image } from '@tarojs/components'
|
||||
import { AtFloatLayout, AtButton } from 'taro-ui'
|
||||
import { useImmer } from 'use-immer'
|
||||
import {
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
import doc from '@/doc'
|
||||
import entryLaunch from '@/utils/entryLaunch'
|
||||
import { useNavigation } from '@/hooks'
|
||||
import { updateChooseAddress } from '@/store/slices/user'
|
||||
import { ACTIVITY_LIST } from '@/consts'
|
||||
import { $t, ti, useTranslation } from '@/i18n'
|
||||
import { WgtFilm, WgtSlider, WgtImgHotZone } from '@/pages/home/wgts'
|
||||
@@ -178,12 +179,15 @@ const initialState = {
|
||||
recommendList: [],
|
||||
activityId: '',
|
||||
enterpriseId: '',
|
||||
isParameter: false
|
||||
isParameter: false,
|
||||
imgHeightList: [],
|
||||
defaultImageHeight: 520
|
||||
}
|
||||
|
||||
function EspierDetail(props) {
|
||||
const { i18n } = useTranslation()
|
||||
const pageRef = useRef()
|
||||
const dispatch = useDispatch()
|
||||
const { userInfo, address } = useSelector((state) => state.user)
|
||||
const { colorPrimary, openRecommend } = useSelector((state) => state.sys)
|
||||
const {
|
||||
@@ -219,13 +223,27 @@ function EspierDetail(props) {
|
||||
recommendList,
|
||||
activityId,
|
||||
enterpriseId,
|
||||
isParameter
|
||||
isParameter,
|
||||
imgHeightList,
|
||||
defaultImageHeight
|
||||
} = state
|
||||
|
||||
useEffect(() => {
|
||||
init()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
loadDefaultAddress()
|
||||
}, [])
|
||||
|
||||
const loadDefaultAddress = async () => {
|
||||
const { list } = await api.member.addressList()
|
||||
const defaultAddress = list?.find((item) => item.is_def > 0) || list?.[0]
|
||||
if (defaultAddress) {
|
||||
dispatch(updateChooseAddress(defaultAddress))
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const eid = curEnterpriseId || enterpriseId || purchase_share_info?.enterprise_id
|
||||
if (!eid) {
|
||||
@@ -358,8 +376,19 @@ function EspierDetail(props) {
|
||||
subscribe
|
||||
}
|
||||
draft.promotionActivity = data.promotionActivity
|
||||
draft.imgHeightList = new Array(data?.imgs?.length).fill(draft.defaultImageHeight)
|
||||
})
|
||||
|
||||
getMultipleImageInfo(data.imgs)
|
||||
.then((heights) => {
|
||||
setState((draft) => {
|
||||
draft.imgHeightList = heights
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('计算图片高度失败,使用默认高度:', error)
|
||||
})
|
||||
|
||||
if (isAPP() && userInfo) {
|
||||
try {
|
||||
Taro.SAPPShare.init({
|
||||
@@ -393,18 +422,56 @@ function EspierDetail(props) {
|
||||
})
|
||||
}
|
||||
|
||||
const getMultipleImageInfo = async (imageUrls = []) => {
|
||||
let windowWidth = defaultImageHeight
|
||||
try {
|
||||
const sys = Taro.getSystemInfoSync()
|
||||
if (sys && sys.windowWidth) windowWidth = sys.windowWidth
|
||||
} catch (e) {
|
||||
console.log('获取系统信息失败,使用默认宽度:', e)
|
||||
}
|
||||
|
||||
const promises = imageUrls.map(async (url) => {
|
||||
try {
|
||||
const imageInfo = await Taro.getImageInfo({ src: url })
|
||||
const imgWidth = Number(imageInfo?.width) || 0
|
||||
const imgHeight = Number(imageInfo?.height) || 0
|
||||
if (imgWidth > 0 && imgHeight > 0) {
|
||||
return Math.round((windowWidth * imgHeight) / imgWidth)
|
||||
}
|
||||
return Math.round(windowWidth)
|
||||
} catch (error) {
|
||||
console.log('获取图片信息失败:', url, error)
|
||||
return Math.round(windowWidth)
|
||||
}
|
||||
})
|
||||
|
||||
return Promise.all(promises)
|
||||
}
|
||||
|
||||
const handleChooseDeliveryAddress = () => {
|
||||
Taro.navigateTo({
|
||||
url: '/marketing/pages/member/address?isPicker=choose'
|
||||
})
|
||||
}
|
||||
|
||||
const onChangeSwiper = (e) => {
|
||||
setState((draft) => {
|
||||
const onChangeSwiper = async (e) => {
|
||||
await setState((draft) => {
|
||||
draft.curImgIdx = e.detail.current
|
||||
})
|
||||
}
|
||||
|
||||
const setSwiperCss = (item) => {
|
||||
return {
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
'background-size': 'cover',
|
||||
'background-image': `url(${item})`,
|
||||
'background-repeat': 'no-repeat',
|
||||
'background-position': 'center'
|
||||
}
|
||||
}
|
||||
|
||||
const onChangeToolBar = (key) => {
|
||||
setState((draft) => {
|
||||
draft.skuPanelOpen = true
|
||||
@@ -412,8 +479,6 @@ function EspierDetail(props) {
|
||||
})
|
||||
}
|
||||
|
||||
const { windowWidth } = Taro.getSystemInfoSync()
|
||||
|
||||
let sessionFrom = {}
|
||||
if (info) {
|
||||
sessionFrom['商品'] = info.itemName
|
||||
@@ -488,15 +553,13 @@ function EspierDetail(props) {
|
||||
className='goods-swiper'
|
||||
// current={curImgIdx}
|
||||
onChange={onChangeSwiper}
|
||||
style={{ height: (imgHeightList[curImgIdx] || defaultImageHeight) + 'px' }}
|
||||
>
|
||||
{info.imgs.map((img, idx) => (
|
||||
<SwiperItem key={`swiperitem__${idx}`}>
|
||||
<SpImage
|
||||
mode='aspectFit'
|
||||
src={img}
|
||||
width={windowWidth * 2}
|
||||
height={windowWidth * 2}
|
||||
></SpImage>
|
||||
<View style={setSwiperCss(img)}>
|
||||
<Image mode='scaleToFill' src={img} className='swiperitem__img' />
|
||||
</View>
|
||||
</SwiperItem>
|
||||
))}
|
||||
</Swiper>
|
||||
|
||||
@@ -122,7 +122,16 @@
|
||||
}
|
||||
|
||||
.goods-swiper {
|
||||
height: 750px;
|
||||
transition: height 0.2s ease-in-out;
|
||||
overflow: hidden;
|
||||
.swiperitem__img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.video-container {
|
||||
|
||||
@@ -28,12 +28,12 @@ function PurchaseAuthEmail() {
|
||||
const [vcode, setVcode] = useState('')
|
||||
const [countdown, setCountdown] = useState(0)
|
||||
const [enterpriseName, setEnterpriseName] = useState('')
|
||||
const [activityBg, setActivityBg] = useState('')
|
||||
const sendCodeLockRef = useRef(false)
|
||||
const { showModal } = useModal()
|
||||
const dispatch = useDispatch()
|
||||
const { params } = useRouter()
|
||||
const { appName } = useSelector((state) => state.sys)
|
||||
const { curEnterpriseLogo } = useSelector((state) => state.purchase)
|
||||
const {
|
||||
enterprise_id,
|
||||
enterprise_name,
|
||||
@@ -85,10 +85,8 @@ function PurchaseAuthEmail() {
|
||||
(item) => String(item?.id ?? item?.enterprise_id) === String(enterprise_id)
|
||||
)
|
||||
setEnterpriseName(found?.name || '')
|
||||
setActivityBg(found?.logo || '')
|
||||
} catch (e) {
|
||||
setEnterpriseName('')
|
||||
setActivityBg('')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,7 +235,11 @@ function PurchaseAuthEmail() {
|
||||
|
||||
return (
|
||||
<SpPage className='purchase-email-auth'>
|
||||
<SpImage src={activityBg} className='purchase-email-auth__cover-img' mode='widthFix' />
|
||||
<SpImage
|
||||
src={curEnterpriseLogo}
|
||||
className='purchase-email-auth__cover-img'
|
||||
mode='widthFix'
|
||||
/>
|
||||
|
||||
<SpPurchaseEnterpriseBar
|
||||
name={enterpriseName || appName || $t('c2581d4c.6fb7d0')}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright © ShopeX (http://www.shopex.cn). All rights reserved.
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
import React, { useEffect, useRef, useMemo } from 'react'
|
||||
import React, { useEffect, useMemo } from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { useImmer } from 'use-immer'
|
||||
import Taro, { getCurrentInstance } from '@tarojs/taro'
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
SpHtml,
|
||||
SpInput as AtInput
|
||||
} from '@/components'
|
||||
import { View, Text, Picker, ScrollView } from '@tarojs/components'
|
||||
import { View, Text, Picker } from '@tarojs/components'
|
||||
import { AFTER_SALE_TYPE, REFUND_FEE_TYPE, AFTER_SALE_TYPE1 } from '@/consts'
|
||||
import { pickBy, showToast, classNames, VERSION_STANDARD, VERSION_PLATFORM } from '@/utils'
|
||||
import { useTranslation, $t, ti } from '@/i18n'
|
||||
@@ -38,7 +38,7 @@ const initialState = {
|
||||
reasons: [],
|
||||
refundFee: 0,
|
||||
refundPoint: 0,
|
||||
refundType: 'offline',
|
||||
refundType: 'logistics',
|
||||
description: '',
|
||||
pic: '',
|
||||
// 用于云店后台交易设置-到店退货关闭时判断
|
||||
@@ -50,7 +50,7 @@ const initialState = {
|
||||
offline_freight: '', //运费
|
||||
mobile: '', // 联系电话
|
||||
openRefundType: false,
|
||||
selectRefundValue: 'offline',
|
||||
selectRefundValue: 'logistics',
|
||||
afterSaleDesc: {
|
||||
intro: '',
|
||||
is_open: false
|
||||
@@ -63,7 +63,6 @@ function TradeAfterSale(props) {
|
||||
const { setNavigationBarTitle } = useNavigation()
|
||||
const $instance = getCurrentInstance() || {}
|
||||
const [state, setState] = useImmer(initialState)
|
||||
const pageRef = useRef()
|
||||
const {
|
||||
info,
|
||||
curTabIdx,
|
||||
@@ -93,6 +92,34 @@ function TradeAfterSale(props) {
|
||||
return info && info.deliveryStatus != 'DONE'
|
||||
}, [info])
|
||||
|
||||
const currentAftersalesType = useMemo(() => {
|
||||
const list = OnlyRefundShow ? tabList : tabList1
|
||||
return list[curTabIdx]?.type
|
||||
}, [OnlyRefundShow, tabList, tabList1, curTabIdx])
|
||||
|
||||
const realRefundFee = useMemo(() => {
|
||||
if (!info) return '0.00'
|
||||
const rFee = info.items
|
||||
.filter((item) => item.checked)
|
||||
.reduce((sum, { price, num, refundNum }) => sum + (price / num) * refundNum, 0)
|
||||
return rFee.toFixed(2)
|
||||
}, [info])
|
||||
|
||||
const realRefundPoint = useMemo(() => {
|
||||
if (!info) return 0
|
||||
return info.items
|
||||
.filter((item) => item.checked)
|
||||
.reduce((sum, { point, num, refundNum, leftAftersalesNum }) => {
|
||||
if (leftAftersalesNum == refundNum) {
|
||||
return Math.ceil(sum + (point / num) * refundNum)
|
||||
}
|
||||
if (num > refundNum) {
|
||||
return Math.floor(sum + (point / num) * refundNum)
|
||||
}
|
||||
return sum + (point / num) * refundNum
|
||||
}, 0)
|
||||
}, [info])
|
||||
|
||||
useEffect(() => {
|
||||
const syncTitle = () => setNavigationBarTitle($t('b3d4a245.45eb0c'))
|
||||
syncTitle()
|
||||
@@ -114,14 +141,6 @@ function TradeAfterSale(props) {
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (openRefundType) {
|
||||
pageRef.current.pageLock()
|
||||
} else {
|
||||
pageRef.current.pageUnLock()
|
||||
}
|
||||
}, [openRefundType])
|
||||
|
||||
const onCancel = () => {
|
||||
Taro.navigateBack()
|
||||
}
|
||||
@@ -167,39 +186,6 @@ function TradeAfterSale(props) {
|
||||
})
|
||||
}
|
||||
|
||||
const getRealRefundFee = () => {
|
||||
let rFee = 0
|
||||
if (info) {
|
||||
const { items } = info
|
||||
rFee = items
|
||||
.filter((item) => item.checked)
|
||||
.reduce((sum, { price, num, refundNum }) => sum + (price / num) * refundNum, 0)
|
||||
}
|
||||
return rFee.toFixed(2)
|
||||
}
|
||||
|
||||
const getRealRefundPoint = () => {
|
||||
let rPoint = 0
|
||||
if (info) {
|
||||
const { items } = info
|
||||
rPoint = items
|
||||
.filter((item) => item.checked)
|
||||
.reduce((sum, { point, num, refundNum, leftAftersalesNum }) => {
|
||||
console.log(sum + (point / num) * refundNum, '---')
|
||||
console.log(refundNum, leftAftersalesNum, '---')
|
||||
if (leftAftersalesNum == refundNum) {
|
||||
// 可申请数量=退货数量时,向上取整 积分47 总数2件 可申请为1件 申请1件 退24积分
|
||||
return Math.ceil(sum + (point / num) * refundNum)
|
||||
} else if (num > refundNum) {
|
||||
// 总数大于退货数量时,向下取整 积分47 总数2件 可申请2件 申请1件 退23积分
|
||||
return Math.floor(sum + (point / num) * refundNum)
|
||||
}
|
||||
return sum + (point / num) * refundNum
|
||||
}, 0)
|
||||
}
|
||||
return rPoint
|
||||
}
|
||||
|
||||
const onChangeRefundType = ({ value }) => {
|
||||
setState((draft) => {
|
||||
draft.selectRefundValue = value
|
||||
@@ -221,7 +207,7 @@ function TradeAfterSale(props) {
|
||||
if (!reasons?.[reasonIndex]) {
|
||||
return showToast($t('44d65d28.d030d6'))
|
||||
}
|
||||
const aftersales_type = OnlyRefundShow ? tabList[curTabIdx].type : tabList1[curTabIdx].type
|
||||
const aftersales_type = currentAftersalesType
|
||||
const reason = reasons?.[reasonIndex]
|
||||
let params = {
|
||||
detail: checkedItems.map(({ id: _id, refundNum }) => {
|
||||
@@ -283,7 +269,6 @@ function TradeAfterSale(props) {
|
||||
|
||||
return (
|
||||
<SpPage
|
||||
ref={pageRef}
|
||||
className='page-trade-after-sale'
|
||||
renderFooter={
|
||||
<View className='btn-wrap'>
|
||||
@@ -293,8 +278,7 @@ function TradeAfterSale(props) {
|
||||
</View>
|
||||
}
|
||||
>
|
||||
<ScrollView scrollY className='scroll-view'>
|
||||
<View className='scroll-view-body'>
|
||||
<View className='page-content'>
|
||||
<SpTabs
|
||||
current={curTabIdx}
|
||||
tablist={OnlyRefundShow ? tabList : tabList1}
|
||||
@@ -406,16 +390,16 @@ function TradeAfterSale(props) {
|
||||
)}
|
||||
|
||||
<View className='refund-amount'>
|
||||
<SpCell title={$t('44d65d28.a0cd4c')} value={getRealRefundFee()} />
|
||||
<SpCell title={$t('44d65d28.a0cd4c')} value={realRefundFee} />
|
||||
</View>
|
||||
|
||||
<View className='refund-point'>
|
||||
{/* <SpCell title='退积分' value={info?.point} /> */}
|
||||
<SpCell title={$t('44d65d28.401595')} value={getRealRefundPoint()} />
|
||||
<SpCell title={$t('44d65d28.401595')} value={realRefundPoint} />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{curTabIdx == 1 && (
|
||||
{currentAftersalesType === 'REFUND_GOODS' && (
|
||||
<View className='return-goods-type'>
|
||||
<SpCell
|
||||
border
|
||||
@@ -526,8 +510,7 @@ function TradeAfterSale(props) {
|
||||
<SpHtml content={afterSaleDesc.intro} />
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
|
||||
<SpFloatLayout
|
||||
title={$t('44d65d28.5add21')}
|
||||
|
||||
@@ -7,11 +7,9 @@
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.scroll-view {
|
||||
height: 100%;
|
||||
&-body {
|
||||
overflow: hidden;
|
||||
}
|
||||
.page-content {
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.comp-trade-info {
|
||||
|
||||
Reference in New Issue
Block a user